mirror of
https://github.com/LazyDuchess/OpenTS2.git
synced 2025-01-22 08:11:47 -05:00
Add loading of neighborhood object XML files.
These are the files that assosciate the neighborhood GUIDs to the models. This also adds a class to handle cGZPropertySetString files since we will likely need to parse those more in the future.
This commit is contained in:
parent
fcb7484d80
commit
2d439d9552
15 changed files with 230 additions and 14 deletions
|
@ -0,0 +1,18 @@
|
|||
using OpenTS2.Files.Formats.XML;
|
||||
|
||||
namespace OpenTS2.Content.DBPF
|
||||
{
|
||||
public class NeighborhoodObjectAsset : AbstractAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the model for this neighborhood object.
|
||||
/// </summary>
|
||||
public string ModelName { get; }
|
||||
/// <summary>
|
||||
/// The global unique id for the object.
|
||||
/// </summary>
|
||||
public uint Guid { get; }
|
||||
|
||||
public NeighborhoodObjectAsset(string modelName, uint guid) => (ModelName, Guid) = (modelName, guid);
|
||||
}
|
||||
}
|
3
Assets/Scripts/OpenTS2/Content/DBPF/NeighborhoodObjectAsset.cs.meta
generated
Normal file
3
Assets/Scripts/OpenTS2/Content/DBPF/NeighborhoodObjectAsset.cs.meta
generated
Normal file
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2817bdbb142146e69613242edf3d8f21
|
||||
timeCreated: 1689819849
|
|
@ -26,6 +26,7 @@ namespace OpenTS2.Files.Formats.DBPF
|
|||
public const uint NHOOD_INFO = 0xAC8A7A2E;
|
||||
// Called neighborhood "occupants" in game.
|
||||
public const uint NHOOD_DECORATIONS = 0xABD0DC63;
|
||||
public const uint NHOOD_OBJECT = 0x6D619378;
|
||||
public const uint SCENEGRAPH_GMDC = Scenegraph.Block.GeometryDataContainerBlock.TYPE_ID;
|
||||
public const uint STR = 0x53545223;
|
||||
public const uint IMG = 0x856DDBAC;
|
||||
|
|
|
@ -47,8 +47,9 @@ namespace OpenTS2.Files.Formats.DBPF
|
|||
private static FloraDecoration[] ReadFlora(IoBuffer reader)
|
||||
{
|
||||
var version = reader.ReadUInt16();
|
||||
// Versions above this are read differently but don't seem to exist in practice.
|
||||
Debug.Assert(version >= 6);
|
||||
// Versions above this are read differently (e.g they don't have individual objectVersion fields inside)
|
||||
// but don't seem to exist in practice.
|
||||
Debug.Assert(version > 7);
|
||||
|
||||
var count = reader.ReadUInt32();
|
||||
var flora = new FloraDecoration[count];
|
||||
|
@ -57,21 +58,14 @@ namespace OpenTS2.Files.Formats.DBPF
|
|||
{
|
||||
var position = ReadDecorationPosition(reader);
|
||||
var objectVersion = reader.ReadByte();
|
||||
// Same as above, there is code to handle versions below this in the game but these don't seem to exist
|
||||
// and don't even have a rotation or GUID.
|
||||
Debug.Assert(objectVersion > 7);
|
||||
|
||||
var rotation = 0.0f;
|
||||
if (objectVersion >= 7)
|
||||
{
|
||||
rotation = reader.ReadFloat();
|
||||
}
|
||||
|
||||
var rotation = reader.ReadFloat();
|
||||
position.Rotation = rotation;
|
||||
|
||||
uint objectId = 0;
|
||||
if (objectVersion > 7)
|
||||
{
|
||||
objectId = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
var objectId = reader.ReadUInt32();
|
||||
flora[i] = new FloraDecoration(position, objectId);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using OpenTS2.Common;
|
||||
using OpenTS2.Content;
|
||||
using OpenTS2.Content.DBPF;
|
||||
using OpenTS2.Files.Formats.XML;
|
||||
|
||||
namespace OpenTS2.Files.Formats.DBPF
|
||||
{
|
||||
[Codec(TypeIDs.NHOOD_OBJECT)]
|
||||
public class NeighborhoodObjectCodec : AbstractCodec
|
||||
{
|
||||
public override AbstractAsset Deserialize(byte[] bytes, ResourceKey tgi, DBPFFile sourceFile)
|
||||
{
|
||||
var propertySet = new PropertySet(Encoding.UTF8.GetString(bytes));
|
||||
|
||||
var modelName = propertySet.GetProperty<StringProp>("modelname").Value;
|
||||
// Yup, the game just tacks on a _cres to the end of this.
|
||||
if (!modelName.EndsWith("_cres"))
|
||||
{
|
||||
modelName += "_cres";
|
||||
}
|
||||
|
||||
return new NeighborhoodObjectAsset(
|
||||
modelName,
|
||||
propertySet.GetProperty<Uint32Prop>("guid").Value);
|
||||
}
|
||||
}
|
||||
}
|
3
Assets/Scripts/OpenTS2/Files/Formats/DBPF/NeighborhoodObjectCodec.cs.meta
generated
Normal file
3
Assets/Scripts/OpenTS2/Files/Formats/DBPF/NeighborhoodObjectCodec.cs.meta
generated
Normal file
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dfc8dbc0be2a4fc4b646e74ae9dfb3f6
|
||||
timeCreated: 1689819769
|
3
Assets/Scripts/OpenTS2/Files/Formats/XML.meta
generated
Normal file
3
Assets/Scripts/OpenTS2/Files/Formats/XML.meta
generated
Normal file
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7d1809ee5d5a4b6fad8a81f87bf3b9f9
|
||||
timeCreated: 1689816978
|
70
Assets/Scripts/OpenTS2/Files/Formats/XML/PropertySet.cs
Normal file
70
Assets/Scripts/OpenTS2/Files/Formats/XML/PropertySet.cs
Normal file
|
@ -0,0 +1,70 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace OpenTS2.Files.Formats.XML
|
||||
{
|
||||
/// <summary>
|
||||
/// A cGZPropertySetString element that stores strings keys and arbitrary values in xml files.
|
||||
/// </summary>
|
||||
public class PropertySet
|
||||
{
|
||||
public Dictionary<string, IPropertyType> Properties { get; } = new Dictionary<string, IPropertyType>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a property of a particular type. Throws if type does not match.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public T GetProperty<T>(string key) where T: IPropertyType
|
||||
{
|
||||
if (Properties[key] is T type)
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
throw new ArgumentException($"{key} is of type {Properties[key].GetType()}, not {typeof(T)}");
|
||||
}
|
||||
|
||||
public PropertySet(string xml)
|
||||
{
|
||||
var parsed = XElement.Parse(xml);
|
||||
if (parsed.Name.LocalName != "cGZPropertySetString")
|
||||
{
|
||||
throw new ArgumentException("cGZPropertySetString not in xml");
|
||||
}
|
||||
|
||||
foreach (var property in parsed.Elements())
|
||||
{
|
||||
var key = property.Attribute("key")?.Value;
|
||||
if (key == null)
|
||||
throw new ArgumentException("Property with no key attribute: " + property);
|
||||
|
||||
var innerText = string.Concat(property.Nodes());
|
||||
IPropertyType value = property.Name.LocalName switch
|
||||
{
|
||||
"AnyString" => new StringProp { Value = innerText },
|
||||
"AnyUint32" => new Uint32Prop { Value = uint.Parse(innerText) },
|
||||
_ => null
|
||||
};
|
||||
Properties[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface IPropertyType
|
||||
{
|
||||
}
|
||||
|
||||
public struct StringProp : IPropertyType
|
||||
{
|
||||
public string Value;
|
||||
}
|
||||
|
||||
public struct Uint32Prop : IPropertyType
|
||||
{
|
||||
public uint Value;
|
||||
}
|
||||
}
|
3
Assets/Scripts/OpenTS2/Files/Formats/XML/PropertySet.cs.meta
generated
Normal file
3
Assets/Scripts/OpenTS2/Files/Formats/XML/PropertySet.cs.meta
generated
Normal file
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e330210470394dc19ec5972e68b97ed3
|
||||
timeCreated: 1689816018
|
|
@ -0,0 +1,25 @@
|
|||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using OpenTS2.Content;
|
||||
using OpenTS2.Content.DBPF;
|
||||
using OpenTS2.Files.Formats.DBPF;
|
||||
|
||||
public class NeighborhoodObjectCodecTest
|
||||
{
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
TestMain.Initialize();
|
||||
ContentProvider.Get().AddPackage("TestAssets/Codecs/NeighborhoodDecorations.package");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSuccessfullyLoadsNeighborhoodObject()
|
||||
{
|
||||
var objectAsset = ContentProvider.Get()
|
||||
.GetAssetsOfType<NeighborhoodObjectAsset>(TypeIDs.NHOOD_OBJECT).Single();
|
||||
|
||||
Assert.That(objectAsset.ModelName, Is.EqualTo("ufoCrash_cres"));
|
||||
Assert.That(objectAsset.Guid, Is.EqualTo(0x16));
|
||||
}
|
||||
}
|
3
Assets/Tests/OpenTS2/Files/Formats/DBPF/NeighborhoodObjectCodecTest.cs.meta
generated
Normal file
3
Assets/Tests/OpenTS2/Files/Formats/DBPF/NeighborhoodObjectCodecTest.cs.meta
generated
Normal file
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d86756d05ef7430e842b66f542ba6195
|
||||
timeCreated: 1689820647
|
3
Assets/Tests/OpenTS2/Files/Formats/XML.meta
generated
Normal file
3
Assets/Tests/OpenTS2/Files/Formats/XML.meta
generated
Normal file
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 62012cc9c4b840519ad97f4121e0d761
|
||||
timeCreated: 1689817013
|
58
Assets/Tests/OpenTS2/Files/Formats/XML/PropertySetTest.cs
Normal file
58
Assets/Tests/OpenTS2/Files/Formats/XML/PropertySetTest.cs
Normal file
|
@ -0,0 +1,58 @@
|
|||
using System;
|
||||
using NUnit.Framework;
|
||||
using OpenTS2.Files.Formats.XML;
|
||||
|
||||
public class PropertySetTest
|
||||
{
|
||||
// Note: the double double-quotes in these tests are because we use the C#
|
||||
// @"string" feature.
|
||||
[Test]
|
||||
public void ParsesPropertySetSuccessfully()
|
||||
{
|
||||
const string xml = @"<?xml version=""1.0"" encoding=""UTF-8""?>
|
||||
<cGZPropertySetString>
|
||||
<AnyUint32 key=""key-with-int"" type=""0xeb61e4f7"">42</AnyUint32>
|
||||
<AnyString key=""key-with-string"" type=""0x0b8bea18"">hello world</AnyString>
|
||||
</cGZPropertySetString>";
|
||||
var set = new PropertySet(xml);
|
||||
|
||||
Assert.That(set.Properties, Contains.Key("key-with-int"));
|
||||
Assert.That(set.Properties, Contains.Key("key-with-string"));
|
||||
Assert.That(set.GetProperty<StringProp>("key-with-string").Value, Is.EqualTo("hello world"));
|
||||
Assert.That(set.GetProperty<Uint32Prop>("key-with-int").Value, Is.EqualTo(42));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetPropertyThrowsWhenTypeDoesNotMatch()
|
||||
{
|
||||
const string xml = @"
|
||||
<cGZPropertySetString>
|
||||
<AnyUint32 key=""key-with-int"" type=""0xeb61e4f7"">42</AnyUint32>
|
||||
</cGZPropertySetString>";
|
||||
var set = new PropertySet(xml);
|
||||
|
||||
Assert.That(set.Properties, Contains.Key("key-with-int"));
|
||||
Assert.Throws<ArgumentException>(() => set.GetProperty<StringProp>("key-with-int"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParserFailsWhenXmlDoesNotHaveCorrectElement()
|
||||
{
|
||||
const string xml = @"<?xml version=""1.0"" encoding=""UTF-8""?>
|
||||
<oops>
|
||||
</oops>";
|
||||
|
||||
Assert.Throws<ArgumentException>(() => new PropertySet(xml));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParseFailsWhenPropertyDoesNotHaveKey()
|
||||
{
|
||||
const string xml = @"<?xml version=""1.0"" encoding=""UTF-8""?>
|
||||
<cGZPropertySetString>
|
||||
<AnyUint32 type=""0xeb61e4f7"">42</AnyUint32>
|
||||
</cGZPropertySetString>";
|
||||
|
||||
Assert.Throws<ArgumentException>(() => new PropertySet(xml));
|
||||
}
|
||||
}
|
3
Assets/Tests/OpenTS2/Files/Formats/XML/PropertySetTest.cs.meta
generated
Normal file
3
Assets/Tests/OpenTS2/Files/Formats/XML/PropertySetTest.cs.meta
generated
Normal file
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c3226a0fd5ee4fa7a7a24d5d027b8ab7
|
||||
timeCreated: 1689817764
|
Binary file not shown.
Loading…
Reference in a new issue