Merge pull request #10232 from penev92/modSupport

Implement mod loading from the support directory
This commit is contained in:
Matthias Mailänder
2016-01-11 12:37:35 +01:00
12 changed files with 139 additions and 92 deletions

View File

@@ -191,7 +191,7 @@ namespace OpenRA
public static void InitializeSettings(Arguments args) public static void InitializeSettings(Arguments args)
{ {
Settings = new Settings(Platform.ResolvePath("^", "settings.yaml"), args); Settings = new Settings(Platform.ResolvePath(Path.Combine("^", "settings.yaml")), args);
} }
internal static void Initialize(Arguments args) internal static void Initialize(Arguments args)

View File

@@ -29,7 +29,7 @@ namespace OpenRA
} }
} }
// Describes what is to be loaded in order to run a mod /// <summary> Describes what is to be loaded in order to run a mod. </summary>
public class Manifest public class Manifest
{ {
public static readonly Dictionary<string, Manifest> AllMods = LoadMods(); public static readonly Dictionary<string, Manifest> AllMods = LoadMods();
@@ -61,13 +61,16 @@ namespace OpenRA
readonly TypeDictionary modules = new TypeDictionary(); readonly TypeDictionary modules = new TypeDictionary();
readonly Dictionary<string, MiniYaml> yaml; readonly Dictionary<string, MiniYaml> yaml;
public Manifest(string mod) public Manifest(string modId, string modPath = null)
{ {
var path = Platform.ResolvePath(".", "mods", mod, "mod.yaml"); if (modPath == null)
modPath = ModMetadata.CandidateModPaths[modId];
var path = Path.Combine(modPath, "mod.yaml");
yaml = new MiniYaml(null, MiniYaml.FromFile(path)).ToDictionary(); yaml = new MiniYaml(null, MiniYaml.FromFile(path)).ToDictionary();
Mod = FieldLoader.Load<ModMetadata>(yaml["Metadata"]); Mod = FieldLoader.Load<ModMetadata>(yaml["Metadata"]);
Mod.Id = mod; Mod.Id = modId;
// TODO: Use fieldloader // TODO: Use fieldloader
Folders = YamlList(yaml, "Folders", true); Folders = YamlList(yaml, "Folders", true);
@@ -106,12 +109,10 @@ namespace OpenRA
RequiresMods = yaml["RequiresMods"].ToDictionary(my => my.Value); RequiresMods = yaml["RequiresMods"].ToDictionary(my => my.Value);
// Allow inherited mods to import parent maps. // Allow inherited mods to import parent maps.
var compat = new List<string>(); var compat = new List<string> { Mod.Id };
compat.Add(mod);
if (yaml.ContainsKey("SupportsMapsFrom")) if (yaml.ContainsKey("SupportsMapsFrom"))
foreach (var c in yaml["SupportsMapsFrom"].Value.Split(',')) compat.AddRange(yaml["SupportsMapsFrom"].Value.Split(',').Select(c => c.Trim()));
compat.Add(c.Trim());
MapCompatibility = compat.ToArray(); MapCompatibility = compat.ToArray();
@@ -156,8 +157,10 @@ namespace OpenRA
if (!yaml.ContainsKey(key)) if (!yaml.ContainsKey(key))
return new string[] { }; return new string[] { };
var list = yaml[key].ToDictionary().Keys.ToArray(); if (parsePaths)
return parsePaths ? list.Select(Platform.ResolvePath).ToArray() : list; return yaml[key].Nodes.Select(node => Platform.ResolvePath(node.Key, node.Value.Value ?? string.Empty)).ToArray();
return yaml[key].ToDictionary().Keys.ToArray();
} }
static IReadOnlyDictionary<string, string> YamlDictionary(Dictionary<string, MiniYaml> yaml, string key, bool parsePaths = false) static IReadOnlyDictionary<string, string> YamlDictionary(Dictionary<string, MiniYaml> yaml, string key, bool parsePaths = false)
@@ -168,15 +171,19 @@ namespace OpenRA
var inner = new Dictionary<string, string>(); var inner = new Dictionary<string, string>();
foreach (var node in yaml[key].Nodes) foreach (var node in yaml[key].Nodes)
{ {
var line = node.Key;
if (node.Value.Value != null)
line += ":" + node.Value.Value;
// '@' may be used in mod.yaml to indicate extra information (similar to trait @ tags). // '@' may be used in mod.yaml to indicate extra information (similar to trait @ tags).
// Applies to MapFolders (to indicate System and User directories) and Packages (to indicate package annotation). // Applies to MapFolders (to indicate System and User directories) and Packages (to indicate package annotation).
if (node.Key.Contains('@')) if (line.Contains('@'))
{ {
var split = node.Key.Split('@'); var split = line.Split('@');
inner.Add(split[0], split[1]); inner.Add(parsePaths ? Platform.ResolvePath(split[0]) : split[0], split[1]);
} }
else else
inner.Add(node.Key, null); inner.Add(line, null);
} }
return new ReadOnlyDictionary<string, string>(inner); return new ReadOnlyDictionary<string, string>(inner);
@@ -198,20 +205,16 @@ namespace OpenRA
static Dictionary<string, Manifest> LoadMods() static Dictionary<string, Manifest> LoadMods()
{ {
var basePath = Platform.ResolvePath(".", "mods");
var mods = Directory.GetDirectories(basePath)
.Select(x => x.Substring(basePath.Length + 1));
var ret = new Dictionary<string, Manifest>(); var ret = new Dictionary<string, Manifest>();
foreach (var mod in mods) foreach (var mod in ModMetadata.CandidateModPaths)
{ {
if (!File.Exists(Platform.ResolvePath(".", "mods", mod, "mod.yaml"))) if (!File.Exists(Path.Combine(mod.Value, "mod.yaml")))
continue; continue;
try try
{ {
var manifest = new Manifest(mod); var manifest = new Manifest(mod.Key, mod.Value);
ret.Add(mod, manifest); ret.Add(mod.Key, manifest);
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@@ -17,6 +17,7 @@ namespace OpenRA
{ {
public class ModMetadata public class ModMetadata
{ {
public static readonly Dictionary<string, string> CandidateModPaths = GetCandidateMods();
public static readonly Dictionary<string, ModMetadata> AllMods = ValidateMods(); public static readonly Dictionary<string, ModMetadata> AllMods = ValidateMods();
public string Id; public string Id;
@@ -24,21 +25,19 @@ namespace OpenRA
public string Description; public string Description;
public string Version; public string Version;
public string Author; public string Author;
public string LogoImagePath;
public string PreviewImagePath;
public bool Hidden; public bool Hidden;
public ContentInstaller Content; public ContentInstaller Content;
static Dictionary<string, ModMetadata> ValidateMods() static Dictionary<string, ModMetadata> ValidateMods()
{ {
var basePath = Platform.ResolvePath(".", "mods");
var mods = Directory.GetDirectories(basePath)
.Select(x => x.Substring(basePath.Length + 1));
var ret = new Dictionary<string, ModMetadata>(); var ret = new Dictionary<string, ModMetadata>();
foreach (var m in mods) foreach (var pair in CandidateModPaths)
{ {
try try
{ {
var yamlPath = Platform.ResolvePath(".", "mods", m, "mod.yaml"); var yamlPath = Path.Combine(pair.Value, "mod.yaml");
if (!File.Exists(yamlPath)) if (!File.Exists(yamlPath))
continue; continue;
@@ -47,22 +46,40 @@ namespace OpenRA
if (!nd.ContainsKey("Metadata")) if (!nd.ContainsKey("Metadata"))
continue; continue;
var mod = FieldLoader.Load<ModMetadata>(nd["Metadata"]); var metadata = FieldLoader.Load<ModMetadata>(nd["Metadata"]);
mod.Id = m; metadata.Id = pair.Key;
if (nd.ContainsKey("ContentInstaller")) if (nd.ContainsKey("ContentInstaller"))
mod.Content = FieldLoader.Load<ContentInstaller>(nd["ContentInstaller"]); metadata.Content = FieldLoader.Load<ContentInstaller>(nd["ContentInstaller"]);
ret.Add(m, mod); ret.Add(pair.Key, metadata);
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine("An exception occurred when trying to load ModMetadata for `{0}`:".F(m)); Console.WriteLine("An exception occurred when trying to load ModMetadata for `{0}`:".F(pair.Key));
Console.WriteLine(ex.Message); Console.WriteLine(ex.Message);
} }
} }
return ret; return ret;
} }
static Dictionary<string, string> GetCandidateMods()
{
// Get mods that are in the game folder.
var basePath = Platform.ResolvePath(Path.Combine(".", "mods"));
var mods = Directory.GetDirectories(basePath)
.ToDictionary(x => x.Substring(basePath.Length + 1));
// Get mods that are in the support folder.
var supportPath = Platform.ResolvePath(Path.Combine("^", "mods"));
if (!Directory.Exists(supportPath))
return mods;
foreach (var pair in Directory.GetDirectories(supportPath).ToDictionary(x => x.Substring(supportPath.Length + 1)))
mods.Add(pair.Key, pair.Value);
return mods;
}
} }
} }

View File

@@ -95,11 +95,19 @@ namespace OpenRA
public static string GameDir { get { return AppDomain.CurrentDomain.BaseDirectory; } } public static string GameDir { get { return AppDomain.CurrentDomain.BaseDirectory; } }
/// <summary>Replace special character prefixes with full paths</summary> /// <summary>Replaces special character prefixes with full paths.</summary>
public static string ResolvePath(string path) public static string ResolvePath(string path)
{ {
path = path.TrimEnd(new char[] { ' ', '\t' }); path = path.TrimEnd(new char[] { ' ', '\t' });
// If the path contains ':', chances are it is a package path.
// If it isn't, someone passed an already resolved path, which is wrong.
if (path.IndexOf(":", StringComparison.Ordinal) > 1)
{
var split = path.Split(':');
return ResolvePath(split[0], split[1]);
}
// paths starting with ^ are relative to the support dir // paths starting with ^ are relative to the support dir
if (path.StartsWith("^")) if (path.StartsWith("^"))
path = SupportDir + path.Substring(1); path = SupportDir + path.Substring(1);
@@ -111,7 +119,17 @@ namespace OpenRA
return path; return path;
} }
/// <summary>Replace special character prefixes with full paths</summary> /// <summary>Replaces package names with full paths. Avoid using this for non-package paths.</summary>
public static string ResolvePath(string package, string target)
{
// Resolve mod package paths.
if (ModMetadata.AllMods.ContainsKey(package))
package = ModMetadata.CandidateModPaths[package];
return ResolvePath(Path.Combine(package, target));
}
/// <summary>Replace special character prefixes with full paths.</summary>
public static string ResolvePath(params string[] path) public static string ResolvePath(params string[] path)
{ {
return ResolvePath(path.Aggregate(Path.Combine)); return ResolvePath(path.Aggregate(Path.Combine));

View File

@@ -11,6 +11,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using OpenRA.Graphics; using OpenRA.Graphics;
@@ -49,7 +50,7 @@ namespace OpenRA
var resolution = GetResolution(graphicSettings); var resolution = GetResolution(graphicSettings);
var rendererName = serverSettings.Dedicated ? "Null" : graphicSettings.Renderer; var rendererName = serverSettings.Dedicated ? "Null" : graphicSettings.Renderer;
var rendererPath = Platform.ResolvePath(".", "OpenRA.Platforms." + rendererName + ".dll"); var rendererPath = Platform.ResolvePath(Path.Combine(".", "OpenRA.Platforms." + rendererName + ".dll"));
Device = CreateDevice(Assembly.LoadFile(rendererPath), resolution.Width, resolution.Height, graphicSettings.Mode); Device = CreateDevice(Assembly.LoadFile(rendererPath), resolution.Width, resolution.Height, graphicSettings.Mode);

View File

@@ -33,7 +33,7 @@ namespace OpenRA
public Sound(string engineName) public Sound(string engineName)
{ {
var enginePath = Platform.ResolvePath(".", "OpenRA.Platforms." + engineName + ".dll"); var enginePath = Platform.ResolvePath(Path.Combine(".", "OpenRA.Platforms." + engineName + ".dll"));
soundEngine = CreateDevice(Assembly.LoadFile(enginePath)); soundEngine = CreateDevice(Assembly.LoadFile(enginePath));
} }

View File

@@ -82,7 +82,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
{ {
try try
{ {
using (var preview = new Bitmap(Platform.ResolvePath(".", "mods", mod.Id, "preview.png"))) using (var preview = new Bitmap(Platform.ResolvePath(mod.PreviewImagePath)))
if (preview.Width == 296 && preview.Height == 196) if (preview.Width == 296 && preview.Height == 196)
previews.Add(mod.Id, sheetBuilder.Add(preview)); previews.Add(mod.Id, sheetBuilder.Add(preview));
} }
@@ -90,7 +90,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
try try
{ {
using (var logo = new Bitmap(Platform.ResolvePath(".", "mods", mod.Id, "logo.png"))) using (var logo = new Bitmap(Platform.ResolvePath(mod.LogoImagePath)))
if (logo.Width == 96 && logo.Height == 96) if (logo.Width == 96 && logo.Height == 96)
logos.Add(mod.Id, sheetBuilder.Add(logo)); logos.Add(mod.Id, sheetBuilder.Add(logo));
} }

View File

@@ -17,7 +17,7 @@ Chrome:
Assemblies: Assemblies:
./mods/common/OpenRA.Mods.Common.dll ./mods/common/OpenRA.Mods.Common.dll
./mods/ra/OpenRA.Mods.RA.dll ./mods/ra/OpenRA.Mods.RA.dll
./mods/d2k/OpenRA.Mods.D2k.dll d2k:OpenRA.Mods.D2k.dll
./mods/cnc/OpenRA.Mods.Cnc.dll ./mods/cnc/OpenRA.Mods.Cnc.dll
./mods/ts/OpenRA.Mods.TS.dll ./mods/ts/OpenRA.Mods.TS.dll

View File

@@ -3,6 +3,8 @@ Metadata:
Description: Join the Global Defense Initiative or the Brotherhood of Nod in our\nrecreation of the classic game that started it all.\n\nTiberian Dawn modernizes the original Command & Conquer gameplay\nby introducing features from later games, including per-factory\nproduction queues, unit veterancy, and capturable tech structures. Description: Join the Global Defense Initiative or the Brotherhood of Nod in our\nrecreation of the classic game that started it all.\n\nTiberian Dawn modernizes the original Command & Conquer gameplay\nby introducing features from later games, including per-factory\nproduction queues, unit veterancy, and capturable tech structures.
Version: {DEV_VERSION} Version: {DEV_VERSION}
Author: the OpenRA Developers Author: the OpenRA Developers
LogoImagePath: ./mods/cnc/logo.png
PreviewImagePath: ./mods/cnc/preview.png
RequiresMods: RequiresMods:
modchooser: {DEV_VERSION} modchooser: {DEV_VERSION}

View File

@@ -3,96 +3,98 @@ Metadata:
Description: Three great houses fight for the precious spice, melange.\nHe who controls the spice controls the universe!\n\nTry to establish a foothold on the desert planet Arrakis\nwith its harsh environmental conditions and protect your\nharvesting operations from giant sandworms as well as\nruthless enemy factions. Description: Three great houses fight for the precious spice, melange.\nHe who controls the spice controls the universe!\n\nTry to establish a foothold on the desert planet Arrakis\nwith its harsh environmental conditions and protect your\nharvesting operations from giant sandworms as well as\nruthless enemy factions.
Version: {DEV_VERSION} Version: {DEV_VERSION}
Author: the OpenRA Developers Author: the OpenRA Developers
LogoImagePath: d2k:logo.png
PreviewImagePath: d2k:preview.png
RequiresMods: RequiresMods:
modchooser: {DEV_VERSION} modchooser: {DEV_VERSION}
Folders: Folders:
. .
./mods/d2k d2k:
./mods/d2k/bits d2k:bits
./mods/d2k/bits/tex d2k:bits/tex
./mods/d2k/bits/xmas d2k:bits/xmas
./mods/d2k/uibits d2k:uibits
~^Content/d2k ~^Content/d2k
~^Content/d2k/GAMESFX ~^Content/d2k/GAMESFX
~^Content/d2k/Movies ~^Content/d2k/Movies
~^Content/d2k/Music ~^Content/d2k/Music
MapFolders: MapFolders:
./mods/d2k/maps@System d2k:maps@System
~^maps/d2k@User ~^maps/d2k@User
Packages: Packages:
SOUND.RS SOUND.RS
Rules: Rules:
./mods/d2k/rules/misc.yaml d2k:rules/misc.yaml
./mods/d2k/rules/ai.yaml d2k:rules/ai.yaml
./mods/d2k/rules/player.yaml d2k:rules/player.yaml
./mods/d2k/rules/world.yaml d2k:rules/world.yaml
./mods/d2k/rules/palettes.yaml d2k:rules/palettes.yaml
./mods/d2k/rules/defaults.yaml d2k:rules/defaults.yaml
./mods/d2k/rules/vehicles.yaml d2k:rules/vehicles.yaml
./mods/d2k/rules/starport.yaml d2k:rules/starport.yaml
./mods/d2k/rules/husks.yaml d2k:rules/husks.yaml
./mods/d2k/rules/structures.yaml d2k:rules/structures.yaml
./mods/d2k/rules/aircraft.yaml d2k:rules/aircraft.yaml
./mods/d2k/rules/infantry.yaml d2k:rules/infantry.yaml
./mods/d2k/rules/arrakis.yaml d2k:rules/arrakis.yaml
Sequences: Sequences:
./mods/d2k/sequences/aircraft.yaml d2k:sequences/aircraft.yaml
./mods/d2k/sequences/vehicles.yaml d2k:sequences/vehicles.yaml
./mods/d2k/sequences/infantry.yaml d2k:sequences/infantry.yaml
./mods/d2k/sequences/structures.yaml d2k:sequences/structures.yaml
./mods/d2k/sequences/misc.yaml d2k:sequences/misc.yaml
TileSets: TileSets:
./mods/d2k/tilesets/arrakis.yaml d2k:tilesets/arrakis.yaml
MapGrid: MapGrid:
TileSize: 32,32 TileSize: 32,32
Type: Rectangular Type: Rectangular
Cursors: Cursors:
./mods/d2k/cursors.yaml d2k:cursors.yaml
Chrome: Chrome:
./mods/d2k/chrome.yaml d2k:chrome.yaml
Assemblies: Assemblies:
./mods/common/OpenRA.Mods.Common.dll ./mods/common/OpenRA.Mods.Common.dll
./mods/cnc/OpenRA.Mods.Cnc.dll ./mods/cnc/OpenRA.Mods.Cnc.dll
./mods/d2k/OpenRA.Mods.D2k.dll d2k:OpenRA.Mods.D2k.dll
ChromeLayout: ChromeLayout:
./mods/d2k/chrome/ingame.yaml d2k:chrome/ingame.yaml
./mods/ra/chrome/ingame-chat.yaml ./mods/ra/chrome/ingame-chat.yaml
./mods/ra/chrome/ingame-diplomacy.yaml ./mods/ra/chrome/ingame-diplomacy.yaml
./mods/ra/chrome/ingame-fmvplayer.yaml ./mods/ra/chrome/ingame-fmvplayer.yaml
./mods/d2k/chrome/ingame-menu.yaml d2k:chrome/ingame-menu.yaml
./mods/ra/chrome/ingame-info.yaml ./mods/ra/chrome/ingame-info.yaml
./mods/ra/chrome/ingame-infoscripterror.yaml ./mods/ra/chrome/ingame-infoscripterror.yaml
./mods/ra/chrome/ingame-infobriefing.yaml ./mods/ra/chrome/ingame-infobriefing.yaml
./mods/ra/chrome/ingame-infoobjectives.yaml ./mods/ra/chrome/ingame-infoobjectives.yaml
./mods/d2k/chrome/ingame-infostats.yaml d2k:chrome/ingame-infostats.yaml
./mods/d2k/chrome/ingame-observer.yaml d2k:chrome/ingame-observer.yaml
./mods/ra/chrome/ingame-observerstats.yaml ./mods/ra/chrome/ingame-observerstats.yaml
./mods/d2k/chrome/ingame-player.yaml d2k:chrome/ingame-player.yaml
./mods/ra/chrome/ingame-perf.yaml ./mods/ra/chrome/ingame-perf.yaml
./mods/ra/chrome/ingame-debug.yaml ./mods/ra/chrome/ingame-debug.yaml
./mods/d2k/chrome/mainmenu.yaml d2k:chrome/mainmenu.yaml
./mods/ra/chrome/settings.yaml ./mods/ra/chrome/settings.yaml
./mods/ra/chrome/credits.yaml ./mods/ra/chrome/credits.yaml
./mods/ra/chrome/lobby.yaml ./mods/ra/chrome/lobby.yaml
./mods/ra/chrome/lobby-mappreview.yaml ./mods/ra/chrome/lobby-mappreview.yaml
./mods/d2k/chrome/lobby-players.yaml d2k:chrome/lobby-players.yaml
./mods/d2k/chrome/lobby-options.yaml d2k:chrome/lobby-options.yaml
./mods/ra/chrome/lobby-music.yaml ./mods/ra/chrome/lobby-music.yaml
./mods/ra/chrome/lobby-kickdialogs.yaml ./mods/ra/chrome/lobby-kickdialogs.yaml
./mods/ra/chrome/lobby-globalchat.yaml ./mods/ra/chrome/lobby-globalchat.yaml
./mods/d2k/chrome/color-picker.yaml d2k:chrome/color-picker.yaml
./mods/ra/chrome/map-chooser.yaml ./mods/ra/chrome/map-chooser.yaml
./mods/ra/chrome/multiplayer.yaml ./mods/ra/chrome/multiplayer.yaml
./mods/ra/chrome/multiplayer-browser.yaml ./mods/ra/chrome/multiplayer-browser.yaml
@@ -100,33 +102,33 @@ ChromeLayout:
./mods/ra/chrome/multiplayer-directconnect.yaml ./mods/ra/chrome/multiplayer-directconnect.yaml
./mods/ra/chrome/multiplayer-globalchat.yaml ./mods/ra/chrome/multiplayer-globalchat.yaml
./mods/ra/chrome/connection.yaml ./mods/ra/chrome/connection.yaml
./mods/d2k/chrome/dropdowns.yaml d2k:chrome/dropdowns.yaml
./mods/ra/chrome/musicplayer.yaml ./mods/ra/chrome/musicplayer.yaml
./mods/d2k/chrome/tooltips.yaml d2k:chrome/tooltips.yaml
./mods/ra/chrome/assetbrowser.yaml ./mods/ra/chrome/assetbrowser.yaml
./mods/d2k/chrome/missionbrowser.yaml d2k:chrome/missionbrowser.yaml
./mods/ra/chrome/confirmation-dialogs.yaml ./mods/ra/chrome/confirmation-dialogs.yaml
./mods/ra/chrome/editor.yaml ./mods/ra/chrome/editor.yaml
./mods/ra/chrome/replaybrowser.yaml ./mods/ra/chrome/replaybrowser.yaml
Weapons: Weapons:
./mods/d2k/weapons.yaml d2k:weapons.yaml
./mods/d2k/weapons/debris.yaml d2k:weapons/debris.yaml
Voices: Voices:
./mods/d2k/audio/voices.yaml d2k:audio/voices.yaml
Notifications: Notifications:
./mods/d2k/audio/notifications.yaml d2k:audio/notifications.yaml
Music: Music:
./mods/d2k/audio/music.yaml d2k:audio/music.yaml
Translations: Translations:
./mods/d2k/languages/english.yaml d2k:languages/english.yaml
LoadScreen: LogoStripeLoadScreen LoadScreen: LogoStripeLoadScreen
Image: ./mods/d2k/uibits/loadscreen.png Image: d2k:uibits/loadscreen.png
Text: Filling Crates..., Breeding Sandworms..., Fuelling carryalls..., Deploying harvesters..., Preparing 'thopters..., Summoning mentats... Text: Filling Crates..., Breeding Sandworms..., Fuelling carryalls..., Deploying harvesters..., Preparing 'thopters..., Summoning mentats...
ContentInstaller: ContentInstaller:
@@ -161,7 +163,7 @@ LobbyDefaults:
TechLevel: Unrestricted TechLevel: Unrestricted
ChromeMetrics: ChromeMetrics:
./mods/d2k/metrics.yaml d2k:metrics.yaml
Fonts: Fonts:
Regular: Regular:
@@ -171,7 +173,7 @@ Fonts:
Font:./mods/common/FreeSansBold.ttf Font:./mods/common/FreeSansBold.ttf
Size:14 Size:14
Title: Title:
Font:./mods/d2k/Dune2k.ttf Font:d2k:Dune2k.ttf
Size:32 Size:32
MediumBold: MediumBold:
Font:./mods/common/FreeSansBold.ttf Font:./mods/common/FreeSansBold.ttf
@@ -190,7 +192,7 @@ Fonts:
Size:10 Size:10
Missions: Missions:
./mods/d2k/missions.yaml d2k:missions.yaml
SupportsMapsFrom: d2k SupportsMapsFrom: d2k

View File

@@ -3,6 +3,8 @@ Metadata:
Description: In a world where Hitler was assassinated and the Third Reich never\nexisted, the Soviet Union seeks power over all of Europe. Allied\nagainst this Evil Empire, the free world faces a Cold War turned hot.\n\nRed Alert fuses the quick and fun gameplay of the original\nC&C: Red Alert, with balance improvements and new gameplay\nfeatures inspired by modern RTS games. Description: In a world where Hitler was assassinated and the Third Reich never\nexisted, the Soviet Union seeks power over all of Europe. Allied\nagainst this Evil Empire, the free world faces a Cold War turned hot.\n\nRed Alert fuses the quick and fun gameplay of the original\nC&C: Red Alert, with balance improvements and new gameplay\nfeatures inspired by modern RTS games.
Version: {DEV_VERSION} Version: {DEV_VERSION}
Author: the OpenRA Developers Author: the OpenRA Developers
LogoImagePath: ./mods/ra/logo.png
PreviewImagePath: ./mods/ra/preview.png
RequiresMods: RequiresMods:
modchooser: {DEV_VERSION} modchooser: {DEV_VERSION}

View File

@@ -3,6 +3,8 @@ Metadata:
Description: Developer stub, not yet ready for release! Description: Developer stub, not yet ready for release!
Version: {DEV_VERSION} Version: {DEV_VERSION}
Author: the OpenRA Developers Author: the OpenRA Developers
LogoImagePath: ./mods/ts/logo.png
PreviewImagePath: ./mods/ts/preview.png
RequiresMods: RequiresMods:
modchooser: {DEV_VERSION} modchooser: {DEV_VERSION}
@@ -142,7 +144,7 @@ ChromeLayout:
./mods/ra/chrome/ingame-infobriefing.yaml ./mods/ra/chrome/ingame-infobriefing.yaml
./mods/ra/chrome/ingame-infoobjectives.yaml ./mods/ra/chrome/ingame-infoobjectives.yaml
./mods/ra/chrome/ingame-infostats.yaml ./mods/ra/chrome/ingame-infostats.yaml
./mods/d2k/chrome/ingame-observer.yaml d2k:chrome/ingame-observer.yaml
./mods/ts/chrome/ingame-observerstats.yaml ./mods/ts/chrome/ingame-observerstats.yaml
./mods/ts/chrome/ingame-player.yaml ./mods/ts/chrome/ingame-player.yaml
./mods/ra/chrome/ingame-perf.yaml ./mods/ra/chrome/ingame-perf.yaml