Reformat & Cleanup

This commit is contained in:
MSWS
2025-07-28 13:26:40 -07:00
parent 404fef40b0
commit c8b5941837
40 changed files with 162 additions and 167 deletions

View File

@@ -2,7 +2,7 @@ namespace TTT.Api.Events;
[AttributeUsage(AttributeTargets.Method)]
public class EventHandlerAttribute : Attribute {
public uint Priority { get; set; } = TTT.Api.Events.Priority.DEFAULT;
public uint Priority { get; set; } = Events.Priority.DEFAULT;
public bool IgnoreCanceled { get; set; } = false;
}

View File

@@ -4,8 +4,8 @@ namespace TTT.Api;
public interface IGame {
/// <summary>
/// The list of players in the game.
/// Spectators are not included in this list.
/// The list of players in the game.
/// Spectators are not included in this list.
/// </summary>
ICollection<IPlayer> Players { get; }
@@ -14,8 +14,8 @@ public interface IGame {
SortedDictionary<DateTime, ISet<IAction>> Actions { get; }
/// <summary>
/// Attempts to start a game.
/// Depending on implementation, this may start a countdown or immediately start the game.
/// Attempts to start a game.
/// Depending on implementation, this may start a countdown or immediately start the game.
/// </summary>
void Start();
}

View File

@@ -3,6 +3,7 @@ using CounterStrikeSharp.API.Core;
namespace TTT.Api;
public interface IPluginModule : ITerrorModule {
void Start(BasePlugin? plugin) => Start();
void Start(BasePlugin? plugin, bool hotReload) => Start(plugin);
void Start(BasePlugin? plugin) { Start(); }
void Start(BasePlugin? plugin, bool hotReload) { Start(plugin); }
}

View File

@@ -4,8 +4,8 @@ using TTT.Api.Player;
namespace TTT.Api;
/// <summary>
/// Represents a role that can be assigned to a player.
/// Does not necessarily imply they are in the game.
/// Represents a role that can be assigned to a player.
/// Does not necessarily imply they are in the game.
/// </summary>
public interface IRole {
string Id { get; }

View File

@@ -4,7 +4,7 @@ namespace TTT.Api.Messages;
public interface IMessenger {
/// <summary>
/// Attempt to send a message to a player.
/// Attempt to send a message to a player.
/// </summary>
/// <param name="player">The player to send the message to.</param>
/// <param name="message">The message to send</param>
@@ -12,24 +12,26 @@ public interface IMessenger {
Task<bool> Message(IPlayer player, string message);
/// <summary>
/// Attempt to send a message to a player without showing it on the screen.
/// This could mean sending to console, background file, or just
/// falling back to showing it on the screen.
/// Attempt to send a message to a player without showing it on the screen.
/// This could mean sending to console, background file, or just
/// falling back to showing it on the screen.
/// </summary>
/// <param name="player"></param>
/// <param name="message"></param>
/// <returns></returns>
Task<bool> BackgroundMsg(IPlayer player, string message)
=> Message(player, message);
Task<bool> BackgroundMsg(IPlayer player, string message) {
return Message(player, message);
}
/// <summary>
/// Attempt to send a message to a player that will be shown on the screen using
/// an alternative method, such as a popup or a notification.
/// May just fall back to showing it on the screen if no alternative is available.
/// Attempt to send a message to a player that will be shown on the screen using
/// an alternative method, such as a popup or a notification.
/// May just fall back to showing it on the screen if no alternative is available.
/// </summary>
/// <param name="player"></param>
/// <param name="message"></param>
/// <returns></returns>
Task<bool> ScreenMsg(IPlayer player, string message)
=> Message(player, message);
Task<bool> ScreenMsg(IPlayer player, string message) {
return Message(player, message);
}
}

View File

@@ -2,8 +2,8 @@ namespace TTT.Api.Player;
public interface IPlayer {
/// <summary>
/// The unique identifier for the player, should
/// be unique across all players at all times.
/// The unique identifier for the player, should
/// be unique across all players at all times.
/// </summary>
string Id { get; }

View File

@@ -1,3 +1,4 @@
# TTT - API
This project contains the public API for TTT.
No game logic, internal management, etc. is (or ever should be) included here.

View File

@@ -8,11 +8,6 @@ namespace TTT.CS2;
public class CCPlayerConverter : IPluginModule,
IPlayerConverter<CCSPlayerController> {
private readonly Dictionary<string, CS2Player> playerCache = new();
public void Dispose() { playerCache.Clear(); }
public string Name => "PlayerConverter";
public string Version => GitVersionInformation.FullSemVer;
public void Start() { }
public IPlayer GetPlayer(CCSPlayerController player) {
if (playerCache.TryGetValue(player.SteamID.ToString(),
@@ -23,12 +18,17 @@ public class CCPlayerConverter : IPluginModule,
out var cachedPlayerByIndex))
return cachedPlayerByIndex;
if (player == null) {
if (player == null)
throw new ArgumentNullException(nameof(player), "Player cannot be null");
}
var newPlayer = new CS2Player(player);
playerCache[newPlayer.Id] = newPlayer;
return newPlayer;
}
public void Dispose() { playerCache.Clear(); }
public string Name => "PlayerConverter";
public string Version => GitVersionInformation.FullSemVer;
public void Start() { }
}

View File

@@ -6,16 +6,12 @@ using TTT.Api.Player;
namespace TTT.CS2;
/// <summary>
/// A CS2-specific implementation of <see cref="IOnlinePlayer"/>.
/// Human players will **always** be tracked by their Steam ID.
/// Non-human players (bots) will be tracked by their entity index.
///
/// Note that slot numbers are not guaranteed to be stable across server restarts.
/// A CS2-specific implementation of <see cref="IOnlinePlayer" />.
/// Human players will **always** be tracked by their Steam ID.
/// Non-human players (bots) will be tracked by their entity index.
/// Note that slot numbers are not guaranteed to be stable across server restarts.
/// </summary>
public class CS2Player : IOnlinePlayer {
public string Id { get; }
public string Name { get; }
protected CS2Player(string id, string name) {
Id = id;
Name = name;
@@ -38,10 +34,13 @@ public class CS2Player : IOnlinePlayer {
Name = player.PlayerName;
}
public string Id { get; }
public string Name { get; }
public ICollection<IRole> Roles { get; } = [];
public static string GetKey(CCSPlayerController player) {
if (player.IsBot || player.IsHLTV) return player.Index.ToString();
return player.SteamID.ToString();
}
public ICollection<IRole> Roles { get; } = [];
}

View File

@@ -14,6 +14,8 @@ public class PlayerListeners(IEventBus bus,
public void Start() { }
public void Dispose() { }
[GameEventHandler]
public HookResult OnPlayerConnect(EventPlayerConnectFull ev,
GameEventInfo _) {
@@ -35,6 +37,4 @@ public class PlayerListeners(IEventBus bus,
bus.Dispatch(new PlayerLeaveEvent(gamePlayer));
return HookResult.Continue;
}
public void Dispose() { }
}

View File

@@ -1,7 +1,6 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using TTT.Api.Events;
using TTT.Api.Messages;
using TTT.Api.Player;
using TTT.Game;

View File

@@ -8,7 +8,7 @@
<ItemGroup>
<ProjectReference Include="..\TTT.Api\TTT.Api.csproj"/>
<ProjectReference Include="..\TTT.Game\TTT.Game.csproj" />
<ProjectReference Include="..\TTT.Game\TTT.Game.csproj"/>
</ItemGroup>
<ItemGroup>

View File

@@ -31,7 +31,7 @@ public class EventBus : IEventBus {
}
// Sort handlers by priority
foreach (var type in dirtyTypes) {
foreach (var type in dirtyTypes)
handlers[type]
.Sort((a, b) => {
var aPriority = a.method.GetCustomAttribute<EventHandlerAttribute>()
@@ -40,7 +40,6 @@ public class EventBus : IEventBus {
?.Priority ?? Priority.DEFAULT;
return aPriority.CompareTo(bPriority);
});
}
}
public void UnregisterListener(IListener listener) {
@@ -59,7 +58,8 @@ public class EventBus : IEventBus {
foreach (var (listener, method) in list) {
if (cancelable is { IsCanceled: true } && method
.GetCustomAttribute<EventHandlerAttribute>()
?.IgnoreCanceled == true) { continue; }
?.IgnoreCanceled == true)
continue;
method.Invoke(listener, [ev]);
}

View File

@@ -13,12 +13,14 @@ public abstract class EventModifiedMessenger(IEventBus bus) : IMessenger {
return SendMessage(player, messageEvent.Message);
}
abstract protected Task<bool> SendMessage(IPlayer player, string message);
// Allow for overriding in derived classes
public virtual Task<bool> BackgroundMsg(IPlayer player, string message)
=> Message(player, message);
public virtual Task<bool> BackgroundMsg(IPlayer player, string message) {
return Message(player, message);
}
public virtual Task<bool> ScreenMsg(IPlayer player, string message)
=> Message(player, message);
public virtual Task<bool> ScreenMsg(IPlayer player, string message) {
return Message(player, message);
}
abstract protected Task<bool> SendMessage(IPlayer player, string message);
}

View File

@@ -6,6 +6,6 @@ namespace TTT.Game.Events.Game;
public class GameStateUpdateEvent(IGame game, RoundBasedGame.State newState)
: GameEvent(game), ICancelableEvent {
public override string Id => "basegame.event.game.update";
public bool IsCanceled { get; set; } = false;
public RoundBasedGame.State NewState { get; } = newState;
public bool IsCanceled { get; set; } = false;
}

View File

@@ -7,15 +7,30 @@ namespace TTT.Game.Events.Player;
public class PlayerDamagedEvent(IOnlinePlayer player, IOnlinePlayer? attacker,
int dmgDealt, int hpLeft) : PlayerEvent(player), ICancelableEvent {
public PlayerDamagedEvent(IPlayerConverter<CCSPlayerController> converter,
EventPlayerHurt ev) : this(
converter.GetPlayer(ev.Userid!) as IOnlinePlayer
?? throw new InvalidOperationException(),
ev.Attacker == null ?
null :
converter.GetPlayer(ev.Attacker) as IOnlinePlayer, ev.DmgHealth,
ev.Health) {
ArmorDamage = ev.DmgArmor;
ArmorRemaining = ev.Armor;
DmgDealt = ev.DmgHealth;
HpLeft = ev.Health;
Weapon = ev.Weapon;
}
public override string Id => "basegame.event.player.damaged";
public bool IsCanceled { get; set; } = false;
public IOnlinePlayer? Attacker { get; private set; } = attacker;
public int ArmorDamage { get; private set; } = 0;
public int ArmorRemaining { get; private set; } = 0;
public int ArmorDamage { get; private set; }
public int ArmorRemaining { get; private set; }
public int DmgDealt { get; private set; } = dmgDealt;
public int HpLeft { get; private set; } = hpLeft;
public string Weapon { get; private set; } = string.Empty;
public bool IsCanceled { get; set; } = false;
public PlayerDamagedEvent WithAttacker(IOnlinePlayer? attacker) {
Attacker = attacker;
@@ -31,19 +46,4 @@ public class PlayerDamagedEvent(IOnlinePlayer player, IOnlinePlayer? attacker,
ArmorRemaining = armorRemaining;
return this;
}
public PlayerDamagedEvent(IPlayerConverter<CCSPlayerController> converter,
EventPlayerHurt ev) : this(
converter.GetPlayer(ev.Userid!) as IOnlinePlayer
?? throw new InvalidOperationException(),
ev.Attacker == null ?
null :
converter.GetPlayer(ev.Attacker) as IOnlinePlayer, ev.DmgHealth,
ev.Health) {
ArmorDamage = ev.DmgArmor;
ArmorRemaining = ev.Armor;
DmgDealt = ev.DmgHealth;
HpLeft = ev.Health;
Weapon = ev.Weapon;
}
}

View File

@@ -5,13 +5,24 @@ using TTT.Api.Player;
namespace TTT.Game.Events.Player;
public class PlayerDeathEvent(IPlayer player) : PlayerEvent(player) {
public PlayerDeathEvent(IPlayerConverter<CCSPlayerController> converter,
EventPlayerDeath ev) : this(converter.GetPlayer(ev.Userid!)) {
if (ev.Assister != null) Assister = converter.GetPlayer(ev.Assister);
if (ev.Attacker != null) Killer = converter.GetPlayer(ev.Attacker);
Headshot = ev.Headshot;
NoScope = ev.Noscope;
ThruSmoke = ev.Thrusmoke;
Weapon = ev.Weapon;
}
public override string Id => "basegame.event.player.death";
public IPlayer? Assister { get; private set; } = null;
public IPlayer? Killer { get; private set; } = null;
public bool Headshot { get; private set; } = false;
public bool NoScope { get; private set; } = false;
public bool ThruSmoke { get; private set; } = false;
public IPlayer? Assister { get; private set; }
public IPlayer? Killer { get; private set; }
public bool Headshot { get; private set; }
public bool NoScope { get; private set; }
public bool ThruSmoke { get; private set; }
public string Weapon { get; private set; } = string.Empty;
public PlayerDeathEvent WithAssister(IPlayer? assister) {
@@ -43,15 +54,4 @@ public class PlayerDeathEvent(IPlayer player) : PlayerEvent(player) {
Weapon = weapon;
return this;
}
public PlayerDeathEvent(IPlayerConverter<CCSPlayerController> converter,
EventPlayerDeath ev) : this(converter.GetPlayer(ev.Userid!)) {
if (ev.Assister != null) Assister = converter.GetPlayer(ev.Assister);
if (ev.Attacker != null) Killer = converter.GetPlayer(ev.Attacker);
Headshot = ev.Headshot;
NoScope = ev.Noscope;
ThruSmoke = ev.Thrusmoke;
Weapon = ev.Weapon;
}
}

View File

@@ -3,8 +3,8 @@ using TTT.Api.Player;
namespace TTT.Game.Events.Player;
/// <summary>
/// Indicates that a player has joined the server.
/// A game is not necessarily in progress when this event is fired.
/// Indicates that a player has joined the server.
/// A game is not necessarily in progress when this event is fired.
/// </summary>
/// <param name="player"></param>
public class PlayerJoinEvent(IPlayer player) : PlayerEvent(player) {

View File

@@ -3,8 +3,8 @@ using TTT.Api.Player;
namespace TTT.Game.Events.Player;
/// <summary>
/// Indicates that a player has left the server.
/// A game is not necessarily in progress when this event is fired.
/// Indicates that a player has left the server.
/// A game is not necessarily in progress when this event is fired.
/// </summary>
public class PlayerLeaveEvent(IPlayer player) : PlayerEvent(player) {
public override string Id => "basegame.event.player.leave";

View File

@@ -6,6 +6,6 @@ namespace TTT.Game.Events.Player;
public class PlayerMessageEvent(IPlayer player, string message)
: PlayerEvent(player), ICancelableEvent {
public override string Id => "basegame.event.player.message";
public bool IsCanceled { get; set; } = false;
public string Message { get; set; } = message;
public bool IsCanceled { get; set; } = false;
}

View File

@@ -1,6 +1,4 @@
using System.Drawing;
using TTT.Api;
using TTT.Api.Player;
namespace TTT.Game.Roles;

View File

@@ -9,5 +9,7 @@ public class SpectatorRole : IRole {
public string Name => "Spectator";
public Color Color => Color.Gray;
public IPlayer? FindPlayerToAssign(ISet<IOnlinePlayer> players) => null;
public IPlayer? FindPlayerToAssign(ISet<IOnlinePlayer> players) {
return null;
}
}

View File

@@ -1,6 +1,4 @@
using System.Drawing;
using TTT.Api;
using TTT.Api.Player;
namespace TTT.Game.Roles;

View File

@@ -6,34 +6,24 @@ using TTT.Game.Events.Game;
namespace TTT.Game;
public class RoundBasedGame(IEventBus bus) : IGame {
public ICollection<IPlayer> Players { get; } = new List<IPlayer>();
public DateTime? StartedAt { get; } = null;
public DateTime? FinishedAt { get; } = null;
public SortedDictionary<DateTime, ISet<IAction>> Actions { get; } = new();
public void Start() {
}
public enum State {
/// <summary>
/// Waiting for players to join.
/// Waiting for players to join.
/// </summary>
WAITING,
/// <summary>
/// Waiting for the countdown to finish before starting the game.
/// Waiting for the countdown to finish before starting the game.
/// </summary>
COUNTDOWN,
/// <summary>
/// Currently playing the game.
/// Currently playing the game.
/// </summary>
IN_PROGRESS,
/// <summary>
/// Game has finished.
/// Game has finished.
/// </summary>
FINISHED
}
@@ -50,4 +40,12 @@ public class RoundBasedGame(IEventBus bus) : IGame {
get => currentState;
}
public ICollection<IPlayer> Players { get; } = new List<IPlayer>();
public DateTime? StartedAt { get; } = null;
public DateTime? FinishedAt { get; } = null;
public SortedDictionary<DateTime, ISet<IAction>> Actions { get; } = new();
public void Start() { }
}

View File

@@ -7,11 +7,11 @@
</PropertyGroup>
<ItemGroup>
<Folder Include="Events\" />
<Folder Include="Events\"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\TTT.Api\TTT.Api.csproj" />
<ProjectReference Include="..\TTT.Api\TTT.Api.csproj"/>
</ItemGroup>
</Project>

View File

@@ -1,2 +1,3 @@
# TTT - Plugin
This project is the basic bootstrapper for [TTT.CS2](../TTT.CS2).

View File

@@ -7,13 +7,12 @@ using TTT.Api;
namespace TTT.Plugin;
public class TTT(IServiceProvider provider) : BasePlugin {
private IServiceScope scope = null!;
public override string ModuleName => "TTT.Plugin";
public override string ModuleVersion
=> $"{GitVersionInformation.BranchName}-{GitVersionInformation.FullSemVer}-{GitVersionInformation.BuildMetaDataPadded}";
private IServiceScope scope = null!;
public override void Load(bool hotReload) {
Logger.LogInformation($"{ModuleName} {ModuleVersion} Starting...");

View File

@@ -1,9 +1,6 @@
using TTT.Api;
using TTT.Api.Events;
using TTT.Api.Messages;
using TTT.Api.Player;
using TTT.Game;
using TTT.Game.Events.Player;
namespace TTT.Test.Fakes;

View File

@@ -17,5 +17,5 @@ public class FakePlayerFinder(IEventBus bus) : IPlayerFinder {
bus.Dispatch(new PlayerLeaveEvent(player));
}
public ISet<IOnlinePlayer> GetAllPlayers() => players;
public ISet<IOnlinePlayer> GetAllPlayers() { return players; }
}

View File

@@ -6,6 +6,8 @@ public class CancelableEventListener(IEventBus bus, bool cancelEvent)
: IListener {
public int Fired { get; private set; }
public void Dispose() { bus.UnregisterListener(this); }
[EventHandler]
public void OnEvent(TestEvent e) {
Fired++;
@@ -14,6 +16,4 @@ public class CancelableEventListener(IEventBus bus, bool cancelEvent)
[EventHandler(Priority = Priority.LOW, IgnoreCanceled = true)]
public void AfterOnEvent(TestEvent e) { Fired++; }
public void Dispose() => bus.UnregisterListener(this);
}

View File

@@ -6,14 +6,16 @@ public class PriorityEventListener(IEventBus bus) : IListener {
private readonly List<uint> fireOrders = [];
public List<uint> FireOrders => [..fireOrders];
public void Dispose() { bus.UnregisterListener(this); }
[EventHandler(Priority = Priority.HIGH)]
public void OnEventHighPriority(TestEvent e) => fireOrders.Add(Priority.HIGH);
public void OnEventHighPriority(TestEvent e) {
fireOrders.Add(Priority.HIGH);
}
[EventHandler(Priority = Priority.LOW)]
public void OnEventLowPriority(TestEvent e) => fireOrders.Add(Priority.LOW);
public void OnEventLowPriority(TestEvent e) { fireOrders.Add(Priority.LOW); }
[EventHandler(Priority = Priority.DEFAULT)]
public void OnEvent(TestEvent e) => fireOrders.Add(Priority.DEFAULT);
public void Dispose() { bus.UnregisterListener(this); }
public void OnEvent(TestEvent e) { fireOrders.Add(Priority.DEFAULT); }
}

View File

@@ -3,9 +3,9 @@ using TTT.Api.Events;
namespace TTT.Test.Core.Event;
public class SingleEventListener(IEventBus bus) : IListener {
public int fired { get; private set; } = 0;
public int fired { get; private set; }
public void Dispose() => bus.UnregisterListener(this);
public void Dispose() { bus.UnregisterListener(this); }
[EventHandler]
public void OnTestEvent(TestEvent e) { fired++; }

View File

@@ -1,4 +1,3 @@
using TTT.Api;
using TTT.Api.Events;
using TTT.Api.Messages;
using TTT.Game.Events.Player;

View File

@@ -9,15 +9,6 @@ public class MessageModificationTest(IEventBus bus, IMessenger messenger) {
private const string ORIGINAL_MESSAGE = "Original Message";
private const string MODIFIED_MESSAGE = "Modified Message";
private class MessageModifyListener(IEventBus bus) : IListener {
public void Dispose() => bus.UnregisterListener(this);
[EventHandler]
public void OnMessage(PlayerMessageEvent ev) {
ev.Message = MODIFIED_MESSAGE;
}
}
[Fact]
public void TestMessageModification() {
// Arrange
@@ -32,4 +23,13 @@ public class MessageModificationTest(IEventBus bus, IMessenger messenger) {
Assert.Single(player.Messages);
Assert.Equal(MODIFIED_MESSAGE, player.Messages[0]);
}
private class MessageModifyListener(IEventBus bus) : IListener {
public void Dispose() { bus.UnregisterListener(this); }
[EventHandler]
public void OnMessage(PlayerMessageEvent ev) {
ev.Message = MODIFIED_MESSAGE;
}
}
}

View File

@@ -1,4 +1,5 @@
# TTT.Test
Unit Testing for TTT.
Note: For nix-os developers, use the `nix-shell` command to enter the development environment.

View File

@@ -1,10 +1,8 @@
using Microsoft.Extensions.DependencyInjection;
using TTT.Api;
using TTT.Api.Events;
using TTT.Api.Messages;
using TTT.Api.Player;
using TTT.Game;
using TTT.Plugin;
using TTT.Test.Fakes;
namespace TTT.Test;

View File

@@ -7,28 +7,28 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions">
<HintPath>..\..\..\..\..\..\.nuget\packages\microsoft.extensions.dependencyinjection.abstractions\8.0.0\lib\net8.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions">
<HintPath>..\..\..\..\..\..\.nuget\packages\microsoft.extensions.dependencyinjection.abstractions\8.0.0\lib\net8.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\TTT.Api\TTT.Api.csproj" />
<ProjectReference Include="..\TTT.Plugin\TTT.Plugin.csproj" />
<ProjectReference Include="..\TTT.Api\TTT.Api.csproj"/>
<ProjectReference Include="..\TTT.Plugin\TTT.Plugin.csproj"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="Xunit.DependencyInjection" Version="10.6.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="xunit.v3" Version="3.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1"/>
<PackageReference Include="Xunit.DependencyInjection" Version="10.6.0"/>
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="xunit.v3" Version="3.0.0"/>
</ItemGroup>
<ItemGroup>
<Folder Include="Game\Roles\" />
<Folder Include="Game\Roles\"/>
</ItemGroup>
</Project>

View File

@@ -4,14 +4,13 @@ using TTT.Api.Player;
namespace TTT.Test;
public class TestPlayer(string id, string name) : IOnlinePlayer {
public TestPlayer() : this("314159", "Test Player") { }
public List<string> Messages { get; } = [];
public string Id { get; } = id;
public string Name { get; } = name;
public ICollection<IRole> Roles { get; } = (List<IRole>) [];
public List<string> Messages { get; } = [];
public TestPlayer() : this("314159", "Test Player") { }
public static TestPlayer Random() {
return new TestPlayer(new Random().NextInt64().ToString(),
"Test Player " + Guid.NewGuid());

View File

@@ -1,10 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -1,5 +1,4 @@
using System.Text.Json;
using System.IO;
var jsonPath = Path.Combine(Directory.GetCurrentDirectory(), "gitversion.json");
var outputPath = Path.Combine(Directory.GetCurrentDirectory(),
@@ -26,11 +25,11 @@ foreach (var property in json.EnumerateObject()) {
$" public const string {name} = \"{value.GetString()?.Replace("\"", "\\\"")}\";";
break;
case JsonValueKind.Number:
if (value.TryGetInt32(out int intVal))
if (value.TryGetInt32(out var intVal))
line = $" public const int {name} = {intVal};";
else if (value.TryGetInt64(out long longVal))
else if (value.TryGetInt64(out var longVal))
line = $" public const long {name} = {longVal}L;";
else if (value.TryGetDouble(out double dblVal))
else if (value.TryGetDouble(out var dblVal))
line = $" public const double {name} = {dblVal};";
else
continue; // Skip if unknown number type