void LuaChatForm::OnOptionClicked(int option) { SetMoney(1000000000); lua_State *l = Lua::manager->GetLuaState(); LUA_DEBUG_START(l); lua_getfield(l, LUA_REGISTRYINDEX, "PiAdverts"); assert(lua_istable(l, -1)); lua_pushinteger(l, GetAdvert()->ref); lua_gettable(l, -2); assert(!lua_isnil(l, -1)); lua_getfield(l, -1, "onChat"); assert(lua_isfunction(l, -1)); LuaObject<LuaChatForm>::PushToLua(this); lua_pushinteger(l, GetAdvert()->ref); lua_pushinteger(l, option); pi_lua_protected_call(l, 3, 0); lua_pop(l, 2); LUA_DEBUG_END(l, 0); }
void LuaEventQueueBase::Emit() { if (!m_events.size()) return; lua_State *l = Pi::luaManager->GetLuaState(); LUA_DEBUG_START(l); lua_getfield(l, LUA_REGISTRYINDEX, "PiEventQueue"); assert(lua_istable(l, -1)); lua_getfield(l, -1, m_name); assert(lua_istable(l, -1)); while (m_events.size()) { LuaEventBase *e = m_events.front(); m_events.pop_front(); lua_pushnil(l); while (lua_next(l, -2) != 0) { int top = lua_gettop(l); PrepareLuaStack(l, e); pi_lua_protected_call(l, lua_gettop(l) - top, 0); } delete e; } lua_pop(l, 2); LUA_DEBUG_END(l, 0); }
void Emit() { lua_State *l = Lua::manager->GetLuaState(); LUA_DEBUG_START(l); if (!_get_method_onto_stack(l, "_Emit")) return; pi_lua_protected_call(l, 0, 0); LUA_DEBUG_END(l, 0); }
static void _signal_trampoline(PropertyMap &map, const std::string &k, LuaRef ref, lua_State *l) { ref.PushCopyToStack(); lua_pushlstring(l, k.c_str(), k.size()); map.PushLuaTable(); lua_pushvalue(l, -2); lua_rawget(l, -2); lua_remove(l, -2); pi_lua_protected_call(l, 2, 0); }
static void _fail_callback(const std::string &error, void *userdata) { CallbackPair *cp = reinterpret_cast<CallbackPair*>(userdata); if (!cp->failCallback.IsValid()) return; cp->failCallback.PushCopyToStack(); lua_pushlstring(cp->lua, error.c_str(), error.size()); pi_lua_protected_call(cp->lua, 1, 0); delete cp; }
void LuaTimer::Tick() { assert(Pi::game); lua_State *l = Pi::luaManager->GetLuaState(); LUA_DEBUG_START(l); lua_getfield(l, LUA_REGISTRYINDEX, "PiTimerCallbacks"); if (lua_isnil(l, -1)) { lua_pop(l, 1); LUA_DEBUG_END(l, 0); return; } assert(lua_istable(l, -1)); double now = Pi::game->GetTime(); lua_pushnil(l); while (lua_next(l, -2)) { assert(lua_istable(l, -1)); lua_getfield(l, -1, "at"); double at = lua_tonumber(l, -1); lua_pop(l, 1); if (at <= now) { lua_getfield(l, -1, "callback"); pi_lua_protected_call(l, 0, 1); bool cancel = lua_toboolean(l, -1); lua_pop(l, 1); lua_getfield(l, -1, "every"); if (lua_isnil(l, -1) || cancel) { lua_pop(l, 1); lua_pushvalue(l, -2); lua_pushnil(l); lua_settable(l, -5); } else { double every = lua_tonumber(l, -1); lua_pop(l, 1); pi_lua_settable(l, "at", Pi::game->GetTime() + every); } } lua_pop(l, 1); } lua_pop(l, 1); LUA_DEBUG_END(l, 0); }
static void _success_callback(const Json &data, void *userdata) { CallbackPair *cp = reinterpret_cast<CallbackPair*>(userdata); if (!cp->successCallback.IsValid()) return; cp->successCallback.PushCopyToStack(); _json_to_lua(cp->lua, data); pi_lua_protected_call(cp->lua, 1, 0); delete cp; }
void LuaChatForm::Sold(Equip::Type t) { lua_State *l = Lua::manager->GetLuaState(); LUA_DEBUG_START(l); _get_trade_function(l, GetAdvert()->ref, "sold"); lua_pushinteger(l, GetAdvert()->ref); lua_pushstring(l, EnumStrings::GetString("EquipType", t)); pi_lua_protected_call(l, 2, 0); LUA_DEBUG_END(l, 0); }
void LuaChatForm::Bought(Equip::Type t) { lua_State *l = Lua::manager->GetLuaState(); LUA_DEBUG_START(l); _get_trade_function(l, GetAdvert()->ref, "bought"); lua_pushinteger(l, GetAdvert()->ref); lua_pushstring(l, LuaConstants::GetConstantString(l, "EquipType", t)); pi_lua_protected_call(l, 2, 0); LUA_DEBUG_END(l, 0); }
void LuaChatForm::OnClose() { StationAdvertForm::OnClose(); lua_State *l = Lua::manager->GetLuaState(); int ref = GetAdvert()->ref; LUA_DEBUG_START(l); if (m_commodityTradeWidget) { lua_getfield(l, LUA_REGISTRYINDEX, "PiAdverts"); assert(lua_istable(l, -1)); lua_pushinteger(l, ref); lua_gettable(l, -2); assert(!lua_isnil(l, -1)); lua_pushstring(l, "tradeWidgetFunctions"); lua_pushnil(l); lua_settable(l, -3); lua_pop(l, 2); } if (!AdTaken()) return; lua_getfield(l, LUA_REGISTRYINDEX, "PiAdverts"); assert(lua_istable(l, -1)); lua_pushinteger(l, ref); lua_gettable(l, -2); assert(!lua_isnil(l, -1)); lua_getfield(l, -1, "onDelete"); if (!lua_isnil(l, -1)) { lua_pushinteger(l, ref); pi_lua_protected_call(l, 1, 0); } else lua_pop(l, 1); lua_pop(l, 1); lua_pushinteger(l, ref); lua_pushnil(l); lua_settable(l, -3); lua_pop(l, 1); LUA_DEBUG_END(l, 0); }
inline void LuaEventQueueBase::DoEventCall(lua_State *l, LuaEventBase *e) { if (m_debugTimer) { int top = lua_gettop(l); lua_pushvalue(l, -1); lua_Debug ar; lua_getinfo(l, ">S", &ar); PrepareLuaStack(l, e); Uint32 start = SDL_GetTicks(); pi_lua_protected_call(l, lua_gettop(l) - top, 0); Uint32 end = SDL_GetTicks(); Pi::luaConsole->AddOutput(stringf("DEBUG: %0 %1{u}ms %2:%3{d}", m_name, end-start, ar.source, ar.linedefined)); } else { int top = lua_gettop(l); PrepareLuaStack(l, e); pi_lua_protected_call(l, lua_gettop(l) - top, 0); } }
void Queue(const char *event, const ArgsBase &args) { lua_State *l = Lua::manager->GetLuaState(); LUA_DEBUG_START(l); if (!_get_method_onto_stack(l, "Queue")) return; int top = lua_gettop(l); lua_pushstring(l, event); args.PrepareStack(); pi_lua_protected_call(l, lua_gettop(l) - top, 0); LUA_DEBUG_END(l, 0); }
std::string LuaNameGen::Surname(RefCountedPtr<Random> &rng) { lua_State *l = m_luaManager->GetLuaState(); if (!GetNameGenFunc(l, "Surname")) return DEFAULT_SURNAME; LuaObject<Random>::PushToLua(rng.Get()); pi_lua_protected_call(l, 1, 1); std::string surname = luaL_checkstring(l, -1); lua_pop(l, 1); return surname; }
Widget *Context::CallTemplate(const char *name, const LuaTable &args) { lua_State *l = m_lua->GetLuaState(); m_templateStore.PushCopyToStack(); const LuaTable t(l, -1); if (!t.Get<bool,const char *>(name)) return 0; t.PushValueToStack<const char*>(name); lua_pushvalue(l, args.GetIndex()); pi_lua_protected_call(m_lua->GetLuaState(), 1, 1); return LuaObject<UI::Widget>::CheckFromLua(-1); }
std::string LuaNameGen::FullName(bool isFemale, RefCountedPtr<Random> &rng) { lua_State *l = m_luaManager->GetLuaState(); if (!GetNameGenFunc(l, "FullName")) return isFemale ? DEFAULT_FULL_NAME_FEMALE : DEFAULT_FULL_NAME_MALE; lua_pushboolean(l, isFemale); LuaObject<Random>::PushToLua(rng.Get()); pi_lua_protected_call(l, 2, 1); std::string fullname = luaL_checkstring(l, -1); lua_pop(l, 1); return fullname; }
std::string LuaNameGen::BodyName(SystemBody *body, RefCountedPtr<Random> &rng) { lua_State *l = m_luaManager->GetLuaState(); if (!GetNameGenFunc(l, "BodyName")) return DEFAULT_BODY_NAME; LuaObject<SystemBody>::PushToLua(body); LuaObject<Random>::PushToLua(rng.Get()); pi_lua_protected_call(l, 2, 1); std::string bodyname = luaL_checkstring(l, -1); lua_pop(l, 1); return bodyname; }
void LuaSerializer::Serialize(Serializer::Writer &wr) { lua_State *l = Lua::manager->GetLuaState(); LUA_DEBUG_START(l); lua_newtable(l); int savetable = lua_gettop(l); lua_getfield(l, LUA_REGISTRYINDEX, "PiSerializerCallbacks"); if (lua_isnil(l, -1)) { lua_pop(l, 1); lua_newtable(l); lua_pushvalue(l, -1); lua_setfield(l, LUA_REGISTRYINDEX, "PiSerializerCallbacks"); } lua_pushnil(l); while (lua_next(l, -2) != 0) { lua_pushinteger(l, 1); lua_gettable(l, -2); pi_lua_protected_call(l, 0, 1); lua_pushvalue(l, -3); lua_insert(l, -2); lua_settable(l, savetable); lua_pop(l, 1); } lua_pop(l, 1); lua_newtable(l); lua_setfield(l, LUA_REGISTRYINDEX, "PiSerializerTableRefs"); std::string pickled; pickle(l, savetable, pickled); wr.String(pickled); lua_pop(l, 1); lua_pushnil(l); lua_setfield(l, LUA_REGISTRYINDEX, "PiSerializerTableRefs"); LUA_DEBUG_END(l, 0); }
void LuaSerializer::Unserialize(Serializer::Reader &rd) { lua_State *l = Lua::manager->GetLuaState(); LUA_DEBUG_START(l); lua_newtable(l); lua_setfield(l, LUA_REGISTRYINDEX, "PiSerializerTableRefs"); std::string pickled = rd.String(); const char *start = pickled.c_str(); const char *end = unpickle(l, start); if (size_t(end - start) != pickled.length()) throw SavedGameCorruptException(); if (!lua_istable(l, -1)) throw SavedGameCorruptException(); int savetable = lua_gettop(l); lua_pushnil(l); lua_setfield(l, LUA_REGISTRYINDEX, "PiSerializerTableRefs"); lua_getfield(l, LUA_REGISTRYINDEX, "PiSerializerCallbacks"); if (lua_isnil(l, -1)) { lua_pop(l, 1); lua_newtable(l); lua_pushvalue(l, -1); lua_setfield(l, LUA_REGISTRYINDEX, "PiSerializerCallbacks"); } lua_pushnil(l); while (lua_next(l, -2) != 0) { lua_pushvalue(l, -2); lua_pushinteger(l, 2); lua_gettable(l, -3); lua_getfield(l, savetable, lua_tostring(l, -2)); if (lua_isnil(l, -1)) { lua_pop(l, 1); lua_newtable(l); } pi_lua_protected_call(l, 1, 0); lua_pop(l, 2); } lua_pop(l, 2); LUA_DEBUG_END(l, 0); }
Sint64 LuaChatForm::GetPrice(Equip::Type t) const { lua_State *l = Lua::manager->GetLuaState(); LUA_DEBUG_START(l); _get_trade_function(l, GetAdvert()->ref, "getPrice"); lua_pushinteger(l, GetAdvert()->ref); lua_pushstring(l, EnumStrings::GetString("EquipType", t)); pi_lua_protected_call(l, 2, 1); Sint64 price = Sint64(lua_tonumber(l, -1) * 100.0); lua_pop(l, 1); LUA_DEBUG_END(l, 0); return price; }
int LuaChatForm::GetStock(Equip::Type t) const { lua_State *l = Lua::manager->GetLuaState(); LUA_DEBUG_START(l); _get_trade_function(l, GetAdvert()->ref, "getStock"); lua_pushinteger(l, GetAdvert()->ref); lua_pushstring(l, EnumStrings::GetString("EquipType", t)); pi_lua_protected_call(l, 2, 1); int stock = lua_tointeger(l, -1); lua_pop(l, 1); LUA_DEBUG_END(l, 0); return stock; }
bool LuaChatForm::DoesSell(Equip::Type t) const { lua_State *l = Lua::manager->GetLuaState(); LUA_DEBUG_START(l); _get_trade_function(l, GetAdvert()->ref, "canTrade"); lua_pushinteger(l, GetAdvert()->ref); lua_pushstring(l, EnumStrings::GetString("EquipType", t)); pi_lua_protected_call(l, 2, 1); bool can_trade = lua_toboolean(l, -1) != 0; lua_pop(l, 1); LUA_DEBUG_END(l, 0); return can_trade; }
/* * Method: RemoveAdvert * * Remove an advertisement from the station's bulletin board * * > station:RemoveAdvert(ref) * * If the deletefunc parameter was supplied to <AddAdvert> when the ad was * created, it will be called as part of this call. * * Parameters: * * ref - the advert reference number returned by <AddAdvert> * * Availability: * * alpha 10 * * Status: * * stable */ static int l_spacestation_remove_advert(lua_State *l) { LUA_DEBUG_START(l); SpaceStation *s = LuaSpaceStation::GetFromLua(1); int ref = luaL_checkinteger(l, 2); if (!s->RemoveBBAdvert(ref)) return 0; lua_getfield(l, LUA_REGISTRYINDEX, "PiAdverts"); if (lua_isnil(l, -1)) { lua_pop(l, 1); return 0; } lua_pushinteger(l, ref); lua_gettable(l, -2); if (lua_isnil(l, -1)) { lua_pop(l, 2); return 0; } lua_getfield(l, -1, "onDelete"); if (lua_isnil(l, -1)) lua_pop(l, 1); else { lua_pushinteger(l, ref); pi_lua_protected_call(l, 1, 0); } lua_pop(l, 1); lua_pushinteger(l, ref); lua_pushnil(l); lua_settable(l, -3); lua_pop(l, 1); LUA_DEBUG_END(l,0); return 0; }
void LuaSerializer::FromJson(const Json::Value &jsonObj) { if (!jsonObj.isMember("lua_modules")) throw SavedGameCorruptException(); lua_State *l = Lua::manager->GetLuaState(); LUA_DEBUG_START(l); std::string pickled = JsonToBinStr(jsonObj, "lua_modules"); const char *start = pickled.c_str(); const char *end = unpickle(l, start); if (size_t(end - start) != pickled.length()) throw SavedGameCorruptException(); if (!lua_istable(l, -1)) throw SavedGameCorruptException(); int savetable = lua_gettop(l); lua_getfield(l, LUA_REGISTRYINDEX, "PiSerializerCallbacks"); if (lua_isnil(l, -1)) { lua_pop(l, 1); lua_newtable(l); lua_pushvalue(l, -1); lua_setfield(l, LUA_REGISTRYINDEX, "PiSerializerCallbacks"); } lua_pushnil(l); while (lua_next(l, -2) != 0) { lua_pushvalue(l, -2); lua_pushinteger(l, 2); lua_gettable(l, -3); lua_getfield(l, savetable, lua_tostring(l, -2)); if (lua_isnil(l, -1)) { lua_pop(l, 1); lua_newtable(l); } pi_lua_protected_call(l, 1, 0); lua_pop(l, 2); } lua_pop(l, 2); LUA_DEBUG_END(l, 0); }
void LuaSerializer::ToJson(Json::Value &jsonObj) { PROFILE_SCOPED() lua_State *l = Lua::manager->GetLuaState(); LUA_DEBUG_START(l); lua_newtable(l); int savetable = lua_gettop(l); lua_getfield(l, LUA_REGISTRYINDEX, "PiSerializerCallbacks"); if (lua_isnil(l, -1)) { lua_pop(l, 1); lua_newtable(l); lua_pushvalue(l, -1); lua_setfield(l, LUA_REGISTRYINDEX, "PiSerializerCallbacks"); } lua_pushnil(l); while (lua_next(l, -2) != 0) { lua_pushinteger(l, 1); // 1, fntable, key lua_gettable(l, -2); // fn, fntable, key pi_lua_protected_call(l, 0, 1); // table, fntable, key lua_pushvalue(l, -3); // key, table, fntable, key lua_insert(l, -2); // table, key, fntable, key lua_settable(l, savetable); // fntable, key lua_pop(l, 1); } lua_pop(l, 1); std::string pickled; pickle(l, savetable, pickled); BinStrToJson(jsonObj, pickled, "lua_modules"); lua_pop(l, 1); LUA_DEBUG_END(l, 0); }
void LuaChatForm::OnClickSell(int t) { lua_State *l = Lua::manager->GetLuaState(); LUA_DEBUG_START(l); _get_trade_function(l, GetAdvert()->ref, "onClickSell"); lua_pushinteger(l, GetAdvert()->ref); lua_pushstring(l, EnumStrings::GetString("EquipType", t)); pi_lua_protected_call(l, 2, 1); bool allow_sell = lua_toboolean(l, -1) != 0; lua_pop(l, 1); LUA_DEBUG_END(l, 0); if (allow_sell) { if (BuyFrom(Pi::player, static_cast<Equip::Type>(t), true)) { Pi::Message(stringf(Lang::SOLD_1T_OF, formatarg("commodity", Equip::types[t].name))); } m_commodityTradeWidget->UpdateStock(t); } }
void LuaEventQueueBase::EmitSingleEvent(LuaEventBase *e) { lua_State *l = Pi::luaManager->GetLuaState(); LUA_DEBUG_START(l); lua_getfield(l, LUA_REGISTRYINDEX, "PiEventQueue"); assert(lua_istable(l, -1)); lua_getfield(l, -1, m_name); assert(lua_istable(l, -1)); lua_pushnil(l); while (lua_next(l, -2) != 0) { int top = lua_gettop(l); PrepareLuaStack(l, e); pi_lua_protected_call(l, lua_gettop(l) - top, 0); } lua_pop(l, 2); LUA_DEBUG_END(l, 0); delete e; }
static void _delete_station_ads(SpaceStation *s) { lua_State *l = Pi::luaManager->GetLuaState(); LUA_DEBUG_START(l); lua_getfield(l, LUA_REGISTRYINDEX, "PiAdverts"); assert(lua_istable(l, -1)); const std::list<const BBAdvert*> bbadverts = s->GetBBAdverts(); for (std::list<const BBAdvert*>::const_iterator i = bbadverts.begin(); i != bbadverts.end(); i++) { lua_pushinteger(l, (*i)->ref); lua_gettable(l, -2); if (lua_isnil(l, -1)) { lua_pop(l, 1); continue; } assert(lua_istable(l, -1)); lua_getfield(l, -1, "onDelete"); if (lua_isnil(l, -1)) lua_pop(l, 1); else { lua_pushinteger(l, (*i)->ref); pi_lua_protected_call(l, 1, 0); } lua_pop(l, 1); } lua_pop(l, 1); LUA_DEBUG_END(l, 0); _station_delete_conns.erase(s); }
void LuaSerializer::pickle(lua_State *l, int idx, std::string &out, const char *key = NULL) { static char buf[256]; LUA_DEBUG_START(l); idx = lua_absindex(l, idx); if (lua_getmetatable(l, idx)) { lua_getfield(l, -1, "class"); if (lua_isnil(l, -1)) lua_pop(l, 2); else { const char *cl = lua_tostring(l, -1); snprintf(buf, sizeof(buf), "o%s\n", cl); lua_getglobal(l, cl); if (lua_isnil(l, -1)) luaL_error(l, "No Serialize method found for class '%s'\n", cl); lua_getfield(l, -1, "Serialize"); if (lua_isnil(l, -1)) luaL_error(l, "No Serialize method found for class '%s'\n", cl); lua_pushvalue(l, idx); pi_lua_protected_call(l, 1, 1); lua_remove(l, idx); lua_insert(l, idx); lua_pop(l, 3); if (lua_isnil(l, idx)) { LUA_DEBUG_END(l, 0); return; } out += buf; } } switch (lua_type(l, idx)) { case LUA_TNIL: break; case LUA_TNUMBER: { snprintf(buf, sizeof(buf), "f%f\n", lua_tonumber(l, idx)); out += buf; break; } case LUA_TBOOLEAN: { snprintf(buf, sizeof(buf), "b%d", lua_toboolean(l, idx) ? 1 : 0); out += buf; break; } case LUA_TSTRING: { lua_pushvalue(l, idx); const char *str = lua_tostring(l, -1); snprintf(buf, sizeof(buf), "s" SIZET_FMT "\n", strlen(str)); out += buf; out += str; lua_pop(l, 1); break; } case LUA_TTABLE: { lua_pushinteger(l, lua_Integer(lua_topointer(l, idx))); // ptr lua_getfield(l, LUA_REGISTRYINDEX, "PiSerializerTableRefs"); // ptr reftable lua_pushvalue(l, -2); // ptr reftable ptr lua_rawget(l, -2); // ptr reftable ??? if (!lua_isnil(l, -1)) { out += "r"; pickle(l, -3, out, key); lua_pop(l, 3); // [empty] } else { out += "t"; lua_pushvalue(l, -3); // ptr reftable nil ptr lua_pushvalue(l, idx); // ptr reftable nil ptr table lua_rawset(l, -4); // ptr reftable nil pickle(l, -3, out, key); lua_pop(l, 3); // [empty] lua_pushvalue(l, idx); lua_pushnil(l); while (lua_next(l, -2)) { if (key) { pickle(l, -2, out, key); pickle(l, -1, out, key); } else { lua_pushvalue(l, -2); const char *k = lua_tostring(l, -1); pickle(l, -3, out, k); pickle(l, -2, out, k); lua_pop(l, 1); } lua_pop(l, 1); } lua_pop(l, 1); out += "n"; } break; } case LUA_TUSERDATA: { out += "u"; lid *idp = static_cast<lid*>(lua_touserdata(l, idx)); LuaObjectBase *lo = LuaObjectBase::Lookup(*idp); if (!lo) Error("Lua serializer '%s' tried to serialize object with id 0x%08x, but it no longer exists", key, *idp); // XXX object wrappers should really have Serialize/Unserialize // methods to deal with this if (lo->Isa("SystemPath")) { SystemPath *sbp = dynamic_cast<SystemPath*>(lo->m_object); snprintf(buf, sizeof(buf), "SystemPath\n%d\n%d\n%d\n%u\n%u\n", sbp->sectorX, sbp->sectorY, sbp->sectorZ, sbp->systemIndex, sbp->bodyIndex); out += buf; break; } if (lo->Isa("Body")) { Body *b = dynamic_cast<Body*>(lo->m_object); snprintf(buf, sizeof(buf), "Body\n%u\n", Pi::game->GetSpace()->GetIndexForBody(b)); out += buf; break; } Error("Lua serializer '%s' tried to serialize unsupported userdata value", key); break; } default: Error("Lua serializer '%s' tried to serialize %s value", key, lua_typename(l, lua_type(l, idx))); break; } LUA_DEBUG_END(l, 0); }
void LuaSerializer::pickle(lua_State *l, int to_serialize, std::string &out, std::string key) { static char buf[256]; LUA_DEBUG_START(l); // tables are pickled recursively, so we can run out of Lua stack space if we're not careful // start by ensuring we have enough (this grows the stack if necessary) // (20 is somewhat arbitrary) if (!lua_checkstack(l, 20)) luaL_error(l, "The Lua stack couldn't be extended (out of memory?)"); to_serialize = lua_absindex(l, to_serialize); int idx = to_serialize; if (lua_getmetatable(l, idx)) { lua_getfield(l, -1, "class"); if (lua_isnil(l, -1)) lua_pop(l, 2); else { const char *cl = lua_tostring(l, -1); snprintf(buf, sizeof(buf), "o%s\n", cl); lua_getfield(l, LUA_REGISTRYINDEX, "PiSerializerClasses"); lua_getfield(l, -1, cl); if (lua_isnil(l, -1)) luaL_error(l, "No Serialize method found for class '%s'\n", cl); lua_getfield(l, -1, "Serialize"); if (lua_isnil(l, -1)) luaL_error(l, "No Serialize method found for class '%s'\n", cl); lua_pushvalue(l, idx); pi_lua_protected_call(l, 1, 1); idx = lua_gettop(l); if (lua_isnil(l, idx)) { lua_pop(l, 5); LUA_DEBUG_END(l, 0); return; } out += buf; } } switch (lua_type(l, idx)) { case LUA_TNIL: break; case LUA_TNUMBER: { snprintf(buf, sizeof(buf), "f%f\n", lua_tonumber(l, idx)); out += buf; break; } case LUA_TBOOLEAN: { snprintf(buf, sizeof(buf), "b%d", lua_toboolean(l, idx) ? 1 : 0); out += buf; break; } case LUA_TSTRING: { lua_pushvalue(l, idx); size_t len; const char *str = lua_tolstring(l, -1, &len); snprintf(buf, sizeof(buf), "s" SIZET_FMT "\n", len); out += buf; out.append(str, len); lua_pop(l, 1); break; } case LUA_TTABLE: { lua_pushinteger(l, lua_Integer(lua_topointer(l, to_serialize))); // ptr lua_getfield(l, LUA_REGISTRYINDEX, "PiSerializerTableRefs"); // ptr reftable lua_pushvalue(l, -2); // ptr reftable ptr lua_rawget(l, -2); // ptr reftable ??? if (!lua_isnil(l, -1)) { out += "r"; pickle(l, -3, out, key); lua_pop(l, 3); // [empty] } else { out += "t"; lua_pushvalue(l, -3); // ptr reftable nil ptr lua_pushvalue(l, to_serialize); // ptr reftable nil ptr table lua_rawset(l, -4); // ptr reftable nil pickle(l, -3, out, key); lua_pop(l, 3); // [empty] lua_pushvalue(l, idx); lua_pushnil(l); while (lua_next(l, -2)) { lua_pushvalue(l, -2); const char *k = lua_tostring(l, -1); std::string new_key = key + "." + (k? std::string(k) : "<" + std::string(lua_typename(l, lua_type(l, -1))) + ">"); lua_pop(l, 1); // Copy the values to pickle, as they might be mutated by the pickling process. pickle(l, -2, out, new_key); pickle(l, -1, out, new_key); lua_pop(l, 1); } lua_pop(l, 1); out += "n"; } break; } case LUA_TUSERDATA: { out += "u"; LuaObjectBase *lo = static_cast<LuaObjectBase*>(lua_touserdata(l, idx)); void *o = lo->GetObject(); if (!o) Error("Lua serializer '%s' tried to serialize an invalid '%s' object", key.c_str(), lo->GetType()); out += lo->Serialize(); break; } default: Error("Lua serializer '%s' tried to serialize %s value", key.c_str(), lua_typename(l, lua_type(l, idx))); break; } if (idx != lua_absindex(l, to_serialize)) // It means we called a transformation function on the data, so we clean it up. lua_pop(l, 5); LUA_DEBUG_END(l, 0); }
const char *LuaSerializer::unpickle(lua_State *l, const char *pos) { LUA_DEBUG_START(l); char type = *pos++; switch (type) { case 'f': { char *end; double f = strtod(pos, &end); if (pos == end) throw SavedGameCorruptException(); lua_pushnumber(l, f); pos = end+1; // skip newline break; } case 'b': { if (*pos != '0' && *pos != '1') throw SavedGameCorruptException(); bool b = (*pos == '0') ? false : true; lua_pushboolean(l, b); pos++; break; } case 's': { char *end; int len = strtol(pos, const_cast<char**>(&end), 0); if (pos == end) throw SavedGameCorruptException(); end++; // skip newline lua_pushlstring(l, end, len); pos = end + len; break; } case 't': { lua_newtable(l); lua_getfield(l, LUA_REGISTRYINDEX, "PiSerializerTableRefs"); pos = unpickle(l, pos); lua_pushvalue(l, -3); lua_rawset(l, -3); lua_pop(l, 1); while (*pos != 'n') { pos = unpickle(l, pos); pos = unpickle(l, pos); lua_rawset(l, -3); } pos++; break; } case 'r': { pos = unpickle(l, pos); lua_getfield(l, LUA_REGISTRYINDEX, "PiSerializerTableRefs"); lua_pushvalue(l, -2); lua_rawget(l, -2); if (lua_isnil(l, -1)) throw SavedGameCorruptException(); lua_insert(l, -3); lua_pop(l, 2); break; } case 'u': { const char *end = strchr(pos, '\n'); if (!end) throw SavedGameCorruptException(); int len = end - pos; end++; // skip newline if (len == 10 && strncmp(pos, "SystemPath", 10) == 0) { pos = end; Sint32 sectorX = strtol(pos, const_cast<char**>(&end), 0); if (pos == end) throw SavedGameCorruptException(); pos = end+1; // skip newline Sint32 sectorY = strtol(pos, const_cast<char**>(&end), 0); if (pos == end) throw SavedGameCorruptException(); pos = end+1; // skip newline Sint32 sectorZ = strtol(pos, const_cast<char**>(&end), 0); if (pos == end) throw SavedGameCorruptException(); pos = end+1; // skip newline Uint32 systemNum = strtoul(pos, const_cast<char**>(&end), 0); if (pos == end) throw SavedGameCorruptException(); pos = end+1; // skip newline Uint32 sbodyId = strtoul(pos, const_cast<char**>(&end), 0); if (pos == end) throw SavedGameCorruptException(); pos = end+1; // skip newline SystemPath *sbp = new SystemPath(sectorX, sectorY, sectorZ, systemNum, sbodyId); LuaSystemPath::PushToLuaGC(sbp); break; } if (len == 4 && strncmp(pos, "Body", 4) == 0) { pos = end; Uint32 n = strtoul(pos, const_cast<char**>(&end), 0); if (pos == end) throw SavedGameCorruptException(); pos = end+1; // skip newline Body *body = Pi::game->GetSpace()->GetBodyByIndex(n); if (pos == end) throw SavedGameCorruptException(); switch (body->GetType()) { case Object::BODY: LuaBody::PushToLua(body); break; case Object::SHIP: LuaShip::PushToLua(dynamic_cast<Ship*>(body)); break; case Object::SPACESTATION: LuaSpaceStation::PushToLua(dynamic_cast<SpaceStation*>(body)); break; case Object::PLANET: LuaPlanet::PushToLua(dynamic_cast<Planet*>(body)); break; case Object::STAR: LuaStar::PushToLua(dynamic_cast<Star*>(body)); break; case Object::PLAYER: LuaPlayer::PushToLua(dynamic_cast<Player*>(body)); break; default: throw SavedGameCorruptException(); } break; } throw SavedGameCorruptException(); } case 'o': { const char *end = strchr(pos, '\n'); if (!end) throw SavedGameCorruptException(); int len = end - pos; end++; // skip newline const char *cl = pos; // unpickle the object, and insert it beneath the method table value pos = unpickle(l, end); // get _G[typename] lua_rawgeti(l, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS); lua_pushlstring(l, cl, len); lua_gettable(l, -2); lua_remove(l, -2); if (lua_isnil(l, -1)) { lua_pop(l, 2); break; } lua_getfield(l, -1, "Unserialize"); if (lua_isnil(l, -1)) { lua_pushlstring(l, cl, len); luaL_error(l, "No Unserialize method found for class '%s'\n", lua_tostring(l, -1)); } lua_insert(l, -3); lua_pop(l, 1); pi_lua_protected_call(l, 1, 1); break; } default: throw SavedGameCorruptException(); } LUA_DEBUG_END(l, 1); return pos; }