Skip to content
Open
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
16 changes: 16 additions & 0 deletions AssettoServer/Server/EventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Numerics;
using System.Text;
using AssettoServer.Network.Tcp;
using AssettoServer.Server.Plugin;
using AssettoServer.Shared.Network.Packets.Outgoing;
using AssettoServer.Shared.Network.Packets.Outgoing.Handshake;
using AssettoServer.Shared.Network.Packets.Shared;
Expand Down Expand Up @@ -146,3 +147,18 @@ public CarListResponseSendingEventArgs(CarListResponse packet)
Packet = packet;
}
}

public class PluginDataEventArgs : EventArgs
{
public required PluginDataType DataType { get; init; }
public required string Plugin { get; init; }
public required string Name { get; init; }

/// <summary>
/// Points: self-explanatory
/// Time: Time in milliseconds
/// EventWin: Can be left as 0
/// </summary>
public long Value { get; init; }
public EntryCar? Opponent { get; init; }
}
20 changes: 20 additions & 0 deletions AssettoServer/Server/Plugin/PluginDataManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace AssettoServer.Server.Plugin;

public class PluginDataManager
{
/// <summary>
/// Fires when a shared event is initiated through a plugin.
/// e.g. A player gets a new PB time or finishes a race challenge.
/// </summary>
public event EventHandler<EntryCar, PluginDataEventArgs>? PluginEvent;

public void SendPluginEvent(EntryCar entryCar, PluginDataEventArgs eventArgs)
=> PluginEvent?.Invoke(entryCar, eventArgs);
}

public enum PluginDataType
{
Points,
Time,
EventWin
}
1 change: 1 addition & 0 deletions AssettoServer/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ public void ConfigureContainer(ContainerBuilder builder)
builder.RegisterType<CSPClientMessageHandler>().AsSelf().SingleInstance();
builder.RegisterType<SessionManager>().AsSelf().SingleInstance();
builder.RegisterType<VoteManager>().AsSelf().SingleInstance();
builder.RegisterType<PluginDataManager>().AsSelf().SingleInstance();
builder.RegisterType<EntryCarManager>().AsSelf().SingleInstance();
builder.RegisterType<IpApiGeoParamsProvider>().As<IGeoParamsProvider>();
builder.RegisterType<GeoParamsManager>().AsSelf().SingleInstance();
Expand Down
59 changes: 58 additions & 1 deletion DiscordAuditPlugin/Discord.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using AssettoServer.Network.Tcp;
using AssettoServer.Server;
using AssettoServer.Server.Configuration;
using AssettoServer.Server.Plugin;
using AssettoServer.Shared.Discord;
using AssettoServer.Shared.Network.Packets.Outgoing;
using CSharpDiscordWebhook.NET.Discord;
Expand All @@ -18,8 +19,13 @@ public class Discord

private DiscordWebhook? AuditHook { get; }
private DiscordWebhook? ChatHook { get; }
private DiscordWebhook? PluginEventHook { get; }

public Discord(DiscordConfiguration configuration, EntryCarManager entryCarManager, ACServerConfiguration serverConfiguration, ChatService chatService)
public Discord(DiscordConfiguration configuration,
EntryCarManager entryCarManager,
PluginDataManager pluginDataManager,
ACServerConfiguration serverConfiguration,
ChatService chatService)
{
_serverNameSanitized = DiscordUtils.SanitizeUsername(serverConfiguration.Server.Name);
_configuration = configuration;
Expand Down Expand Up @@ -49,6 +55,16 @@ public Discord(DiscordConfiguration configuration, EntryCarManager entryCarManag

chatService.MessageReceived += OnChatMessageReceived;
}

if (!string.IsNullOrEmpty(_configuration.PluginEventUrl))
{
PluginEventHook = new DiscordWebhook
{
Uri = new Uri(_configuration.PluginEventUrl)
};

pluginDataManager.PluginEvent += OnPluginEvent;
}
}

private void OnClientConnected(ACTcpClient sender, EventArgs args)
Expand Down Expand Up @@ -232,4 +248,45 @@ private DiscordMessage PrepareAuditMessage(

return message;
}

private void OnPluginEvent(EntryCar sender, PluginDataEventArgs args)
{
if (sender.Client == null) return;

string title;
switch (args.DataType)
{
case PluginDataType.Points:
title = $":joystick: Scored {args.Value} points";
break;
case PluginDataType.Time:
title = $":stopwatch: Time of {TimeSpan.FromMilliseconds(args.Value)}";
break;
case PluginDataType.EventWin:
title = ":trophy: Winner of Event";
break;
default:
return;
}

Task.Run(async () =>
{
try
{
await PluginEventHook!.SendAsync(PrepareAuditMessage(
title,
_serverNameSanitized,
sender.Client.Guid,
sender.Client.Name,
$"Event {args.Name} from plugin {args.Plugin}",
Color.Blue,
null
));
}
catch (Exception ex)
{
Log.Error(ex, "Error in Discord webhook");
}
});
}
}
2 changes: 2 additions & 0 deletions DiscordAuditPlugin/DiscordConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ public class DiscordConfiguration
public string? AuditUrl { get; init; }
[YamlMember(Description = "Discord webhook URL for chat messages")]
public string? ChatUrl { get; init; }
[YamlMember(Description = "Discord webhook URL for plugin events")]
public string? PluginEventUrl { get; init; }
[YamlMember(Description = "Set this to true if the Discord username of the bot should be the AC server name")]
public bool ChatMessageIncludeServerName { get; init; } = false;
[YamlMember(Description = "Set this to true if the audit message should include the Steam ID")]
Expand Down
13 changes: 11 additions & 2 deletions RaceChallengePlugin/Race.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using AssettoServer.Server;
using AssettoServer.Shared.Network.Packets.Shared;
using AssettoServer.Server.Plugin;
using Serilog;

namespace RaceChallengePlugin;
Expand All @@ -24,16 +24,18 @@ public class Race
private readonly SessionManager _sessionManager;
private readonly EntryCarManager _entryCarManager;
private readonly RaceChallengePlugin _plugin;
private readonly PluginDataManager _pluginDataManager;

public delegate Race Factory(EntryCar challenger, EntryCar challenged, bool lineUpRequired = true);

public Race(EntryCar challenger, EntryCar challenged, SessionManager sessionManager, EntryCarManager entryCarManager, RaceChallengePlugin plugin, bool lineUpRequired = true)
public Race(EntryCar challenger, EntryCar challenged, SessionManager sessionManager, EntryCarManager entryCarManager, RaceChallengePlugin plugin, PluginDataManager pluginDataManager, bool lineUpRequired = true)
{
Challenger = challenger;
Challenged = challenged;
_sessionManager = sessionManager;
_entryCarManager = entryCarManager;
_plugin = plugin;
_pluginDataManager = pluginDataManager;
LineUpRequired = lineUpRequired;

ChallengerName = Challenger.Client?.Name!;
Expand Down Expand Up @@ -219,6 +221,13 @@ private void FinishRace()

_entryCarManager.BroadcastChat($"{winnerName} just beat {loserName} in a race.");
Log.Information("{WinnerName} just beat {LoserName} in a race", winnerName, loserName);
_pluginDataManager.SendPluginEvent(Leader, new PluginDataEventArgs
{
Plugin = GetType().Namespace!,
Name = GetType().Name,
DataType = PluginDataType.EventWin,
Opponent = Follower
});
}
}

Expand Down
16 changes: 8 additions & 8 deletions TagModePlugin/EntryCarTagMode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ public class EntryCarTagMode
private readonly EntryCarManager _entryCarManager;
private readonly TagModeConfiguration _configuration;
private readonly TagModePlugin _plugin;
private readonly EntryCar _entryCar;
public readonly EntryCar EntryCar;
public bool IsTagged { get; private set; } = false;

public bool IsConnected => _entryCar.Client is { HasSentFirstUpdate: true };
public bool IsConnected => EntryCar.Client is { HasSentFirstUpdate: true };
public Color CurrentColor { get; private set; } = Color.Empty;

public EntryCarTagMode(EntryCar entryCar, EntryCarManager entryCarManager, TagModeConfiguration configuration, TagModePlugin plugin)
{
_entryCar = entryCar;
EntryCar = entryCar;
_entryCarManager = entryCarManager;
_configuration = configuration;
_plugin = plugin;
Expand Down Expand Up @@ -57,20 +57,20 @@ public void OnCollision(CollisionEventArgs args)
if (!targetCar.IsTagged) return;

SetTagged();
_plugin.CurrentSession.LastCaught = _entryCar;
_plugin.CurrentSession.LastCaught = EntryCar;
}

public void SetTagged(bool val = true)
{
if (_entryCar.Client == null) return;
if (EntryCar.Client == null) return;

IsTagged = val;

if (!IsTagged) return;

UpdateColor(_plugin.TaggedColor);
_entryCar.Client.SendChatMessage("You are now a tagger.");
_entryCar.Logger.Information("{Player} is now a tagger", _entryCar.Client.Name);
EntryCar.Client.SendChatMessage("You are now a tagger.");
EntryCar.Logger.Information("{Player} is now a tagger", EntryCar.Client.Name);
}

public void UpdateColor(Color color, bool disconnect = false)
Expand All @@ -79,7 +79,7 @@ public void UpdateColor(Color color, bool disconnect = false)
var packet = new TagModeColorPacket
{
Color = color,
SessionId = _entryCar.SessionId,
SessionId = EntryCar.SessionId,
Disconnect = disconnect
};
_entryCarManager.BroadcastPacket(packet);
Expand Down
39 changes: 34 additions & 5 deletions TagModePlugin/TagSession.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Drawing;
using AssettoServer.Server;
using Microsoft.Net.Http.Headers;
using AssettoServer.Server.Plugin;
using Serilog;

namespace TagModePlugin;
Expand All @@ -14,7 +14,8 @@ public class TagSession
private bool IsCancelled { get; set; }
public bool HasEnded { get; private set; }
private long StartTimeMilliseconds { get; set; }


private readonly PluginDataManager _pluginDataManager;
private readonly SessionManager _sessionManager;
private readonly EntryCarManager _entryCarManager;
private readonly TagModePlugin _plugin;
Expand All @@ -23,12 +24,14 @@ public class TagSession
public delegate TagSession Factory(EntryCar initialTagger);

public TagSession(EntryCar initialTagger,
PluginDataManager pluginDataManager,
SessionManager sessionManager,
EntryCarManager entryCarManager,
TagModePlugin plugin,
TagModeConfiguration configuration)
{
InitialTagger = LastCaught = initialTagger;
_pluginDataManager = pluginDataManager;
_sessionManager = sessionManager;
_entryCarManager = entryCarManager;
_plugin = plugin;
Expand Down Expand Up @@ -105,16 +108,42 @@ private async Task FinishSession()
switch (_configuration.EnableEndlessMode)
{
case false:
var winners = _plugin.Instances.Any(car => car.Value is { IsTagged: false, IsConnected: true }) ? "Runners" : "Taggers";
var anyUntaggedLeft = _plugin.Instances.Any(car => car.Value is
{
IsTagged: false,
IsConnected: true
});
var winners = _plugin.Instances.Where(x => x.Value is
{
IsConnected: true
} car && car.IsTagged == !anyUntaggedLeft).Select(x => x.Value).ToList();

var winnerName = winners.Count != 0 ? "Runners" : "Taggers";
_entryCarManager.BroadcastChat($"The {winnerName} just won this game of tag.");
Log.Information("The {Winners} just won this game of tag", winnerName);

_entryCarManager.BroadcastChat($"The {winners} just won this game of tag.");
Log.Information("The {Winners} just won this game of tag", winners);
foreach (var winnerCar in winners)
{
_pluginDataManager.SendPluginEvent(winnerCar.EntryCar, new PluginDataEventArgs
{
Plugin = GetType().Namespace!,
Name = GetType().Name,
DataType = PluginDataType.EventWin
});
}
break;
case true:
var winner = LastCaught.Client?.Name ?? $"Car #{LastCaught.SessionId}";

_entryCarManager.BroadcastChat($"'{winner}' just won this game of tag.");
Log.Information("{Winner} just won this game of tag", winner);

_pluginDataManager.SendPluginEvent(LastCaught, new PluginDataEventArgs
{
Plugin = GetType().Namespace!,
Name = GetType().Name,
DataType = PluginDataType.EventWin
});
break;
}
}
Expand Down