diff --git a/code/cgame/cg_predict.c b/code/cgame/cg_predict.c index f3b041a6..41e61614 100644 --- a/code/cgame/cg_predict.c +++ b/code/cgame/cg_predict.c @@ -42,6 +42,35 @@ void CG_BuildSolidList( void ) { cent = &cg_entities[ snap->entities[ i ].number ]; ent = ¢->currentState; + // All consumers of `cg_solidEntities` + // (i.e. `CG_ClipMoveToEntities` and `CG_PointContents`) + // read the entities' `currentState` or `lerpOrigin` + // (which is (generally) a lerp between `currentState` and `nextState`). + // So we must ensure that `cg_solidEntities` + // only contains entities present in `cg.snap` (and not `cg.nextSnap`). + // Otheriwse we get bugs like + // https://github.com/ioquake/ioq3/issues/732, + // i.e. `CG_ScanForCrosshairEntity` using a player position + // from a very old snap. + // + // We still do check `nextState.solid` (below) though, + // in order to drop an entity from the solid list + // as soon as it stops being solid in the next snap + // (e.g. player getting gibbed). + // + // Thoughts: + // Maybe there was a bigger idea behind trying to use `cg.nextSnap` + // for building the solid list. + // Looking at the fact that we're in a file named `cg_predict.c`, + // maybe it was better movement prediction, + // i.e. maybe detecting a collision as soon as a solid + // is in `cg.nextSnap` but not yet in `cg.snap`. + // But until we're sure that we don't access invalid state, + // let's just have this check. + if ( !cent->currentValid ) { + continue; + } + if ( ent->eType == ET_ITEM || ent->eType == ET_PUSH_TRIGGER || ent->eType == ET_TELEPORT_TRIGGER ) { cg_triggerEntities[cg_numTriggerEntities] = cent; cg_numTriggerEntities++;