Add backend plumbing for model loaders.
This commit is contained in:
@@ -165,7 +165,7 @@ namespace OpenRA
|
||||
using (new PerfTimer("PrepareMap"))
|
||||
map = ModData.PrepareMap(mapUID);
|
||||
using (new PerfTimer("NewWorld"))
|
||||
OrderManager.World = new World(map, OrderManager, type);
|
||||
OrderManager.World = new World(ModData, map, OrderManager, type);
|
||||
|
||||
worldRenderer = new WorldRenderer(ModData, OrderManager.World);
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace OpenRA
|
||||
public readonly IReadOnlyDictionary<string, MusicInfo> Music;
|
||||
public readonly TileSet TileSet;
|
||||
public readonly SequenceProvider Sequences;
|
||||
public readonly IReadOnlyDictionary<string, MiniYamlNode> ModelSequences;
|
||||
|
||||
public Ruleset(
|
||||
IReadOnlyDictionary<string, ActorInfo> actors,
|
||||
@@ -37,7 +38,8 @@ namespace OpenRA
|
||||
IReadOnlyDictionary<string, SoundInfo> notifications,
|
||||
IReadOnlyDictionary<string, MusicInfo> music,
|
||||
TileSet tileSet,
|
||||
SequenceProvider sequences)
|
||||
SequenceProvider sequences,
|
||||
IReadOnlyDictionary<string, MiniYamlNode> modelSequences)
|
||||
{
|
||||
Actors = actors;
|
||||
Weapons = weapons;
|
||||
@@ -46,6 +48,7 @@ namespace OpenRA
|
||||
Music = music;
|
||||
TileSet = tileSet;
|
||||
Sequences = sequences;
|
||||
ModelSequences = modelSequences;
|
||||
|
||||
foreach (var a in Actors.Values)
|
||||
{
|
||||
@@ -119,8 +122,11 @@ namespace OpenRA
|
||||
var music = MergeOrDefault("Manifest,Music", fs, m.Music, null, null,
|
||||
k => new MusicInfo(k.Key, k.Value));
|
||||
|
||||
var modelSequences = MergeOrDefault("Manifest,ModelSequences", fs, m.VoxelSequences, null, null,
|
||||
k => k);
|
||||
|
||||
// The default ruleset does not include a preferred tileset or sequence set
|
||||
ruleset = new Ruleset(actors, weapons, voices, notifications, music, null, null);
|
||||
ruleset = new Ruleset(actors, weapons, voices, notifications, music, null, null, modelSequences);
|
||||
};
|
||||
|
||||
if (modData.IsOnMainThread)
|
||||
@@ -145,12 +151,13 @@ namespace OpenRA
|
||||
var dr = modData.DefaultRules;
|
||||
var ts = modData.DefaultTileSets[tileSet];
|
||||
var sequences = modData.DefaultSequences[tileSet];
|
||||
return new Ruleset(dr.Actors, dr.Weapons, dr.Voices, dr.Notifications, dr.Music, ts, sequences);
|
||||
|
||||
return new Ruleset(dr.Actors, dr.Weapons, dr.Voices, dr.Notifications, dr.Music, ts, sequences, dr.ModelSequences);
|
||||
}
|
||||
|
||||
public static Ruleset Load(ModData modData, IReadOnlyFileSystem fileSystem, string tileSet,
|
||||
MiniYaml mapRules, MiniYaml mapWeapons, MiniYaml mapVoices, MiniYaml mapNotifications,
|
||||
MiniYaml mapMusic, MiniYaml mapSequences)
|
||||
MiniYaml mapMusic, MiniYaml mapSequences, MiniYaml mapModelSequences)
|
||||
{
|
||||
var m = modData.Manifest;
|
||||
var dr = modData.DefaultRules;
|
||||
@@ -180,8 +187,12 @@ namespace OpenRA
|
||||
var sequences = mapSequences == null ? modData.DefaultSequences[tileSet] :
|
||||
new SequenceProvider(fileSystem, modData, ts, mapSequences);
|
||||
|
||||
// TODO: Add support for custom voxel sequences
|
||||
ruleset = new Ruleset(actors, weapons, voices, notifications, music, ts, sequences);
|
||||
var modelSequences = dr.ModelSequences;
|
||||
if (mapModelSequences != null)
|
||||
modelSequences = MergeOrDefault("ModelSequences", fileSystem, m.VoxelSequences, mapModelSequences, dr.ModelSequences,
|
||||
k => k);
|
||||
|
||||
ruleset = new Ruleset(actors, weapons, voices, notifications, music, ts, sequences, modelSequences);
|
||||
};
|
||||
|
||||
if (modData.IsOnMainThread)
|
||||
|
||||
69
OpenRA.Game/Graphics/Model.cs
Normal file
69
OpenRA.Game/Graphics/Model.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2017 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using OpenRA.FileSystem;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
public interface IModel
|
||||
{
|
||||
uint Frames { get; }
|
||||
uint Sections { get; }
|
||||
|
||||
float[] TransformationMatrix(uint section, uint frame);
|
||||
float[] Size { get; }
|
||||
float[] Bounds(uint frame);
|
||||
VoxelRenderData RenderData(uint section);
|
||||
}
|
||||
|
||||
public interface IModelCache : IDisposable
|
||||
{
|
||||
IModel GetModelSequence(string model, string sequence);
|
||||
bool HasModelSequence(string model, string sequence);
|
||||
IVertexBuffer<Vertex> VertexBuffer { get; }
|
||||
}
|
||||
|
||||
public interface IModelSequenceLoader
|
||||
{
|
||||
Action<string> OnMissingModelError { get; set; }
|
||||
IModelCache CacheModels(IReadOnlyFileSystem fileSystem, ModData modData, IReadOnlyDictionary<string, MiniYamlNode> modelDefinitions);
|
||||
}
|
||||
|
||||
public class PlaceholderModelSequenceLoader : IModelSequenceLoader
|
||||
{
|
||||
public Action<string> OnMissingModelError { get; set; }
|
||||
|
||||
class PlaceholderModelCache : IModelCache
|
||||
{
|
||||
public IVertexBuffer<Vertex> VertexBuffer { get { throw new NotImplementedException(); } }
|
||||
|
||||
public void Dispose() { }
|
||||
|
||||
public IModel GetModelSequence(string model, string sequence)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool HasModelSequence(string model, string sequence)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public PlaceholderModelSequenceLoader(ModData modData) { }
|
||||
|
||||
public IModelCache CacheModels(IReadOnlyFileSystem fileSystem, ModData modData, IReadOnlyDictionary<string, MiniYamlNode> modelDefinitions)
|
||||
{
|
||||
return new PlaceholderModelCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,17 @@ namespace OpenRA
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ModelSequenceFormat : IGlobalModData
|
||||
{
|
||||
public readonly string Type;
|
||||
public readonly IReadOnlyDictionary<string, MiniYaml> Metadata;
|
||||
public ModelSequenceFormat(MiniYaml yaml)
|
||||
{
|
||||
Type = yaml.Value;
|
||||
Metadata = new ReadOnlyDictionary<string, MiniYaml>(yaml.ToDictionary());
|
||||
}
|
||||
}
|
||||
|
||||
public class ModMetadata
|
||||
{
|
||||
public string Title;
|
||||
|
||||
@@ -18,6 +18,7 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using OpenRA.FileSystem;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Support;
|
||||
using OpenRA.Traits;
|
||||
|
||||
@@ -386,7 +387,7 @@ namespace OpenRA
|
||||
try
|
||||
{
|
||||
Rules = Ruleset.Load(modData, this, Tileset, RuleDefinitions, WeaponDefinitions,
|
||||
VoiceDefinitions, NotificationDefinitions, MusicDefinitions, SequenceDefinitions);
|
||||
VoiceDefinitions, NotificationDefinitions, MusicDefinitions, SequenceDefinitions, VoxelSequenceDefinitions);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -307,8 +307,9 @@ namespace OpenRA
|
||||
var musicDefinitions = LoadRuleSection(yaml, "Music");
|
||||
var notificationDefinitions = LoadRuleSection(yaml, "Notifications");
|
||||
var sequenceDefinitions = LoadRuleSection(yaml, "Sequences");
|
||||
var modelSequenceDefinitions = LoadRuleSection(yaml, "VoxelSequences");
|
||||
var rules = Ruleset.Load(modData, this, TileSet, ruleDefinitions, weaponDefinitions,
|
||||
voiceDefinitions, notificationDefinitions, musicDefinitions, sequenceDefinitions);
|
||||
voiceDefinitions, notificationDefinitions, musicDefinitions, sequenceDefinitions, modelSequenceDefinitions);
|
||||
var flagged = Ruleset.DefinesUnsafeCustomRules(modData, this, ruleDefinitions,
|
||||
weaponDefinitions, voiceDefinitions, notificationDefinitions, sequenceDefinitions);
|
||||
return Pair.New(rules, flagged);
|
||||
@@ -390,8 +391,9 @@ namespace OpenRA
|
||||
var musicDefinitions = LoadRuleSection(rulesYaml, "Music");
|
||||
var notificationDefinitions = LoadRuleSection(rulesYaml, "Notifications");
|
||||
var sequenceDefinitions = LoadRuleSection(rulesYaml, "Sequences");
|
||||
var modelSequenceDefinitions = LoadRuleSection(rulesYaml, "VoxelSequences");
|
||||
var rules = Ruleset.Load(modData, this, TileSet, ruleDefinitions, weaponDefinitions,
|
||||
voiceDefinitions, notificationDefinitions, musicDefinitions, sequenceDefinitions);
|
||||
voiceDefinitions, notificationDefinitions, musicDefinitions, sequenceDefinitions, modelSequenceDefinitions);
|
||||
var flagged = Ruleset.DefinesUnsafeCustomRules(modData, this, ruleDefinitions,
|
||||
weaponDefinitions, voiceDefinitions, notificationDefinitions, sequenceDefinitions);
|
||||
return Pair.New(rules, flagged);
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace OpenRA
|
||||
public readonly ISoundLoader[] SoundLoaders;
|
||||
public readonly ISpriteLoader[] SpriteLoaders;
|
||||
public readonly ISpriteSequenceLoader SpriteSequenceLoader;
|
||||
public readonly IModelSequenceLoader ModelSequenceLoader;
|
||||
public ILoadScreen LoadScreen { get; private set; }
|
||||
public VoxelLoader VoxelLoader { get; private set; }
|
||||
public CursorProvider CursorProvider { get; private set; }
|
||||
@@ -73,13 +74,22 @@ namespace OpenRA
|
||||
|
||||
var sequenceFormat = Manifest.Get<SpriteSequenceFormat>();
|
||||
var sequenceLoader = ObjectCreator.FindType(sequenceFormat.Type + "Loader");
|
||||
var ctor = sequenceLoader != null ? sequenceLoader.GetConstructor(new[] { typeof(ModData) }) : null;
|
||||
if (sequenceLoader == null || !sequenceLoader.GetInterfaces().Contains(typeof(ISpriteSequenceLoader)) || ctor == null)
|
||||
var sequenceCtor = sequenceLoader != null ? sequenceLoader.GetConstructor(new[] { typeof(ModData) }) : null;
|
||||
if (sequenceLoader == null || !sequenceLoader.GetInterfaces().Contains(typeof(ISpriteSequenceLoader)) || sequenceCtor == null)
|
||||
throw new InvalidOperationException("Unable to find a sequence loader for type '{0}'.".F(sequenceFormat.Type));
|
||||
|
||||
SpriteSequenceLoader = (ISpriteSequenceLoader)ctor.Invoke(new[] { this });
|
||||
SpriteSequenceLoader = (ISpriteSequenceLoader)sequenceCtor.Invoke(new[] { this });
|
||||
SpriteSequenceLoader.OnMissingSpriteError = s => Log.Write("debug", s);
|
||||
|
||||
var modelFormat = Manifest.Get<ModelSequenceFormat>();
|
||||
var modelLoader = ObjectCreator.FindType(modelFormat.Type + "Loader");
|
||||
var modelCtor = modelLoader != null ? modelLoader.GetConstructor(new[] { typeof(ModData) }) : null;
|
||||
if (modelLoader == null || !modelLoader.GetInterfaces().Contains(typeof(IModelSequenceLoader)) || modelCtor == null)
|
||||
throw new InvalidOperationException("Unable to find a model loader for type '{0}'.".F(modelFormat.Type));
|
||||
|
||||
ModelSequenceLoader = (IModelSequenceLoader)modelCtor.Invoke(new[] { this });
|
||||
ModelSequenceLoader.OnMissingModelError = s => Log.Write("debug", s);
|
||||
|
||||
defaultRules = Exts.Lazy(() => Ruleset.LoadDefaults(this));
|
||||
defaultTileSets = Exts.Lazy(() =>
|
||||
{
|
||||
|
||||
@@ -256,6 +256,7 @@
|
||||
<Compile Include="CryptoUtil.cs" />
|
||||
<Compile Include="Support\VariableExpression.cs" />
|
||||
<Compile Include="ExternalMods.cs" />
|
||||
<Compile Include="Graphics\Model.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="FileSystem\Folder.cs" />
|
||||
|
||||
@@ -40,6 +40,7 @@ namespace OpenRA
|
||||
public Session LobbyInfo { get { return OrderManager.LobbyInfo; } }
|
||||
|
||||
public readonly MersenneTwister SharedRandom;
|
||||
public readonly IModelCache ModelCache;
|
||||
|
||||
public Player[] Players = new Player[0];
|
||||
|
||||
@@ -147,7 +148,7 @@ namespace OpenRA
|
||||
}
|
||||
}
|
||||
|
||||
internal World(Map map, OrderManager orderManager, WorldType type)
|
||||
internal World(ModData modData, Map map, OrderManager orderManager, WorldType type)
|
||||
{
|
||||
Type = type;
|
||||
OrderManager = orderManager;
|
||||
@@ -156,6 +157,8 @@ namespace OpenRA
|
||||
Timestep = orderManager.LobbyInfo.GlobalSettings.Timestep;
|
||||
SharedRandom = new MersenneTwister(orderManager.LobbyInfo.GlobalSettings.RandomSeed);
|
||||
|
||||
ModelCache = modData.ModelSequenceLoader.CacheModels(map, modData, map.Rules.ModelSequences);
|
||||
|
||||
var worldActorType = type == WorldType.Editor ? "EditorWorld" : "World";
|
||||
WorldActor = CreateActor(worldActorType, new TypeDictionary());
|
||||
ActorMap = WorldActor.Trait<IActorMap>();
|
||||
@@ -437,6 +440,8 @@ namespace OpenRA
|
||||
Game.Sound.StopAudio();
|
||||
Game.Sound.StopVideo();
|
||||
|
||||
ModelCache.Dispose();
|
||||
|
||||
// Dispose newer actors first, and the world actor last
|
||||
foreach (var a in actors.Values.Reverse())
|
||||
a.Dispose();
|
||||
|
||||
@@ -30,3 +30,5 @@ SoundFormats:
|
||||
SpriteFormats:
|
||||
|
||||
SpriteSequenceFormat: DefaultSpriteSequence
|
||||
|
||||
ModelSequenceFormat: PlaceholderModelSequence
|
||||
|
||||
@@ -197,6 +197,8 @@ SpriteSequenceFormat: TilesetSpecificSpriteSequence
|
||||
DESERT: .des
|
||||
JUNGLE: .jun
|
||||
|
||||
ModelSequenceFormat: PlaceholderModelSequence
|
||||
|
||||
GameSpeeds:
|
||||
slower:
|
||||
Name: Slower
|
||||
|
||||
@@ -174,6 +174,8 @@ SpriteFormats: R8, ShpTD, TmpRA
|
||||
|
||||
SpriteSequenceFormat: DefaultSpriteSequence
|
||||
|
||||
ModelSequenceFormat: PlaceholderModelSequence
|
||||
|
||||
GameSpeeds:
|
||||
slower:
|
||||
Name: Slower
|
||||
|
||||
@@ -55,3 +55,5 @@ SoundFormats:
|
||||
SpriteFormats: ShpTD
|
||||
|
||||
SpriteSequenceFormat: DefaultSpriteSequence
|
||||
|
||||
ModelSequenceFormat: PlaceholderModelSequence
|
||||
|
||||
@@ -200,6 +200,8 @@ SpriteSequenceFormat: TilesetSpecificSpriteSequence
|
||||
INTERIOR: .int
|
||||
DESERT: .des
|
||||
|
||||
ModelSequenceFormat: PlaceholderModelSequence
|
||||
|
||||
GameSpeeds:
|
||||
slower:
|
||||
Name: Slower
|
||||
|
||||
@@ -236,6 +236,8 @@ SpriteSequenceFormat: TilesetSpecificSpriteSequence
|
||||
TEMPERATE: t
|
||||
SNOW: a
|
||||
|
||||
ModelSequenceFormat: PlaceholderModelSequence
|
||||
|
||||
GameSpeeds:
|
||||
slower:
|
||||
Name: Slower
|
||||
|
||||
Reference in New Issue
Block a user