mirror of
https://github.com/Sanae6/SmoOnlineServer.git
synced 2024-11-30 15:13:07 +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 => {
|
CommandHandler.RegisterCommand("send", args => {
|
||||||
const string optionUsage = "Usage: send <stage> <id> <scenario[-1..127]> <player/*>";
|
const string optionUsage = "Usage: send <stage> <id> <scenario[-1..127]> <player/*>";
|
||||||
if (args.Length < 4)
|
if (args.Length < 4) {
|
||||||
return optionUsage;
|
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];
|
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)
|
if (!sbyte.TryParse(args[2], out sbyte scenario) || scenario < -1)
|
||||||
return $"Invalid scenario number {args[2]} (range: [-1 to 127])";
|
return $"Invalid scenario number {args[2]} (range: [-1 to 127])";
|
||||||
Client[] players = args[3] == "*"
|
Client[] players = args[3] == "*"
|
||||||
|
@ -384,17 +381,13 @@ CommandHandler.RegisterCommand("send", args => {
|
||||||
|
|
||||||
CommandHandler.RegisterCommand("sendall", args => {
|
CommandHandler.RegisterCommand("sendall", args => {
|
||||||
const string optionUsage = "Usage: sendall <stage>";
|
const string optionUsage = "Usage: sendall <stage>";
|
||||||
if (args.Length < 1)
|
if (args.Length < 1) {
|
||||||
return optionUsage;
|
return optionUsage;
|
||||||
|
|
||||||
string stage = args[0];
|
|
||||||
|
|
||||||
if (Constants.MapNames.TryGetValue(stage.ToLower(), out string? mapName)) {
|
|
||||||
stage = mapName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!stage.Contains("Stage") && !stage.Contains("Zone")) {
|
string? stage = Stages.Input2Stage(args[0]);
|
||||||
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 (stage == null) {
|
||||||
|
return "Invalid Stage Name! ```" + Stages.KingdomAliasMapping() + "```";
|
||||||
}
|
}
|
||||||
|
|
||||||
Client[] players = server.Clients.Where(c => c.Connected).ToArray();
|
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);
|
.ToDictionary(type => type.GetCustomAttribute<PacketAttribute>()!.Type, type => type);
|
||||||
|
|
||||||
public static int HeaderSize { get; } = PacketHeader.StaticSize;
|
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