Skip to content

Commit

Permalink
Player promote commands
Browse files Browse the repository at this point in the history
Branch password compatibility
0.7.4 compatibility
  • Loading branch information
Equinox- committed Sep 9, 2023
1 parent 13ed02c commit 55e28f8
Show file tree
Hide file tree
Showing 22 changed files with 358 additions and 142 deletions.
2 changes: 2 additions & 0 deletions Meds.Shared/MessagePipeFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ void Register<T>(Message type) where T : struct, IFlatbufferObject
Register<DataStoreSync>(Message.DataStoreSync);
Register<RestoreSceneRequest>(Message.RestoreSceneRequest);
Register<RestoreSceneResponse>(Message.RestoreSceneResponse);
Register<PromotePlayerRequest>(Message.PromotePlayerRequest);
Register<PromotePlayerResponse>(Message.PromotePlayerResponse);
}

private sealed class UdpMessageQueue<T> : ISubscriber<T>, IPublisher<T> where T : struct, IFlatbufferObject
Expand Down
15 changes: 15 additions & 0 deletions Meds.Shared/Schema.fbs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,19 @@ table RestoreSceneResponse {
replaced_groups: uint32;
}

table PromotePlayerRequest {
steam_id: uint64;
promotion: PlayerPromotionLevel;
}

table PromotePlayerResponse {
steam_id: uint64;
name: string;
old_promotion: PlayerPromotionLevel;
requested_promotion: PlayerPromotionLevel;
successful: bool;
}

union Message {
HealthState,
ShutdownRequest,
Expand All @@ -153,6 +166,8 @@ union Message {
DataStoreSync,
RestoreSceneRequest,
RestoreSceneResponse,
PromotePlayerRequest,
PromotePlayerResponse,
}

table Packet {
Expand Down
5 changes: 4 additions & 1 deletion Meds.Watchdog/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,11 @@ public class SteamConfig : MemberwiseEquatable<SteamConfig>
{
[XmlAttribute]
public string Branch = "communityedition";

[XmlAttribute]
public string BranchPassword;
}

private static readonly MemberwiseEqualityComparer<Configuration> EqualityComparer = MemberwiseEqualityComparer<Configuration>.ByFields;

public bool Equals(Configuration other) => EqualityComparer.Equals(this, other);
Expand Down
116 changes: 116 additions & 0 deletions Meds.Watchdog/Discord/DiscordCmdPlayers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
using System;
using System.Text;
using System.Threading.Tasks;
using DSharpPlus;
using DSharpPlus.SlashCommands;
using Meds.Shared;
using Meds.Shared.Data;

namespace Meds.Watchdog.Discord
{
public class DiscordCmdPlayers : ApplicationCommandModule
{
private readonly ISubscriber<PlayersResponse> _playersSubscriber;
private readonly IPublisher<PlayersRequest> _playersRequest;
private readonly ISubscriber<PromotePlayerResponse> _promoteSubscriber;
private readonly IPublisher<PromotePlayerRequest> _promoteRequest;

public DiscordCmdPlayers(ISubscriber<PlayersResponse> playersSubscriber, IPublisher<PlayersRequest> playersRequest,
ISubscriber<PromotePlayerResponse> promoteSubscriber, IPublisher<PromotePlayerRequest> promoteRequest)
{
_playersSubscriber = playersSubscriber;
_playersRequest = playersRequest;
_promoteSubscriber = promoteSubscriber;
_promoteRequest = promoteRequest;
}

[SlashCommand("players", "Lists online players")]
[SlashCommandPermissions(Permissions.UseApplicationCommands)]
public async Task PlayersCommand(InteractionContext context)
{
await context.CreateResponseAsync(InteractionResponseType.DeferredChannelMessageWithSource);
try
{
var response = await _playersSubscriber.AwaitResponse(msg =>
{
var response = new StringBuilder();
response.Append($"{msg.PlayersLength} Online Players");
for (var i = 0; i < msg.PlayersLength; i++)
{
response.Append("\n");
// ReSharper disable once PossibleInvalidOperationException
var player = msg.Players(i).Value;
if (player.FactionTag != null)
response.Append("[").Append(player.FactionTag).Append("] ");
response.Append(player.Name);
switch (player.Promotion)
{
case PlayerPromotionLevel.Moderator:
response.Append(" (Moderator)");
break;
case PlayerPromotionLevel.Admin:
response.Append(" (Admin)");
break;
case PlayerPromotionLevel.None:
default:
break;
}
}
return response.ToString();
}, sendRequest: () =>
{
using var token = _playersRequest.Publish();
PlayersRequest.StartPlayersRequest(token.Builder);
token.Send(PlayersRequest.EndPlayersRequest(token.Builder));
});
await context.EditResponseAsync(response);
}
catch (TimeoutException)
{
await context.EditResponseAsync("Server did not respond to players request. Is it offline?");
}
}

public enum DiscordPlayerPromotionLevel
{
None,
Moderator,
Administrator
}

[SlashCommand("player-promote", "Promotes or demotes a player")]
[SlashCommandPermissions(Permissions.Administrator)]
public async Task PromotePlayer(InteractionContext context,
[Option("player", "Player steam ID")] [Autocomplete(typeof(DiscordPlayersAutocomplete))]
string steamIdString,
[Option("promotion", "What level to promote / demote the player to")]
DiscordPlayerPromotionLevel promotionLevel)
{
var steamId = ulong.Parse(steamIdString);
await context.CreateResponseAsync(InteractionResponseType.DeferredChannelMessageWithSource);
try
{
var response = await _promoteSubscriber.AwaitResponse(
msg =>
$"{(msg.Successful ? "Promoted" : "Failed to promote")} {msg.Name} ({msg.SteamId}) from {msg.OldPromotion} to {msg.RequestedPromotion}",
sendRequest: () =>
{
using var token = _promoteRequest.Publish();
token.Send(PromotePlayerRequest.CreatePromotePlayerRequest(token.Builder, steamId, promotionLevel switch
{
DiscordPlayerPromotionLevel.None => PlayerPromotionLevel.None,
DiscordPlayerPromotionLevel.Moderator => PlayerPromotionLevel.Moderator,
DiscordPlayerPromotionLevel.Administrator => PlayerPromotionLevel.Admin,
_ => throw new ArgumentOutOfRangeException(nameof(promotionLevel), promotionLevel, null)
}));
});
await context.EditResponseAsync(response);
}
catch (TimeoutException)
{
await context.EditResponseAsync("Server did not respond to promotion request. Is it offline?");
}
}
}
}
5 changes: 0 additions & 5 deletions Meds.Watchdog/Discord/DiscordCmdSave.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using DSharpPlus;
Expand Down
58 changes: 1 addition & 57 deletions Meds.Watchdog/Discord/DiscordCmdStatus.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
using System;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using DSharpPlus;
using DSharpPlus.Entities;
using DSharpPlus.SlashCommands;
using Meds.Shared;
using Meds.Shared.Data;

namespace Meds.Watchdog.Discord
{
Expand All @@ -15,15 +13,10 @@ public class DiscordCmdStatus : ApplicationCommandModule
{
private readonly LifecycleController _lifetimeController;
private readonly HealthTracker _healthTracker;
private readonly ISubscriber<PlayersResponse> _playersSubscriber;
private readonly IPublisher<PlayersRequest> _playersRequest;

public DiscordCmdStatus(LifecycleController lifetimeController, ISubscriber<PlayersResponse> playersSubscriber,
IPublisher<PlayersRequest> playersRequest, HealthTracker healthTracker)
public DiscordCmdStatus(LifecycleController lifetimeController, HealthTracker healthTracker)
{
_lifetimeController = lifetimeController;
_playersSubscriber = playersSubscriber;
_playersRequest = playersRequest;
_healthTracker = healthTracker;
}

Expand Down Expand Up @@ -123,54 +116,5 @@ string FormatVersion(string gitHash, DateTime compiledAt)

await context.CreateResponseAsync(builder.Build());
}


[SlashCommand("players", "Lists online players")]
[SlashCommandPermissions(Permissions.UseApplicationCommands)]
public async Task PlayersCommand(InteractionContext context)
{
await context.CreateResponseAsync(InteractionResponseType.DeferredChannelMessageWithSource);
try
{
var response = await _playersSubscriber.AwaitResponse(msg =>
{
var response = new StringBuilder();
response.Append($"{msg.PlayersLength} Online Players");
for (var i = 0; i < msg.PlayersLength; i++)
{
response.Append("\n");
// ReSharper disable once PossibleInvalidOperationException
var player = msg.Players(i).Value;
if (player.FactionTag != null)
response.Append("[").Append(player.FactionTag).Append("] ");
response.Append(player.Name);
switch (player.Promotion)
{
case PlayerPromotionLevel.Moderator:
response.Append(" (Moderator)");
break;
case PlayerPromotionLevel.Admin:
response.Append(" (Admin)");
break;
case PlayerPromotionLevel.None:
default:
break;
}
}
return response.ToString();
}, sendRequest: () =>
{
using var token = _playersRequest.Publish();
PlayersRequest.StartPlayersRequest(token.Builder);
token.Send(PlayersRequest.EndPlayersRequest(token.Builder));
});
await context.EditResponseAsync(response);
}
catch (TimeoutException)
{
await context.EditResponseAsync("Server did not respond to players request. Is it offline?");
}
}
}
}
1 change: 1 addition & 0 deletions Meds.Watchdog/Discord/DiscordInit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public State(DiscordService owner, string token)
commands.RegisterCommands<DiscordCmdSave>();
commands.RegisterCommands<DiscordCmdSaveSearch>();
commands.RegisterCommands<DiscordCmdStatus>();
commands.RegisterCommands<DiscordCmdPlayers>();
}
}

Expand Down
39 changes: 39 additions & 0 deletions Meds.Watchdog/Discord/DiscordPlayersAutocomplete.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using DSharpPlus.Entities;
using DSharpPlus.SlashCommands;
using Meds.Shared;
using Meds.Shared.Data;
using Microsoft.Extensions.DependencyInjection;

namespace Meds.Watchdog.Discord
{
public class DiscordPlayersAutocomplete : IAutocompleteProvider
{
public Task<IEnumerable<DiscordAutoCompleteChoice>> Provider(AutocompleteContext ctx)
{
var publisher = ctx.Services.GetRequiredService<IPublisher<PlayersRequest>>();
var subscriber = ctx.Services.GetRequiredService<ISubscriber<PlayersResponse>>();
return subscriber.AwaitResponse(response =>
{
var players = new List<DiscordAutoCompleteChoice>();
for (var i = 0; i < response.PlayersLength; i++)
{
var player = response.Players(i);
if (!player.HasValue) continue;
var id = player.Value.SteamId;
var name = player.Value.Name;
var level = player.Value.Promotion;
players.Add(new DiscordAutoCompleteChoice($"{name} ({id}) {level}", id.ToString()));
}
return (IEnumerable<DiscordAutoCompleteChoice>) players;
}, TimeSpan.FromSeconds(5), () =>
{
var token = publisher.Publish();
PlayersRequest.StartPlayersRequest(token.Builder);
token.Send(PlayersRequest.EndPlayersRequest(token.Builder));
});
}
}
}
2 changes: 2 additions & 0 deletions Meds.Watchdog/Meds.Watchdog.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,15 @@
<Compile Include="DataStore.cs" />
<Compile Include="DiagnosticController.cs" />
<Compile Include="Discord\DiscordCmdDiagnostic.cs" />
<Compile Include="Discord\DiscordCmdPlayers.cs" />
<Compile Include="Discord\DiscordCmdSave.cs" />
<Compile Include="Discord\DiscordCmdSaveSearch.cs" />
<Compile Include="Discord\DiscordCmdStatus.cs" />
<Compile Include="Discord\DiscordConfig.cs" />
<Compile Include="Discord\DiscordInit.cs" />
<Compile Include="Discord\DiscordCmdLifecycle.cs" />
<Compile Include="Discord\DiscordMessageBridge.cs" />
<Compile Include="Discord\DiscordPlayersAutocomplete.cs" />
<Compile Include="Discord\DiscordSaveFileUtils.cs" />
<Compile Include="Discord\DiscordStatusMonitor.cs" />
<Compile Include="Discord\DiscordUtils.cs" />
Expand Down
21 changes: 21 additions & 0 deletions Meds.Watchdog/Steam/PICSProductInfoExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,27 @@ public static ulong GetManifestId(this PICSProductInfo info, uint depotId, strin
return info.GetSection(EAppInfoSection.Depots)[depotId.ToString()]["manifests"][branch]["gid"].AsUnsignedLong();
}

public static byte[] GetEncryptedManifestId(this PICSProductInfo info, uint depotId, string branch)
{
var hex = info.GetSection(EAppInfoSection.Depots)[depotId.ToString()]["encryptedmanifests"][branch]["gid"].AsString();
if (string.IsNullOrEmpty(hex))
return null;
var bytes = new byte[hex.Length >> 1];
for (int i = 0, j = 0; i < bytes.Length; i++, j += 2)
bytes[i] = (byte)((Hex(hex[j]) << 4) | Hex(hex[j + 1]));
return bytes;

int Hex(char chr)
{
var val = (int)chr;
if (val < 'A')
return val - '0';
if (val < 'a')
return 10 + val - 'A';
return 10 + val - 'a';
}
}

public static uint GetWorkshopDepot(this PICSProductInfo info)
{
return info.GetSection(EAppInfoSection.Depots)["workshopdepot"].AsUnsignedInteger();
Expand Down
Loading

0 comments on commit 55e28f8

Please sign in to comment.