Skip to content

Commit

Permalink
feat(game): add basic observability (#190)
Browse files Browse the repository at this point in the history
added gauge for connections
added gauge for entities per map
added histogram for tick time
  • Loading branch information
MeikelLP authored Oct 12, 2024
1 parent 603d404 commit cd510fd
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 19 deletions.
17 changes: 10 additions & 7 deletions src/Executables/Game/GameServer.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Collections.Immutable;
using System.Diagnostics;
using System.Diagnostics.Metrics;
using System.Net;
using System.Reflection;
using Microsoft.Extensions.Logging;
Expand All @@ -14,16 +15,15 @@
using QuantumCore.Core.Networking;
using QuantumCore.Core.Utils;
using QuantumCore.Extensions;
using QuantumCore.Game.Commands;
using QuantumCore.Game.Persistence;
using QuantumCore.Game.PlayerUtils;
using QuantumCore.Game.Services;
using QuantumCore.Networking;

namespace QuantumCore.Game
{
public class GameServer : ServerBase<GameConnection>, IGame, IGameServer
{
public static readonly Meter Meter = new Meter("QuantumCore:Game");
private readonly Histogram<double> _serverTimes = Meter.CreateHistogram<double>("TickTime", "ms");
private readonly HostingOptions _hostingOptions;
private readonly ILogger<GameServer> _logger;
private readonly PluginExecutor _pluginExecutor;
Expand Down Expand Up @@ -78,6 +78,7 @@ public GameServer(IOptions<HostingOptions> hostingOptions, IPacketManager packet
_dropProvider = dropProvider;
_skillManager = skillManager;
Instance = this;
Meter.CreateObservableGauge("Connections", () => Connections.Length);
}

private void Update(double elapsedTime)
Expand Down Expand Up @@ -111,7 +112,7 @@ await Task.WhenAll(
_skillManager.LoadAsync(stoppingToken)
);


// Initialize session manager
_sessionManager.Init(this);

Expand Down Expand Up @@ -166,13 +167,15 @@ await _pluginExecutor.ExecutePlugins<IGameTickListener>(_logger,
private async ValueTask Tick()
{
var currentTicks = _gameTime.Elapsed.Ticks;
_accumulatedElapsedTime += TimeSpan.FromTicks(currentTicks - _previousTicks);
var elapsedTime = TimeSpan.FromTicks(currentTicks - _previousTicks);
_serverTimes.Record(elapsedTime.TotalMilliseconds);
_accumulatedElapsedTime += elapsedTime;
_previousTicks = currentTicks;

if (_accumulatedElapsedTime < _targetElapsedTime)
{
var sleepTime = (_targetElapsedTime - _accumulatedElapsedTime).TotalMilliseconds;
await Task.Delay((int)sleepTime).ConfigureAwait(false);
await Task.Delay((int) sleepTime).ConfigureAwait(false);
return;
}

Expand Down Expand Up @@ -200,4 +203,4 @@ public void RegisterCommandNamespace(Type t)
_commandManager.Register(t.Namespace!, t.Assembly);
}
}
}
}
33 changes: 21 additions & 12 deletions src/Executables/Game/World/Map.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System.Diagnostics.Metrics;
using System.Security.Cryptography;
using EnumsNET;
using Microsoft.Extensions.Logging;
Expand Down Expand Up @@ -33,6 +34,7 @@ public class Map : IMap
public IWorld World => _world;
public IReadOnlyCollection<IEntity> Entities => _entities;

private readonly ObservableGauge<int> _entityGauge;
private readonly List<IEntity> _entities = new();
private readonly QuadTree _quadTree;
private readonly List<SpawnPoint> _spawnPoints = new();
Expand Down Expand Up @@ -70,6 +72,7 @@ public Map(IMonsterManager monsterManager, IAnimationManager animationManager, I
Width = width;
Height = height;
_quadTree = new QuadTree((int) x, (int) y, (int) (width * MapUnit), (int) (height * MapUnit), 20);
_entityGauge = GameServer.Meter.CreateObservableGauge($"Map:{name}:EntityCount", () => Entities.Count);
}

public async Task Initialize()
Expand All @@ -83,7 +86,7 @@ public async Task Initialize()
_spawnPoints.AddRange(await _spawnPointProvider.GetSpawnPointsForMap(Name));

_logger.LogDebug("Loaded {SpawnPointsCount} spawn points for map {MapName}", _spawnPoints.Count, Name);

// Populate map
foreach (var spawnPoint in _spawnPoints)
{
Expand Down Expand Up @@ -298,34 +301,39 @@ private MonsterEntity SpawnMonster(uint id, SpawnPoint spawnPoint)

if (monster.Proto.AiFlag.HasAnyFlags(EAiFlags.NoMove))
{
monster.PositionX = (int)(PositionX + baseX * SPAWN_POSITION_MULTIPLIER);
monster.PositionY = (int)(PositionY + baseY * SPAWN_POSITION_MULTIPLIER);
var compassDirection = (int)spawnPoint.Direction - 1;
if (compassDirection < 0 || compassDirection > (int)Enum.GetValues<ESpawnPointDirection>().Last())
monster.PositionX = (int) (PositionX + baseX * SPAWN_POSITION_MULTIPLIER);
monster.PositionY = (int) (PositionY + baseY * SPAWN_POSITION_MULTIPLIER);
var compassDirection = (int) spawnPoint.Direction - 1;

if (compassDirection < 0 || compassDirection > (int) Enum.GetValues<ESpawnPointDirection>().Last())
{
compassDirection = (int)ESpawnPointDirection.Random;
compassDirection = (int) ESpawnPointDirection.Random;
}

var rotation = SPAWN_ROTATION_SLICE_DEGREES * compassDirection;
monster.Rotation = rotation;
}
else
{
monster.PositionX = (int) PositionX + (baseX + RandomNumberGenerator.GetInt32(-SPAWN_BASE_OFFSET, SPAWN_BASE_OFFSET)) * SPAWN_POSITION_MULTIPLIER;
monster.PositionY = (int) PositionY + (baseY + RandomNumberGenerator.GetInt32(-SPAWN_BASE_OFFSET, SPAWN_BASE_OFFSET)) * SPAWN_POSITION_MULTIPLIER;
monster.PositionX = (int) PositionX +
(baseX + RandomNumberGenerator.GetInt32(-SPAWN_BASE_OFFSET, SPAWN_BASE_OFFSET)) *
SPAWN_POSITION_MULTIPLIER;
monster.PositionY = (int) PositionY +
(baseY + RandomNumberGenerator.GetInt32(-SPAWN_BASE_OFFSET, SPAWN_BASE_OFFSET)) *
SPAWN_POSITION_MULTIPLIER;
}

if (monster.Rotation == 0)
{
monster.Rotation = RandomNumberGenerator.GetInt32(0, 360);
}

EventSystem.EnqueueEvent(() =>
{
_world.SpawnEntity(monster);
return 0;
}, spawnPoint.RespawnTime * 1000);

return monster;
}

Expand Down Expand Up @@ -362,7 +370,8 @@ public void SpawnEntity(IEntity entity)
/// <param name="ownerName"></param>
public void AddGroundItem(ItemInstance item, int x, int y, uint amount = 0, string? ownerName = null)
{
var groundItem = new GroundItem(_animationManager, _world.GenerateVid(), item, amount, ownerName) {
var groundItem = new GroundItem(_animationManager, _world.GenerateVid(), item, amount, ownerName)
{
PositionX = x,
PositionY = y
};
Expand Down
1 change: 1 addition & 0 deletions src/Executables/Game/World/World.cs
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ public void SpawnEntity(IEntity e)

_pluginExecutor.ExecutePlugins<IGameEntityLifetimeListener>(_logger, x => x.OnPreCreatedAsync()).Wait();
map.SpawnEntity(e);

_pluginExecutor.ExecutePlugins<IGameEntityLifetimeListener>(_logger, x => x.OnPostCreatedAsync()).Wait();
}

Expand Down

0 comments on commit cd510fd

Please sign in to comment.