Compare commits
5 Commits
354155db20
...
9e115b6906
Author | SHA1 | Date |
---|---|---|
Jarrod Doyle | 9e115b6906 | |
Jarrod Doyle | 6f87bc6904 | |
Jarrod Doyle | 001b6a944e | |
Jarrod Doyle | a6e667e1da | |
Jarrod Doyle | 963ab721cd |
|
@ -66,3 +66,8 @@ public class GenericChunk : IChunk
|
|||
writer.Write(Data);
|
||||
}
|
||||
}
|
||||
|
||||
public interface IMergable
|
||||
{
|
||||
public abstract void Merge(IMergable other);
|
||||
}
|
|
@ -34,7 +34,7 @@ public record LinkId
|
|||
}
|
||||
}
|
||||
|
||||
public class LinkChunk : IChunk
|
||||
public class LinkChunk : IChunk, IMergable
|
||||
{
|
||||
public record Link
|
||||
{
|
||||
|
@ -68,9 +68,15 @@ public class LinkChunk : IChunk
|
|||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public void Merge(IMergable other)
|
||||
{
|
||||
links.AddRange(((LinkChunk)other).links);
|
||||
}
|
||||
}
|
||||
|
||||
public class LinkDataMetaProp : IChunk
|
||||
// TODO: This should be generic like Property
|
||||
public class LinkDataMetaProp : IChunk, IMergable
|
||||
{
|
||||
public record LinkData
|
||||
{
|
||||
|
@ -102,4 +108,9 @@ public class LinkDataMetaProp : IChunk
|
|||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public void Merge(IMergable other)
|
||||
{
|
||||
linkData.AddRange(((LinkDataMetaProp)other).linkData);
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ public class Property
|
|||
}
|
||||
}
|
||||
|
||||
public class PropertyChunk<T> : IChunk where T : Property, new()
|
||||
public class PropertyChunk<T> : IChunk, IMergable where T : Property, new()
|
||||
{
|
||||
public ChunkHeader Header { get; set; }
|
||||
public List<T> properties;
|
||||
|
@ -38,6 +38,11 @@ public class PropertyChunk<T> : IChunk where T : Property, new()
|
|||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public void Merge(IMergable other)
|
||||
{
|
||||
properties.AddRange(((PropertyChunk<T>)other).properties);
|
||||
}
|
||||
}
|
||||
|
||||
public class PropGeneric : Property
|
||||
|
@ -111,3 +116,14 @@ public class PropString : Property
|
|||
// value = tmpName[..Math.Min(length - 1, tmpName.Length)];
|
||||
}
|
||||
}
|
||||
|
||||
public class PropFloat : Property
|
||||
{
|
||||
public float value;
|
||||
|
||||
public override void Read(BinaryReader reader)
|
||||
{
|
||||
base.Read(reader);
|
||||
value = reader.ReadSingle();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,6 +109,7 @@ public class DbFile
|
|||
"P$OTxtRepr1" => new PropertyChunk<PropString>(),
|
||||
"P$OTxtRepr2" => new PropertyChunk<PropString>(),
|
||||
"P$OTxtRepr3" => new PropertyChunk<PropString>(),
|
||||
"P$RenderAlp" => new PropertyChunk<PropFloat>(),
|
||||
"LD$MetaProp" => new LinkDataMetaProp(),
|
||||
_ when entryName.StartsWith("L$") => new LinkChunk(),
|
||||
_ when entryName.StartsWith("P$") => new PropertyChunk<PropGeneric>(),
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using KeepersCompound.LGS.Database.Chunks;
|
||||
|
||||
|
@ -35,112 +36,69 @@ public class ObjectHierarchy
|
|||
{
|
||||
_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("P$OTxtRepr0", out var txtRepl0Raw) &&
|
||||
db.Chunks.TryGetValue("P$OTxtRepr1", out var txtRepl1Raw) &&
|
||||
db.Chunks.TryGetValue("P$OTxtRepr2", out var txtRepl2Raw) &&
|
||||
db.Chunks.TryGetValue("P$OTxtRepr3", out var txtRepl3Raw) &&
|
||||
db.Chunks.TryGetValue("L$MetaProp", out var metaPropLinksRaw) &&
|
||||
db.Chunks.TryGetValue("LD$MetaProp", out var metaPropLinkDataRaw))
|
||||
T GetMergedChunk<T>(string name) where T : IMergable
|
||||
{
|
||||
var modelNames = (PropertyChunk<PropModelName>)modelNamesRaw;
|
||||
var scales = (PropertyChunk<PropScale>)scalesRaw;
|
||||
var renderTypes = (PropertyChunk<PropRenderType>)renderTypesRaw;
|
||||
var txtRepl0s = (PropertyChunk<PropString>)txtRepl0Raw;
|
||||
var txtRepl1s = (PropertyChunk<PropString>)txtRepl1Raw;
|
||||
var txtRepl2s = (PropertyChunk<PropString>)txtRepl2Raw;
|
||||
var txtRepl3s = (PropertyChunk<PropString>)txtRepl3Raw;
|
||||
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("P$OTxtRepr0", out var gamTxtRepl0s) &&
|
||||
gam.Chunks.TryGetValue("P$OTxtRepr1", out var gamTxtRepl1s) &&
|
||||
gam.Chunks.TryGetValue("P$OTxtRepr2", out var gamTxtRepl2s) &&
|
||||
gam.Chunks.TryGetValue("P$OTxtRepr3", out var gamTxtRepl3s) &&
|
||||
gam.Chunks.TryGetValue("L$MetaProp", out var gamLinks) &&
|
||||
gam.Chunks.TryGetValue("LD$MetaProp", out var gamLinkData))
|
||||
if (db.Chunks.TryGetValue(name, out var rawChunk))
|
||||
{
|
||||
modelNames.properties.AddRange(((PropertyChunk<PropModelName>)gamModelNames).properties);
|
||||
scales.properties.AddRange(((PropertyChunk<PropScale>)gamScales).properties);
|
||||
renderTypes.properties.AddRange(((PropertyChunk<PropRenderType>)gamRenderTypes).properties);
|
||||
txtRepl0s.properties.AddRange(((PropertyChunk<PropString>)gamTxtRepl0s).properties);
|
||||
txtRepl1s.properties.AddRange(((PropertyChunk<PropString>)gamTxtRepl1s).properties);
|
||||
txtRepl2s.properties.AddRange(((PropertyChunk<PropString>)gamTxtRepl2s).properties);
|
||||
txtRepl3s.properties.AddRange(((PropertyChunk<PropString>)gamTxtRepl3s).properties);
|
||||
metaPropLinks.links.AddRange(((LinkChunk)gamLinks).links);
|
||||
metaPropLinkData.linkData.AddRange(((LinkDataMetaProp)gamLinkData).linkData);
|
||||
var chunk = (T)rawChunk;
|
||||
if (gam != null && gam.Chunks.TryGetValue(name, out var rawGamChunk))
|
||||
{
|
||||
var gamChunk = (T)rawGamChunk;
|
||||
chunk.Merge(gamChunk);
|
||||
}
|
||||
return chunk;
|
||||
}
|
||||
|
||||
// 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));
|
||||
}
|
||||
throw new ArgumentException($"No chunk with name ({name}) found", nameof(name));
|
||||
}
|
||||
|
||||
if (linkData.priority == 0)
|
||||
{
|
||||
_objects[childId].parentId = parentId;
|
||||
}
|
||||
// Add parentages
|
||||
var metaPropLinks = GetMergedChunk<LinkChunk>("L$MetaProp");
|
||||
var metaPropLinkData = GetMergedChunk<LinkDataMetaProp>("LD$MetaProp");
|
||||
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));
|
||||
}
|
||||
|
||||
void TryAddProp(string propName, Property prop)
|
||||
if (linkData.priority == 0)
|
||||
{
|
||||
_objects[childId].parentId = parentId;
|
||||
}
|
||||
}
|
||||
|
||||
void AddProp<T>(string name) where T : Property, new()
|
||||
{
|
||||
var chunk = GetMergedChunk<PropertyChunk<T>>(name);
|
||||
foreach (var prop in chunk.properties)
|
||||
{
|
||||
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);
|
||||
}
|
||||
foreach (var prop in txtRepl0s.properties)
|
||||
{
|
||||
TryAddProp("P$OTxtRepr0", prop);
|
||||
}
|
||||
foreach (var prop in txtRepl1s.properties)
|
||||
{
|
||||
TryAddProp("P$OTxtRepr1", prop);
|
||||
}
|
||||
foreach (var prop in txtRepl2s.properties)
|
||||
{
|
||||
TryAddProp("P$OTxtRepr2", prop);
|
||||
}
|
||||
foreach (var prop in txtRepl3s.properties)
|
||||
{
|
||||
TryAddProp("P$OTxtRepr3", prop);
|
||||
_objects[id].properties.TryAdd(name, prop);
|
||||
}
|
||||
}
|
||||
|
||||
AddProp<PropModelName>("P$ModelName");
|
||||
AddProp<PropScale>("P$Scale");
|
||||
AddProp<PropRenderType>("P$RenderTyp");
|
||||
AddProp<PropString>("P$OTxtRepr0");
|
||||
AddProp<PropString>("P$OTxtRepr1");
|
||||
AddProp<PropString>("P$OTxtRepr2");
|
||||
AddProp<PropString>("P$OTxtRepr3");
|
||||
AddProp<PropFloat>("P$RenderAlp");
|
||||
}
|
||||
|
||||
public T GetProperty<T>(int objectId, string propName) where T : Property
|
||||
|
|
|
@ -62,6 +62,11 @@ public class ResourcePathManager
|
|||
_extractionPath = extractionPath;
|
||||
}
|
||||
|
||||
public static string ConvertSeparator(string path)
|
||||
{
|
||||
return path.Replace('\\', '/');
|
||||
}
|
||||
|
||||
public bool Init(string installPath)
|
||||
{
|
||||
// TODO: This can be done less awkwardly with the resource paths
|
||||
|
@ -156,6 +161,7 @@ public class ResourcePathManager
|
|||
throw new ArgumentException("No campaign found with given name", nameof(campaignName));
|
||||
}
|
||||
|
||||
// This expects resourceName to already have it's separator converted
|
||||
public (string, string) GetResourcePath(
|
||||
ResourceType type,
|
||||
string campaignName,
|
||||
|
@ -206,11 +212,12 @@ public class ResourcePathManager
|
|||
{
|
||||
foreach (var path in Directory.EnumerateFiles(dir, "*", texOptions))
|
||||
{
|
||||
var ext = Path.GetExtension(path);
|
||||
var convertedPath = ConvertSeparator(path);
|
||||
var ext = Path.GetExtension(convertedPath);
|
||||
if (validExtensions.Contains(ext.ToLower()))
|
||||
{
|
||||
var key = Path.GetFileNameWithoutExtension(path).ToLower();
|
||||
pathMap.TryAdd(key, path);
|
||||
var key = Path.GetFileNameWithoutExtension(convertedPath).ToLower();
|
||||
pathMap.TryAdd(key, convertedPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -234,11 +241,12 @@ public class ResourcePathManager
|
|||
{
|
||||
foreach (var path in Directory.EnumerateFiles(dir, "*", textureOptions))
|
||||
{
|
||||
var ext = Path.GetExtension(path);
|
||||
var convertedPath = ConvertSeparator(path);
|
||||
var ext = Path.GetExtension(convertedPath);
|
||||
if (validExtensions.Contains(ext.ToLower()))
|
||||
{
|
||||
var key = Path.GetRelativePath(root, path)[..^ext.Length].ToLower();
|
||||
pathMap.TryAdd(key, path);
|
||||
var key = Path.GetRelativePath(root, convertedPath)[..^ext.Length].ToLower();
|
||||
pathMap.TryAdd(key, convertedPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -260,8 +268,9 @@ public class ResourcePathManager
|
|||
{
|
||||
foreach (var path in Directory.EnumerateFiles(dir, "*.bin", binOptions))
|
||||
{
|
||||
var key = Path.GetRelativePath(dir, path).ToLower();
|
||||
pathMap.TryAdd(key, path);
|
||||
var convertedPath = ConvertSeparator(path);
|
||||
var key = Path.GetRelativePath(dir, convertedPath).ToLower();
|
||||
pathMap.TryAdd(key, convertedPath);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -277,8 +286,8 @@ public class ResourcePathManager
|
|||
{
|
||||
if (line.StartsWith("load_path"))
|
||||
{
|
||||
// TODO: Do we only need to replace on systems with a different path separator?
|
||||
var path = line.Split(" ")[1].Replace("\\", "/");
|
||||
// TODO: This can have multiple paths I think
|
||||
var path = ConvertSeparator(line.Split(" ")[1]);
|
||||
omsPath = Path.GetFullPath(root + path);
|
||||
break;
|
||||
}
|
||||
|
@ -294,8 +303,9 @@ public class ResourcePathManager
|
|||
};
|
||||
foreach (var path in Directory.GetFiles(omsPath, "*.mis", searchOptions))
|
||||
{
|
||||
var baseName = Path.GetFileName(path).ToLower();
|
||||
map.Add(baseName, path);
|
||||
var convertedPath = ConvertSeparator(path);
|
||||
var baseName = Path.GetFileName(convertedPath).ToLower();
|
||||
map.Add(baseName, convertedPath);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -329,7 +339,7 @@ public class ResourcePathManager
|
|||
if (line.StartsWith("fm_path"))
|
||||
{
|
||||
// TODO: I think this can technically contain multiple paths
|
||||
var path = line.Split(" ")[1].Replace("\\", "/");
|
||||
var path = ConvertSeparator(line.Split(" ")[1]);
|
||||
fmsPath = Path.GetFullPath(root + path);
|
||||
break;
|
||||
}
|
||||
|
@ -344,10 +354,11 @@ public class ResourcePathManager
|
|||
var campaignMap = new Dictionary<string, string>();
|
||||
foreach (var path in Directory.GetFiles(dir))
|
||||
{
|
||||
if (extensions.Contains(Path.GetExtension(path).ToLower()))
|
||||
var convertedPath = ConvertSeparator(path);
|
||||
if (extensions.Contains(Path.GetExtension(convertedPath).ToLower()))
|
||||
{
|
||||
var baseName = Path.GetFileName(path).ToLower();
|
||||
campaignMap.Add(baseName, path);
|
||||
var baseName = Path.GetFileName(convertedPath).ToLower();
|
||||
campaignMap.Add(baseName, ConvertSeparator(path));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,8 @@ public partial class Mission : Node3D
|
|||
}
|
||||
}
|
||||
|
||||
private const string OBJECT_MODELS_GROUP = "ObjectModels";
|
||||
|
||||
[Export(PropertyHint.GlobalFile, "*.mis")]
|
||||
public string FileName { get; set; }
|
||||
[Export]
|
||||
|
@ -94,10 +96,14 @@ public partial class Mission : Node3D
|
|||
{
|
||||
Build = true;
|
||||
}
|
||||
if (keyEvent.Keycode == Key.O)
|
||||
if (keyEvent.Keycode == Key.L)
|
||||
{
|
||||
ToggleLightmap();
|
||||
}
|
||||
if (keyEvent.Keycode == Key.O)
|
||||
{
|
||||
ToggleObjectRendering();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,6 +133,17 @@ public partial class Mission : Node3D
|
|||
}
|
||||
}
|
||||
|
||||
public void ToggleObjectRendering()
|
||||
{
|
||||
// It might be "better" to use a parent node and just toggle that, but
|
||||
// the performance of this is completely fine so we'll stick with it
|
||||
foreach (var node in GetTree().GetNodesInGroup(OBJECT_MODELS_GROUP))
|
||||
{
|
||||
var node3d = node as Node3D;
|
||||
node3d.Visible = !node3d.Visible;
|
||||
}
|
||||
}
|
||||
|
||||
public void ToggleLightmap()
|
||||
{
|
||||
if (_lmLayerMask == Vector2I.Zero)
|
||||
|
@ -236,6 +253,7 @@ public partial class Mission : Node3D
|
|||
var txtRepl1 = objHierarchy.GetProperty<PropString>(id, "P$OTxtRepr1");
|
||||
var txtRepl2 = objHierarchy.GetProperty<PropString>(id, "P$OTxtRepr2");
|
||||
var txtRepl3 = objHierarchy.GetProperty<PropString>(id, "P$OTxtRepr3");
|
||||
var renderAlpha = objHierarchy.GetProperty<PropFloat>(id, "P$RenderAlp");
|
||||
var renderMode = renderTypeProp == null ? PropRenderType.Mode.Normal : renderTypeProp.mode;
|
||||
|
||||
if (modelNameProp == null || renderMode == PropRenderType.Mode.NotRendered)
|
||||
|
@ -278,7 +296,8 @@ public partial class Mission : Node3D
|
|||
else
|
||||
{
|
||||
var resType = ResourceType.ObjectTexture;
|
||||
var resName = Path.GetFileNameWithoutExtension(prop.value);
|
||||
var convertedValue = ResourcePathManager.ConvertSeparator(prop.value);
|
||||
var resName = Path.GetFileNameWithoutExtension(convertedValue);
|
||||
path = pathManager.GetResourcePath(resType, _campaignName, resName).Item2;
|
||||
}
|
||||
|
||||
|
@ -308,6 +327,13 @@ public partial class Mission : Node3D
|
|||
}
|
||||
}
|
||||
|
||||
if (renderAlpha != null)
|
||||
{
|
||||
model.Transparency = 1.0f - renderAlpha.value;
|
||||
}
|
||||
|
||||
model.AddToGroup(OBJECT_MODELS_GROUP);
|
||||
|
||||
AddChild(model);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,8 @@ public class ModelLoader
|
|||
{
|
||||
if (material.Type == 0)
|
||||
{
|
||||
var resName = Path.GetFileNameWithoutExtension(material.Name);
|
||||
var convertedName = ResourcePathManager.ConvertSeparator(material.Name);
|
||||
var resName = Path.GetFileNameWithoutExtension(convertedName);
|
||||
var (_, path) = pathManager.GetResourcePath(ResourceType.ObjectTexture, campaignName, resName);
|
||||
if (path == null)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue