From 8d19634f9ffa47c4500bf4161061f063675edeea Mon Sep 17 00:00:00 2001 From: bones_was_here Date: Mon, 12 Jun 2023 03:52:25 +1000 Subject: [PATCH] items: fix animation interference with physics and reset animation properly if disabled Spawns item at the sine wave midpoint instead of "fading in". --- qcsrc/client/items/items.qc | 103 +++++++++++++++++++++--------------- qcsrc/client/items/items.qh | 4 +- xonotic-client.cfg | 2 +- 3 files changed, 61 insertions(+), 48 deletions(-) diff --git a/qcsrc/client/items/items.qc b/qcsrc/client/items/items.qc index a10ac41e4..740294b2c 100644 --- a/qcsrc/client/items/items.qc +++ b/qcsrc/client/items/items.qc @@ -12,47 +12,72 @@ .bool item_simple; // probably not really needed, but better safe than sorry .float alpha; .bool pushable; +.float anim_start_time; // reusing for bob waveform synchronisation +.vector angles_held; // reusing for (re)storing original angles void ItemDraw(entity this) { - if(this.gravity) + // no bobbing applied to simple items, for consistency's sake (no visual difference between ammo and weapons) + bool animate = autocvar_cl_items_animate & 1 && this.item_simple <= 0 && (this.ItemStatus & ITS_ANIMATE1 || this.ItemStatus & ITS_ANIMATE2); + + // rotation must be set before running physics + if(!animate) { - Movetype_Physics_MatchServer(this, false); - if(IS_ONGROUND(this)) - { // For some reason avelocity gets set to '0 0 0' here ... - this.oldorigin = this.origin; - this.gravity = 0; + this.avelocity_y = 0; + this.angles = this.angles_held; // restore angles sent from server + } + else if(!this.avelocity_y) // unset by MOVETYPE_TOSS or animation was disabled previously + { + if(this.ItemStatus & ITS_ANIMATE1) + this.avelocity_y = 180; + else if(this.ItemStatus & ITS_ANIMATE2) + this.avelocity_y = -90; + } - if(autocvar_cl_animate_items) - { // ... so reset it if animations are requested. + // CSQC physics OR bobbing (both would look weird) + float bobheight = 0; // reset bob offset if animations are disabled + if(this.move_movetype && (!IS_ONGROUND(this) || this.velocity != '0 0 0')) + { + // this isn't equivalent to player prediction but allows smooth motion with very low ISF_LOCATION rate + // which requires running this even if the item is just outside visible range (it could be moving into range) + if(animate) + bobheight = this.origin_z - this.oldorigin_z; + Movetype_Physics_MatchServer(this, false); + this.oldorigin = this.origin; // update real (SVQC equivalent) origin + if(animate) + { + if(bobheight) + { + this.anim_start_time += frametime; // bobbing is paused this frame + this.oldorigin_z -= bobheight; // restore bob offset (CSQC physics uses the offset bbox) + } + else + { + this.anim_start_time = time; // starting our bob animation from NOW if(this.ItemStatus & ITS_ANIMATE1) - this.avelocity = '0 180 0'; - - if(this.ItemStatus & ITS_ANIMATE2) - this.avelocity = '0 -90 0'; + bobheight = 10; // height of wave at 0 time + else if(this.ItemStatus & ITS_ANIMATE2) + bobheight = 8; // height of wave at 0 time } - - // delay is for blocking item's position for a while; - // it's a workaround for dropped weapons that receive the position - // another time right after they spawn overriding animation position - this.onground_time = time + 0.5; } } - else if (autocvar_cl_animate_items && !this.item_simple) // no bobbing applied to simple items, for consistency's sake (no visual difference between ammo and weapons) + else if(animate) { + this.angles += this.avelocity * frametime; // MOVETYPE_TOSS does this while it's moving + if(this.ItemStatus & ITS_ANIMATE1) - { - this.angles += this.avelocity * frametime; - float fade_in = bound(0, time - this.onground_time, 1); - setorigin(this, this.oldorigin + fade_in * ('0 0 10' + '0 0 8' * sin((time - this.onground_time) * 2))); - } + bobheight = 10 + 8 * sin((time - this.anim_start_time) * 2); + else if(this.ItemStatus & ITS_ANIMATE2) + bobheight = 8 + 4 * sin((time - this.anim_start_time) * 3); + } - if(this.ItemStatus & ITS_ANIMATE2) - { - this.angles += this.avelocity * frametime; - float fade_in = bound(0, time - this.onground_time, 1); - setorigin(this, this.oldorigin + fade_in * ('0 0 8' + '0 0 4' * sin((time - this.onground_time) * 3))); - } + // apply new bob offset + if (bobheight != this.origin_z - this.oldorigin_z) + { + this.origin_z = this.oldorigin_z + bobheight; + this.mins_z = 0 - bobheight; // don't want the absmin and absmax to bob + this.maxs_z = 48 - bobheight; + // bones_was_here TODO: network proper box size for sv_legacy_bbox_expand 0 } // set alpha based on distance @@ -123,14 +148,15 @@ NET_HANDLE(ENT_CLIENT_ITEM, bool isnew) if(sf & ISF_LOCATION) { - vector org = ReadVector(); - setorigin(this, org); - this.oldorigin = org; + float bobheight = this.origin_z - this.oldorigin_z; + this.origin = this.oldorigin = ReadVector(); + this.origin_z += bobheight; // restore animation offset (SVQC physics is unaware of CSQC bbox offset) + setorigin(this, this.origin); // link } if(sf & ISF_ANGLES) { - this.angles = ReadAngleVector(); + this.angles = this.angles_held = ReadAngleVector(); } if(sf & ISF_SIZE) @@ -158,7 +184,6 @@ NET_HANDLE(ENT_CLIENT_ITEM, bool isnew) if(sf & ISF_MODEL) { - set_movetype(this, MOVETYPE_TOSS); if (isnew) IL_PUSH(g_drawables, this); this.draw = ItemDraw; this.solid = SOLID_TRIGGER; @@ -231,7 +256,6 @@ NET_HANDLE(ENT_CLIENT_ITEM, bool isnew) //this.angles = '0 0 0'; set_movetype(this, MOVETYPE_TOSS); this.velocity = ReadVector(); - setorigin(this, this.oldorigin); if(!this.move_time) { @@ -242,15 +266,6 @@ NET_HANDLE(ENT_CLIENT_ITEM, bool isnew) this.move_time = max(this.move_time, time); } - if(autocvar_cl_animate_items) - { - if(this.ItemStatus & ITS_ANIMATE1) - this.avelocity = '0 180 0'; - - if(this.ItemStatus & ITS_ANIMATE2) - this.avelocity = '0 -90 0'; - } - this.entremove = ItemRemove; return true; diff --git a/qcsrc/client/items/items.qh b/qcsrc/client/items/items.qh index aa8122697..03ba02e37 100644 --- a/qcsrc/client/items/items.qh +++ b/qcsrc/client/items/items.qh @@ -2,12 +2,10 @@ const int AMMO_COUNT = 4; // amount of ammo types to show in the ammo panel -.float onground_time; - +float autocvar_cl_items_animate = 7; float autocvar_cl_items_fadedist = 500; float autocvar_cl_items_vehicle_alpha = 0.75; vector autocvar_cl_items_vehicle_color = '2 0.5 0.5'; -float autocvar_cl_animate_items = 1; float autocvar_cl_ghost_items = 0.45; vector autocvar_cl_ghost_items_color = '-1 -1 -1'; vector autocvar_cl_weapon_stay_color = '2 0.5 0.5'; diff --git a/xonotic-client.cfg b/xonotic-client.cfg index 5cce26783..691ab3a97 100644 --- a/xonotic-client.cfg +++ b/xonotic-client.cfg @@ -905,10 +905,10 @@ exec hud_luma.cfg // enable menu syncing - must be after files that call menu_sync on startup - see alias menu_sync "" alias menu_sync "menu_cmd sync" +seta cl_items_animate 7 "1 enables bobbing and spinning of 3d items, 2 enables fading out of despawning loot items, 4 enables glowing particles for despawning loot items; add the numbers together to enable that combination." seta cl_items_fadedist 500 "distance, relative to the server's g_items_maxdist, at which far away items will start to fade out; 0 disables fading effect" seta cl_items_vehicle_alpha 0.75 "Alpha of items seen from inside a vehicle" seta cl_items_vehicle_color "2 0.5 0.5" "Colour of items seen from inside a vehicle" -seta cl_animate_items 1 seta cl_ghost_items 0.45 "enable ghosted items (when between 0 and 1, overrides the alpha value)" seta cl_ghost_items_color "-1 -1 -1" "color of ghosted items (colormod format: 0 0 0 leaves the color unchanged, negative values allowed)" seta cl_simple_items 0 "enable simple items (if server allows)" -- 2.39.2