mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-04-20 16:15:43 +00:00
ZoneCodeGenerator: Add possibility to define custom actions that should be performed after loading a certain Structure
This commit is contained in:
parent
c995a12001
commit
bdb0958c16
@ -378,6 +378,7 @@ set condition basemap never;
|
||||
|
||||
// GfxImageLoadDef
|
||||
use GfxImageLoadDef;
|
||||
set action LoadImageData(GfxImageLoadDef, GfxImage);
|
||||
set arraysize data resourceSize;
|
||||
|
||||
// =========================================
|
||||
|
17
src/ZoneCodeGenerator/Domain/CustomAction.cs
Normal file
17
src/ZoneCodeGenerator/Domain/CustomAction.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ZoneCodeGenerator.Domain
|
||||
{
|
||||
class CustomAction
|
||||
{
|
||||
public string ActionName { get; }
|
||||
public IList<DataType> ParameterTypes { get; }
|
||||
|
||||
public CustomAction(string actionName, IEnumerable<DataType> parameterTypes)
|
||||
{
|
||||
ActionName = actionName;
|
||||
ParameterTypes = new List<DataType>(parameterTypes);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ZoneCodeGenerator.Domain.FastFileStructure;
|
||||
using System.Collections.Generic;
|
||||
using ZoneCodeGenerator.Generating.Computations;
|
||||
using ZoneCodeGenerator.Persistence;
|
||||
|
||||
namespace ZoneCodeGenerator.Domain.Information
|
||||
{
|
||||
@ -31,6 +27,8 @@ namespace ZoneCodeGenerator.Domain.Information
|
||||
public bool ArrayReferenceExists { get; set; }
|
||||
public bool ReferenceFromNonDefaultNormalBlockExists { get; set; }
|
||||
|
||||
public CustomAction PostLoadAction { get; set; }
|
||||
|
||||
public bool IsLeaf { get; set; }
|
||||
|
||||
public List<MemberInformation> NameChain { get; set; }
|
||||
@ -47,6 +45,7 @@ namespace ZoneCodeGenerator.Domain.Information
|
||||
ReferenceFromNonDefaultNormalBlockExists = false;
|
||||
Usages = new List<StructureInformation>();
|
||||
OrderedMembers = new List<MemberInformation>();
|
||||
PostLoadAction = null;
|
||||
IsLeaf = true;
|
||||
NameChain = null;
|
||||
}
|
||||
|
@ -11,10 +11,12 @@ namespace ZoneCodeGenerator.Generating
|
||||
{
|
||||
public class UsedType
|
||||
{
|
||||
public bool MembersLoaded { get; set; }
|
||||
public DataType Type { get; }
|
||||
public StructureInformation Information { get; }
|
||||
public bool IsContextAsset { get; set; }
|
||||
|
||||
public bool NonRuntimeReferenceExists { get; set; }
|
||||
public bool NonEmbeddedReferenceExists { get; set; }
|
||||
public bool ArrayReferenceExists { get; set; }
|
||||
public bool PointerArrayReferenceExists { get; set; }
|
||||
@ -22,9 +24,11 @@ namespace ZoneCodeGenerator.Generating
|
||||
|
||||
public UsedType(DataType type, StructureInformation information)
|
||||
{
|
||||
MembersLoaded = false;
|
||||
Type = type;
|
||||
Information = information;
|
||||
IsContextAsset = false;
|
||||
NonRuntimeReferenceExists = false;
|
||||
NonEmbeddedReferenceExists = false;
|
||||
ArrayReferenceExists = false;
|
||||
PointerArrayReferenceExists = false;
|
||||
@ -33,17 +37,16 @@ namespace ZoneCodeGenerator.Generating
|
||||
}
|
||||
|
||||
public string Game { get; set; }
|
||||
public StructureInformation Asset { get; set; }
|
||||
public StructureInformation Asset { get; private set; }
|
||||
|
||||
private readonly IDictionary<DataType, UsedType> usedTypes;
|
||||
public IEnumerable<UsedType> UsedTypes => usedTypes.Values;
|
||||
|
||||
public IEnumerable<StructureInformation> UsedStructures => UsedTypes
|
||||
.Select(type => type.Information)
|
||||
.Where(information => information != null)
|
||||
.Distinct();
|
||||
public IEnumerable<UsedType> UsedStructures => UsedTypes
|
||||
.Where(usedType => usedType.Information != null && usedType.Information.Type == usedType.Type);
|
||||
|
||||
public IEnumerable<UsedType> ReferencedAssets => UsedTypes.Where(type => type.Information != null && type.Information.IsAsset && type.Information != Asset);
|
||||
public IEnumerable<UsedType> ReferencedAssets => UsedTypes.Where(type =>
|
||||
type.Information != null && type.Information.IsAsset && type.Information != Asset);
|
||||
|
||||
public IList<FastFileBlock> Blocks { get; private set; }
|
||||
|
||||
@ -51,30 +54,45 @@ namespace ZoneCodeGenerator.Generating
|
||||
Blocks.FirstOrDefault(block => block.IsNormal);
|
||||
|
||||
public FastFileBlock DefaultTempBlock => Blocks.FirstOrDefault(block => block.IsDefault && block.IsTemp) ??
|
||||
Blocks.FirstOrDefault(block => block.IsTemp);
|
||||
Blocks.FirstOrDefault(block => block.IsTemp);
|
||||
|
||||
public bool HasActions => UsedTypes.Any(type =>
|
||||
(type.Information == null || !type.Information.IsAsset || type.IsContextAsset) && type.NonRuntimeReferenceExists &&
|
||||
type.Information?.PostLoadAction != null);
|
||||
|
||||
private RenderingContext()
|
||||
{
|
||||
usedTypes = new Dictionary<DataType, UsedType>();
|
||||
}
|
||||
|
||||
private void AddToContext(StructureInformation structureInformation)
|
||||
private UsedType GetBaseType(UsedType usedType)
|
||||
{
|
||||
if (usedTypes.ContainsKey(structureInformation.Type))
|
||||
return;
|
||||
if (usedType.Type is DataTypeTypedef typeDef)
|
||||
{
|
||||
while (typeDef.TypeDefinition.Type is DataTypeTypedef anotherTypeDef)
|
||||
{
|
||||
typeDef = anotherTypeDef;
|
||||
}
|
||||
|
||||
var newUsage = new UsedType(structureInformation.Type, structureInformation);
|
||||
usedTypes.Add(newUsage.Type, newUsage);
|
||||
if (!usedTypes.ContainsKey(typeDef.TypeDefinition.Type))
|
||||
{
|
||||
var result = new UsedType(typeDef.TypeDefinition.Type, usedType.Information);
|
||||
usedTypes.Add(typeDef.TypeDefinition.Type, result);
|
||||
|
||||
if (structureInformation.IsAsset && structureInformation != Asset)
|
||||
return;
|
||||
return result;
|
||||
}
|
||||
|
||||
return usedTypes[typeDef.TypeDefinition.Type];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void AddMembersToContext(StructureInformation structureInformation)
|
||||
{
|
||||
foreach (var member in structureInformation.OrderedMembers
|
||||
.Where(member => !member.Computations.ShouldIgnore))
|
||||
{
|
||||
if(member.StructureType != null)
|
||||
AddToContext(member.StructureType);
|
||||
|
||||
UsedType usedType;
|
||||
if (!usedTypes.ContainsKey(member.Member.VariableType.Type))
|
||||
{
|
||||
@ -86,6 +104,16 @@ namespace ZoneCodeGenerator.Generating
|
||||
usedType = usedTypes[member.Member.VariableType.Type];
|
||||
}
|
||||
|
||||
var baseUsedType = GetBaseType(usedType);
|
||||
|
||||
if (!member.Computations.IsRuntimeBlock)
|
||||
{
|
||||
usedType.NonRuntimeReferenceExists = true;
|
||||
|
||||
if (baseUsedType != null)
|
||||
baseUsedType.NonRuntimeReferenceExists = true;
|
||||
}
|
||||
|
||||
if (member.Computations.ContainsNonEmbeddedReference)
|
||||
usedType.NonEmbeddedReferenceExists = true;
|
||||
|
||||
@ -99,20 +127,34 @@ namespace ZoneCodeGenerator.Generating
|
||||
if (member.IsReusable)
|
||||
usedType.PointerArrayReferenceIsReusable = true;
|
||||
}
|
||||
|
||||
if (usedType.Information != null && !usedType.Information.IsAsset && !member.Computations.IsRuntimeBlock &&
|
||||
!usedType.MembersLoaded)
|
||||
{
|
||||
usedType.MembersLoaded = true;
|
||||
AddMembersToContext(usedType.Information);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void MakeAsset(StructureInformation asset)
|
||||
{
|
||||
Asset = asset;
|
||||
var usage = new UsedType(asset.Type, asset) {IsContextAsset = true};
|
||||
usedTypes.Add(usage.Type, usage);
|
||||
|
||||
AddMembersToContext(asset);
|
||||
}
|
||||
|
||||
public static RenderingContext BuildContext(CUISession session, StructureInformation asset)
|
||||
{
|
||||
var context = new RenderingContext
|
||||
{
|
||||
Asset = asset,
|
||||
Game = session.Game,
|
||||
Blocks = session.Repository.GetAllFastFileBlocks().ToList()
|
||||
};
|
||||
|
||||
context.AddToContext(asset);
|
||||
context.usedTypes[asset.Type].IsContextAsset = true;
|
||||
context.MakeAsset(asset);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
@ -45,12 +45,18 @@ header(context) ::= <<
|
||||
|
||||
#include "Loading/AssetLoader.h"
|
||||
#include "Game/$context.Game$/$context.Game$.h"
|
||||
$if(context.HasActions)$
|
||||
#include "Game/$context.Game$/XAssets/$Lower(context.Asset.Type.Name)$/$Lower(context.Asset.Type.Name)$_actions.h"
|
||||
$endif$
|
||||
#include <string>
|
||||
|
||||
namespace $context.Game$
|
||||
{
|
||||
class $LoaderClassName(context.Asset)$ final : public AssetLoader
|
||||
{
|
||||
$if(context.HasActions)$
|
||||
Actions_$context.Asset.Type.Name$ m_actions;
|
||||
$endif$
|
||||
$VariableDeclaration(context.Asset.Type)$
|
||||
$PointerVariableDeclaration(context.Asset.Type)$
|
||||
|
||||
@ -60,8 +66,8 @@ namespace $context.Game$
|
||||
$endif$}$$\\$
|
||||
|
||||
$context.UsedTypes:{usedType | $if(usedType.PointerArrayReferenceExists)$$HeaderPtrArrayLoadMethodDeclaration(usedType.Type)$$\n$$endif$}$
|
||||
$context.UsedTypes:{usedType | $if(usedType.ArrayReferenceExists && usedType.Information && !usedType.Information.IsLeaf)$$HeaderArrayLoadMethodDeclaration(usedType.Type)$$\n$$endif$}$
|
||||
$context.UsedStructures:{usedStructure | $if(!usedStructure.IsLeaf && !usedStructure.IsAsset)$$HeaderLoadMethodDeclaration(usedStructure)$$\n$$endif$}$
|
||||
$context.UsedTypes:{usedType | $if(usedType.ArrayReferenceExists && usedType.Information && !usedType.Information.IsLeaf && usedType.NonRuntimeReferenceExists)$$HeaderArrayLoadMethodDeclaration(usedType.Type)$$\n$$endif$}$
|
||||
$context.UsedStructures:{usedStructure | $if(usedStructure.NonRuntimeReferenceExists && !usedStructure.Information.IsLeaf && !usedStructure.Information.IsAsset)$$HeaderLoadMethodDeclaration(usedStructure.Information)$$\n$$endif$}$
|
||||
$HeaderLoadMethodDeclaration(context.Asset)$
|
||||
$HeaderTempPtrLoadMethodDeclaration(context.Asset)$
|
||||
$HeaderAssetLoadMethodDeclaration(context.Asset)$
|
||||
@ -274,7 +280,8 @@ var$type.Name$Ptr = nullptr;
|
||||
|
||||
ConstructorMethod(context) ::= <<
|
||||
$LoaderClassName(context.Asset)$::$LoaderClassName(context.Asset)$(IZoneScriptStringProvider* scriptStringProvider, Zone* zone, IZoneInputStream* stream)
|
||||
: AssetLoader($context.Asset.AssetEnumEntry.Name$, scriptStringProvider, zone, stream)
|
||||
: AssetLoader($context.Asset.AssetEnumEntry.Name$, scriptStringProvider, zone, stream)$\\$
|
||||
$if(context.HasActions)$, m_actions(zone)$endif$
|
||||
{
|
||||
$VariableInitialization(context.Asset.Type)$
|
||||
$PointerVariableInitialization(context.Asset.Type)$
|
||||
@ -341,8 +348,8 @@ using namespace $context.Game$;
|
||||
$ConstructorMethod(context)$
|
||||
|
||||
$context.UsedTypes:{usedType | $if(usedType.PointerArrayReferenceExists)$$LoadPointerArrayMethod(context, usedType.Type, usedType.Information, usedType.PointerArrayReferenceIsReusable)$$\n$$\n$$endif$}$
|
||||
$context.UsedTypes:{usedType | $if(usedType.ArrayReferenceExists && usedType.Information && !usedType.Information.IsLeaf)$$LoadArrayMethod(context, usedType.Type, usedType.Information)$$\n$$\n$$endif$}$
|
||||
$context.UsedStructures:{usedStructure | $if(!usedStructure.IsLeaf && !usedStructure.IsAsset)$$LoadMethod(context, usedStructure)$$\n$$\n$$endif$}$
|
||||
$context.UsedTypes:{usedType | $if(usedType.ArrayReferenceExists && usedType.Information && !usedType.Information.IsLeaf && usedType.NonRuntimeReferenceExists)$$LoadArrayMethod(context, usedType.Type, usedType.Information)$$\n$$\n$$endif$}$
|
||||
$context.UsedStructures:{usedStructure | $if(usedStructure.NonRuntimeReferenceExists && !usedStructure.Information.IsLeaf && !usedStructure.Information.IsAsset)$$LoadMethod(context, usedStructure.Information)$$\n$$\n$$endif$}$
|
||||
$LoadMethod(context, context.Asset)$
|
||||
|
||||
$LoadTempPtrMethod(context, context.Asset)$
|
||||
|
@ -15,6 +15,7 @@ namespace ZoneCodeGenerator.Parsing.CommandFile.Impl
|
||||
{
|
||||
private static readonly ITokenTest<ICommandParserState>[] tests =
|
||||
{
|
||||
new TestAction(),
|
||||
new TestArrayCount(),
|
||||
new TestArraySize(),
|
||||
new TestAsset(),
|
||||
|
114
src/ZoneCodeGenerator/Parsing/CommandFile/Tests/TestAction.cs
Normal file
114
src/ZoneCodeGenerator/Parsing/CommandFile/Tests/TestAction.cs
Normal file
@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ZoneCodeGenerator.Domain;
|
||||
using ZoneCodeGenerator.Domain.Information;
|
||||
using ZoneCodeGenerator.Parsing.Matching;
|
||||
using ZoneCodeGenerator.Parsing.Matching.Matchers;
|
||||
using ZoneCodeGenerator.Parsing.Testing;
|
||||
|
||||
namespace ZoneCodeGenerator.Parsing.CommandFile.Tests
|
||||
{
|
||||
class TestAction : AbstractTokenTest<ICommandParserState>
|
||||
{
|
||||
private const string TokenTypename = "typeName";
|
||||
private const string TagTypename = "typeName";
|
||||
|
||||
private const string TokenActionName = "actionName";
|
||||
|
||||
private const string TokenActionArgument = "actionArgument";
|
||||
private const string TagActionArguments = "actionArguments";
|
||||
|
||||
private static readonly TokenMatcher actionArguments = new MatcherGroupAnd(
|
||||
new MatcherLiteral("("),
|
||||
new MatcherGroupOptional(new MatcherGroupAnd(
|
||||
new MatcherTypename().WithName(TokenActionArgument),
|
||||
new MatcherGroupLoop(MatcherGroupLoop.LoopMode.ZeroOneMultiple, new MatcherGroupAnd(
|
||||
new MatcherLiteral(","),
|
||||
new MatcherTypename().WithName(TokenActionArgument)
|
||||
))
|
||||
)),
|
||||
new MatcherLiteral(")")
|
||||
).WithTag(TagActionArguments);
|
||||
|
||||
private static readonly TokenMatcher[] matchers =
|
||||
{
|
||||
new MatcherLiteral("set"),
|
||||
new MatcherLiteral("action"),
|
||||
new MatcherGroupOr(
|
||||
new MatcherGroupAnd(
|
||||
new MatcherName().WithName(TokenActionName),
|
||||
new MatcherWithTag(TagActionArguments)
|
||||
),
|
||||
new MatcherGroupAnd(
|
||||
new MatcherTypename().WithName(TokenTypename).WithTag(TagTypename),
|
||||
new MatcherName().WithName(TokenActionName),
|
||||
new MatcherWithTag(TagActionArguments)
|
||||
)
|
||||
),
|
||||
new MatcherLiteral(";")
|
||||
};
|
||||
|
||||
public TestAction() : base(matchers)
|
||||
{
|
||||
AddTaggedMatcher(actionArguments);
|
||||
}
|
||||
|
||||
protected override void ProcessMatch(ICommandParserState state)
|
||||
{
|
||||
StructureInformation selectedStructure;
|
||||
if (PeekTag().Equals(TagTypename))
|
||||
{
|
||||
NextTag();
|
||||
var typeName = NextMatch(TokenTypename);
|
||||
var typeNameParts = typeName.Split(new[] {"::"}, StringSplitOptions.None);
|
||||
|
||||
if (state.DataTypeInUse != null &&
|
||||
state.GetMembersFromParts(typeNameParts, state.DataTypeInUse, out var selectedMembers))
|
||||
{
|
||||
selectedStructure = state.DataTypeInUse;
|
||||
}
|
||||
else if (state.GetTypenameAndMembersFromParts(typeNameParts, out selectedStructure, out selectedMembers))
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new TestFailedException($"Could not find type '{typeName}'.");
|
||||
}
|
||||
|
||||
if (selectedMembers.Any())
|
||||
{
|
||||
selectedStructure = selectedMembers.Last().StructureType ??
|
||||
throw new TestFailedException("Member is not a data type with members.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedStructure = state.DataTypeInUse ?? throw new TestFailedException("No type found for action.");
|
||||
}
|
||||
|
||||
var actionName = NextMatch(TokenActionName);
|
||||
if (string.IsNullOrEmpty(actionName))
|
||||
{
|
||||
throw new TestFailedException("Action needs a valid name!");
|
||||
}
|
||||
|
||||
var parameterTypes = new List<DataType>();
|
||||
string parameter;
|
||||
while ((parameter = NextMatch(TokenActionArgument)) != null)
|
||||
{
|
||||
var parameterDataType = state.Repository.GetDataTypeByName(parameter);
|
||||
|
||||
if (parameterDataType == null)
|
||||
{
|
||||
throw new TestFailedException($"Could not find type '{parameter}'.");
|
||||
}
|
||||
|
||||
parameterTypes.Add(parameterDataType);
|
||||
}
|
||||
|
||||
selectedStructure.PostLoadAction = new CustomAction(actionName, parameterTypes);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
#include "gfximage_actions.h"
|
||||
|
||||
Actions_GfxImage::Actions_GfxImage(Zone* zone)
|
||||
: AssetLoadingActions(zone)
|
||||
{
|
||||
}
|
||||
|
||||
void Actions_GfxImage::LoadImageData(T6::GfxImageLoadDef* loadDef, T6::GfxImage* image)
|
||||
{
|
||||
}
|
12
src/ZoneLoading/Game/T6/XAssets/gfximage/gfximage_actions.h
Normal file
12
src/ZoneLoading/Game/T6/XAssets/gfximage/gfximage_actions.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "Loading/AssetLoadingActions.h"
|
||||
#include "Game/T6/T6.h"
|
||||
|
||||
class Actions_GfxImage final : public AssetLoadingActions
|
||||
{
|
||||
public:
|
||||
explicit Actions_GfxImage(Zone* zone);
|
||||
|
||||
void LoadImageData(T6::GfxImageLoadDef* loadDef, T6::GfxImage* image);
|
||||
};
|
6
src/ZoneLoading/Loading/AssetLoadingActions.cpp
Normal file
6
src/ZoneLoading/Loading/AssetLoadingActions.cpp
Normal file
@ -0,0 +1,6 @@
|
||||
#include "AssetLoadingActions.h"
|
||||
|
||||
AssetLoadingActions::AssetLoadingActions(Zone* zone)
|
||||
{
|
||||
m_zone = zone;
|
||||
}
|
12
src/ZoneLoading/Loading/AssetLoadingActions.h
Normal file
12
src/ZoneLoading/Loading/AssetLoadingActions.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "Zone/Zone.h"
|
||||
|
||||
class AssetLoadingActions
|
||||
{
|
||||
protected:
|
||||
Zone* m_zone;
|
||||
|
||||
public:
|
||||
explicit AssetLoadingActions(Zone* zone);
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user