public async Task TakeMe(IMyPlayer player, int index) { if (player == null) { throw new ArgumentException("calling player not found"); } var entities = _clusters[index]; if (entities.Length == 0) { throw new InvalidOperationException("entities not found"); } var(_, center) = VRageUtils.GetBound(entities.Select(e => e.Position)); player.Character.SetPosition(center); DeleteGpss(player.IdentityId); await GameLoopObserver.MoveToGameLoop(); // to create gps entities foreach (var grid in entities) { var gps = CreateGridGps($"{GpsNamePrefix}{grid.Name}", grid.Position, "", Color.Purple); MySession.Static.Gpss.SendAddGps(player.IdentityId, ref gps); } await TaskUtils.MoveToThreadPool(); }
async Task PunishGrid(MyCubeGrid grid) { var blocks = grid.GetFatBlocks(); for (var i = 0; i < blocks.Count; i++) { // move to the next frame so we won't lag the server if (i % ProcessedBlockCountPerFrame == 0) { await VRageUtils.MoveToGameLoop(); } var block = blocks[i]; if (block == null) { continue; } switch (_config.PunishType) { case PunishType.Shutdown: { DisableFunctionalBlock(block); break; } case PunishType.Damage: { DamageBlock(block); break; } } } }
async Task BroadcastLaggyGrids(CancellationToken cancellationToken) { if (_config.PunishType != PunishType.Broadcast) { _entityGpsBroadcaster.ClearGpss(); return; } var allGpsSources = new Dictionary <long, GridGpsSource>(); foreach (var(player, rank) in _players.Entities.GetLaggiestEntities(true).Indexed()) { var playerId = player.Id; if (!_grids.TryGetLaggiestGridOwnedBy(playerId, out var laggiestGrid)) { continue; } var gpsSource = new GridGpsSource(laggiestGrid.Id, player.LagNormal, player.PinRemainingTime, rank); allGpsSources[gpsSource.GridId] = gpsSource; } foreach (var(grid, rank) in _grids.Entities.GetLaggiestEntities(true).Indexed()) { var gpsSource = new GridGpsSource(grid.Id, grid.LagNormal, grid.PinRemainingTime, rank); allGpsSources[gpsSource.GridId] = gpsSource; } await VRageUtils.MoveToGameLoop(cancellationToken); _entityGpsBroadcaster.ReplaceGpss(allGpsSources.Values); await VRageUtils.MoveToThreadPool(cancellationToken); Log.Trace("broadcast done"); }
bool TryCreateGps(GridGpsSource source, out LocalGpsSource gps) { if (!VRageUtils.TryGetCubeGridById(source.GridId, out var grid)) { Log.Trace($"broadcast: grid not found: {source.GridId}"); gps = default; return(false); } var playerName = (string)null; if (!grid.BigOwners.TryGetFirst(out var playerId)) { Log.Trace($"grid no owner: \"{grid.DisplayName}\""); } else if (!MySession.Static.Players.TryGetPlayerById(playerId, out var player)) { Log.Trace($"player not found for grid: \"{grid.DisplayName}\": {playerId}"); } else { playerName = player.DisplayName; } var faction = MySession.Static.Factions.GetPlayerFaction(playerId); var factionTag = faction?.Tag; var name = Format(_config.GpsNameFormat); var description = Format(_config.GpsDescriptionFormat); gps = new LocalGpsSource { Id = grid.EntityId, Name = name, Color = ColorUtils.TranslateColor(_config.GpsColorCode), Description = description, Position = grid.PositionComp.GetPosition(), Radius = 0, EntityId = grid.EntityId, PromoteLevel = (int)_config.GpsVisiblePromoteLevel, ExcludedPlayers = _config.GpsMutedPlayers.ToArray(), }; return(true); string Format(string format) { return(format .Replace("{grid}", grid.DisplayName) .Replace("{player}", playerName ?? "<none>") .Replace("{faction}", factionTag ?? "<none>") .Replace("{ratio}", $"{source.LongLagNormal * 100:0}%") .Replace("{rank}", GpsUtils.RankToString(source.Rank)) .Replace("{time}", GpsUtils.RemainingTimeToString(source.RemainingTime))); } }
public async Task Main(CancellationToken canceller) { Log.Info("started main"); await VRageUtils.MoveToGameLoop(canceller); _entityGpsBroadcaster.ClearGpss(); await VRageUtils.MoveToThreadPool(canceller); _questTracker.Clear(); // Wait for some time during the session startup await TaskUtils.Delay(() => _config.FirstIdleTime.Seconds(), 1.Seconds(), canceller); IsIdle = false; Log.Info("started collector loop"); // MAIN LOOP while (!canceller.IsCancellationRequested) { if (!_config.IsEnabled) { _grids.Clear(); _players.Clear(); _questTracker.Clear(); _punishExecutor.Clear(); _punishChatFeed.Clear(); await VRageUtils.MoveToGameLoop(canceller); _entityGpsBroadcaster.ClearGpss(); await Task.Delay(1.Seconds(), canceller); return; } using var _ = CustomProfiling.Profile("AutoModerator.Main"); await Profile(canceller); FixExemptBlockTypeCollection(); Warn(); AnnouncePunishments(); await Punish(canceller); await AnnounceDeletedGrids(canceller); Log.Debug("interval done"); } }
public async Task Update(IReadOnlyDictionary <long, PunishSource> lags) { // move to the game loop so we can synchronously operate on blocks await VRageUtils.MoveToGameLoop(); foreach (var(gridId, lag) in lags) { if (!lag.IsPinned) { continue; } if (!VRageUtils.TryGetCubeGridById(gridId, out var grid)) { Log.Warn($"grid not found for grid id: {gridId}"); continue; } if (!_punishedIds.Contains(gridId)) { _punishedIds.Add(gridId); Log.Info($"Punished: \"{grid.DisplayName}\" type: {_config.PunishType}"); } await PunishGrid(grid); Log.Debug($"block punish: \"{grid.Name}\" <{lag.GridId}> {_config.PunishType}"); // move to the next frame so we won't lag the server await VRageUtils.MoveToGameLoop(); } foreach (var existingId in _punishedIds) { if (!lags.ContainsKey(existingId)) { var name = VRageUtils.TryGetCubeGridById(existingId, out var g) ? $"\"{g.DisplayName}\"" : $"<{existingId}>"; Log.Info($"Done punishment: {name}"); } } _punishedIds.ExceptWith(lags.Keys); // back to some worker thread await TaskUtils.MoveToThreadPool(); }
async Task AnnounceDeletedGrids(CancellationToken canceller) { // stop tracking deleted grids & report cheating // we're doing this right here to get the max chance of grabbing the owner name var lostGrids = new List <TrackedEntity>(); await VRageUtils.MoveToGameLoop(canceller); foreach (var(_, trackedGrid) in _grids.Entities) { if (!MyEntities.TryGetEntityById(trackedGrid.Id, out _)) { lostGrids.Add(trackedGrid); } } await TaskUtils.MoveToThreadPool(canceller); foreach (var lostGrid in lostGrids) { _grids.StopTracking(lostGrid.Id); // high-profile grid deleted if (lostGrid.LagNormal >= _config.QuestLagNormal) { var gridName = lostGrid.Name; var ownerName = lostGrid.OwnerName; Log.Warn($"Laggy grid deleted by player: {gridName}: {ownerName}"); if (_config.EnablePunishChatFeed) { _chatManager.SendMessage(_config.PunishReportChatName, 0, $"Laggy grid deleted by player: {gridName}: {ownerName}"); } } } Log.Trace("announcing deleted entities done"); }