Skip to content

Commit

Permalink
Add Script.DelayByFrames
Browse files Browse the repository at this point in the history
  • Loading branch information
sprunk authored and lhog committed Jul 19, 2023
1 parent 4d85bee commit 784e417
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 0 deletions.
3 changes: 3 additions & 0 deletions doc/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ Lua:
- add `Spring.GetUnitIsBeingBuilt(unitID) -> bool beingBuilt, number buildProgress`. Note that this
doesn't bring new capability because `buildProgress` was already available from `GetUnitHealth`,
and `beingBuilt` from `GetUnitIsStunned`, but as you can see it wasn't terribly convenient/intuitive.
- add `Script.DelayByFrames(frameDelay, function, args...)`. Runs `function(args...)` after a delay
of the specified number of frames (at least 1). Multiple functions can be queued onto the same frame
and run in the order they were added, just before that frame's GameFrame call-in.


Misc:
Expand Down
51 changes: 51 additions & 0 deletions rts/Lua/LuaHandle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#include <tracy/Tracy.hpp>
#include <tracy/TracyLua.hpp>

#include <algorithm>
#include <string>


Expand Down Expand Up @@ -710,6 +711,30 @@ void CLuaHandle::GamePaused(int playerID, bool paused)
RunCallInTraceback(L, cmdStr, 2, 0, traceBack.GetErrFuncIdx(), false);
}

void CLuaHandle::RunDelayedFunctions(int frameNum)
{
static const LuaHashString cmdStr(__func__);

const auto currentFrameIterator = delayedCallsByFrame.find(frameNum);
if (currentFrameIterator == delayedCallsByFrame.end())
return;

const auto& functions = currentFrameIterator->second;
for (const auto& [function, args] : functions) {
const LuaUtils::ScopedDebugTraceBack traceBack(L);
luaL_checkstack(L, args.size() + 3, __func__); // the +3 is cargo-cult, most other callins do it like that

lua_rawgeti(L, LUA_REGISTRYINDEX, function);
luaL_unref(L, LUA_REGISTRYINDEX, function);
for (const auto arg : args) {
lua_rawgeti(L, LUA_REGISTRYINDEX, arg);
luaL_unref(L, LUA_REGISTRYINDEX, arg);
}
RunCallInTraceback(L, cmdStr, (int) args.size(), 0, traceBack.GetErrFuncIdx(), false);
}

delayedCallsByFrame.erase(currentFrameIterator);
}

/*** Called for every game simulation frame (30 per second).
*
Expand All @@ -726,6 +751,8 @@ void CLuaHandle::GameFrame(int frameNum)
return;
}

RunDelayedFunctions(frameNum);

LUA_CALL_IN_CHECK(L);
luaL_checkstack(L, 4, __func__);

Expand Down Expand Up @@ -3611,6 +3638,7 @@ bool CLuaHandle::AddBasicCalls(lua_State* L)
HSTR_PUSH_CFUNC(L, "GetGlobal", CallOutGetGlobal);
HSTR_PUSH_CFUNC(L, "GetRegistry", CallOutGetRegistry);
HSTR_PUSH_CFUNC(L, "GetCallInList", CallOutGetCallInList);
HSTR_PUSH_CFUNC(L, "DelayByFrames", CallOutDelayByFrames);
HSTR_PUSH_CFUNC(L, "IsEngineMinVersion", CallOutIsEngineMinVersion);
// special team constants
HSTR_PUSH_NUMBER(L, "NO_ACCESS_TEAM", CEventClient::NoAccessTeam);
Expand Down Expand Up @@ -3709,6 +3737,29 @@ int CLuaHandle::CallOutIsEngineMinVersion(lua_State* L)
return (LuaUtils::IsEngineMinVersion(L));
}

int CLuaHandle::CallOutDelayByFrames(lua_State* L)
{
int argCount = lua_gettop(L);
if (argCount < 2 || !lua_isnumber(L, 1) || !lua_isfunction(L, 2))
luaL_error(L, "Incorrect arguments to DelayByFrames(positive number frameDelay, func[, args])");

const auto frameDelay = lua_tointeger(L, 1);
if (frameDelay <= 0)
luaL_error(L, "Incorrect arguments to DelayByFrames(positive number frameDelay, func[, args])");

argCount -= 2;

std::vector <int> args;
args.reserve(argCount);
while (argCount--)
args.push_back(luaL_ref(L, LUA_REGISTRYINDEX));
std::reverse(args.begin(), args.end()); // ref has stack semantics, but pcall expects the last arg at the top

GetHandle(L)->delayedCallsByFrame[gs->GetLuaSimFrame() + frameDelay]
.emplace_back(luaL_ref(L, LUA_REGISTRYINDEX), std::move(args));

return 0;
}

int CLuaHandle::CallOutGetCallInList(lua_State* L)
{
Expand Down
6 changes: 6 additions & 0 deletions rts/Lua/LuaHandle.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
#include "LuaHashString.h"
#include "lib/lua/include/LuaInclude.h" //FIXME needed for GetLuaContextData

#include <map>
#include <string>
#include <tuple>
#include <vector>

#define LUA_HANDLE_ORDER_RULES 100
Expand Down Expand Up @@ -326,6 +328,9 @@ class CLuaHandle : public CEventClient

std::string killMsg;

std::map <int, std::vector <std::pair <int, std::vector <int>>>> delayedCallsByFrame;
void RunDelayedFunctions(int frameNum);

std::vector<bool> watchUnitDefs; // callin masks for Unit*Collision, UnitMoveFailed
std::vector<bool> watchFeatureDefs; // callin masks for UnitFeatureCollision
std::vector<bool> watchProjectileDefs; // callin masks for Projectile*
Expand All @@ -347,6 +352,7 @@ class CLuaHandle : public CEventClient
static int CallOutGetCallInList(lua_State* L);
static int CallOutUpdateCallIn(lua_State* L);
static int CallOutIsEngineMinVersion(lua_State* L);
static int CallOutDelayByFrames(lua_State* L);

public: // static
#if (!defined(UNITSYNC) && !defined(DEDICATED))
Expand Down

0 comments on commit 784e417

Please sign in to comment.