Sends an extra update that triggers the effect prior to removal.
Currently only used for loot items when picked up or touching void.
Fixes #2849
without reverting to the old way of sending the effect in SVQC which
caused every player to receive it even if they couldn't see the item,
and without the expense of additional culling.
Changes the pipeline hash because g_powerups_drop_ondeath is enabled by
default and bots remove an item from their goals immediately if it's
deleted, but if it still exists (for 1-2 frames in this case) they only
remove it if it's in their PVS.
- wget -nv -O data/maps/stormkeep.waypoints https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints
- wget -nv -O data/maps/stormkeep.waypoints.cache https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints.cache
- - EXPECT=9fb6b4ba8c0f8b04995c123e3801b32d
+ - EXPECT=f68507df6290e8a8bd8b2a383913184f
- HASH=$(${ENGINE} +exec serverbench.cfg
| tee /dev/stderr
| grep '^:'
void ItemRemove(entity this)
{
- if(this.alpha)
- if(!this.wait || time < this.wait - ticrate) // despawning loot items have their own effects
- pointparticles(EFFECT_ITEM_PICKUP, (this.absmin + this.absmax) * 0.5, '0 0 0', 1);
strfree(this.mdl);
}
IL_PUSH(g_drawables, this);
this.draw = ItemDraw;
this.flags |= FL_ITEM;
+ this.entremove = ItemRemove;
}
this.fade_end = ReadShort();
SET_ONGROUND(this); // extra overkill
}
- this.entremove = ItemRemove;
+ if(sf & ISF_REMOVEFX && !(sf & ISF_SIZE) && !(sf & ISF_MODEL)) // TODO !isnew isn't reliable for this... are we double sending initialisations?
+ {
+ // no longer available to pick up, about to be removed
+ if (this.drawmask) // this.alpha > 0
+ pointparticles(EFFECT_ITEM_PICKUP, (this.absmin + this.absmax) * 0.5, '0 0 0', 1);
+ // removing now causes CSQC_Ent_Remove() to spam
+ this.drawmask = 0;
+ IL_REMOVE(g_drawables, this);
+ this.solid = SOLID_NOT;
+ }
return true;
}
const int IT_PICKUPMASK = IT_UNLIMITED_AMMO | IT_UNLIMITED_SUPERWEAPONS | IT_JETPACK | IT_FUEL_REGEN; // strength and invincible are handled separately
// item networking
+const int ISF_REMOVEFX = BIT(0); // technically unnecessary (after the kludge in Item_Think() is reverted), but cheaper and cleaner than using ITS_AVAILABLE
const int ISF_LOCATION = BIT(1);
const int ISF_MODEL = BIT(2);
const int ISF_STATUS = BIT(3);
{
if (ITEM_TOUCH_NEEDKILL())
{
+ this.SendFlags |= ISF_REMOVEFX;
RemoveItem(this);
return;
}
if (ITEM_IS_LOOT(this))
{
- delete(this);
+ this.SendFlags |= ISF_REMOVEFX;
+ RemoveItem(this);
return;
}
if (!this.spawnshieldtime)
if(wasfreed(this) || !this) { return; }
if(this.waypointsprite_attached)
WaypointSprite_Kill(this.waypointsprite_attached);
- delete(this);
+
+ if (this.SendFlags & ISF_REMOVEFX)
+ {
+ // delay removal until ISF_REMOVEFX has been sent
+ setthink(this, RemoveItem);
+ this.nextthink = time + 2 * autocvar_sys_ticrate; // micro optimisation: next frame will be too soon
+ this.solid = SOLID_NOT; // untouchable
+ }
+ else
+ delete(this);
}
// pickup evaluation functions