summaryrefslogtreecommitdiff
path: root/library/LuaTools.cpp
diff options
context:
space:
mode:
authorAlexander Gavrilov2012-05-04 20:59:06 +0400
committerAlexander Gavrilov2012-05-04 20:59:06 +0400
commit7e01b004e9675fec417bee0eead7d3d0702395e6 (patch)
tree5d37f646154b15659e2db4cb5f3a515080aabc87 /library/LuaTools.cpp
parentd4d6349f48d01b31f59f94238d6656e3b5d08508 (diff)
downloaddfhack-7e01b004e9675fec417bee0eead7d3d0702395e6.tar.gz
dfhack-7e01b004e9675fec417bee0eead7d3d0702395e6.tar.bz2
dfhack-7e01b004e9675fec417bee0eead7d3d0702395e6.tar.xz
Implement timeouts in the core lua context, and quicksave script.
Diffstat (limited to 'library/LuaTools.cpp')
-rw-r--r--library/LuaTools.cpp129
1 files changed, 129 insertions, 0 deletions
diff --git a/library/LuaTools.cpp b/library/LuaTools.cpp
index 17ad0abd..10ff51ba 100644
--- a/library/LuaTools.cpp
+++ b/library/LuaTools.cpp
@@ -53,6 +53,7 @@ distribution.
#include "df/building.h"
#include "df/unit.h"
#include "df/item.h"
+#include "df/world.h"
#include <lua.h>
#include <lauxlib.h>
@@ -1412,13 +1413,135 @@ lua_State *DFHack::Lua::Open(color_ostream &out, lua_State *state)
return state;
}
+static int next_timeout_id = 0;
+static int frame_idx = 0;
+static std::multimap<int,int> frame_timers;
+static std::multimap<int,int> tick_timers;
+
+int DFHACK_TIMEOUTS_TOKEN = 0;
+
+static const char *const timeout_modes[] = {
+ "frames", "ticks", "days", "months", "years", NULL
+};
+
+int dfhack_timeout(lua_State *L)
+{
+ using df::global::world;
+ using df::global::enabler;
+
+ lua_Number time = luaL_checknumber(L, 1);
+ int mode = luaL_checkoption(L, 2, NULL, timeout_modes);
+ luaL_checktype(L, 3, LUA_TFUNCTION);
+ lua_settop(L, 3);
+
+ if (mode > 0 && !Core::getInstance().isWorldLoaded())
+ {
+ lua_pushnil(L);
+ return 1;
+ }
+
+ switch (mode)
+ {
+ case 2:
+ time *= 1200;
+ break;
+ case 3:
+ time *= 33600;
+ break;
+ case 4:
+ time *= 403200;
+ break;
+ default:;
+ }
+
+ int id = next_timeout_id++;
+ int delta = time;
+
+ if (delta <= 0)
+ luaL_error(L, "Invalid timeout: %d", delta);
+
+ if (mode)
+ tick_timers.insert(std::pair<int,int>(world->frame_counter+delta, id));
+ else
+ frame_timers.insert(std::pair<int,int>(frame_idx+delta, id));
+
+ lua_rawgetp(L, LUA_REGISTRYINDEX, &DFHACK_TIMEOUTS_TOKEN);
+ lua_swap(L);
+ lua_rawseti(L, -2, id);
+
+ lua_pushinteger(L, id);
+ return 1;
+}
+
+static void cancel_tick_timers()
+{
+ using Lua::Core::State;
+
+ Lua::StackUnwinder frame(State);
+ lua_rawgetp(State, LUA_REGISTRYINDEX, &DFHACK_TIMEOUTS_TOKEN);
+
+ for (auto it = tick_timers.begin(); it != tick_timers.end(); ++it)
+ {
+ lua_pushnil(State);
+ lua_rawseti(State, frame[1], it->second);
+ }
+
+ tick_timers.clear();
+}
+
void DFHack::Lua::Core::onStateChange(color_ostream &out, int code) {
if (!State) return;
+ switch (code)
+ {
+ case SC_MAP_UNLOADED:
+ case SC_WORLD_UNLOADED:
+ cancel_tick_timers();
+ break;
+
+ default:;
+ }
+
Lua::Push(State, code);
Lua::InvokeEvent(out, State, (void*)onStateChange, 1);
}
+void DFHack::Lua::Core::onUpdate(color_ostream &out)
+{
+ using df::global::world;
+
+ Lua::StackUnwinder frame(State);
+ lua_rawgetp(State, LUA_REGISTRYINDEX, &DFHACK_TIMEOUTS_TOKEN);
+
+ frame_idx++;
+
+ while (!frame_timers.empty() &&
+ frame_timers.begin()->first <= frame_idx)
+ {
+ int id = frame_timers.begin()->second;
+ frame_timers.erase(frame_timers.begin());
+
+ lua_rawgeti(State, frame[1], id);
+ lua_pushnil(State);
+ lua_rawseti(State, frame[1], id);
+
+ Lua::SafeCall(out, State, 0, 0);
+ }
+
+ while (!tick_timers.empty() &&
+ tick_timers.begin()->first <= world->frame_counter)
+ {
+ int id = tick_timers.begin()->second;
+ tick_timers.erase(tick_timers.begin());
+
+ lua_rawgeti(State, frame[1], id);
+ lua_pushnil(State);
+ lua_rawseti(State, frame[1], id);
+
+ Lua::SafeCall(out, State, 0, 0);
+ }
+}
+
void DFHack::Lua::Core::Init(color_ostream &out)
{
if (State)
@@ -1428,12 +1551,18 @@ void DFHack::Lua::Core::Init(color_ostream &out)
Lua::Open(out, State);
+ lua_newtable(State);
+ lua_rawsetp(State, LUA_REGISTRYINDEX, &DFHACK_TIMEOUTS_TOKEN);
+
// Register events
lua_rawgetp(State, LUA_REGISTRYINDEX, &DFHACK_DFHACK_TOKEN);
MakeEvent(State, (void*)onStateChange);
lua_setfield(State, -2, "onStateChange");
+ lua_pushcfunction(State, dfhack_timeout);
+ lua_setfield(State, -2, "timeout");
+
lua_pop(State, 1);
}