Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace AssettoServer.Network.Tcp;
namespace AssettoServer.Shared.Model;

public enum ChecksumStatus
{
Expand Down
27 changes: 26 additions & 1 deletion AssettoServer.Shared/Model/IClient.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,34 @@
namespace AssettoServer.Shared.Model;
using System.Numerics;
using AssettoServer.Shared.Network.Packets.Outgoing;
using Serilog;

namespace AssettoServer.Shared.Model;

public interface IClient
{
public CarStatus Status { get; set; }
public byte SessionId { get; }
public ulong Guid { get; }
public string HashedGuid { get; }
public string? Name { get; }
public string? Team { get; }
public string? NationCode { get; }

public bool IsAdministrator { get; }
public int SecurityLevel { get; }
public bool IsConnected { get; set; }
public ushort Ping { get; set; }
public int TimeOffset { get; set; }
public long LastPingTime { get; set; }
public long LastPongTime { get; set; }
public bool HasSentFirstUpdate { get; }
public bool HasUdpEndpoint { get; }
public bool IsDisconnectRequested { get; }
public ChecksumStatus ChecksumStatus { get; }
public int? CSPVersion { get; }
public bool SupportsCSPCustomUpdate { get; }
public IEntryCar EntryCar { get; }
public IEntryCar? TargetCar { get; set; }

public ILogger Logger { get; }
}
29 changes: 25 additions & 4 deletions AssettoServer.Shared/Model/IEntryCar.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,34 @@
namespace AssettoServer.Shared.Model;

public interface IEntryCar<out TClient> where TClient : IClient
public interface IEntryCar
{
public IClient? Client { get; set; }
public byte SessionId { get; }
public bool IsSpectator { get; }
public string Model { get; }
public string Skin { get; }
public CarStatus Status { get; }
public TClient? Client { get; }
public bool IsSpectator { get; }
public float Ballast { get; set; }
public int Restrictor { get; set; }
public string? FixedSetup { get; }
public string LegalTyres { get; }
public bool ForceLights { get; set; }
public bool AiControlled { get; }
public AiMode AiMode { get; set; }
public string? AiName { get; }

public bool IsInRange(IEntryCar target, float range);
public void Reset();
public void SetActive();
public void SetAiOverbooking(int count);

public void SetCollisions(bool enable);

public bool TryResetPosition();
}

public enum AiMode
{
None,
Auto,
Fixed
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ public class CarListResponse : IOutgoingNetworkPacket
{
public int PageIndex;
public int EntryCarsCount;
public required IEnumerable<IEntryCar<IClient>> EntryCars;
public required IEnumerable<IEntryCar> EntryCars;
public required Dictionary<byte, EntryCarResult> CarResults;

public void ToWriter(ref PacketWriter writer)
Expand All @@ -23,7 +23,7 @@ public void ToWriter(ref PacketWriter writer)
writer.WriteUTF8String(CarResults[car.SessionId].Team);
writer.WriteUTF8String(CarResults[car.SessionId].NationCode);
writer.Write(car.IsSpectator);
writer.Write(car.Status.DamageZoneLevel);
writer.Write(car.Client?.Status.DamageZoneLevel ?? new DamageZoneLevel());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ public class CurrentSessionUpdate : IOutgoingNetworkPacket
{
public Session? CurrentSession;
public float TrackGrip;
public IEnumerable<IEntryCar<IClient>>? Grid;
public IEnumerable<IEntryCar>? Grid;
public long StartTime;

public void ToWriter(ref PacketWriter writer)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace AssettoServer.Shared.Network.Packets.Outgoing;

public class DriverInfoUpdate : IOutgoingNetworkPacket
{
public required IEnumerable<IEntryCar<IClient>> ConnectedCars { get; init; }
public required IEnumerable<IEntryCar> ConnectedCars { get; init; }

public void ToWriter(ref PacketWriter writer)
{
Expand Down
2 changes: 1 addition & 1 deletion AssettoServer/Commands/ACModuleBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace AssettoServer.Commands;
[UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)]
public class ACModuleBase : ModuleBase<BaseCommandContext>
{
public ACTcpClient? Client => (Context as ChatCommandContext)?.Client;
public PlayerClient? Client => (Context as ChatCommandContext)?.Client;

public void Reply(string message)
=> Context.Reply(message);
Expand Down
26 changes: 15 additions & 11 deletions AssettoServer/Commands/ChatService.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
using System;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using AssettoServer.Commands.Contexts;
using AssettoServer.Commands.TypeParsers;
using AssettoServer.Network.Rcon;
using AssettoServer.Network.Tcp;
using AssettoServer.Server;
using AssettoServer.Server.Plugin;
using AssettoServer.Shared.Model;
using AssettoServer.Shared.Network.Packets.Shared;
using AssettoServer.Utils;
using Qmmands;
Expand All @@ -19,13 +18,13 @@ namespace AssettoServer.Commands;
public partial class ChatService
{
private readonly EntryCarManager _entryCarManager;
private readonly Func<ACTcpClient, ChatCommandContext> _chatContextFactory;
private readonly Func<PlayerClient, ChatCommandContext> _chatContextFactory;
private readonly CommandService _commandService;

public event EventHandler<ACTcpClient, ChatEventArgs>? MessageReceived;
public event EventHandler<PlayerClient, ChatEventArgs>? MessageReceived;

public ChatService(ACPluginLoader loader,
Func<ACTcpClient, ChatCommandContext> chatContextFactory,
Func<PlayerClient, ChatCommandContext> chatContextFactory,
ACClientTypeParser acClientTypeParser,
EntryCarManager entryCarManager,
CommandService commandService)
Expand All @@ -45,12 +44,17 @@ public ChatService(ACPluginLoader loader,
}
}

private void OnClientConnected(ACTcpClient sender, EventArgs args)
private void OnClientConnected(IClient sender, EventArgs args)
{
sender.ChatMessageReceived += OnChatMessageReceived;
switch (sender)
{
case PlayerClient client:
client.ChatMessageReceived += OnChatMessageReceived;
break;
}
}

private async Task ProcessCommandAsync(ACTcpClient client, ChatMessage message)
private async Task ProcessCommandAsync(PlayerClient client, ChatMessage message)
=> await ProcessCommandAsync(_chatContextFactory(client), message.Message);

public async Task ProcessCommandAsync(BaseCommandContext context, string command)
Expand All @@ -74,7 +78,7 @@ private ValueTask OnCommandExecutionFailed(object? sender, CommandExecutionFaile
return ValueTask.CompletedTask;
}

private void OnChatMessageReceived(ACTcpClient sender, ChatMessageEventArgs args)
private void OnChatMessageReceived(PlayerClient sender, ChatMessageEventArgs args)
{
if (!CommandUtilities.HasPrefix(args.ChatMessage.Message, '/', out string commandStr))
{
Expand All @@ -91,9 +95,9 @@ private void OnChatMessageReceived(ACTcpClient sender, ChatMessageEventArgs args

foreach (var car in _entryCarManager.EntryCars)
{
if (car.Client is { HasSentFirstUpdate: true })
if (car.Client is PlayerClient { HasSentFirstUpdate: true } playerClient)
{
car.Client?.SendPacket(car.Client?.CSPVersion < CSPVersion.V0_1_80_p389 ? oldVersionMessage : args.ChatMessage);
playerClient.SendPacket(car.Client?.CSPVersion < CSPVersion.V0_1_80_p389 ? oldVersionMessage : args.ChatMessage);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions AssettoServer/Commands/Contexts/ChatCommandContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
namespace AssettoServer.Commands.Contexts;

public class ChatCommandContext(
ACTcpClient client,
PlayerClient client,
EntryCarManager entryEntryCarManager,
IServiceProvider? serviceProvider = null)
: BaseCommandContext(entryEntryCarManager, serviceProvider)
{
public ACTcpClient Client { get; } = client;
public PlayerClient Client { get; } = client;

public override bool IsAdministrator => Client.IsAdministrator;

Expand Down
22 changes: 11 additions & 11 deletions AssettoServer/Commands/Modules/AdminModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public AdminModule(IWeatherImplementation weatherImplementation,
}

[Command("kick", "kick_id")]
public Task KickAsync(ACTcpClient player, [Remainder] string? reason = null)
public Task KickAsync(PlayerClient player, [Remainder] string? reason = null)
{
if (player.SessionId == Client?.SessionId)
Reply("You cannot kick yourself.");
Expand All @@ -62,7 +62,7 @@ public Task KickAsync(ACTcpClient player, [Remainder] string? reason = null)
}

[Command("ban", "ban_id")]
public Task BanAsync(ACTcpClient player, [Remainder] string? reason = null)
public Task BanAsync(PlayerClient player, [Remainder] string? reason = null)
{
if (player.SessionId == Client?.SessionId)
Reply("You cannot ban yourself.");
Expand Down Expand Up @@ -98,7 +98,7 @@ public void RestartSessionAsync()
}

[Command("pit")]
public void TeleportToPits([Remainder] ACTcpClient player)
public void TeleportToPits([Remainder] PlayerClient player)
{
_sessionManager.SendCurrentSession(player);
player.SendChatMessage("You have been teleported to the pits.");
Expand Down Expand Up @@ -183,13 +183,13 @@ public void SetGrip(float grip)
}

[Command("distance"), RequireConnectedPlayer]
public void GetDistance([Remainder] ACTcpClient player)
public void GetDistance([Remainder] PlayerClient player)
{
Reply(Vector3.Distance(Client!.EntryCar.Status.Position, player.EntryCar.Status.Position).ToString(CultureInfo.InvariantCulture));
Reply(Vector3.Distance(Client!.Status.Position, player.Status.Position).ToString(CultureInfo.InvariantCulture));
}

[Command("forcelights")]
public void ForceLights(string toggle, [Remainder] ACTcpClient player)
public void ForceLights(string toggle, [Remainder] PlayerClient player)
{
bool forceLights = toggle == "on";
player.EntryCar.ForceLights = forceLights;
Expand All @@ -198,11 +198,11 @@ public void ForceLights(string toggle, [Remainder] ACTcpClient player)
}

[Command("whois")]
public void WhoIs(ACTcpClient player)
public void WhoIs(PlayerClient player)
{
Reply($"IP: {((IPEndPoint?)player.TcpClient.Client.RemoteEndPoint)?.Redact(_configuration.Extra.RedactIpAddresses)}");
Reply($"Profile: https://steamcommunity.com/profiles/{player.Guid}\nPing: {player.EntryCar.Ping}ms");
Reply($"Position: {player.EntryCar.Status.Position}\nVelocity: {(int)(player.EntryCar.Status.Velocity.Length() * 3.6)}kmh");
Reply($"Profile: https://steamcommunity.com/profiles/{player.Guid}\nPing: {player.Ping}ms");
Reply($"Position: {player.Status.Position}\nVelocity: {(int)(player.Status.Velocity.Length() * 3.6)}kmh");
if (player.OwnerGuid.HasValue && player.Guid != player.OwnerGuid)
{
Reply($"Steam Family Sharing Owner: https://steamcommunity.com/profiles/{player.OwnerGuid}");
Expand All @@ -211,7 +211,7 @@ public void WhoIs(ACTcpClient player)

// keep restrict for backwards compatibility
[Command("restrict", "restrictor")]
public void Restrict(ACTcpClient player, int restrictor)
public void Restrict(PlayerClient player, int restrictor)
{
if (restrictor is > 400 or < 0)
{
Expand All @@ -225,7 +225,7 @@ public void Restrict(ACTcpClient player, int restrictor)
}

[Command("ballast")]
public void Ballast(ACTcpClient? player = null, float? ballastKg = null)
public void Ballast(PlayerClient? player = null, float? ballastKg = null)
{
if (player == null || ballastKg == null)
{
Expand Down
2 changes: 1 addition & 1 deletion AssettoServer/Commands/Modules/GeneralModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public GeneralModule(WeatherManager weatherManager,

[Command("ping"), RequireConnectedPlayer]
public void Ping()
=> Reply($"Pong! {Client!.EntryCar.Ping}ms.");
=> Reply($"Pong! {Client!.Ping}ms.");

[Command("time")]
public void Time()
Expand Down
31 changes: 16 additions & 15 deletions AssettoServer/Commands/TypeParsers/ACClientTypeParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace AssettoServer.Commands.TypeParsers;

public class ACClientTypeParser : TypeParser<ACTcpClient>
public class ACClientTypeParser : TypeParser<PlayerClient>
{
private readonly EntryCarManager _entryCarManager;

Expand All @@ -16,33 +16,34 @@ public ACClientTypeParser(EntryCarManager entryCarManager)
_entryCarManager = entryCarManager;
}

public override ValueTask<TypeParserResult<ACTcpClient>> ParseAsync(Parameter parameter, string value, CommandContext context)
public override ValueTask<TypeParserResult<PlayerClient>> ParseAsync(Parameter parameter, string value, CommandContext context)
{
if (int.TryParse(value, out int result)
&& _entryCarManager.ConnectedCars.TryGetValue(result, out EntryCar? car)
&& car.Client != null)
&& car.Client is PlayerClient carClient)
{
return TypeParserResult<ACTcpClient>.Successful(car.Client);
return TypeParserResult<PlayerClient>.Successful(carClient);
}

if (ulong.TryParse(value, out ulong guid)
&& _entryCarManager.ConnectedCars.FirstOrDefault(x => x.Value.Client?.Guid == guid) is { Value.Client: not null } guidCar)
&& _entryCarManager.ConnectedCars.FirstOrDefault(x => x.Value.Client?.Guid == guid) is { Value.Client: not null } guidCar
&& guidCar.Value.Client is PlayerClient guidCarClient)
{
return TypeParserResult<ACTcpClient>.Successful(guidCar.Value.Client);
return TypeParserResult<PlayerClient>.Successful(guidCarClient);
}

ACTcpClient? exactMatch = null;
ACTcpClient? ignoreCaseMatch = null;
ACTcpClient? containsMatch = null;
ACTcpClient? ignoreCaseContainsMatch = null;
PlayerClient? exactMatch = null;
PlayerClient? ignoreCaseMatch = null;
PlayerClient? containsMatch = null;
PlayerClient? ignoreCaseContainsMatch = null;

if (value.StartsWith('@'))
value = value[1..];

foreach (EntryCar entryCar in _entryCarManager.EntryCars)
{
ACTcpClient? client = entryCar.Client;
if (client != null && client.Name != null)
if (entryCar.Client is not PlayerClient client) continue;
if (client.Name != null)
{
if (client.Name == value)
{
Expand All @@ -58,7 +59,7 @@ public override ValueTask<TypeParserResult<ACTcpClient>> ParseAsync(Parameter pa
}
}

ACTcpClient? bestMatch = null;
PlayerClient? bestMatch = null;
if (exactMatch != null)
bestMatch = exactMatch;
else if (ignoreCaseMatch != null)
Expand All @@ -69,8 +70,8 @@ public override ValueTask<TypeParserResult<ACTcpClient>> ParseAsync(Parameter pa
bestMatch = ignoreCaseContainsMatch;

if (bestMatch != null)
return TypeParserResult<ACTcpClient>.Successful(bestMatch);
return TypeParserResult<PlayerClient>.Successful(bestMatch);

return ValueTask.FromResult(TypeParserResult<ACTcpClient>.Failed("This player is not connected."));
return ValueTask.FromResult(TypeParserResult<PlayerClient>.Failed("This player is not connected."));
}
}
Loading