void Join(GameServer server) { if (server == null || !server.CanJoin()) { return; } var host = server.Address.Split(':')[0]; var port = Exts.ParseIntegerInvariant(server.Address.Split(':')[1]); ConnectionLogic.Connect(host, port, "", OpenLobby, DoNothing); }
public void Run(ModData modData, string[] args) { // HACK: The engine code assumes that Game.modData is set. Game.modData = modData; var map = new Map(args[1]); var engineDate = Exts.ParseIntegerInvariant(args[2]); UpgradeRules.UpgradeWeaponRules(engineDate, ref map.WeaponDefinitions, null, 0); UpgradeRules.UpgradeActorRules(engineDate, ref map.RuleDefinitions, null, 0); map.Save(args[1]); }
static void SetBounds(Map map, IniSection mapSection) { var offsetX = Exts.ParseIntegerInvariant(mapSection.GetValue("X", "0")); var offsetY = Exts.ParseIntegerInvariant(mapSection.GetValue("Y", "0")); var width = Exts.ParseIntegerInvariant(mapSection.GetValue("Width", "0")); var height = Exts.ParseIntegerInvariant(mapSection.GetValue("Height", "0")); var tl = new PPos(offsetX, offsetY); var br = new PPos(offsetX + width - 1, offsetY + height - 1); map.SetBounds(tl, br); }
void LoadActors(IniFile file, string section) { foreach (var s in file.GetSection(section, true)) { // Structures: num=owner,type,health,location,turret-facing,trigger // Units: num=owner,type,health,location,facing,action,trigger // Infantry: num=owner,type,health,location,subcell,action,facing,trigger try { var parts = s.Value.Split(','); var loc = Exts.ParseIntegerInvariant(parts[3]); if (parts[0] == "") { parts[0] = "Neutral"; } if (!players.Contains(parts[0])) { players.Add(parts[0]); } var actor = new ActorReference(parts[1].ToLowerInvariant()) { new LocationInit(new CPos(loc % mapSize, loc / mapSize)), new OwnerInit(parts[0]), new HealthInit(float.Parse(parts[2], NumberFormatInfo.InvariantInfo) / 256), new FacingInit((section == "INFANTRY") ? Exts.ParseIntegerInvariant(parts[6]) : Exts.ParseIntegerInvariant(parts[4])), }; if (section == "INFANTRY") { actor.Add(new SubCellInit(Exts.ParseIntegerInvariant(parts[4]))); } if (!rules.Actors.ContainsKey(parts[1].ToLowerInvariant())) { errorHandler("Ignoring unknown actor type: `{0}`".F(parts[1].ToLowerInvariant())); } else { map.Actors.Value.Add("Actor" + actorCount++, actor); } } catch (Exception) { errorHandler("Malformed actor definition: `{0}`".F(s)); } } }
static bool ClearPlayerSpawn(S server, Connection conn, Session.Client client, string s) { var spawnPoint = Exts.ParseIntegerInvariant(s); if (spawnPoint == 0) { return(true); } var existingClient = server.LobbyInfo.Clients.FirstOrDefault(cc => cc.SpawnPoint == spawnPoint); if (client != existingClient && !client.IsAdmin) { server.SendOrderTo(conn, "Message", "Only admins can clear spawn points."); return(true); } // Clearing a selected spawn point removes the player if (existingClient != null) { // Prevent a map-defined lock spawn from being affected if (existingClient.Slot != null && server.LobbyInfo.Slots[existingClient.Slot].LockSpawn) { return(true); } existingClient.SpawnPoint = 0; if (existingClient.State == Session.ClientState.Ready) { existingClient.State = Session.ClientState.NotReady; } server.SyncLobbyClients(); return(true); } // Clearing an empty spawn point prevents it from being selected // Clearing a disabled spawn restores it for use if (!server.LobbyInfo.DisabledSpawnPoints.Contains(spawnPoint)) { server.LobbyInfo.DisabledSpawnPoints.Add(spawnPoint); } else { server.LobbyInfo.DisabledSpawnPoints.Remove(spawnPoint); } server.SyncLobbyInfo(); return(true); }
public void StartGame(Arguments args) { Launch = new LaunchArguments(args); Ui.ResetAll(); Game.Settings.Save(); // Join a server directly var connect = Launch.GetConnectAddress(); if (!string.IsNullOrEmpty(connect)) { var parts = connect.Split(':'); if (parts.Length == 2) { var host = parts[0]; var port = Exts.ParseIntegerInvariant(parts[1]); Game.LoadShellMap(); Game.RemoteDirectConnect(host, port); return; } } // Load a replay directly if (!string.IsNullOrEmpty(Launch.Replay)) { var replayMeta = ReplayMetadata.Read(Launch.Replay); if (ReplayUtils.PromptConfirmReplayCompatibility(replayMeta, Game.LoadShellMap)) { Game.JoinReplay(Launch.Replay); } if (replayMeta != null) { var mod = replayMeta.GameInfo.Mod; if (mod != null && mod != Game.ModData.Manifest.Mod.Id && ModMetadata.AllMods.ContainsKey(mod)) { Game.InitializeMod(mod, args); } } return; } Game.LoadShellMap(); Game.Settings.Save(); }
public void WorldLoaded(World w, WorldRenderer wr) { var first = smudges.First().Value.First(); var sheet = first.Sheet; if (smudges.Values.Any(sprites => sprites.Any(s => s.Sheet != sheet))) { throw new InvalidDataException("Resource sprites span multiple sheets. Try loading their sequences earlier."); } var blendMode = first.BlendMode; if (smudges.Values.Any(sprites => sprites.Any(s => s.BlendMode != blendMode))) { throw new InvalidDataException("Smudges specify different blend modes. " + "Try using different smudge types for smudges that use different blend modes."); } render = new TerrainSpriteLayer(w, wr, sheet, blendMode, wr.Palette(Info.Palette), wr.World.Type != WorldType.Editor); // Add map smudges foreach (var s in w.Map.SmudgeDefinitions) { var name = s.Key; var vals = name.Split(' '); var type = vals[0]; if (!smudges.ContainsKey(type)) { continue; } var loc = vals[1].Split(','); var cell = new CPos(Exts.ParseIntegerInvariant(loc[0]), Exts.ParseIntegerInvariant(loc[1])); var depth = Exts.ParseIntegerInvariant(vals[2]); var smudge = new Smudge { Type = type, Depth = depth, Sprite = smudges[type][depth] }; tiles.Add(cell, smudge); render.Update(cell, smudge.Sprite); } }
public void Run(ModData modData, string[] args) { // HACK: The engine code assumes that Game.modData is set. Game.ModData = modData; // HACK: We know that maps can only be oramap or folders, which are ReadWrite var package = modData.ModFiles.OpenPackage(args[1], new Folder(".")) as IReadWritePackage; if (package == null) { throw new FileNotFoundException(args[1]); } var engineDate = Exts.ParseIntegerInvariant(args[2]); UpgradeMap(modData, package, engineDate); }
public DirectConnectLogic(Widget widget, Action onExit, Action openLobby, ConnectionTarget directConnectEndPoint) { var panel = widget; var ipField = panel.Get <TextFieldWidget>("IP"); var portField = panel.Get <TextFieldWidget>("PORT"); var text = Game.Settings.Player.LastServer; var last = text.LastIndexOf(':'); if (last < 0) { ipField.Text = "localhost"; portField.Text = "1234"; } else { ipField.Text = text.Substring(0, last); portField.Text = text.Substring(last + 1); } panel.Get <ButtonWidget>("JOIN_BUTTON").OnClick = () => { var port = Exts.WithDefault(1234, () => Exts.ParseIntegerInvariant(portField.Text)); Game.Settings.Player.LastServer = "{0}:{1}".F(ipField.Text, port); Game.Settings.Save(); ConnectionLogic.Connect(new ConnectionTarget(ipField.Text, port), "", () => { Ui.CloseWindow(); openLobby(); }, DoNothing); }; panel.Get <ButtonWidget>("BACK_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); }; if (directConnectEndPoint != null) { // The connection window must be opened at the end of the tick for the widget hierarchy to // work out, but we also want to prevent the server browser from flashing visible for one tick. widget.Visible = false; Game.RunAfterTick(() => { ConnectionLogic.Connect(directConnectEndPoint, "", () => { Ui.CloseWindow(); openLobby(); }, DoNothing); widget.Visible = true; }); } }
public CursorSequence(FrameCache cache, string name, string cursorSrc, string palette, MiniYaml info) { var d = info.ToDictionary(); Start = Exts.ParseIntegerInvariant(d["Start"].Value); Palette = palette; Name = name; if ((d.ContainsKey("Length") && d["Length"].Value == "*") || (d.ContainsKey("End") && d["End"].Value == "*")) { Length = Frames.Length - Start; } else if (d.ContainsKey("Length")) { Length = Exts.ParseIntegerInvariant(d["Length"].Value); } else if (d.ContainsKey("End")) { Length = Exts.ParseIntegerInvariant(d["End"].Value) - Start; } else { Length = 1; } Frames = cache[cursorSrc] .Skip(Start) .Take(Length) .ToArray(); if (d.ContainsKey("X")) { int x; Exts.TryParseIntegerInvariant(d["X"].Value, out x); Hotspot = Hotspot.WithX(x); } if (d.ContainsKey("Y")) { int y; Exts.TryParseIntegerInvariant(d["Y"].Value, out y); Hotspot = Hotspot.WithY(y); } }
public void OnNumeric(NumericLine line) { switch (line.Numeric) { case NumericCommand.RPL_WELCOME: new User(line.Message.Substring(line.Message.LastIndexOf(' ') + 1)).CopyTo(this); break; case NumericCommand.RPL_NAMREPLY: { var channel = line.GetChannel(); var nicknames = line.Message.Replace("~", "").Replace("&", "").Replace("@", "").Replace("%", "").Replace("+", "").Split(' '); foreach (var nickname in nicknames.Where(n => !channel.Users.ContainsKey(n))) { channel.Users.Add(nickname, new User { Nickname = nickname }); } } break; case NumericCommand.RPL_TOPIC: line.GetChannel().Topic.Message = line.Message; break; case NumericCommand.RPL_TOPICWHOTIME: { var topic = line.GetChannel().Topic; topic.Author = new User(line[4]); topic.Time = IrcUtils.DateTimeFromUnixTime(Exts.ParseIntegerInvariant(line[5])); } break; case NumericCommand.ERR_NICKNAMEINUSE: if (line.Target == "*") // no nickname set yet { Client.SetNickname(Client.Nickname + new Random().Next(10000, 99999)); } break; } }
public void WorldLoaded(World w, WorldRenderer wr) { world = w; tiles = new Dictionary <CPos, Smudge>(); dirty = new Dictionary <CPos, Smudge>(); smudges = new Dictionary <string, Sprite[]>(); var types = world.Map.SequenceProvider.Sequences(Info.Sequence); foreach (var t in types) { var seq = world.Map.SequenceProvider.GetSequence(Info.Sequence, t); var sprites = Exts.MakeArray(seq.Length, x => seq.GetSprite(x)); smudges.Add(t, sprites); } // Add map smudges foreach (var s in w.Map.SmudgeDefinitions) { var name = s.Key; var vals = name.Split(' '); var type = vals[0]; if (!smudges.ContainsKey(type)) { continue; } var loc = vals[1].Split(','); var cell = new CPos(Exts.ParseIntegerInvariant(loc[0]), Exts.ParseIntegerInvariant(loc[1])); var depth = Exts.ParseIntegerInvariant(vals[2]); var smudge = new Smudge { Type = type, Depth = depth, Sprite = smudges[type][depth] }; tiles.Add(cell, smudge); } }
internal static void TryUpdateHSLColor(ref string value) { if (value.Length == 0) { return; } try { var parts = value.Split(','); if (parts.Length == 3 || parts.Length == 4) { value = FieldSaver.FormatValue(new HSLColor( (byte)Exts.ParseIntegerInvariant(parts[0]).Clamp(0, 255), (byte)Exts.ParseIntegerInvariant(parts[1]).Clamp(0, 255), (byte)Exts.ParseIntegerInvariant(parts[2]).Clamp(0, 255))); } } catch { } }
void ReadCncTrees(IniFile file) { var terrain = file.GetSection("TERRAIN", true); if (terrain == null) { return; } foreach (var kv in terrain) { var loc = Exts.ParseIntegerInvariant(kv.Key); map.Actors.Value.Add("Actor" + actorCount++, new ActorReference(kv.Value.Split(',')[0].ToLowerInvariant()) { new LocationInit(new CPos(loc % mapSize, loc / mapSize)), new OwnerInit("Neutral") }); } }
void ReadRATrees(IniFile file) { var terrain = file.GetSection("TERRAIN", true); if (terrain == null) { return; } foreach (var kv in terrain) { var loc = Exts.ParseIntegerInvariant(kv.Key); var ar = new ActorReference(kv.Value.ToLowerInvariant()) { new LocationInit(new CPos(loc % mapSize, loc / mapSize)), new OwnerInit("Neutral") }; map.ActorDefinitions.Add(new MiniYamlNode("Actor" + actorCount++, ar.Save())); } }
void IUtilityCommand.Run(Utility utility, string[] args) { // HACK: The engine code assumes that Game.modData is set. var modData = Game.ModData = utility.ModData; var engineDate = Exts.ParseIntegerInvariant(args[1]); if (engineDate < UpgradeRules.MinimumSupportedVersion) { Console.WriteLine("Unsupported engine version. Use the release-{0} utility to update to that version, and then try again", UpgradeRules.MinimumSupportedVersion); return; } ProcessYaml("Rules", modData.Manifest.Rules, modData, engineDate, UpgradeRules.UpgradeActorRules); ProcessYaml("Weapons", modData.Manifest.Weapons, modData, engineDate, UpgradeRules.UpgradeWeaponRules); ProcessYaml("Sequences", modData.Manifest.Sequences, modData, engineDate, UpgradeRules.UpgradeSequences); ProcessYaml("Tilesets", modData.Manifest.TileSets, modData, engineDate, UpgradeRules.UpgradeTileset); ProcessYaml("Cursors", modData.Manifest.Cursors, modData, engineDate, UpgradeRules.UpgradeCursors); ProcessYaml("Chrome Metrics", modData.Manifest.ChromeMetrics, modData, engineDate, UpgradeRules.UpgradeChromeMetrics); ProcessYaml("Chrome Layout", modData.Manifest.ChromeLayout, modData, engineDate, UpgradeRules.UpgradeChromeLayout); // The map cache won't be valid if there was a map format upgrade, so walk the map packages manually // Only upgrade system maps - user maps must be updated manually using --upgrade-map Console.WriteLine("Processing System Maps:"); foreach (var map in modData.MapCache.EnumerateMapsWithoutCaching()) { try { Console.WriteLine(map.Package.Name); UpgradeMapCommand.UpgradeMap(modData, (IReadWritePackage)map.Package, engineDate); } catch (Exception e) { Console.WriteLine("Failed to upgrade map {0}", map); Console.WriteLine("Error was: {0}", e.ToString()); } } }
static bool Handicap(S server, Connection conn, Session.Client client, string s) { lock (server.LobbyInfo) { var parts = s.Split(' '); var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0])); // Only the host can change other client's info if (targetClient.Index != client.Index && !client.IsAdmin) { return(true); } // Map has disabled handicap changes if (server.LobbyInfo.Slots[targetClient.Slot].LockHandicap) { return(true); } if (!Exts.TryParseIntegerInvariant(parts[1], out var handicap)) { Log.Write("server", "Invalid handicap: {0}", s); return(false); } // Handicaps may be set between 0 - 95% in steps of 5% var options = Enumerable.Range(0, 20).Select(i => 5 * i); if (!options.Contains(handicap)) { Log.Write("server", "Invalid handicap: {0}", s); return(false); } targetClient.Handicap = handicap; server.SyncLobbyClients(); return(true); } }
void ReadTrees(IniFile file) { var terrain = file.GetSection("TERRAIN", true); if (terrain == null) { return; } foreach (var kv in terrain) { var loc = Exts.ParseIntegerInvariant(kv.Key); var treeActor = ParseTreeActor(kv.Value); var ar = new ActorReference(treeActor) { new LocationInit(ParseActorLocation(treeActor, loc)), new OwnerInit("Neutral") }; var actorCount = Map.ActorDefinitions.Count; Map.ActorDefinitions.Add(new MiniYamlNode("Actor" + actorCount++, ar.Save())); } }
public DirectConnectLogic(Widget widget, Action onExit, Action openLobby) { var panel = widget; var ipField = panel.Get <TextFieldWidget>("IP"); var portField = panel.Get <TextFieldWidget>("PORT"); var last = Game.Settings.Player.LastServer.Split(':'); ipField.Text = last.Length > 1 ? last[0] : "localhost"; portField.Text = last.Length == 2 ? last[1] : "1234"; panel.Get <ButtonWidget>("JOIN_BUTTON").OnClick = () => { var port = Exts.WithDefault(1234, () => Exts.ParseIntegerInvariant(portField.Text)); Game.Settings.Player.LastServer = "{0}:{1}".F(ipField.Text, port); Game.Settings.Save(); Ui.CloseWindow(); ConnectionLogic.Connect(ipField.Text, port, "", openLobby, onExit); }; panel.Get <ButtonWidget>("BACK_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); }; }
internal static void UpgradeMapFormat(ModData modData, IReadWritePackage package) { if (package == null) { return; } var yamlStream = package.GetStream("map.yaml"); if (yamlStream == null) { return; } var yaml = new MiniYaml(null, MiniYaml.FromStream(yamlStream, package.Name)); var nd = yaml.ToDictionary(); var mapFormat = FieldLoader.GetValue <int>("MapFormat", nd["MapFormat"].Value); if (mapFormat < 6) { throw new InvalidDataException("Map format {0} is not supported.\n File: {1}".F(mapFormat, package.Name)); } // Format 6 -> 7 combined the Selectable and UseAsShellmap flags into the Class enum if (mapFormat < 7) { MiniYaml useAsShellmap; if (nd.TryGetValue("UseAsShellmap", out useAsShellmap) && bool.Parse(useAsShellmap.Value)) { yaml.Nodes.Add(new MiniYamlNode("Visibility", new MiniYaml("Shellmap"))); } else if (nd["Type"].Value == "Mission" || nd["Type"].Value == "Campaign") { yaml.Nodes.Add(new MiniYamlNode("Visibility", new MiniYaml("MissionSelector"))); } } // Format 7 -> 8 replaced normalized HSL triples with rgb(a) hex colors if (mapFormat < 8) { var players = yaml.Nodes.FirstOrDefault(n => n.Key == "Players"); if (players != null) { bool noteHexColors = false; bool noteColorRamp = false; foreach (var player in players.Value.Nodes) { var colorRampNode = player.Value.Nodes.FirstOrDefault(n => n.Key == "ColorRamp"); if (colorRampNode != null) { Color dummy; var parts = colorRampNode.Value.Value.Split(','); if (parts.Length == 3 || parts.Length == 4) { // Try to convert old normalized HSL value to a rgb hex color try { HSLColor color = new HSLColor( (byte)Exts.ParseIntegerInvariant(parts[0].Trim()).Clamp(0, 255), (byte)Exts.ParseIntegerInvariant(parts[1].Trim()).Clamp(0, 255), (byte)Exts.ParseIntegerInvariant(parts[2].Trim()).Clamp(0, 255)); colorRampNode.Value.Value = FieldSaver.FormatValue(color); noteHexColors = true; } catch (Exception) { throw new InvalidDataException("Invalid ColorRamp value.\n File: " + package.Name); } } else if (parts.Length != 1 || !HSLColor.TryParseRGB(parts[0], out dummy)) { throw new InvalidDataException("Invalid ColorRamp value.\n File: " + package.Name); } colorRampNode.Key = "Color"; noteColorRamp = true; } } if (noteHexColors) { Console.WriteLine("ColorRamp is now called Color and uses rgb(a) hex value - rrggbb[aa]."); } else if (noteColorRamp) { Console.WriteLine("ColorRamp is now called Color."); } } } // Format 8 -> 9 moved map options and videos from the map file itself to traits if (mapFormat < 9) { var rules = yaml.Nodes.FirstOrDefault(n => n.Key == "Rules"); var worldNode = rules.Value.Nodes.FirstOrDefault(n => n.Key == "World"); if (worldNode == null) { worldNode = new MiniYamlNode("World", new MiniYaml("", new List <MiniYamlNode>())); } var playerNode = rules.Value.Nodes.FirstOrDefault(n => n.Key == "Player"); if (playerNode == null) { playerNode = new MiniYamlNode("Player", new MiniYaml("", new List <MiniYamlNode>())); } var visibilityNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Visibility"); if (visibilityNode != null) { var visibility = FieldLoader.GetValue <MapVisibility>("Visibility", visibilityNode.Value.Value); if (visibility.HasFlag(MapVisibility.MissionSelector)) { var missionData = new MiniYamlNode("MissionData", new MiniYaml("", new List <MiniYamlNode>())); worldNode.Value.Nodes.Add(missionData); var description = yaml.Nodes.FirstOrDefault(n => n.Key == "Description"); if (description != null) { missionData.Value.Nodes.Add(new MiniYamlNode("Briefing", description.Value.Value)); } var videos = yaml.Nodes.FirstOrDefault(n => n.Key == "Videos"); if (videos != null && videos.Value.Nodes.Any()) { var backgroundVideo = videos.Value.Nodes.FirstOrDefault(n => n.Key == "BackgroundInfo"); if (backgroundVideo != null) { missionData.Value.Nodes.Add(new MiniYamlNode("BackgroundVideo", backgroundVideo.Value.Value)); } var briefingVideo = videos.Value.Nodes.FirstOrDefault(n => n.Key == "Briefing"); if (briefingVideo != null) { missionData.Value.Nodes.Add(new MiniYamlNode("BriefingVideo", briefingVideo.Value.Value)); } var startVideo = videos.Value.Nodes.FirstOrDefault(n => n.Key == "GameStart"); if (startVideo != null) { missionData.Value.Nodes.Add(new MiniYamlNode("StartVideo", startVideo.Value.Value)); } var winVideo = videos.Value.Nodes.FirstOrDefault(n => n.Key == "GameWon"); if (winVideo != null) { missionData.Value.Nodes.Add(new MiniYamlNode("WinVideo", winVideo.Value.Value)); } var lossVideo = videos.Value.Nodes.FirstOrDefault(n => n.Key == "GameLost"); if (lossVideo != null) { missionData.Value.Nodes.Add(new MiniYamlNode("LossVideo", lossVideo.Value.Value)); } } } } var mapOptions = yaml.Nodes.FirstOrDefault(n => n.Key == "Options"); if (mapOptions != null) { var cheats = mapOptions.Value.Nodes.FirstOrDefault(n => n.Key == "Cheats"); if (cheats != null) { worldNode.Value.Nodes.Add(new MiniYamlNode("DeveloperMode", new MiniYaml("", new List <MiniYamlNode>() { new MiniYamlNode("Locked", "True"), new MiniYamlNode("Enabled", cheats.Value.Value) }))); } var crates = mapOptions.Value.Nodes.FirstOrDefault(n => n.Key == "Crates"); if (crates != null && !worldNode.Value.Nodes.Any(n => n.Key == "-CrateSpawner")) { if (!FieldLoader.GetValue <bool>("crates", crates.Value.Value)) { worldNode.Value.Nodes.Add(new MiniYamlNode("-CrateSpawner", new MiniYaml(""))); } } var creeps = mapOptions.Value.Nodes.FirstOrDefault(n => n.Key == "Creeps"); if (creeps != null) { worldNode.Value.Nodes.Add(new MiniYamlNode("MapCreeps", new MiniYaml("", new List <MiniYamlNode>() { new MiniYamlNode("Locked", "True"), new MiniYamlNode("Enabled", creeps.Value.Value) }))); } var fog = mapOptions.Value.Nodes.FirstOrDefault(n => n.Key == "Fog"); var shroud = mapOptions.Value.Nodes.FirstOrDefault(n => n.Key == "Shroud"); if (fog != null || shroud != null) { var shroudNode = new MiniYamlNode("Shroud", new MiniYaml("", new List <MiniYamlNode>())); playerNode.Value.Nodes.Add(shroudNode); if (fog != null) { shroudNode.Value.Nodes.Add(new MiniYamlNode("FogLocked", "True")); shroudNode.Value.Nodes.Add(new MiniYamlNode("FogEnabled", fog.Value.Value)); } if (shroud != null) { var enabled = FieldLoader.GetValue <bool>("shroud", shroud.Value.Value); shroudNode.Value.Nodes.Add(new MiniYamlNode("ExploredMapLocked", "True")); shroudNode.Value.Nodes.Add(new MiniYamlNode("ExploredMapEnabled", FieldSaver.FormatValue(!enabled))); } } var allyBuildRadius = mapOptions.Value.Nodes.FirstOrDefault(n => n.Key == "AllyBuildRadius"); if (allyBuildRadius != null) { worldNode.Value.Nodes.Add(new MiniYamlNode("MapBuildRadius", new MiniYaml("", new List <MiniYamlNode>() { new MiniYamlNode("AllyBuildRadiusLocked", "True"), new MiniYamlNode("AllyBuildRadiusEnabled", allyBuildRadius.Value.Value) }))); } var startingCash = mapOptions.Value.Nodes.FirstOrDefault(n => n.Key == "StartingCash"); if (startingCash != null) { playerNode.Value.Nodes.Add(new MiniYamlNode("PlayerResources", new MiniYaml("", new List <MiniYamlNode>() { new MiniYamlNode("DefaultCashLocked", "True"), new MiniYamlNode("DefaultCash", startingCash.Value.Value) }))); } var startingUnits = mapOptions.Value.Nodes.FirstOrDefault(n => n.Key == "ConfigurableStartingUnits"); if (startingUnits != null && !worldNode.Value.Nodes.Any(n => n.Key == "-SpawnMPUnits")) { worldNode.Value.Nodes.Add(new MiniYamlNode("SpawnMPUnits", new MiniYaml("", new List <MiniYamlNode>() { new MiniYamlNode("Locked", "True"), }))); } var techLevel = mapOptions.Value.Nodes.FirstOrDefault(n => n.Key == "TechLevel"); var difficulties = mapOptions.Value.Nodes.FirstOrDefault(n => n.Key == "Difficulties"); var shortGame = mapOptions.Value.Nodes.FirstOrDefault(n => n.Key == "ShortGame"); if (techLevel != null || difficulties != null || shortGame != null) { var optionsNode = new MiniYamlNode("MapOptions", new MiniYaml("", new List <MiniYamlNode>())); worldNode.Value.Nodes.Add(optionsNode); if (techLevel != null) { optionsNode.Value.Nodes.Add(new MiniYamlNode("TechLevelLocked", "True")); optionsNode.Value.Nodes.Add(new MiniYamlNode("TechLevel", techLevel.Value.Value)); } if (difficulties != null) { optionsNode.Value.Nodes.Add(new MiniYamlNode("Difficulties", difficulties.Value.Value)); } if (shortGame != null) { optionsNode.Value.Nodes.Add(new MiniYamlNode("ShortGameLocked", "True")); optionsNode.Value.Nodes.Add(new MiniYamlNode("ShortGameEnabled", shortGame.Value.Value)); } } } if (worldNode.Value.Nodes.Any() && !rules.Value.Nodes.Contains(worldNode)) { rules.Value.Nodes.Add(worldNode); } if (playerNode.Value.Nodes.Any() && !rules.Value.Nodes.Contains(playerNode)) { rules.Value.Nodes.Add(playerNode); } } // Format 9 -> 10 moved smudges to SmudgeLayer, and uses map.png for all maps if (mapFormat < 10) { ExtractSmudges(yaml); if (package.Contains("map.png")) { yaml.Nodes.Add(new MiniYamlNode("LockPreview", new MiniYaml("True"))); } } // Format 10 -> 11 replaced the single map type field with a list of categories if (mapFormat < 11) { var type = yaml.Nodes.First(n => n.Key == "Type"); yaml.Nodes.Add(new MiniYamlNode("Categories", type.Value)); yaml.Nodes.Remove(type); } if (mapFormat < Map.SupportedMapFormat) { yaml.Nodes.First(n => n.Key == "MapFormat").Value = new MiniYaml(Map.SupportedMapFormat.ToString()); Console.WriteLine("Converted {0} to MapFormat {1}.", package.Name, Map.SupportedMapFormat); } package.Update("map.yaml", Encoding.UTF8.GetBytes(yaml.Nodes.WriteToString())); }
public bool InterpretCommand(S server, Connection conn, Session.Client client, string cmd) { if (server == null || conn == null || client == null || !ValidateCommand(server, conn, client, cmd)) { return(false); } var dict = new Dictionary <string, Func <string, bool> > { { "state", s => { var state = Session.ClientState.Invalid; if (!Enum <Session.ClientState> .TryParse(s, false, out state)) { server.SendOrderTo(conn, "Message", "Malformed state command"); return(true); } client.State = state; Log.Write("server", "Player @{0} is {1}", conn.Socket.RemoteEndPoint, client.State); server.SyncLobbyClients(); CheckAutoStart(server); return(true); } }, { "startgame", s => { if (!client.IsAdmin) { server.SendOrderTo(conn, "Message", "Only the host can start the game."); return(true); } if (server.LobbyInfo.Slots.Any(sl => sl.Value.Required && server.LobbyInfo.ClientInSlot(sl.Key) == null)) { server.SendOrderTo(conn, "Message", "Unable to start the game until required slots are full."); return(true); } if (!server.LobbyInfo.GlobalSettings.EnableSingleplayer && server.LobbyInfo.Clients.Where(c => c.Bot == null && c.Slot != null).Count() == 1) { server.SendOrderTo(conn, "Message", server.TwoHumansRequiredText); return(true); } server.StartGame(); return(true); } }, { "slot", s => { if (!server.LobbyInfo.Slots.ContainsKey(s)) { Log.Write("server", "Invalid slot: {0}", s); return(false); } var slot = server.LobbyInfo.Slots[s]; if (slot.Closed || server.LobbyInfo.ClientInSlot(s) != null) { return(false); } // If the previous slot had a locked spawn then we must not carry that to the new slot var oldSlot = client.Slot != null ? server.LobbyInfo.Slots[client.Slot] : null; if (oldSlot != null && oldSlot.LockSpawn) { client.SpawnPoint = 0; } client.Slot = s; S.SyncClientToPlayerReference(client, server.Map.Players.Players[s]); if (!slot.LockColor) { client.PreferredColor = client.Color = SanitizePlayerColor(server, client.Color, client.Index, conn); } server.SyncLobbyClients(); CheckAutoStart(server); return(true); } }, { "allow_spectators", s => { if (bool.TryParse(s, out server.LobbyInfo.GlobalSettings.AllowSpectators)) { server.SyncLobbyGlobalSettings(); return(true); } else { server.SendOrderTo(conn, "Message", "Malformed allow_spectate command"); return(true); } } }, { "spectate", s => { if (server.LobbyInfo.GlobalSettings.AllowSpectators || client.IsAdmin) { client.Slot = null; client.SpawnPoint = 0; client.Color = HSLColor.FromRGB(255, 255, 255); server.SyncLobbyClients(); CheckAutoStart(server); return(true); } else { return(false); } } }, { "slot_close", s => { if (!ValidateSlotCommand(server, conn, client, s, true)) { return(false); } // kick any player that's in the slot var occupant = server.LobbyInfo.ClientInSlot(s); if (occupant != null) { if (occupant.Bot != null) { server.LobbyInfo.Clients.Remove(occupant); server.SyncLobbyClients(); var ping = server.LobbyInfo.PingFromClient(occupant); if (ping != null) { server.LobbyInfo.ClientPings.Remove(ping); server.SyncClientPing(); } } else { var occupantConn = server.Conns.FirstOrDefault(c => c.PlayerIndex == occupant.Index); if (occupantConn != null) { server.SendOrderTo(occupantConn, "ServerError", "Your slot was closed by the host."); server.DropClient(occupantConn); } } } server.LobbyInfo.Slots[s].Closed = true; server.SyncLobbySlots(); return(true); } }, { "slot_open", s => { if (!ValidateSlotCommand(server, conn, client, s, true)) { return(false); } var slot = server.LobbyInfo.Slots[s]; slot.Closed = false; server.SyncLobbySlots(); // Slot may have a bot in it var occupant = server.LobbyInfo.ClientInSlot(s); if (occupant != null && occupant.Bot != null) { server.LobbyInfo.Clients.Remove(occupant); var ping = server.LobbyInfo.PingFromClient(occupant); if (ping != null) { server.LobbyInfo.ClientPings.Remove(ping); server.SyncClientPing(); } } server.SyncLobbyClients(); return(true); } }, { "slot_bot", s => { var parts = s.Split(' '); if (parts.Length < 3) { server.SendOrderTo(conn, "Message", "Malformed slot_bot command"); return(true); } if (!ValidateSlotCommand(server, conn, client, parts[0], true)) { return(false); } var slot = server.LobbyInfo.Slots[parts[0]]; var bot = server.LobbyInfo.ClientInSlot(parts[0]); int controllerClientIndex; if (!Exts.TryParseIntegerInvariant(parts[1], out controllerClientIndex)) { Log.Write("server", "Invalid bot controller client index: {0}", parts[1]); return(false); } var botType = parts.Skip(2).JoinWith(" "); // Invalid slot if (bot != null && bot.Bot == null) { server.SendOrderTo(conn, "Message", "Can't add bots to a slot with another client."); return(true); } slot.Closed = false; if (bot == null) { // Create a new bot bot = new Session.Client() { Index = server.ChooseFreePlayerIndex(), Name = botType, Bot = botType, Slot = parts[0], Faction = "Random", SpawnPoint = 0, Team = 0, State = Session.ClientState.NotReady, BotControllerClientIndex = controllerClientIndex }; // Pick a random color for the bot var validator = server.ModData.Manifest.Get <ColorValidator>(); var tileset = server.Map.Rules.TileSet; var terrainColors = tileset.TerrainInfo.Where(ti => ti.RestrictPlayerColor).Select(ti => ti.Color); var playerColors = server.LobbyInfo.Clients.Select(c => c.Color.RGB) .Concat(server.Map.Players.Players.Values.Select(p => p.Color.RGB)); bot.Color = bot.PreferredColor = validator.RandomValidColor(server.Random, terrainColors, playerColors); server.LobbyInfo.Clients.Add(bot); } else { // Change the type of the existing bot bot.Name = botType; bot.Bot = botType; } S.SyncClientToPlayerReference(bot, server.Map.Players.Players[parts[0]]); server.SyncLobbyClients(); server.SyncLobbySlots(); return(true); } }, { "map", s => { if (!client.IsAdmin) { server.SendOrderTo(conn, "Message", "Only the host can change the map."); return(true); } var lastMap = server.LobbyInfo.GlobalSettings.Map; Action <MapPreview> selectMap = map => { // Make sure the map hasn't changed in the meantime if (server.LobbyInfo.GlobalSettings.Map != lastMap) { return; } server.LobbyInfo.GlobalSettings.Map = map.Uid; var oldSlots = server.LobbyInfo.Slots.Keys.ToArray(); server.Map = server.ModData.MapCache[server.LobbyInfo.GlobalSettings.Map]; server.LobbyInfo.Slots = server.Map.Players.Players .Select(p => MakeSlotFromPlayerReference(p.Value)) .Where(ss => ss != null) .ToDictionary(ss => ss.PlayerReference, ss => ss); LoadMapSettings(server, server.LobbyInfo.GlobalSettings, server.Map.Rules); // Reset client states foreach (var c in server.LobbyInfo.Clients) { c.State = Session.ClientState.Invalid; } // Reassign players into new slots based on their old slots: // - Observers remain as observers // - Players who now lack a slot are made observers // - Bots who now lack a slot are dropped // - Bots who are not defined in the map rules are dropped var botNames = server.Map.Rules.Actors["player"].TraitInfos <IBotInfo>().Select(t => t.Name); var slots = server.LobbyInfo.Slots.Keys.ToArray(); var i = 0; foreach (var os in oldSlots) { var c = server.LobbyInfo.ClientInSlot(os); if (c == null) { continue; } c.SpawnPoint = 0; c.Slot = i < slots.Length ? slots[i++] : null; if (c.Slot != null) { // Remove Bot from slot if slot forbids bots if (c.Bot != null && (!server.Map.Players.Players[c.Slot].AllowBots || !botNames.Contains(c.Bot))) { server.LobbyInfo.Clients.Remove(c); } S.SyncClientToPlayerReference(c, server.Map.Players.Players[c.Slot]); } else if (c.Bot != null) { server.LobbyInfo.Clients.Remove(c); } } // Validate if color is allowed and get an alternative if it isn't foreach (var c in server.LobbyInfo.Clients) { if (c.Slot == null || (c.Slot != null && !server.LobbyInfo.Slots[c.Slot].LockColor)) { c.Color = c.PreferredColor = SanitizePlayerColor(server, c.Color, c.Index, conn); } } server.SyncLobbyInfo(); server.SendMessage("{0} changed the map to {1}.".F(client.Name, server.Map.Title)); if (server.Map.DefinesUnsafeCustomRules) { server.SendMessage("This map contains custom rules. Game experience may change."); } if (!server.LobbyInfo.GlobalSettings.EnableSingleplayer) { server.SendMessage(server.TwoHumansRequiredText); } else if (server.Map.Players.Players.Where(p => p.Value.Playable).All(p => !p.Value.AllowBots)) { server.SendMessage("Bots have been disabled on this map."); } var briefing = MissionBriefingOrDefault(server); if (briefing != null) { server.SendMessage(briefing); } }; Action queryFailed = () => server.SendOrderTo(conn, "Message", "Map was not found on server."); var m = server.ModData.MapCache[s]; if (m.Status == MapStatus.Available || m.Status == MapStatus.DownloadAvailable) { selectMap(m); } else if (server.Settings.QueryMapRepository) { server.SendOrderTo(conn, "Message", "Searching for map on the Resource Center..."); server.ModData.MapCache.QueryRemoteMapDetails(new[] { s }, selectMap, queryFailed); } else { queryFailed(); } return(true); } }, { "option", s => { if (!client.IsAdmin) { server.SendOrderTo(conn, "Message", "Only the host can change the configuration."); return(true); } var allOptions = server.Map.Rules.Actors["player"].TraitInfos <ILobbyOptions>() .Concat(server.Map.Rules.Actors["world"].TraitInfos <ILobbyOptions>()) .SelectMany(t => t.LobbyOptions(server.Map.Rules)); // Overwrite keys with duplicate ids var options = new Dictionary <string, LobbyOption>(); foreach (var o in allOptions) { options[o.Id] = o; } var split = s.Split(' '); LobbyOption option; if (split.Length < 2 || !options.TryGetValue(split[0], out option) || !option.Values.ContainsKey(split[1])) { server.SendOrderTo(conn, "Message", "Invalid configuration command."); return(true); } if (option.Locked) { server.SendOrderTo(conn, "Message", "{0} cannot be changed.".F(option.Name)); return(true); } var oo = server.LobbyInfo.GlobalSettings.LobbyOptions[option.Id]; if (oo.Value == split[1]) { return(true); } oo.Value = oo.PreferredValue = split[1]; if (option.Id == "gamespeed") { var speed = server.ModData.Manifest.Get <GameSpeeds>().Speeds[oo.Value]; server.LobbyInfo.GlobalSettings.Timestep = speed.Timestep; server.LobbyInfo.GlobalSettings.OrderLatency = speed.OrderLatency; } server.SyncLobbyGlobalSettings(); server.SendMessage(option.ValueChangedMessage(client.Name, split[1])); return(true); } }, { "assignteams", s => { if (!client.IsAdmin) { server.SendOrderTo(conn, "Message", "Only the host can set that option."); return(true); } int teamCount; if (!Exts.TryParseIntegerInvariant(s, out teamCount)) { server.SendOrderTo(conn, "Message", "Number of teams could not be parsed: {0}".F(s)); return(true); } var maxTeams = (server.LobbyInfo.Clients.Count(c => c.Slot != null) + 1) / 2; teamCount = teamCount.Clamp(0, maxTeams); var clients = server.LobbyInfo.Slots .Select(slot => server.LobbyInfo.ClientInSlot(slot.Key)) .Where(c => c != null && !server.LobbyInfo.Slots[c.Slot].LockTeam); var assigned = 0; var clientCount = clients.Count(); foreach (var player in clients) { // Free for all if (teamCount == 0) { player.Team = 0; } // Humans vs Bots else if (teamCount == 1) { player.Team = player.Bot == null ? 1 : 2; } else { player.Team = assigned++ *teamCount / clientCount + 1; } } server.SyncLobbyClients(); return(true); } }, { "kick", s => { if (!client.IsAdmin) { server.SendOrderTo(conn, "Message", "Only the host can kick players."); return(true); } var split = s.Split(' '); if (split.Length < 2) { server.SendOrderTo(conn, "Message", "Malformed kick command"); return(true); } int kickClientID; Exts.TryParseIntegerInvariant(split[0], out kickClientID); var kickConn = server.Conns.SingleOrDefault(c => server.GetClient(c) != null && server.GetClient(c).Index == kickClientID); if (kickConn == null) { server.SendOrderTo(conn, "Message", "No-one in that slot."); return(true); } var kickClient = server.GetClient(kickConn); Log.Write("server", "Kicking client {0}.", kickClientID); server.SendMessage("{0} kicked {1} from the server.".F(client.Name, kickClient.Name)); server.SendOrderTo(kickConn, "ServerError", "You have been kicked from the server."); server.DropClient(kickConn); bool tempBan; bool.TryParse(split[1], out tempBan); if (tempBan) { Log.Write("server", "Temporarily banning client {0} ({1}).", kickClientID, kickClient.IpAddress); server.SendMessage("{0} temporarily banned {1} from the server.".F(client.Name, kickClient.Name)); server.TempBans.Add(kickClient.IpAddress); } server.SyncLobbyClients(); server.SyncLobbySlots(); return(true); } }, { "name", s => { var sanitizedName = Settings.SanitizedPlayerName(s); if (sanitizedName == client.Name) { return(true); } Log.Write("server", "Player@{0} is now known as {1}.", conn.Socket.RemoteEndPoint, sanitizedName); server.SendMessage("{0} is now known as {1}.".F(client.Name, sanitizedName)); client.Name = sanitizedName; server.SyncLobbyClients(); return(true); } }, { "faction", s => { var parts = s.Split(' '); var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0])); // Only the host can change other client's info if (targetClient.Index != client.Index && !client.IsAdmin) { return(true); } // Map has disabled faction changes if (server.LobbyInfo.Slots[targetClient.Slot].LockFaction) { return(true); } var factions = server.Map.Rules.Actors["world"].TraitInfos <FactionInfo>() .Where(f => f.Selectable).Select(f => f.InternalName); if (!factions.Contains(parts[1])) { server.SendOrderTo(conn, "Message", "Invalid faction selected: {0}".F(parts[1])); server.SendOrderTo(conn, "Message", "Supported values: {0}".F(factions.JoinWith(", "))); return(true); } targetClient.Faction = parts[1]; server.SyncLobbyClients(); return(true); } }, { "team", s => { var parts = s.Split(' '); var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0])); // Only the host can change other client's info if (targetClient.Index != client.Index && !client.IsAdmin) { return(true); } // Map has disabled team changes if (server.LobbyInfo.Slots[targetClient.Slot].LockTeam) { return(true); } int team; if (!Exts.TryParseIntegerInvariant(parts[1], out team)) { Log.Write("server", "Invalid team: {0}", s); return(false); } targetClient.Team = team; server.SyncLobbyClients(); return(true); } }, { "spawn", s => { var parts = s.Split(' '); var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0])); // Only the host can change other client's info if (targetClient.Index != client.Index && !client.IsAdmin) { return(true); } // Spectators don't need a spawnpoint if (targetClient.Slot == null) { return(true); } // Map has disabled spawn changes if (server.LobbyInfo.Slots[targetClient.Slot].LockSpawn) { return(true); } int spawnPoint; if (!Exts.TryParseIntegerInvariant(parts[1], out spawnPoint) || spawnPoint <0 || spawnPoint> server.Map.SpawnPoints.Length) { Log.Write("server", "Invalid spawn point: {0}", parts[1]); return(true); } if (server.LobbyInfo.Clients.Where(cc => cc != client).Any(cc => (cc.SpawnPoint == spawnPoint) && (cc.SpawnPoint != 0))) { server.SendOrderTo(conn, "Message", "You cannot occupy the same spawn point as another player."); return(true); } // Check if any other slot has locked the requested spawn if (spawnPoint > 0) { var spawnLockedByAnotherSlot = server.LobbyInfo.Slots.Where(ss => ss.Value.LockSpawn).Any(ss => { var pr = PlayerReferenceForSlot(server, ss.Value); return(pr != null && pr.Spawn == spawnPoint); }); if (spawnLockedByAnotherSlot) { server.SendOrderTo(conn, "Message", "The spawn point is locked to another player slot."); return(true); } } targetClient.SpawnPoint = spawnPoint; server.SyncLobbyClients(); return(true); } }, { "color", s => { var parts = s.Split(' '); var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0])); // Only the host can change other client's info if (targetClient.Index != client.Index && !client.IsAdmin) { return(true); } // Spectator or map has disabled color changes if (targetClient.Slot == null || server.LobbyInfo.Slots[targetClient.Slot].LockColor) { return(true); } // Validate if color is allowed and get an alternative it isn't var newColor = FieldLoader.GetValue <HSLColor>("(value)", parts[1]); targetClient.Color = SanitizePlayerColor(server, newColor, targetClient.Index, conn); // Only update player's preferred color if new color is valid if (newColor == targetClient.Color) { targetClient.PreferredColor = targetClient.Color; } server.SyncLobbyClients(); return(true); } }, { "sync_lobby", s => { if (!client.IsAdmin) { server.SendOrderTo(conn, "Message", "Only the host can set lobby info"); return(true); } var lobbyInfo = Session.Deserialize(s); if (lobbyInfo == null) { server.SendOrderTo(conn, "Message", "Invalid Lobby Info Sent"); return(true); } server.LobbyInfo = lobbyInfo; server.SyncLobbyInfo(); return(true); } } }; var cmdName = cmd.Split(' ').First(); var cmdValue = cmd.Split(' ').Skip(1).JoinWith(" "); Func <string, bool> a; if (!dict.TryGetValue(cmdName, out a)) { return(false); } return(a(cmdValue)); }
enum IniMapFormat { RedAlert = 3 } // otherwise, cnc (2 variants exist, we don't care to differentiate) public void ConvertIniMap(string iniFile) { using (var stream = GlobalFileSystem.Open(iniFile)) { var file = new IniFile(stream); var basic = file.GetSection("Basic"); var mapSection = file.GetSection("Map"); var legacyMapFormat = (IniMapFormat)Exts.ParseIntegerInvariant(basic.GetValue("NewINIFormat", "0")); var offsetX = Exts.ParseIntegerInvariant(mapSection.GetValue("X", "0")); var offsetY = Exts.ParseIntegerInvariant(mapSection.GetValue("Y", "0")); var width = Exts.ParseIntegerInvariant(mapSection.GetValue("Width", "0")); var height = Exts.ParseIntegerInvariant(mapSection.GetValue("Height", "0")); mapSize = (legacyMapFormat == IniMapFormat.RedAlert) ? 128 : 64; var tileset = Truncate(mapSection.GetValue("Theater", "TEMPERAT"), 8); map = new Map(rules.TileSets[tileset], mapSize, mapSize) { Title = basic.GetValue("Name", Path.GetFileNameWithoutExtension(iniFile)), Author = "Westwood Studios" }; var tl = new PPos(offsetX, offsetY); var br = new PPos(offsetX + width - 1, offsetY + height - 1); map.SetBounds(tl, br); if (legacyMapFormat == IniMapFormat.RedAlert) { UnpackRATileData(ReadPackedSection(file.GetSection("MapPack"))); UnpackRAOverlayData(ReadPackedSection(file.GetSection("OverlayPack"))); ReadRATrees(file); } else { // CnC using (var s = GlobalFileSystem.Open(iniFile.Substring(0, iniFile.Length - 4) + ".bin")) UnpackCncTileData(s); ReadCncOverlay(file); ReadCncTrees(file); } LoadVideos(file, "BASIC"); LoadActors(file, "STRUCTURES"); LoadActors(file, "UNITS"); LoadActors(file, "INFANTRY"); LoadActors(file, "SHIPS"); LoadSmudges(file, "SMUDGE"); var wps = file.GetSection("Waypoints") .Where(kv => Exts.ParseIntegerInvariant(kv.Value) > 0) .Select(kv => Pair.New(Exts.ParseIntegerInvariant(kv.Key), LocationFromMapOffset(Exts.ParseIntegerInvariant(kv.Value), mapSize))); // Add waypoint actors foreach (var kv in wps) { if (kv.First <= 7) { var ar = new ActorReference("mpspawn") { new LocationInit((CPos)kv.Second), new OwnerInit("Neutral") }; map.ActorDefinitions.Add(new MiniYamlNode("Actor" + actorCount++, ar.Save())); } else { var ar = new ActorReference("waypoint") { new LocationInit((CPos)kv.Second), new OwnerInit("Neutral") }; map.ActorDefinitions.Add(new MiniYamlNode("waypoint" + kv.First, ar.Save())); } } // Create default player definitions only if there are no players to import mapPlayers = new MapPlayers(map.Rules, (players.Count == 0) ? map.SpawnPoints.Value.Length : 0); foreach (var p in players) { LoadPlayer(file, p, legacyMapFormat == IniMapFormat.RedAlert); } map.PlayerDefinitions = mapPlayers.ToMiniYaml(); } }
void LoadSmudges(IniFile file, string section) { foreach (var s in file.GetSection(section, true)) { // loc=type,loc,depth var parts = s.Value.Split(','); var loc = Exts.ParseIntegerInvariant(parts[1]); map.Smudges.Value.Add(new SmudgeReference(parts[0].ToLowerInvariant(), new int2(loc % mapSize, loc / mapSize), Exts.ParseIntegerInvariant(parts[2]))); } }
void LoadSmudges(IniFile file, string section) { foreach (var s in file.GetSection(section, true)) { // loc=type,loc,depth var parts = s.Value.Split(','); var loc = Exts.ParseIntegerInvariant(parts[1]); var key = "{0} {1},{2} {3}".F(parts[0].ToLowerInvariant(), loc % mapSize, loc / mapSize, Exts.ParseIntegerInvariant(parts[2])); map.SmudgeDefinitions.Add(new MiniYamlNode(key, "")); } }
public bool InterpretCommand(S server, Connection conn, Session.Client client, string cmd) { if (!ValidateCommand(server, conn, client, cmd)) { return(false); } var dict = new Dictionary <string, Func <string, bool> > { { "state", s => { var state = Session.ClientState.Invalid; if (!Enum <Session.ClientState> .TryParse(s, false, out state)) { server.SendOrderTo(conn, "Message", "Malformed state command"); return(true); } client.State = state; Log.Write("server", "Player @{0} is {1}", conn.socket.RemoteEndPoint, client.State); server.SyncLobbyClients(); CheckAutoStart(server); return(true); } }, { "startgame", s => { if (!client.IsAdmin) { server.SendOrderTo(conn, "Message", "Only the host can start the game"); return(true); } if (server.LobbyInfo.Slots.Any(sl => sl.Value.Required && server.LobbyInfo.ClientInSlot(sl.Key) == null)) { server.SendOrderTo(conn, "Message", "Unable to start the game until required slots are full."); return(true); } server.StartGame(); return(true); } }, { "slot", s => { if (!server.LobbyInfo.Slots.ContainsKey(s)) { Log.Write("server", "Invalid slot: {0}", s); return(false); } var slot = server.LobbyInfo.Slots[s]; if (slot.Closed || server.LobbyInfo.ClientInSlot(s) != null) { return(false); } client.Slot = s; S.SyncClientToPlayerReference(client, server.Map.Players[s]); server.SyncLobbyClients(); CheckAutoStart(server); return(true); } }, { "allow_spectators", s => { if (bool.TryParse(s, out server.LobbyInfo.GlobalSettings.AllowSpectators)) { server.SyncLobbyGlobalSettings(); return(true); } else { server.SendOrderTo(conn, "Message", "Malformed allow_spectate command"); return(true); } } }, { "spectate", s => { if (server.LobbyInfo.GlobalSettings.AllowSpectators || client.IsAdmin) { client.Slot = null; client.SpawnPoint = 0; client.Color = HSLColor.FromRGB(255, 255, 255); server.SyncLobbyClients(); return(true); } else { return(false); } } }, { "slot_close", s => { if (!ValidateSlotCommand(server, conn, client, s, true)) { return(false); } // kick any player that's in the slot var occupant = server.LobbyInfo.ClientInSlot(s); if (occupant != null) { if (occupant.Bot != null) { server.LobbyInfo.Clients.Remove(occupant); server.SyncLobbyClients(); var ping = server.LobbyInfo.PingFromClient(occupant); server.LobbyInfo.ClientPings.Remove(ping); server.SyncClientPing(); } else { var occupantConn = server.Conns.FirstOrDefault(c => c.PlayerIndex == occupant.Index); if (occupantConn != null) { server.SendOrderTo(occupantConn, "ServerError", "Your slot was closed by the host"); server.DropClient(occupantConn); } } } server.LobbyInfo.Slots[s].Closed = true; server.SyncLobbySlots(); return(true); } }, { "slot_open", s => { if (!ValidateSlotCommand(server, conn, client, s, true)) { return(false); } var slot = server.LobbyInfo.Slots[s]; slot.Closed = false; server.SyncLobbySlots(); // Slot may have a bot in it var occupant = server.LobbyInfo.ClientInSlot(s); if (occupant != null && occupant.Bot != null) { server.LobbyInfo.Clients.Remove(occupant); var ping = server.LobbyInfo.PingFromClient(occupant); server.LobbyInfo.ClientPings.Remove(ping); } server.SyncLobbyClients(); return(true); } }, { "slot_bot", s => { var parts = s.Split(' '); if (parts.Length < 3) { server.SendOrderTo(conn, "Message", "Malformed slot_bot command"); return(true); } if (!ValidateSlotCommand(server, conn, client, parts[0], true)) { return(false); } var slot = server.LobbyInfo.Slots[parts[0]]; var bot = server.LobbyInfo.ClientInSlot(parts[0]); int controllerClientIndex; if (!Exts.TryParseIntegerInvariant(parts[1], out controllerClientIndex)) { Log.Write("server", "Invalid bot controller client index: {0}", parts[1]); return(false); } var botType = parts.Skip(2).JoinWith(" "); // Invalid slot if (bot != null && bot.Bot == null) { server.SendOrderTo(conn, "Message", "Can't add bots to a slot with another client"); return(true); } slot.Closed = false; if (bot == null) { // Create a new bot bot = new Session.Client() { Index = server.ChooseFreePlayerIndex(), Name = botType, Bot = botType, Slot = parts[0], Country = "random", SpawnPoint = 0, Team = 0, State = Session.ClientState.NotReady, BotControllerClientIndex = controllerClientIndex }; // Pick a random color for the bot HSLColor botColor; do { var hue = (byte)server.Random.Next(255); var sat = (byte)server.Random.Next(255); var lum = (byte)server.Random.Next(51, 255); botColor = new HSLColor(hue, sat, lum); } while (!ColorValidator.ValidatePlayerNewColor(server, botColor.RGB, bot.Index)); bot.Color = bot.PreferredColor = botColor; server.LobbyInfo.Clients.Add(bot); } else { // Change the type of the existing bot bot.Name = botType; bot.Bot = botType; } S.SyncClientToPlayerReference(bot, server.Map.Players[parts[0]]); server.SyncLobbyClients(); server.SyncLobbySlots(); return(true); } }, { "map", s => { if (!client.IsAdmin) { server.SendOrderTo(conn, "Message", "Only the host can change the map"); return(true); } if (server.ModData.MapCache[s].Status != MapStatus.Available) { server.SendOrderTo(conn, "Message", "Map was not found on server"); return(true); } server.LobbyInfo.GlobalSettings.Map = s; var oldSlots = server.LobbyInfo.Slots.Keys.ToArray(); LoadMap(server); SetDefaultDifficulty(server); // Reset client states foreach (var c in server.LobbyInfo.Clients) { c.State = Session.ClientState.Invalid; } // Reassign players into new slots based on their old slots: // - Observers remain as observers // - Players who now lack a slot are made observers // - Bots who now lack a slot are dropped var slots = server.LobbyInfo.Slots.Keys.ToArray(); var i = 0; foreach (var os in oldSlots) { var c = server.LobbyInfo.ClientInSlot(os); if (c == null) { continue; } c.SpawnPoint = 0; c.Slot = i < slots.Length ? slots[i++] : null; if (c.Slot != null) { // Remove Bot from slot if slot forbids bots if (c.Bot != null && !server.Map.Players[c.Slot].AllowBots) { server.LobbyInfo.Clients.Remove(c); } S.SyncClientToPlayerReference(c, server.Map.Players[c.Slot]); } else if (c.Bot != null) { server.LobbyInfo.Clients.Remove(c); } } foreach (var c in server.LobbyInfo.Clients) { // Validate if color is allowed and get an alternative it it isn't c.Color = c.PreferredColor = ColorValidator.ValidatePlayerColorAndGetAlternative(server, c.Color, c.Index, conn); } server.SyncLobbyInfo(); server.SendMessage("{0} changed the map to {1}.".F(client.Name, server.Map.Title)); return(true); } }, { "fragilealliance", s => { if (!client.IsAdmin) { server.SendOrderTo(conn, "Message", "Only the host can set that option"); return(true); } if (server.Map.Options.FragileAlliances.HasValue) { server.SendOrderTo(conn, "Message", "Map has disabled alliance configuration"); return(true); } bool.TryParse(s, out server.LobbyInfo.GlobalSettings.FragileAlliances); server.SyncLobbyGlobalSettings(); server.SendMessage("{0} {1} Diplomacy Changes." .F(client.Name, server.LobbyInfo.GlobalSettings.FragileAlliances ? "enabled" : "disabled")); return(true); } }, { "allowcheats", s => { if (!client.IsAdmin) { server.SendOrderTo(conn, "Message", "Only the host can set that option"); return(true); } if (server.Map.Options.Cheats.HasValue) { server.SendOrderTo(conn, "Message", "Map has disabled cheat configuration"); return(true); } bool.TryParse(s, out server.LobbyInfo.GlobalSettings.AllowCheats); server.SyncLobbyGlobalSettings(); server.SendMessage("{0} {1} Developer Cheats." .F(client.Name, server.LobbyInfo.GlobalSettings.AllowCheats ? "allowed" : "disallowed")); return(true); } }, { "shroud", s => { if (!client.IsAdmin) { server.SendOrderTo(conn, "Message", "Only the host can set that option"); return(true); } if (server.Map.Options.Shroud.HasValue) { server.SendOrderTo(conn, "Message", "Map has disabled shroud configuration"); return(true); } bool.TryParse(s, out server.LobbyInfo.GlobalSettings.Shroud); server.SyncLobbyGlobalSettings(); server.SendMessage("{0} {1} Shroud." .F(client.Name, server.LobbyInfo.GlobalSettings.Shroud ? "enabled" : "disabled")); return(true); } }, { "fog", s => { if (!client.IsAdmin) { server.SendOrderTo(conn, "Message", "Only the host can set that option"); return(true); } if (server.Map.Options.Fog.HasValue) { server.SendOrderTo(conn, "Message", "Map has disabled fog configuration"); return(true); } bool.TryParse(s, out server.LobbyInfo.GlobalSettings.Fog); server.SyncLobbyGlobalSettings(); server.SendMessage("{0} {1} Fog of War." .F(client.Name, server.LobbyInfo.GlobalSettings.Fog ? "enabled" : "disabled")); return(true); } }, { "assignteams", s => { if (!client.IsAdmin) { server.SendOrderTo(conn, "Message", "Only the host can set that option"); return(true); } int teamCount; if (!Exts.TryParseIntegerInvariant(s, out teamCount)) { server.SendOrderTo(conn, "Message", "Number of teams could not be parsed: {0}".F(s)); return(true); } var maxTeams = (server.LobbyInfo.Clients.Count(c => c.Slot != null) + 1) / 2; teamCount = teamCount.Clamp(0, maxTeams); var players = server.LobbyInfo.Slots .Select(slot => server.LobbyInfo.ClientInSlot(slot.Key)) .Where(c => c != null && !server.LobbyInfo.Slots[c.Slot].LockTeam); var assigned = 0; var playerCount = players.Count(); foreach (var player in players) { // Free for all if (teamCount == 0) { player.Team = 0; } // Humans vs Bots else if (teamCount == 1) { player.Team = player.Bot == null ? 1 : 2; } else { player.Team = assigned++ *teamCount / playerCount + 1; } } server.SyncLobbyClients(); return(true); } }, { "crates", s => { if (!client.IsAdmin) { server.SendOrderTo(conn, "Message", "Only the host can set that option"); return(true); } if (server.Map.Options.Crates.HasValue) { server.SendOrderTo(conn, "Message", "Map has disabled crate configuration"); return(true); } bool.TryParse(s, out server.LobbyInfo.GlobalSettings.Crates); server.SyncLobbyGlobalSettings(); server.SendMessage("{0} {1} Crates Appear." .F(client.Name, server.LobbyInfo.GlobalSettings.Crates ? "enabled" : "disabled")); return(true); } }, { "allybuildradius", s => { if (!client.IsAdmin) { server.SendOrderTo(conn, "Message", "Only the host can set that option"); return(true); } if (server.Map.Options.AllyBuildRadius.HasValue) { server.SendOrderTo(conn, "Message", "Map has disabled ally build radius configuration"); return(true); } bool.TryParse(s, out server.LobbyInfo.GlobalSettings.AllyBuildRadius); server.SyncLobbyGlobalSettings(); server.SendMessage("{0} {1} Build off Ally ConYards." .F(client.Name, server.LobbyInfo.GlobalSettings.AllyBuildRadius ? "enabled" : "disabled")); return(true); } }, { "difficulty", s => { if (!client.IsAdmin) { server.SendOrderTo(conn, "Message", "Only the host can set that option"); return(true); } if (s != null && !server.Map.Options.Difficulties.Contains(s)) { server.SendOrderTo(conn, "Message", "Unsupported difficulty selected: {0}".F(s)); server.SendOrderTo(conn, "Message", "Supported difficulties: {0}".F(server.Map.Options.Difficulties.JoinWith(","))); return(true); } server.LobbyInfo.GlobalSettings.Difficulty = s; server.SyncLobbyGlobalSettings(); server.SendMessage("{0} changed difficulty to {1}.".F(client.Name, s)); return(true); } }, { "startingunits", s => { if (!client.IsAdmin) { server.SendOrderTo(conn, "Message", "Only the host can set that option"); return(true); } if (!server.Map.Options.ConfigurableStartingUnits) { server.SendOrderTo(conn, "Message", "Map has disabled start unit configuration"); return(true); } var startUnitsInfo = server.Map.Rules.Actors["world"].Traits.WithInterface <MPStartUnitsInfo>(); var selectedClass = startUnitsInfo.Where(u => u.Class == s).Select(u => u.ClassName).FirstOrDefault(); var className = selectedClass != null ? selectedClass : s; server.LobbyInfo.GlobalSettings.StartingUnitsClass = s; server.SyncLobbyGlobalSettings(); server.SendMessage("{0} changed Starting Units to {1}.".F(client.Name, className)); return(true); } }, { "startingcash", s => { if (!client.IsAdmin) { server.SendOrderTo(conn, "Message", "Only the host can set that option"); return(true); } if (server.Map.Options.StartingCash.HasValue) { server.SendOrderTo(conn, "Message", "Map has disabled cash configuration"); return(true); } server.LobbyInfo.GlobalSettings.StartingCash = Exts.ParseIntegerInvariant(s); server.SyncLobbyGlobalSettings(); server.SendMessage("{0} changed Starting Cash to ${1}.".F(client.Name, s)); return(true); } }, { "techlevel", s => { if (!client.IsAdmin) { server.SendOrderTo(conn, "Message", "Only the host can set that option"); return(true); } if (server.Map.Options.TechLevel != null) { server.SendOrderTo(conn, "Message", "Map has disabled Tech configuration"); return(true); } server.LobbyInfo.GlobalSettings.TechLevel = s; server.SyncLobbyInfo(); server.SendMessage("{0} changed Tech Level to {1}.".F(client.Name, s)); return(true); } }, { "kick", s => { if (!client.IsAdmin) { server.SendOrderTo(conn, "Message", "Only the host can kick players"); return(true); } var split = s.Split(' '); if (split.Length < 2) { server.SendOrderTo(conn, "Message", "Malformed kick command"); return(true); } int kickClientID; Exts.TryParseIntegerInvariant(split[0], out kickClientID); var kickConn = server.Conns.SingleOrDefault(c => server.GetClient(c) != null && server.GetClient(c).Index == kickClientID); if (kickConn == null) { server.SendOrderTo(conn, "Message", "Noone in that slot."); return(true); } var kickClient = server.GetClient(kickConn); Log.Write("server", "Kicking client {0} as requested", kickClientID); server.SendMessage("{0} kicked {1} from the server.".F(client.Name, kickClient.Name)); server.SendOrderTo(kickConn, "ServerError", "You have been kicked from the server"); server.DropClient(kickConn); bool tempBan; bool.TryParse(split[1], out tempBan); if (tempBan) { Log.Write("server", "Temporarily banning client {0} ({1}) as requested", kickClientID, kickClient.IpAddress); server.SendMessage("{0} temporarily banned {1} from the server.".F(client.Name, kickClient.Name)); server.TempBans.Add(kickClient.IpAddress); } server.SyncLobbyClients(); server.SyncLobbySlots(); return(true); } }, { "name", s => { Log.Write("server", "Player@{0} is now known as {1}", conn.socket.RemoteEndPoint, s); server.SendMessage("{0} is now known as {1}.".F(client.Name, s)); client.Name = s; server.SyncLobbyClients(); return(true); } }, { "race", s => { var parts = s.Split(' '); var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0])); // Only the host can change other client's info if (targetClient.Index != client.Index && !client.IsAdmin) { return(true); } // Map has disabled race changes if (server.LobbyInfo.Slots[targetClient.Slot].LockRace) { return(true); } targetClient.Country = parts[1]; server.SyncLobbyClients(); return(true); } }, { "team", s => { var parts = s.Split(' '); var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0])); // Only the host can change other client's info if (targetClient.Index != client.Index && !client.IsAdmin) { return(true); } // Map has disabled team changes if (server.LobbyInfo.Slots[targetClient.Slot].LockTeam) { return(true); } int team; if (!Exts.TryParseIntegerInvariant(parts[1], out team)) { Log.Write("server", "Invalid team: {0}", s); return(false); } targetClient.Team = team; server.SyncLobbyClients(); return(true); } }, { "spawn", s => { var parts = s.Split(' '); var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0])); // Only the host can change other client's info if (targetClient.Index != client.Index && !client.IsAdmin) { return(true); } // Spectators don't need a spawnpoint if (targetClient.Slot == null) { return(true); } // Map has disabled spawn changes if (server.LobbyInfo.Slots[targetClient.Slot].LockSpawn) { return(true); } int spawnPoint; if (!Exts.TryParseIntegerInvariant(parts[1], out spawnPoint) || spawnPoint <0 || spawnPoint> server.Map.GetSpawnPoints().Length) { Log.Write("server", "Invalid spawn point: {0}", parts[1]); return(true); } if (server.LobbyInfo.Clients.Where(cc => cc != client).Any(cc => (cc.SpawnPoint == spawnPoint) && (cc.SpawnPoint != 0))) { server.SendOrderTo(conn, "Message", "You can't be at the same spawn point as another player"); return(true); } targetClient.SpawnPoint = spawnPoint; server.SyncLobbyClients(); return(true); } }, { "color", s => { var parts = s.Split(' '); var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0])); // Only the host can change other client's info if (targetClient.Index != client.Index && !client.IsAdmin) { return(true); } // Spectator or map has disabled color changes if (targetClient.Slot == null || server.LobbyInfo.Slots[targetClient.Slot].LockColor) { return(true); } var newHslColor = FieldLoader.GetValue <HSLColor>("(value)", parts[1]); // Validate if color is allowed and get an alternative it it isn't var altHslColor = ColorValidator.ValidatePlayerColorAndGetAlternative(server, newHslColor, targetClient.Index, conn); targetClient.Color = altHslColor; // Only update player's preferred color if new color is valid if (newHslColor == altHslColor) { targetClient.PreferredColor = altHslColor; } server.SyncLobbyClients(); return(true); } } }; var cmdName = cmd.Split(' ').First(); var cmdValue = cmd.Split(' ').Skip(1).JoinWith(" "); Func <string, bool> a; if (!dict.TryGetValue(cmdName, out a)) { return(false); } return(a(cmdValue)); }
public void StartGame(Arguments args) { Launch = new LaunchArguments(args); Ui.ResetAll(); Game.Settings.Save(); if (Launch.Benchmark) { Log.AddChannel("cpu", "cpu.csv"); Log.Write("cpu", "tick;time [ms]"); Log.AddChannel("render", "render.csv"); Log.Write("render", "frame;time [ms]"); Console.WriteLine("Saving benchmark data into {0}".F(Path.Combine(Platform.SupportDir, "Logs"))); Game.BenchmarkMode = true; } // Join a server directly var connect = Launch.GetConnectAddress(); if (!string.IsNullOrEmpty(connect)) { var parts = connect.Split(':'); if (parts.Length == 2) { var host = parts[0]; var port = Exts.ParseIntegerInvariant(parts[1]); Game.LoadShellMap(); Game.RemoteDirectConnect(host, port); return; } } // Load a replay directly if (!string.IsNullOrEmpty(Launch.Replay)) { ReplayMetadata replayMeta = null; try { replayMeta = ReplayMetadata.Read(Launch.Replay); } catch { } if (ReplayUtils.PromptConfirmReplayCompatibility(replayMeta, Game.LoadShellMap)) { Game.JoinReplay(Launch.Replay); } if (replayMeta != null) { var mod = replayMeta.GameInfo.Mod; if (mod != null && mod != Game.ModData.Manifest.Id && Game.Mods.ContainsKey(mod)) { Game.InitializeMod(mod, args); } } return; } Game.LoadShellMap(); Game.Settings.Save(); }
public static void LoadActors(IniFile file, string section, List <string> players, int mapSize, Map map) { foreach (var s in file.GetSection(section, true)) { // Structures: num=owner,type,health,location,turret-facing,trigger // Units: num=owner,type,health,location,facing,action,trigger // Infantry: num=owner,type,health,location,subcell,action,facing,trigger try { var parts = s.Value.Split(','); if (parts[0] == "") { parts[0] = "Neutral"; } if (!players.Contains(parts[0])) { players.Add(parts[0]); } var loc = Exts.ParseIntegerInvariant(parts[3]); var health = Exts.ParseIntegerInvariant(parts[2]) * 100 / 256; var facing = (section == "INFANTRY") ? Exts.ParseIntegerInvariant(parts[6]) : Exts.ParseIntegerInvariant(parts[4]); var actor = new ActorReference(parts[1].ToLowerInvariant()) { new LocationInit(new CPos(loc % mapSize, loc / mapSize)), new OwnerInit(parts[0]), }; var initDict = actor.InitDict; if (health != 100) { initDict.Add(new HealthInit(health)); } if (facing != 0) { initDict.Add(new FacingInit(255 - facing)); } if (section == "INFANTRY") { actor.Add(new SubCellInit(Exts.ParseIntegerInvariant(parts[4]))); } var actorCount = map.ActorDefinitions.Count; if (!map.Rules.Actors.ContainsKey(parts[1].ToLowerInvariant())) { Console.WriteLine("Ignoring unknown actor type: `{0}`".F(parts[1].ToLowerInvariant())); } else { map.ActorDefinitions.Add(new MiniYamlNode("Actor" + actorCount++, actor.Save())); } } catch (Exception) { Console.WriteLine("Malformed actor definition: `{0}`".F(s)); } } }
void IUtilityCommand.Run(Utility utility, string[] args) { // HACK: The engine code assumes that Game.modData is set. var modData = Game.ModData = utility.ModData; modData.MapCache.LoadMaps(); var engineDate = Exts.ParseIntegerInvariant(args[1]); if (engineDate < UpgradeRules.MinimumSupportedVersion) { Console.WriteLine("Unsupported engine version. Use the release-{0} utility to update to that version, and then try again", UpgradeRules.MinimumSupportedVersion); return; } ProcessYaml("Rules", modData.Manifest.Rules, modData, engineDate, UpgradeRules.UpgradeActorRules); ProcessYaml("Weapons", modData.Manifest.Weapons, modData, engineDate, UpgradeRules.UpgradeWeaponRules); ProcessYaml("Sequences", modData.Manifest.Sequences, modData, engineDate, UpgradeRules.UpgradeSequences); ProcessYaml("Tilesets", modData.Manifest.TileSets, modData, engineDate, UpgradeRules.UpgradeTileset); ProcessYaml("Cursors", modData.Manifest.Cursors, modData, engineDate, UpgradeRules.UpgradeCursors); ProcessYaml("Chrome Metrics", modData.Manifest.ChromeMetrics, modData, engineDate, UpgradeRules.UpgradeChromeMetrics); ProcessYaml("Chrome Layout", modData.Manifest.ChromeLayout, modData, engineDate, UpgradeRules.UpgradeChromeLayout); // The map cache won't be valid if there was a map format upgrade, so walk the map packages manually // Only upgrade system maps - user maps must be updated manually using --upgrade-map Console.WriteLine("Processing Maps:"); foreach (var kv in modData.Manifest.MapFolders) { var name = kv.Key; var classification = string.IsNullOrEmpty(kv.Value) ? MapClassification.Unknown : Enum <MapClassification> .Parse(kv.Value); if (classification != MapClassification.System) { continue; } var optional = name.StartsWith("~"); if (optional) { name = name.Substring(1); } try { using (var package = (IReadWritePackage)modData.ModFiles.OpenPackage(name)) { foreach (var map in package.Contents) { try { using (var mapPackage = package.OpenPackage(map, modData.ModFiles)) { if (mapPackage != null) { UpgradeMapCommand.UpgradeMap(modData, (IReadWritePackage)mapPackage, engineDate); } } } catch (Exception e) { Console.WriteLine("Failed to upgrade map {0}", map); Console.WriteLine("Error was: {0}", e.ToString()); } } } } catch { } } }
public void StartGame(Arguments args) { Ui.ResetAll(); Game.Settings.Save(); // Check whether the mod content is installed // TODO: The installation code has finally been beaten into shape, so we can // finally move it all into the planned "Manage Content" panel in the modchooser mod. var installData = Game.ModData.Manifest.Get <ContentInstaller>(); var installModContent = !installData.TestFiles.All(f => GlobalFileSystem.Exists(f)); var installModMusic = args != null && args.Contains("Install.Music"); if (installModContent || installModMusic) { var widgetArgs = new WidgetArgs() { { "continueLoading", () => Game.InitializeMod(Game.Settings.Game.Mod, args) }, }; if (installData.BackgroundWidget != null) { Ui.LoadWidget(installData.BackgroundWidget, Ui.Root, widgetArgs); } var menu = installModContent ? installData.MenuWidget : installData.MusicMenuWidget; Ui.OpenWindow(menu, widgetArgs); return; } // Join a server directly var connect = string.Empty; if (args != null) { if (args.Contains("Launch.Connect")) { connect = args.GetValue("Launch.Connect", null); } if (args.Contains("Launch.URI")) { connect = args.GetValue("Launch.URI", null); if (connect != null) { connect = connect.Replace("openra://", ""); connect = connect.TrimEnd('/'); } } } if (!string.IsNullOrEmpty(connect)) { var parts = connect.Split(':'); if (parts.Length == 2) { var host = parts[0]; var port = Exts.ParseIntegerInvariant(parts[1]); Game.LoadShellMap(); Game.RemoteDirectConnect(host, port); return; } } // Load a replay directly var replayFilename = args != null?args.GetValue("Launch.Replay", null) : null; if (!string.IsNullOrEmpty(replayFilename)) { var replayMeta = ReplayMetadata.Read(replayFilename); if (ReplayUtils.PromptConfirmReplayCompatibility(replayMeta, Game.LoadShellMap)) { Game.JoinReplay(replayFilename); } if (replayMeta != null) { var mod = replayMeta.GameInfo.Mod; if (mod != null && mod != Game.ModData.Manifest.Mod.Id && ModMetadata.AllMods.ContainsKey(mod)) { Game.InitializeMod(mod, args); } } return; } Game.LoadShellMap(); Game.Settings.Save(); }
enum IniMapFormat { RedAlert = 3 } // otherwise, cnc (2 variants exist, we don't care to differentiate) public void ConvertIniMap(string iniFile) { var file = new IniFile(GlobalFileSystem.Open(iniFile)); var basic = file.GetSection("Basic"); var mapSection = file.GetSection("Map"); var legacyMapFormat = (IniMapFormat)Exts.ParseIntegerInvariant(basic.GetValue("NewINIFormat", "0")); var offsetX = Exts.ParseIntegerInvariant(mapSection.GetValue("X", "0")); var offsetY = Exts.ParseIntegerInvariant(mapSection.GetValue("Y", "0")); var width = Exts.ParseIntegerInvariant(mapSection.GetValue("Width", "0")); var height = Exts.ParseIntegerInvariant(mapSection.GetValue("Height", "0")); mapSize = (legacyMapFormat == IniMapFormat.RedAlert) ? 128 : 64; var size = new Size(mapSize, mapSize); var tileset = Truncate(mapSection.GetValue("Theater", "TEMPERAT"), 8); map = Map.FromTileset(rules.TileSets[tileset]); map.Title = basic.GetValue("Name", Path.GetFileNameWithoutExtension(iniFile)); map.Author = "Westwood Studios"; map.MapSize.X = mapSize; map.MapSize.Y = mapSize; map.Bounds = Rectangle.FromLTRB(offsetX, offsetY, offsetX + width, offsetY + height); map.Selectable = true; map.Smudges = Exts.Lazy(() => new List <SmudgeReference>()); map.Actors = Exts.Lazy(() => new Dictionary <string, ActorReference>()); map.MapResources = Exts.Lazy(() => new CellLayer <ResourceTile>(TileShape.Rectangle, size)); map.MapTiles = Exts.Lazy(() => new CellLayer <TerrainTile>(TileShape.Rectangle, size)); map.Options = new MapOptions(); if (legacyMapFormat == IniMapFormat.RedAlert) { UnpackRATileData(ReadPackedSection(file.GetSection("MapPack"))); UnpackRAOverlayData(ReadPackedSection(file.GetSection("OverlayPack"))); ReadRATrees(file); } else { // CnC using (var s = GlobalFileSystem.Open(iniFile.Substring(0, iniFile.Length - 4) + ".bin")) UnpackCncTileData(s); ReadCncOverlay(file); ReadCncTrees(file); } LoadActors(file, "STRUCTURES"); LoadActors(file, "UNITS"); LoadActors(file, "INFANTRY"); LoadSmudges(file, "SMUDGE"); foreach (var p in players) { LoadPlayer(file, p, legacyMapFormat == IniMapFormat.RedAlert); } var wps = file.GetSection("Waypoints") .Where(kv => Exts.ParseIntegerInvariant(kv.Value) > 0) .Select(kv => Pair.New(Exts.ParseIntegerInvariant(kv.Key), LocationFromMapOffset(Exts.ParseIntegerInvariant(kv.Value), mapSize))) .ToArray(); // Add waypoint actors foreach (var kv in wps) { if (kv.First <= 7) { var a = new ActorReference("mpspawn"); a.Add(new LocationInit((CPos)kv.Second)); a.Add(new OwnerInit("Neutral")); map.Actors.Value.Add("Actor" + map.Actors.Value.Count.ToString(), a); } else { var a = new ActorReference("waypoint"); a.Add(new LocationInit((CPos)kv.Second)); a.Add(new OwnerInit("Neutral")); map.Actors.Value.Add("waypoint" + kv.First, a); } } }