fix most of item sync, fix some theoretical minor bugs in inventory sync/enemy sync

This commit is contained in:
bgkillas 2024-11-23 11:30:58 -05:00
parent b8e16e1f1f
commit a60a1f7aff
3 changed files with 93 additions and 71 deletions

View file

@ -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
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)

View file

@ -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
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
end
EntityKill(item)
break
end
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
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 phys_info = util.get_phys_info(item, true)
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
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}
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
if ctx.is_host then
item_sync.make_item_global(ent)
else
EntityKill(ent)
end
end
end
end
if GameGetFrameNum() % 5 == 3 then
send_item_positions()
end
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)

View file

@ -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)