After NotBefore<> support to control initialization order.

Requires<T> means that trait of type T will be initialized first, and asserts that at least one exists. The new NotBefore<T> means that trait of type T will be initialized first, but allows no traits.

This allows traits to control initialization order for optional dependencies. They want to be initialized second so they can rely on the dependencies having been initialized. But if the dependencies are optional then to not throw if none are present.

We apply this to Locomotor which was previously using AddFrameEndTask to work around trait order initialization. This improves the user experience as the initialization is applied whilst the loading screen is still visible, rather than the game starting and creating jank by performing initialization on the first tick.
This commit is contained in:
RoosterDragon
2022-02-06 10:19:31 +00:00
committed by Paul Chote
parent 62e7c7a318
commit 2583a7af31
9 changed files with 100 additions and 34 deletions

View File

@@ -17,7 +17,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
[TraitLocation(SystemActors.World)]
public class ElevatedBridgeLayerInfo : TraitInfo, Requires<DomainIndexInfo>, ILobbyCustomRulesIgnore
public class ElevatedBridgeLayerInfo : TraitInfo, Requires<DomainIndexInfo>, ILobbyCustomRulesIgnore, ICustomMovementLayerInfo
{
[Desc("Terrain type used by cells outside any elevated bridge footprint.")]
public readonly string ImpassableTerrainType = "Impassable";

View File

@@ -16,7 +16,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
[TraitLocation(SystemActors.World)]
public class JumpjetActorLayerInfo : TraitInfo
public class JumpjetActorLayerInfo : TraitInfo, ICustomMovementLayerInfo
{
[Desc("Terrain type of the airborne layer.")]
public readonly string TerrainType = "Jumpjet";

View File

@@ -57,7 +57,7 @@ namespace OpenRA.Mods.Common.Traits
[TraitLocation(SystemActors.World | SystemActors.EditorWorld)]
[Desc("Used by Mobile. Attach these to the world actor. You can have multiple variants by adding @suffixes.")]
public class LocomotorInfo : TraitInfo
public class LocomotorInfo : TraitInfo, NotBefore<ICustomMovementLayerInfo>
{
[Desc("Locomotor ID.")]
public readonly string Name = "default";
@@ -376,34 +376,31 @@ namespace OpenRA.Mods.Common.Traits
map.CustomTerrain.CellEntryChanged += UpdateCellCost;
map.Tiles.CellEntryChanged += UpdateCellCost;
// This section needs to run after WorldLoaded() because we need to be sure that all types of ICustomMovementLayer have been initialized.
w.AddFrameEndTask(_ =>
// NotBefore<> ensures all custom movement layers have been initialized.
var customMovementLayers = world.GetCustomMovementLayers();
Array.Resize(ref cellsCost, customMovementLayers.Length);
Array.Resize(ref blockingCache, customMovementLayers.Length);
foreach (var cml in customMovementLayers)
{
var customMovementLayers = world.GetCustomMovementLayers();
Array.Resize(ref cellsCost, customMovementLayers.Length);
Array.Resize(ref blockingCache, customMovementLayers.Length);
foreach (var cml in customMovementLayers)
if (cml == null)
continue;
var cellLayer = new CellLayer<short>(map);
cellsCost[cml.Index] = cellLayer;
blockingCache[cml.Index] = new CellLayer<CellCache>(map);
foreach (var cell in map.AllCells)
{
if (cml == null)
continue;
var index = cml.GetTerrainIndex(cell);
var cellLayer = new CellLayer<short>(map);
cellsCost[cml.Index] = cellLayer;
blockingCache[cml.Index] = new CellLayer<CellCache>(map);
var cost = PathGraph.MovementCostForUnreachableCell;
foreach (var cell in map.AllCells)
{
var index = cml.GetTerrainIndex(cell);
if (index != byte.MaxValue)
cost = terrainInfos[index].Cost;
var cost = PathGraph.MovementCostForUnreachableCell;
if (index != byte.MaxValue)
cost = terrainInfos[index].Cost;
cellLayer[cell] = cost;
}
cellLayer[cell] = cost;
}
});
}
}
CellCache GetCache(CPos cell)

View File

@@ -16,7 +16,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
[TraitLocation(SystemActors.World)]
public class SubterraneanActorLayerInfo : TraitInfo
public class SubterraneanActorLayerInfo : TraitInfo, ICustomMovementLayerInfo
{
[Desc("Terrain type of the underground layer.")]
public readonly string TerrainType = "Subterranean";

View File

@@ -17,7 +17,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
[TraitLocation(SystemActors.World)]
public class TerrainTunnelLayerInfo : TraitInfo, Requires<DomainIndexInfo>, ILobbyCustomRulesIgnore
public class TerrainTunnelLayerInfo : TraitInfo, Requires<DomainIndexInfo>, ILobbyCustomRulesIgnore, ICustomMovementLayerInfo
{
[Desc("Terrain type used by cells outside any tunnel footprint.")]
public readonly string ImpassableTerrainType = "Impassable";