Start adding codecs for OBJM and XOBJ files

This commit is contained in:
Ammar Askar 2024-10-03 23:38:44 -04:00
parent 53bfe6f3f6
commit a21b12ffd4
13 changed files with 297 additions and 0 deletions

View file

@ -0,0 +1,10 @@
namespace OpenTS2.Content.DBPF
{
/// <summary>
/// Called cEdithObjectModule in game.
/// </summary>
public class ObjectModuleAsset : AbstractAsset
{
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 88d31fc370514416b28927df14c0e41d
timeCreated: 1727972177

View file

@ -0,0 +1,7 @@
namespace OpenTS2.Content.DBPF
{
public class SimsObjectAsset : AbstractAsset
{
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ac6c2c1af0484515b3e9c91dc91159dc
timeCreated: 1727122236

View file

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

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a49ebb5f202a4e24a7d135e40c194bc8
timeCreated: 1727969785

View file

@ -5,6 +5,7 @@ using OpenTS2.Common;
using OpenTS2.Content;
using OpenTS2.Content.DBPF;
using OpenTS2.Files.Utils;
using UnityEngine;
namespace OpenTS2.Files.Formats.DBPF
{

View file

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

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 56e83332c7cd425b96ef041bca7ee9fc
timeCreated: 1727121939

View file

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

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c290fd6845f2442c94c96b4a69ddddc3
timeCreated: 1727972116

View file

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

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 13359c34be754888864a20da2042ea57
timeCreated: 1727122336