ZoneCodeGenerator: Make unions work with conditions and only load one union member at a time consistently

This commit is contained in:
Jan 2019-12-06 16:33:05 +01:00
parent f4a2639e30
commit 9253ac14fa
9 changed files with 196 additions and 17 deletions

View File

@ -1,29 +1,34 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using ZoneCodeGenerator.Domain.Evaluation; using ZoneCodeGenerator.Domain.Evaluation;
using ZoneCodeGenerator.Domain.FastFileStructure;
using ZoneCodeGenerator.Generating.Computations; using ZoneCodeGenerator.Generating.Computations;
namespace ZoneCodeGenerator.Domain.Information namespace ZoneCodeGenerator.Domain.Information
{ {
class MemberInformation class MemberInformation
{ {
public StructureInformation Parent { get; }
public StructureInformation StructureType { get; } public StructureInformation StructureType { get; }
public Variable Member { get; set; } public Variable Member { get; set; }
public bool IsString { get; set; } public bool IsString { get; set; }
public bool IsScriptString { get; set; } public bool IsScriptString { get; set; }
public bool IsReusable { get; set; } public bool IsReusable { get; set; }
public bool IsLeaf { get; set; }
public IEvaluation Condition { get; set; } public IEvaluation Condition { get; set; }
public FastFileBlock Block { get; set; } public FastFileBlock Block { get; set; }
public MemberComputations Computations => new MemberComputations(this); public MemberComputations Computations => new MemberComputations(this);
public MemberInformation(Variable member, StructureInformation structureType) public MemberInformation(StructureInformation parent, Variable member, StructureInformation structureType)
{ {
Parent = parent;
Member = member; Member = member;
StructureType = structureType; StructureType = structureType;
IsString = false; IsString = false;
IsScriptString = false; IsScriptString = false;
IsReusable = false; IsReusable = false;
IsLeaf = false;
Condition = null; Condition = null;
Block = null; Block = null;
} }

View File

@ -73,6 +73,12 @@ namespace ZoneCodeGenerator.Generating.Computations
public bool IsNotDefaultNormalBlock => public bool IsNotDefaultNormalBlock =>
information.Block != null && !(information.Block.IsNormal && information.Block.IsDefault); 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 MemberReferenceComputations References => new MemberReferenceComputations(information);
public MemberComputations(MemberInformation information) public MemberComputations(MemberInformation information)

View File

@ -79,35 +79,86 @@ Loading member $member.Member.Name$
LoadMemberReference(context, structure, member, reference) ::= <% LoadMemberReference(context, structure, member, reference) ::= <%
$if(reference.IsSinglePointer)$ $if(reference.IsSinglePointer)$
$\n$$\n$
$LoadSinglePointer(context, structure, member, reference)$ $LoadSinglePointer(context, structure, member, reference)$
$elseif(reference.IsArrayPointer)$ $elseif(reference.IsArrayPointer)$
$\n$$\n$
$LoadArrayPointer(context, structure, member, reference)$ $LoadArrayPointer(context, structure, member, reference)$
$elseif(reference.IsPointerArray)$ $elseif(reference.IsPointerArray)$
$\n$$\n$
$LoadPointerArray(context, structure, member, reference)$ $LoadPointerArray(context, structure, member, reference)$
$elseif(reference.IsArray && !reference.NextReference)$ $elseif(reference.IsArray && !reference.NextReference)$
$\n$$\n$
$LoadEmbeddedArray(context, structure, member, reference)$ $LoadEmbeddedArray(context, structure, member, reference)$
$elseif(!reference.Reference)$ $elseif(!reference.Reference)$
$\n$$\n$
$LoadEmbedded(context, structure, member, reference)$ $LoadEmbedded(context, structure, member, reference)$
$else$ $else$
$\n$$\n$
// $member.Member.Name$ // $member.Member.Name$
$endif$ $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) ::= <% LoadMemberIfNeedsTreatment(context, structure, member) ::= <%
$if(!member.Computations.ShouldIgnore)$ $if(!member.Computations.ShouldIgnore)$
$if(member.IsString || member.IsScriptString)$ $if(member.IsString || member.IsScriptString)$
$LoadMemberReference(context, structure, member, member.Computations.References)$ $LoadMemberCondition(context, structure, member)$
$elseif(member.Computations.ContainsNonEmbeddedReference)$ $elseif(member.Computations.ContainsNonEmbeddedReference)$
$LoadMemberReference(context, structure, member, member.Computations.References)$ $LoadMemberCondition(context, structure, member)$
$elseif(member.StructureType && !member.StructureType.IsLeaf)$ $elseif(member.StructureType && !member.StructureType.IsLeaf)$
$LoadMemberReference(context, structure, member, member.Computations.References)$ $LoadMemberCondition(context, structure, member)$
$endif$ $endif$
$endif$ $endif$

View File

@ -14,7 +14,9 @@ namespace ZoneCodeGenerator.Parsing.CommandFile
private static readonly IDataPostProcessor[] postProcessors = private static readonly IDataPostProcessor[] postProcessors =
{ {
new PostProcessorUsages(), new PostProcessorUsages(),
new PostProcessorLeafs() new PostProcessorLeafs(),
new PostProcessorMemberLeafs(),
new PostProcessorUnions(),
}; };
public static bool ReadFile(string path, CUISession session, bool verbose = false) public static bool ReadFile(string path, CUISession session, bool verbose = false)

View File

@ -7,7 +7,7 @@ namespace ZoneCodeGenerator.Parsing.CommandFile.PostProcessor
{ {
class PostProcessorLeafs : IDataPostProcessor class PostProcessorLeafs : IDataPostProcessor
{ {
private static bool IsLeaf(StructureInformation structureInformation) public static bool IsLeaf(StructureInformation structureInformation)
{ {
foreach (var member in structureInformation.OrderedMembers) foreach (var member in structureInformation.OrderedMembers)
{ {

View File

@ -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<ReferenceTypePointer>().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<DataTypeWithMembers>()
.Concat(repository.GetAllUnions())
.Select(repository.GetInformationFor))
{
ProcessStructureInformation(structure);
}
return true;
}
}
}

View File

@ -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);
}
}
}

View File

@ -124,7 +124,7 @@ namespace ZoneCodeGenerator.Persistence
memberStructureInformation = GetInformationFor(memberType); memberStructureInformation = GetInformationFor(memberType);
} }
information.OrderedMembers.Add(new MemberInformation(member, memberStructureInformation)); information.OrderedMembers.Add(new MemberInformation(information, member, memberStructureInformation));
} }
} }

View File

@ -4619,11 +4619,9 @@ union FxElemDefVisuals
union FxElemExtendedDefPtr union FxElemExtendedDefPtr
{ {
FxTrailDef *localTrailDef;
FxTrailDef *trailDef; FxTrailDef *trailDef;
FxSpotLightDef *localSpotLightDef;
FxSpotLightDef *spotLightDef; FxSpotLightDef *spotLightDef;
void *unknownDef; char *unknownDef;
}; };
struct FxBillboardTrim struct FxBillboardTrim
@ -4643,6 +4641,26 @@ struct FxElemSpawnSound
const char *spawnSound; 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 const struct FxElemDef
{ {
int flags; int flags;
@ -4664,7 +4682,7 @@ const struct FxElemDef
FxFloatRange reflectionFactor; FxFloatRange reflectionFactor;
FxElemAtlas atlas; FxElemAtlas atlas;
float windInfluence; float windInfluence;
char elemType; FxElemType elemType;
char visualCount; char visualCount;
char velIntervalCount; char velIntervalCount;
char visStateIntervalCount; char visStateIntervalCount;