mirror of
https://github.com/IntQuant/noita_entangled_worlds.git
synced 2025-10-19 07:03:16 +00:00
Spectator helps system.
This commit is contained in:
parent
5220185c3e
commit
c9f26a3f24
6 changed files with 236 additions and 33 deletions
|
@ -31,41 +31,44 @@ local function is_measure_perf_enabled()
|
|||
return false
|
||||
end
|
||||
|
||||
function ctx.add_hook(hook_name, system_name, fn)
|
||||
if rawget(ctx.hook, hook_name) == nil then
|
||||
local tbl = {}
|
||||
if is_measure_perf_enabled() then
|
||||
setmetatable(tbl, {
|
||||
__call = function (self, ...)
|
||||
for _, entry in ipairs(self) do
|
||||
local start_time = GameGetRealWorldTimeSinceStarted()
|
||||
entry.fn(...)
|
||||
local end_time = GameGetRealWorldTimeSinceStarted()
|
||||
local delta = (end_time-start_time) * 1000
|
||||
if delta > 0.02 then
|
||||
print("Hook "..hook_name.." took "..(delta).." ms to run for "..entry.system_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
else
|
||||
setmetatable(tbl, {
|
||||
__call = function (self, ...)
|
||||
for _, entry in ipairs(self) do
|
||||
entry.fn(...)
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
ctx.hook[hook_name] = tbl
|
||||
end
|
||||
table.insert(ctx.hook[hook_name], {fn=fn, system_name=system_name})
|
||||
end
|
||||
|
||||
function ctx.dofile_and_add_hooks(path, system_name)
|
||||
print("Loading "..path)
|
||||
system_name = system_name or path
|
||||
local result = dofile_once(path)
|
||||
for key, value in pairs(result) do
|
||||
if string.sub(key, 1, 3) == "on_" then
|
||||
local hook_name = key
|
||||
if rawget(ctx.hook, hook_name) == nil then
|
||||
local tbl = {}
|
||||
if is_measure_perf_enabled() then
|
||||
setmetatable(tbl, {
|
||||
__call = function (self, ...)
|
||||
for _, entry in ipairs(self) do
|
||||
local start_time = GameGetRealWorldTimeSinceStarted()
|
||||
entry.fn(...)
|
||||
local end_time = GameGetRealWorldTimeSinceStarted()
|
||||
local delta = (end_time-start_time) * 1000
|
||||
if delta > 0.02 then
|
||||
print("Hook "..hook_name.." took "..(delta).." ms to run for "..entry.system_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
else
|
||||
setmetatable(tbl, {
|
||||
__call = function (self, ...)
|
||||
for _, entry in ipairs(self) do
|
||||
entry.fn(...)
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
ctx.hook[hook_name] = tbl
|
||||
end
|
||||
table.insert(ctx.hook[hook_name], {fn=value, system_name=system_name})
|
||||
for hook_name, fn in pairs(result) do
|
||||
if string.sub(hook_name, 1, 3) == "on_" then
|
||||
ctx.add_hook(hook_name, system_name, fn)
|
||||
end
|
||||
end
|
||||
return result
|
||||
|
|
|
@ -12,8 +12,6 @@ local net = {}
|
|||
|
||||
net.net_handling = net_handling
|
||||
|
||||
ctx.lib.net = net
|
||||
|
||||
function net.update()
|
||||
reactor:update()
|
||||
end
|
||||
|
@ -39,6 +37,31 @@ function rpc_base.opts_everywhere()
|
|||
rpc_inner.opts.everywhere = true
|
||||
end
|
||||
|
||||
function rpc_base:create_var(name, cb_fn)
|
||||
local var = {}
|
||||
local rpc_name = "_set_var_"..name
|
||||
var.values = {}
|
||||
self.opts_reliable()
|
||||
self.opts_everywhere()
|
||||
self[rpc_name] = function(new_value)
|
||||
if cb_fn ~= nil then
|
||||
cb_fn(new_value)
|
||||
end
|
||||
var.values[ctx.rpc_peer_id] = new_value
|
||||
end
|
||||
local set_rpc = self[rpc_name]
|
||||
function var.set(new_value)
|
||||
if new_value ~= var.values[ctx.my_id] then
|
||||
set_rpc(new_value)
|
||||
var.values[ctx.my_id] = new_value
|
||||
end
|
||||
end
|
||||
ctx.add_hook("on_should_send_updates", "net_vars", function()
|
||||
set_rpc(var.values[ctx.my_id])
|
||||
end)
|
||||
return var
|
||||
end
|
||||
|
||||
local rpc_meta = {
|
||||
__newindex = function (t, k, v)
|
||||
table.insert(rpc_inner.rpcs, v)
|
||||
|
|
|
@ -162,6 +162,7 @@ function spectate.on_world_update()
|
|||
right_held = false
|
||||
end
|
||||
set_camera_pos()
|
||||
ctx.spectating_over_peer_id = camera_player_id
|
||||
end
|
||||
|
||||
return spectate
|
104
quant.ew/files/system/spectator_helps/shield_base.xml
Normal file
104
quant.ew/files/system/spectator_helps/shield_base.xml
Normal file
|
@ -0,0 +1,104 @@
|
|||
<Entity name="spectator_shield">
|
||||
|
||||
<HitboxComponent
|
||||
_tags="enabled_in_world"
|
||||
aabb_min_x="-4"
|
||||
aabb_max_x="4"
|
||||
aabb_min_y="-3"
|
||||
aabb_max_y="3"
|
||||
></HitboxComponent>
|
||||
|
||||
<InheritTransformComponent
|
||||
_tags="enabled_in_hand"
|
||||
use_root_parent="1"
|
||||
only_position="1"
|
||||
>
|
||||
<Transform
|
||||
position.x="0"
|
||||
position.y="-4" >
|
||||
</Transform>
|
||||
</InheritTransformComponent>
|
||||
|
||||
<ParticleEmitterComponent
|
||||
_tags="character,enabled_in_hand"
|
||||
emitted_material_name="plasma_fading"
|
||||
gravity.y="0.0"
|
||||
lifetime_min="0.1"
|
||||
lifetime_max="0.5"
|
||||
count_min="2"
|
||||
count_max="4"
|
||||
render_on_grid="1"
|
||||
fade_based_on_lifetime="1"
|
||||
area_circle_radius.max="75"
|
||||
area_circle_sector_degrees="30"
|
||||
cosmetic_force_create="0"
|
||||
airflow_force="0.5"
|
||||
airflow_time="0.1"
|
||||
airflow_scale="0.5"
|
||||
emission_interval_min_frames="1"
|
||||
emission_interval_max_frames="1"
|
||||
emit_cosmetic_particles="1"
|
||||
is_emitting="1" >
|
||||
</ParticleEmitterComponent>
|
||||
|
||||
<ParticleEmitterComponent
|
||||
_tags="character,enabled_in_hand,item_identified__LEGACY,shield_ring"
|
||||
emitted_material_name="plasma_fading"
|
||||
gravity.y="0.0"
|
||||
lifetime_min="0.02"
|
||||
lifetime_max="0.05"
|
||||
count_min="40"
|
||||
count_max="50"
|
||||
render_on_grid="1"
|
||||
fade_based_on_lifetime="1"
|
||||
area_circle_radius.min="75"
|
||||
area_circle_radius.max="75"
|
||||
area_circle_sector_degrees="30"
|
||||
cosmetic_force_create="0"
|
||||
airflow_force="0.3"
|
||||
airflow_time="0.01"
|
||||
airflow_scale="0.05"
|
||||
emission_interval_min_frames="0"
|
||||
emission_interval_max_frames="0"
|
||||
emit_cosmetic_particles="1"
|
||||
is_emitting="1" >
|
||||
</ParticleEmitterComponent>
|
||||
|
||||
<ParticleEmitterComponent
|
||||
_tags="character,shield_hit"
|
||||
emitted_material_name="plasma_fading"
|
||||
gravity.y="0.0"
|
||||
lifetime_min="0.3"
|
||||
lifetime_max="1"
|
||||
count_min="300"
|
||||
count_max="360"
|
||||
render_on_grid="1"
|
||||
fade_based_on_lifetime="1"
|
||||
area_circle_radius.min="75"
|
||||
area_circle_radius.max="75"
|
||||
area_circle_sector_degrees="30"
|
||||
cosmetic_force_create="0"
|
||||
airflow_force="2.8"
|
||||
airflow_time="0.03"
|
||||
airflow_scale="0.8"
|
||||
emission_interval_min_frames="0"
|
||||
emission_interval_max_frames="0"
|
||||
emit_cosmetic_particles="1"
|
||||
is_emitting="0" >
|
||||
</ParticleEmitterComponent>
|
||||
|
||||
<AudioComponent
|
||||
_tags="enabled_in_hand,item_identified"
|
||||
file="data/audio/Desktop/projectiles.bank"
|
||||
event_root="player_projectiles/shield"
|
||||
set_latest_event_position="1" >
|
||||
</AudioComponent>
|
||||
|
||||
<EnergyShieldComponent
|
||||
recharge_speed="0.1"
|
||||
energy_required_to_shield="0.5"
|
||||
radius="75.0"
|
||||
sector_degrees="30"
|
||||
>
|
||||
</EnergyShieldComponent>
|
||||
</Entity>
|
71
quant.ew/files/system/spectator_helps/spectator_helps.lua
Normal file
71
quant.ew/files/system/spectator_helps/spectator_helps.lua
Normal file
|
@ -0,0 +1,71 @@
|
|||
local rpc = net.new_rpc_namespace()
|
||||
|
||||
local shield_entities = {}
|
||||
|
||||
local function create_shield_for(spectator_peer_id, target_entity)
|
||||
local ent = EntityLoad("mods/quant.ew/files/system/spectator_helps/shield_base.xml")
|
||||
EntityAddChild(target_entity, ent)
|
||||
shield_entities[spectator_peer_id] = ent
|
||||
|
||||
-- EntityAddComponent2(ent, "EnergyShieldComponent", {})
|
||||
end
|
||||
|
||||
local spectating_which = rpc:create_var("spectating_which", function(new_value)
|
||||
if shield_entities[ctx.rpc_peer_id] ~= nil then
|
||||
EntityKill(shield_entities[ctx.rpc_peer_id])
|
||||
shield_entities[ctx.rpc_peer_id] = nil
|
||||
end
|
||||
if ctx.rpc_peer_id ~= new_value and new_value ~= nil then
|
||||
create_shield_for(ctx.rpc_peer_id, player_fns.peer_get_player_data(new_value).entity)
|
||||
end
|
||||
end)
|
||||
|
||||
local shield_angle = rpc:create_var("shield_angle", function(new_value)
|
||||
local shield_ent = shield_entities[ctx.rpc_peer_id]
|
||||
if shield_ent ~= nil then
|
||||
local x, y = EntityGetTransform(shield_ent)
|
||||
EntitySetTransform(shield_ent, x, y, new_value)
|
||||
end
|
||||
end)
|
||||
|
||||
local module = {}
|
||||
|
||||
local function is_acceptable_help_target(spectating_over)
|
||||
-- No helping myself
|
||||
if spectating_over == ctx.my_id then
|
||||
return false
|
||||
end
|
||||
-- No helping notplayers
|
||||
local player_data = ctx.players[spectating_over]
|
||||
if player_data.status == nil or not player_data.status.is_alive then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function module.on_world_update()
|
||||
local notplayer_active = GameHasFlagRun("ew_flag_notplayer_active")
|
||||
if notplayer_active and ctx.spectating_over_peer_id ~= nil and is_acceptable_help_target(ctx.spectating_over_peer_id) then
|
||||
spectating_which.set(ctx.spectating_over_peer_id)
|
||||
if GameGetFrameNum() % 6 == 3 then
|
||||
local mx, my = DEBUG_GetMouseWorld()
|
||||
local cx, cy = GameGetCameraPos()
|
||||
local dx, dy = mx - cx, my - cy
|
||||
local angle = math.atan2(dy, dx)
|
||||
shield_angle.set(angle)
|
||||
end
|
||||
else
|
||||
spectating_which.set(nil)
|
||||
end
|
||||
end
|
||||
|
||||
function module.on_local_player_spawn()
|
||||
-- Cleanup after restarts
|
||||
for _, child in ipairs(EntityGetAllChildren(ctx.my_player.entity) or {}) do
|
||||
if EntityGetName(child) == "spectator_shield" then
|
||||
EntityKill(child)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return module
|
|
@ -53,6 +53,7 @@ local function load_modules()
|
|||
if ctx.proxy_opt.game_mode == "local_health" then
|
||||
ctx.load_system("local_health")
|
||||
ctx.load_system("notplayer_ai")
|
||||
ctx.load_system("spectator_helps")
|
||||
end
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue