From a61dce59e20aeb3e1b086dde70bf6ab02a8d09c8 Mon Sep 17 00:00:00 2001 From: TimePath Date: Sat, 25 Jun 2016 13:04:43 +1000 Subject: [PATCH] Move MOVETYPE_FLY to ecs --- qcsrc/common/triggers/trigger/jumppads.qc | 1 + qcsrc/common/weapons/weapon/electro.qc | 9 +- qcsrc/dpdefs/doc.md | 15 ++++ qcsrc/ecs/_lib.inc | 57 +----------- qcsrc/ecs/_lib.qh | 57 ++++++++++++ qcsrc/ecs/components/physics.qh | 1 + qcsrc/ecs/systems/physics.qc | 100 ++++++++++++++++++++++ qcsrc/lib/_all.inc | 5 ++ qcsrc/lib/iter.qh | 23 ++++- qcsrc/lib/vector.qh | 11 +++ qcsrc/server/g_world.qc | 3 +- qcsrc/server/miscfunctions.qc | 3 +- qcsrc/server/sv_main.qc | 1 + 13 files changed, 222 insertions(+), 64 deletions(-) create mode 100644 qcsrc/ecs/_lib.qh diff --git a/qcsrc/common/triggers/trigger/jumppads.qc b/qcsrc/common/triggers/trigger/jumppads.qc index 8100f6b79..caa62e036 100644 --- a/qcsrc/common/triggers/trigger/jumppads.qc +++ b/qcsrc/common/triggers/trigger/jumppads.qc @@ -240,6 +240,7 @@ void trigger_push_touch(entity this) if (other.flags & FL_PROJECTILE) { other.angles = vectoangles (other.velocity); + other.com_phys_gravity_factor = 1; switch(other.movetype) { case MOVETYPE_FLY: diff --git a/qcsrc/common/weapons/weapon/electro.qc b/qcsrc/common/weapons/weapon/electro.qc index 09cb77c8b..1fc3cb4b1 100644 --- a/qcsrc/common/weapons/weapon/electro.qc +++ b/qcsrc/common/weapons/weapon/electro.qc @@ -202,8 +202,12 @@ void W_Electro_TouchExplode(entity this) W_Electro_Explode(this); } + +void sys_phys_update_single(entity this); + void W_Electro_Bolt_Think(entity this) { + sys_phys_update_single(this); if(time >= this.ltime) { this.use(this, NULL, NULL); @@ -252,6 +256,7 @@ void W_Electro_Bolt_Think(entity this) { this.nextthink = min(time + WEP_CVAR_PRI(electro, midaircombo_interval), this.ltime); } } else { this.nextthink = this.ltime; } + this.nextthink = time; } void W_Electro_Attack_Bolt(Weapon thiswep, entity actor) @@ -285,7 +290,7 @@ void W_Electro_Attack_Bolt(Weapon thiswep, entity actor) proj.projectiledeathtype = WEP_ELECTRO.m_id; setorigin(proj, w_shotorg); - proj.movetype = MOVETYPE_FLY; + if (IS_CSQC) proj.movetype = MOVETYPE_FLY; W_SetupProjVelocity_PRI(proj, electro); proj.angles = vectoangles(proj.velocity); settouch(proj, W_Electro_TouchExplode); @@ -296,6 +301,8 @@ void W_Electro_Attack_Bolt(Weapon thiswep, entity actor) CSQCProjectile(proj, true, PROJECTILE_ELECTRO_BEAM, true); MUTATOR_CALLHOOK(EditProjectile, actor, proj); + proj.com_phys_pos = proj.origin; + proj.com_phys_vel = proj.velocity; } void W_Electro_Orb_Touch(entity this) diff --git a/qcsrc/dpdefs/doc.md b/qcsrc/dpdefs/doc.md index 240eec0c1..01fa43aaf 100644 --- a/qcsrc/dpdefs/doc.md +++ b/qcsrc/dpdefs/doc.md @@ -55,6 +55,21 @@ float sound_starttime; # SVQC +Main loop: +* SV_Physics() + * StartFrame() + * if (force_retouch) + * foreach entity: + * .touch() + * foreach client: + * PlayerPreThink() + * .think() + * PlayerPostThink() + * foreach nonclient: + * .think() + * EndFrame() + + ``` .entity clientcamera; diff --git a/qcsrc/ecs/_lib.inc b/qcsrc/ecs/_lib.inc index ef8e67c58..726f693e9 100644 --- a/qcsrc/ecs/_lib.inc +++ b/qcsrc/ecs/_lib.inc @@ -1,59 +1,4 @@ -/** Components always interpolate from the previous state */ -#define COMPONENT(com) \ - void com_##com##_interpolate(entity it, float a); \ - .bool com_##com - -#define FOREACH_COMPONENT(com, body) FOREACH_ENTITY_FLOAT(com_##com, true, body) - - -#define EVENT(T, args) .bool evt_##T##_listener; .void args evt_##T - -#define emit(T, ...) \ - MACRO_BEGIN \ - FOREACH_ENTITY_FLOAT_ORDERED(evt_##T##_listener, true, it.evt_##T(__VA_ARGS__)); \ - MACRO_END - -#define subscribe(listener, T, fn) \ - MACRO_BEGIN \ - listener.evt_##T = (fn); \ - listener.evt_##T##_listener = true; \ - MACRO_END - - -/** - * framelimit 0 is no limit, interpolation does not apply - * framerate below minfps will result in less than 100% speed - */ -#define SYSTEM(sys, frameLimit, minfps) \ - void sys_##sys##_update(entity this, float dt); \ - float autocvar_xon_sys_##sys##_dt = ((frameLimit) ? (1 / (frameLimit)) : 0); \ - float autocvar_xon_sys_##sys##_minfps = (1 / (1 / (minfps))) - -#define SYSTEM_UPDATE(sys) \ - MACRO_BEGIN \ - static float t = 0; \ - float dt = autocvar_xon_sys_##sys##_dt; \ - float minfps = autocvar_xon_sys_##sys##_minfps; \ - static float accumulator = 0; \ - float a = 0; \ - if (dt) { \ - accumulator += min(frametime, 1 / (minfps)); \ - } else { \ - accumulator += frametime; \ - dt = accumulator; \ - a = 1; \ - } \ - while (accumulator >= dt) \ - { \ - time = t; \ - FOREACH_COMPONENT(sys, sys_##sys##_update(it, dt)); \ - t += dt; \ - accumulator -= dt; \ - } \ - if (!a) a = accumulator / dt; \ - FOREACH_COMPONENT(sys, com_##sys##_interpolate(it, a)); \ - MACRO_END - +#include "_lib.qh" #include "_mod.inc" #include "components/_mod.inc" diff --git a/qcsrc/ecs/_lib.qh b/qcsrc/ecs/_lib.qh new file mode 100644 index 000000000..a617c73b0 --- /dev/null +++ b/qcsrc/ecs/_lib.qh @@ -0,0 +1,57 @@ +#pragma once + +/** Components always interpolate from the previous state */ +#define COMPONENT(com) \ + void com_##com##_interpolate(entity it, float a); \ + .bool com_##com + +#define FOREACH_COMPONENT(com, body) FOREACH_ENTITY_FLOAT(com_##com, true, body) + + +#define EVENT(T, args) .bool evt_##T##_listener; .void args evt_##T + +#define emit(T, ...) \ + MACRO_BEGIN \ + FOREACH_ENTITY_FLOAT_ORDERED(evt_##T##_listener, true, it.evt_##T(__VA_ARGS__)); \ + MACRO_END + +#define subscribe(listener, T, fn) \ + MACRO_BEGIN \ + listener.evt_##T = (fn); \ + listener.evt_##T##_listener = true; \ + MACRO_END + + +/** + * framelimit 0 is no limit, interpolation does not apply + * framerate below minfps will result in less than 100% speed + */ +#define SYSTEM(sys, frameLimit, minfps) \ + void sys_##sys##_update(entity this, float dt); \ + float autocvar_xon_sys_##sys##_dt = ((frameLimit) ? (1 / (frameLimit)) : 0); \ + float autocvar_xon_sys_##sys##_minfps = (1 / (1 / (minfps))) + +#define SYSTEM_UPDATE(sys) \ + MACRO_BEGIN \ + static float t = 0; \ + float dt = autocvar_xon_sys_##sys##_dt; \ + float minfps = autocvar_xon_sys_##sys##_minfps; \ + static float accumulator = 0; \ + float a = 0; \ + if (dt) { \ + accumulator += min(frametime, 1 / (minfps)); \ + } else { \ + accumulator += frametime; \ + dt = accumulator; \ + a = 1; \ + } \ + while (accumulator >= dt) \ + { \ + time = t; \ + FOREACH_COMPONENT(sys, sys_##sys##_update(it, dt)); \ + t += dt; \ + accumulator -= dt; \ + } \ + if (!a) a = accumulator / dt; \ + FOREACH_COMPONENT(sys, com_##sys##_interpolate(it, a)); \ + MACRO_END diff --git a/qcsrc/ecs/components/physics.qh b/qcsrc/ecs/components/physics.qh index 14e010ab2..377e1d1d8 100644 --- a/qcsrc/ecs/components/physics.qh +++ b/qcsrc/ecs/components/physics.qh @@ -15,6 +15,7 @@ COMPONENT(phys); .float com_phys_friction; .vector com_phys_gravity; +.float com_phys_gravity_factor; // TODO: remove .bool com_phys_ground; .bool com_phys_air; diff --git a/qcsrc/ecs/systems/physics.qc b/qcsrc/ecs/systems/physics.qc index 14f1d30ab..7267a4864 100644 --- a/qcsrc/ecs/systems/physics.qc +++ b/qcsrc/ecs/systems/physics.qc @@ -4,9 +4,14 @@ .int disableclientprediction; void sys_phys_simulate(entity this, float dt); +void sys_phys_simulate_simple(entity this, float dt); void sys_phys_update(entity this, float dt) { + if (!IS_CLIENT(this)) { + sys_phys_simulate_simple(this, dt); + return; + } sys_in_update(this, dt); sys_phys_fix(this, dt); @@ -150,6 +155,7 @@ void sys_phys_update(entity this, float dt) this.lastclassname = this.classname; } +/** for players */ void sys_phys_simulate(entity this, float dt) { const vector g = -this.com_phys_gravity; @@ -391,3 +397,97 @@ void sys_phys_simulate(entity this, float dt) } PM_ClientMovement_Move(this); } + +.entity groundentity; +/** for other entities */ +void sys_phys_simulate_simple(entity this, float dt) +{ + vector mn = this.mins; + vector mx = this.maxs; + + vector g = '0 0 0'; + if (this.com_phys_gravity_factor && !g) g = '0 0 -1' * PHYS_GRAVITY(NULL); + + vector acc = this.com_phys_acc; + vector vel = this.com_phys_vel; + vector pos = this.com_phys_pos; + + // SV_Physics_Toss + + vel += g * dt; + + this.angles += dt * this.avelocity; + float movetime = dt; + for (int i = 0; i < MAX_CLIP_PLANES && movetime > 0; i++) { + vector push = vel * movetime; + vector p0 = pos; + vector p1 = p0 + push; + // SV_PushEntity + tracebox(p0, mn, mx, p1, MOVE_NORMAL, this); + if (!trace_startsolid) { + bool hit = trace_fraction < 1; + pos = trace_endpos; + entity ent = trace_ent; + // SV_LinkEdict_TouchAreaGrid + if (this.solid != SOLID_NOT) { + FOREACH_ENTITY_RADIUS_ORDERED(0.5 * (this.absmin + this.absmax), 0.5 * vlen(this.absmax - this.absmin), true, { + if (it.solid != SOLID_TRIGGER || it == this) continue; + if (gettouch(it) && boxesoverlap(it.absmin, it.absmax, this.absmin, this.absmax)) { + // SV_LinkEdict_TouchAreaGrid_Call + trace_allsolid = false; + trace_startsolid = false; + trace_fraction = 1; + trace_inwater = false; + trace_inopen = true; + trace_endpos = it.origin; + trace_plane_normal = '0 0 1'; + trace_plane_dist = 0; + trace_ent = this; + trace_dpstartcontents = 0; + trace_dphitcontents = 0; + trace_dphitq3surfaceflags = 0; + trace_dphittexturename = string_null; + gettouch(it)((other = this, it)); + vel = this.velocity; + } + }); + } + if (hit && this.solid >= SOLID_TRIGGER && (!IS_ONGROUND(this) || this.groundentity != ent)) { + // SV_Impact (ent, trace); + tracebox(p0, mn, mx, p1, MOVE_NORMAL, this); + void(entity) touched = gettouch(this); + if (touched && this.solid != SOLID_NOT) { + touched((other = ent, this)); + } + void(entity) touched2 = gettouch(ent); + if (this && ent && touched2 && ent.solid != SOLID_NOT) { + trace_endpos = ent.origin; + trace_plane_normal *= -1; + trace_plane_dist *= -1; + trace_ent = this; + trace_dpstartcontents = 0; + trace_dphitcontents = 0; + trace_dphitq3surfaceflags = 0; + trace_dphittexturename = string_null; + touched2((other = this, ent)); + } + } + } + // end SV_PushEntity + if (wasfreed(this)) { return; } + tracebox(p0, mn, mx, p1, MOVE_NORMAL, this); + if (trace_fraction == 1) { break; } + movetime *= 1 - min(1, trace_fraction); + ClipVelocity(vel, trace_plane_normal, vel, 1); + } + + this.com_phys_acc = acc; + this.com_phys_vel = vel; + this.com_phys_pos = pos; + setorigin(this, this.com_phys_pos); +} + +void sys_phys_update_single(entity this) +{ + sys_phys_simulate_simple(this, frametime); +} diff --git a/qcsrc/lib/_all.inc b/qcsrc/lib/_all.inc index d121f1e66..1d63a28e5 100644 --- a/qcsrc/lib/_all.inc +++ b/qcsrc/lib/_all.inc @@ -248,3 +248,8 @@ void isnt_bool(float this) { print(ftos(this)); } #define CSQC_Ent_Remove _CSQC_Ent_Remove #endif #undef ENGINE_EVENT + +#ifndef MENUQC + #include + #include +#endif diff --git a/qcsrc/lib/iter.qh b/qcsrc/lib/iter.qh index c21d02121..49c2a41e8 100644 --- a/qcsrc/lib/iter.qh +++ b/qcsrc/lib/iter.qh @@ -122,13 +122,19 @@ if (cond) LAMBDA(body) \ } \ } MACRO_END +#define MUTEX_LOCK(this) MACRO_BEGIN \ + if (this) LOG_SEVEREF("Loop mutex held by %s", this); \ + this = __FUNC__; \ +MACRO_END +#define MUTEX_UNLOCK(this) MACRO_BEGIN \ + this = string_null; \ +MACRO_END #define _FOREACH_ENTITY_FIND_UNORDERED(id, T, fld, match, cond, body) \ MACRO_BEGIN { \ - if (_FOREACH_ENTITY_FIND_##T##_##id##mutex) LOG_SEVEREF("Loop mutex held by %s", _FOREACH_ENTITY_FIND_##T##_##id##mutex); \ - _FOREACH_ENTITY_FIND_##T##_##id##mutex = __FUNC__; \ + MUTEX_LOCK(_FOREACH_ENTITY_FIND_##T##_##id##mutex); \ entity _foundchain_first = _findchain##T##_tofield(fld, match, _FOREACH_ENTITY_FIND_##T##_next##id); \ FOREACH_LIST(_foundchain, _FOREACH_ENTITY_FIND_##T##_next##id, cond, body); \ - _FOREACH_ENTITY_FIND_##T##_##id##mutex = string_null; \ + MUTEX_UNLOCK(_FOREACH_ENTITY_FIND_##T##_##id##mutex); \ } MACRO_END #define FOREACH_ENTITY(cond, body) ORDERED(FOREACH_ENTITY)(cond, body) @@ -154,9 +160,18 @@ #ifndef MENUQC entity(vector org, float rad, .entity tofield) _findchainradius_tofield = #22; -#define FOREACH_ENTITY_RADIUS(org, dist, cond, body) FOREACH_ENTITY_RADIUS_UNORDERED(org, dist, cond, body) +#define FOREACH_ENTITY_RADIUS(org, dist, cond, body) ORDERED(FOREACH_ENTITY_RADIUS)(org, dist, cond, body) .entity _FOREACH_ENTITY_FIND_radius_next; noref string _FOREACH_ENTITY_FIND_radius_mutex; #define FOREACH_ENTITY_RADIUS_UNORDERED(org, dist, cond, body) _FOREACH_ENTITY_FIND_UNORDERED(, radius, org, dist, cond, body) +.entity _FOREACH_ENTITY_FIND_radius_nexttmp; noref string _FOREACH_ENTITY_FIND_radius_tmpmutex; +#define FOREACH_ENTITY_RADIUS_ORDERED(org, dist, cond, body) \ +MACRO_BEGIN \ + entity _rev_first = NULL; \ + _FOREACH_ENTITY_FIND_UNORDERED(tmp, radius, org, dist, cond, (it._FOREACH_ENTITY_FIND_radius_nexttmp = _rev_first, _rev_first = it)); \ + MUTEX_LOCK(_FOREACH_ENTITY_FIND_radius_tmpmutex); \ + FOREACH_LIST(_rev, _FOREACH_ENTITY_FIND_radius_nexttmp, true, body); \ + MUTEX_UNLOCK(_FOREACH_ENTITY_FIND_radius_tmpmutex); \ +MACRO_END #endif #define FOREACH_ENTITY_FLOAT(fld, match, body) ORDERED(FOREACH_ENTITY_FLOAT)(fld, match, body) diff --git a/qcsrc/lib/vector.qh b/qcsrc/lib/vector.qh index 98b15115c..10e8ed8c4 100644 --- a/qcsrc/lib/vector.qh +++ b/qcsrc/lib/vector.qh @@ -131,6 +131,17 @@ vector vec_reflect(vector vel, vector norm, float bounce) return vel - (1 + bounce) * (vel * norm) * norm; } +vector vec_epsilon(vector this, float eps) +{ + if (this.x > -eps && this.x < eps) this.x = 0; + if (this.y > -eps && this.y < eps) this.y = 0; + if (this.z > -eps && this.z < eps) this.z = 0; + return this; +} + +#define ClipVelocity(in, normal, out, overbounce) \ + (out = vec_epsilon(vec_reflect(in, normal, (overbounce) - 1), 0.1)) + #ifndef MENUQC vector get_corner_position(entity box, int corner) { diff --git a/qcsrc/server/g_world.qc b/qcsrc/server/g_world.qc index c959bafd0..3ae2f27f3 100644 --- a/qcsrc/server/g_world.qc +++ b/qcsrc/server/g_world.qc @@ -1983,7 +1983,7 @@ string GotoMap(string m) return "Map switch will happen after scoreboard."; } - +void systems_update(); void EndFrame() { anticheat_endframe(); @@ -2015,6 +2015,7 @@ void EndFrame() PlayerState s = PS(it); s.ps_push(s, it); }); + systems_update(); } diff --git a/qcsrc/server/miscfunctions.qc b/qcsrc/server/miscfunctions.qc index 2c206cf1a..e4d9156f6 100644 --- a/qcsrc/server/miscfunctions.qc +++ b/qcsrc/server/miscfunctions.qc @@ -1031,8 +1031,7 @@ bool SUB_NoImpactCheck(entity this, entity toucher) // these stop the projectile from moving, so... if(trace_dphitcontents == 0) { - //dprint("A hit happened with zero hit contents... DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct.\n"); - LOG_TRACEF("A hit from a projectile happened with no hit contents! DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct. (edict: %d, classname: %s, origin: %s)\n", etof(this), this.classname, vtos(this.origin)); + LOG_TRACEF("A hit from a projectile happened with no hit contents! DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct. (edict: %i, classname: %s, origin: %v)", this, this.classname, this.origin); checkclient(this); } if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT) diff --git a/qcsrc/server/sv_main.qc b/qcsrc/server/sv_main.qc index 8b4d2c22c..dc2019792 100644 --- a/qcsrc/server/sv_main.qc +++ b/qcsrc/server/sv_main.qc @@ -154,6 +154,7 @@ float game_delay_last; bool autocvar_sv_autopause = true; float RedirectionThink(); +void systems_update(); void sys_phys_update(entity this, float dt); void StartFrame() { -- 2.39.2