Skip to content

Commit

Permalink
better deepcopy_object implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
estebanfer committed Aug 3, 2024
1 parent 4b1a8b2 commit 98cb792
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 16 deletions.
2 changes: 1 addition & 1 deletion docs/src/includes/_types.md
Original file line number Diff line number Diff line change
Expand Up @@ -3115,7 +3115,7 @@ array<[THEME](#THEME), 9> | [journal_progress_theme_slots](https://github.
[LiquidPhysics](#LiquidPhysics) | [liquid](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=liquid) |
int | [next_entity_uid](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=next_entity_uid) | Next entity spawned will have this uid
[RoomOwnersInfo](#RoomOwnersInfo) | [room_owners](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=room_owners) | Holds info about owned rooms and items (shops, challenge rooms, vault etc.)
any | [user_data](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=user_data) | You can put any arbitrary lua object here and it will work correctly in online multiplayer, by having a copy on each state and being copied when the game does.<br/>
any | [user_data](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=user_data) | You can store a table (or lua primitive) here and it will store data correctly in online multiplayer, by having a different copy on each state and being copied over when the game does.<br/>Doesn't support recursive tables / cyclic references. Metatables will be transferred by reference instead of being copied<br/>

## Texture types

Expand Down
45 changes: 41 additions & 4 deletions src/game_api/script/lua_backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
#include <fmt/format.h> // for format_error
#include <list> // for _List_iterator, _List_co...
#include <sol/sol.hpp> // for table_proxy, optional
#include <stack> // for stack
#include <tuple> // for get
#include <vector> // for vector
#include <sol/types.hpp>
#include <stack> // for stack
#include <tuple> // for get
#include <vector> // for vector

#include "aliases.hpp" // for IMAGE, JournalPageType
#include "bucket.hpp" // for Bucket
Expand Down Expand Up @@ -1871,6 +1872,42 @@ void LuaBackend::on_post(ON event)
}
}

sol::table deepcopy_lua_table(sol::state& sol_state, sol::table& from_r)
{
sol::table new_table(sol_state, sol::create);
for (auto& [k, v] : from_r.as<sol::table>())
{
if (v.is<sol::table>())
{
sol::table v_table = v.as<sol::table>();
new_table.raw_set(k, deepcopy_lua_table(sol_state, v_table));
}
else
{
new_table.raw_set(k, v);
}
}
auto maybe_metatable = from_r.raw_get<sol::optional<sol::table>>(sol::metatable_key);
if (maybe_metatable)
{
new_table.raw_set(sol::metatable_key, maybe_metatable.value());
}
return new_table;
}

inline sol::object deepcopy_lua(sol::state& sol_state, sol::object& from)
{
if (from.is<sol::table>())
{
auto from_t = from.as<sol::table>();
return deepcopy_lua_table(sol_state, from_t);
}
else
{
return from;
}
}

void LuaBackend::copy_locals(StateMemory* from, StateMemory* to)
{
if (!local_state_datas.contains(from))
Expand All @@ -1882,7 +1919,7 @@ void LuaBackend::copy_locals(StateMemory* from, StateMemory* to)
sol::object from_user_data = from_data.user_data;
if (from_user_data != sol::lua_nil)
{
to_data.user_data = (*vm)["deepcopy_object"](from_user_data);
to_data.user_data = deepcopy_lua(*vm, from_user_data);
}
}

Expand Down
10 changes: 0 additions & 10 deletions src/game_api/script/lua_vm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2266,16 +2266,6 @@ end
/// Initializes some seedeed run related values and loads the character select screen, as if starting a new seeded run after entering the seed.
lua["play_seeded"] = init_seeded;

lua.script(R"##(
function deepcopy_object(obj)
if type(obj) ~= 'table' then return obj end
local res = {}
for k, v in pairs(obj) do res[deepcopy_object(k)] = deepcopy_object(v) end
res = setmetatable(res, getmetatable(obj))
return res
end
)##");

/// Change layer at which the liquid spawns in, THIS FUNCTION NEEDS TO BE CALLED BEFORE THE LEVEL IS BUILD, otherwise collisions and other stuff will be wrong for the newly spawned liquid
/// This sadly also makes lavamanders extinct, since the logic for their spawn is harcoded to front layer with bunch of other unrelated stuff (you can still spawn them with script or place them directly in level files)
/// Everything should be working more or less correctly (report on community discord if you find something unusual)
Expand Down
3 changes: 2 additions & 1 deletion src/game_api/script/usertypes/state_lua.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,8 @@ void register_usertypes(sol::state& lua)
statememory_type["user_data"] = std::move(user_data);
/* StateMemory
// user_data
// You can put any arbitrary lua object here and it will work correctly in online multiplayer, by having a copy on each state and being copied when the game does.
// You can store a table (or lua primitive) here and it will store data correctly in online multiplayer, by having a different copy on each state and being copied over when the game does.
// Doesn't support recursive tables / cyclic references. Metatables will be transferred by reference instead of being copied
*/

lua.create_named_table("FADE", "NONE", 0, "OUT", 1, "LOAD", 2, "IN", 3);
Expand Down

0 comments on commit 98cb792

Please sign in to comment.