Exemple #1
0
        public string Serialize()
        {
            var data = new List <MiniYamlNode>();

            data.Add(new MiniYamlNode("Handshake", null,
                                      new string[] { "Mod", "Version", "Password" }.Select(p => FieldSaver.SaveField(this, p)).ToList()));
            data.Add(new MiniYamlNode("Client", FieldSaver.Save(Client)));

            return(data.WriteToString());
        }
        void IUtilityCommand.Run(Utility utility, string[] args)
        {
            // HACK: The engine code assumes that Game.modData is set.
            Game.ModData = utility.ModData;

            var version = utility.ModData.Manifest.Metadata.Version;

            if (args.Length > 1)
            {
                version = args[1];
            }

            Console.WriteLine(
                "This documentation is aimed at modders. It displays a template for weapon definitions " +
                "as well as its contained types (warheads and projectiles) with default values and developer commentary. " +
                "Please do not edit it directly, but add new `[Desc(\"String\")]` tags to the source code. This file has been " +
                "automatically generated for version {0} of OpenRA.", version);
            Console.WriteLine();

            var toc = new StringBuilder();
            var doc = new StringBuilder();

            var currentNamespace = "";

            var objectCreator = utility.ModData.ObjectCreator;
            var weaponInfo    = objectCreator.GetTypesImplementing <WeaponInfo>();
            var warheads      = objectCreator.GetTypesImplementing <IWarhead>().OrderBy(t => t.Namespace);
            var projectiles   = objectCreator.GetTypesImplementing <IProjectileInfo>().OrderBy(t => t.Namespace);

            var weaponTypes = Enumerable.Concat(weaponInfo, Enumerable.Concat(projectiles, warheads));

            foreach (var t in weaponTypes)
            {
                // skip helpers like TraitInfo<T>
                if (t.ContainsGenericParameters || t.IsAbstract)
                {
                    continue;
                }

                if (currentNamespace != t.Namespace)
                {
                    currentNamespace = t.Namespace;
                    doc.AppendLine();
                    doc.AppendLine("## {0}".F(currentNamespace));
                    toc.AppendLine("* [{0}](#{1})".F(currentNamespace, currentNamespace.Replace(".", "").ToLowerInvariant()));
                }

                var traitName = t.Name.EndsWith("Info") ? t.Name.Substring(0, t.Name.Length - 4) : t.Name;
                toc.AppendLine("  * [{0}](#{1})".F(traitName, traitName.ToLowerInvariant()));
                doc.AppendLine();
                doc.AppendLine("### {0}".F(traitName));

                var traitDescLines = t.GetCustomAttributesExts <DescAttribute>(false).SelectMany(d => d.Lines);
                foreach (var line in traitDescLines)
                {
                    doc.AppendLine(line);
                }

                var infos = FieldLoader.GetTypeLoadInfo(t);
                if (!infos.Any())
                {
                    continue;
                }

                doc.AppendLine("<table>");
                doc.AppendLine("<tr><th>Property</th><th>Default Value</th><th>Type</th><th>Description</th></tr>");

                var liveTraitInfo = t == typeof(WeaponInfo) ? null : objectCreator.CreateBasic(t);
                foreach (var info in infos)
                {
                    var fieldDescLines = info.Field.GetCustomAttributesExts <DescAttribute>(true).SelectMany(d => d.Lines);
                    var fieldType      = Util.FriendlyTypeName(info.Field.FieldType);
                    var defaultValue   = liveTraitInfo == null ? "" : FieldSaver.SaveField(liveTraitInfo, info.Field.Name).Value.Value;
                    doc.Append("<tr><td>{0}</td><td>{1}</td><td>{2}</td>".F(info.YamlName, defaultValue, fieldType));
                    doc.Append("<td>");

                    foreach (var line in fieldDescLines)
                    {
                        doc.Append(line + " ");
                    }

                    doc.AppendLine("</td></tr>");
                }

                doc.AppendLine("</table>");
            }

            Console.Write(toc.ToString());
            Console.Write(doc.ToString());
        }
Exemple #3
0
        internal static void UpgradeActorRules(ModData modData, int engineVersion, ref List <MiniYamlNode> nodes, MiniYamlNode parent, int depth)
        {
            var addNodes = new List <MiniYamlNode>();

            foreach (var node in nodes)
            {
                // Add a warning to add WithRearmAnimation to actors that might need it.
                if (engineVersion < 20161020 && depth == 2)
                {
                    if (node.Key == "RearmBuildings")
                    {
                        foreach (var host in node.Value.Value.Split(','))
                        {
                            Console.WriteLine("Actor type `{0}` is denoted as a RearmBuilding. Consider adding the `WithRearmAnimation` trait to it.".F(host));
                        }
                    }
                }

                // Resource type properties were renamed, and support for tooltips added
                if (engineVersion < 20161020)
                {
                    if (node.Key.StartsWith("ResourceType", StringComparison.Ordinal))
                    {
                        var image = node.Value.Nodes.FirstOrDefault(n => n.Key == "Sequence");
                        if (image != null)
                        {
                            image.Key = "Image";
                        }

                        var sequences = node.Value.Nodes.FirstOrDefault(n => n.Key == "Variants");
                        if (sequences != null)
                        {
                            sequences.Key = "Sequences";
                        }

                        var name = node.Value.Nodes.FirstOrDefault(n => n.Key == "Name");
                        if (name != null)
                        {
                            node.Value.Nodes.Add(new MiniYamlNode("Type", name.Value.Value));
                        }
                    }
                }

                // Renamed AttackSequence to DefaultAttackSequence in WithInfantryBody.
                if (engineVersion < 20161020)
                {
                    if (node.Key == "WithInfantryBody")
                    {
                        var attackSequence = node.Value.Nodes.FirstOrDefault(n => n.Key == "AttackSequence");
                        if (attackSequence != null)
                        {
                            attackSequence.Key = "DefaultAttackSequence";
                        }
                    }
                }

                // Move production description from Tooltip to Buildable
                if (engineVersion < 20161020)
                {
                    var tooltipChild = node.Value.Nodes.FirstOrDefault(n => n.Key == "Tooltip" || n.Key == "DisguiseToolTip");
                    if (tooltipChild != null)
                    {
                        var descNode = tooltipChild.Value.Nodes.FirstOrDefault(n => n.Key == "Description");
                        if (descNode != null)
                        {
                            var buildableNode = node.Value.Nodes.FirstOrDefault(n => n.Key == "Buildable");
                            if (buildableNode == null)
                            {
                                node.Value.Nodes.Add(buildableNode = new MiniYamlNode("Buildable", ""));
                            }

                            buildableNode.Value.Nodes.Add(descNode);
                            tooltipChild.Value.Nodes.Remove(descNode);
                        }
                    }
                }

                // Move production icon sequence from Tooltip to Buildable
                if (engineVersion < 20161022)
                {
                    var tooltipChild = node.Value.Nodes.FirstOrDefault(n => n.Key == "Tooltip" || n.Key == "DisguiseToolTip");
                    if (tooltipChild != null)
                    {
                        var iconNode = tooltipChild.Value.Nodes.FirstOrDefault(n => n.Key == "Icon");
                        if (iconNode != null)
                        {
                            var buildableNode = node.Value.Nodes.FirstOrDefault(n => n.Key == "Buildable");
                            if (buildableNode == null)
                            {
                                node.Value.Nodes.Add(buildableNode = new MiniYamlNode("Buildable", ""));
                            }

                            buildableNode.Value.Nodes.Add(iconNode);
                            tooltipChild.Value.Nodes.Remove(iconNode);
                        }
                    }
                }

                // Replaced upgrade consumers with conditions
                if (engineVersion < 20161117)
                {
                    var upgradeTypesNode = node.Value.Nodes.FirstOrDefault(n => n.Key == "UpgradeTypes");
                    if (upgradeTypesNode != null)
                    {
                        var upgradeMinEnabledLevel  = 0;
                        var upgradeMaxEnabledLevel  = int.MaxValue;
                        var upgradeMaxAcceptedLevel = 1;
                        var upgradeTypes            = FieldLoader.GetValue <string[]>("", upgradeTypesNode.Value.Value);
                        var minEnabledNode          = node.Value.Nodes.FirstOrDefault(n => n.Key == "UpgradeMinEnabledLevel");
                        if (minEnabledNode != null)
                        {
                            upgradeMinEnabledLevel = FieldLoader.GetValue <int>("", minEnabledNode.Value.Value);
                        }

                        var maxEnabledNode = node.Value.Nodes.FirstOrDefault(n => n.Key == "UpgradeMaxEnabledLevel");
                        if (maxEnabledNode != null)
                        {
                            upgradeMaxEnabledLevel = FieldLoader.GetValue <int>("", maxEnabledNode.Value.Value);
                        }

                        var maxAcceptedNode = node.Value.Nodes.FirstOrDefault(n => n.Key == "UpgradeMaxAcceptedLevel");
                        if (maxAcceptedNode != null)
                        {
                            upgradeMaxAcceptedLevel = FieldLoader.GetValue <int>("", maxAcceptedNode.Value.Value);
                        }

                        var processed = false;
                        if (upgradeMinEnabledLevel == 0 && upgradeMaxEnabledLevel == 0 && upgradeMaxAcceptedLevel == 1)
                        {
                            node.Value.Nodes.Add(new MiniYamlNode("RequiresCondition", upgradeTypes.Select(u => "!" + u).JoinWith(" && ")));
                            processed = true;
                        }
                        else if (upgradeMinEnabledLevel == 1 && upgradeMaxEnabledLevel == int.MaxValue && upgradeMaxAcceptedLevel == 1)
                        {
                            node.Value.Nodes.Add(new MiniYamlNode("RequiresCondition", upgradeTypes.JoinWith(" || ")));
                            processed = true;
                        }
                        else if (upgradeMinEnabledLevel == 0 && upgradeMaxEnabledLevel < int.MaxValue)
                        {
                            node.Value.Nodes.Add(new MiniYamlNode("RequiresCondition", upgradeTypes.JoinWith(" + ") + " <= " + upgradeMaxEnabledLevel));
                            processed = true;
                        }
                        else if (upgradeMaxEnabledLevel == int.MaxValue && upgradeMinEnabledLevel > 1)
                        {
                            node.Value.Nodes.Add(new MiniYamlNode("RequiresCondition", upgradeTypes.JoinWith(" + ") + " >= " + upgradeMinEnabledLevel));
                            processed = true;
                        }
                        else if (upgradeMaxEnabledLevel < int.MaxValue && upgradeMinEnabledLevel > 0)
                        {
                            var lowerBound = upgradeMinEnabledLevel + " <= " + upgradeTypes.JoinWith(" + ");
                            var upperBound = upgradeTypes.JoinWith(" + ") + " <= " + upgradeMaxEnabledLevel;
                            node.Value.Nodes.Add(new MiniYamlNode("RequiresCondition", lowerBound + " && " + upperBound));
                            processed = true;
                        }

                        if (processed)
                        {
                            node.Value.Nodes.RemoveAll(n => n.Key == "UpgradeTypes" || n.Key == "UpgradeMinEnabledLevel" ||
                                                       n.Key == "UpgradeMaxEnabledLevel" || n.Key == "UpgradeMaxAcceptedLevel");
                        }
                        else
                        {
                            Console.WriteLine("Unable to automatically migrate {0}:{1} UpgradeTypes to RequiresCondition. This must be corrected manually", parent.Key, node.Key);
                        }
                    }
                }

                if (engineVersion < 20161119)
                {
                    // Migrated carryalls over to new conditions system
                    ConvertUpgradesToCondition(parent, node, "CarryableUpgrades", "CarriedCondition");

                    if (node.Key == "WithDecorationCarryable")
                    {
                        node.Key = "WithDecoration@CARRYALL";
                        node.Value.Nodes.Add(new MiniYamlNode("RequiresCondition", "carryall-reserved"));
                    }
                }

                if (engineVersion < 20161120)
                {
                    if (node.Key.StartsWith("TimedUpgradeBar", StringComparison.Ordinal))
                    {
                        RenameNodeKey(node, "TimedConditionBar");
                        ConvertUpgradesToCondition(parent, node, "Upgrade", "Condition");
                    }

                    if (node.Key.StartsWith("GrantUpgradePower", StringComparison.Ordinal))
                    {
                        Console.WriteLine("GrantUpgradePower Condition must be manually added to all target actor's ExternalConditions list.");
                        RenameNodeKey(node, "GrantExternalConditionPower");
                        ConvertUpgradesToCondition(parent, node, "Upgrades", "Condition");

                        var soundNode = node.Value.Nodes.FirstOrDefault(n => n.Key == "GrantUpgradeSound");
                        if (soundNode != null)
                        {
                            soundNode.Key = "OnFireSound";
                        }
                        else
                        {
                            node.Value.Nodes.Add(new MiniYamlNode("OnFireSound", "ironcur9.aud"));
                        }

                        var sequenceNode = node.Value.Nodes.FirstOrDefault(n => n.Key == "GrantUpgradeSequence");
                        if (sequenceNode != null)
                        {
                            sequenceNode.Key = "Sequence";
                        }
                    }

                    if (node.Key.StartsWith("GrantUpgradeCrateAction", StringComparison.Ordinal))
                    {
                        Console.WriteLine("GrantUpgradeCrateAction Condition must be manually added to all target actor's ExternalConditions list.");
                        RenameNodeKey(node, "GrantExternalConditionCrateAction");
                        ConvertUpgradesToCondition(parent, node, "Upgrades", "Condition");
                    }
                }

                // Reworking bridge logic
                if (engineVersion < 20161210)
                {
                    if (node.Key == "BridgeHut")
                    {
                        RenameNodeKey(node, "LegacyBridgeHut");
                    }

                    if (node.Key == "BridgeLayer")
                    {
                        RenameNodeKey(node, "LegacyBridgeLayer");
                    }
                }

                // Removed WithBuildingExplosion
                if (engineVersion < 20161210)
                {
                    if (node.Key == "WithBuildingExplosion")
                    {
                        node.Value.Nodes.Add(new MiniYamlNode("Type", "Footprint"));
                        node.Value.Nodes.Add(new MiniYamlNode("Weapon", "UnitExplodeSmall"));
                        node.Key = "Explodes";
                        Console.WriteLine("The trait WithBuildingExplosion has been removed and superseded by additional 'Explodes' functionality.");
                        Console.WriteLine("If you need a delayed building explosion, use 'Explodes' with 'Type: Footprint' and a cosmetic weapon with warhead delay.");
                    }
                }

                if (engineVersion < 20161210)
                {
                    // Migrated lua upgrades to conditions
                    if (node.Key.StartsWith("ScriptUpgradesCache", StringComparison.Ordinal))
                    {
                        RenameNodeKey(node, "ExternalConditions");
                        var conditions = node.Value.Nodes.FirstOrDefault(n => n.Key == "Upgrades");
                        if (conditions != null)
                        {
                            conditions.Key = "Conditions";
                        }
                    }
                }

                if (engineVersion < 20161212)
                {
                    if (node.Key.StartsWith("UpgradeActorsNear", StringComparison.Ordinal))
                    {
                        RenameNodeKey(node, "ProximityExternalCondition");
                        ConvertUpgradesToCondition(parent, node, "Upgrades", "Condition");
                    }

                    if (node.Key == "Cargo")
                    {
                        ConvertUpgradesToCondition(parent, node, "LoadingUpgrades", "LoadingCondition");
                    }

                    if (node.Key == "Passenger" && node.Value.Nodes.Any(n => n.Key == "GrantUpgrades"))
                    {
                        Console.WriteLine("Passenger.GrantUpgrades support has been removed.");
                        Console.WriteLine("Define passenger-conditions using Cargo.PassengerConditions on the transports instead.");
                        node.Value.Nodes.RemoveAll(n => n.Key == "GrantUpgrades");
                    }
                }

                if (engineVersion < 20161213)
                {
                    if (node.Key == "Aircraft")
                    {
                        ConvertUpgradesToCondition(parent, node, "AirborneUpgrades", "AirborneCondition");
                        ConvertUpgradesToCondition(parent, node, "CruisingUpgrades", "CruisingCondition");
                    }

                    if (node.Key.StartsWith("Cloak", StringComparison.Ordinal))
                    {
                        ConvertUpgradesToCondition(parent, node, "WhileCloakedUpgrades", "CloakedCondition");
                    }

                    if (node.Key == "Disguise")
                    {
                        ConvertUpgradesToCondition(parent, node, "Upgrades", "DisguisedCondition");
                        if (!node.Value.Nodes.Any(n => n.Key == "DisguisedCondition"))
                        {
                            node.Value.Nodes.Add(new MiniYamlNode("DisguisedCondition", "disguise"));
                        }
                    }

                    if (node.Key == "Parachutable")
                    {
                        ConvertUpgradesToCondition(parent, node, "ParachuteUpgrade", "ParachutingCondition");
                        if (!node.Value.Nodes.Any(n => n.Key == "ParachutingCondition"))
                        {
                            node.Value.Nodes.Add(new MiniYamlNode("ParachutingCondition", "parachute"));
                        }
                    }

                    if (node.Key == "PrimaryBuilding")
                    {
                        ConvertUpgradesToCondition(parent, node, "Upgrades", "PrimaryCondition");
                        if (!node.Value.Nodes.Any(n => n.Key == "PrimaryCondition"))
                        {
                            node.Value.Nodes.Add(new MiniYamlNode("PrimaryCondition", "primary"));
                        }
                    }

                    if (node.Key.StartsWith("UpgradeOnDamageState", StringComparison.Ordinal))
                    {
                        RenameNodeKey(node, "GrantConditionOnDamageState");
                        ConvertUpgradesToCondition(parent, node, "Upgrades", "Condition");
                    }

                    if (node.Key.StartsWith("UpgradeOnMovement", StringComparison.Ordinal))
                    {
                        RenameNodeKey(node, "GrantConditionOnMovement");
                        ConvertUpgradesToCondition(parent, node, "Upgrades", "Condition");
                    }

                    if (node.Key.StartsWith("UpgradeOnTerrain", StringComparison.Ordinal))
                    {
                        RenameNodeKey(node, "GrantConditionOnTerrain");
                        ConvertUpgradesToCondition(parent, node, "Upgrades", "Condition");
                        if (!node.Value.Nodes.Any(n => n.Key == "Condition"))
                        {
                            node.Value.Nodes.Add(new MiniYamlNode("Condition", "terrain"));
                        }
                    }

                    if (node.Key == "AttackSwallow")
                    {
                        ConvertUpgradesToCondition(parent, node, "AttackingUpgrades", "AttackingCondition");
                        if (!node.Value.Nodes.Any(n => n.Key == "AttackingCondition"))
                        {
                            node.Value.Nodes.Add(new MiniYamlNode("AttackingCondition", "attacking"));
                        }
                    }

                    if (node.Key.StartsWith("Pluggable", StringComparison.Ordinal))
                    {
                        var upgrades = node.Value.Nodes.FirstOrDefault(n => n.Key == "Upgrades");
                        if (upgrades != null)
                        {
                            upgrades.Key = "Conditions";
                            foreach (var n in upgrades.Value.Nodes)
                            {
                                var conditions = FieldLoader.GetValue <string[]>("", n.Value.Value);
                                if (conditions.Length > 1)
                                {
                                    Console.WriteLine("Unable to automatically migrate multiple Pluggable upgrades to a condition. This must be corrected manually");
                                }
                            }
                        }
                    }

                    if (node.Key.StartsWith("GlobalUpgradable", StringComparison.Ordinal))
                    {
                        RenameNodeKey(node, "GrantConditionOnPrerequisite");
                        ConvertUpgradesToCondition(parent, node, "Upgrades", "Condition");
                    }

                    if (node.Key.StartsWith("GlobalUpgradeManager", StringComparison.Ordinal))
                    {
                        RenameNodeKey(node, "GrantConditionOnPrerequisiteManager");
                    }

                    if (node.Key.StartsWith("DeployToUpgrade", StringComparison.Ordinal))
                    {
                        RenameNodeKey(node, "GrantConditionOnDeploy");
                        ConvertUpgradesToCondition(parent, node, "UndeployedUpgrades", "UndeployedCondition");
                        ConvertUpgradesToCondition(parent, node, "DeployedUpgrades", "DeployedCondition");
                    }

                    if (node.Key == "GainsExperience")
                    {
                        var upgrades = node.Value.Nodes.FirstOrDefault(n => n.Key == "Upgrades");
                        if (upgrades != null)
                        {
                            upgrades.Key = "Conditions";
                            foreach (var n in upgrades.Value.Nodes)
                            {
                                var conditions = FieldLoader.GetValue <string[]>("", n.Value.Value);
                                if (conditions.Length > 1)
                                {
                                    Console.WriteLine("Unable to automatically migrate multiple GainsExperience upgrades to a condition. This must be corrected manually");
                                }
                            }
                        }
                    }

                    if (node.Key.StartsWith("DisableOnUpgrade", StringComparison.Ordinal))
                    {
                        RenameNodeKey(node, "DisableOnCondition");
                    }
                }

                if (engineVersion < 20161223)
                {
                    if (node.Key.StartsWith("UpgradeManager", StringComparison.Ordinal))
                    {
                        RenameNodeKey(node, "ConditionManager");
                    }

                    if (node.Key.StartsWith("-UpgradeManager", StringComparison.Ordinal))
                    {
                        RenameNodeKey(node, "-ConditionManager");
                    }
                }

                // Replaced NukePower CameraActor with CameraRange (effect-based reveal)
                if (engineVersion < 20161227)
                {
                    var nukePower = node.Value.Nodes.FirstOrDefault(n => n.Key.StartsWith("NukePower", StringComparison.Ordinal));
                    if (nukePower != null)
                    {
                        var cameraActor = nukePower.Value.Nodes.FirstOrDefault(n => n.Key == "CameraActor");
                        if (cameraActor != null)
                        {
                            nukePower.Value.Nodes.Remove(cameraActor);
                            nukePower.Value.Nodes.Add(new MiniYamlNode("CameraRange", "10"));
                            Console.WriteLine("If your camera actor had a different reveal range than 10, you'll need to correct that manually");
                        }
                    }
                }

                // Capture bonus was decoupled from CashTrickler to a separate trait.
                if (engineVersion < 20170108 && depth == 0)
                {
                    var trickler = node.Value.Nodes.FirstOrDefault(n => n.Key == "CashTrickler");
                    if (trickler != null)
                    {
                        var capture = trickler.Value.Nodes.FirstOrDefault(n => n.Key == "CaptureAmount");
                        if (capture != null)
                        {
                            var gcoc = new MiniYamlNode("GivesCashOnCapture", "");
                            gcoc.Value.Nodes.Add(capture);
                            trickler.Value.Nodes.Remove(capture);

                            var show = trickler.Value.Nodes.FirstOrDefault(n => n.Key == "ShowTicks");
                            if (show != null)
                            {
                                gcoc.Value.Nodes.Add(show);
                            }

                            node.Value.Nodes.Add(gcoc);
                            RenameNodeKey(capture, "Amount");
                        }

                        var period = trickler.Value.Nodes.FirstOrDefault(n => n.Key == "Period");
                        if (period != null)
                        {
                            period.Key = "Interval";
                        }
                    }
                }

                if (engineVersion < 20170121)
                {
                    if (node.Key.StartsWith("ProvidesRadar", StringComparison.Ordinal))
                    {
                        if (node.Value.Nodes.Any(n => n.Key == "RequiresCondition"))
                        {
                            Console.WriteLine("You must manually add the `disabled` condition to the ProvidesRadar RequiresCondition expression");
                        }
                        else
                        {
                            node.Value.Nodes.Add(new MiniYamlNode("RequiresCondition", "!disabled"));
                        }

                        if (!parent.Value.Nodes.Any(n => n.Key == "GrantConditionOnDisabled@IDISABLE"))
                        {
                            addNodes.Add(new MiniYamlNode("GrantConditionOnDisabled@IDISABLE", new MiniYaml("",
                                                                                                            new List <MiniYamlNode>()
                            {
                                new MiniYamlNode("Condition", "disabled")
                            })));
                        }
                    }

                    if (node.Key.StartsWith("JamsRadar", StringComparison.Ordinal))
                    {
                        Console.WriteLine("JamsRadar has been replaced with trait conditions.");
                        Console.WriteLine("You must manually add the `jammed` condition to the ProvidesRadar traits that you want to be affected.");
                        Console.WriteLine("You must manually add a WithRangeCircle trait to render the radar jamming range.");
                        RenameNodeKey(node, "ProximityExternalCondition@JAMMER");
                        var stances = node.Value.Nodes.FirstOrDefault(n => n.Key == "Stances");
                        if (stances != null)
                        {
                            stances.Key = "ValidStances";
                        }
                        else
                        {
                            node.Value.Nodes.Add(new MiniYamlNode("ValidStances", "Enemy, Neutral"));
                        }

                        node.Value.Nodes.Add(new MiniYamlNode("Condition", "jammed"));
                    }
                }

                // Rename UpgradeOverlay to WithColoredOverlay
                if (engineVersion < 20170201)
                {
                    if (node.Key.StartsWith("UpgradeOverlay", StringComparison.Ordinal))
                    {
                        RenameNodeKey(node, "WithColoredOverlay");
                    }
                }

                // Remove SpiceBloom.RespawnDelay to get rid of DelayedAction, and rename GrowthDelay to Lifetime
                if (engineVersion < 20170203)
                {
                    var spiceBloom = node.Value.Nodes.FirstOrDefault(n => n.Key == "SpiceBloom");
                    if (spiceBloom != null)
                    {
                        var respawnDelay = spiceBloom.Value.Nodes.FirstOrDefault(n => n.Key == "RespawnDelay");
                        if (respawnDelay != null)
                        {
                            spiceBloom.Value.Nodes.Remove(respawnDelay);
                            Console.WriteLine("RespawnDelay has been removed from SpiceBloom for technical reasons.");
                            Console.WriteLine("Increase self-kill delay of the spice bloom spawnpoint actor instead.");
                        }

                        var growthDelay = spiceBloom.Value.Nodes.FirstOrDefault(n => n.Key == "GrowthDelay");
                        if (growthDelay != null)
                        {
                            growthDelay.Key = "Lifetime";
                        }
                    }
                }

                if (engineVersion < 20170205)
                {
                    if (node.Key.StartsWith("SpiceBloom", StringComparison.Ordinal))
                    {
                        var spawnActor = node.Value.Nodes.FirstOrDefault(n => n.Key == "SpawnActor");
                        if (spawnActor != null)
                        {
                            node.Value.Nodes.Remove(spawnActor);
                            spawnActor.Key = "Actor";
                        }
                        else
                        {
                            spawnActor = new MiniYamlNode("Actor", new MiniYaml("spicebloom.spawnpoint"));
                        }

                        addNodes.Add(new MiniYamlNode("SpawnActorOnDeath", new MiniYaml("", new List <MiniYamlNode>()
                        {
                            spawnActor
                        })));
                    }
                }

                if (engineVersion < 20170210)
                {
                    if (node.Key.StartsWith("AttackCharge", StringComparison.Ordinal))
                    {
                        RenameNodeKey(node, "AttackTesla");
                    }

                    if (node.Key.StartsWith("WithChargeOverlay", StringComparison.Ordinal))
                    {
                        RenameNodeKey(node, "WithTeslaChargeOverlay");
                    }

                    if (node.Key.StartsWith("WithChargeAnimation", StringComparison.Ordinal))
                    {
                        RenameNodeKey(node, "WithTeslaChargeAnimation");
                    }
                }

                // Default values for ArrowSequence, CircleSequence and ClockSequence were changed (to null)
                if (engineVersion < 20170212)
                {
                    var supportPowerNodes = new[] { "AirstrikePower", "ParatroopersPower", "NukePower" };

                    if (supportPowerNodes.Any(s => node.Key.StartsWith(s, StringComparison.Ordinal)))
                    {
                        var arrow = node.Value.Nodes.FirstOrDefault(n => n.Key == "ArrowSequence");
                        if (arrow == null)
                        {
                            node.Value.Nodes.Add(new MiniYamlNode("ArrowSequence", "arrow"));
                        }

                        var circle = node.Value.Nodes.FirstOrDefault(n => n.Key == "CircleSequence");
                        if (circle == null)
                        {
                            node.Value.Nodes.Add(new MiniYamlNode("CircleSequence", "circles"));
                        }

                        var clock = node.Value.Nodes.FirstOrDefault(n => n.Key == "ClockSequence");
                        if (clock == null)
                        {
                            node.Value.Nodes.Add(new MiniYamlNode("ClockSequence", "clock"));
                        }
                    }
                }

                if (engineVersion < 20170218)
                {
                    var externalConditions = node.Value.Nodes.Where(n => n.Key.StartsWith("ExternalConditions", StringComparison.Ordinal));
                    foreach (var ec in externalConditions.ToList())
                    {
                        var conditionsNode = ec.Value.Nodes.FirstOrDefault(n => n.Key == "Conditions");
                        if (conditionsNode != null)
                        {
                            var conditions = FieldLoader.GetValue <string[]>("", conditionsNode.Value.Value);
                            foreach (var c in conditions)
                            {
                                node.Value.Nodes.Add(new MiniYamlNode("ExternalCondition@" + c.ToUpperInvariant(),
                                                                      new MiniYaml("", new List <MiniYamlNode>()
                                {
                                    new MiniYamlNode("Condition", c)
                                })));
                            }

                            node.Value.Nodes.Remove(ec);
                        }
                    }
                }

                // Renamed DisguiseToolTip to DisguiseTooltip in Disguise.
                if (engineVersion < 20170303)
                {
                    if (node.Key.StartsWith("DisguiseToolTip", StringComparison.Ordinal))
                    {
                        RenameNodeKey(node, "DisguiseTooltip");
                    }
                }

                // Split UncloakOn: Damage => Damage, Heal, SelfHeal
                if (engineVersion < 20170315)
                {
                    if (node.Key.StartsWith("UncloakOn", StringComparison.Ordinal))
                    {
                        node.Value.Value = node.Value.Value.Replace("Damage", "Damage, Heal, SelfHeal");
                    }
                }

                // Removed dead ActorGroupProxy trait
                if (engineVersion < 20170318)
                {
                    node.Value.Nodes.RemoveAll(n => n.Key == "ActorGroupProxy");
                }

                // Refactor SupplyTruck/AcceptsSupplies traits to DeliversCash/AcceptsDeliveredCash
                if (engineVersion < 20170415)
                {
                    if (node.Key == "SupplyTruck")
                    {
                        RenameNodeKey(node, "DeliversCash");
                    }
                    if (node.Key == "-SupplyTruck")
                    {
                        RenameNodeKey(node, "-DeliversCash");
                    }

                    if (node.Key == "AcceptsSupplies")
                    {
                        RenameNodeKey(node, "AcceptsDeliveredCash");
                    }
                    if (node.Key == "-AcceptsSupplies")
                    {
                        RenameNodeKey(node, "-AcceptsDeliveredCash");
                    }
                }

                // Add random sound support to AmbientSound
                if (engineVersion < 20170422)
                {
                    if (node.Key == "SoundFile" && parent.Key.StartsWith("AmbientSound", StringComparison.Ordinal))
                    {
                        RenameNodeKey(node, "SoundFiles");
                    }
                }

                // PauseOnLowPower property has been replaced with PauseOnCondition/RequiresCondition
                if (engineVersion < 20170501)
                {
                    if (node.Key.StartsWith("WithRearmAnimation", StringComparison.Ordinal) || node.Key.StartsWith("WithRepairAnimation", StringComparison.Ordinal) ||
                        node.Key.StartsWith("WithIdleAnimation", StringComparison.Ordinal))
                    {
                        var pauseOnLowPowerNode = node.Value.Nodes.FirstOrDefault(n => n.Key == "PauseOnLowPower");
                        if (pauseOnLowPowerNode != null)
                        {
                            node.Value.Nodes.Remove(pauseOnLowPowerNode);
                            Console.WriteLine("PauseOnLowPower has been removed from {0}; use RequiresCondition instead.".F(node.Key));
                        }
                    }
                    else if (node.Key.StartsWith("WithIdleOverlay", StringComparison.Ordinal) || node.Key.StartsWith("WithRepairOverlay", StringComparison.Ordinal))
                    {
                        var pauseOnLowPowerNode = node.Value.Nodes.FirstOrDefault(n => n.Key == "PauseOnLowPower");
                        if (pauseOnLowPowerNode != null)
                        {
                            node.Value.Nodes.Remove(pauseOnLowPowerNode);
                            Console.WriteLine("PauseOnLowPower has been removed from {0}; use PauseOnCondition or RequiresCondition instead.".F(node.Key));
                        }
                    }
                    else if (node.Key.StartsWith("AffectedByPowerOutage", StringComparison.Ordinal))
                    {
                        Console.WriteLine("Actor {0} has AffectedByPowerOutage; use the Condition property to apply its effects.".F(node.Key));
                    }
                    else if (node.Key.StartsWith("IonCannonPower", StringComparison.Ordinal) || node.Key.StartsWith("ProduceActorPower", StringComparison.Ordinal) ||
                             node.Key.StartsWith("NukePower", StringComparison.Ordinal) || node.Key.StartsWith("AttackOrderPower", StringComparison.Ordinal) ||
                             node.Key.StartsWith("GpsPower", StringComparison.Ordinal))
                    {
                        Console.WriteLine("{0} requires PauseOnCondition for pausing.".F(node.Key));
                    }
                }

                if (engineVersion < 20170507)
                {
                    if (node.Key == "Offset" && parent.Key.StartsWith("WithHarvestOverlay", StringComparison.Ordinal))
                    {
                        RenameNodeKey(node, "LocalOffset");
                    }

                    if (node.Key == "LocalOffset")
                    {
                        var orig   = FieldLoader.GetValue <WVec[]>(node.Key, node.Value.Value);
                        var scaled = orig.Select(o => FieldSaver.FormatValue(new WVec(
                                                                                 (int)Math.Round(Math.Sqrt(2) * o.X),
                                                                                 (int)Math.Round(Math.Sqrt(2) * o.Y),
                                                                                 (int)Math.Round(Math.Sqrt(2) * o.Z))));
                        node.Value.Value = scaled.JoinWith(", ");
                    }
                }

                // Refactor Rectangle shape RotateToIsometry bool into WAngle LocalYaw
                if (engineVersion < 20170509)
                {
                    if (node.Key.StartsWith("RotateToIsometry", StringComparison.Ordinal))
                    {
                        var value = FieldLoader.GetValue <bool>("RotateToIsometry", node.Value.Value);
                        node.Value.Value = value ? "128" : "0";

                        node.Key = "LocalYaw";
                    }
                }

                // Removed GrantConditionOnDeploy.DeployAnimation and made WithMakeAnimation compatible instead
                if (engineVersion < 20170510)
                {
                    var grantCondOnDeploy = node.Value.Nodes.FirstOrDefault(n => n.Key == "GrantConditionOnDeploy");
                    if (grantCondOnDeploy != null)
                    {
                        var deployAnimNode = grantCondOnDeploy.Value.Nodes.FirstOrDefault(n => n.Key == "DeployAnimation");
                        if (deployAnimNode != null)
                        {
                            grantCondOnDeploy.Value.Nodes.Remove(deployAnimNode);
                            Console.WriteLine("DeployAnimation was removed from GrantConditionOnDeploy.");
                            Console.WriteLine("Use WithMakeAnimation instead if a deploy animation is needed.");
                        }
                    }
                }

                UpgradeActorRules(modData, engineVersion, ref node.Value.Nodes, node, depth + 1);
            }

            foreach (var a in addNodes)
            {
                nodes.Add(a);
            }
        }
 public override MiniYaml Save()
 {
     return(new MiniYaml(FieldSaver.FormatValue(value)));
 }
Exemple #5
0
 public MiniYamlNode Serialize()
 {
     return(new MiniYamlNode($"Slot@{PlayerReference}", FieldSaver.Save(this)));
 }
Exemple #6
0
 public static void AddNode(this MiniYamlNode node, string key, object value)
 {
     node.Value.Nodes.Add(new MiniYamlNode(key, FieldSaver.FormatValue(value)));
 }
        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()));
        }
 string BuildYaml(string palette, int[] shadow, string tileset, string filename)
 {
     return("PaletteFromFile@{0}:\n    Name: {1}\n    Tileset: {2}\n    Filename: {3}\n    ShadowIndex: {4}".F(
                palette + '-' + tileset.ToLower(), palette, tileset, filename, FieldSaver.FormatValue(shadow)));
 }
Exemple #9
0
 public MiniYamlNode Serialize(string key)
 {
     return(new MiniYamlNode("SlotClient@{0}".F(key), FieldSaver.Save(this)));
 }
Exemple #10
0
 public MiniYamlNode Serialize()
 {
     return(new MiniYamlNode("Slot@{0}".F(PlayerReference), FieldSaver.Save(this)));
 }
        void IUtilityCommand.Run(Utility utility, string[] args)
        {
            // HACK: The engine code assumes that Game.modData is set.
            Game.ModData = utility.ModData;

            var version = utility.ModData.Manifest.Metadata.Version;

            if (args.Length > 1)
            {
                version = args[1];
            }

            Console.WriteLine(
                "This documentation is aimed at modders. It displays all traits with default values and developer commentary. " +
                "Please do not edit it directly, but add new `[Desc(\"String\")]` tags to the source code. This file has been " +
                "automatically generated for version {0} of OpenRA.", version);
            Console.WriteLine();

            var doc = new StringBuilder();
            var currentNamespace = "";

            foreach (var t in Game.ModData.ObjectCreator.GetTypesImplementing <TraitInfo>().OrderBy(t => t.Namespace))
            {
                if (t.ContainsGenericParameters || t.IsAbstract)
                {
                    continue;                     // skip helpers like TraitInfo<T>
                }
                if (currentNamespace != t.Namespace)
                {
                    currentNamespace = t.Namespace;
                    doc.AppendLine();
                    doc.AppendLine($"## {currentNamespace}");
                }

                var traitName      = t.Name.EndsWith("Info") ? t.Name.Substring(0, t.Name.Length - 4) : t.Name;
                var traitDescLines = t.GetCustomAttributes <DescAttribute>(false).SelectMany(d => d.Lines);
                doc.AppendLine();
                doc.AppendLine($"### {traitName}");
                foreach (var line in traitDescLines)
                {
                    doc.AppendLine(line);
                }

                var requires = RequiredTraitTypes(t);
                var reqCount = requires.Length;
                if (reqCount > 0)
                {
                    if (t.HasAttribute <DescAttribute>())
                    {
                        doc.AppendLine();
                    }

                    doc.Append($"Requires trait{(reqCount > 1 ? "s" : "")}: ");

                    var i = 0;
                    foreach (var require in requires)
                    {
                        var n    = require.Name;
                        var name = n.EndsWith("Info") ? n.Remove(n.Length - 4, 4) : n;
                        doc.Append($"[`{name}`](#{name.ToLowerInvariant()}){(i + 1 == reqCount ? ".\n" : ", ")}");
                        i++;
                    }
                }

                var infos = FieldLoader.GetTypeLoadInfo(t);
                if (!infos.Any())
                {
                    continue;
                }
                doc.AppendLine();
                doc.AppendLine("| Property | Default Value | Type | Description |");
                doc.AppendLine("| -------- | --------------| ---- | ----------- |");
                var liveTraitInfo = Game.ModData.ObjectCreator.CreateBasic(t);
                foreach (var info in infos)
                {
                    var fieldDescLines = info.Field.GetCustomAttributes <DescAttribute>(true).SelectMany(d => d.Lines);
                    var fieldType      = Util.FriendlyTypeName(info.Field.FieldType);
                    var loadInfo       = info.Field.GetCustomAttributes <FieldLoader.SerializeAttribute>(true).FirstOrDefault();
                    var defaultValue   = loadInfo != null && loadInfo.Required ? "*(required)*" : FieldSaver.SaveField(liveTraitInfo, info.Field.Name).Value.Value;
                    doc.Append($"| {info.YamlName} | {defaultValue} | {fieldType} | ");
                    foreach (var line in fieldDescLines)
                    {
                        doc.Append(line + " ");
                    }
                    doc.AppendLine("|");
                }
            }

            Console.Write(doc.ToString());
        }
        public override IEnumerable <string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
        {
            var locationKey = "{0} ({1})".F(actorNode.Key, actorNode.Location.Filename);
            var anyConditionalSmokeTrail = false;

            foreach (var smokeTrail in actorNode.ChildrenMatching("SmokeTrailWhenDamaged"))
            {
                var spriteNode = smokeTrail.LastChildMatching("Sprite");
                if (spriteNode != null)
                {
                    smokeTrail.RenameChildrenMatching("Sprite", "Image");
                }
                else
                {
                    smokeTrail.AddNode("Image", FieldSaver.FormatValue("smokey"));
                }

                var intervalNode = smokeTrail.LastChildMatching("Interval");
                if (intervalNode != null)
                {
                    var interval = intervalNode.NodeValue <int>();
                    smokeTrail.RenameChildrenMatching("Interval", "MovingInterval");
                    smokeTrail.AddNode("StationaryInterval", FieldSaver.FormatValue(interval));
                }
                else
                {
                    smokeTrail.AddNode("MovingInterval", FieldSaver.FormatValue(3));
                    smokeTrail.AddNode("StationaryInterval", FieldSaver.FormatValue(3));
                }

                var minDamageNode = smokeTrail.LastChildMatching("MinDamage");
                var isConditional = true;
                if (minDamageNode != null)
                {
                    var minDamage = minDamageNode.NodeValue <string>();
                    if (minDamage == "Undamaged")
                    {
                        isConditional = false;
                    }
                    else if (minDamage != "Heavy")
                    {
                        locations.GetOrAdd(locationKey).Add(smokeTrail.Key);
                    }

                    smokeTrail.RemoveNode(minDamageNode);
                }

                smokeTrail.AddNode("SpawnAtLastPosition", FieldSaver.FormatValue(false));
                smokeTrail.AddNode("TrailWhileStationary", FieldSaver.FormatValue(true));
                smokeTrail.AddNode("Type", FieldSaver.FormatValue("CenterPosition"));

                if (isConditional)
                {
                    smokeTrail.AddNode("RequiresCondition", FieldSaver.FormatValue("enable-smoke"));
                    anyConditionalSmokeTrail = true;
                }

                smokeTrail.RenameChildrenMatching("Sequence", "Sequences");
                smokeTrail.RenameChildrenMatching("Offset", "Offsets");
                smokeTrail.RenameKey("LeavesTrails");
            }

            if (anyConditionalSmokeTrail)
            {
                var grantCondition = new MiniYamlNode("GrantConditionOnDamageState@SmokeTrail", "");
                grantCondition.AddNode("Condition", FieldSaver.FormatValue("enable-smoke"));
                actorNode.AddNode(grantCondition);
            }

            yield break;
        }
Exemple #13
0
 public MiniYamlNode Serialize(string key)
 {
     return(new MiniYamlNode($"SlotClient@{key}", FieldSaver.Save(this)));
 }
        public void Run(ModData modData, string[] args)
        {
            // HACK: The engine code assumes that Game.modData is set.
            Game.ModData = modData;

            Console.WriteLine(
                "This documentation is aimed at modders. It displays all traits with default values and developer commentary. " +
                "Please do not edit it directly, but add new `[Desc(\"String\")]` tags to the source code. This file has been " +
                "automatically generated for version {0} of OpenRA.", Game.ModData.Manifest.Mod.Version);
            Console.WriteLine();

            var toc = new StringBuilder();
            var doc = new StringBuilder();

            foreach (var t in Game.ModData.ObjectCreator.GetTypesImplementing <ITraitInfo>().OrderBy(t => t.Namespace))
            {
                if (t.ContainsGenericParameters || t.IsAbstract)
                {
                    continue;                     // skip helpers like TraitInfo<T>
                }
                var traitName = t.Name.EndsWith("Info") ? t.Name.Substring(0, t.Name.Length - 4) : t.Name;
                toc.AppendLine("* [{0}](#{1})".F(traitName, traitName.ToLowerInvariant()));
                var traitDescLines = t.GetCustomAttributes <DescAttribute>(false).SelectMany(d => d.Lines);
                doc.AppendLine();
                doc.AppendLine("### {0}".F(traitName));
                foreach (var line in traitDescLines)
                {
                    doc.AppendLine(line);
                }

                var requires = RequiredTraitTypes(t);
                var reqCount = requires.Length;
                if (reqCount > 0)
                {
                    if (t.HasAttribute <DescAttribute>())
                    {
                        doc.AppendLine();
                    }

                    doc.Append("Requires trait{0}: ".F(reqCount > 1 ? "s" : ""));

                    var i = 0;
                    foreach (var require in requires)
                    {
                        var n    = require.Name;
                        var name = n.EndsWith("Info") ? n.Remove(n.Length - 4, 4) : n;
                        doc.Append("[`{0}`](#{1}){2}".F(name, name.ToLowerInvariant(), i + 1 == reqCount ? ".\n" : ", "));
                        i++;
                    }
                }

                var infos = FieldLoader.GetTypeLoadInfo(t);
                if (!infos.Any())
                {
                    continue;
                }
                doc.AppendLine("<table>");
                doc.AppendLine("<tr><th>Property</th><th>Default Value</th><th>Type</th><th>Description</th></tr>");
                var liveTraitInfo = Game.ModData.ObjectCreator.CreateBasic(t);
                foreach (var info in infos)
                {
                    var fieldDescLines = info.Field.GetCustomAttributes <DescAttribute>(true).SelectMany(d => d.Lines);
                    var fieldType      = FriendlyTypeName(info.Field.FieldType);
                    var defaultValue   = FieldSaver.SaveField(liveTraitInfo, info.Field.Name).Value.Value;
                    doc.Append("<tr><td>{0}</td><td>{1}</td><td>{2}</td>".F(info.YamlName, defaultValue, fieldType));
                    doc.Append("<td>");
                    foreach (var line in fieldDescLines)
                    {
                        doc.Append(line + " ");
                    }
                    doc.AppendLine("</td></tr>");
                }

                doc.AppendLine("</table>");
            }

            Console.Write(toc.ToString());
            Console.Write(doc.ToString());
        }
Exemple #15
0
 public MiniYamlNode Serialize()
 {
     return(new MiniYamlNode($"ClientPing@{Index}", FieldSaver.Save(this)));
 }
Exemple #16
0
 public MiniYamlNode Serialize()
 {
     return(new MiniYamlNode("Client@{0}".F(Index), FieldSaver.Save(this)));
 }
Exemple #17
0
 public MiniYamlNode Serialize()
 {
     return(new MiniYamlNode("GlobalSettings", FieldSaver.Save(this)));
 }