diff --git a/src/ZoneCodeGenerator/Domain/Information/MemberInformation.cs b/src/ZoneCodeGenerator/Domain/Information/MemberInformation.cs index c79efe73..84610855 100644 --- a/src/ZoneCodeGenerator/Domain/Information/MemberInformation.cs +++ b/src/ZoneCodeGenerator/Domain/Information/MemberInformation.cs @@ -1,29 +1,34 @@ using System.Collections.Generic; using System.Linq; using ZoneCodeGenerator.Domain.Evaluation; +using ZoneCodeGenerator.Domain.FastFileStructure; using ZoneCodeGenerator.Generating.Computations; namespace ZoneCodeGenerator.Domain.Information { class MemberInformation { + public StructureInformation Parent { get; } public StructureInformation StructureType { get; } public Variable Member { get; set; } public bool IsString { get; set; } public bool IsScriptString { get; set; } public bool IsReusable { get; set; } + public bool IsLeaf { get; set; } public IEvaluation Condition { get; set; } public FastFileBlock Block { get; set; } public MemberComputations Computations => new MemberComputations(this); - public MemberInformation(Variable member, StructureInformation structureType) + public MemberInformation(StructureInformation parent, Variable member, StructureInformation structureType) { + Parent = parent; Member = member; StructureType = structureType; IsString = false; IsScriptString = false; IsReusable = false; + IsLeaf = false; Condition = null; Block = null; } diff --git a/src/ZoneCodeGenerator/Generating/Computations/MemberComputations.cs b/src/ZoneCodeGenerator/Generating/Computations/MemberComputations.cs index 0771921f..9faddbd1 100644 --- a/src/ZoneCodeGenerator/Generating/Computations/MemberComputations.cs +++ b/src/ZoneCodeGenerator/Generating/Computations/MemberComputations.cs @@ -73,6 +73,12 @@ namespace ZoneCodeGenerator.Generating.Computations public bool IsNotDefaultNormalBlock => information.Block != null && !(information.Block.IsNormal && information.Block.IsDefault); + public bool IsFirstMember => + information.Parent.OrderedMembers.FirstOrDefault(member => !member.IsLeaf && !member.Computations.ShouldIgnore) == information; + + public bool IsLastMember => + information.Parent.OrderedMembers.LastOrDefault(member => !member.IsLeaf && !member.Computations.ShouldIgnore) == information; + public MemberReferenceComputations References => new MemberReferenceComputations(information); public MemberComputations(MemberInformation information) diff --git a/src/ZoneCodeGenerator/Generating/Templates/ZoneLoad.stg b/src/ZoneCodeGenerator/Generating/Templates/ZoneLoad.stg index 96ed4e28..d71c9d47 100644 --- a/src/ZoneCodeGenerator/Generating/Templates/ZoneLoad.stg +++ b/src/ZoneCodeGenerator/Generating/Templates/ZoneLoad.stg @@ -79,35 +79,86 @@ Loading member $member.Member.Name$ LoadMemberReference(context, structure, member, reference) ::= <% $if(reference.IsSinglePointer)$ -$\n$$\n$ $LoadSinglePointer(context, structure, member, reference)$ $elseif(reference.IsArrayPointer)$ -$\n$$\n$ $LoadArrayPointer(context, structure, member, reference)$ $elseif(reference.IsPointerArray)$ -$\n$$\n$ $LoadPointerArray(context, structure, member, reference)$ $elseif(reference.IsArray && !reference.NextReference)$ -$\n$$\n$ $LoadEmbeddedArray(context, structure, member, reference)$ $elseif(!reference.Reference)$ -$\n$$\n$ $LoadEmbedded(context, structure, member, reference)$ $else$ -$\n$$\n$ // $member.Member.Name$ $endif$ %> +LoadMemberCondition_Struct(context, structure, member) ::= << + + +$if(member.Condition)$ +if($PrintEvaluation(member.Condition)$) +{ + $LoadMemberReference(context, structure, member, member.Computations.References)$ +}$\\$ +$else$ +$LoadMemberReference(context, structure, member, member.Computations.References)$$\\$ +$endif$ +>> + +LoadMemberCondition_Union(context, structure, member) ::= << +$if(member.Computations.IsFirstMember)$$\\$ +$if(member.Condition)$ + +if($PrintEvaluation(member.Condition)$) +{ + $LoadMemberReference(context, structure, member, member.Computations.References)$ +}$\\$ +$else$ + +$LoadMemberReference(context, structure, member, member.Computations.References)$$\\$ +$endif$$\\$ +$elseif(member.Computations.IsLastMember)$$\\$ +$if(member.Condition)$ +else if($PrintEvaluation(member.Condition)$) +{ + $LoadMemberReference(context, structure, member, member.Computations.References)$ +}$\\$ +$else$ +else +{ + $LoadMemberReference(context, structure, member, member.Computations.References)$ +}$\\$ +$endif$$\\$ +$else$$\\$ +$if(member.Condition)$ +else if($PrintEvaluation(member.Condition)$) +{ + $LoadMemberReference(context, structure, member, member.Computations.References)$ +}$\\$ +$else$$\\$ +#error Middle member of union must have condition ($member.Member.Name$) +$endif$$\\$ +$endif$ +>> + +LoadMemberCondition(context, structure, member) ::= <% +$if(structure.IsUnion)$ +$LoadMemberCondition_Union(context, structure, member)$ +$else$ +$LoadMemberCondition_Struct(context, structure, member)$ +$endif$ +%> + LoadMemberIfNeedsTreatment(context, structure, member) ::= <% $if(!member.Computations.ShouldIgnore)$ $if(member.IsString || member.IsScriptString)$ -$LoadMemberReference(context, structure, member, member.Computations.References)$ +$LoadMemberCondition(context, structure, member)$ $elseif(member.Computations.ContainsNonEmbeddedReference)$ -$LoadMemberReference(context, structure, member, member.Computations.References)$ +$LoadMemberCondition(context, structure, member)$ $elseif(member.StructureType && !member.StructureType.IsLeaf)$ -$LoadMemberReference(context, structure, member, member.Computations.References)$ +$LoadMemberCondition(context, structure, member)$ $endif$ $endif$ diff --git a/src/ZoneCodeGenerator/Parsing/CommandFile/CommandFileReader.cs b/src/ZoneCodeGenerator/Parsing/CommandFile/CommandFileReader.cs index f088ba76..aa457105 100644 --- a/src/ZoneCodeGenerator/Parsing/CommandFile/CommandFileReader.cs +++ b/src/ZoneCodeGenerator/Parsing/CommandFile/CommandFileReader.cs @@ -14,7 +14,9 @@ namespace ZoneCodeGenerator.Parsing.CommandFile private static readonly IDataPostProcessor[] postProcessors = { new PostProcessorUsages(), - new PostProcessorLeafs() + new PostProcessorLeafs(), + new PostProcessorMemberLeafs(), + new PostProcessorUnions(), }; public static bool ReadFile(string path, CUISession session, bool verbose = false) diff --git a/src/ZoneCodeGenerator/Parsing/CommandFile/PostProcessor/PostProcessorLeafs.cs b/src/ZoneCodeGenerator/Parsing/CommandFile/PostProcessor/PostProcessorLeafs.cs index 0ef37ab1..a7616102 100644 --- a/src/ZoneCodeGenerator/Parsing/CommandFile/PostProcessor/PostProcessorLeafs.cs +++ b/src/ZoneCodeGenerator/Parsing/CommandFile/PostProcessor/PostProcessorLeafs.cs @@ -7,7 +7,7 @@ namespace ZoneCodeGenerator.Parsing.CommandFile.PostProcessor { class PostProcessorLeafs : IDataPostProcessor { - private static bool IsLeaf(StructureInformation structureInformation) + public static bool IsLeaf(StructureInformation structureInformation) { foreach (var member in structureInformation.OrderedMembers) { diff --git a/src/ZoneCodeGenerator/Parsing/CommandFile/PostProcessor/PostProcessorMemberLeafs.cs b/src/ZoneCodeGenerator/Parsing/CommandFile/PostProcessor/PostProcessorMemberLeafs.cs new file mode 100644 index 00000000..422dfd11 --- /dev/null +++ b/src/ZoneCodeGenerator/Parsing/CommandFile/PostProcessor/PostProcessorMemberLeafs.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using ZoneCodeGenerator.Domain; +using ZoneCodeGenerator.Domain.Information; +using ZoneCodeGenerator.Persistence; + +namespace ZoneCodeGenerator.Parsing.CommandFile.PostProcessor +{ + class PostProcessorMemberLeafs : IDataPostProcessor + { + private static bool MemberIsLeaf(MemberInformation member) + { + if (member.IsString || member.IsScriptString) + return false; + + if (member.StructureType != null && !member.StructureType.IsLeaf) + return false; + + // If there are any Pointer members that are not always count 0 it needs to be processed. + var hasNoPointerMembers = member.Member.VariableType.References.OfType().All(pointer => + { + if (!pointer.Count.IsStatic) + return false; + + return pointer.Count.EvaluateNumeric() == 0; + }); + + if (!hasNoPointerMembers) + return false; + + return true; + } + + private static void ProcessStructureInformation(StructureInformation structure) + { + foreach (var member in structure.OrderedMembers) + { + member.IsLeaf = MemberIsLeaf(member); + } + } + + public bool PostProcess(IDataRepository repository) + { + foreach (var structure in repository.GetAllStructs() + .Cast() + .Concat(repository.GetAllUnions()) + .Select(repository.GetInformationFor)) + { + ProcessStructureInformation(structure); + } + + return true; + } + } +} \ No newline at end of file diff --git a/src/ZoneCodeGenerator/Parsing/CommandFile/PostProcessor/PostProcessorUnions.cs b/src/ZoneCodeGenerator/Parsing/CommandFile/PostProcessor/PostProcessorUnions.cs new file mode 100644 index 00000000..5d56d4cc --- /dev/null +++ b/src/ZoneCodeGenerator/Parsing/CommandFile/PostProcessor/PostProcessorUnions.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using ZoneCodeGenerator.Domain; +using ZoneCodeGenerator.Domain.Information; +using ZoneCodeGenerator.Persistence; + +namespace ZoneCodeGenerator.Parsing.CommandFile.PostProcessor +{ + class PostProcessorUnions : IDataPostProcessor + { + private static bool ProcessUnion(StructureInformation unionInformation) + { + var entriesWithoutConditionCount = + unionInformation.OrderedMembers.Count(member => member.Condition == null && !member.IsLeaf); + + if (entriesWithoutConditionCount > 1 && unionInformation.Usages.Any() && !unionInformation.IsLeaf) + { + Console.WriteLine($"Union '{unionInformation.Type.FullName}' has more than one entry without a condition!"); + return false; + } + else if (entriesWithoutConditionCount == 1) + { + // If there is only one entry without condition make it the last of the ordered members + var entryWithoutCondition = unionInformation.OrderedMembers.First(information => information.Condition == null); + + unionInformation.OrderedMembers.Remove(entryWithoutCondition); + unionInformation.OrderedMembers.Insert(unionInformation.OrderedMembers.Count, entryWithoutCondition); + } + + return true; + } + + public bool PostProcess(IDataRepository repository) + { + return repository.GetAllUnions() + .Select(repository.GetInformationFor) + .All(ProcessUnion); + } + } +} \ No newline at end of file diff --git a/src/ZoneCodeGenerator/Persistence/InMemoryDataRepository.cs b/src/ZoneCodeGenerator/Persistence/InMemoryDataRepository.cs index 720272eb..3e13a3a8 100644 --- a/src/ZoneCodeGenerator/Persistence/InMemoryDataRepository.cs +++ b/src/ZoneCodeGenerator/Persistence/InMemoryDataRepository.cs @@ -124,7 +124,7 @@ namespace ZoneCodeGenerator.Persistence memberStructureInformation = GetInformationFor(memberType); } - information.OrderedMembers.Add(new MemberInformation(member, memberStructureInformation)); + information.OrderedMembers.Add(new MemberInformation(information, member, memberStructureInformation)); } } diff --git a/src/ZoneCommon/Game/T6/T6_Assets.h b/src/ZoneCommon/Game/T6/T6_Assets.h index c5cadbf6..e9c141e2 100644 --- a/src/ZoneCommon/Game/T6/T6_Assets.h +++ b/src/ZoneCommon/Game/T6/T6_Assets.h @@ -4619,11 +4619,9 @@ union FxElemDefVisuals union FxElemExtendedDefPtr { - FxTrailDef *localTrailDef; FxTrailDef *trailDef; - FxSpotLightDef *localSpotLightDef; FxSpotLightDef *spotLightDef; - void *unknownDef; + char *unknownDef; }; struct FxBillboardTrim @@ -4643,6 +4641,26 @@ struct FxElemSpawnSound const char *spawnSound; }; +enum FxElemType : char +{ + FX_ELEM_TYPE_SPRITE_BILLBOARD = 0x0, + FX_ELEM_TYPE_SPRITE_ORIENTED = 0x1, + FX_ELEM_TYPE_SPRITE_ROTATED = 0x2, + FX_ELEM_TYPE_TAIL = 0x3, + FX_ELEM_TYPE_LINE = 0x4, + FX_ELEM_TYPE_TRAIL = 0x5, + FX_ELEM_TYPE_CLOUD = 0x6, + FX_ELEM_TYPE_MODEL = 0x7, + FX_ELEM_TYPE_OMNI_LIGHT = 0x8, + FX_ELEM_TYPE_SPOT_LIGHT = 0x9, + FX_ELEM_TYPE_SOUND = 0xA, + FX_ELEM_TYPE_DECAL = 0xB, + FX_ELEM_TYPE_RUNNER = 0xC, + FX_ELEM_TYPE_COUNT = 0xD, + FX_ELEM_TYPE_LAST_SPRITE = 0x5, + FX_ELEM_TYPE_LAST_DRAWN = 0x9, +}; + const struct FxElemDef { int flags; @@ -4664,7 +4682,7 @@ const struct FxElemDef FxFloatRange reflectionFactor; FxElemAtlas atlas; float windInfluence; - char elemType; + FxElemType elemType; char visualCount; char velIntervalCount; char visStateIntervalCount;