Merge branch 'master' of github.com:LuoTianOrange/noita_entangled_worlds

This commit is contained in:
LuoTianOrange 2024-09-17 04:51:53 +08:00
commit 67a8538a64
14 changed files with 147 additions and 43 deletions

View file

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

View file

@ -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 {}
}
}

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,20 @@
<Entity
tags="shop" >
<HitboxComponent
_tags="enabled_in_world"
aabb_min_x="-5"
aabb_min_y="-5"
aabb_max_x="5"
aabb_max_y="5"
damage_multiplier="1"
is_enemy="1"
is_item="0"
is_player="0"
offset.x="0"
offset.y="0"
/>
<InheritTransformComponent _tags="enabled_in_world"/>
<LuaComponent _tags="enabled_in_world" execute_every_n_frame="300" script_source_file="mods/quant.ew/files/system/gen_sync/tmp_shop_script.lua"/>
</Entity>

View file

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

View file

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

View file

@ -0,0 +1,32 @@
<Entity>
<ParticleEmitterComponent
emitted_material_name="spark_green"
gravity.y="0.0"
lifetime_min="2"
lifetime_max="5"
count_min="4"
count_max="4"
render_on_grid="1"
fade_based_on_lifetime="1"
area_circle_radius.min="0"
area_circle_radius.max="0"
cosmetic_force_create="0"
airflow_force="0.251"
airflow_time="1.01"
airflow_scale="0.05"
emission_interval_min_frames="1"
emission_interval_max_frames="1"
emit_cosmetic_particles="1"
image_animation_file="data/particles/image_emitters/animated_emitter_large.png"
image_animation_speed="3"
image_animation_loop="0"
is_emitting="1" >
</ParticleEmitterComponent>
<LifetimeComponent
lifetime="260" >
</LifetimeComponent>
</Entity>

View file

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

View file

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

View file

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

View file

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