Skip to content

Commit

Permalink
Start adding codecs for OBJM and XOBJ files
Browse files Browse the repository at this point in the history
  • Loading branch information
ammaraskar committed Oct 4, 2024
1 parent 53bfe6f commit a21b12f
Show file tree
Hide file tree
Showing 13 changed files with 297 additions and 0 deletions.
10 changes: 10 additions & 0 deletions Assets/Scripts/OpenTS2/Content/DBPF/ObjectModuleAsset.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace OpenTS2.Content.DBPF
{
/// <summary>
/// Called cEdithObjectModule in game.
/// </summary>
public class ObjectModuleAsset : AbstractAsset
{

}
}
3 changes: 3 additions & 0 deletions Assets/Scripts/OpenTS2/Content/DBPF/ObjectModuleAsset.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions Assets/Scripts/OpenTS2/Content/DBPF/SimsObjectAsset.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace OpenTS2.Content.DBPF
{
public class SimsObjectAsset : AbstractAsset
{

}
}
3 changes: 3 additions & 0 deletions Assets/Scripts/OpenTS2/Content/DBPF/SimsObjectAsset.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

54 changes: 54 additions & 0 deletions Assets/Scripts/OpenTS2/Files/Formats/DBPF/ObjectModuleCodec.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System;
using System.IO;
using OpenTS2.Common;
using OpenTS2.Content;
using OpenTS2.Content.DBPF;
using OpenTS2.Files.Utils;
using UnityEngine;

namespace OpenTS2.Files.Formats.DBPF
{
/// <summary>
/// Codec for what is known in game as cEdithObjectModule. Likely a container for different types of objects.
/// </summary>
[Codec(TypeIDs.OBJM)]
public class ObjectModuleCodec : AbstractCodec
{
public override AbstractAsset Deserialize(byte[] bytes, ResourceKey tgi, DBPFFile sourceFile)
{
var asset = new ObjectModuleAsset();
var stream = new MemoryStream(bytes);
var reader = IoBuffer.FromStream(stream, ByteOrder.LITTLE_ENDIAN);

// Skip first 64 bytes.
reader.Seek(SeekOrigin.Begin, 64);

// First int, ignored.
reader.Seek(SeekOrigin.Current, 4);
// Version number.
int version = reader.ReadInt32();
Debug.Log($"Version: 0x{version:X}");
// Type identifier.
uint type = reader.ReadUInt32();
if (type != 0x4F626A4D)
{
// Corresponds to the string "ObjM"
throw new NotImplementedException("ObjM file does not have `ObjM` magic bytes");
}

// Next is the number of objects.
int numObjects = reader.ReadInt32();
Debug.Log($"numObjects: {numObjects}");
for (var i = 0; i < numObjects; i++)
{
int selectorSaveType = reader.ReadInt32();
int missingObjectSaveType = reader.ReadInt32();

Debug.Log($"selectorSaveType: {selectorSaveType}, missingObjectSaveType: {missingObjectSaveType}");
break;
}

return asset;
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using OpenTS2.Content;
using OpenTS2.Content.DBPF;
using OpenTS2.Files.Utils;
using UnityEngine;

namespace OpenTS2.Files.Formats.DBPF
{
Expand Down
155 changes: 155 additions & 0 deletions Assets/Scripts/OpenTS2/Files/Formats/DBPF/SimsObjectCodec.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
using System;
using System.Collections.Generic;
using System.IO;
using OpenTS2.Common;
using OpenTS2.Content;
using OpenTS2.Content.DBPF;
using OpenTS2.Files.Utils;
using UnityEngine;

namespace OpenTS2.Files.Formats.DBPF
{
/// <summary>
/// Codec for what is known in game as cTSObject. Contains attributes and locations of objects.
/// </summary>
[Codec(TypeIDs.XOBJ)]
public class SimsObjectCodec : AbstractCodec
{
public override AbstractAsset Deserialize(byte[] bytes, ResourceKey tgi, DBPFFile sourceFile)
{
var asset = new SimsObjectAsset();
var stream = new MemoryStream(bytes);
var reader = IoBuffer.FromStream(stream, ByteOrder.LITTLE_ENDIAN);

// Skip first 64 bytes.
reader.Seek(SeekOrigin.Begin, 64);

// TODO: this is for versions = 0xAD, see if we need to handle lower.

// 4 skipped/unused floats
for (int i = 0; i < 4; i++)
{
reader.ReadFloat();
}

var tileLocationY = reader.ReadFloat();
var tileLocationX = reader.ReadFloat();
var level = reader.ReadInt32();
// ignored int16
reader.ReadUInt16();
var elevation = reader.ReadFloat();
var objectGroupId = reader.ReadInt32();
var unknown = reader.ReadInt16();

Debug.Log($"tileLocationY: {tileLocationY}, tileLocationX: {tileLocationX}, level: {level}, " +
$"elevation: {elevation}, objectGroupId: {objectGroupId}, unknown: {unknown}");

var numAttrs = reader.ReadInt16();
var attrs = new short[numAttrs];
for (var i = 0; i < numAttrs; i++)
{
attrs[i] = reader.ReadInt16();
}
Debug.Log($"numAttrs: {numAttrs}, attrs: [{string.Join(", ", attrs)}]");

var numSemiAttrs = reader.ReadInt16();
var semiAttrs = new short[numSemiAttrs];
for (var i = 0; i < numSemiAttrs; i++)
{
semiAttrs[i] = reader.ReadInt16();
}
Debug.Log($"numSemiAttrs: {numAttrs}, semiAttrs: [{string.Join(", ", semiAttrs)}]");

Debug.Log($" Data array offset: {reader.Position:X}");

/*
// 8 unknown shorts called "data".
var dataArray = new short[8];
for (var i = 0; i < dataArray.Length; i++)
{
dataArray[i] = reader.ReadInt16();
}
Debug.Log($"dataArray: [{string.Join(", ", dataArray)}]");
// Next is a number of shorts that depends on the exact version of the file.
uint numShorts = 0x57 + 6;
for (var i = 0; i < numShorts; i++)
{
reader.ReadInt16();
}
// Another 8 shorts, called the "tempTokenFields".
for (var i = 0; i < 8; i++)
{
reader.ReadInt16();
}
// Next is the number of object arrays. Each being a short array itself.
var numObjectArrays = reader.ReadInt16();
var shortArrays = new List<short[]>(numObjectArrays);
for (var i = 0; i < numObjectArrays; i++)
{
var objectArray = new short[reader.ReadInt16()];
for (var j = 0; j < objectArray.Length; j++)
{
objectArray[j] = reader.ReadInt16();
}
shortArrays.Add(objectArray);
}
Debug.Log($"numObjectArrays: {numObjectArrays}");
// An array of shorts. Unknown.
var numSecondShortArray = reader.ReadInt16();
for (var i = 0; i < numSecondShortArray; i++)
{
reader.ReadInt16();
}
Debug.Log($"numSecondShortArrays: {numSecondShortArray}");
var ownershipValue = reader.ReadInt32();
Debug.Log($"ownershipValue: {ownershipValue}");
Debug.Log($" Position before strings: 0x{reader.Position:X}");
// A number of material subsitution strings.
var numMaterialSubstitues = reader.ReadInt16();
Debug.Log($" numMaterialSubstitues: {numMaterialSubstitues}");
for (var i = 0; i < numMaterialSubstitues; i++)
{
var materialSubstitute = reader.ReadVariableLengthPascalString();
Debug.Log($"materialSubstitute: {materialSubstitute}");
}
var persistentFlag = reader.ReadUInt16();
Debug.Log($"persistentFlag: {persistentFlag}");
// Slots...
var slotsFlag = reader.ReadInt16();
Debug.Log($"slotsFlag: {slotsFlag}");
var numSlots = reader.ReadInt16();
for (var i = 0; i < numSlots; i++)
{
var slotValue = reader.ReadInt16();
}
Debug.Log($"numSlots: {numSlots}");
var numEffects = reader.ReadInt16();
Debug.Log($"numEffects: {numEffects}");
Debug.Log($"Position after numEffects: 0x{reader.Position:X}");
var numbOverrides = reader.ReadInt16();
Debug.Log($"numOverides: {numbOverrides}");
for (int i = 0; i < numbOverrides; i++)
{
var overrideString1 = reader.ReadVariableLengthPascalString();
var overrideString2 = reader.ReadVariableLengthPascalString();
var overrideString3 = reader.ReadVariableLengthPascalString();
Debug.Log($"{overrideString1} / {overrideString2} / {overrideString3}");
}*/

return asset;
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions Assets/Tests/OpenTS2/Files/Formats/DBPF/ObjectModuleCodecTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using NUnit.Framework;
using OpenTS2.Common;
using OpenTS2.Content;
using OpenTS2.Content.DBPF;
using OpenTS2.Files.Formats.DBPF;

public class ObjectModuleCodecTest
{
private uint _groupID;

[SetUp]
public void SetUp()
{
TestMain.Initialize();
_groupID = ContentProvider.Get().AddPackage("TestAssets/Codecs/ObjCodecs.package").GroupID;
}

[Test]
public void TestSuccessfullyLoadsObjectModule()
{
var objectModuleAsset = ContentProvider.Get()
.GetAsset<ObjectModuleAsset>(new ResourceKey(0x1, _groupID, TypeIDs.OBJM));

Assert.That(objectModuleAsset, Is.Not.Null);
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions Assets/Tests/OpenTS2/Files/Formats/DBPF/SimsObjectCodecTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Linq;
using NUnit.Framework;
using OpenTS2.Common;
using OpenTS2.Content;
using OpenTS2.Content.DBPF;
using OpenTS2.Files.Formats.DBPF;

public class SimsObjectCodecTest
{
private uint _groupID;

[SetUp]
public void SetUp()
{
TestMain.Initialize();
_groupID = ContentProvider.Get().AddPackage("TestAssets/Codecs/ObjCodecs.package").GroupID;
}

[Test]
public void TestSuccessfullyLoadsSimsObject()
{
var objectAsset = ContentProvider.Get().GetAsset<SimsObjectAsset>(new ResourceKey(0x158, _groupID, TypeIDs.XOBJ));

Assert.That(objectAsset, Is.Not.Null);
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit a21b12f

Please sign in to comment.