Compare commits
No commits in common. "2365f0993156e850d80b5b8795a0f46518fa6ad2" and "8aa1c7c4bce36deec7a3f8b7f62da8f6d3608b5b" have entirely different histories.
2365f09931
...
8aa1c7c4bc
|
@ -107,7 +107,6 @@ public class DbFile
|
||||||
"P$RenderTyp" => new PropertyChunk<PropRenderType>(),
|
"P$RenderTyp" => new PropertyChunk<PropRenderType>(),
|
||||||
"LD$MetaProp" => new LinkDataMetaProp(),
|
"LD$MetaProp" => new LinkDataMetaProp(),
|
||||||
_ when entryName.StartsWith("L$") => new LinkChunk(),
|
_ when entryName.StartsWith("L$") => new LinkChunk(),
|
||||||
_ when entryName.StartsWith("P$") => new PropertyChunk<PropGeneric>(),
|
|
||||||
_ => new GenericChunk(),
|
_ => new GenericChunk(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,139 +0,0 @@
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using KeepersCompound.LGS.Database.Chunks;
|
|
||||||
|
|
||||||
namespace KeepersCompound.LGS.Database;
|
|
||||||
|
|
||||||
public class ObjectHierarchy
|
|
||||||
{
|
|
||||||
public class DarkObject
|
|
||||||
{
|
|
||||||
public int objectId;
|
|
||||||
public int parentId;
|
|
||||||
public Dictionary<string, Property> properties;
|
|
||||||
|
|
||||||
public DarkObject(int id)
|
|
||||||
{
|
|
||||||
objectId = id;
|
|
||||||
parentId = 0;
|
|
||||||
properties = new Dictionary<string, Property>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public T GetProperty<T>(string propName) where T : Property
|
|
||||||
{
|
|
||||||
if (properties.TryGetValue(propName, out var prop))
|
|
||||||
{
|
|
||||||
return (T)prop;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Dictionary<int, DarkObject> _objects;
|
|
||||||
|
|
||||||
public ObjectHierarchy(DbFile db, DbFile gam = null)
|
|
||||||
{
|
|
||||||
_objects = new Dictionary<int, DarkObject>();
|
|
||||||
|
|
||||||
if (db.Chunks.TryGetValue("P$ModelName", out var modelNamesRaw) &&
|
|
||||||
db.Chunks.TryGetValue("P$Scale", out var scalesRaw) &&
|
|
||||||
db.Chunks.TryGetValue("P$RenderTyp", out var renderTypesRaw) &&
|
|
||||||
db.Chunks.TryGetValue("L$MetaProp", out var metaPropLinksRaw) &&
|
|
||||||
db.Chunks.TryGetValue("LD$MetaProp", out var metaPropLinkDataRaw))
|
|
||||||
{
|
|
||||||
var modelNames = (PropertyChunk<PropModelName>)modelNamesRaw;
|
|
||||||
var scales = (PropertyChunk<PropScale>)scalesRaw;
|
|
||||||
var renderTypes = (PropertyChunk<PropRenderType>)renderTypesRaw;
|
|
||||||
var metaPropLinks = (LinkChunk)metaPropLinksRaw;
|
|
||||||
var metaPropLinkData = (LinkDataMetaProp)metaPropLinkDataRaw;
|
|
||||||
|
|
||||||
// Merge gam chunks
|
|
||||||
if (gam != null &&
|
|
||||||
gam.Chunks.TryGetValue("P$ModelName", out var gamModelNames) &&
|
|
||||||
gam.Chunks.TryGetValue("P$Scale", out var gamScales) &&
|
|
||||||
gam.Chunks.TryGetValue("P$RenderTyp", out var gamRenderTypes) &&
|
|
||||||
gam.Chunks.TryGetValue("L$MetaProp", out var gamLinks) &&
|
|
||||||
gam.Chunks.TryGetValue("LD$MetaProp", out var gamLinkData))
|
|
||||||
{
|
|
||||||
modelNames.properties.AddRange(((PropertyChunk<PropModelName>)gamModelNames).properties);
|
|
||||||
scales.properties.AddRange(((PropertyChunk<PropScale>)gamScales).properties);
|
|
||||||
renderTypes.properties.AddRange(((PropertyChunk<PropRenderType>)gamRenderTypes).properties);
|
|
||||||
metaPropLinks.links.AddRange(((LinkChunk)gamLinks).links);
|
|
||||||
metaPropLinkData.linkData.AddRange(((LinkDataMetaProp)gamLinkData).linkData);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add parentages
|
|
||||||
var length = metaPropLinks.links.Count;
|
|
||||||
for (var i = 0; i < length; i++)
|
|
||||||
{
|
|
||||||
var link = metaPropLinks.links[i];
|
|
||||||
var linkData = metaPropLinkData.linkData[i];
|
|
||||||
var childId = link.source;
|
|
||||||
var parentId = link.destination;
|
|
||||||
if (!_objects.ContainsKey(childId))
|
|
||||||
{
|
|
||||||
_objects.Add(childId, new DarkObject(childId));
|
|
||||||
}
|
|
||||||
if (!_objects.ContainsKey(parentId))
|
|
||||||
{
|
|
||||||
_objects.Add(parentId, new DarkObject(parentId));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (linkData.priority == 0)
|
|
||||||
{
|
|
||||||
_objects[childId].parentId = parentId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TryAddProp(string propName, Property prop)
|
|
||||||
{
|
|
||||||
var id = prop.objectId;
|
|
||||||
if (!_objects.ContainsKey(id))
|
|
||||||
{
|
|
||||||
_objects.Add(id, new DarkObject(id));
|
|
||||||
}
|
|
||||||
_objects[id].properties.TryAdd(propName, prop);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Find a way to do this better
|
|
||||||
foreach (var prop in modelNames.properties)
|
|
||||||
{
|
|
||||||
TryAddProp("P$ModelName", prop);
|
|
||||||
}
|
|
||||||
foreach (var prop in scales.properties)
|
|
||||||
{
|
|
||||||
TryAddProp("P$Scale", prop);
|
|
||||||
}
|
|
||||||
foreach (var prop in renderTypes.properties)
|
|
||||||
{
|
|
||||||
TryAddProp("P$RenderTyp", prop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T GetProperty<T>(int objectId, string propName) where T : Property
|
|
||||||
{
|
|
||||||
if (!_objects.ContainsKey(objectId))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var parentId = objectId;
|
|
||||||
while (parentId != 0)
|
|
||||||
{
|
|
||||||
if (!_objects.TryGetValue(parentId, out var obj))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var prop = obj.GetProperty<T>(propName);
|
|
||||||
if (prop != null)
|
|
||||||
{
|
|
||||||
return prop;
|
|
||||||
}
|
|
||||||
parentId = obj.parentId;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -101,32 +101,54 @@ public partial class Mission : Node3D
|
||||||
_file = new(FileName);
|
_file = new(FileName);
|
||||||
UseChunk<TxList>("TXLIST", LoadTextures);
|
UseChunk<TxList>("TXLIST", LoadTextures);
|
||||||
UseChunk<WorldRep>("WREXT", BuildWrMeshes);
|
UseChunk<WorldRep>("WREXT", BuildWrMeshes);
|
||||||
|
|
||||||
ObjectHierarchy objHierarchy;
|
|
||||||
if (_file.Chunks.TryGetValue("GAM_FILE", out var gamFileChunk))
|
|
||||||
{
|
|
||||||
|
|
||||||
var options = new EnumerationOptions { MatchCasing = MatchCasing.CaseInsensitive };
|
|
||||||
var name = ((GamFile)gamFileChunk).fileName;
|
|
||||||
var paths = Directory.GetFiles(FileName.GetBaseDir(), name, options);
|
|
||||||
if (!paths.IsEmpty())
|
|
||||||
{
|
|
||||||
objHierarchy = new ObjectHierarchy(_file, new DbFile(paths[0]));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
objHierarchy = new ObjectHierarchy(_file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
objHierarchy = new ObjectHierarchy(_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
_file.Chunks.TryGetValue("BRLIST", out var brList))
|
_file.Chunks.TryGetValue("BRLIST", out var brListRaw) &&
|
||||||
|
_file.Chunks.TryGetValue("P$ModelName", out var modelNamesRaw) &&
|
||||||
|
_file.Chunks.TryGetValue("P$Scale", out var scalesRaw) &&
|
||||||
|
_file.Chunks.TryGetValue("P$RenderTyp", out var renderTypesRaw) &&
|
||||||
|
_file.Chunks.TryGetValue("L$MetaProp", out var metaPropLinksRaw) &&
|
||||||
|
_file.Chunks.TryGetValue("LD$MetaProp", out var metaPropLinkDataRaw)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
PlaceObjects((BrList)brList, objHierarchy);
|
var brList = (BrList)brListRaw;
|
||||||
|
var modelNames = (PropertyChunk<PropModelName>)modelNamesRaw;
|
||||||
|
var scales = (PropertyChunk<PropScale>)scalesRaw;
|
||||||
|
var renderTypes = (PropertyChunk<PropRenderType>)renderTypesRaw;
|
||||||
|
var metaPropLinks = (LinkChunk)metaPropLinksRaw;
|
||||||
|
var metaPropLinkData = (LinkDataMetaProp)metaPropLinkDataRaw;
|
||||||
|
|
||||||
|
// TODO: Do this somewhere else lol
|
||||||
|
if (_file.Chunks.TryGetValue("GAM_FILE", out var gamFileChunk))
|
||||||
|
{
|
||||||
|
GD.Print("GAM_FILE detected");
|
||||||
|
|
||||||
|
var options = new EnumerationOptions { MatchCasing = MatchCasing.CaseInsensitive };
|
||||||
|
var name = ((GamFile)gamFileChunk).fileName;
|
||||||
|
GD.Print($"Searching for GAM: {FileName.GetBaseDir()}/{name}");
|
||||||
|
var paths = Directory.GetFiles(FileName.GetBaseDir(), name, options);
|
||||||
|
GD.Print($"Found paths: {paths.Length}");
|
||||||
|
if (!paths.IsEmpty())
|
||||||
|
{
|
||||||
|
GD.Print($"Attempting to load GAM at: {paths[0]}");
|
||||||
|
var gamFile = new DbFile(paths[0]);
|
||||||
|
if (gamFile.Chunks.TryGetValue("P$ModelName", out var gamChunk1) &&
|
||||||
|
gamFile.Chunks.TryGetValue("L$MetaProp", out var gamChunk2) &&
|
||||||
|
gamFile.Chunks.TryGetValue("LD$MetaProp", out var gamChunk3) &&
|
||||||
|
gamFile.Chunks.TryGetValue("P$Scale", out var gamChunk4) &&
|
||||||
|
gamFile.Chunks.TryGetValue("P$RenderTyp", out var gamChunk5))
|
||||||
|
{
|
||||||
|
GD.Print($"Pre-Merged chunks: {modelNames.properties.Count} {metaPropLinks.links.Count} {metaPropLinkData.linkData.Count}");
|
||||||
|
modelNames.properties.AddRange(((PropertyChunk<PropModelName>)gamChunk1).properties);
|
||||||
|
metaPropLinks.links.AddRange(((LinkChunk)gamChunk2).links);
|
||||||
|
metaPropLinkData.linkData.AddRange(((LinkDataMetaProp)gamChunk3).linkData);
|
||||||
|
scales.properties.AddRange(((PropertyChunk<PropScale>)gamChunk4).properties);
|
||||||
|
renderTypes.properties.AddRange(((PropertyChunk<PropRenderType>)gamChunk5).properties);
|
||||||
|
GD.Print($"Post-Merged chunks: {modelNames.properties.Count} {metaPropLinks.links.Count} {metaPropLinkData.linkData.Count}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PlaceObjects(brList, modelNames, scales, renderTypes, metaPropLinks, metaPropLinkData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,7 +164,13 @@ public partial class Mission : Node3D
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PlaceObjects(BrList brList, ObjectHierarchy objHierarchy)
|
private void PlaceObjects(
|
||||||
|
BrList brList,
|
||||||
|
PropertyChunk<PropModelName> modelNames,
|
||||||
|
PropertyChunk<PropScale> scales,
|
||||||
|
PropertyChunk<PropRenderType> renderTypes,
|
||||||
|
LinkChunk metapropLink,
|
||||||
|
LinkDataMetaProp metaPropLinkData)
|
||||||
{
|
{
|
||||||
foreach (var brush in brList.Brushes)
|
foreach (var brush in brList.Brushes)
|
||||||
{
|
{
|
||||||
|
@ -151,27 +179,93 @@ public partial class Mission : Node3D
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Build an actual hierarchy and such :)
|
||||||
|
// TODO: We need to load the gamesys :)
|
||||||
|
// Determine if we have a model name :))
|
||||||
var id = (int)brush.brushInfo;
|
var id = (int)brush.brushInfo;
|
||||||
var modelNameProp = objHierarchy.GetProperty<PropModelName>(id, "P$ModelName");
|
var modelName = "";
|
||||||
var scaleProp = objHierarchy.GetProperty<PropScale>(id, "P$Scale");
|
var scale = Vector3.One;
|
||||||
var renderTypeProp = objHierarchy.GetProperty<PropRenderType>(id, "P$RenderTyp");
|
var scaleFound = false;
|
||||||
var renderMode = renderTypeProp == null ? PropRenderType.Mode.Normal : renderTypeProp.mode;
|
var renderType = PropRenderType.Mode.Normal;
|
||||||
|
var renderTypeFound = false;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
// See if there's a modelname property
|
||||||
|
if (modelName == "")
|
||||||
|
{
|
||||||
|
foreach (var prop in modelNames.properties)
|
||||||
|
{
|
||||||
|
if (prop.objectId == id)
|
||||||
|
{
|
||||||
|
modelName = prop.modelName;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (modelNameProp == null || renderMode == PropRenderType.Mode.NotRendered)
|
if (!scaleFound)
|
||||||
|
{
|
||||||
|
foreach (var prop in scales.properties)
|
||||||
|
{
|
||||||
|
if (prop.objectId == id)
|
||||||
|
{
|
||||||
|
scale = prop.scale.ToGodotVec3(false);
|
||||||
|
scaleFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!renderTypeFound)
|
||||||
|
{
|
||||||
|
foreach (var prop in renderTypes.properties)
|
||||||
|
{
|
||||||
|
if (prop.objectId == id)
|
||||||
|
{
|
||||||
|
renderType = prop.mode;
|
||||||
|
renderTypeFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modelName != "" && scaleFound && renderTypeFound)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for a parent
|
||||||
|
var length = metapropLink.links.Count;
|
||||||
|
var prevId = id;
|
||||||
|
for (var i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
var link = metapropLink.links[i];
|
||||||
|
var linkData = metaPropLinkData.linkData[i];
|
||||||
|
if (link.source == id && linkData.priority == 0)
|
||||||
|
{
|
||||||
|
id = link.destination;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// No parent found
|
||||||
|
if (id == prevId)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (modelName == "" || renderType == PropRenderType.Mode.NotRendered)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let's try and place an object :)
|
// Let's try and place an object :)
|
||||||
var modelName = modelNameProp.modelName + ".bin";
|
var fmName = FileName.GetBaseDir().GetFile();
|
||||||
var fmName = FileName.GetBaseDir().GetFile(); // TODO: Doesn't work for OMs
|
var objPath = _installPaths.GetObjectPath(fmName, modelName + ".bin");
|
||||||
var objPath = _installPaths.GetObjectPath(fmName, modelName);
|
objPath ??= _installPaths.GetObjectPath(modelName + ".bin");
|
||||||
objPath ??= _installPaths.GetObjectPath(modelName);
|
|
||||||
|
|
||||||
var pos = brush.position.ToGodotVec3();
|
var pos = brush.position.ToGodotVec3();
|
||||||
var rawRot = brush.angle;
|
var rawRot = brush.angle;
|
||||||
var rot = new Vector3(rawRot.Y, rawRot.Z, rawRot.X) * 360 / ushort.MaxValue;
|
var rot = new Vector3(rawRot.Y, rawRot.Z, rawRot.X) * 360 / ushort.MaxValue;
|
||||||
var scale = scaleProp == null ? Vector3.One : scaleProp.scale.ToGodotVec3(false);
|
|
||||||
var model = new Model
|
var model = new Model
|
||||||
{
|
{
|
||||||
Position = pos,
|
Position = pos,
|
||||||
|
|
Loading…
Reference in New Issue