mirror of
https://github.com/Sanae6/SmoOnlineServer.git
synced 2024-11-27 13:43:05 +00:00
verify stage values for send and sendall
Changes: - Moved alias mapping from Constants.cs to Stages.cs. - Added `odyssey` as an alias. - Hardcoded all known stage values. - Verfify that the stage input is either a alias or a known stage name. - Added an option to append `!` to a stage name to force sending even if the stage is not known (e.g. for custom kingdoms). Before it only checked that it was a known alias or that it contained `Stage` or `Zone`. That made it impossible to send players to`MoonWorldShopRoom` and `MoonWorldSphinxRoom`. And a typo would have resulted in a game crash.
This commit is contained in:
parent
47fc1527bf
commit
71bb96bf1e
3 changed files with 264 additions and 39 deletions
|
@ -349,20 +349,17 @@ CommandHandler.RegisterCommand("ban", args => {
|
|||
|
||||
CommandHandler.RegisterCommand("send", args => {
|
||||
const string optionUsage = "Usage: send <stage> <id> <scenario[-1..127]> <player/*>";
|
||||
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 <stage>";
|
||||
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();
|
||||
|
|
|
@ -21,24 +21,4 @@ public static class Constants {
|
|||
.ToDictionary(type => type.GetCustomAttribute<PacketAttribute>()!.Type, type => type);
|
||||
|
||||
public static int HeaderSize { get; } = PacketHeader.StaticSize;
|
||||
|
||||
public static readonly Dictionary<string, string> MapNames = new Dictionary<string, string>() {
|
||||
{"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"}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
252
Shared/Stages.cs
Normal file
252
Shared/Stages.cs
Normal file
|
@ -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<string, string> Alias2Stage = new Dictionary<string, string>() {
|
||||
{ "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<string, string> Stage2Alias = new Dictionary<string, string>() {
|
||||
{ "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" },
|
||||
};
|
||||
}
|
Loading…
Reference in a new issue