mod manifest loading

This commit is contained in:
Chris Forbes
2010-01-20 21:48:47 +13:00
parent 06b9c0dcf5
commit 19ff382b7f
30 changed files with 160 additions and 61 deletions

View File

@@ -347,8 +347,36 @@ namespace OpenRA.Server
SyncLobbyInfo(); SyncLobbyInfo();
return true; return true;
}}, }},
{ "addmod", { "addpkg",
s => s =>
{
if (GameStarted)
{
DispatchOrdersToClient(conn, 0,
new ServerOrder( conn.PlayerIndex, "Chat",
"You can't change packages after the game has started" ).Serialize() );
}
Console.WriteLine("** Added package: `{0}`", s);
try
{
lobbyInfo.GlobalSettings.Packages =
lobbyInfo.GlobalSettings.Packages.Concat( new string[] {
MakePackageString(s)}).ToArray();
SyncLobbyInfo();
return true;
}
catch
{
Console.WriteLine("That went horribly wrong.");
DispatchOrdersToClient(conn, 0,
new ServerOrder( conn.PlayerIndex, "Chat",
"Adding the package failed." ).Serialize() );
return true;
}
}},
{ "addmod",
s =>
{ {
if (GameStarted) if (GameStarted)
{ {
@@ -360,9 +388,8 @@ namespace OpenRA.Server
Console.WriteLine("** Added mod: `{0}`", s); Console.WriteLine("** Added mod: `{0}`", s);
try try
{ {
lobbyInfo.GlobalSettings.Packages = lobbyInfo.GlobalSettings.Mods =
lobbyInfo.GlobalSettings.Packages.Concat( new string[] { lobbyInfo.GlobalSettings.Mods.Concat( new[] { s } ).ToArray();
MakePackageString(s)}).ToArray();
SyncLobbyInfo(); SyncLobbyInfo();
return true; return true;
} }

View File

@@ -31,7 +31,32 @@ namespace OpenRa.FileFormats
{ {
public string Map = "scm12ea.ini"; public string Map = "scm12ea.ini";
public string[] Packages = {}; // filename:sha1 pairs. public string[] Packages = {}; // filename:sha1 pairs.
public string[] Mods = { "ra" }; // mod names
public int OrderLatency = 3; public int OrderLatency = 3;
} }
} }
public class Manifest
{
public readonly string[] Packages = { };
public readonly string[] LegacyRules = { };
public readonly string[] Rules = { };
public readonly string[] Sequences = { };
public readonly string[] Assemblies = { };
public Manifest(string[] mods)
{
var yaml = mods
.Select(m => MiniYaml.FromFile("mods/" + m + "/mod.yaml"))
.Aggregate(MiniYaml.Merge);
Packages = YamlList(yaml, "Packages");
LegacyRules = YamlList(yaml, "LegacyRules");
Rules = YamlList(yaml, "Rules");
Sequences = YamlList(yaml, "Sequences");
Assemblies = YamlList(yaml, "Assemblies");
}
static string[] YamlList(Dictionary<string, MiniYaml> ys, string key) { return ys[key].Nodes.Keys.ToArray(); }
}
} }

View File

@@ -32,7 +32,7 @@ namespace OpenRa
if (name != null) if (name != null)
{ {
Info = Rules.ActorInfo[name.ToLowerInvariant()]; Info = Rules.Info[name.ToLowerInvariant()];
Health = this.GetMaxHP(); Health = this.GetMaxHP();
foreach (var trait in Info.Traits.WithInterface<ITraitInfo>()) foreach (var trait in Info.Traits.WithInterface<ITraitInfo>())

View File

@@ -111,7 +111,7 @@ namespace OpenRa
panelSprites = Graphics.Util.MakeArray(8, panelSprites = Graphics.Util.MakeArray(8,
n => ChromeProvider.GetImage(renderer, "panel", n.ToString())); n => ChromeProvider.GetImage(renderer, "panel", n.ToString()));
tabSprites = Rules.ActorInfo.Values tabSprites = Rules.Info.Values
.Where(u => u.Traits.Contains<BuildableInfo>()) .Where(u => u.Traits.Contains<BuildableInfo>())
.ToDictionary( .ToDictionary(
u => u.Name, u => u.Name,
@@ -122,7 +122,7 @@ namespace OpenRa
u => u.Key, u => u.Key,
u => SpriteSheetBuilder.LoadAllSprites(u.Value.Image)[0]); u => SpriteSheetBuilder.LoadAllSprites(u.Value.Image)[0]);
var groups = Rules.ActorInfo.Values.Select( x => x.Category ).Distinct().Where( g => g != null ).ToList(); var groups = Rules.Info.Values.Select( x => x.Category ).Distinct().Where( g => g != null ).ToList();
tabImageNames = groups.Select( tabImageNames = groups.Select(
(g, i) => Pair.New(g, (g, i) => Pair.New(g,
@@ -758,7 +758,7 @@ namespace OpenRa
void StartProduction( string item ) void StartProduction( string item )
{ {
var unit = Rules.ActorInfo[item]; var unit = Rules.Info[item];
Sound.Play(unit.Traits.Contains<BuildingInfo>() ? "abldgin1.aud" : "train1.aud"); Sound.Play(unit.Traits.Contains<BuildingInfo>() ? "abldgin1.aud" : "train1.aud");
Game.controller.AddOrder(Order.StartProduction(Game.LocalPlayer, item)); Game.controller.AddOrder(Order.StartProduction(Game.LocalPlayer, item));
} }
@@ -766,7 +766,7 @@ namespace OpenRa
void HandleBuildPalette(string item, bool isLmb) void HandleBuildPalette(string item, bool isLmb)
{ {
var player = Game.LocalPlayer; var player = Game.LocalPlayer;
var unit = Rules.ActorInfo[item]; var unit = Rules.Info[item];
var queue = player.PlayerActor.traits.Get<Traits.ProductionQueue>(); var queue = player.PlayerActor.traits.Get<Traits.ProductionQueue>();
var producing = queue.AllItems(unit.Category).FirstOrDefault( a => a.Item == item ); var producing = queue.AllItems(unit.Category).FirstOrDefault( a => a.Item == item );
@@ -851,7 +851,7 @@ namespace OpenRa
rgbaRenderer.DrawSprite(tooltipSprite, p, PaletteType.Chrome); rgbaRenderer.DrawSprite(tooltipSprite, p, PaletteType.Chrome);
rgbaRenderer.Flush(); rgbaRenderer.Flush();
var info = Rules.ActorInfo[unit]; var info = Rules.Info[unit];
var buildable = info.Traits.Get<BuildableInfo>(); var buildable = info.Traits.Get<BuildableInfo>();
renderer.DrawText2(buildable.Description, p.ToInt2() + new int2(5,5), Color.White); renderer.DrawText2(buildable.Description, p.ToInt2() + new int2(5,5), Color.White);
@@ -888,7 +888,7 @@ namespace OpenRa
if( a[ 0 ] == '@' ) if( a[ 0 ] == '@' )
return "any " + a.Substring( 1 ); return "any " + a.Substring( 1 );
else else
return Rules.ActorInfo[ a.ToLowerInvariant() ].Traits.Get<BuildableInfo>().Description; return Rules.Info[ a.ToLowerInvariant() ].Traits.Get<BuildableInfo>().Description;
} }
void DrawSupportPowers() void DrawSupportPowers()

View File

@@ -50,13 +50,19 @@ namespace OpenRa
public static void ChangeMap(string mapName) public static void ChangeMap(string mapName)
{ {
var manifest = new Manifest(LobbyInfo.GlobalSettings.Mods);
chat.AddLine(Color.White, "Debug", "Map change {0} -> {1}".F(Game.mapName, mapName)); chat.AddLine(Color.White, "Debug", "Map change {0} -> {1}".F(Game.mapName, mapName));
Game.changePending = false; Game.changePending = false;
Game.mapName = mapName; Game.mapName = mapName;
SheetBuilder.Initialize(renderer); SheetBuilder.Initialize(renderer);
SpriteSheetBuilder.Initialize(); SpriteSheetBuilder.Initialize();
FileSystem.UnmountTemporaryPackages(); FileSystem.UnmountTemporaryPackages();
Rules.LoadRules(mapName, usingAftermath);
foreach (var pkg in manifest.Packages)
FileSystem.MountTemporary(new Package(pkg));
Rules.LoadRules(mapName, manifest);
world = null; // trying to access the old world will NRE, rather than silently doing it wrong. world = null; // trying to access the old world will NRE, rather than silently doing it wrong.
world = new World(); world = new World();
@@ -75,11 +81,7 @@ namespace OpenRa
players[i] = new Player(i, LobbyInfo.Clients.FirstOrDefault(a => a.Index == i)); players[i] = new Player(i, LobbyInfo.Clients.FirstOrDefault(a => a.Index == i));
} }
var sequenceFiles = usingAftermath SequenceProvider.Initialize(manifest.Sequences);
? new[] { "sequences.xml", "sequences-aftermath.xml" }
: new[] { "sequences.xml" };
SequenceProvider.Initialize(sequenceFiles);
viewport = new Viewport(clientSize, Game.world.Map.Offset, Game.world.Map.Offset + Game.world.Map.Size, renderer); viewport = new Viewport(clientSize, Game.world.Map.Offset, Game.world.Map.Offset + Game.world.Map.Size, renderer);
skipMakeAnims = true; skipMakeAnims = true;

View File

@@ -52,13 +52,19 @@ namespace OpenRa.GameRules
return node; return node;
} }
// todo: use mod metadata to do this static Pair<Assembly, string>[] ModAssemblies;
static Pair<Assembly, string>[] ModAssemblies = public static void LoadModAssemblies(Manifest m)
{ {
Pair.New( typeof(ITraitInfo).Assembly, typeof(ITraitInfo).Namespace ), var asms = new List<Pair<Assembly, string>>();
Pair.New( Assembly.LoadFile(Path.GetFullPath(@"mods\ra\OpenRa.Mods.RA.dll")), "OpenRa.Mods.RA" ),
Pair.New( Assembly.LoadFile(Path.GetFullPath(@"mods\aftermath\OpenRa.Mods.Aftermath.dll")), "OpenRa.Mods.Aftermath" ) // all the core stuff is in this assembly
}; asms.Add(Pair.New(typeof(ITraitInfo).Assembly, typeof(ITraitInfo).Namespace));
// add the mods
foreach (var a in m.Assemblies)
asms.Add(Pair.New(Assembly.LoadFile(Path.GetFullPath(a)), Path.GetFileNameWithoutExtension(a)));
ModAssemblies = asms.ToArray();
}
static ITraitInfo LoadTraitInfo(string traitName, MiniYaml my) static ITraitInfo LoadTraitInfo(string traitName, MiniYaml my)
{ {

View File

@@ -20,28 +20,20 @@ namespace OpenRa
public static AftermathInfo Aftermath; public static AftermathInfo Aftermath;
public static TechTree TechTree; public static TechTree TechTree;
public static Dictionary<string, ActorInfo> ActorInfo; public static Dictionary<string, ActorInfo> Info;
public static void LoadRules(string mapFileName, bool useAftermath) public static void LoadRules(string map, Manifest m)
{ {
if (useAftermath) var legacyRules = m.LegacyRules.Reverse().ToList();
AllRules = new IniFile( legacyRules.Insert(0, map);
FileSystem.Open(mapFileName), AllRules = new IniFile(legacyRules.Select(a => FileSystem.Open(a)).ToArray());
FileSystem.Open("aftermathUnits.ini"),
FileSystem.Open("units.ini"),
FileSystem.Open("aftrmath.ini"),
FileSystem.Open("rules.ini"));
else
AllRules = new IniFile(
FileSystem.Open(mapFileName),
FileSystem.Open("units.ini"),
FileSystem.Open("rules.ini"));
General = new GeneralInfo(); General = new GeneralInfo();
FieldLoader.Load(General, AllRules.GetSection("General")); FieldLoader.Load(General, AllRules.GetSection("General"));
// dirty hack. all of this needs to either die or go to traitinfos
Aftermath = new AftermathInfo(); Aftermath = new AftermathInfo();
if (useAftermath) if (AllRules.GetSection("Aftermath", true).Count() > 0)
FieldLoader.Load(Aftermath, AllRules.GetSection("Aftermath")); FieldLoader.Load(Aftermath, AllRules.GetSection("Aftermath"));
LoadCategories( LoadCategories(
@@ -62,15 +54,12 @@ namespace OpenRa
SupportPowerInfo = new InfoLoader<SupportPowerInfo>( SupportPowerInfo = new InfoLoader<SupportPowerInfo>(
Pair.New<string, Func<string, SupportPowerInfo>>("SupportPower", _ => new SupportPowerInfo())); Pair.New<string, Func<string, SupportPowerInfo>>("SupportPower", _ => new SupportPowerInfo()));
var yamlRules = MiniYaml.Merge( MiniYaml.FromFile( "ra.yaml" ), MiniYaml.FromFile( "defaults.yaml" ) ); var yamlRules = m.Rules.Reverse().Select(a => MiniYaml.FromFile(a)).Aggregate(MiniYaml.Merge);
if( useAftermath )
yamlRules = MiniYaml.Merge( MiniYaml.FromFile( "aftermath.yaml" ), yamlRules );
yamlRules = MiniYaml.Merge( MiniYaml.FromFile( "[mod]Separate buildqueue for defense.yaml" ), yamlRules ); ActorInfo.LoadModAssemblies(m);
Info = new Dictionary<string, ActorInfo>();
ActorInfo = new Dictionary<string, ActorInfo>();
foreach( var kv in yamlRules ) foreach( var kv in yamlRules )
ActorInfo.Add(kv.Key.ToLowerInvariant(), new ActorInfo(kv.Key.ToLowerInvariant(), kv.Value, yamlRules)); Info.Add(kv.Key.ToLowerInvariant(), new ActorInfo(kv.Key.ToLowerInvariant(), kv.Value, yamlRules));
TechTree = new TechTree(); TechTree = new TechTree();
} }

View File

@@ -11,7 +11,7 @@ namespace OpenRa.GameRules
public TechTree() public TechTree()
{ {
foreach( var info in Rules.ActorInfo.Values ) foreach( var info in Rules.Info.Values )
{ {
var pi = info.Traits.GetOrDefault<ProductionInfo>(); var pi = info.Traits.GetOrDefault<ProductionInfo>();
if (pi != null) if (pi != null)
@@ -62,7 +62,7 @@ namespace OpenRa.GameRules
public IEnumerable<ActorInfo> AllBuildables(Player player, params string[] categories) public IEnumerable<ActorInfo> AllBuildables(Player player, params string[] categories)
{ {
return Rules.ActorInfo.Values return Rules.Info.Values
.Where( x => x.Name[ 0 ] != '^' ) .Where( x => x.Name[ 0 ] != '^' )
.Where( x => categories.Contains( x.Category ) ) .Where( x => categories.Contains( x.Category ) )
.Where( x => x.Traits.Contains<BuildableInfo>() ); .Where( x => x.Traits.Contains<BuildableInfo>() );
@@ -72,7 +72,7 @@ namespace OpenRa.GameRules
{ {
var builtAt = info.Traits.Get<BuildableInfo>().BuiltAt; var builtAt = info.Traits.Get<BuildableInfo>().BuiltAt;
if( builtAt.Length != 0 ) if( builtAt.Length != 0 )
return builtAt.Select( x => Rules.ActorInfo[ x.ToLowerInvariant() ] ); return builtAt.Select( x => Rules.Info[ x.ToLowerInvariant() ] );
else else
return producesIndex[ info.Category ]; return producesIndex[ info.Category ];
} }

View File

@@ -8,7 +8,7 @@ namespace OpenRa.Orders
{ {
readonly Actor Producer; readonly Actor Producer;
readonly string Building; readonly string Building;
BuildingInfo BuildingInfo { get { return Rules.ActorInfo[ Building ].Traits.Get<BuildingInfo>(); } } BuildingInfo BuildingInfo { get { return Rules.Info[ Building ].Traits.Get<BuildingInfo>(); } }
public PlaceBuildingOrderGenerator(Actor producer, string name) public PlaceBuildingOrderGenerator(Actor producer, string name)
{ {
@@ -42,7 +42,7 @@ namespace OpenRa.Orders
public void Tick() public void Tick()
{ {
var producing = Producer.traits.Get<Traits.ProductionQueue>().CurrentItem( Rules.ActorInfo[ Building ].Category ); var producing = Producer.traits.Get<Traits.ProductionQueue>().CurrentItem( Rules.Info[ Building ].Category );
if (producing == null || producing.Item != Building || producing.RemainingTime != 0) if (producing == null || producing.Item != Building || producing.RemainingTime != 0)
Game.controller.CancelInputMode(); Game.controller.CancelInputMode();
} }

View File

@@ -68,7 +68,7 @@ namespace OpenRa.Orders
else else
return Cursor.MoveBlocked; return Cursor.MoveBlocked;
case "DeployMcv": case "DeployMcv":
var factBuildingInfo = Rules.ActorInfo["fact"].Traits.Get<BuildingInfo>(); var factBuildingInfo = Rules.Info["fact"].Traits.Get<BuildingInfo>();
if (Game.world.CanPlaceBuilding("fact", factBuildingInfo, a.Location - new int2(1, 1), a)) if (Game.world.CanPlaceBuilding("fact", factBuildingInfo, a.Location - new int2(1, 1), a))
return Cursor.Deploy; return Cursor.Deploy;
else else

View File

@@ -50,7 +50,7 @@ namespace OpenRa
var buildings = Rules.TechTree.GatherBuildings(Owner); var buildings = Rules.TechTree.GatherBuildings(Owner);
var effectivePrereq = Info.Prerequisite var effectivePrereq = Info.Prerequisite
.Select( a => a.ToLowerInvariant() ) .Select( a => a.ToLowerInvariant() )
.Where( a => Rules.ActorInfo[a].Traits.Get<BuildableInfo>().Owner.Contains( Owner.Race )); .Where( a => Rules.Info[a].Traits.Get<BuildableInfo>().Owner.Contains( Owner.Race ));
IsAvailable = Info.TechLevel > -1 IsAvailable = Info.TechLevel > -1
&& effectivePrereq.Any() && effectivePrereq.Any()

View File

@@ -24,7 +24,7 @@ namespace OpenRa.Traits
{ {
if( order.OrderString == "DeployMcv" ) if( order.OrderString == "DeployMcv" )
{ {
var factBuildingInfo = Rules.ActorInfo[ "fact" ].Traits.Get<BuildingInfo>(); var factBuildingInfo = Rules.Info[ "fact" ].Traits.Get<BuildingInfo>();
if( Game.world.CanPlaceBuilding( "fact", factBuildingInfo, self.Location - new int2( 1, 1 ), self ) ) if( Game.world.CanPlaceBuilding( "fact", factBuildingInfo, self.Location - new int2( 1, 1 ), self ) )
{ {
self.CancelActivity(); self.CancelActivity();

View File

@@ -17,7 +17,7 @@ namespace OpenRa.Traits
Game.world.AddFrameEndTask( _ => Game.world.AddFrameEndTask( _ =>
{ {
var queue = self.traits.Get<ProductionQueue>(); var queue = self.traits.Get<ProductionQueue>();
var unit = Rules.ActorInfo[ order.TargetString ]; var unit = Rules.Info[ order.TargetString ];
var producing = queue.CurrentItem(unit.Category); var producing = queue.CurrentItem(unit.Category);
if( producing == null || producing.Item != order.TargetString || producing.RemainingTime != 0 ) if( producing == null || producing.Item != order.TargetString || producing.RemainingTime != 0 )
return; return;

View File

@@ -33,7 +33,7 @@ namespace OpenRa.Traits
{ {
case "StartProduction": case "StartProduction":
{ {
var unit = Rules.ActorInfo[ order.TargetString ]; var unit = Rules.Info[ order.TargetString ];
var ui = unit.Traits.Get<BuildableInfo>(); var ui = unit.Traits.Get<BuildableInfo>();
var time = ui.Cost var time = ui.Cost
* Rules.General.BuildSpeed /* todo: country-specific build speed bonus */ * Rules.General.BuildSpeed /* todo: country-specific build speed bonus */
@@ -65,7 +65,7 @@ namespace OpenRa.Traits
} }
case "PauseProduction": case "PauseProduction":
{ {
var producing = CurrentItem( Rules.ActorInfo[ order.TargetString ].Category ); var producing = CurrentItem( Rules.Info[ order.TargetString ].Category );
if( producing != null && producing.Item == order.TargetString ) if( producing != null && producing.Item == order.TargetString )
producing.Paused = ( order.TargetLocation.X != 0 ); producing.Paused = ( order.TargetLocation.X != 0 );
break; break;
@@ -95,7 +95,7 @@ namespace OpenRa.Traits
public void CancelProduction( string itemName ) public void CancelProduction( string itemName )
{ {
var category = Rules.ActorInfo[itemName].Category; var category = Rules.Info[itemName].Category;
var queue = production[ category ]; var queue = production[ category ];
if (queue.Count == 0) return; if (queue.Count == 0) return;
@@ -126,7 +126,7 @@ namespace OpenRa.Traits
public void BuildUnit( string name ) public void BuildUnit( string name )
{ {
var newUnitType = Rules.ActorInfo[ name ]; var newUnitType = Rules.Info[ name ];
var producerTypes = Rules.TechTree.UnitBuiltAt( newUnitType ); var producerTypes = Rules.TechTree.UnitBuiltAt( newUnitType );
Actor producer = null; Actor producer = null;

View File

0
aftrmath.ini → mods/aftermath/aftrmath.ini Executable file → Normal file
View File

17
mods/aftermath/mod.yaml Normal file
View File

@@ -0,0 +1,17 @@
# Red Alert: The Aftermath -- Package Manifest
# Requires classic RA mod
Packages:
LegacyRules:
mods/aftermath/aftrmath.ini: More or less original Aftermath rules file.
mods/aftermath/aftrmathUnits.ini: OpenRA patches
Rules:
mods/aftermath/rules.yaml: OpenRA actorinfos
Sequences:
mods/aftermath/sequences.xml: Additional aftermath
Assemblies:
mods/aftermath/OpenRa.Mods.Aftermath.dll: Traits used

12
mods/ra-ng/mod.yaml Normal file
View File

@@ -0,0 +1,12 @@
# Red Alert: Next Generation - Rules Manifest
Packages:
LegacyRules:
Rules:
mods/ra-ng/defense-queue.yaml
Sequences:
Assemblies:

0
campaignUnits.ini → mods/ra/campaignUnits.ini Executable file → Normal file
View File

17
mods/ra/mod.yaml Normal file
View File

@@ -0,0 +1,17 @@
# Classic Red Alert Mod -- Package Manifest
Packages:
LegacyRules:
mods/ra/rules.ini: More or less original Red Alert rules file.
mods/ra/units.ini: OpenRA patches
Rules:
mods/ra/defaults.yaml: Basic stuff
mods/ra/rules.yaml: OpenRA actorinfos
Sequences:
mods/ra/sequences.xml: Original animation sequences
Assemblies:
mods/ra/OpenRa.Mods.RA.dll: Traits used

View File

@@ -1,2 +1,6 @@
RulesConverter\bin\debug\RulesConverter.exe units.ini rules.ini trees.ini campaignUnits.ini ra.yaml pushd mods\ra\
RulesConverter\bin\debug\RulesConverter.exe aftermathUnits.ini aftrmath.ini aftermath.yaml ..\..\RulesConverter\bin\debug\RulesConverter.exe units.ini rules.ini trees.ini campaignUnits.ini rules.yaml
popd
pushd mods\aftermath\
RulesConverter\bin\debug\RulesConverter.exe aftermathUnits.ini aftrmath.ini rules.yaml
popd