mod manifest loading
This commit is contained in:
@@ -347,6 +347,34 @@ namespace OpenRA.Server
|
||||
SyncLobbyInfo();
|
||||
return true;
|
||||
}},
|
||||
{ "addpkg",
|
||||
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 =>
|
||||
{
|
||||
@@ -360,9 +388,8 @@ namespace OpenRA.Server
|
||||
Console.WriteLine("** Added mod: `{0}`", s);
|
||||
try
|
||||
{
|
||||
lobbyInfo.GlobalSettings.Packages =
|
||||
lobbyInfo.GlobalSettings.Packages.Concat( new string[] {
|
||||
MakePackageString(s)}).ToArray();
|
||||
lobbyInfo.GlobalSettings.Mods =
|
||||
lobbyInfo.GlobalSettings.Mods.Concat( new[] { s } ).ToArray();
|
||||
SyncLobbyInfo();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,32 @@ namespace OpenRa.FileFormats
|
||||
{
|
||||
public string Map = "scm12ea.ini";
|
||||
public string[] Packages = {}; // filename:sha1 pairs.
|
||||
public string[] Mods = { "ra" }; // mod names
|
||||
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(); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace OpenRa
|
||||
|
||||
if (name != null)
|
||||
{
|
||||
Info = Rules.ActorInfo[name.ToLowerInvariant()];
|
||||
Info = Rules.Info[name.ToLowerInvariant()];
|
||||
Health = this.GetMaxHP();
|
||||
|
||||
foreach (var trait in Info.Traits.WithInterface<ITraitInfo>())
|
||||
|
||||
@@ -111,7 +111,7 @@ namespace OpenRa
|
||||
panelSprites = Graphics.Util.MakeArray(8,
|
||||
n => ChromeProvider.GetImage(renderer, "panel", n.ToString()));
|
||||
|
||||
tabSprites = Rules.ActorInfo.Values
|
||||
tabSprites = Rules.Info.Values
|
||||
.Where(u => u.Traits.Contains<BuildableInfo>())
|
||||
.ToDictionary(
|
||||
u => u.Name,
|
||||
@@ -122,7 +122,7 @@ namespace OpenRa
|
||||
u => u.Key,
|
||||
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(
|
||||
(g, i) => Pair.New(g,
|
||||
@@ -758,7 +758,7 @@ namespace OpenRa
|
||||
|
||||
void StartProduction( string item )
|
||||
{
|
||||
var unit = Rules.ActorInfo[item];
|
||||
var unit = Rules.Info[item];
|
||||
Sound.Play(unit.Traits.Contains<BuildingInfo>() ? "abldgin1.aud" : "train1.aud");
|
||||
Game.controller.AddOrder(Order.StartProduction(Game.LocalPlayer, item));
|
||||
}
|
||||
@@ -766,7 +766,7 @@ namespace OpenRa
|
||||
void HandleBuildPalette(string item, bool isLmb)
|
||||
{
|
||||
var player = Game.LocalPlayer;
|
||||
var unit = Rules.ActorInfo[item];
|
||||
var unit = Rules.Info[item];
|
||||
var queue = player.PlayerActor.traits.Get<Traits.ProductionQueue>();
|
||||
var producing = queue.AllItems(unit.Category).FirstOrDefault( a => a.Item == item );
|
||||
|
||||
@@ -851,7 +851,7 @@ namespace OpenRa
|
||||
rgbaRenderer.DrawSprite(tooltipSprite, p, PaletteType.Chrome);
|
||||
rgbaRenderer.Flush();
|
||||
|
||||
var info = Rules.ActorInfo[unit];
|
||||
var info = Rules.Info[unit];
|
||||
var buildable = info.Traits.Get<BuildableInfo>();
|
||||
|
||||
renderer.DrawText2(buildable.Description, p.ToInt2() + new int2(5,5), Color.White);
|
||||
@@ -888,7 +888,7 @@ namespace OpenRa
|
||||
if( a[ 0 ] == '@' )
|
||||
return "any " + a.Substring( 1 );
|
||||
else
|
||||
return Rules.ActorInfo[ a.ToLowerInvariant() ].Traits.Get<BuildableInfo>().Description;
|
||||
return Rules.Info[ a.ToLowerInvariant() ].Traits.Get<BuildableInfo>().Description;
|
||||
}
|
||||
|
||||
void DrawSupportPowers()
|
||||
|
||||
@@ -50,13 +50,19 @@ namespace OpenRa
|
||||
|
||||
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));
|
||||
Game.changePending = false;
|
||||
Game.mapName = mapName;
|
||||
SheetBuilder.Initialize(renderer);
|
||||
SpriteSheetBuilder.Initialize();
|
||||
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 = new World();
|
||||
@@ -75,11 +81,7 @@ namespace OpenRa
|
||||
players[i] = new Player(i, LobbyInfo.Clients.FirstOrDefault(a => a.Index == i));
|
||||
}
|
||||
|
||||
var sequenceFiles = usingAftermath
|
||||
? new[] { "sequences.xml", "sequences-aftermath.xml" }
|
||||
: new[] { "sequences.xml" };
|
||||
|
||||
SequenceProvider.Initialize(sequenceFiles);
|
||||
SequenceProvider.Initialize(manifest.Sequences);
|
||||
viewport = new Viewport(clientSize, Game.world.Map.Offset, Game.world.Map.Offset + Game.world.Map.Size, renderer);
|
||||
|
||||
skipMakeAnims = true;
|
||||
|
||||
@@ -52,13 +52,19 @@ namespace OpenRa.GameRules
|
||||
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 ),
|
||||
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" )
|
||||
};
|
||||
var asms = new List<Pair<Assembly, string>>();
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
||||
@@ -20,28 +20,20 @@ namespace OpenRa
|
||||
public static AftermathInfo Aftermath;
|
||||
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)
|
||||
AllRules = new IniFile(
|
||||
FileSystem.Open(mapFileName),
|
||||
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"));
|
||||
var legacyRules = m.LegacyRules.Reverse().ToList();
|
||||
legacyRules.Insert(0, map);
|
||||
AllRules = new IniFile(legacyRules.Select(a => FileSystem.Open(a)).ToArray());
|
||||
|
||||
General = new GeneralInfo();
|
||||
FieldLoader.Load(General, AllRules.GetSection("General"));
|
||||
|
||||
// dirty hack. all of this needs to either die or go to traitinfos
|
||||
Aftermath = new AftermathInfo();
|
||||
if (useAftermath)
|
||||
if (AllRules.GetSection("Aftermath", true).Count() > 0)
|
||||
FieldLoader.Load(Aftermath, AllRules.GetSection("Aftermath"));
|
||||
|
||||
LoadCategories(
|
||||
@@ -62,15 +54,12 @@ namespace OpenRa
|
||||
SupportPowerInfo = new InfoLoader<SupportPowerInfo>(
|
||||
Pair.New<string, Func<string, SupportPowerInfo>>("SupportPower", _ => new SupportPowerInfo()));
|
||||
|
||||
var yamlRules = MiniYaml.Merge( MiniYaml.FromFile( "ra.yaml" ), MiniYaml.FromFile( "defaults.yaml" ) );
|
||||
if( useAftermath )
|
||||
yamlRules = MiniYaml.Merge( MiniYaml.FromFile( "aftermath.yaml" ), yamlRules );
|
||||
var yamlRules = m.Rules.Reverse().Select(a => MiniYaml.FromFile(a)).Aggregate(MiniYaml.Merge);
|
||||
|
||||
yamlRules = MiniYaml.Merge( MiniYaml.FromFile( "[mod]Separate buildqueue for defense.yaml" ), yamlRules );
|
||||
|
||||
ActorInfo = new Dictionary<string, ActorInfo>();
|
||||
ActorInfo.LoadModAssemblies(m);
|
||||
Info = new Dictionary<string, ActorInfo>();
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace OpenRa.GameRules
|
||||
|
||||
public TechTree()
|
||||
{
|
||||
foreach( var info in Rules.ActorInfo.Values )
|
||||
foreach( var info in Rules.Info.Values )
|
||||
{
|
||||
var pi = info.Traits.GetOrDefault<ProductionInfo>();
|
||||
if (pi != null)
|
||||
@@ -62,7 +62,7 @@ namespace OpenRa.GameRules
|
||||
|
||||
public IEnumerable<ActorInfo> AllBuildables(Player player, params string[] categories)
|
||||
{
|
||||
return Rules.ActorInfo.Values
|
||||
return Rules.Info.Values
|
||||
.Where( x => x.Name[ 0 ] != '^' )
|
||||
.Where( x => categories.Contains( x.Category ) )
|
||||
.Where( x => x.Traits.Contains<BuildableInfo>() );
|
||||
@@ -72,7 +72,7 @@ namespace OpenRa.GameRules
|
||||
{
|
||||
var builtAt = info.Traits.Get<BuildableInfo>().BuiltAt;
|
||||
if( builtAt.Length != 0 )
|
||||
return builtAt.Select( x => Rules.ActorInfo[ x.ToLowerInvariant() ] );
|
||||
return builtAt.Select( x => Rules.Info[ x.ToLowerInvariant() ] );
|
||||
else
|
||||
return producesIndex[ info.Category ];
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace OpenRa.Orders
|
||||
{
|
||||
readonly Actor Producer;
|
||||
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)
|
||||
{
|
||||
@@ -42,7 +42,7 @@ namespace OpenRa.Orders
|
||||
|
||||
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)
|
||||
Game.controller.CancelInputMode();
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace OpenRa.Orders
|
||||
else
|
||||
return Cursor.MoveBlocked;
|
||||
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))
|
||||
return Cursor.Deploy;
|
||||
else
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace OpenRa
|
||||
var buildings = Rules.TechTree.GatherBuildings(Owner);
|
||||
var effectivePrereq = Info.Prerequisite
|
||||
.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
|
||||
&& effectivePrereq.Any()
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace OpenRa.Traits
|
||||
{
|
||||
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 ) )
|
||||
{
|
||||
self.CancelActivity();
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace OpenRa.Traits
|
||||
Game.world.AddFrameEndTask( _ =>
|
||||
{
|
||||
var queue = self.traits.Get<ProductionQueue>();
|
||||
var unit = Rules.ActorInfo[ order.TargetString ];
|
||||
var unit = Rules.Info[ order.TargetString ];
|
||||
var producing = queue.CurrentItem(unit.Category);
|
||||
if( producing == null || producing.Item != order.TargetString || producing.RemainingTime != 0 )
|
||||
return;
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace OpenRa.Traits
|
||||
{
|
||||
case "StartProduction":
|
||||
{
|
||||
var unit = Rules.ActorInfo[ order.TargetString ];
|
||||
var unit = Rules.Info[ order.TargetString ];
|
||||
var ui = unit.Traits.Get<BuildableInfo>();
|
||||
var time = ui.Cost
|
||||
* Rules.General.BuildSpeed /* todo: country-specific build speed bonus */
|
||||
@@ -65,7 +65,7 @@ namespace OpenRa.Traits
|
||||
}
|
||||
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 )
|
||||
producing.Paused = ( order.TargetLocation.X != 0 );
|
||||
break;
|
||||
@@ -95,7 +95,7 @@ namespace OpenRa.Traits
|
||||
|
||||
public void CancelProduction( string itemName )
|
||||
{
|
||||
var category = Rules.ActorInfo[itemName].Category;
|
||||
var category = Rules.Info[itemName].Category;
|
||||
var queue = production[ category ];
|
||||
if (queue.Count == 0) return;
|
||||
|
||||
@@ -126,7 +126,7 @@ namespace OpenRa.Traits
|
||||
|
||||
public void BuildUnit( string name )
|
||||
{
|
||||
var newUnitType = Rules.ActorInfo[ name ];
|
||||
var newUnitType = Rules.Info[ name ];
|
||||
var producerTypes = Rules.TechTree.UnitBuiltAt( newUnitType );
|
||||
Actor producer = null;
|
||||
|
||||
|
||||
0
aftermathUnits.ini → mods/aftermath/aftermathUnits.ini
Executable file → Normal file
0
aftermathUnits.ini → mods/aftermath/aftermathUnits.ini
Executable file → Normal file
0
aftrmath.ini → mods/aftermath/aftrmath.ini
Executable file → Normal file
0
aftrmath.ini → mods/aftermath/aftrmath.ini
Executable file → Normal file
17
mods/aftermath/mod.yaml
Normal file
17
mods/aftermath/mod.yaml
Normal 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
|
||||
0
[mod]Separate buildqueue for defense.yaml → mods/ra-ng/defense-queue.yaml
Executable file → Normal file
0
[mod]Separate buildqueue for defense.yaml → mods/ra-ng/defense-queue.yaml
Executable file → Normal file
12
mods/ra-ng/mod.yaml
Normal file
12
mods/ra-ng/mod.yaml
Normal 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
0
campaignUnits.ini → mods/ra/campaignUnits.ini
Executable file → Normal file
17
mods/ra/mod.yaml
Normal file
17
mods/ra/mod.yaml
Normal 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
|
||||
@@ -1,2 +1,6 @@
|
||||
RulesConverter\bin\debug\RulesConverter.exe units.ini rules.ini trees.ini campaignUnits.ini ra.yaml
|
||||
RulesConverter\bin\debug\RulesConverter.exe aftermathUnits.ini aftrmath.ini aftermath.yaml
|
||||
pushd mods\ra\
|
||||
..\..\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
|
||||
Reference in New Issue
Block a user