mirror of
https://github.com/IntQuant/noita_entangled_worlds.git
synced 2025-10-19 07:03:16 +00:00
Kinda sync enemies
This commit is contained in:
parent
b321f7e3f0
commit
69a12dd2c8
8 changed files with 147 additions and 10 deletions
5
README.md
Normal file
5
README.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# Noita Entangled Worlds
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Special thanks to @EvaisaDev for allowing to use code from Noita Arena mod.
|
|
@ -3,8 +3,10 @@ local ctx = {
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.init = function()
|
ctx.init = function()
|
||||||
|
ctx.host_id = 0
|
||||||
ctx.my_id = nil
|
ctx.my_id = nil
|
||||||
ctx.players = {}
|
ctx.players = {}
|
||||||
|
ctx.enemy_by_remote_id = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
return ctx
|
return ctx
|
87
files/src/enemy_sync.lua
Normal file
87
files/src/enemy_sync.lua
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
local util = dofile_once("mods/quant.ew/files/src/util.lua")
|
||||||
|
local ctx = dofile_once("mods/quant.ew/files/src/ctx.lua")
|
||||||
|
|
||||||
|
local enemy_sync = {}
|
||||||
|
|
||||||
|
local function world_exists_for(entity)
|
||||||
|
local x, y = EntityGetFirstHitboxCenter(entity)
|
||||||
|
local w, h = 5, 5 -- TODO
|
||||||
|
w = w * 0.5
|
||||||
|
h = h * 0.5
|
||||||
|
return DoesWorldExistAt(x - w, y - h, x + w, y + h)
|
||||||
|
end
|
||||||
|
|
||||||
|
function enemy_sync.host_upload_entities()
|
||||||
|
local enemy_list = EntityGetWithTag("enemy") -- TODO maybe only sync those close to players?
|
||||||
|
local enemy_data_list = {}
|
||||||
|
for i, enemy_id in ipairs(enemy_list) do
|
||||||
|
if not world_exists_for(enemy_id) then
|
||||||
|
goto continue
|
||||||
|
end
|
||||||
|
local filename = EntityGetFilename(enemy_id)
|
||||||
|
--print("ent "..enemy_id.." "..filename)
|
||||||
|
local x, y = EntityGetTransform(enemy_id)
|
||||||
|
local hp, max_hp = util.get_ent_health(enemy_id)
|
||||||
|
table.insert(enemy_data_list, {enemy_id, filename, x, y, hp, max_hp})
|
||||||
|
::continue::
|
||||||
|
end
|
||||||
|
--print(#enemy_data_list)
|
||||||
|
return enemy_data_list
|
||||||
|
end
|
||||||
|
|
||||||
|
function enemy_sync.client_cleanup()
|
||||||
|
local enemy_list = EntityGetWithTag("enemy")
|
||||||
|
for i, enemy_id in ipairs(enemy_list) do
|
||||||
|
if not EntityHasTag(enemy_id, "ew_replicated") then
|
||||||
|
print("Despawning unreplicated "..enemy_id)
|
||||||
|
EntityKill(enemy_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local frame = GameGetFrameNum()
|
||||||
|
for remote_id, enemy_data in pairs(ctx.enemy_by_remote_id) do
|
||||||
|
if frame - enemy_data.frame > 60*10 then
|
||||||
|
print("Despawning stale "..remote_id)
|
||||||
|
EntityKill(enemy_data.id)
|
||||||
|
ctx.enemy_by_remote_id[remote_id] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function enemy_sync.handle_enemy_data(enemy_data)
|
||||||
|
-- GamePrint("Got enemy data")
|
||||||
|
for _, enemy_info_raw in ipairs(enemy_data) do
|
||||||
|
local remote_enemy_id = enemy_info_raw[1]
|
||||||
|
local filename = enemy_info_raw[2]
|
||||||
|
local x = enemy_info_raw[3]
|
||||||
|
local y = enemy_info_raw[4]
|
||||||
|
local hp = enemy_info_raw[5]
|
||||||
|
local max_hp = enemy_info_raw[6]
|
||||||
|
|
||||||
|
local frame = GameGetFrameNum()
|
||||||
|
|
||||||
|
if ctx.enemy_by_remote_id[remote_enemy_id] ~= nil and not EntityGetIsAlive(ctx.enemy_by_remote_id[remote_enemy_id].id) then
|
||||||
|
ctx.enemy_by_remote_id[remote_enemy_id] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if ctx.enemy_by_remote_id[remote_enemy_id] == nil then
|
||||||
|
local enemy_id = EntityLoad(filename, x, y)
|
||||||
|
EntityAddTag(enemy_id, "ew_replicated")
|
||||||
|
ctx.enemy_by_remote_id[remote_enemy_id] = {id = enemy_id, frame = frame}
|
||||||
|
end
|
||||||
|
|
||||||
|
local enemy_data = ctx.enemy_by_remote_id[remote_enemy_id]
|
||||||
|
enemy_data.frame = frame
|
||||||
|
local enemy_id = enemy_data.id
|
||||||
|
local px, py = EntityGetTransform(enemy_id)
|
||||||
|
local tp_limit = 30
|
||||||
|
local alpha = 0.2
|
||||||
|
-- if math.pow(px-x, 2) + math.pow(py-y, 2) > math.pow(tp_limit, 2) then
|
||||||
|
EntitySetTransform(enemy_id, x, y)
|
||||||
|
-- else
|
||||||
|
-- EntitySetTransform(util.lerp(px, x, alpha), util.lerp(py, y, alpha))
|
||||||
|
-- end
|
||||||
|
util.set_ent_health(enemy_id, {hp, max_hp})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return enemy_sync
|
|
@ -99,4 +99,8 @@ function net.send_player_perks(perk_data)
|
||||||
net.send("perks", perk_data, true)
|
net.send("perks", perk_data, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function net.send_enemy_data(enemy_data)
|
||||||
|
net.send("enemy", enemy_data)
|
||||||
|
end
|
||||||
|
|
||||||
return net
|
return net
|
|
@ -1,5 +1,6 @@
|
||||||
local player_fns = dofile_once("mods/quant.ew/files/src/player_fns.lua")
|
local player_fns = dofile_once("mods/quant.ew/files/src/player_fns.lua")
|
||||||
local ctx = dofile_once("mods/quant.ew/files/src/ctx.lua")
|
local ctx = dofile_once("mods/quant.ew/files/src/ctx.lua")
|
||||||
|
local enemy_sync = dofile_once("mods/quant.ew/files/src/enemy_sync.lua")
|
||||||
local perk_fns = dofile_once("mods/quant.ew/files/src/perk_fns.lua")
|
local perk_fns = dofile_once("mods/quant.ew/files/src/perk_fns.lua")
|
||||||
|
|
||||||
local net_handling = {
|
local net_handling = {
|
||||||
|
@ -52,4 +53,10 @@ function net_handling.mod.perks(peer_id, perk_data)
|
||||||
perk_fns.update_perks(perk_data, player_data)
|
perk_fns.update_perks(perk_data, player_data)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function net_handling.mod.enemy(peer_id, enemy_data)
|
||||||
|
if peer_id == ctx.host_id then
|
||||||
|
enemy_sync.handle_enemy_data(enemy_data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return net_handling
|
return net_handling
|
|
@ -15,4 +15,31 @@ function util.set_ent_variable(entity, key, value)
|
||||||
ComponentSetValue2(storage, "value_string", bitser.dumps(value))
|
ComponentSetValue2(storage, "value_string", bitser.dumps(value))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function util.get_ent_health(entity)
|
||||||
|
local damage_model = EntityGetFirstComponentIncludingDisabled(entity, "DamageModelComponent")
|
||||||
|
if damage_model == 0 then
|
||||||
|
return 0, 0
|
||||||
|
end
|
||||||
|
local hp = ComponentGetValue2(damage_model, "hp")
|
||||||
|
local max_hp = ComponentGetValue2(damage_model, "max_hp")
|
||||||
|
return hp, max_hp
|
||||||
|
end
|
||||||
|
|
||||||
|
function util.set_ent_health(entity, hp_data)
|
||||||
|
local damage_model = EntityGetFirstComponentIncludingDisabled(entity, "DamageModelComponent")
|
||||||
|
if damage_model == 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if hp_data[1] ~= nil then
|
||||||
|
ComponentSetValue2(damage_model, "hp", hp_data[1])
|
||||||
|
end
|
||||||
|
if hp_data[2] ~= nil then
|
||||||
|
ComponentSetValue2(damage_model, "max_hp", hp_data[2])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function util.lerp(a, b, alpha)
|
||||||
|
return a * alpha + b * (1 - alpha)
|
||||||
|
end
|
||||||
|
|
||||||
return util
|
return util
|
16
init.lua
16
init.lua
|
@ -13,6 +13,7 @@ local net = dofile_once("mods/quant.ew/files/src/net.lua")
|
||||||
local ctx = dofile_once("mods/quant.ew/files/src/ctx.lua")
|
local ctx = dofile_once("mods/quant.ew/files/src/ctx.lua")
|
||||||
local pretty = dofile_once("mods/quant.ew/files/lib/pretty_print.lua")
|
local pretty = dofile_once("mods/quant.ew/files/lib/pretty_print.lua")
|
||||||
local perk_fns = dofile_once("mods/quant.ew/files/src/perk_fns.lua")
|
local perk_fns = dofile_once("mods/quant.ew/files/src/perk_fns.lua")
|
||||||
|
local enemy_sync = dofile_once("mods/quant.ew/files/src/enemy_sync.lua")
|
||||||
|
|
||||||
function OnProjectileFired(shooter_id, projectile_id, rng, position_x, position_y, target_x, target_y, send_message,
|
function OnProjectileFired(shooter_id, projectile_id, rng, position_x, position_y, target_x, target_y, send_message,
|
||||||
unknown1, multicast_index, unknown3)
|
unknown1, multicast_index, unknown3)
|
||||||
|
@ -77,14 +78,15 @@ function OnPlayerSpawned( player_entity ) -- This runs when player entity has be
|
||||||
GamePrint("My peer_id: "..ctx.my_id)
|
GamePrint("My peer_id: "..ctx.my_id)
|
||||||
ctx.players[ctx.my_id] = my_player
|
ctx.players[ctx.my_id] = my_player
|
||||||
ctx.ready = true
|
ctx.ready = true
|
||||||
|
ctx.is_host = ctx.my_id == ctx.host_id
|
||||||
|
|
||||||
np.SetPauseState(4)
|
np.SetPauseState(4)
|
||||||
np.SetPauseState(0)
|
np.SetPauseState(0)
|
||||||
|
|
||||||
dofile_once("data/scripts/perks/perk.lua")
|
dofile_once("data/scripts/perks/perk.lua")
|
||||||
local x, y = EntityGetFirstHitboxCenter(player_entity)
|
local x, y = EntityGetFirstHitboxCenter(player_entity)
|
||||||
perk_spawn(x, y, "LASER_AIM")
|
perk_spawn(x, y, "LASER_AIM", true)
|
||||||
perk_spawn(x-50, y, "GLASS_CANNON")
|
perk_spawn(x-50, y, "GLASS_CANNON", true)
|
||||||
end
|
end
|
||||||
|
|
||||||
function OnWorldPreUpdate() -- This is called every time the game is about to start updating the world
|
function OnWorldPreUpdate() -- This is called every time the game is about to start updating the world
|
||||||
|
@ -92,13 +94,21 @@ function OnWorldPreUpdate() -- This is called every time the game is about to st
|
||||||
-- GamePrint( "Pre-update hook " .. tostring(GameGetFrameNum()) )
|
-- GamePrint( "Pre-update hook " .. tostring(GameGetFrameNum()) )
|
||||||
|
|
||||||
net.update()
|
net.update()
|
||||||
if GameGetFrameNum() % 2 == 0 then
|
if GameGetFrameNum() % 1 == 0 then
|
||||||
local input_data = player_fns.serialize_inputs(my_player)
|
local input_data = player_fns.serialize_inputs(my_player)
|
||||||
local pos_data = player_fns.serialize_position(my_player)
|
local pos_data = player_fns.serialize_position(my_player)
|
||||||
local current_slot = player_fns.get_current_slot(my_player)
|
local current_slot = player_fns.get_current_slot(my_player)
|
||||||
net.send_player_update(input_data, pos_data, current_slot)
|
net.send_player_update(input_data, pos_data, current_slot)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if GameGetFrameNum() % 2 == 1 then
|
||||||
|
if ctx.is_host then
|
||||||
|
net.send_enemy_data(enemy_sync.host_upload_entities())
|
||||||
|
else
|
||||||
|
enemy_sync.client_cleanup()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if GameGetFrameNum() % 120 == 0 then
|
if GameGetFrameNum() % 120 == 0 then
|
||||||
local inventory_state = player_fns.serialize_items(my_player)
|
local inventory_state = player_fns.serialize_items(my_player)
|
||||||
net.send_player_inventory(inventory_state)
|
net.send_player_inventory(inventory_state)
|
||||||
|
|
9
todo.txt
9
todo.txt
|
@ -1,15 +1,10 @@
|
||||||
+ Синхронизация перков
|
+ Синхронизация перков
|
||||||
#- ShotEffectComponent
|
k Синхронизация противников
|
||||||
- Общее хп
|
- Общее хп
|
||||||
- Синхронизация хп
|
- Синхронизация хп
|
||||||
- Проверка окончания игры
|
- Проверка окончания игры
|
||||||
- Удаление лишних клиентов при загрузке игры
|
- Удаление лишних клиентов при загрузке игры
|
||||||
|
|
||||||
#- Immunities
|
|
||||||
#- Sectors
|
|
||||||
#- Telekenesis
|
|
||||||
#- Unli
|
|
||||||
|
|
||||||
- Fix weird no gui mode
|
- Fix weird no gui mode
|
||||||
|
|
||||||
- Figure out what to do with one-off perks,
|
- Figure out what to do with one-off perks,
|
||||||
|
@ -22,10 +17,10 @@
|
||||||
+ ...и текущего предмета
|
+ ...и текущего предмета
|
||||||
- reliability
|
- reliability
|
||||||
+ Сжатие пакетов
|
+ Сжатие пакетов
|
||||||
- Синхронизация противников
|
|
||||||
- Перекидывание предметов
|
- Перекидывание предметов
|
||||||
- Синхронизация мира
|
- Синхронизация мира
|
||||||
? Фикс наведения на клиентов
|
? Фикс наведения на клиентов
|
||||||
- fungal shift-ы
|
- fungal shift-ы
|
||||||
|
- orbs sync
|
||||||
- test tangled better
|
- test tangled better
|
||||||
- poly on clients
|
- poly on clients
|
Loading…
Add table
Add a link
Reference in a new issue