From 553f1054d2a955e23cda33375613ec8f2b56c3fe Mon Sep 17 00:00:00 2001 From: Govorunb Date: Thu, 11 Jul 2024 13:43:18 +1000 Subject: [PATCH] add "refund" deprecate some redeems add refund cases where it makes sense --- SCHIZO/Commands/Output/CommonResults.cs | 46 +++++++++++++++++-- .../CustomJukeboxTrackPatches.BelowZero.cs | 3 +- SCHIZO/SwarmControl/MessageProcessor.cs | 21 +++++---- .../Models/Game/Messages/HelloBackMessage.cs | 5 +- .../Models/Game/Messages/RedeemMessage.cs | 4 +- .../Models/Game/Messages/ResultMessage.cs | 24 ++++++++-- .../Models/Game/Messages/TwitchUser.cs | 16 +++++-- .../DetachBackSeatruckModule.BelowZero.cs | 6 +-- .../SwarmControl/Redeems/Annoying/FlipPDA.cs | 2 +- .../Redeems/Annoying/FloodBaseRedeem.cs | 2 +- .../Annoying/ScanTotallyRandomFragment.cs | 4 +- .../Redeems/Annoying/ShowCaptcha.cs | 2 +- .../Redeems/Annoying/ShowNotif.cs | 3 +- .../Annoying/SpinHimAround.BelowZero.cs | 2 +- .../SwarmControl/Redeems/Audio/PlayNoise.cs | 3 +- .../Redeems/Audio/PlayTrollNoise.cs | 3 +- .../SwarmControl/Redeems/Helpful/SaveGame.cs | 4 +- .../SeaMonkeyDeliverySystem.BelowZero.cs | 2 +- SCHIZO/SwarmControl/Redeems/Misc/BigErm.cs | 5 +- SCHIZO/SwarmControl/Redeems/Misc/Floaties.cs | 2 + .../SwarmControl/Redeems/Misc/MidasTouch.cs | 5 +- 21 files changed, 117 insertions(+), 47 deletions(-) diff --git a/SCHIZO/Commands/Output/CommonResults.cs b/SCHIZO/Commands/Output/CommonResults.cs index 2a7ad81b..c5b06b2c 100644 --- a/SCHIZO/Commands/Output/CommonResults.cs +++ b/SCHIZO/Commands/Output/CommonResults.cs @@ -5,15 +5,55 @@ namespace SCHIZO.Commands.Output; public static class CommonResults { // sizeof says 1 byte for the empty types (i'm guessing type marker or pointer padding) + // aaaa i'm having withdrawals i miss rust enums + + /// Indicates that the command was executed successfully. public readonly record struct OKResult; + + /// + /// Mostly for internal use; shows usage information to the user.
+ /// This must never be returned from a redeem. + ///
public readonly record struct ShowUsageResult; - public readonly record struct ErrorResult(string message); - // aaaa i'm having withdrawals i miss rust enums + + /// + /// An internal error occurred while trying to execute the command. + /// public readonly record struct ExceptionResult(Exception Exception); + + /// + /// Something went wrong and the command could not be executed cleanly. + /// + /// Message to return to the user. Will be logged on the backend, as well as posting a notification on Discord. + public readonly record struct ErrorResult(string message); + // no MessageResult(string) because you can just return a string (may still add one in the future for log levels and such) + /// + /// Acts like in that the user is shown an error and the redeem gets refunded;
+ /// The difference is that this does not trigger Discord logs. + ///
+ /// Message to display to the user. This will be logged to the database but will not notify on Discord. + public readonly record struct DenyResult(string reason); + public static OKResult OK() => new(); + /// + /// The parameters supplied to the command were incorrect.
+ /// Do not return this from a redeem. + ///
public static ShowUsageResult ShowUsage() => new(); - public static ErrorResult Error(string message) => new(message); + /// + /// Commands automatically catch exceptions but you can still use this. + /// public static ExceptionResult Exception(Exception e) => new(e); + /// + /// The command failed to execute due to an error. + /// + /// The message to return to the user. + public static ErrorResult Error(string message) => new(message); + /// + /// The command could not be executed due to a precondition (such as a cooldown). + /// + /// Message to return to the user. + public static DenyResult Deny(string reason) => new(reason); } diff --git a/SCHIZO/Jukebox/CustomJukeboxTrackPatches.BelowZero.cs b/SCHIZO/Jukebox/CustomJukeboxTrackPatches.BelowZero.cs index 0e3b3122..de48e9ae 100644 --- a/SCHIZO/Jukebox/CustomJukeboxTrackPatches.BelowZero.cs +++ b/SCHIZO/Jukebox/CustomJukeboxTrackPatches.BelowZero.cs @@ -1,6 +1,5 @@ using System.Collections; using System.Collections.Generic; -using System.IO; using System.Reflection; using System.Reflection.Emit; using FMOD; @@ -268,7 +267,7 @@ public static void OnSwitchingTracks(JukeboxInstance __instance) __instance.SetPositionKnobVisible(!__instance.IsPlayingStream(out _)); } - //[HarmonyPatch(typeof(File), nameof(File.Exists))] + //[HarmonyPatch(typeof(System.IO.File), nameof(System.IO.File.Exists))] //[HarmonyPostfix] public static void DebugStuff(string path) { diff --git a/SCHIZO/SwarmControl/MessageProcessor.cs b/SCHIZO/SwarmControl/MessageProcessor.cs index 3d11fdc4..46abab25 100644 --- a/SCHIZO/SwarmControl/MessageProcessor.cs +++ b/SCHIZO/SwarmControl/MessageProcessor.cs @@ -76,7 +76,7 @@ private void OnRedeem(RedeemMessage msg) if (!CommandRegistry.TryGetInnermostCommand(msg.Command.SplitOnce(' ').Before, out Command command)) { LOGGER.LogDebug($"{msg.GetUsername()} tried to redeem unknown command \"{msg.Command}\""); - SendResult(guid, false, "Command not found"); + SendResult(guid, ResultMessage.ResultKind.Error, "Command not found"); return; } // prevents server replaying redeems in case we receive one but the game doesn't acknowledge it or something (so the server thinks it didn't send and replays it later) @@ -117,25 +117,28 @@ private void OnRedeem(RedeemMessage msg) switch (ctx.Result) { case CommonResults.ErrorResult { message: string error }: - SendResult(msg.Guid, false, error); + SendResult(msg.Guid, ResultMessage.ResultKind.Error, error); + break; + case CommonResults.DenyResult { reason: string reason }: + SendResult(msg.Guid, ResultMessage.ResultKind.Deny, reason); break; case null or CommonResults.OKResult: - SendResult(msg.Guid, true); + SendResult(msg.Guid, ResultMessage.ResultKind.Success); break; case CommonResults.ExceptionResult { Exception: Exception e }: - SendResult(msg.Guid, false, e.ToString()); + SendResult(msg.Guid, ResultMessage.ResultKind.Error, e.ToString()); break; case CommonResults.ShowUsageResult: - SendResult(msg.Guid, false, $"Incorrect command usage - {ShowUsage.GetUsageString(command)}"); + SendResult(msg.Guid, ResultMessage.ResultKind.Error, $"Incorrect command usage - {ShowUsage.GetUsageString(command)}"); break; default: - SendResult(msg.Guid, true, ctx.Result.ToString()); + SendResult(msg.Guid, ResultMessage.ResultKind.Success, ctx.Result.ToString()); break; } } catch (Exception e) { - SendResult(msg.Guid, false, e.ToString()); + SendResult(msg.Guid, ResultMessage.ResultKind.Error, e.ToString()); } }); } @@ -148,12 +151,12 @@ private void SendHello() }); } - private void SendResult(Guid guid, bool success, string? message = null) + private void SendResult(Guid guid, ResultMessage.ResultKind kind, string? message = null) { ResultMessage msg = new() { Guid = guid, - Success = success, + Status = kind, Message = message }; _results[msg.Guid] = msg; diff --git a/SCHIZO/SwarmControl/Models/Game/Messages/HelloBackMessage.cs b/SCHIZO/SwarmControl/Models/Game/Messages/HelloBackMessage.cs index 945b1210..6424cbc4 100644 --- a/SCHIZO/SwarmControl/Models/Game/Messages/HelloBackMessage.cs +++ b/SCHIZO/SwarmControl/Models/Game/Messages/HelloBackMessage.cs @@ -1,9 +1,6 @@ -using System.Diagnostics.CodeAnalysis; - namespace SwarmControl.Models.Game.Messages; -[method: SetsRequiredMembers] -public sealed record HelloBackMessage() : BackendMessage() +public sealed record HelloBackMessage : BackendMessage { public override MessageType MessageType => MessageType.HelloBack; public bool Allowed { get; init; } diff --git a/SCHIZO/SwarmControl/Models/Game/Messages/RedeemMessage.cs b/SCHIZO/SwarmControl/Models/Game/Messages/RedeemMessage.cs index 641ef2aa..5ef7198f 100644 --- a/SCHIZO/SwarmControl/Models/Game/Messages/RedeemMessage.cs +++ b/SCHIZO/SwarmControl/Models/Game/Messages/RedeemMessage.cs @@ -1,11 +1,9 @@ using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; namespace SwarmControl.Models.Game.Messages; #nullable enable -[method: SetsRequiredMembers] -public sealed record RedeemMessage() : BackendMessage() +public sealed record RedeemMessage : BackendMessage { public override MessageType MessageType => MessageType.Redeem; diff --git a/SCHIZO/SwarmControl/Models/Game/Messages/ResultMessage.cs b/SCHIZO/SwarmControl/Models/Game/Messages/ResultMessage.cs index 9804f4c5..e93b758f 100644 --- a/SCHIZO/SwarmControl/Models/Game/Messages/ResultMessage.cs +++ b/SCHIZO/SwarmControl/Models/Game/Messages/ResultMessage.cs @@ -1,12 +1,28 @@ -using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Serialization; namespace SwarmControl.Models.Game.Messages; #nullable enable -[method: SetsRequiredMembers] -public sealed record ResultMessage() : GameMessage() +public sealed record ResultMessage : GameMessage { + [JsonConverter(typeof(StringEnumConverter))] + public enum ResultKind + { + /// The redeem succeeded. + [EnumMember(Value = "success")] + Success, + /// The redeem failed to execute. The user should be notified (and refunded), and the backend should send a Discord notification. + [EnumMember(Value = "error")] + Error, + /// The redeem did not execute due to a precondition. The user is still refunded, but there is no need to ping in Discord. + [EnumMember(Value = "deny")] + Deny, + } public override MessageType MessageType => MessageType.Result; - public bool Success { get; set; } + [JsonProperty(NamingStrategyType = typeof(CamelCaseNamingStrategy), Required = Required.Always)] + public ResultKind Status { get; set; } public string? Message { get; set; } } diff --git a/SCHIZO/SwarmControl/Models/Game/Messages/TwitchUser.cs b/SCHIZO/SwarmControl/Models/Game/Messages/TwitchUser.cs index 0102f92c..b3cac2a1 100644 --- a/SCHIZO/SwarmControl/Models/Game/Messages/TwitchUser.cs +++ b/SCHIZO/SwarmControl/Models/Game/Messages/TwitchUser.cs @@ -4,7 +4,15 @@ namespace SwarmControl.Models.Game.Messages; /// /// Twitch user info. /// -/// Channel ID. -/// Username/channel name. -/// What's displayed in chat. -public record TwitchUser(string Id, string Login, string DisplayName); +/// Channel ID. +/// Username/channel name. +/// The name you see in chat. +public class TwitchUser(string id, string? login = null, string? displayName = null) +{ + /// Twitch's internal channel ID that corresponds to this user. + public string Id { get; } = id; + /// Username/channel name. + public string Login { get; } = login ?? id; + /// The name displayed in chat. + public string DisplayName { get; } = displayName ?? login ?? id; +} diff --git a/SCHIZO/SwarmControl/Redeems/Annoying/DetachBackSeatruckModule.BelowZero.cs b/SCHIZO/SwarmControl/Redeems/Annoying/DetachBackSeatruckModule.BelowZero.cs index e62b1847..99a4dc21 100644 --- a/SCHIZO/SwarmControl/Redeems/Annoying/DetachBackSeatruckModule.BelowZero.cs +++ b/SCHIZO/SwarmControl/Redeems/Annoying/DetachBackSeatruckModule.BelowZero.cs @@ -18,10 +18,10 @@ internal class DetachBackSeatruckModule : Command, IParameters protected override object? ExecuteCore(CommandExecutionContext ctx) { - if (!Player.main) return CommonResults.Error("Requires a loaded game."); + if (!Player.main) return CommonResults.Deny("Requires a loaded game."); SeaTruckUpgrades cabin = GameObject.FindObjectOfType(); - if (!cabin) return CommonResults.Error("Sea Truck not found."); + if (!cabin) return CommonResults.Deny("Sea Truck not found."); SeaTruckSegment cabinSegment = cabin.GetComponent(); SeaTruckSegment rearSegment = cabinSegment; @@ -29,7 +29,7 @@ internal class DetachBackSeatruckModule : Command, IParameters rearSegment = rearSegment.rearConnection.connection.truckSegment; if (rearSegment == cabinSegment) - return CommonResults.Error("Sea Truck not connected to any modules."); + return CommonResults.Deny("Sea Truck is not connected to any modules."); rearSegment.Detach(); diff --git a/SCHIZO/SwarmControl/Redeems/Annoying/FlipPDA.cs b/SCHIZO/SwarmControl/Redeems/Annoying/FlipPDA.cs index aaea9ba1..6f57f941 100644 --- a/SCHIZO/SwarmControl/Redeems/Annoying/FlipPDA.cs +++ b/SCHIZO/SwarmControl/Redeems/Annoying/FlipPDA.cs @@ -28,7 +28,7 @@ public enum Direction protected override object ExecuteCore(CommandExecutionContext ctx) { - if (!Player.main) return CommonResults.Error("Requires a loaded game."); + if (!Player.main) return CommonResults.Deny("Requires a loaded game."); PDA pda = Player.main.GetPDA(); if (!pda) return CommonResults.Error("Could not get PDA."); // should never ever ever happen diff --git a/SCHIZO/SwarmControl/Redeems/Annoying/FloodBaseRedeem.cs b/SCHIZO/SwarmControl/Redeems/Annoying/FloodBaseRedeem.cs index 409d4f51..d9149ac7 100644 --- a/SCHIZO/SwarmControl/Redeems/Annoying/FloodBaseRedeem.cs +++ b/SCHIZO/SwarmControl/Redeems/Annoying/FloodBaseRedeem.cs @@ -16,7 +16,7 @@ internal class FloodBaseRedeem() : ProxyCommand("damagebase") public override IReadOnlyList Parameters => []; protected override object? ExecuteCore(CommandExecutionContext ctx) { - if (!Player.main) return CommonResults.Error("Requires a loaded game"); + if (!Player.main) return CommonResults.Deny("Requires a loaded game"); return base.ExecuteCore(ctx); } diff --git a/SCHIZO/SwarmControl/Redeems/Annoying/ScanTotallyRandomFragment.cs b/SCHIZO/SwarmControl/Redeems/Annoying/ScanTotallyRandomFragment.cs index cb828671..6790fdbb 100644 --- a/SCHIZO/SwarmControl/Redeems/Annoying/ScanTotallyRandomFragment.cs +++ b/SCHIZO/SwarmControl/Redeems/Annoying/ScanTotallyRandomFragment.cs @@ -8,10 +8,12 @@ namespace SCHIZO.SwarmControl.Redeems.Annoying; +[System.Obsolete("This was only ever going to be funny for one stream", true)] [Redeem( Name = "redeem_scanrandomfragment", DisplayName = "Scan Random Fragment", - Description = "Auto-scans a random fragment, chosen by fair dice roll." + Description = "Auto-scans a random fragment, chosen by fair dice roll.", + Export = false )] internal class ScanTotallyRandomFragment : Command, IParameters { diff --git a/SCHIZO/SwarmControl/Redeems/Annoying/ShowCaptcha.cs b/SCHIZO/SwarmControl/Redeems/Annoying/ShowCaptcha.cs index 69d2e90c..522fc579 100644 --- a/SCHIZO/SwarmControl/Redeems/Annoying/ShowCaptcha.cs +++ b/SCHIZO/SwarmControl/Redeems/Annoying/ShowCaptcha.cs @@ -20,7 +20,7 @@ internal class ShowCaptcha : Command, IParameters protected override object? ExecuteCore(CommandExecutionContext ctx) { - if (!Player.main) return CommonResults.Error("Requires a loaded game."); + if (!Player.main) return CommonResults.Deny("Requires a loaded game."); if (!Captcha.Instance) return CommonResults.Error("Captcha not found."); CoroutineHost.StartCoroutine(Coro()); diff --git a/SCHIZO/SwarmControl/Redeems/Annoying/ShowNotif.cs b/SCHIZO/SwarmControl/Redeems/Annoying/ShowNotif.cs index fca9ac06..9a5b3808 100644 --- a/SCHIZO/SwarmControl/Redeems/Annoying/ShowNotif.cs +++ b/SCHIZO/SwarmControl/Redeems/Annoying/ShowNotif.cs @@ -9,7 +9,8 @@ namespace SCHIZO.SwarmControl.Redeems.Annoying; [Redeem( Name = "redeem_notif", DisplayName = "Ping Alex", - Description = "This will log an error on the backend, pinging Alex for no reason" + Description = "This will log an error on the backend, pinging Alex for no reason", + Export = false )] internal class ShowNotif : Command, IParameters { diff --git a/SCHIZO/SwarmControl/Redeems/Annoying/SpinHimAround.BelowZero.cs b/SCHIZO/SwarmControl/Redeems/Annoying/SpinHimAround.BelowZero.cs index da012265..b3e9b79e 100644 --- a/SCHIZO/SwarmControl/Redeems/Annoying/SpinHimAround.BelowZero.cs +++ b/SCHIZO/SwarmControl/Redeems/Annoying/SpinHimAround.BelowZero.cs @@ -17,7 +17,7 @@ internal class SpinHimAround : Command, IParameters protected override object ExecuteCore(CommandExecutionContext ctx) { - if (!Player.main) return CommonResults.Error("Requires a loaded game."); + if (!Player.main) return CommonResults.Deny("Requires a loaded game."); Player.main.lilyPaddlerHypnosis.StartHypnosis(DayNightCycle.main.timePassed); CoroutineHost.StartCoroutine(Coro()); diff --git a/SCHIZO/SwarmControl/Redeems/Audio/PlayNoise.cs b/SCHIZO/SwarmControl/Redeems/Audio/PlayNoise.cs index 39f9ae82..008d3a08 100644 --- a/SCHIZO/SwarmControl/Redeems/Audio/PlayNoise.cs +++ b/SCHIZO/SwarmControl/Redeems/Audio/PlayNoise.cs @@ -10,7 +10,8 @@ namespace SCHIZO.SwarmControl.Redeems.Audio; [Redeem( Name = "redeem_noise", DisplayName = "Play Sound", - Announce = false + Announce = false, + Export = false )] internal class PlayNoise : Command, IParameters { diff --git a/SCHIZO/SwarmControl/Redeems/Audio/PlayTrollNoise.cs b/SCHIZO/SwarmControl/Redeems/Audio/PlayTrollNoise.cs index 385227b3..07b928b9 100644 --- a/SCHIZO/SwarmControl/Redeems/Audio/PlayTrollNoise.cs +++ b/SCHIZO/SwarmControl/Redeems/Audio/PlayTrollNoise.cs @@ -12,7 +12,8 @@ namespace SCHIZO.SwarmControl.Redeems.Audio; Name = "redeem_trollnoise", DisplayName = "Play Troll Sound", Description = "IMPORTANT: Leviathan sound will not play if not underwater", - Announce = false + Announce = false, + Export = false )] internal class PlayTrollNoise : Command, IParameters { diff --git a/SCHIZO/SwarmControl/Redeems/Helpful/SaveGame.cs b/SCHIZO/SwarmControl/Redeems/Helpful/SaveGame.cs index 01f7af80..6014b425 100644 --- a/SCHIZO/SwarmControl/Redeems/Helpful/SaveGame.cs +++ b/SCHIZO/SwarmControl/Redeems/Helpful/SaveGame.cs @@ -33,9 +33,9 @@ protected override object ExecuteCore(CommandExecutionContext ctx) _lastSave = PDA.time; return CommonResults.OK(); } - else // yoink money from spammers + else { - return "Last save was less than a minute ago. Rest assured the game is saved."; + return CommonResults.Deny("Last save was less than a minute ago. You will be credited back for this redeem."); } } } diff --git a/SCHIZO/SwarmControl/Redeems/Helpful/SeaMonkeyDeliverySystem.BelowZero.cs b/SCHIZO/SwarmControl/Redeems/Helpful/SeaMonkeyDeliverySystem.BelowZero.cs index bcc996d7..262da153 100644 --- a/SCHIZO/SwarmControl/Redeems/Helpful/SeaMonkeyDeliverySystem.BelowZero.cs +++ b/SCHIZO/SwarmControl/Redeems/Helpful/SeaMonkeyDeliverySystem.BelowZero.cs @@ -27,7 +27,7 @@ internal class SeaMonkeyDeliverySystem : Command, IParameters protected override object ExecuteCore(CommandExecutionContext ctx) { - if (!Player.main) return CommonResults.Error("Requires a loaded game"); + if (!Player.main) return CommonResults.Deny("Requires a loaded game"); TechType item; try diff --git a/SCHIZO/SwarmControl/Redeems/Misc/BigErm.cs b/SCHIZO/SwarmControl/Redeems/Misc/BigErm.cs index b99adcf8..a7606422 100644 --- a/SCHIZO/SwarmControl/Redeems/Misc/BigErm.cs +++ b/SCHIZO/SwarmControl/Redeems/Misc/BigErm.cs @@ -16,9 +16,10 @@ namespace SCHIZO.SwarmControl.Redeems.Misc; #nullable enable -[Redeem(Name = "redeem_bigerm", +[Redeem( + Name = "redeem_bigerm", DisplayName = "Big Erm", - Description = "The Erm Moon sends its regards" + Description = "Convert a nearby ermfish to be Big. The Erm Moon sends its regards" )] internal class BigErm : Command, IParameters { diff --git a/SCHIZO/SwarmControl/Redeems/Misc/Floaties.cs b/SCHIZO/SwarmControl/Redeems/Misc/Floaties.cs index 0a7da971..6ba0bd13 100644 --- a/SCHIZO/SwarmControl/Redeems/Misc/Floaties.cs +++ b/SCHIZO/SwarmControl/Redeems/Misc/Floaties.cs @@ -26,6 +26,8 @@ public Floaties() protected override object ExecuteCore(CommandExecutionContext ctx) { + if (!Player.main.IsUnderwaterForSwimming()) + return CommonResults.Deny("Player must be swimming underwater"); _timer.AddTime(Duration); _timer.Start(); return CommonResults.OK(); diff --git a/SCHIZO/SwarmControl/Redeems/Misc/MidasTouch.cs b/SCHIZO/SwarmControl/Redeems/Misc/MidasTouch.cs index aa298a79..5c1c7ffc 100644 --- a/SCHIZO/SwarmControl/Redeems/Misc/MidasTouch.cs +++ b/SCHIZO/SwarmControl/Redeems/Misc/MidasTouch.cs @@ -10,7 +10,8 @@ namespace SCHIZO.SwarmControl.Redeems.Misc; [Redeem( Name = "redeem_midas", DisplayName = "Midas' Touch", - Description = "And all that glitters is gold" + Description = "And all that glitters is gold", + Export = false )] public sealed class MidasTouch : Command, IParameters { @@ -67,7 +68,7 @@ protected override object ExecuteCore(CommandExecutionContext ctx) .ToArray(); if (items.Length == 0) { - return CommonResults.Error("No items to turn"); + return CommonResults.Deny("No items to turn"); } foreach (InventoryItem item in items) {