Spectator helps system.

This commit is contained in:
IQuant 2024-08-27 19:54:54 +03:00
parent 5220185c3e
commit c9f26a3f24
6 changed files with 236 additions and 33 deletions

View file

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

View file

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

View file

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

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

View 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

View file

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