From a60a1f7aff72ad6e60fd5b65b6db21e6d1c428d0 Mon Sep 17 00:00:00 2001 From: bgkillas Date: Sat, 23 Nov 2024 11:30:58 -0500 Subject: [PATCH] fix most of item sync, fix some theoretical minor bugs in inventory sync/enemy sync --- quant.ew/files/system/enemy_sync.lua | 17 +++- quant.ew/files/system/item_sync.lua | 144 ++++++++++++++------------- quant.ew/init.lua | 3 +- 3 files changed, 93 insertions(+), 71 deletions(-) diff --git a/quant.ew/files/system/enemy_sync.lua b/quant.ew/files/system/enemy_sync.lua index aa7ac2b6..59e29829 100644 --- a/quant.ew/files/system/enemy_sync.lua +++ b/quant.ew/files/system/enemy_sync.lua @@ -49,6 +49,8 @@ local HpData = util.make_type({ f32 = {"hp", "max_hp"} }) +local wait_1_frame = false + local FULL_TURN = math.pi * 2 local frame = 0 @@ -358,12 +360,22 @@ function enemy_sync.on_world_update_host() end function enemy_sync.on_world_update_client() - if GameGetFrameNum() % 10 == 1 then - enemy_sync.client_cleanup() + if GameGetFrameNum() % 12 == 1 then + if wait_1_frame then + async(function() + wait(1) + enemy_sync.client_cleanup() + end) + else + enemy_sync.client_cleanup() + end end if GameGetFrameNum() % (60*60) == 1 then times_spawned_last_minute = {} end + if wait_1_frame then + wait_1_frame = false + end end local function sync_enemy(enemy_info_raw, force_no_cull) @@ -676,6 +688,7 @@ function rpc.handle_enemy_data(enemy_data) for _, enemy_info_raw in ipairs(enemy_data) do sync_enemy(enemy_info_raw, false) end + wait_1_frame = true end function rpc.handle_enemy_health(enemy_health_data) diff --git a/quant.ew/files/system/item_sync.lua b/quant.ew/files/system/item_sync.lua index a50bcf5c..38facf40 100644 --- a/quant.ew/files/system/item_sync.lua +++ b/quant.ew/files/system/item_sync.lua @@ -18,6 +18,10 @@ local pickup_handlers = {} local dead_entities = {} +local frame = {} + +local gid_last_frame_updated = {} + function rpc.open_chest(gid) local ent = item_sync.find_by_gid(gid) if ent ~= nil then @@ -87,25 +91,7 @@ end -- Try to guess if the item is in world. local function is_item_on_ground(item) - local has_physics = EntityGetComponent(item, "SimplePhysicsComponent") ~= nil or EntityGetComponent(item, "PhysicsBodyComponent") ~= nil - if has_physics then - -- Has at least one of phys components enabled, definitely in world. - return true, "has physics" - end - -- What if it's a new wand? - local spec = EntityGetFirstComponent(item, "SpriteParticleEmitterComponent") - if spec == nil then - -- All disabled, certainly not in world. - return false, "no spec component" - end - -- Ones in starter wands don't have any tags, ukko rock and co do. - if ComponentHasTag(spec, "enabled_in_hand") then - return false, "spec tags enabled_in_hand" - end - if ComponentHasTag(spec, "enabled_in_inventory") then - return false, "spec tags enabled_in_inventory" - end - return true, "other "..spec + return EntityGetRootEntity(item) == item end function item_sync.get_global_item_id(item) @@ -144,19 +130,14 @@ function item_sync.find_by_gid(gid) end function item_sync.remove_item_with_id_now(gid) - local global_items = EntityGetWithTag("ew_global_item") - for _, item in ipairs(global_items) do - local i_gid = item_sync.get_global_item_id(item) - if i_gid == gid then - --TODO properly note when actually was from a peer picking up a potion maybe - for _, audio in ipairs(EntityGetComponent(item, "AudioComponent") or {}) do - if string.sub(ComponentGetValue2(audio, "event_root"), 1, 10) == "collision/" then - EntitySetComponentIsEnabled(item, audio, false) - end + local item = item_sync.find_by_gid(gid) + if item ~= nil and is_item_on_ground(item) then + for _, audio in ipairs(EntityGetComponent(item, "AudioComponent") or {}) do + if string.sub(ComponentGetValue2(audio, "event_root"), 1, 10) == "collision/" then + EntitySetComponentIsEnabled(item, audio, false) end - EntityKill(item) - break end + EntityKill(item) end end @@ -229,10 +210,6 @@ function item_sync.make_item_global(item, instant, give_authority_to) if give_authority_to ~= nil then local itemcom = EntityGetFirstComponentIncludingDisabled(item, "ItemComponent") - if ComponentGetValue2(itemcom, "play_hover_animation") then - ComponentSetValue2(itemcom, "play_hover_animation", false) - ComponentSetValue2(itemcom, "play_spinning_animation", false) - end end ctx.item_prevent_localize[gid] = false @@ -312,35 +289,43 @@ function rpc.handle_death_data(death_data) end EntityInflictDamage(enemy_id, 1000000000, "DAMAGE_CURSE", "", "NONE", 0, 0, responsible_entity) -- Just to be sure - EntityKill(enemy_id) + async(function() + wait(1) + EntityKill(enemy_id) + end) end ::continue:: end end -local function send_item_positions() +local DISTANCE_LIMIT = 128 * 4 + +local function send_item_positions(all) local position_data = {} for _, item in ipairs(EntityGetWithTag("ew_global_item")) do local gid = item_sync.get_global_item_id(item) -- Only send info about items created by us. if is_my_item(gid) and is_item_on_ground(item) then - local x, y, r = EntityGetTransform(item) - local costcom = EntityGetFirstComponentIncludingDisabled(item, "ItemCostComponent") - local cost = 0 - if costcom ~= nil then - cost = ComponentGetValue2(costcom, "cost") - local mx, my = GameGetCameraPos() - if math.abs(mx - x) < 1024 and math.abs(my - y) < 1024 and EntityGetFirstComponentIncludingDisabled(item, "VariableStorageComponent", "ew_try_stealable") then - ComponentSetValue2(costcom, "stealable", true) - end - end local phys_info = util.get_phys_info(item, true) - if phys_info ~= nil then - position_data[gid] = {x, y, r, phys_info, cost} + local x, y = EntityGetTransform(item) + if (phys_info[1][1] ~= nil or phys_info[2][1] ~= nil or all) + and (#EntityGetInRadiusWithTag(x, y, DISTANCE_LIMIT, "ew_peer") ~= 0 + or #EntityGetInRadiusWithTag(x, y, DISTANCE_LIMIT, "polymorphed_player") ~= 0) then + local costcom = EntityGetFirstComponentIncludingDisabled(item, "ItemCostComponent") + local cost = 0 + if costcom ~= nil then + cost = ComponentGetValue2(costcom, "cost") + local mx, my = GameGetCameraPos() + if math.abs(mx - x) < 1024 and math.abs(my - y) < 1024 + and EntityGetFirstComponentIncludingDisabled(item, "VariableStorageComponent", "ew_try_stealable") then + ComponentSetValue2(costcom, "stealable", true) + end + end + position_data[gid] = {x, y, phys_info, cost} end end end - rpc.update_positions(position_data) + rpc.update_positions(position_data, all) if #dead_entities > 0 then rpc.handle_death_data(dead_entities) end @@ -396,17 +381,23 @@ function item_sync.on_world_update() item_sync.remove_item_with_id_now(gid) end end - if GameGetFrameNum() % 5 == 2 then + if GameGetFrameNum() % 60 == 35 then for _, ent in ipairs(EntityGetWithTag("mimic_potion")) do - if ctx.is_host and not EntityHasTag(ent, "polymorphed_player") then + if not EntityHasTag(ent, "polymorphed_player") and is_item_on_ground(ent) then if not EntityHasTag(ent, "ew_global_item") then - item_sync.make_item_global(ent) + if ctx.is_host then + item_sync.make_item_global(ent) + else + EntityKill(ent) + end end end end end - if GameGetFrameNum() % 5 == 3 then - send_item_positions() + if GameGetFrameNum() % 60 == 3 then + send_item_positions(true) + elseif GameGetFrameNum() % 5 == 3 then + send_item_positions(false) end end @@ -507,13 +498,6 @@ function rpc.item_globalize(item_data) ComponentSetValue2(damage_component, "wait_for_kill_flag_on_death", true) EntityAddComponent2(item, "LuaComponent", {_tags="ew_immortal", script_damage_about_to_be_received = "mods/quant.ew/files/resource/cbs/immortal.lua"}) end - if not is_my_item(item_data.gid) then - local itemcom = EntityGetFirstComponentIncludingDisabled(item, "ItemComponent") - if ComponentGetValue2(itemcom, "play_hover_animation") then - ComponentSetValue2(itemcom, "play_hover_animation", false) - ComponentSetValue2(itemcom, "play_spinning_animation", false) - end - end end rpc.opts_reliable() @@ -537,18 +521,36 @@ function rpc.item_localize_req(gid) item_sync.host_localize_item(gid, ctx.rpc_peer_id) end -function rpc.update_positions(position_data) - local LIMIT = 128 * 3 +local function cleanup(peer) + for gid, num in pairs(gid_last_frame_updated[peer]) do + if frame[peer] > num then + local item = item_sync.find_by_gid(gid) + if is_item_on_ground(item) then + EntityKill(item) + end + end + end + gid_last_frame_updated[peer] = {} +end + +function rpc.update_positions(position_data, all) + if frame[ctx.rpc_peer_id] == nil or all then + frame[ctx.rpc_peer_id] = GameGetFrameNum() + if gid_last_frame_updated[ctx.rpc_peer_id] == nil then + gid_last_frame_updated[ctx.rpc_peer_id] = {} + end + end local cx, cy = GameGetCameraPos() for gid, el in pairs(position_data) do - local x, y, r = el[1], el[2], el[3] - local phys_info = el[4] - local price = el[5] - if math.abs(x - cx) < LIMIT and math.abs(y - cy) < LIMIT then + local x, y = el[1], el[2] + if math.abs(x - cx) < DISTANCE_LIMIT and math.abs(y - cy) < DISTANCE_LIMIT then + gid_last_frame_updated[ctx.rpc_peer_id][gid] = frame[ctx.rpc_peer_id] + local phys_info = el[3] + local price = el[4] local item = item_sync.find_by_gid(gid) if item ~= nil then if not util.set_phys_info(item, phys_info) then - EntitySetTransform(item, x, y, r) + EntitySetTransform(item, x, y) end local costcom = EntityGetFirstComponentIncludingDisabled(item, "ItemCostComponent") if costcom ~= nil then @@ -569,6 +571,12 @@ function rpc.update_positions(position_data) end end end + if all then + async(function() + wait(1) + cleanup(ctx.rpc_peer_id) + end) + end end function rpc.request_send_again(gid) diff --git a/quant.ew/init.lua b/quant.ew/init.lua index 426b836b..1fd86fb6 100755 --- a/quant.ew/init.lua +++ b/quant.ew/init.lua @@ -310,7 +310,8 @@ local function on_world_pre_update_inner() player_fns.respawn_if_necessary() end - if ctx.events.new_player_just_connected or ctx.events.inventory_maybe_just_changed or (GameGetFrameNum() % 5 == 0 and inventory_helper.has_inventory_changed(ctx.my_player)) then + local sha_check = GameGetFrameNum() % 5 == 0 and inventory_helper.has_inventory_changed(ctx.my_player) + if ctx.events.new_player_just_connected or ctx.events.inventory_maybe_just_changed or sha_check then local inventory_state = player_fns.serialize_items(ctx.my_player) if inventory_state ~= nil then net.send_player_inventory(inventory_state)