Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions rts/Lua/LuaHandleSynced.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@

#include "System/Misc/TracyDefs.h"

#include <ranges>

LuaRulesParams::Params CSplitLuaHandle::gameParams;

Expand Down Expand Up @@ -1196,6 +1197,42 @@ bool CSyncedLuaHandle::AllowResourceTransfer(int oldTeam, int newTeam, const cha
return allow;
}

/*** Called when excess resources are added.
* Accumulates all excesses within a single gameframe.
*
* @function SyncedCallins:ResourceExcess
* @param excesses table
* @return boolean whether or not Lua handled the event
*/
bool CSyncedLuaHandle::ResourceExcess(const std::map <int, SResourcePack>& excesses)
{
RECOIL_DETAILED_TRACY_ZONE;
LUA_CALL_IN_CHECK(L, true);
luaL_checkstack(L, 3, __func__);

static const LuaHashString cmdStr(__func__);
if (!cmdStr.GetGlobalFunc(L))
return false;

lua_createtable(L, excesses.size(), 1);

for (const auto &[teamID, excess] : excesses) {
lua_createtable(L, excess.MAX_RESOURCES, 0);
for (const auto &[resourceID, resource] : std::views::enumerate(excess)) {
lua_pushnumber(L, resource);
lua_rawseti(L, -2, resourceID + 1);
}
lua_rawseti(L, -2, teamID);
}

if (!RunCallIn(L, cmdStr, 1, 1))
return false;

const bool handled = luaL_optboolean(L, -1, false);
lua_pop(L, 1);
return handled;
}


/*** Determines if this unit can be controlled directly in FPS view.
*
Expand Down
2 changes: 2 additions & 0 deletions rts/Lua/LuaHandleSynced.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ class CSyncedLuaHandle : public CLuaHandle
bool CommandFallback(const CUnit* unit, const Command& cmd) override;
bool AllowCommand(const CUnit* unit, const Command& cmd, int playerNum, bool fromSynced, bool fromLua) override;

bool ResourceExcess(const std::map <int, SResourcePack>& excess) override;

std::pair <bool, bool> AllowUnitCreation(const UnitDef* unitDef, const CUnit* builder, const BuildInfo* buildInfo) override;
bool AllowUnitTransfer(const CUnit* unit, int newTeam, bool capture) override;
bool AllowUnitBuildStep(const CUnit* builder, const CUnit* unit, float part) override;
Expand Down
47 changes: 47 additions & 0 deletions rts/Lua/LuaSyncedCtrl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ bool LuaSyncedCtrl::PushEntries(lua_State* L)
REGISTER_LUA_CFUNC(AddTeamResource);
REGISTER_LUA_CFUNC(UseTeamResource);
REGISTER_LUA_CFUNC(SetTeamResource);
REGISTER_LUA_CFUNC(AddTeamResourceExcessStats);
REGISTER_LUA_CFUNC(SetTeamShareLevel);
REGISTER_LUA_CFUNC(ShareTeamResource);

Expand Down Expand Up @@ -1404,6 +1405,52 @@ int LuaSyncedCtrl::SetTeamShareLevel(lua_State* L)
}


/***
* Records resource excess for a team without moving resources.
*
* The engine normally tracks excess, but if you use `gadget:ResourceExcess`
* to handle it manually it's now also up to you to track stats.
*
* @function Spring.AddTeamResourceExcessStats
* @param teamID integer
* @param type ResourceName
* @param excess number Amount wasted this tick.
* @return nil
*/
int LuaSyncedCtrl::AddTeamResourceExcessStats(lua_State* L)
{
const int teamID = luaL_checkint(L, 1);

if (!teamHandler.IsValidTeam(teamID))
return 0;

if (!CanControlTeam(L, teamID))
return 0;

CTeam* team = teamHandler.Team(teamID);

if (team == nullptr)
return 0;

const char rtype = luaL_checkstring(L, 2)[0];
if (rtype != 'm' && rtype != 'e')
return 0;

const bool isMetal = (rtype == 'm');
const float val = std::max(0.0f, luaL_checkfloat(L, 3));

float& resExcess = isMetal ? team->resPrevExcess.metal : team->resPrevExcess.energy;

TeamStatistics& stats = team->GetCurrentStats();
float& statExcess = isMetal ? stats.metalExcess : stats.energyExcess;

resExcess += val;
statExcess += val;

return 0;
}


/*** Transfers resources between two teams.
* Transfers directly, without involving AllowResourceTransfer callin.
* Approximately equivalent to doing Use and Add for the sender and receiver,
Expand Down
1 change: 1 addition & 0 deletions rts/Lua/LuaSyncedCtrl.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class LuaSyncedCtrl
static int AddTeamResource(lua_State* L);
static int UseTeamResource(lua_State* L);
static int SetTeamResource(lua_State* L);
static int AddTeamResourceExcessStats(lua_State* L);
static int SetTeamShareLevel(lua_State* L);
static int ShareTeamResource(lua_State* L);

Expand Down
7 changes: 4 additions & 3 deletions rts/Sim/Misc/Team.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ CR_REG_METADATA(CTeam, (
CR_MEMBER(resPrevExpense),
CR_MEMBER(resShare),
CR_MEMBER(resDelayedShare),
CR_MEMBER(resExcessThisFrame),
CR_MEMBER(resSent),
CR_MEMBER(resPrevSent),
CR_MEMBER(resReceived),
Expand Down Expand Up @@ -156,7 +157,7 @@ void CTeam::AddMetal(float amount, bool useIncomeMultiplier)
if (res.metal <= resStorage.metal)
return;

resDelayedShare.metal += (res.metal - resStorage.metal);
resExcessThisFrame.metal += (res.metal - resStorage.metal);
res.metal = resStorage.metal;
}

Expand All @@ -170,7 +171,7 @@ void CTeam::AddEnergy(float amount, bool useIncomeMultiplier)
resIncome.energy += amount;

if (res.energy > resStorage.energy) {
resDelayedShare.energy += (res.energy - resStorage.energy);
resExcessThisFrame.energy += (res.energy - resStorage.energy);
res.energy = resStorage.energy;
}
}
Expand All @@ -196,7 +197,7 @@ void CTeam::AddResources(SResourcePack amount, bool useIncomeMultiplier)
if (res[i] <= resStorage[i])
continue;

resDelayedShare[i] += (res[i] - resStorage[i]);
resExcessThisFrame[i] += (res[i] - resStorage[i]);
res[i] = resStorage[i];
}
}
Expand Down
4 changes: 4 additions & 0 deletions rts/Sim/Misc/Team.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ class CTeam : public TeamBase
void AddUnit(CUnit* unit, AddType type);
void RemoveUnit(CUnit* unit, RemoveType type);

private:
void HandleFrameExcess();

public:
int teamNum;
unsigned int numUnits; // number of units this team controls
Expand All @@ -88,6 +91,7 @@ class CTeam : public TeamBase
SResourcePack resIncome, resPrevIncome;
SResourcePack resExpense, resPrevExpense;
SResourcePack resShare;
SResourcePack resExcessThisFrame; //< accumulates excess over a gameframe
SResourcePack resDelayedShare; //< excess that might be shared next SlowUpdate
SResourcePack resSent, resPrevSent;
SResourcePack resReceived, resPrevReceived;
Expand Down
27 changes: 27 additions & 0 deletions rts/Sim/Misc/TeamHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "Game/GameSetup.h"
#include "Sim/Misc/GlobalConstants.h"
#include "Sim/Misc/GlobalSynced.h"
#include "System/EventHandler.h"

#include "System/Misc/TracyDefs.h"

Expand Down Expand Up @@ -113,9 +114,35 @@ void CTeamHandler::SetDefaultStartPositions(const CGameSetup* setup)
}
}

void CTeamHandler::HandleFrameExcess()
{
std::map <int, SResourcePack> excesses;
for (const auto &team : teams)
excesses.emplace(team.teamNum, team.resExcessThisFrame);

/* Note that `resDelayedShare` is a metaaccumulator,
* the reason to have this two-layer accumulation is
* that handling excess right when it happens would
* be too expensive (for example you can have tens of
* thousands of windgens each generating a resource
* instance), having the Lua event handled at slow
* update would reduce control, and having the engine
* handle excess natively outside slow update would
* be inconsistent with other native resource handling. */
if (!eventHandler.ResourceExcess(excesses))
for (auto &team : teams)
team.resDelayedShare += team.resExcessThisFrame;

for (auto &team : teams)
team.resExcessThisFrame = 0.0f;
}

void CTeamHandler::GameFrame(int frameNum)
{
RECOIL_DETAILED_TRACY_ZONE;

HandleFrameExcess();

if ((frameNum % TEAM_SLOWUPDATE_RATE) != 0)
return;

Expand Down
1 change: 1 addition & 0 deletions rts/Sim/Misc/TeamHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ class CTeamHandler
bool TransferTeamMaxUnits(CTeam* fromTeam, CTeam* toTeam, int transferAmnt);

private:
void HandleFrameExcess();

/**
* @brief gaia team
Expand Down
4 changes: 4 additions & 0 deletions rts/System/EventClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#define EVENT_CLIENT_H

#include <algorithm>
#include <map>
#include <typeinfo>
#include <string>
#include <vector>
Expand Down Expand Up @@ -35,6 +36,7 @@ struct BuildInfo;
struct FeatureDef;
class LuaMaterial;
struct WeaponDef;
struct SResourcePack;

#ifndef zipFile
// might be defined through zip.h already
Expand Down Expand Up @@ -122,6 +124,8 @@ class CEventClient

virtual void TeamDied(int teamID) {}
virtual void TeamChanged(int teamID) {}
virtual bool ResourceExcess(const std::map <int, SResourcePack>& excess) { return false; }

virtual void PlayerChanged(int playerID) {}
virtual void PlayerAdded(int playerID) {}
virtual void PlayerRemoved(int playerID, int reason) {}
Expand Down
6 changes: 6 additions & 0 deletions rts/System/EventHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,12 @@ void CEventHandler::TeamDied(int teamID)
ITERATE_EVENTCLIENTLIST(TeamDied, teamID);
}

bool CEventHandler::ResourceExcess(const std::map <int, SResourcePack> &excess)
{
ZoneScoped;
return ControlIterateDefFalse(listResourceExcess, &CEventClient::ResourceExcess, excess);
}

void CEventHandler::TeamChanged(int teamID)
{
ZoneScoped;
Expand Down
2 changes: 2 additions & 0 deletions rts/System/EventHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ class CEventHandler

void TeamDied(int teamID);
void TeamChanged(int teamID);
bool ResourceExcess(const std::map <int, SResourcePack>& excess);

void PlayerChanged(int playerID);
void PlayerAdded(int playerID);
void PlayerRemoved(int playerID, int reason);
Expand Down
4 changes: 4 additions & 0 deletions rts/System/Events.def
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,12 @@
SETUP_EVENT(GamePaused, MANAGED_BIT)
SETUP_EVENT(GameFrame, MANAGED_BIT)
SETUP_EVENT(GameFramePost, MANAGED_BIT)

SETUP_EVENT(TeamDied, MANAGED_BIT)
SETUP_EVENT(TeamChanged, MANAGED_BIT)

SETUP_EVENT(ResourceExcess, MANAGED_BIT | CONTROL_BIT)

SETUP_EVENT(PlayerChanged, MANAGED_BIT | UNSYNCED_BIT)
SETUP_EVENT(PlayerAdded, MANAGED_BIT | UNSYNCED_BIT)
SETUP_EVENT(PlayerRemoved, MANAGED_BIT | UNSYNCED_BIT)
Expand Down
Loading