diff --git a/src/Branch/PackageObjectLegacyVersion.cs b/src/Branch/PackageObjectLegacyVersion.cs
index efc0055..39ced3d 100644
--- a/src/Branch/PackageObjectLegacyVersion.cs
+++ b/src/Branch/PackageObjectLegacyVersion.cs
@@ -8,7 +8,7 @@ public enum PackageObjectLegacyVersion
/// This is one particular update with A LOT of general package changes.
///
ReturnExpressionAddedToReturnToken = 62,
-
+
SphereExtendsPlane = 62,
LazyArrayAdded = 63,
@@ -19,18 +19,22 @@ public enum PackageObjectLegacyVersion
///
CastStringSizeTokenDeprecated = 70,
+ PanUVRemovedFromPoly = 78,
+
///
/// FIXME: Version, set 95 (Deus Ex: IW)
///
PrimitiveCastTokenAdded = 95,
-
-
+
+ LightMapScaleAddedToPoly = 106,
+
KerningAddedToUFont = 119,
FontPagesDisplaced = 122,
-
- UE3 = 184,
- RangeConstTokenDeprecated = UE3,
+ // The estimated version changes that came after the latest known UE2 build.
+ TextureDeprecatedFromPoly = 170,
+ MaterialAddedToPoly = 170,
+
///
/// Present in all released UE3 games (starting with RoboBlitz).
///
@@ -38,9 +42,33 @@ public enum PackageObjectLegacyVersion
///
IsLocalAddedToDelegateFunctionToken = 181,
+ UE3 = 184,
+ RangeConstTokenDeprecated = UE3,
+
+ // 227 according to the GoW client
+ FixedVerticesToArrayFromPoly = 227,
+
+ // FIXME: Not attested in the GoW client, must have been before v321
+ LightMapScaleRemovedFromPoly = 300,
+
+ // FIXME: Not attested in the GoW client, must have been before v321
+ ShadowMapScaleAddedToPoly = 300,
+
+ // 321 according to the GoW client
+ ElementOwnerAddedToUPolys = 321,
+
+ // 417 according to the GoW client
+ LightingChannelsAddedToPoly = 417,
+
VerticalOffsetAddedToUFont = 506,
CleanupFonts = 511,
-
+
+ LightmassAdded = 600,
+ UProcBuildingReferenceAddedToPoly = 606,
+ LightmassShadowIndirectOnlyOptionAdded = 652,
+ LightmassExplicitEmissiveLightRadiusAdded = 636,
+ PolyRulesetVariationTypeChangedToName = 670,
+
ProbeMaskReducedAndIgnoreMaskRemoved = 692,
ForceScriptOrderAddedToUClass = 749,
SuperReferenceMovedToUStruct = 756,
diff --git a/src/Eliot.UELib.csproj b/src/Eliot.UELib.csproj
index 675581a..d9f6f09 100644
--- a/src/Eliot.UELib.csproj
+++ b/src/Eliot.UELib.csproj
@@ -183,6 +183,9 @@
+
+
+
@@ -194,6 +197,7 @@
+
@@ -204,6 +208,7 @@
+
diff --git a/src/Engine/Classes/UModel.cs b/src/Engine/Classes/UModel.cs
index ab3b982..95631a3 100644
--- a/src/Engine/Classes/UModel.cs
+++ b/src/Engine/Classes/UModel.cs
@@ -1,14 +1,26 @@
+using UELib.Engine;
+using UELib.ObjectModel.Annotations;
+
namespace UELib.Core
{
///
- /// Implements UModel/Engine.Model
+ /// Implements UModel/Engine.Model
///
+ [Output("Brush")]
[UnrealRegisterClass]
public class UModel : UObject
{
+ [Output]
+ public UPolys Polys;
+
public UModel()
{
ShouldDeserializeOnDemand = true;
}
+
+ protected override void Deserialize()
+ {
+ base.Deserialize();
+ }
}
}
\ No newline at end of file
diff --git a/src/Engine/Classes/UPolys.cs b/src/Engine/Classes/UPolys.cs
new file mode 100644
index 0000000..804a882
--- /dev/null
+++ b/src/Engine/Classes/UPolys.cs
@@ -0,0 +1,62 @@
+using UELib.Annotations;
+using UELib.Branch;
+using UELib.Core;
+using UELib.Flags;
+using UELib.ObjectModel.Annotations;
+
+namespace UELib.Engine
+{
+ ///
+ /// Implements UPolys/Engine.Polys
+ ///
+ [Output("PolyList")]
+ [UnrealRegisterClass]
+ public class UPolys : UObject
+ {
+ [CanBeNull] public UObject ElementOwner;
+
+ [Output]
+ public UArray Element;
+
+ public UPolys()
+ {
+ ShouldDeserializeOnDemand = true;
+ }
+
+ protected override void Deserialize()
+ {
+ base.Deserialize();
+
+ // Faster serialization for cooked packages, no don't have to check for the package's version here.
+ if (Package.Summary.PackageFlags.HasFlag(PackageFlags.Cooked))
+ {
+ ElementOwner = _Buffer.ReadObject();
+ Record(nameof(ElementOwner), ElementOwner);
+
+ _Buffer.ReadArray(out Element);
+ Record(nameof(Element), Element);
+ return;
+ }
+
+ int num, max;
+
+ num = _Buffer.ReadInt32();
+ Record(nameof(num), num);
+ max = _Buffer.ReadInt32();
+ Record(nameof(max), max);
+
+ if (_Buffer.Version >= (uint)PackageObjectLegacyVersion.ElementOwnerAddedToUPolys)
+ {
+ ElementOwner = _Buffer.ReadObject();
+ Record(nameof(ElementOwner), ElementOwner);
+ }
+
+ Element = new UArray(num);
+ if (num > 0)
+ {
+ _Buffer.ReadArray(out Element, num);
+ Record(nameof(Element), Element);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Engine/Classes/UProcBuildingRuleset.cs b/src/Engine/Classes/UProcBuildingRuleset.cs
new file mode 100644
index 0000000..381d746
--- /dev/null
+++ b/src/Engine/Classes/UProcBuildingRuleset.cs
@@ -0,0 +1,13 @@
+using UELib.Core;
+
+namespace UELib.Engine
+{
+ ///
+ /// Implements UProcBuildingRuleset/Engine.ProcBuildingRuleset
+ ///
+ [UnrealRegisterClass]
+ [BuildGeneration(BuildGeneration.UE3)]
+ public class UProcBuildingRuleset : UObject
+ {
+ }
+}
\ No newline at end of file
diff --git a/src/Engine/Types/LightingChannelContainer.cs b/src/Engine/Types/LightingChannelContainer.cs
new file mode 100644
index 0000000..d189a9c
--- /dev/null
+++ b/src/Engine/Types/LightingChannelContainer.cs
@@ -0,0 +1,16 @@
+using System.Runtime.InteropServices;
+
+namespace UELib.Engine
+{
+ ///
+ /// See LightingChannelContainer in Engine/Classes/LightComponent.uc
+ ///
+ [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 4)]
+ public struct LightingChannelContainer : IUnrealAtomicStruct
+ {
+ [MarshalAs(UnmanagedType.I1)] public bool Initialized;
+ [MarshalAs(UnmanagedType.I1)] public bool BSP;
+ [MarshalAs(UnmanagedType.I1)] public bool Static;
+ [MarshalAs(UnmanagedType.I1)] public bool Dynamic;
+ }
+}
\ No newline at end of file
diff --git a/src/Engine/Types/LightmassPrimitiveSettings.cs b/src/Engine/Types/LightmassPrimitiveSettings.cs
new file mode 100644
index 0000000..e38043d
--- /dev/null
+++ b/src/Engine/Types/LightmassPrimitiveSettings.cs
@@ -0,0 +1,75 @@
+using System.ComponentModel;
+using System.Runtime.InteropServices;
+using UELib.Branch;
+
+namespace UELib.Engine
+{
+ ///
+ /// Implements FLightmassPrimitiveSettings
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public struct LightmassPrimitiveSettings : IUnrealSerializableClass
+ {
+ [MarshalAs(UnmanagedType.I1)] public bool UseTwoSidedLighting;
+ [MarshalAs(UnmanagedType.I1)] public bool ShadowIndirectOnly;
+ [MarshalAs(UnmanagedType.I1)] public bool UseEmissiveForStaticLighting;
+
+ public float EmissiveLightFalloffExponent;
+ public float EmissiveLightExplicitInfluenceRadius;
+ public float EmissiveBoost;
+ public float DiffuseBoost;
+ public float SpecularBoost;
+
+ [DefaultValue(1.0f)] public float FullyOccludedSamplesFraction;
+
+ public void Deserialize(IUnrealStream stream)
+ {
+ if (stream.Version >= (uint)PackageObjectLegacyVersion.LightmassShadowIndirectOnlyOptionAdded)
+ {
+ stream.Read(out UseTwoSidedLighting);
+ stream.Read(out ShadowIndirectOnly);
+ stream.Read(out FullyOccludedSamplesFraction);
+ }
+
+ if (stream.Version >= (uint)PackageObjectLegacyVersion.LightmassAdded)
+ {
+ stream.Read(out UseEmissiveForStaticLighting);
+ stream.Read(out EmissiveLightFalloffExponent);
+ }
+
+ if (stream.Version >= (uint)PackageObjectLegacyVersion.LightmassExplicitEmissiveLightRadiusAdded)
+ {
+ stream.Read(out EmissiveLightExplicitInfluenceRadius);
+ }
+
+ stream.Read(out EmissiveBoost);
+ stream.Read(out DiffuseBoost);
+ stream.Read(out SpecularBoost);
+ }
+
+ public void Serialize(IUnrealStream stream)
+ {
+ if (stream.Version >= (uint)PackageObjectLegacyVersion.LightmassShadowIndirectOnlyOptionAdded)
+ {
+ stream.Write(UseTwoSidedLighting);
+ stream.Write(ShadowIndirectOnly);
+ stream.Write(FullyOccludedSamplesFraction);
+ }
+
+ if (stream.Version >= (uint)PackageObjectLegacyVersion.LightmassAdded)
+ {
+ stream.Write(UseEmissiveForStaticLighting);
+ stream.Write(EmissiveLightFalloffExponent);
+ }
+
+ if (stream.Version >= (uint)PackageObjectLegacyVersion.LightmassExplicitEmissiveLightRadiusAdded)
+ {
+ stream.Write(EmissiveLightExplicitInfluenceRadius);
+ }
+
+ stream.Write(EmissiveBoost);
+ stream.Write(DiffuseBoost);
+ stream.Write(SpecularBoost);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Engine/Types/Poly.cs b/src/Engine/Types/Poly.cs
new file mode 100644
index 0000000..aa70cc1
--- /dev/null
+++ b/src/Engine/Types/Poly.cs
@@ -0,0 +1,173 @@
+using System;
+using System.ComponentModel;
+using System.Numerics;
+using UELib.Annotations;
+using UELib.Branch;
+using UELib.Core;
+using UELib.ObjectModel.Annotations;
+
+namespace UELib.Engine
+{
+ ///
+ /// Implements FPoly
+ ///
+ [Output("Polygon")]
+ public class Poly : IUnrealSerializableClass, IAcceptable
+ {
+ [CanBeNull] public UObject Actor;
+
+ public int BrushPoly = -1;
+
+ [DefaultValue(null)] [Output("Item", OutputSlot.Parameter)]
+ public UName ItemName;
+
+ [DefaultValue(null)] [Output("Texture")]
+ public UObject Material;
+
+ [DefaultValue(3584u)] [Output("Flags", OutputSlot.Parameter)]
+ public uint PolyFlags = 3584u;
+
+ [DefaultValue(-1)] [Output(OutputSlot.Parameter)]
+ public int Link = -1;
+
+ [DefaultValue(32.0f)] [Output(OutputSlot.Parameter)]
+ public float ShadowMapScale = 32.0f;
+
+ //[Output(OutputSlot.Parameter)]
+ public LightingChannelContainer LightingChannels;
+
+ [Output("Origin", OutputFlags.ShorthandProperty)]
+ public UVector Base;
+
+ [Output(OutputFlags.ShorthandProperty)]
+ public UVector Normal;
+
+ [DefaultValue(0)] [Output("U")] public short PanU;
+ [DefaultValue(0)] [Output("V")] public short PanV;
+
+ [Output(OutputFlags.ShorthandProperty)]
+ public UVector TextureU;
+
+ [Output(OutputFlags.ShorthandProperty)]
+ public UVector TextureV;
+
+ [Output(OutputFlags.ShorthandProperty)]
+ public UArray Vertex;
+
+ [DefaultValue(32.0f)] public float LightMapScale = 32.0f; // Not exported for some reason
+
+ public LightmassPrimitiveSettings LightmassSettings;
+
+ [DefaultValue(null)] public UProcBuildingRuleset Ruleset;
+ [DefaultValue(null)] public UName RulesetVariation;
+
+ public void Accept(IVisitor visitor)
+ {
+ visitor.Visit(this);
+ }
+
+ public TResult Accept(IVisitor visitor)
+ {
+ return visitor.Visit(this);
+ }
+
+ public void Deserialize(IUnrealStream stream)
+ {
+ // Always 16
+ int numVertices = stream.Version < (uint)PackageObjectLegacyVersion.FixedVerticesToArrayFromPoly
+ ? stream.ReadIndex()
+ : -1;
+
+ stream.ReadStruct(out Base);
+ stream.ReadStruct(out Normal);
+ stream.ReadStruct(out TextureU);
+ stream.ReadStruct(out TextureV);
+
+ if (stream.Version >= (uint)PackageObjectLegacyVersion.FixedVerticesToArrayFromPoly)
+ {
+ stream.Read(out Vertex);
+ }
+ else
+ {
+ stream.ReadArray(out Vertex, numVertices);
+ }
+
+ PolyFlags = stream.ReadUInt32();
+ if (stream.Version < 250)
+ {
+ PolyFlags |= 0xe00;
+ }
+
+ Actor = stream.ReadObject();
+ if (stream.Version < (uint)PackageObjectLegacyVersion.TextureDeprecatedFromPoly)
+ {
+ Material = stream.ReadObject();
+ }
+
+ ItemName = stream.ReadNameReference();
+ // The fact this is serialized after ItemName indicates we may have had both (A texture and material) at one point.
+ if (stream.Version >= (uint)PackageObjectLegacyVersion.MaterialAddedToPoly)
+ {
+ Material = stream.ReadObject();
+ }
+
+ Link = stream.ReadIndex();
+ BrushPoly = stream.ReadIndex();
+
+ if (stream.Version < (uint)PackageObjectLegacyVersion.PanUVRemovedFromPoly)
+ {
+ PanU = stream.ReadInt16();
+ PanV = stream.ReadInt16();
+
+ // Fix UV
+ var newBase = (Vector3)Base;
+ newBase -= (Vector3)TextureU / ((Vector3)TextureU).LengthSquared() * PanU;
+ newBase -= (Vector3)TextureV / ((Vector3)TextureV).LengthSquared() * PanV;
+ Base = (UVector)newBase;
+ }
+
+ if (stream.Version >= (uint)PackageObjectLegacyVersion.LightMapScaleAddedToPoly &&
+ stream.Version < (uint)PackageObjectLegacyVersion.LightMapScaleRemovedFromPoly)
+ {
+ LightMapScale = stream.ReadFloat();
+ }
+
+ if (stream.Version >= (uint)PackageObjectLegacyVersion.ShadowMapScaleAddedToPoly)
+ {
+ ShadowMapScale = stream.ReadFloat();
+ }
+
+ if (stream.Version >= (uint)PackageObjectLegacyVersion.LightingChannelsAddedToPoly)
+ {
+ stream.ReadAtomicStruct(out LightingChannels);
+ }
+ else
+ {
+ LightingChannels.Initialized = true;
+ LightingChannels.BSP = true;
+ }
+
+ if (stream.Version >= (uint)PackageObjectLegacyVersion.LightmassAdded)
+ {
+ stream.ReadStruct(out LightmassSettings);
+ }
+
+ if (stream.Version >= (uint)PackageObjectLegacyVersion.UProcBuildingReferenceAddedToPoly)
+ {
+ if (stream.Version >= (uint)PackageObjectLegacyVersion.PolyRulesetVariationTypeChangedToName)
+ {
+ stream.Read(out RulesetVariation);
+ }
+ else
+ {
+ stream.Read(out Ruleset);
+ }
+ }
+ }
+
+ public void Serialize(IUnrealStream stream)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
\ No newline at end of file