diff --git a/Server/Program.cs b/Server/Program.cs index 71c0f3c..7e46b1e 100644 --- a/Server/Program.cs +++ b/Server/Program.cs @@ -349,20 +349,17 @@ CommandHandler.RegisterCommand("ban", args => { CommandHandler.RegisterCommand("send", args => { const string optionUsage = "Usage: send "; - if (args.Length < 4) + if (args.Length < 4) { return optionUsage; + } + + string? stage = Stages.Input2Stage(args[0]); + if (stage == null) { + return "Invalid Stage Name! ```" + Stages.KingdomAliasMapping() + "```"; + } - string stage = args[0]; string id = args[1]; - if (Constants.MapNames.TryGetValue(stage.ToLower(), out string? mapName)) { - stage = mapName; - } - - if (!stage.Contains("Stage") && !stage.Contains("Zone")) { - return "Invalid Stage Name! ```cap -> Cap Kingdom\ncascade -> Cascade Kingdom\nsand -> Sand Kingdom\nlake -> Lake Kingdom\nwooded -> Wooded Kingdom\ncloud -> Cloud Kingdom\nlost -> Lost Kingdom\nmetro -> Metro Kingdom\nsea -> Sea Kingdom\nsnow -> Snow Kingdom\nlunch -> Luncheon Kingdom\nruined -> Ruined Kingdom\nbowser -> Bowser's Kingdom\nmoon -> Moon Kingdom\nmush -> Mushroom Kingdom\ndark -> Dark Side\ndarker -> Darker Side```"; - } - if (!sbyte.TryParse(args[2], out sbyte scenario) || scenario < -1) return $"Invalid scenario number {args[2]} (range: [-1 to 127])"; Client[] players = args[3] == "*" @@ -384,17 +381,13 @@ CommandHandler.RegisterCommand("send", args => { CommandHandler.RegisterCommand("sendall", args => { const string optionUsage = "Usage: sendall "; - if (args.Length < 1) + if (args.Length < 1) { return optionUsage; - - string stage = args[0]; - - if (Constants.MapNames.TryGetValue(stage.ToLower(), out string? mapName)) { - stage = mapName; } - if (!stage.Contains("Stage") && !stage.Contains("Zone")) { - return "Invalid Stage Name! ```cap -> Cap Kingdom\ncascade -> Cascade Kingdom\nsand -> Sand Kingdom\nlake -> Lake Kingdom\nwooded -> Wooded Kingdom\ncloud -> Cloud Kingdom\nlost -> Lost Kingdom\nmetro -> Metro Kingdom\nsea -> Sea Kingdom\nsnow -> Snow Kingdom\nlunch -> Luncheon Kingdom\nruined -> Ruined Kingdom\nbowser -> Bowser's Kingdom\nmoon -> Moon Kingdom\nmush -> Mushroom Kingdom\ndark -> Dark Side\ndarker -> Darker Side```"; + string? stage = Stages.Input2Stage(args[0]); + if (stage == null) { + return "Invalid Stage Name! ```" + Stages.KingdomAliasMapping() + "```"; } Client[] players = server.Clients.Where(c => c.Connected).ToArray(); diff --git a/Shared/Constants.cs b/Shared/Constants.cs index 5df41d8..15a4c06 100644 --- a/Shared/Constants.cs +++ b/Shared/Constants.cs @@ -21,24 +21,4 @@ public static class Constants { .ToDictionary(type => type.GetCustomAttribute()!.Type, type => type); public static int HeaderSize { get; } = PacketHeader.StaticSize; - - public static readonly Dictionary MapNames = new Dictionary() { - {"cap", "CapWorldHomeStage"}, - {"cascade", "WaterfallWorldHomeStage"}, - {"sand", "SandWorldHomeStage"}, - {"lake", "LakeWorldHomeStage"}, - {"wooded", "ForestWorldHomeStage"}, - {"cloud", "CloudWorldHomeStage"}, - {"lost", "ClashWorldHomeStage"}, - {"metro", "CityWorldHomeStage"}, - {"sea", "SeaWorldHomeStage"}, - {"snow", "SnowWorldHomeStage"}, - {"lunch", "LavaWorldHomeStage"}, - {"ruined", "BossRaidWorldHomeStage"}, - {"bowser", "SkyWorldHomeStage"}, - {"moon", "MoonWorldHomeStage"}, - {"mush", "PeachWorldHomeStage"}, - {"dark", "Special1WorldHomeStage"}, - {"darker", "Special2WorldHomeStage"} - }; -} \ No newline at end of file +} diff --git a/Shared/Stages.cs b/Shared/Stages.cs new file mode 100644 index 0000000..bbb8171 --- /dev/null +++ b/Shared/Stages.cs @@ -0,0 +1,252 @@ +using System.Collections; +using System.Collections.Specialized; + +namespace Shared; + +public static class Stages { + + public static string? Input2Stage(string input) { + // alias value + if (Alias2Stage.TryGetValue(input.ToLower(), out string? mapName)) { + return mapName; + } + // exact stage value + if (Stage2Alias.ContainsKey(input)) { + return input; + } + // force input value with a ! + if (input.EndsWith("!")) { + return input.Substring(0, input.Length - 1); + } + return null; + } + + public static string KingdomAliasMapping() { + string result = ""; + foreach (DictionaryEntry item in Alias2Kingdom) { + result += item.Key + " -> " + item.Value + "\n"; + } + return result; + } + + public static readonly Dictionary Alias2Stage = new Dictionary() { + { "cap", "CapWorldHomeStage" }, + { "cascade", "WaterfallWorldHomeStage" }, + { "sand", "SandWorldHomeStage" }, + { "lake", "LakeWorldHomeStage" }, + { "wooded", "ForestWorldHomeStage" }, + { "cloud", "CloudWorldHomeStage" }, + { "lost", "ClashWorldHomeStage" }, + { "metro", "CityWorldHomeStage" }, + { "sea", "SeaWorldHomeStage" }, + { "snow", "SnowWorldHomeStage" }, + { "lunch", "LavaWorldHomeStage" }, + { "ruined", "BossRaidWorldHomeStage" }, + { "bowser", "SkyWorldHomeStage" }, + { "moon", "MoonWorldHomeStage" }, + { "mush", "PeachWorldHomeStage" }, + { "dark", "Special1WorldHomeStage" }, + { "darker", "Special2WorldHomeStage" }, + { "odyssey", "HomeShipInsideStage" }, + }; + + public static readonly OrderedDictionary Alias2Kingdom = new OrderedDictionary() { + { "cap", "Cap Kingdom" }, + { "cascade", "Cascade Kingdom" }, + { "sand", "Sand Kingdom" }, + { "lake", "Lake Kingdom" }, + { "wooded", "Wooded Kingdom" }, + { "cloud", "Cloud Kingdom" }, + { "lost", "Lost Kingdom" }, + { "metro", "Metro Kingdom" }, + { "sea", "Snow Kingdom" }, + { "snow", "Seaside Kingdom" }, + { "lunch", "Luncheon Kingdom" }, + { "ruined", "Ruined Kingdom" }, + { "bowser", "Bowser's Kingdom" }, + { "moon", "Moon Kingdom" }, + { "mush", "Mushroom Kingdom" }, + { "dark", "Dark Side" }, + { "darker", "Darker Side" }, + { "odyssey", "Odyssey" }, + }; + + public static readonly Dictionary Stage2Alias = new Dictionary() { + { "CapWorldHomeStage" , "cap" }, + { "CapWorldTowerStage" , "cap" }, + { "FrogSearchExStage" , "cap" }, + { "PoisonWaveExStage" , "cap" }, + { "PushBlockExStage" , "cap" }, + { "RollingExStage" , "cap" }, + { "WaterfallWorldHomeStage" , "cascade" }, + { "TrexPoppunExStage" , "cascade" }, + { "Lift2DExStage" , "cascade" }, + { "WanwanClashExStage" , "cascade" }, + { "CapAppearExStage" , "cascade" }, + { "WindBlowExStage" , "cascade" }, + { "SandWorldHomeStage" , "sand" }, + { "SandWorldShopStage" , "sand" }, + { "SandWorldSlotStage" , "sand" }, + { "SandWorldVibrationStage" , "sand" }, + { "SandWorldSecretStage" , "sand" }, + { "SandWorldMeganeExStage" , "sand" }, + { "SandWorldKillerExStage" , "sand" }, + { "SandWorldPressExStage" , "sand" }, + { "SandWorldSphinxExStage" , "sand" }, + { "SandWorldCostumeStage" , "sand" }, + { "SandWorldPyramid000Stage" , "sand" }, + { "SandWorldPyramid001Stage" , "sand" }, + { "SandWorldUnderground000Stage" , "sand" }, + { "SandWorldUnderground001Stage" , "sand" }, + { "SandWorldRotateExStage" , "sand" }, + { "MeganeLiftExStage" , "sand" }, + { "RocketFlowerExStage" , "sand" }, + { "WaterTubeExStage" , "sand" }, + { "LakeWorldHomeStage" , "lake" }, + { "LakeWorldShopStage" , "lake" }, + { "FastenerExStage" , "lake" }, + { "TrampolineWallCatchExStage" , "lake" }, + { "GotogotonExStage" , "lake" }, + { "FrogPoisonExStage" , "lake" }, + { "ForestWorldHomeStage" , "wooded" }, + { "ForestWorldWaterExStage" , "wooded" }, + { "ForestWorldTowerStage" , "wooded" }, + { "ForestWorldBossStage" , "wooded" }, + { "ForestWorldBonusStage" , "wooded" }, + { "ForestWorldCloudBonusExStage" , "wooded" }, + { "FogMountainExStage" , "wooded" }, + { "RailCollisionExStage" , "wooded" }, + { "ShootingElevatorExStage" , "wooded" }, + { "ForestWorldWoodsStage" , "wooded" }, + { "ForestWorldWoodsTreasureStage" , "wooded" }, + { "ForestWorldWoodsCostumeStage" , "wooded" }, + { "PackunPoisonExStage" , "wooded" }, + { "AnimalChaseExStage" , "wooded" }, + { "KillerRoadExStage" , "wooded" }, + { "CloudWorldHomeStage" , "cloud" }, + { "FukuwaraiKuriboStage" , "cloud" }, + { "Cube2DExStage" , "cloud" }, + { "ClashWorldHomeStage" , "lost" }, + { "ClashWorldShopStage" , "lost" }, + { "ImomuPoisonExStage" , "lost" }, + { "JangoExStage" , "lost" }, + { "CityWorldHomeStage" , "metro" }, + { "CityWorldMainTowerStage" , "metro" }, + { "CityWorldFactoryStage" , "metro" }, + { "CityWorldShop01Stage" , "metro" }, + { "CityWorldSandSlotStage" , "metro" }, + { "CityPeopleRoadStage" , "metro" }, + { "PoleGrabCeilExStage" , "metro" }, + { "TrexBikeExStage" , "metro" }, + { "PoleKillerExStage" , "metro" }, + { "Note2D3DRoomExStage" , "metro" }, + { "ShootingCityExStage" , "metro" }, + { "CapRotatePackunExStage" , "metro" }, + { "RadioControlExStage" , "metro" }, + { "ElectricWireExStage" , "metro" }, + { "Theater2DExStage" , "metro" }, + { "DonsukeExStage" , "metro" }, + { "SwingSteelExStage" , "metro" }, + { "BikeSteelExStage" , "metro" }, + { "SnowWorldHomeStage" , "snow" }, + { "SnowWorldTownStage" , "snow" }, + { "SnowWorldShopStage" , "snow" }, + { "SnowWorldLobby000Stage" , "snow" }, + { "SnowWorldLobby001Stage" , "snow" }, + { "SnowWorldRaceTutorialStage" , "snow" }, + { "SnowWorldRace000Stage" , "snow" }, + { "SnowWorldRace001Stage" , "snow" }, + { "SnowWorldCostumeStage" , "snow" }, + { "SnowWorldCloudBonusExStage" , "snow" }, + { "IceWalkerExStage" , "snow" }, + { "IceWaterBlockExStage" , "snow" }, + { "ByugoPuzzleExStage" , "snow" }, + { "IceWaterDashExStage" , "snow" }, + { "SnowWorldLobbyExStage" , "snow" }, + { "SnowWorldRaceExStage" , "snow" }, + { "SnowWorldRaceHardExStage" , "snow" }, + { "KillerRailCollisionExStage" , "snow" }, + { "SeaWorldHomeStage" , "sea" }, + { "SeaWorldUtsuboCaveStage" , "sea" }, + { "SeaWorldVibrationStage" , "sea" }, + { "SeaWorldSecretStage" , "sea" }, + { "SeaWorldCostumeStage" , "sea" }, + { "SeaWorldSneakingManStage" , "sea" }, + { "SenobiTowerExStage" , "sea" }, + { "CloudExStage" , "sea" }, + { "WaterValleyExStage" , "sea" }, + { "ReflectBombExStage" , "sea" }, + { "TogezoRotateExStage" , "sea" }, + { "LavaWorldHomeStage" , "lunch" }, + { "LavaWorldUpDownExStage" , "lunch" }, + { "LavaBonus1Zone" , "lunch" }, + { "LavaWorldShopStage" , "lunch" }, + { "LavaWorldCostumeStage" , "lunch" }, + { "ForkExStage" , "lunch" }, + { "LavaWorldExcavationExStage" , "lunch" }, + { "LavaWorldClockExStage" , "lunch" }, + { "LavaWorldBubbleLaneExStage" , "lunch" }, + { "LavaWorldTreasureStage" , "lunch" }, + { "GabuzouClockExStage" , "lunch" }, + { "CapAppearLavaLiftExStage" , "lunch" }, + { "LavaWorldFenceLiftExStage" , "lunch" }, + { "BossRaidWorldHomeStage" , "ruined" }, + { "DotTowerExStage" , "ruined" }, + { "BullRunExStage" , "ruined" }, + { "SkyWorldHomeStage" , "bowser" }, + { "SkyWorldShopStage" , "bowser" }, + { "SkyWorldCostumeStage" , "bowser" }, + { "SkyWorldCloudBonusExStage" , "bowser" }, + { "SkyWorldTreasureStage" , "bowser" }, + { "JizoSwitchExStage" , "bowser" }, + { "TsukkunRotateExStage" , "bowser" }, + { "KaronWingTowerStage" , "bowser" }, + { "TsukkunClimbExStage" , "bowser" }, + { "MoonWorldHomeStage" , "moon" }, + { "MoonWorldCaptureParadeStage" , "moon" }, + { "MoonWorldWeddingRoomStage" , "moon" }, + { "MoonWorldKoopa1Stage" , "moon" }, + { "MoonWorldBasementStage" , "moon" }, + { "MoonWorldWeddingRoom2Stage" , "moon" }, + { "MoonWorldKoopa2Stage" , "moon" }, + { "MoonWorldShopRoom" , "moon" }, + { "MoonWorldSphinxRoom" , "moon" }, + { "MoonAthleticExStage" , "moon" }, + { "Galaxy2DExStage" , "moon" }, + { "PeachWorldHomeStage" , "mush" }, + { "PeachWorldShopStage" , "mush" }, + { "PeachWorldCastleStage" , "mush" }, + { "PeachWorldCostumeStage" , "mush" }, + { "FukuwaraiMarioStage" , "mush" }, + { "DotHardExStage" , "mush" }, + { "YoshiCloudExStage" , "mush" }, + { "PeachWorldPictureBossMagmaStage" , "mush" }, + { "RevengeBossMagmaStage" , "mush" }, + { "PeachWorldPictureGiantWanderBossStage" , "mush" }, + { "RevengeGiantWanderBossStage" , "mush" }, + { "PeachWorldPictureBossKnuckleStage" , "mush" }, + { "RevengeBossKnuckleStage" , "mush" }, + { "PeachWorldPictureBossForestStage" , "mush" }, + { "RevengeForestBossStage" , "mush" }, + { "PeachWorldPictureMofumofuStage" , "mush" }, + { "RevengeMofumofuStage" , "mush" }, + { "PeachWorldPictureBossRaidStage" , "mush" }, + { "RevengeBossRaidStage" , "mush" }, + { "Special1WorldHomeStage" , "dark" }, + { "Special1WorldTowerStackerStage" , "dark" }, + { "Special1WorldTowerBombTailStage" , "dark" }, + { "Special1WorldTowerFireBlowerStage" , "dark" }, + { "Special1WorldTowerCapThrowerStage" , "dark" }, + { "KillerRoadNoCapExStage" , "dark" }, + { "PackunPoisonNoCapExStage" , "dark" }, + { "BikeSteelNoCapExStage" , "dark" }, + { "ShootingCityYoshiExStage" , "dark" }, + { "SenobiTowerYoshiExStage" , "dark" }, + { "LavaWorldUpDownYoshiExStage" , "dark" }, + { "Special2WorldHomeStage" , "darker" }, + { "Special2WorldLavaStage" , "darker" }, + { "Special2WorldCloudStage" , "darker" }, + { "Special2WorldKoopaStage" , "darker" }, + { "HomeShipInsideStage" , "odyssey" }, + }; +}