From 134b0134bd665f5cdcab61e88ce8c97bbcf0e138 Mon Sep 17 00:00:00 2001 From: bones_was_here Date: Mon, 18 Sep 2023 22:12:01 +1000 Subject: [PATCH] Rewrite the QC port of droptofloor() This uses DP_QC_NUDGEOUTOFSOLID to achieve better results (especially noticeable with sv_legacy_bbox_expand 0) in less CPU time. Documents the design. Removes legacy code paths. Adds warnings for badly placed items. Implements Quake-compliant behaviour for each BSP format. See also: https://gitlab.com/xonotic/darkplaces/-/merge_requests/144 Removes hacky workaround for #2774 and thus depends on !1245 Signed-off-by: bones_was_here --- qcsrc/server/world.qc | 146 ++++++++++++++++++++++++++---------------- qcsrc/server/world.qh | 2 - 2 files changed, 92 insertions(+), 56 deletions(-) diff --git a/qcsrc/server/world.qc b/qcsrc/server/world.qc index 7bbbfa0dd..1562d00a2 100644 --- a/qcsrc/server/world.qc +++ b/qcsrc/server/world.qc @@ -2300,16 +2300,55 @@ void InitializeEntitiesRun() delete_fn = remove_unsafely; } -// deferred dropping -// ported from VM_SV_droptofloor TODO: make a common function for the client-side? -void DropToFloor_Handler(entity this) +// originally ported from DP's droptofloor() builtin +// TODO: make a common function for the client-side? +// bones_was_here: when we have a use case for it, yes +void DropToFloor_QC(entity this) { + int nudgeresult; + if(!this || wasfreed(this)) { - // no modifying free entities + LOG_WARN("DropToFloor_QC: can not modify free entity"); return; } + /* Prior to sv_legacy_bbox_expand 0, both droptofloor and nudgeoutofsolid were done for items + * using box '-16 -16 0' '16 16 48' (without the FL_ITEM expansion applied), + * which often resulted in bboxes partially in solids once expansion was applied. + * We don't want bboxes in solids (bad for gameplay and culling), + * but we also don't want items to land on a "skirting board" or the base of a sloping wall. + * For initial nudgeoutofsolid and droptofloor stages we use a small box + * so they fall as far and in the same place as they traditionally would, + * then we nudge the full size box out of solid, in a direction appropriate for the plane(s). + */ + vector saved_mins = this.mins; // gmqcc's used-uninitialized check doesn't handle + vector saved_maxs = this.maxs; // making these assignments FL_ITEM conditional. + if (this.flags & FL_ITEM) + { + // Using the Q3 bbox for best compatibility with all maps, except... + this.mins.x = -15; + this.mins.y = -15; + this.maxs.x = 15; + this.maxs.y = 15; + this.maxs.z = this.mins.z + 30; // ...Nex, Xon and Quake use a different vertical offset, see also: StartItem() + } + + /* NOTE: sv_gameplayfix_droptofloorstartsolid_nudgetocorrect isn't checked, so it won't need to be networked to CSQC. + * It was enabled by default in all Xonotic releases and in Nexuiz, so now certain maps depend on it. + * Example: on erbium 0.8.6 the shards @ crylink are too low (in collision with the floor), + * so without this those fall through the floor. + * Q3, Q2 and Quake don't try to move items out of solid. + */ + if(!Q3COMPAT_COMMON && autocvar_sv_mapformat_is_quake3) // Xonotic, Nexuiz + { + nudgeresult = nudgeoutofsolid(this); + if (!nudgeresult) + LOG_WARNF("DropToFloor_QC at \"%v\": COULD NOT FIX badly placed entity \"%s\" before drop", this.origin, this.classname); + else if (nudgeresult > 0) + LOG_WARNF("DropToFloor_QC at \"%v\": FIXED badly placed entity \"%s\" before drop", this.origin, this.classname); + } + vector end = this.origin; if (autocvar_sv_mapformat_is_quake3) end.z -= 4096; @@ -2317,69 +2356,68 @@ void DropToFloor_Handler(entity this) end.z -= 128; else end.z -= 256; // Quake, QuakeWorld + tracebox(this.origin, this.mins, this.maxs, end, MOVE_NOMONSTERS, this); - // NOTE: SV_NudgeOutOfSolid is used in the engine here - if(autocvar_sv_gameplayfix_droptofloorstartsolid_nudgetocorrect) + if (!autocvar_sv_mapformat_is_quake3 && !autocvar_sv_mapformat_is_quake2 && (trace_allsolid || trace_fraction == 1)) // Quake { - _Movetype_UnstickEntity(this); - move_out_of_solid(this); + // Quake games just delete badly placed entities... + LOG_WARNF("DropToFloor_QC at \"%v\" (Quake compat): DELETING badly placed entity \"%s\"", this.origin, this.classname); + delete(this); + return; } + else if ((Q3COMPAT_COMMON || autocvar_sv_mapformat_is_quake2) && trace_startsolid) // Q3, Q2 + { + // ...but we can't do that on Q3 maps like jamdm1 + // because our tracebox hits things Q3's trace doesn't (patches?). + LOG_WARNF("DropToFloor_QC at \"%v\" (Quake 3 compat): badly placed entity \"%s\"", this.origin, this.classname); + } + + /* NOTE: sv_gameplayfix_droptofloorstartsolid (fallback from tracebox to traceline) isn't implemented. + * It was disabled by default in all Xonotic releases and in Nexuiz. + * Q3 doesn't support it (always uses its '-15 -15 -15' '15 15 15' box when dropping items), neither does Quake or Q2. + */ - tracebox(this.origin, this.mins, this.maxs, end, MOVE_NORMAL, this); + if (!autocvar_sv_mapformat_is_quake2) // Quake, Q3, Nexuiz, Xonotic + // allow to ride movers (or unset if in freefall) + this.groundentity = trace_ent; - if(trace_startsolid && autocvar_sv_gameplayfix_droptofloorstartsolid) + if (!autocvar_sv_mapformat_is_quake3) + // if support is destroyed, keep suspended (gross hack for floating items in various maps) + // bones_was_here: is this for Q1BSP only? Which maps use it? Do we need it at all? Intentions unclear in DP... + this.move_suspendedinair = true; + + if (trace_fraction) + this.origin = trace_endpos; + + if (this.flags & FL_ITEM) { - vector offset, org; - offset = 0.5 * (this.mins + this.maxs); - offset.z = this.mins.z; - org = this.origin + offset; - traceline(org, end, MOVE_NORMAL, this); - trace_endpos = trace_endpos - offset; - if(trace_startsolid) - { - LOG_DEBUGF("DropToFloor_Handler: %v could not fix badly placed entity", this.origin); - _Movetype_LinkEdict(this, false); - SET_ONGROUND(this); - this.groundentity = NULL; - } - else if(trace_fraction < 1) - { - LOG_DEBUGF("DropToFloor_Handler: %v fixed badly placed entity", this.origin); - setorigin(this, trace_endpos); - if(autocvar_sv_gameplayfix_droptofloorstartsolid_nudgetocorrect) - { - _Movetype_UnstickEntity(this); - move_out_of_solid(this); - } - SET_ONGROUND(this); - this.groundentity = trace_ent; - // if support is destroyed, keep suspended (gross hack for floating items in various maps) - this.move_suspendedinair = true; - } + this.mins = saved_mins; + this.maxs = saved_maxs; + + // A side effect of using a small box to drop items (and do the initial nudge) is + // the full size box can end up in collision with a sloping floor or terrain model. + nudgeresult = nudgeoutofsolid(this); + // No warns for successful nudge because it would spam about items on slopes/terrain. } - else + else if (trace_allsolid && trace_fraction) // dropped using "proper" bbox but never left solid { - if(!trace_allsolid && trace_fraction < 1) - { - setorigin(this, trace_endpos); - SET_ONGROUND(this); - this.groundentity = trace_ent; - // if support is destroyed, keep suspended (gross hack for floating items in various maps) - this.move_suspendedinair = true; - } - else - { - // if we can't get the entity out of solid, mark it as on ground so physics doesn't attempt to drop it - // hacky workaround for #2774 - SET_ONGROUND(this); - } + nudgeresult = nudgeoutofsolid(this); + if (nudgeresult > 0) + LOG_WARNF("DropToFloor_QC at \"%v\": FIXED badly placed entity \"%s\" after drop", this.origin, this.classname); } - this.dropped_origin = this.origin; + else + nudgeresult = -1; + + if (!nudgeresult) + if (!Q3COMPAT_COMMON) // to be expected on Q3 maps like gu3-pewter because we use bigger final bboxes + LOG_WARNF("DropToFloor_QC at \"%v\": COULD NOT FIX stuck entity \"%s\" after drop", this.origin, this.classname); + + setorigin(this, this.dropped_origin = this.origin); } void droptofloor(entity this) { - InitializeEntity(this, DropToFloor_Handler, INITPRIO_DROPTOFLOOR); + InitializeEntity(this, DropToFloor_QC, INITPRIO_DROPTOFLOOR); } bool autocvar_sv_gameplayfix_multiplethinksperframe = true; diff --git a/qcsrc/server/world.qh b/qcsrc/server/world.qh index ff799e64c..67adb0fab 100644 --- a/qcsrc/server/world.qh +++ b/qcsrc/server/world.qh @@ -28,8 +28,6 @@ float autocvar_timelimit_max; float autocvar_timelimit_overtime; int autocvar_timelimit_overtimes; float autocvar_timelimit_suddendeath; -bool autocvar_sv_gameplayfix_droptofloorstartsolid; -bool autocvar_sv_gameplayfix_droptofloorstartsolid_nudgetocorrect; bool autocvar_sv_mapformat_is_quake3; bool autocvar_sv_mapformat_is_quake2; -- 2.39.2