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()); }
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))); }
public MiniYamlNode Serialize() { return(new MiniYamlNode($"Slot@{PlayerReference}", FieldSaver.Save(this))); }
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))); }
public MiniYamlNode Serialize(string key) { return(new MiniYamlNode("SlotClient@{0}".F(key), FieldSaver.Save(this))); }
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; }
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()); }
public MiniYamlNode Serialize() { return(new MiniYamlNode($"ClientPing@{Index}", FieldSaver.Save(this))); }
public MiniYamlNode Serialize() { return(new MiniYamlNode("Client@{0}".F(Index), FieldSaver.Save(this))); }
public MiniYamlNode Serialize() { return(new MiniYamlNode("GlobalSettings", FieldSaver.Save(this))); }