From 571fa442d5b2f782250316fe38443d6d251b7e72 Mon Sep 17 00:00:00 2001 From: InvalidArgument3 Date: Tue, 29 Oct 2024 07:04:09 -0500 Subject: [PATCH] nvm its fucked think i'm just gonna rewrite everything --- .../AsteroidNetworkPackets.cs | 2 +- .../DynamicAsteroids/AsteroidSpawner.cs | 194 +++++------------- .../Scripts/DynamicAsteroids/MainSession.cs | 101 ++++----- .../DynamicAsteroids/ZoneNetworkManager.cs | 93 +++------ 4 files changed, 139 insertions(+), 251 deletions(-) diff --git a/Dynamic Asteroids/Data/Scripts/DynamicAsteroids/AsteroidNetworkPackets.cs b/Dynamic Asteroids/Data/Scripts/DynamicAsteroids/AsteroidNetworkPackets.cs index 67f4965..7002524 100644 --- a/Dynamic Asteroids/Data/Scripts/DynamicAsteroids/AsteroidNetworkPackets.cs +++ b/Dynamic Asteroids/Data/Scripts/DynamicAsteroids/AsteroidNetworkPackets.cs @@ -224,8 +224,8 @@ public static void SendAsteroidUpdate(AsteroidEntity asteroid) { } public static void SendAsteroidRemoval(long entityId) { - Log.Info($"Broadcasting asteroid removal: {entityId}"); var packet = new AsteroidRemovalPacket { EntityId = entityId }; + byte[] data = MyAPIGateway.Utilities.SerializeToBinary(packet); MyAPIGateway.Multiplayer.SendMessageToOthers(32000, data); } diff --git a/Dynamic Asteroids/Data/Scripts/DynamicAsteroids/AsteroidSpawner.cs b/Dynamic Asteroids/Data/Scripts/DynamicAsteroids/AsteroidSpawner.cs index c2d11c2..015522b 100644 --- a/Dynamic Asteroids/Data/Scripts/DynamicAsteroids/AsteroidSpawner.cs +++ b/Dynamic Asteroids/Data/Scripts/DynamicAsteroids/AsteroidSpawner.cs @@ -18,13 +18,12 @@ namespace DynamicAsteroids.Data.Scripts.DynamicAsteroids { public class AsteroidZone { - public long PlayerId { get; set; } public Vector3D Center { get; set; } public double Radius { get; set; } public int AsteroidCount { get; set; } public bool IsMerged { get; set; } public long EntityId { get; set; } - public HashSet ContainedAsteroids { get; set; } + public HashSet ContainedAsteroids { get; private set; } public bool IsMarkedForRemoval { get; set; } public DateTime LastActiveTime { get; set; } public double CurrentSpeed { get; set; } // Add this property @@ -87,7 +86,6 @@ public bool IsDisabledDueToSpeed() { public class AsteroidSpawner { private ConcurrentBag _asteroids; - private ConcurrentDictionary _asteroidLookup = new ConcurrentDictionary(); private bool _canSpawnAsteroids = false; private DateTime _worldLoadTime; private Random rand; @@ -264,9 +262,6 @@ public AsteroidSpawner(RealGasGiantsApi realGasGiantsApi) { _networkManager = new ZoneNetworkManager(); } - public bool IsAsteroidTracked(long entityId) { - return _asteroidLookup.ContainsKey(entityId); - } public void Init(int seed) { if (!MyAPIGateway.Session.IsServer) return; @@ -537,66 +532,24 @@ private AsteroidZone FindAlternateZone(Vector3D position, AsteroidZone excludeZo #region Zone Updates public void MergeZones() { List mergedZones = new List(); - foreach (AsteroidZone zone in playerZones.Values) { bool merged = false; foreach (AsteroidZone mergedZone in mergedZones) { double distance = Vector3D.Distance(zone.Center, mergedZone.Center); double combinedRadius = zone.Radius + mergedZone.Radius; - - Log.Info($"Checking zones for merge:" + - $"\nZone 1: Center={zone.Center}, Radius={zone.Radius}" + - $"\nZone 2: Center={mergedZone.Center}, Radius={mergedZone.Radius}" + - $"\nDistance={distance}, Combined Radius={combinedRadius}" + - $"\nOverlapping={distance <= combinedRadius}"); - - if (distance <= combinedRadius) { - Vector3D newCenter = (zone.Center + mergedZone.Center) / 2; - double newRadius = Math.Max(zone.Radius, mergedZone.Radius) + distance / 2; - - // Combine asteroid sets - var combinedAsteroids = new HashSet(mergedZone.ContainedAsteroids); - combinedAsteroids.UnionWith(zone.ContainedAsteroids); - - // Update merged zone - mergedZone.Center = newCenter; - mergedZone.Radius = newRadius; - mergedZone.ContainedAsteroids = combinedAsteroids; - mergedZone.AsteroidCount = combinedAsteroids.Count; - - // Enforce per-zone limit even for merged zones - if (mergedZone.AsteroidCount > AsteroidSettings.MaxAsteroidsPerZone) { - Log.Info($"Merged zone exceeds asteroid limit ({mergedZone.AsteroidCount}/{AsteroidSettings.MaxAsteroidsPerZone}), cleaning up excess"); - - // Remove excess asteroids - var asteroidsToRemove = mergedZone.ContainedAsteroids - .Skip(AsteroidSettings.MaxAsteroidsPerZone) - .ToList(); - - foreach (var asteroidId in asteroidsToRemove) { - mergedZone.ContainedAsteroids.Remove(asteroidId); - var asteroid = MyEntities.GetEntityById(asteroidId) as AsteroidEntity; - if (asteroid != null) { - RemoveAsteroid(asteroid); - } - } - - mergedZone.AsteroidCount = AsteroidSettings.MaxAsteroidsPerZone; - } - - merged = true; - break; - } + if (!(distance <= combinedRadius)) continue; + Vector3D newCenter = (zone.Center + mergedZone.Center) / 2; + double newRadius = Math.Max(zone.Radius, mergedZone.Radius) + distance / 2; + mergedZone.Center = newCenter; + mergedZone.Radius = newRadius; + mergedZone.AsteroidCount += zone.AsteroidCount; + merged = true; + break; } - if (!merged) { - mergedZones.Add(new AsteroidZone(zone.Center, zone.Radius) { - AsteroidCount = zone.AsteroidCount, - ContainedAsteroids = new HashSet(zone.ContainedAsteroids) - }); + mergedZones.Add(new AsteroidZone(zone.Center, zone.Radius) { AsteroidCount = zone.AsteroidCount }); } } - AssignMergedZonesToPlayers(mergedZones); } public void UpdateZones() { @@ -738,7 +691,8 @@ public void SendZoneUpdates() { private Dictionary _lastZonePositions = new Dictionary(); private bool HaveZonesChanged() { bool changed = false; - foreach (var zone in playerZones.Values) { + foreach (var zone in playerZones.Values) + { Vector3D lastPos; if (!_lastZonePositions.TryGetValue(zone.EntityId, out lastPos) || Vector3D.DistanceSquared(lastPos, zone.Center) > 1) { @@ -758,20 +712,21 @@ public IEnumerable GetAsteroids() { } public void AddAsteroid(AsteroidEntity asteroid) { _asteroids.Add(asteroid); - _asteroidLookup[asteroid.EntityId] = asteroid; _newAsteroidTimestamps[asteroid.EntityId] = DateTime.UtcNow; Log.Info($"Added new asteroid {asteroid.EntityId} with grace period"); } public bool TryRemoveAsteroid(AsteroidEntity asteroid) { return _asteroids.TryTake(out asteroid); } - private void RemoveAsteroid(AsteroidEntity asteroid) { if (asteroid == null) return; + try { if (MyAPIGateway.Session.IsServer) { _pendingRemovals.Enqueue(asteroid.EntityId); } + + // Remove from all zone tracking foreach (var zone in playerZones.Values) { zone.ContainedAsteroids.Remove(asteroid.EntityId); zone.TransferredFromOtherZone.Remove(asteroid.EntityId); @@ -779,23 +734,23 @@ private void RemoveAsteroid(AsteroidEntity asteroid) { MyEntities.Remove(asteroid); asteroid.Close(); + AsteroidEntity removed; _asteroids.TryTake(out removed); - AsteroidEntity removedFromLookup; - _asteroidLookup.TryRemove(asteroid.EntityId, out removedFromLookup); + Log.Info($"Successfully removed asteroid {asteroid.EntityId}"); } catch (Exception ex) { Log.Exception(ex, typeof(AsteroidSpawner), $"Error removing asteroid {asteroid?.EntityId}"); } } - public void SpawnAsteroids(List zones) { if (!MyAPIGateway.Session.IsServer) return; if (!AreAsteroidsEnabled()) return; Log.Info($"Starting asteroid spawn cycle for {zones.Count} zones"); + // Update zone positions based on player positions List players = new List(); MyAPIGateway.Players.GetPlayers(players); foreach (AsteroidZone zone in zones) { @@ -805,25 +760,20 @@ public void SpawnAsteroids(List zones) { if (zoneOwner != null) { Vector3D playerPos = zoneOwner.GetPosition(); + // Update zone position to follow player zone.Center = playerPos; zone.LastActiveTime = DateTime.UtcNow; } - - // Check for and handle excess asteroids - if (zone.ContainedAsteroids.Count > AsteroidSettings.MaxAsteroidsPerZone) { - Log.Warning($"Zone exceeded asteroid limit! Count: {zone.ContainedAsteroids.Count}/{AsteroidSettings.MaxAsteroidsPerZone}"); - var excess = zone.ContainedAsteroids.Skip(AsteroidSettings.MaxAsteroidsPerZone).ToList(); - foreach (var asteroidId in excess) { - var asteroid = MyEntities.GetEntityById(asteroidId) as AsteroidEntity; - if (asteroid != null) { - RemoveAsteroid(asteroid); - } - zone.ContainedAsteroids.Remove(asteroidId); - } - } } int totalSpawnAttempts = 0; + if (AsteroidSettings.MaxAsteroidCount == 0) { + Log.Info("Asteroid spawning is disabled."); + return; + } + + int totalAsteroidsSpawned = 0; + int totalZoneSpawnAttempts = 0; List skippedPositions = new List(); List spawnedPositions = new List(); @@ -831,18 +781,23 @@ public void SpawnAsteroids(List zones) { foreach (AsteroidZone zone in zones) { Log.Info($"Checking zone at {zone.Center}:" + - $"\n - Current count: {zone.ContainedAsteroids.Count}/{AsteroidSettings.MaxAsteroidsPerZone}" + - $"\n - Is marked for removal: {zone.IsMarkedForRemoval}"); + $"\n - Current count: {zone.TotalAsteroidCount}/{AsteroidSettings.MaxAsteroidsPerZone}" + + $"\n - Is marked for removal: {zone.IsMarkedForRemoval}" + + $"\n - Can spawn: {zone.TotalAsteroidCount < AsteroidSettings.MaxAsteroidsPerZone}"); if (zone.IsMarkedForRemoval) continue; - if (zone.ContainedAsteroids.Count >= AsteroidSettings.MaxAsteroidsPerZone) { - Log.Info($"Zone at {zone.Center} is at capacity ({zone.ContainedAsteroids.Count} asteroids)"); - continue; - } + if (zone.TotalAsteroidCount >= AsteroidSettings.MaxAsteroidsPerZone) continue; int asteroidsSpawned = 0; int zoneSpawnAttempts = 0; + Log.Info($"Attempting spawn in zone at {zone.Center}, current count: {zone.TotalAsteroidCount}/{AsteroidSettings.MaxAsteroidsPerZone}"); + + if (zone.TotalAsteroidCount >= AsteroidSettings.MaxAsteroidsPerZone) { + Log.Info($"Zone at {zone.Center} is at capacity ({zone.TotalAsteroidCount} asteroids)"); + continue; + } + bool skipSpawning = false; foreach (IMyPlayer player in players) { Vector3D playerPosition = player.GetPosition(); @@ -853,7 +808,7 @@ public void SpawnAsteroids(List zones) { if (IsPlayerMovingTooFast(player)) { skipSpawning = true; - zone.CurrentSpeed = data.Speed; + zone.CurrentSpeed = data.Speed; // Update zone speed tracking Log.Info($"Skipping asteroid spawning for player {player.DisplayName} due to high speed: {data.Speed:F2} m/s > {AsteroidSettings.ZoneSpeedThreshold} m/s"); break; } @@ -861,7 +816,7 @@ public void SpawnAsteroids(List zones) { if (skipSpawning) continue; - while (zone.ContainedAsteroids.Count < AsteroidSettings.MaxAsteroidsPerZone && + while (zone.AsteroidCount < AsteroidSettings.MaxAsteroidsPerZone && asteroidsSpawned < 10 && zoneSpawnAttempts < AsteroidSettings.MaxZoneAttempts && totalSpawnAttempts < AsteroidSettings.MaxTotalAttempts) { @@ -908,6 +863,11 @@ public void SpawnAsteroids(List zones) { continue; } + if (AsteroidSettings.MaxAsteroidCount != -1 && _asteroids.Count >= AsteroidSettings.MaxAsteroidCount) { + Log.Warning($"Maximum asteroid count of {AsteroidSettings.MaxAsteroidCount} reached. No more asteroids will be spawned until existing ones are removed."); + return; + } + float spawnChance = isInRing ? MathHelper.Lerp(0.1f, 1f, ringInfluence) * AsteroidSettings.MaxRingAsteroidDensityMultiplier : 1f; @@ -933,8 +893,8 @@ public void SpawnAsteroids(List zones) { AsteroidEntity asteroid = AsteroidEntity.CreateAsteroid(newPosition, size, newVelocity, type, rotation); if (asteroid != null) { _asteroids.Add(asteroid); - _asteroidLookup[asteroid.EntityId] = asteroid; - zone.ContainedAsteroids.Add(asteroid.EntityId); + zone.ContainedAsteroids.Add(asteroid.EntityId); // Add to tracking + zone.AsteroidCount++; spawnedPositions.Add(newPosition); _messageCache.AddMessage(new AsteroidNetworkMessage( @@ -945,10 +905,12 @@ public void SpawnAsteroids(List zones) { Log.Info($"Spawned asteroid {asteroid.EntityId} at {newPosition} with size {size} and type {type}"); } } + + totalAsteroidsSpawned += asteroidsSpawned; + totalZoneSpawnAttempts += zoneSpawnAttempts; } if (!AsteroidSettings.EnableLogging) return; - if (skippedPositions.Count > 0) { Log.Info($"Skipped spawning asteroids due to proximity to vanilla asteroids. Positions: {string.Join(", ", skippedPositions.Select(p => p.ToString()))}"); } @@ -1010,36 +972,28 @@ private bool IsValidSpawnPosition(Vector3D position, List zones) { private void CleanupOrphanedAsteroids() { if (_isCleanupRunning) return; _isCleanupRunning = true; + try { var currentZones = playerZones.Values.ToList(); var asteroidsToRemove = new List(); var trackedAsteroids = _asteroids.ToList(); - Log.Info($"Starting orphaned asteroid cleanup. Tracked asteroids: {trackedAsteroids.Count}"); - foreach (var asteroid in trackedAsteroids) { if (asteroid == null || asteroid.MarkedForClose) continue; Vector3D asteroidPosition = asteroid.PositionComp.GetPosition(); bool isInAnyZone = false; + foreach (var zone in currentZones) { if (zone.IsPointInZone(asteroidPosition)) { isInAnyZone = true; - // Verify zone tracking - if (!zone.ContainedAsteroids.Contains(asteroid.EntityId)) { - Log.Warning($"Asteroid {asteroid.EntityId} in zone but not tracked by it!"); - zone.ContainedAsteroids.Add(asteroid.EntityId); - } break; } } if (!isInAnyZone) { Log.Info($"Found orphaned asteroid {asteroid.EntityId} at {asteroidPosition}"); - if (MyAPIGateway.Session.IsServer) { - NetworkHandler.SendAsteroidRemoval(asteroid.EntityId); - } - RemoveAsteroid(asteroid); + asteroidsToRemove.Add(asteroid); } } @@ -1050,21 +1004,6 @@ private void CleanupOrphanedAsteroids() { } } - // Verify all zone-tracked asteroids exist - foreach (var zone in currentZones) { - var missingAsteroids = zone.ContainedAsteroids - .Where(id => !IsAsteroidTracked(id)) - .ToList(); - - if (missingAsteroids.Any()) { - Log.Warning($"Zone has {missingAsteroids.Count} tracked asteroids that don't exist!"); - foreach (var id in missingAsteroids) { - zone.ContainedAsteroids.Remove(id); - zone.AsteroidCount = Math.Max(0, zone.AsteroidCount - 1); - } - } - } - _lastCleanupTime = DateTime.UtcNow; } catch (Exception ex) { @@ -1075,7 +1014,6 @@ private void CleanupOrphanedAsteroids() { } } - #endregion #region Main Update and Cleanup Cycle @@ -1151,11 +1089,6 @@ public void UpdateTick() { } } - // Add this every X ticks - if (_updateIntervalTimer % 600 == 0) { // Every 10 seconds - VerifyServerClientSync(); - } - ProcessPendingRemovals(); } catch (Exception ex) { @@ -1503,29 +1436,6 @@ private void ValidateAsteroidTracking() { } } - private void VerifyServerClientSync() { - Log.Info("Verifying server-client sync state:"); - Log.Info($"Total tracked asteroids: {_asteroids.Count}"); - - foreach (var zone in playerZones.Values) { - var missingFromTracking = zone.ContainedAsteroids - .Where(id => !IsAsteroidTracked(id)) - .ToList(); - - if (missingFromTracking.Any()) { - Log.Warning($"Zone has {missingFromTracking.Count} asteroids not in server tracking!"); - foreach (var id in missingFromTracking) { - zone.ContainedAsteroids.Remove(id); - zone.AsteroidCount = Math.Max(0, zone.AsteroidCount - 1); - } - } - - Log.Info($"Zone at {zone.Center}:" + - $"\n - Tracked asteroids: {zone.ContainedAsteroids.Count}" + - $"\n - Asteroid count: {zone.AsteroidCount}" + - $"\n - Missing from tracking: {missingFromTracking.Count}"); - } - } } } \ No newline at end of file diff --git a/Dynamic Asteroids/Data/Scripts/DynamicAsteroids/MainSession.cs b/Dynamic Asteroids/Data/Scripts/DynamicAsteroids/MainSession.cs index 0beb381..a00e0b8 100644 --- a/Dynamic Asteroids/Data/Scripts/DynamicAsteroids/MainSession.cs +++ b/Dynamic Asteroids/Data/Scripts/DynamicAsteroids/MainSession.cs @@ -541,22 +541,23 @@ private void ProcessServerMessage(AsteroidNetworkMessage message, ulong steamId) private void RemoveAsteroidOnClient(long entityId) { try { Log.Info($"Client: Removing asteroid with ID {entityId}"); + + // Remove from tracking first _knownAsteroidIds.Remove(entityId); _serverPositions.Remove(entityId); _serverRotations.Remove(entityId); + // Then remove the entity var asteroid = MyEntities.GetEntityById(entityId) as AsteroidEntity; if (asteroid != null) { - MyAPIGateway.Utilities.InvokeOnGameThread(() => { - try { - MyEntities.Remove(asteroid); - asteroid.Close(); - Log.Info($"Client: Successfully removed asteroid {entityId}"); - } - catch (Exception ex) { - Log.Warning($"Error removing asteroid {entityId}: {ex.Message}"); - } - }); + try { + MyEntities.Remove(asteroid); + asteroid.Close(); + Log.Info($"Client: Successfully removed asteroid {entityId}"); + } + catch (Exception ex) { + Log.Warning($"Error removing asteroid {entityId}: {ex.Message}"); + } } } catch (Exception ex) { @@ -931,56 +932,61 @@ public void UpdateClientZones(Dictionary serverZones) { private void ProcessZoneMessage(byte[] message) { try { var zonePacket = MyAPIGateway.Utilities.SerializeFromBinary(message); - if (zonePacket == null || zonePacket.Zones == null || zonePacket.Zones.Count == 0) return; + if (zonePacket?.Zones == null || zonePacket.Zones.Count == 0) return; - bool zonesChanged = false; + // Clear all existing known asteroid IDs when zones change significantly + bool significantZoneChange = false; foreach (var zoneData in zonePacket.Zones) { Vector3D lastPos; - if (!_lastProcessedZonePositions.TryGetValue(zoneData.PlayerId, out lastPos) || - Vector3D.DistanceSquared(lastPos, zoneData.Center) > 1) { - zonesChanged = true; - break; + if (_lastProcessedZonePositions.TryGetValue(zoneData.PlayerId, out lastPos)) { + if (Vector3D.DistanceSquared(lastPos, zoneData.Center) > AsteroidSettings.ZoneRadius * AsteroidSettings.ZoneRadius) { + significantZoneChange = true; + break; + } } - } - - if (!zonesChanged) return; - - if (MyAPIGateway.Session.IsServer && !MyAPIGateway.Utilities.IsDedicated) { - if (_spawner != null) { - UpdateClientZones(_spawner.playerZones.ToDictionary(kvp => kvp.Key, kvp => kvp.Value)); + else { + significantZoneChange = true; } - return; } - var previousZones = new Dictionary(_clientZones); - _clientZones.Clear(); - - foreach (var zoneData in zonePacket.Zones) { - var newZone = new AsteroidZone(zoneData.Center, zoneData.Radius) { - IsMarkedForRemoval = !zoneData.IsActive, - IsMerged = zoneData.IsMerged, - CurrentSpeed = zoneData.CurrentSpeed, - PlayerId = zoneData.PlayerId - }; - _clientZones[zoneData.PlayerId] = newZone; - previousZones.Remove(zoneData.PlayerId); + if (significantZoneChange) { + Log.Info("Significant zone change detected, clearing client state"); + _knownAsteroidIds.Clear(); + _serverPositions.Clear(); + _serverRotations.Clear(); } - foreach (var removedZone in previousZones.Values) { - _lastRemovedZones.Enqueue(removedZone); - while (_lastRemovedZones.Count > 5) { - _lastRemovedZones.Dequeue(); + if (!MyAPIGateway.Session.IsServer) { + _clientZones.Clear(); + foreach (var zoneData in zonePacket.Zones) { + var newZone = new AsteroidZone(zoneData.Center, zoneData.Radius) { + IsMarkedForRemoval = !zoneData.IsActive, + IsMerged = zoneData.IsMerged, + CurrentSpeed = zoneData.CurrentSpeed, + LastActiveTime = DateTime.UtcNow + }; + _clientZones[zoneData.PlayerId] = newZone; + _lastProcessedZonePositions[zoneData.PlayerId] = zoneData.Center; } - if (!MyAPIGateway.Session.IsServer) { - var entities = new HashSet(); - MyAPIGateway.Entities.GetEntities(entities); - foreach (var entity in entities) { - var asteroid = entity as AsteroidEntity; - if (asteroid != null && removedZone.IsPointInZone(asteroid.PositionComp.GetPosition())) { - RemoveAsteroidOnClient(asteroid.EntityId); + // Clean up asteroids that are no longer in any zone + var entities = new HashSet(); + MyAPIGateway.Entities.GetEntities(entities); + foreach (var entity in entities) { + var asteroid = entity as AsteroidEntity; + if (asteroid == null) continue; + + bool inAnyZone = false; + foreach (var zone in _clientZones.Values) { + if (zone.IsPointInZone(asteroid.PositionComp.GetPosition())) { + inAnyZone = true; + break; } } + + if (!inAnyZone) { + RemoveAsteroidOnClient(asteroid.EntityId); + } } } } @@ -988,6 +994,7 @@ private void ProcessZoneMessage(byte[] message) { Log.Exception(ex, typeof(MainSession), "Error processing zone packet"); } } + private void OnSettingsSyncReceived(ushort handlerId, byte[] data, ulong steamId, bool isFromServer) { if (!isFromServer) return; diff --git a/Dynamic Asteroids/Data/Scripts/DynamicAsteroids/ZoneNetworkManager.cs b/Dynamic Asteroids/Data/Scripts/DynamicAsteroids/ZoneNetworkManager.cs index 9c8ca1b..22a9a79 100644 --- a/Dynamic Asteroids/Data/Scripts/DynamicAsteroids/ZoneNetworkManager.cs +++ b/Dynamic Asteroids/Data/Scripts/DynamicAsteroids/ZoneNetworkManager.cs @@ -8,68 +8,42 @@ using VRage.Game.ModAPI; using VRageMath; -namespace DynamicAsteroids.Data.Scripts.DynamicAsteroids -{ - public class ZoneNetworkManager - { +namespace DynamicAsteroids.Data.Scripts.DynamicAsteroids { + public class ZoneNetworkManager { private Dictionary> _playerZoneAwareness = new Dictionary>(); - private const double ZONE_AWARENESS_RADIUS = 25000; + private const double ZONE_AWARENESS_RADIUS = 25000; // Only sync zones within this range - public void UpdateZoneAwareness(Dictionary playerPositions, - ConcurrentDictionary zones) - { - // Clear old awareness data - _playerZoneAwareness.Clear(); - - // Build new awareness data - foreach (var playerKvp in playerPositions) - { - var playerPos = playerKvp.Value; - var playerid = playerKvp.Key; - - // First, add player's own zone - var ownZone = zones.FirstOrDefault(z => z.Value.IsPointInZone(playerPos)); - if (ownZone.Value != null) - { - if (!_playerZoneAwareness.ContainsKey(playerid)) - { - _playerZoneAwareness[playerid] = new HashSet(); - } - - _playerZoneAwareness[playerid].Add(ownZone.Key); + public void UpdateZoneAwareness( + Dictionary playerPositions, + ConcurrentDictionary zones) { + foreach (var player in playerPositions) { + if (!_playerZoneAwareness.ContainsKey(player.Key)) { + _playerZoneAwareness[player.Key] = new HashSet(); + } - // Then check for merged zones - foreach (var otherZone in zones) - { - if (otherZone.Key == ownZone.Key) continue; + // Find zones this player should be aware of + var relevantZones = zones.Where(z => + Vector3D.Distance(player.Value, z.Value.Center) <= ZONE_AWARENESS_RADIUS); - double distance = Vector3D.Distance(ownZone.Value.Center, otherZone.Value.Center); - if (distance <= ownZone.Value.Radius + otherZone.Value.Radius) - { - _playerZoneAwareness[playerid].Add(otherZone.Key); - } - } - } + _playerZoneAwareness[player.Key] = new HashSet(relevantZones.Select(z => z.Key)); } } - public void SendBatchedUpdates(List updates, ConcurrentDictionary zones) - { - if (updates == null || updates.Count == 0 || zones == null || zones.Count == 0) - { + public void SendBatchedUpdates(List updates, ConcurrentDictionary zones) { + if (updates == null || updates.Count == 0 || zones == null || zones.Count == 0) { return; } // Group updates by zone - var updatesByZone = updates.GroupBy(u => - { + var updatesByZone = updates.GroupBy(u => { var zone = zones.FirstOrDefault(z => z.Value.IsPointInZone(u.Position)); return zone.Key; - }).Where(g => g.Key != 0); + }).Where(g => g.Key != 0); // Filter out updates with no zone + + if (!updatesByZone.Any()) return; - foreach (var zoneGroup in updatesByZone) - { - // Find players who should receive updates for this zone + foreach (var zoneGroup in updatesByZone) { + // Find players who should receive these updates var relevantPlayers = _playerZoneAwareness .Where(p => p.Value.Contains(zoneGroup.Key)) .Select(p => p.Key) @@ -77,36 +51,33 @@ public void SendBatchedUpdates(List updates, ConcurrentDictionary if (relevantPlayers.Count == 0) continue; - // Send updates in batches + // Send batched updates only to relevant players const int MAX_UPDATES_PER_PACKET = 25; - for (int i = 0; i < zoneGroup.Count(); i += MAX_UPDATES_PER_PACKET) - { + for (int i = 0; i < zoneGroup.Count(); i += MAX_UPDATES_PER_PACKET) { var batch = zoneGroup.Skip(i).Take(MAX_UPDATES_PER_PACKET).ToList(); if (batch.Count == 0) continue; var packet = new AsteroidBatchUpdatePacket(); packet.Updates.AddRange(batch); + byte[] data = MyAPIGateway.Utilities.SerializeToBinary(packet); - foreach (var playerId in relevantPlayers) - { - var steamId = NetworkUtils.GetSteamId(playerId); - if (steamId != 0) - { + // Send only to players who care about this zone + foreach (var playerId in relevantPlayers) { + var steamId = GetSteamId(playerId); + if (steamId != 0) { MyAPIGateway.Multiplayer.SendMessageTo(32000, data, steamId); } } } } } - } - public static class NetworkUtils { - public static ulong GetSteamId(long playerId) { + private ulong GetSteamId(long playerId) { var players = new List(); MyAPIGateway.Players.GetPlayers(players); var player = players.FirstOrDefault(p => p.IdentityId == playerId); - return player != null ? player.SteamUserId : 0; + return player?.SteamUserId ?? 0; } } -} \ No newline at end of file +}