diff --git a/docs/capabilities.md b/docs/capabilities.md index dc86f1fc..29c61ea1 100644 --- a/docs/capabilities.md +++ b/docs/capabilities.md @@ -27,7 +27,7 @@ Used by: ## 'item_sync' capability Functions: - - `globalize(entity_id, instantly: bool)` + - `globalize(entity_id, instantly: bool | nil, give_authority_to: PeerId | nil)` - `register_pickup_handler(fn(local_item_id))` Provided by: diff --git a/noita-proxy/tangled/src/common.rs b/noita-proxy/tangled/src/common.rs index a5cf499d..af4c6bb5 100644 --- a/noita-proxy/tangled/src/common.rs +++ b/noita-proxy/tangled/src/common.rs @@ -1,23 +1,12 @@ //! Various common public types. -use std::{fmt::Display, time::Duration}; +use std::fmt::Display; use bitcode::{Decode, Encode}; /// Per-peer settings. Peers that are connected to the same host, as well as the host itself, should have the same settings. #[derive(Debug, Clone)] -pub struct Settings { - /// A single datagram will confirm at most this much messages. Default is 128. - pub confirm_max_per_message: usize, - /// How much time can elapse before another confirm is sent. - /// Confirms are also sent when enough messages are awaiting confirm. - /// Note that confirms also double as "heartbeats" and keep the connection alive, so this value should be much less than `connection_timeout`. - /// Default: 1 second. - pub confirm_max_period: Duration, - /// Peers will be disconnected after this much time without any datagrams from them has passed. - /// Default: 10 seconds. - pub connection_timeout: Duration, -} +pub struct Settings {} /// Tells how reliable a message is. #[derive(Encode, Decode, Clone, Copy, PartialEq, Debug)] @@ -95,11 +84,7 @@ impl Display for PeerId { impl Default for Settings { fn default() -> Self { - Self { - confirm_max_per_message: 128, - confirm_max_period: Duration::from_secs(1), - connection_timeout: Duration::from_secs(10), - } + Self {} } } diff --git a/noita-proxy/tangled/src/connection_manager.rs b/noita-proxy/tangled/src/connection_manager.rs index ba85b9b4..78f175d3 100644 --- a/noita-proxy/tangled/src/connection_manager.rs +++ b/noita-proxy/tangled/src/connection_manager.rs @@ -21,7 +21,7 @@ use quinn::{ pki_types::{CertificateDer, PrivatePkcs8KeyDer}, }, ClientConfig, ConnectError, Connecting, ConnectionError, Endpoint, Incoming, RecvStream, - ServerConfig, + ServerConfig, TransportConfig, }; use thiserror::Error; use tokio::io::{AsyncReadExt, AsyncWriteExt}; @@ -467,6 +467,10 @@ fn default_server_config() -> ServerConfig { let cert_der = CertificateDer::from(cert.cert); let priv_key = PrivatePkcs8KeyDer::from(cert.key_pair.serialize_der()); - let config = ServerConfig::with_single_cert(vec![cert_der.clone()], priv_key.into()).unwrap(); + let mut config = + ServerConfig::with_single_cert(vec![cert_der.clone()], priv_key.into()).unwrap(); + let mut transport_config = TransportConfig::default(); + transport_config.keep_alive_interval(Some(Duration::from_secs(10))); + config.transport_config(Arc::new(transport_config)); config } diff --git a/noita-proxy/tangled/src/lib.rs b/noita-proxy/tangled/src/lib.rs index 3c69b166..a679d3b3 100644 --- a/noita-proxy/tangled/src/lib.rs +++ b/noita-proxy/tangled/src/lib.rs @@ -159,8 +159,6 @@ mod test { async fn test_peer() { info!("Starting test_peer"); let settings = Some(Settings { - confirm_max_period: Duration::from_millis(100), - connection_timeout: Duration::from_millis(1000), ..Default::default() }); let addr = "127.0.0.1:56001".parse().unwrap(); @@ -194,8 +192,6 @@ mod test { #[test_log::test(tokio::test)] async fn test_broadcast() { let settings = Some(Settings { - confirm_max_period: Duration::from_millis(100), - connection_timeout: Duration::from_millis(1000), ..Default::default() }); let addr = "127.0.0.1:56002".parse().unwrap(); @@ -233,8 +229,6 @@ mod test { #[test_log::test(tokio::test)] async fn test_host_has_conn() { let settings = Some(Settings { - confirm_max_period: Duration::from_millis(100), - connection_timeout: Duration::from_millis(1000), ..Default::default() }); let addr = "127.0.0.1:56003".parse().unwrap(); diff --git a/quant.ew/files/system/enemy_sync.lua b/quant.ew/files/system/enemy_sync.lua index 62ea2306..19e2f907 100644 --- a/quant.ew/files/system/enemy_sync.lua +++ b/quant.ew/files/system/enemy_sync.lua @@ -313,7 +313,7 @@ function enemy_sync.client_cleanup() local frame = GameGetFrameNum() for remote_id, enemy_data in pairs(ctx.entity_by_remote_id) do if frame - enemy_data.frame > 60*1 then - print("Despawning stale "..remote_id.." "..enemy_data.id) + --print("Despawning stale "..remote_id.." "..enemy_data.id) EntityKill(enemy_data.id) ctx.entity_by_remote_id[remote_id] = nil end diff --git a/quant.ew/files/system/gen_sync/gen_sync.lua b/quant.ew/files/system/gen_sync/gen_sync.lua index 01370870..a933f809 100644 --- a/quant.ew/files/system/gen_sync/gen_sync.lua +++ b/quant.ew/files/system/gen_sync/gen_sync.lua @@ -42,7 +42,11 @@ local function run_spawn_fn(fn_name, x, y, ...) -- Function returns item's entity id. if fn_info.kind == "item" then local eid = ret - ctx.cap.item_sync.globalize(eid, false) + ctx.cap.item_sync.globalize(eid, true, ctx.rpc_peer_id) + -- Avoid item losing it's cost on host. + local x, y = EntityGetTransform(eid) + local minishop = EntityLoad("mods/quant.ew/files/system/gen_sync/tmp_shop_area.xml", x, y) + EntityAddChild(eid, minishop) end end diff --git a/quant.ew/files/system/gen_sync/tmp_shop_area.xml b/quant.ew/files/system/gen_sync/tmp_shop_area.xml new file mode 100644 index 00000000..4492ccbe --- /dev/null +++ b/quant.ew/files/system/gen_sync/tmp_shop_area.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/quant.ew/files/system/gen_sync/tmp_shop_script.lua b/quant.ew/files/system/gen_sync/tmp_shop_script.lua new file mode 100644 index 00000000..70dfccc3 --- /dev/null +++ b/quant.ew/files/system/gen_sync/tmp_shop_script.lua @@ -0,0 +1,7 @@ +-- Deletes the temporary shop entity after the world has been properly generated. + +local ent = GetUpdatedEntityID() +local x, y = EntityGetTransform(ent) +if DoesWorldExistAt(x-5, y-5, x+5, y+5) then + EntityKill(ent) +end diff --git a/quant.ew/files/system/item_sync.lua b/quant.ew/files/system/item_sync.lua index 15e5ff56..35e9d7b5 100644 --- a/quant.ew/files/system/item_sync.lua +++ b/quant.ew/files/system/item_sync.lua @@ -47,7 +47,6 @@ end function item_sync.get_global_item_id(item) local gid = EntityGetFirstComponentIncludingDisabled(item, "VariableStorageComponent", "ew_global_item_id") if gid == nil then - GamePrint("Item has no gid") return "unknown" end local ret = ComponentGetValue2(gid, "value_string") @@ -110,7 +109,7 @@ function item_sync.host_localize_item(gid, peer_id) rpc.item_localize(peer_id, gid) end -function item_sync.make_item_global(item, instant) +function item_sync.make_item_global(item, instant, give_authority_to) EntityAddTag(item, "ew_global_item") async(function() if not instant then @@ -126,6 +125,9 @@ function item_sync.make_item_global(item, instant) local gid if gid_component == nil then gid = allocate_global_id() + if give_authority_to ~= nil then + gid = give_authority_to..":"..gid + end EntityAddComponent2(item, "VariableStorageComponent", { _tags = "enabled_in_world,enabled_in_hand,enabled_in_inventory,ew_global_item_id", value_string = gid, @@ -317,7 +319,6 @@ end rpc.opts_reliable() function rpc.item_globalize(item_data) if is_safe_to_remove() then - print("remove in globalize") item_sync.remove_item_with_id_now(item_data.gid) end local item = inventory_helper.deserialize_single_item(item_data) diff --git a/quant.ew/files/system/local_health/entities/magical_symbol_player.xml b/quant.ew/files/system/local_health/entities/magical_symbol_player.xml new file mode 100644 index 00000000..fe5ed20b --- /dev/null +++ b/quant.ew/files/system/local_health/entities/magical_symbol_player.xml @@ -0,0 +1,32 @@ + + + + + + + + + + diff --git a/quant.ew/files/system/local_health/local_health.lua b/quant.ew/files/system/local_health/local_health.lua index 1386d8b4..9901f5d4 100644 --- a/quant.ew/files/system/local_health/local_health.lua +++ b/quant.ew/files/system/local_health/local_health.lua @@ -25,7 +25,7 @@ local function do_switch_effect(short) return end local x, y = EntityGetTransform(ctx.my_player.entity) - rpc.switch_effect(x, y) + rpc.switch_effect(x, y, short) if short then LoadGameEffectEntityTo(ctx.my_player.entity, "mods/quant.ew/files/system/local_health/notplayer/safe_effect2.xml") else @@ -315,8 +315,12 @@ function rpc.send_status(status) end rpc.opts_everywhere() -function rpc.switch_effect(x, y) - EntityLoad("data/entities/particles/image_emitters/magical_symbol_fast.xml", x, y) +function rpc.switch_effect(x, y, to_normal_player) + if to_normal_player then + EntityLoad("mods/quant.ew/files/system/local_health/entities/magical_symbol_player.xml", x, y) + else + EntityLoad("data/entities/particles/image_emitters/magical_symbol_fast.xml", x, y) + end end return module \ No newline at end of file diff --git a/quant.ew/files/system/notplayer_ai/damage_tracker.lua b/quant.ew/files/system/notplayer_ai/damage_tracker.lua new file mode 100644 index 00000000..7e7657f6 --- /dev/null +++ b/quant.ew/files/system/notplayer_ai/damage_tracker.lua @@ -0,0 +1,10 @@ +dofile_once("data/scripts/lib/utilities.lua") + +function damage_received( damage, desc, entity_who_caused, is_fatal ) + local entity_id = GetUpdatedEntityID() + local var = EntityGetFirstComponentIncludingDisabled(entity_id, "VariableStorageComponent", "ew_damage_tracker") + if var ~= nil then + local dtype = GetDamageDetails().damage_types + ComponentSetValue2(var, "value_int", dtype) + end +end \ No newline at end of file diff --git a/quant.ew/files/system/notplayer_ai/notplayer_ai.lua b/quant.ew/files/system/notplayer_ai/notplayer_ai.lua index 1b6d0abe..d4b6df2f 100644 --- a/quant.ew/files/system/notplayer_ai/notplayer_ai.lua +++ b/quant.ew/files/system/notplayer_ai/notplayer_ai.lua @@ -221,7 +221,7 @@ local function needs_douse(entity) if damage_model ~= nil then local hp = ComponentGetValue2(damage_model, "hp") local max_hp = ComponentGetValue2(damage_model, "max_hp") - if hp / max_hp <= 0.02 then + if hp / max_hp <= 0.05 then prot_toxic = true end end @@ -451,7 +451,17 @@ local function init_state() control_a = false, control_w = false, control_d = false, + + dtype = 0 } + EntityAddComponent2(ctx.my_player.entity, "LuaComponent", { + script_damage_received = "mods/quant.ew/files/system/notplayer_ai/damage_tracker.lua" + }) + EntityAddComponent2(ctx.my_player.entity, "VariableStorageComponent", { + _tags = "ew_damage_tracker", + name = "ew_damage_tracker", + value_int = 0, + }) end local target @@ -598,6 +608,15 @@ local function choose_movement() give_space = 100 end end + GamePrint(state.dtype) + if state.dtype == 32 then + if (dist > 0 and did_hit_2) or (dist < 0 and did_hit_1) then + give_space = give_space + 10 + else + swap_side = true + end + state.control_w = false + end end local function position_to_area_number(x, y) @@ -613,7 +632,7 @@ local function position_to_area_number(x, y) elseif y < 12975 and (x < 2726 or x > 4135 or y < 12800) then return 5 else - return 8 + return 6 end elseif tonumber(SessionNumbersGetValue("NEW_GAME_PLUS_COUNT")) > 0 then if y < 1199 then @@ -627,7 +646,7 @@ local function position_to_area_number(x, y) elseif y < 12975 and (x < 2726 or x > 4135 or y < 12800) then return 5 else - return 8 + return 6 end else if y < 1199 then @@ -1009,6 +1028,11 @@ end local kick_wait = 0 local function update() + local var = EntityGetFirstComponentIncludingDisabled(ctx.my_player.entity, "VariableStorageComponent", "ew_damage_tracker") + if GameGetFrameNum() % 30 == 0 then + ComponentSetValue2(var, "value_int", 0) + end + state.dtype = ComponentGetValue2(var, "value_int") -- No taking control back, even after pressing esc. ComponentSetValue2(state.control_component, "enabled", false) diff --git a/quant.ew/files/system/world_sync/world_sync.lua b/quant.ew/files/system/world_sync/world_sync.lua index 4519b7f7..c7191df8 100644 --- a/quant.ew/files/system/world_sync/world_sync.lua +++ b/quant.ew/files/system/world_sync/world_sync.lua @@ -24,6 +24,21 @@ local iter_slow = 0 local iter_slow_2 = 0 +local function do_benchmark() + local world_ffi = require("noitapatcher.nsew.world_ffi") + local grid_world = world_ffi.get_grid_world() + local chunk_map = grid_world.vtable.get_chunk_map(grid_world) + local start = GameGetRealWorldTimeSinceStarted() + local iters = 10000 + for i=1, iters do + world.encode_area(chunk_map, 0, 0, 128, 128, encode_area) + -- world_ffi.get_cell(chunk_map, 0, 0) + end + local end_time = GameGetRealWorldTimeSinceStarted() + local elapsed = (end_time - start) * 1000 * 1000 * 1000 / (iters * 128 * 128) + print("Benchmark:", elapsed, "ns/pixel") +end + function world_sync.on_world_initialized() local c = 0 while true do @@ -53,14 +68,18 @@ local function send_chunks(cx, cy, chunk_map) end end -local function get_all_chunks(ocx, ocy, pos_data, priority) +local function get_all_chunks(ocx, ocy, pos_data, priority, give_0) local grid_world = world_ffi.get_grid_world() local chunk_map = grid_world.vtable.get_chunk_map(grid_world) --local thread_impl = grid_world.mThreadImpl local int = 4 -- ctx.proxy_opt.world_sync_interval if GameGetFrameNum() % int == 0 then send_chunks(ocx, ocy, chunk_map) - net.proxy_bin_send(KEY_WORLD_END, string.char(priority)) + local pri = priority + if give_0 then + pri = 0 + end + net.proxy_bin_send(KEY_WORLD_END, string.char(pri)) elseif GameGetFrameNum() % int == 2 then if iter_fast == 0 then send_chunks(ocx + 1, ocy, chunk_map) @@ -163,16 +182,16 @@ function world_sync.on_world_update() local pos_data = ocx..":"..ocy..":"..cx..":"..cy if math.abs(cx - ocx) > 2 or math.abs(cy - ocy) > 2 then if GameGetFrameNum() % 3 ~= 2 then - get_all_chunks(cx, cy, pos_data, 16) + get_all_chunks(cx, cy, pos_data, 16, false) else - get_all_chunks(ocx, ocy, pos_data, 16) + get_all_chunks(ocx, ocy, pos_data, 16, true) end else local pri = 0 if EntityHasTag(ctx.my_player.entity, "ew_notplayer") then pri = 16 end - get_all_chunks(ocx, ocy, pos_data, pri) + get_all_chunks(ocx, ocy, pos_data, pri, true) end end