void UpdateCellBlocking(CPos cell) { using (new PerfSample("locomotor_cache")) { var cache = cell.Layer == 0 ? blockingCache : customLayerBlockingCache[cell.Layer]; var actors = actorMap.GetActorsAt(cell); var cellFlag = CellFlag.HasFreeSpace; if (!actors.Any()) { cache[cell] = new CellCache(default(LongBitSet <PlayerBitMask>), cellFlag); return; } if (sharesCell && actorMap.HasFreeSubCell(cell)) { cache[cell] = new CellCache(default(LongBitSet <PlayerBitMask>), cellFlag); return; } var cellImmovablePlayers = default(LongBitSet <PlayerBitMask>); var cellCrushablePlayers = world.AllPlayersMask; foreach (var actor in actors) { var actorImmovablePlayers = world.AllPlayersMask; var actorCrushablePlayers = world.NoPlayersMask; var crushables = actor.TraitsImplementing <ICrushable>(); var mobile = actor.OccupiesSpace as Mobile; var isMovable = mobile != null && !mobile.IsTraitDisabled && !mobile.IsTraitPaused && !mobile.IsImmovable; var isMoving = isMovable && mobile.CurrentMovementTypes.HasMovementType(MovementType.Horizontal); var building = actor.OccupiesSpace as Building; var isTransitOnly = building != null && building.TransitOnlyCells().Contains(cell); if (isTransitOnly) { cellFlag |= CellFlag.HasTransitOnlyActor; continue; } if (crushables.Any()) { cellFlag |= CellFlag.HasCrushableActor; foreach (var crushable in crushables) { actorCrushablePlayers = actorCrushablePlayers.Union(crushable.CrushableBy(actor, Info.Crushes)); } } if (isMoving) { cellFlag |= CellFlag.HasMovingActor; } else { cellFlag |= CellFlag.HasStationaryActor; } if (isMovable) { cellFlag |= CellFlag.HasMovableActor; actorImmovablePlayers = actorImmovablePlayers.Except(actor.Owner.AlliedPlayersMask); } // PERF: Only perform ITemporaryBlocker trait look-up if mod/map rules contain any actors that are temporary blockers if (world.RulesContainTemporaryBlocker) { // If there is a temporary blocker in this cell. if (actor.TraitOrDefault <ITemporaryBlocker>() != null) { cellFlag |= CellFlag.HasTemporaryBlocker; } } cellCrushablePlayers = cellCrushablePlayers.Intersect(actorCrushablePlayers); cellImmovablePlayers = cellImmovablePlayers.Union(actorImmovablePlayers); } cache[cell] = new CellCache(cellImmovablePlayers, cellFlag, cellCrushablePlayers); } }
void UpdateCellBlocking(CPos cell) { using (new PerfSample("locomotor_cache")) { var actors = actorMap.GetActorsAt(cell); if (!actors.Any()) { blockingCache[cell] = new CellCache(default(LongBitSet <PlayerBitMask>), CellFlag.HasFreeSpace); return; } if (sharesCell && actorMap.HasFreeSubCell(cell)) { blockingCache[cell] = new CellCache(default(LongBitSet <PlayerBitMask>), CellFlag.HasFreeSpace); return; } var cellFlag = CellFlag.HasActor; var cellBlockedPlayers = default(LongBitSet <PlayerBitMask>); var cellCrushablePlayers = world.AllPlayersMask; foreach (var actor in actors) { var actorBlocksPlayers = world.AllPlayersMask; var crushables = actor.TraitsImplementing <ICrushable>(); var mobile = actor.OccupiesSpace as Mobile; var isMoving = mobile != null && mobile.CurrentMovementTypes.HasMovementType(MovementType.Horizontal); if (crushables.Any()) { cellFlag |= CellFlag.HasCrushableActor; foreach (var crushable in crushables) { cellCrushablePlayers = cellCrushablePlayers.Intersect(crushable.CrushableBy(actor, Info.Crushes)); } } else { cellCrushablePlayers = world.NoPlayersMask; } if (isMoving) { actorBlocksPlayers = actorBlocksPlayers.Except(actor.Owner.AlliedPlayersMask); cellFlag |= CellFlag.HasMovingActor; } // PERF: Only perform ITemporaryBlocker trait look-up if mod/map rules contain any actors that are temporary blockers if (world.RulesContainTemporaryBlocker) { // If there is a temporary blocker in this cell. if (actor.TraitOrDefault <ITemporaryBlocker>() != null) { cellFlag |= CellFlag.HasTemporaryBlocker; } } cellBlockedPlayers = cellBlockedPlayers.Union(actorBlocksPlayers); } blockingCache[cell] = new CellCache(cellBlockedPlayers, cellFlag, cellCrushablePlayers); } }