diff --git a/quant.ew/files/core/inventory_helper.lua b/quant.ew/files/core/inventory_helper.lua index 8e86a8a4..402a2741 100644 --- a/quant.ew/files/core/inventory_helper.lua +++ b/quant.ew/files/core/inventory_helper.lua @@ -420,10 +420,10 @@ function inventory_helper.set_item_data(item_data, player_data, local_ent) EntityAddComponent(item_entity, "LuaComponent", { script_throw_item = "mods/quant.ew/files/resource/cbs/throw_item.lua", }) - end - local notify = EntityGetFirstComponentIncludingDisabled(item_entity, "LuaComponent", "ew_notify_component") - if notify ~= nil then - EntityRemoveComponent(item_entity, notify) + local notify = EntityGetFirstComponentIncludingDisabled(item_entity, "LuaComponent", "ew_notify_component") + if notify ~= nil then + EntityRemoveComponent(item_entity, notify) + end end --print("Deserialized wand #"..tostring(k).." - Active? "..tostring(wandInfo.active)) diff --git a/quant.ew/files/core/player_fns.lua b/quant.ew/files/core/player_fns.lua index 74518689..50ed6c87 100644 --- a/quant.ew/files/core/player_fns.lua +++ b/quant.ew/files/core/player_fns.lua @@ -644,7 +644,7 @@ function player_fns.set_current_slot(slot_data, player_data) if (mActiveItem ~= item) then np.SetActiveHeldEntity(player_data.entity, item, false, false) end - return + return true end else print("something in inventory that is not an item") diff --git a/quant.ew/files/core/util.lua b/quant.ew/files/core/util.lua index db4e3945..673e7b94 100644 --- a/quant.ew/files/core/util.lua +++ b/quant.ew/files/core/util.lua @@ -402,7 +402,7 @@ function util.get_phys_info(entity, kill) local ret, info = pcall(serialize_phys_component, phys_component) if not ret and kill then EntityKill(entity) - return nil + return {{}, {}} end table.insert(phys_info, info) end @@ -415,7 +415,7 @@ function util.get_phys_info(entity, kill) local ret, info = pcall(serialize_phys_component, phys_component) if not ret and kill then EntityKill(entity) - return nil + return {{}, {}} end table.insert(phys_info_2, info) else diff --git a/quant.ew/files/system/enemy_sync.lua b/quant.ew/files/system/enemy_sync.lua index 59e29829..9e8a6c60 100644 --- a/quant.ew/files/system/enemy_sync.lua +++ b/quant.ew/files/system/enemy_sync.lua @@ -49,8 +49,6 @@ local HpData = util.make_type({ f32 = {"hp", "max_hp"} }) -local wait_1_frame = false - local FULL_TURN = math.pi * 2 local frame = 0 @@ -361,14 +359,7 @@ end function enemy_sync.on_world_update_client() 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 + enemy_sync.client_cleanup() end if GameGetFrameNum() % (60*60) == 1 then times_spawned_last_minute = {} @@ -674,10 +665,7 @@ function rpc.handle_death_data(death_data) end EntityInflictDamage(enemy_id, 1000000000, "DAMAGE_CURSE", "", "NONE", 0, 0, responsible_entity) -- Just to be sure - async(function() - wait(1) - EntityKill(enemy_id) - end) + EntityKill(enemy_id) end ::continue:: end @@ -688,7 +676,6 @@ 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 672c9963..14e45586 100644 --- a/quant.ew/files/system/item_sync.lua +++ b/quant.ew/files/system/item_sync.lua @@ -22,6 +22,8 @@ local frame = {} local gid_last_frame_updated = {} +local wait_on_send = {} + function rpc.open_chest(gid) local ent = item_sync.find_by_gid(gid) if ent ~= nil then @@ -46,7 +48,7 @@ end util.add_cross_call("ew_chest_opened", function(chest_id) local gid = item_sync.get_global_item_id(chest_id) - if gid ~= "unknown" then + if gid ~= nil then rpc.open_chest(gid) end end) @@ -97,10 +99,10 @@ end function item_sync.get_global_item_id(item) local gid = EntityGetFirstComponentIncludingDisabled(item, "VariableStorageComponent", "ew_global_item_id") if gid == nil then - return "unknown" + return nil end local ret = ComponentGetValue2(gid, "value_string") - return ret or "unknown" + return ret end function item_sync.remove_item_with_id(gid) @@ -110,7 +112,8 @@ end local find_by_gid_cache = {} function item_sync.find_by_gid(gid) if find_by_gid_cache[gid] ~= nil then - if EntityGetIsAlive(find_by_gid_cache[gid]) and EntityHasTag(find_by_gid_cache[gid], "ew_global_item") then + if EntityGetIsAlive(find_by_gid_cache[gid]) + and EntityHasTag(find_by_gid_cache[gid], "ew_global_item") and is_item_on_ground(find_by_gid_cache[gid]) then return find_by_gid_cache[gid] else find_by_gid_cache[gid] = nil @@ -119,14 +122,19 @@ function item_sync.find_by_gid(gid) --print("find_by_gid: searching") - local global_items = EntityGetWithTag("ew_global_item") - for _, item in ipairs(global_items) do + local candidate + for _, item in ipairs(EntityGetWithTag("ew_global_item") or {}) do local i_gid = item_sync.get_global_item_id(item) find_by_gid_cache[i_gid] = item if i_gid == gid then - return item + if is_item_on_ground(item) then + return item + else + candidate = item + end end end + return candidate end function item_sync.remove_item_with_id_now(gid) @@ -163,6 +171,11 @@ function item_sync.host_localize_item(gid, peer_id) item_sync.remove_item_with_id(gid) end rpc.item_localize(peer_id, gid) + if peer_id == ctx.my_id then + item_sync.take_authority(gid) + else + rpc.hand_authority_over_to(peer_id, gid) + end end local wait_for_gid = {} @@ -205,6 +218,7 @@ local function make_global(item, give_authority_to) ctx.item_prevent_localize[gid] = false rpc.item_globalize(item_data) + wait_on_send[gid] = nil end function item_sync.make_item_global(item, instant, give_authority_to) @@ -238,6 +252,10 @@ local function remove_client_items_from_world() end end +local function is_peers_item(gid, peer) + return string.sub(gid, 1, 16) == peer +end + local function is_my_item(gid) return string.sub(gid, 1, 16) == ctx.my_id end @@ -253,7 +271,9 @@ rpc.opts_everywhere() rpc.opts_reliable() function rpc.give_authority_to(gid, new_id) local item = item_sync.find_by_gid(gid) + find_by_gid_cache[gid] = nil if item ~= nil then + find_by_gid_cache[new_id] = item local var = EntityGetFirstComponentIncludingDisabled(item, "VariableStorageComponent", "ew_global_item_id") ComponentSetValue2(var, "value_string", new_id) end @@ -316,10 +336,7 @@ function rpc.handle_death_data(death_data) end EntityInflictDamage(enemy_id, 1000000000, "DAMAGE_CURSE", "", "NONE", 0, 0, responsible_entity) -- Just to be sure - async(function() - wait(1) - EntityKill(enemy_id) - end) + EntityKill(enemy_id) end ::continue:: end @@ -327,16 +344,18 @@ end local DISTANCE_LIMIT = 128 * 4 +local ignore = {} + local function send_item_positions(all) local position_data = {} local cx, cy = EntityGetTransform(ctx.my_player.entity) 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 + if gid ~= nil and is_my_item(gid) and is_item_on_ground(item) then local x, y = EntityGetTransform(item) local dx, dy = x - cx, y - cy - if dx * dx + dy * dy > 1024 * 1024 then + if (ignore[gid] == nil or ignore[gid] < GameGetFrameNum()) and dx * dx + dy * dy > 4 * DISTANCE_LIMIT * DISTANCE_LIMIT then local ent = EntityGetClosestWithTag(x, y, "ew_peer") local nx, ny local ndx, ndy @@ -351,6 +370,7 @@ local function send_item_positions(all) ndx, ndy = x - nx, y - ny end if ent == 0 or ndx * ndx + ndy * ndy > DISTANCE_LIMIT * DISTANCE_LIMIT then + ignore[gid] = GameGetFrameNum() + 60 goto continue end end @@ -358,11 +378,14 @@ local function send_item_positions(all) if data ~= nil then local peer = data.peer_id rpc.hand_authority_over_to(peer, gid) + ignore[gid] = nil + else + ignore[gid] = GameGetFrameNum() + 60 end else local phys_info = util.get_phys_info(item, true) - if ((phys_info[1] ~= nil and phys_info[1][1] ~= nil) - or (phys_info[2] ~= nil and phys_info[2][1] ~= nil) + 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 @@ -371,7 +394,7 @@ local function send_item_positions(all) if costcom ~= nil then cost = ComponentGetValue2(costcom, "cost") local mx, my = GameGetCameraPos() - if math.abs(mx - x) < 1024 and math.abs(my - y) < 1024 + if math.abs(mx - x) < DISTANCE_LIMIT * 2 and math.abs(my - y) < DISTANCE_LIMIT * 2 and EntityGetFirstComponentIncludingDisabled(item, "VariableStorageComponent", "ew_try_stealable") then ComponentSetValue2(costcom, "stealable", true) end @@ -399,11 +422,9 @@ function item_sync.on_world_update_host() item_sync.make_item_global(thrown_item) end local picked_item = get_global_ent("ew_picked") - if picked_item ~= nil and EntityHasTag(picked_item, "ew_global_item") - and EntityHasTag(EntityGetRootEntity(picked_item), "ew_peer") then + if picked_item ~= nil and EntityHasTag(picked_item, "ew_global_item") then local gid = item_sync.get_global_item_id(picked_item) item_sync.host_localize_item(gid, ctx.my_id) - item_sync.take_authority(gid) end remove_client_items_from_world() end @@ -419,11 +440,9 @@ function item_sync.on_world_update_client() end local picked_item = get_global_ent("ew_picked") - if picked_item ~= nil and EntityHasTag(picked_item, "ew_global_item") - and EntityHasTag(EntityGetRootEntity(picked_item), "ew_peer") then + if picked_item ~= nil and EntityHasTag(picked_item, "ew_global_item") then local gid = item_sync.get_global_item_id(picked_item) rpc.item_localize_req(gid) - item_sync.take_authority(gid) end remove_client_items_from_world() end @@ -471,9 +490,8 @@ function item_sync.on_should_send_updates() if not ctx.is_host then return end - local global_items = EntityGetWithTag("ew_global_item") local item_list = {} - for _, item in ipairs(global_items) do + for _, item in ipairs(EntityGetWithTag("ew_global_item") or {}) do if is_item_on_ground(item) and not EntityHasTag(item, "mimic_potion") then local item_data = inventory_helper.serialize_single_item(item) local gid = item_sync.get_global_item_id(item) @@ -548,7 +566,7 @@ function rpc.item_globalize(item_data) item_sync.remove_item_with_id_now(item_data.gid) end local n = item_sync.find_by_gid(item_data.gid) - if n ~= nil and EntityGetRootEntity(n) == n then + if n ~= nil then return end local item = inventory_helper.deserialize_single_item(item_data) @@ -593,10 +611,24 @@ local function cleanup(peer) local item = item_sync.find_by_gid(gid) if is_item_on_ground(item) then EntityKill(item) + gid_last_frame_updated[peer][gid] = nil + end + end + end + local is_duplicate = {} + for _, item in ipairs(EntityGetWithTag("ew_global_item") or {}) do + local gid = item_sync.get_global_item_id(item) + if gid ~= nil and is_peers_item(gid, peer) then + if (gid_last_frame_updated[peer] == nil or is_duplicate[gid]) and is_item_on_ground(item) then + EntityKill(item) + else + if is_duplicate[gid] then + EntityKill(is_duplicate[gid]) + end + is_duplicate[gid] = item end end end - gid_last_frame_updated[peer] = {} end function rpc.update_positions(position_data, all) @@ -628,20 +660,15 @@ function rpc.update_positions(position_data, all) ComponentSetValue2(costcom, "cost", price) end end - else + elseif wait_for_gid[gid] == nil then util.log("Requesting again "..gid) - if wait_for_gid[gid] == nil then - rpc.request_send_again(gid) - wait_for_gid[gid] = GameGetFrameNum() + 300 - end + rpc.request_send_again(gid) + wait_for_gid[gid] = GameGetFrameNum() + 300 end end end if all then - async(function() - wait(1) - cleanup(ctx.rpc_peer_id) - end) + cleanup(ctx.rpc_peer_id) end end @@ -654,7 +681,10 @@ function rpc.request_send_again(gid) util.log("Requested to send item again, but this item wasn't found: "..gid) return end - item_sync.make_item_global(item) + if wait_on_send[gid] == nil or wait_on_send[gid] < GameGetFrameNum() then + wait_on_send[gid] = GameGetFrameNum() + 240 + item_sync.make_item_global(item) + end end ctx.cap.item_sync = { diff --git a/quant.ew/files/system/local_health/local_health.lua b/quant.ew/files/system/local_health/local_health.lua index fea0b0b5..17ed2cdb 100644 --- a/quant.ew/files/system/local_health/local_health.lua +++ b/quant.ew/files/system/local_health/local_health.lua @@ -205,6 +205,22 @@ local function show_death_message() end end +local function reset_cast_state_if_has_any_other_item(player_data) + local inventory2Comp = EntityGetFirstComponentIncludingDisabled(player_data.entity, "Inventory2Component") + if inventory2Comp == nil then + return + end + local mActiveItem = ComponentGetValue2(inventory2Comp, "mActiveItem") + + for k, item in ipairs(inventory_helper.get_inventory_items(player_data, "inventory_quick") or {}) do + if item ~= mActiveItem then + np.SetActiveHeldEntity(player_data.entity, item) + np.SetActiveHeldEntity(player_data.entity, mActiveItem) + break + end + end +end + local function player_died() if ctx.my_player.entity == nil then return @@ -275,12 +291,13 @@ local function player_died() polymorph.switch_entity(ent + 1) remove_healthbar_locally() + inventory_helper.set_item_data(item_data, ctx.my_player, true) for _, child in ipairs(EntityGetAllChildren(ctx.my_player.entity) or {}) do if EntityGetName(child) == "cursor" or EntityGetName(child) == "notcursor" then EntitySetComponentIsEnabled(child, EntityGetFirstComponentIncludingDisabled(child, "SpriteComponent"), false) end end - inventory_helper.set_item_data(item_data, ctx.my_player, true) + reset_cast_state_if_has_any_other_item(ctx.my_player) remove_inventory_tags() perk_fns.update_perks_for_entity(perk_data, ctx.my_player.entity, allow_notplayer_perk) util.set_ent_health(ctx.my_player.entity, {max_hp, max_hp}) diff --git a/quant.ew/files/system/player_sync.lua b/quant.ew/files/system/player_sync.lua index 98254c7c..6c8fae66 100644 --- a/quant.ew/files/system/player_sync.lua +++ b/quant.ew/files/system/player_sync.lua @@ -18,6 +18,22 @@ function rpc.send_money_and_ingestion(money, ingestion_size) end end +local wait_on_send = 0 + +function rpc.request_items(peer_id) + if ctx.my_id == peer_id + and wait_on_send < GameGetFrameNum() then + wait_on_send = GameGetFrameNum() + 240 + inventory_helper.has_inventory_changed(ctx.my_player) + local inventory_state = player_fns.serialize_items(ctx.my_player) + if inventory_state ~= nil then + net.send_player_inventory(inventory_state) + end + end +end + +local wait_on_requst = {} + function rpc.player_update(input_data, pos_data, phys_info, current_slot, team) local peer_id = ctx.rpc_peer_id @@ -43,7 +59,12 @@ function rpc.player_update(input_data, pos_data, phys_info, current_slot, team) player_fns.deserialize_position(pos_data, phys_info, player_data) end if current_slot ~= nil then - player_fns.set_current_slot(current_slot, player_data) + if not player_fns.set_current_slot(current_slot, player_data) + and (wait_on_requst[player_data.peer_id] == nil or wait_on_requst[player_data.peer_id] < GameGetFrameNum()) then + print("slot empty, requesting items") + wait_on_requst[player_data.peer_id] = GameGetFrameNum() + 300 + rpc.request_items(player_data.peer_id) + end end end