Second commit
This commit is contained in:
commit
36840f3ad4
999 files changed
+61364
No files matched your search
@@ -0,0 +1,306 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble
|
||||
{
|
||||
public record BspOptions(float UV2Padding = 0.02f);
|
||||
|
||||
public class MapBsp
|
||||
{
|
||||
public string MapName { get; init; }
|
||||
public float ImportScale { get; init; }
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// State
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
public TexInfo[] TexInfos { get; init; }
|
||||
public Plane[] Planes { get; init; }
|
||||
public BspNode[] Nodes { get; init; }
|
||||
public BspLeaf[] Leaves { get; init; }
|
||||
public int[] LeafFaces { get; init; }
|
||||
public bool[] UsedFaces { get; init; }
|
||||
|
||||
public BspModel[] Models { get; init; }
|
||||
public BspVertex[] Vertices { get; init; }
|
||||
public BspFace[] Faces { get; init; }
|
||||
public int[] MeshVertices { get; init; }
|
||||
|
||||
public List<BspEntity> Entities { get; init; }
|
||||
|
||||
public BspOptions Options { get; init; }
|
||||
|
||||
public MapGroupData[] Groups { get; init; }
|
||||
|
||||
public void GatherResourceList(List<string> outPaths)
|
||||
{
|
||||
TrembleSyncSettings syncSettings = TrembleSyncSettings.Get();
|
||||
|
||||
MaterialNameLookup materialNameLookup = new(syncSettings);
|
||||
PrefabNameLookup prefabNameLookup = new(syncSettings);
|
||||
|
||||
GatherResourceList(materialNameLookup, prefabNameLookup, outPaths);
|
||||
}
|
||||
|
||||
public void GatherResourceList(MaterialNameLookup materialNameLookup, PrefabNameLookup prefabNameLookup, List<string> outPaths)
|
||||
{
|
||||
foreach (TexInfo texInfo in TexInfos)
|
||||
{
|
||||
if (!materialNameLookup.TryGetMaterialPathFromMapName(texInfo.Name, out string materialPath))
|
||||
continue;
|
||||
|
||||
outPaths.Add(materialPath);
|
||||
}
|
||||
|
||||
foreach (BspEntity entity in Entities)
|
||||
{
|
||||
if (!prefabNameLookup.TryGetPrefabPathFromMapName(entity.GetClassname(), out string prefabPath))
|
||||
continue;
|
||||
|
||||
outPaths.Add(prefabPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// Map Types
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
public readonly struct MapGroupData
|
||||
{
|
||||
public string Name { get; init; }
|
||||
public bool IsNoExport { get; init; }
|
||||
public bool IsLayer { get; init; }
|
||||
|
||||
public string LabelName => (IsLayer ? "layer: " : "group: ") + Name;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// BSPTypes
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
public readonly struct BspEntity : IEquatable<BspEntity>
|
||||
{
|
||||
public int SerialNumber { get; init; }
|
||||
public Dictionary<string, string> Entries { get; init; }
|
||||
public float ImportScale { get; init; }
|
||||
|
||||
public bool Equals(BspEntity other)
|
||||
{
|
||||
return other.SerialNumber == SerialNumber;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is BspEntity other && Equals(other);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return SerialNumber;
|
||||
}
|
||||
|
||||
public static bool operator ==(BspEntity left, BspEntity right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(BspEntity left, BspEntity right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct TexInfo
|
||||
{
|
||||
public string Name { get; init; }
|
||||
public int Flags { get; init; }
|
||||
public int Contents { get; init; }
|
||||
}
|
||||
|
||||
public readonly struct BspVertex
|
||||
{
|
||||
public Vector3 Position { get; init; }
|
||||
public Vector3 Normal { get; init; }
|
||||
public Color32 Color { get; init; }
|
||||
public Vector2 TexCoord { get; init; }
|
||||
public Vector2 LightmapCoord { get; init; }
|
||||
}
|
||||
|
||||
public readonly struct BspFace
|
||||
{
|
||||
public int TexID { get; init; }
|
||||
public int Effect { get; init; }
|
||||
public int Type { get; init; } // 1=polygon, 2=patch, 3=mesh, 4=billboard
|
||||
|
||||
public int VertexStartIdx { get; init; }
|
||||
public int NumVertices { get; init; }
|
||||
|
||||
public int MeshVertexStartIdx { get; init; }
|
||||
public int NumMeshVertices { get; init; }
|
||||
|
||||
public int LightmapIndex { get; init; }
|
||||
public Vector2Int LightmapStart { get; init; }
|
||||
public Vector2Int LightmapSize { get; init; }
|
||||
|
||||
public Vector3 LightmapOrigin { get; init; }
|
||||
public Vector3 LightmapVector1 { get; init; }
|
||||
public Vector3 LightmapVector2 { get; init; }
|
||||
public Vector3 Normal { get; init; }
|
||||
|
||||
public Vector2Int Size { get; init; }
|
||||
}
|
||||
|
||||
public readonly struct BspModel
|
||||
{
|
||||
public Vector3 Min { get; init; }
|
||||
public Vector3 Max { get; init; }
|
||||
|
||||
public int StartFaceIdx { get; init; }
|
||||
public int NumFaces { get; init; }
|
||||
|
||||
public int StartBrushIdx { get; init; }
|
||||
public int NumBrushes { get; init; }
|
||||
}
|
||||
|
||||
public readonly struct BspMeshVertex
|
||||
{
|
||||
public Vector3 Position { get; init; }
|
||||
public Vector3 Normal { get; init; }
|
||||
public Vector2 UV { get; init; }
|
||||
|
||||
public int BaseIndex { get; init; }
|
||||
}
|
||||
|
||||
public struct BspSubMesh
|
||||
{
|
||||
public int TexID { get; init; }
|
||||
public List<int> Triangles { get; init; }
|
||||
}
|
||||
|
||||
public readonly struct BspNode
|
||||
{
|
||||
public int PlaneIndex { get; init; }
|
||||
|
||||
public int Child1 { get; init; } // negative numbers are leafs
|
||||
public int Child2 { get; init; }
|
||||
public Vector3Int Min { get; init; }
|
||||
public Vector3Int Max { get; init; }
|
||||
}
|
||||
|
||||
public readonly struct BspLeaf
|
||||
{
|
||||
public int VisCluster { get; init; }
|
||||
public int PortalArea { get; init; }
|
||||
|
||||
public Vector3Int Min { get; init; }
|
||||
public Vector3Int Max { get; init; }
|
||||
|
||||
public int LeafFaceStartIdx { get; init; }
|
||||
public int NumLeafFaces { get; init; }
|
||||
|
||||
public int LeafBrushStartIdx { get; init; }
|
||||
public int NumLeafBrushes { get; init; }
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// MD3 Types
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
public readonly struct MD3Surface
|
||||
{
|
||||
public Vector3[] Vertices { get; init; }
|
||||
public Vector2[] Uvs { get; init; }
|
||||
public Vector3[] Normals { get; init; }
|
||||
public string Texture { get; init; }
|
||||
public string Name { get; init; }
|
||||
|
||||
public int DataSize => Vertices.Length * 16 + Vertices.Length * 4 + 176;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// Vector Conversions
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
public static class Q3VectorExtensions
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector3 Q3ToUnityVector(this Vector3 q3Vector, float scale = 1f)
|
||||
=> new Vector3(q3Vector.x, q3Vector.z, q3Vector.y) * scale;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector3 UnityToQ3Vector(this Vector3 unityVector, float scale = 1f)
|
||||
=> new Vector3(unityVector.x, unityVector.z, unityVector.y) / scale;
|
||||
|
||||
public static bool TryParseQ3Vector(this string inVector, out Vector3 value)
|
||||
{
|
||||
string[] parts = inVector.Split(" ");
|
||||
|
||||
// Vector, e.g. "x y z"
|
||||
if (parts.Length == 3 &&
|
||||
parts[0].TryParseFloat(out float x) &&
|
||||
parts[1].TryParseFloat(out float y) &&
|
||||
parts[2].TryParseFloat(out float z))
|
||||
{
|
||||
value = new(x, y, z);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Float, e.g. "x"
|
||||
if (parts.Length == 1 && parts[0].TryParseFloat(out float f))
|
||||
{
|
||||
value = new(f, f, f);
|
||||
return true;
|
||||
}
|
||||
|
||||
value = Vector3.zero;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// Colour Conversions
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
public static class Q3ColourExtensions
|
||||
{
|
||||
public static bool TryParseQ3Colour(this string inColour, out Color value)
|
||||
{
|
||||
if (inColour.IsNullOrEmpty())
|
||||
{
|
||||
value = Color.white;
|
||||
return false;
|
||||
}
|
||||
|
||||
string[] parts = inColour.Split(" ");
|
||||
if (parts.Length != 3)
|
||||
{
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parts[0].TryParseFloat(out float r)
|
||||
|| !parts[1].TryParseFloat(out float g)
|
||||
|| !parts[2].TryParseFloat(out float b))
|
||||
{
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (r > 1f || g > 1f || b > 1f)
|
||||
{
|
||||
// Assume BYTE values, 0-255
|
||||
value = new(r / 255f, g / 255f, b / 255f);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Assume FLOAT values, 0-1
|
||||
value = new(r, g, b);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a502265f744340118b51b9ce63ad42bc
|
||||
timeCreated: 1698058785
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Types/BspTypes.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,290 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble
|
||||
{
|
||||
public enum EntityType
|
||||
{
|
||||
Brush,
|
||||
Point
|
||||
}
|
||||
|
||||
public static class MapBspGetters
|
||||
{
|
||||
private static TrembleFieldConverterCollection s_ConverterCollection;
|
||||
|
||||
public static bool FindEntityById(this MapBsp mapBsp, string id, out BspEntity entity)
|
||||
{
|
||||
string identityProperty = TrembleSyncSettings.Get().IdentityPropertyName;
|
||||
|
||||
foreach (BspEntity ent in mapBsp.Entities)
|
||||
{
|
||||
if (!ent.TryGetString(identityProperty, out string foundId) || !foundId.EqualsInvariant(id, caseSensitive: true))
|
||||
continue;
|
||||
|
||||
entity = ent;
|
||||
return true;
|
||||
}
|
||||
|
||||
entity = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static List<BspEntity> FindEntitiesById(this MapBsp mapBsp, string id)
|
||||
{
|
||||
string identityProperty = TrembleSyncSettings.Get().IdentityPropertyName;
|
||||
|
||||
List<BspEntity> entities = new();
|
||||
foreach (BspEntity ent in mapBsp.Entities)
|
||||
{
|
||||
if (!ent.TryGetString(identityProperty, out string foundId) || !foundId.EqualsInvariant(id, caseSensitive: true))
|
||||
continue;
|
||||
|
||||
entities.Add(ent);
|
||||
}
|
||||
return entities;
|
||||
}
|
||||
|
||||
public static BspEntity FindFirstEntityOfClass(this MapBsp mapBsp, string className)
|
||||
{
|
||||
foreach (BspEntity ent in mapBsp.Entities)
|
||||
{
|
||||
if (ent.GetClassname().EqualsInvariant(className, caseSensitive: true))
|
||||
return ent;
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
public static List<BspEntity> FindEntitiesOfClass(this MapBsp mapBsp, string className)
|
||||
{
|
||||
List<BspEntity> entities = new();
|
||||
|
||||
foreach (BspEntity ent in mapBsp.Entities)
|
||||
{
|
||||
if (!ent.GetClassname().EqualsInvariant(className, caseSensitive: true))
|
||||
continue;
|
||||
|
||||
entities.Add(ent);
|
||||
}
|
||||
|
||||
return entities;
|
||||
}
|
||||
|
||||
public static TReturnType GetBaseClassData<TReturnType>(this BspEntity entity, ITrembleBaseClass instance, string name)
|
||||
{
|
||||
PropertyInfo defaultProperty = instance
|
||||
.GetType()
|
||||
.GetInterfaces()
|
||||
.SelectMany(i => i.GetProperties())
|
||||
.FirstOrDefault(p => p.Name.EqualsInvariant(name, caseSensitive: true));
|
||||
|
||||
if (defaultProperty == null)
|
||||
return default;
|
||||
|
||||
string fieldName = name.GetFieldNameInMap(TrembleSyncSettings.Get().FieldNamingConvention);
|
||||
|
||||
s_ConverterCollection ??= new();
|
||||
|
||||
TrembleFieldConverter converter = s_ConverterCollection.GetConverterForType(defaultProperty.PropertyType);
|
||||
if (converter != null)
|
||||
{
|
||||
// Use a converter to convert the map value
|
||||
if (converter.TryGetValueFromMap(entity, fieldName, null, defaultProperty, out object mapValue))
|
||||
{
|
||||
if (defaultProperty.GetFieldOrPropertyTypeOrElementType() == typeof(Transform) && mapValue is Component c)
|
||||
{
|
||||
mapValue = c.transform;
|
||||
}
|
||||
|
||||
return (TReturnType)mapValue;
|
||||
}
|
||||
|
||||
// Couldn't convert - read the default value from the interface base
|
||||
return (TReturnType)defaultProperty.GetValue(instance);
|
||||
}
|
||||
|
||||
// Nothing worked - log a warning
|
||||
Debug.LogWarning($"Saw field '{defaultProperty.Name}' of type {defaultProperty.GetFieldOrPropertyType()}, which is not yet supported. Try adding a custom TrembleFieldConverter for it, if you like!");
|
||||
|
||||
return (TReturnType)defaultProperty.GetValue(instance);
|
||||
}
|
||||
|
||||
|
||||
public static BspEntity GetWorldspawnEntity(this MapBsp mapBsp)
|
||||
{
|
||||
return FindFirstEntityOfClass(mapBsp, "worldspawn");
|
||||
}
|
||||
|
||||
public static string GetClassname(this BspEntity entity)
|
||||
=> entity.GetString(FgdConsts.PROPERTY_CLASSNAME);
|
||||
|
||||
public static string GetID(this BspEntity entity)
|
||||
=> entity.GetString(TrembleSyncSettings.Get().IdentityPropertyName);
|
||||
|
||||
public static bool HasID(this BspEntity entity)
|
||||
=> entity.Entries.ContainsKey(TrembleSyncSettings.Get().IdentityPropertyName);
|
||||
|
||||
public static bool HasKey(this BspEntity entity, string key) => entity.Entries.ContainsKey(key);
|
||||
|
||||
public static IEnumerable<string> GetAllNumberedKeys(this BspEntity entity, string prefix)
|
||||
{
|
||||
return entity.Entries.Keys
|
||||
.Where(k => k.StartsWithInvariant(prefix, caseSensitive: true))
|
||||
.OrderBy(k => k);
|
||||
}
|
||||
|
||||
public static bool TryGetString(this BspEntity entity, string key, out string value) => entity.Entries.TryGetValue(key, out value);
|
||||
public static string GetString(this BspEntity entity, string key, string defaultValue = null)
|
||||
=> entity.Entries.GetValueOrDefault(key, defaultValue);
|
||||
public static string[] GetStrings(this BspEntity entity, string keyPrefix)
|
||||
=> entity.GetAllNumberedKeys(keyPrefix).Select(key => entity.GetString(key)).ToArray();
|
||||
|
||||
public static bool TryGetInt(this BspEntity entity, string key, out int value)
|
||||
{
|
||||
if (!entity.Entries.TryGetValue(key, out string strValue))
|
||||
{
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
return int.TryParse(strValue, out value);
|
||||
}
|
||||
public static int GetInt(this BspEntity entity, string key, int defaultValue)
|
||||
=> TryGetInt(entity, key, out int value) ? value : defaultValue;
|
||||
public static int[] GetInts(this BspEntity entity, string keyPrefix)
|
||||
=> entity.GetAllNumberedKeys(keyPrefix).Select(key => entity.GetInt(key, 0)).ToArray();
|
||||
|
||||
public static bool TryGetFloat(this BspEntity entity, string key, out float value)
|
||||
{
|
||||
if (!entity.Entries.TryGetValue(key, out string strValue))
|
||||
{
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
return strValue.TryParseFloat(out value);
|
||||
}
|
||||
public static float GetFloat(this BspEntity entity, string key, float defaultValue)
|
||||
=> TryGetFloat(entity, key, out float value) ? value : defaultValue;
|
||||
public static float[] GetFloats(this BspEntity entity, string keyPrefix)
|
||||
=> entity.GetAllNumberedKeys(keyPrefix).Select(key => entity.GetFloat(key, 0f)).ToArray();
|
||||
|
||||
public static bool TryGetBoolean(this BspEntity entity, string key, out bool value)
|
||||
{
|
||||
if (!entity.Entries.TryGetValue(key, out string strValue)
|
||||
|| !int.TryParse(strValue, out int intValue))
|
||||
{
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
value = (intValue > 0);
|
||||
return true;
|
||||
}
|
||||
public static bool GetBoolean(this BspEntity entity, string key, bool defaultValue)
|
||||
=> TryGetBoolean(entity, key, out bool value) ? value : defaultValue;
|
||||
public static bool[] GetBooleans(this BspEntity entity, string keyPrefix)
|
||||
=> entity.GetAllNumberedKeys(keyPrefix).Select(key => entity.GetBoolean(key, false)).ToArray();
|
||||
|
||||
|
||||
public static bool TryGetSpawnFlag(this BspEntity entity, int bit, out bool value)
|
||||
{
|
||||
int bitValue = 1 << bit;
|
||||
|
||||
if (!entity.Entries.TryGetValue(FgdConsts.PROPERTY_SPAWNFLAGS, out string strValue)
|
||||
|| !int.TryParse(strValue, out int intValue))
|
||||
{
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
value = (intValue & bitValue) > 0;
|
||||
return true;
|
||||
}
|
||||
public static bool GetSpawnFlag(this BspEntity entity, int bit, bool defaultValue)
|
||||
=> TryGetSpawnFlag(entity, bit, out bool value) ? value : defaultValue;
|
||||
|
||||
public static bool TryGetUntransformedVector(this BspEntity entity, string key, out Vector3 value)
|
||||
{
|
||||
if (!entity.Entries.TryGetValue(key, out string strValue))
|
||||
{
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
return strValue.TryParseQ3Vector(out value);
|
||||
}
|
||||
public static Vector3 GetUntransformedVector(this BspEntity entity, string key, Vector3 defaultValue)
|
||||
=> TryGetUntransformedVector(entity, key, out Vector3 value) ? value : defaultValue;
|
||||
public static Vector3[] GetUntransformedVectors(this BspEntity entity, string keyPrefix)
|
||||
=> entity.GetAllNumberedKeys(keyPrefix).Select(key => entity.GetUntransformedVector(key, Vector3.zero)).ToArray();
|
||||
|
||||
|
||||
public static bool TryGetVector(this BspEntity entity, string key, out Vector3 value)
|
||||
{
|
||||
if (!TryGetUntransformedVector(entity, key, out Vector3 rawValue))
|
||||
{
|
||||
value = rawValue;
|
||||
return false;
|
||||
}
|
||||
|
||||
value = rawValue.Q3ToUnityVector(scale: entity.ImportScale);
|
||||
return true;
|
||||
}
|
||||
public static Vector3 GetVector(this BspEntity entity, string key, Vector3 defaultValue)
|
||||
=> TryGetVector(entity, key, out Vector3 value) ? value : defaultValue;
|
||||
public static Vector3[] GetVectors(this BspEntity entity, string keyPrefix)
|
||||
=> entity.GetAllNumberedKeys(keyPrefix).Select(key => entity.GetVector(key, Vector3.zero)).ToArray();
|
||||
|
||||
public static bool TryGetRotation(this BspEntity entity, string key, out Quaternion value)
|
||||
{
|
||||
if (entity.TryGetUntransformedVector(key, out Vector3 rawAngles))
|
||||
{
|
||||
// From TB Docs: "angles" is interpreted as "pitch yaw roll" (if the entity model is a Quake MDL, pitch is inverted)
|
||||
Quaternion quat = Quaternion.identity;
|
||||
if (rawAngles.z != 0) quat = Quaternion.AngleAxis(-rawAngles.z, Vector3.right) * quat; // pitch
|
||||
if (rawAngles.x != 0) quat = Quaternion.AngleAxis(-rawAngles.x, Vector3.forward) * quat; // roll
|
||||
if (rawAngles.y != 0) quat = Quaternion.AngleAxis(-rawAngles.y, Vector3.up) * quat; // yaw
|
||||
|
||||
value = quat;
|
||||
return true;
|
||||
}
|
||||
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
public static Quaternion GetRotation(this BspEntity entity, string key, Quaternion defaultValue)
|
||||
=> TryGetRotation(entity, key, out Quaternion value) ? value : defaultValue;
|
||||
public static Quaternion[] GetRotations(this BspEntity entity, string keyPrefix)
|
||||
=> entity.GetAllNumberedKeys(keyPrefix).Select(key => entity.GetRotation(key, Quaternion.identity)).ToArray();
|
||||
|
||||
|
||||
public static Vector3 GetPosition(this BspEntity entity)
|
||||
=> TryGetVector(entity, FgdConsts.PROPERTY_ORIGIN, out Vector3 value) ? value : Vector3.zero;
|
||||
|
||||
|
||||
public static bool TryGetColour(this BspEntity entity, string key, out Color value)
|
||||
{
|
||||
if (!entity.Entries.TryGetValue(key, out string strValue))
|
||||
{
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
return strValue.TryParseQ3Colour(out value);
|
||||
}
|
||||
public static Color GetColour(this BspEntity entity, string key, Color defaultValue)
|
||||
=> TryGetColour(entity, key, out Color value) ? value : defaultValue;
|
||||
public static Color[] GetColours(this BspEntity entity, string keyPrefix)
|
||||
=> entity.GetAllNumberedKeys(keyPrefix).Select(key => entity.GetColour(key, Color.white)).ToArray();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 282f35cb4fdd4cc59aeffd3c688fb299
|
||||
timeCreated: 1698070299
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Types/MapBspGetters.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,125 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Assembly = System.Reflection.Assembly;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace TinyGoose.Tremble
|
||||
{
|
||||
[Serializable]
|
||||
public class MapProcessorClass
|
||||
{
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// Serialised
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
[SerializeField] private string m_MapClassName;
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// Static lookup
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
private static readonly Dictionary<string, Type> s_MapClassLookup = new();
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// State
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
private Type m_Class;
|
||||
|
||||
public MapProcessorClass(string mapClassName = null)
|
||||
{
|
||||
m_MapClassName = mapClassName;
|
||||
}
|
||||
public MapProcessorClass(Type mapClass)
|
||||
{
|
||||
m_Class = mapClass;
|
||||
m_MapClassName = mapClass.FullName;
|
||||
}
|
||||
|
||||
public static implicit operator MapProcessorClass(Type t) => new(t);
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// Equality
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
protected bool Equals(MapProcessorClass other) => m_MapClassName == other.m_MapClassName;
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is null)
|
||||
return false;
|
||||
if (ReferenceEquals(this, obj))
|
||||
return true;
|
||||
|
||||
return obj.GetType() == GetType() && Equals((MapProcessorClass) obj);
|
||||
}
|
||||
public override int GetHashCode() => m_MapClassName?.GetHashCode() ?? 0;
|
||||
|
||||
public static bool operator ==(MapProcessorClass left, MapProcessorClass right) => Equals(left, right);
|
||||
public static bool operator !=(MapProcessorClass left, MapProcessorClass right) => !Equals(left, right);
|
||||
|
||||
public Type Class
|
||||
{
|
||||
get
|
||||
{
|
||||
// Have cached type?
|
||||
if (m_Class != null)
|
||||
return m_Class;
|
||||
|
||||
m_Class = GetClassWithName(m_MapClassName);
|
||||
return m_Class;
|
||||
}
|
||||
}
|
||||
|
||||
public static Type GetClassWithName(string className)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
// Unsupported - but hopefully fine!
|
||||
return Unsupported.GetTypeFromFullName(className);
|
||||
#else
|
||||
if (className == null)
|
||||
return null;
|
||||
|
||||
if (s_MapClassLookup.Count == 0)
|
||||
{
|
||||
GenerateClassLookup();
|
||||
}
|
||||
|
||||
// Try looking up - we should refresh if not
|
||||
if (s_MapClassLookup.TryGetValue(className, out Type foundClass))
|
||||
return foundClass;
|
||||
|
||||
return null;
|
||||
#endif
|
||||
}
|
||||
|
||||
public MapProcessorBase CreateInstance() => (MapProcessorBase)Activator.CreateInstance(Class);
|
||||
|
||||
public bool IsValid => Class != null;
|
||||
public bool IsA<T>() => Class == typeof(T) || Class.IsSubclassOf(typeof(T));
|
||||
|
||||
private static void GenerateClassLookup()
|
||||
{
|
||||
List<Type> typesFound = new(1024);
|
||||
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
typesFound.AddRange(assembly.GetTypes());
|
||||
|
||||
s_MapClassLookup.Clear();
|
||||
|
||||
foreach (Type availableType in typesFound)
|
||||
{
|
||||
string fullName = availableType.FullName;
|
||||
|
||||
if (fullName == null)
|
||||
continue;
|
||||
|
||||
s_MapClassLookup[fullName] = availableType;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b1c6f641d81f4c8b81744a96934911ef
|
||||
timeCreated: 1707729910
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Types/MapProcessorClass.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble
|
||||
{
|
||||
public enum MaterialExportSize
|
||||
{
|
||||
[InspectorName("16")] Size16,
|
||||
[InspectorName("32")] Size32,
|
||||
[InspectorName("64")] Size64,
|
||||
[InspectorName("128")] Size128,
|
||||
[InspectorName("256")] Size256,
|
||||
[InspectorName("512")] Size512,
|
||||
[InspectorName("1024")] Size1024,
|
||||
[InspectorName("2048")] Size2048,
|
||||
}
|
||||
|
||||
public static class MaterialExportSizeUtils
|
||||
{
|
||||
public static MaterialExportSize GetDefault() => MaterialExportSize.Size64;
|
||||
|
||||
public static string[] Names =>
|
||||
s_Names ??= Enum.GetValues(typeof(MaterialExportSize))
|
||||
.Cast<MaterialExportSize>()
|
||||
.Select(mes => typeof(MaterialExportSize)
|
||||
.GetMember(mes.ToString())[0]
|
||||
.GetCustomAttribute<InspectorNameAttribute>()?.displayName ?? mes.ToString())
|
||||
.ToArray();
|
||||
|
||||
private static int[] IntSizes => s_Sizes ??= Names.Select(int.Parse).ToArray();
|
||||
|
||||
public static int ToIntSize(this MaterialExportSize mes) => IntSizes[(int)mes];
|
||||
|
||||
public static Vector2Int ToVector2IntSize(this MaterialExportSize mes) => new(mes.ToIntSize(), mes.ToIntSize());
|
||||
|
||||
private static string[] s_Names;
|
||||
private static int[] s_Sizes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c9d6ab96c78649b2a9c2b1c4d6cda752
|
||||
timeCreated: 1753866627
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Types/MaterialExportSize.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble
|
||||
{
|
||||
[Serializable]
|
||||
public class MaterialRenderData
|
||||
{
|
||||
public MaterialRenderData(Material material)
|
||||
{
|
||||
m_Material = material;
|
||||
}
|
||||
|
||||
[SerializeField] private Material m_Material;
|
||||
[SerializeField] private MaterialImportMode m_ExportMode;
|
||||
[SerializeField] private bool m_IsResolutionOverridden;
|
||||
[SerializeField] private MaterialExportSize m_ResolutionX = MaterialExportSize.Size64;
|
||||
[SerializeField] private MaterialExportSize m_ResolutionY = MaterialExportSize.Size64;
|
||||
[SerializeField] private bool m_Dirty;
|
||||
|
||||
public Material Material => m_Material;
|
||||
|
||||
public MaterialImportMode ExportMode
|
||||
{
|
||||
get => m_ExportMode;
|
||||
set
|
||||
{
|
||||
m_ExportMode = value;
|
||||
m_Dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsResolutionOverridden
|
||||
{
|
||||
get => m_IsResolutionOverridden;
|
||||
set
|
||||
{
|
||||
m_IsResolutionOverridden = value;
|
||||
m_Dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public MaterialExportSize ResolutionX
|
||||
{
|
||||
get => m_ResolutionX;
|
||||
set
|
||||
{
|
||||
m_ResolutionX = value;
|
||||
m_Dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public MaterialExportSize ResolutionY
|
||||
{
|
||||
get => m_ResolutionY;
|
||||
set
|
||||
{
|
||||
m_ResolutionY = value;
|
||||
m_Dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2Int GetResolutionOrDefault()
|
||||
{
|
||||
if (!m_IsResolutionOverridden)
|
||||
return TrembleSyncSettings.Get().MaterialExportSize.ToVector2IntSize();
|
||||
|
||||
return new(m_ResolutionX.ToIntSize(), m_ResolutionY.ToIntSize());
|
||||
}
|
||||
|
||||
public bool IsDirty => m_Dirty;
|
||||
public void ClearDirty() => m_Dirty = false;
|
||||
}
|
||||
|
||||
|
||||
public enum MaterialImportMode
|
||||
{
|
||||
Dynamic,
|
||||
FixedSize,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5008febfabec473983456dc18bc3cf5d
|
||||
timeCreated: 1753866661
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Types/MaterialRenderData.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,136 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble
|
||||
{
|
||||
[Serializable]
|
||||
public struct TpakTocEntry
|
||||
{
|
||||
public string Path;
|
||||
public string SourcePath;
|
||||
|
||||
public int FileLength;
|
||||
}
|
||||
|
||||
public class TpakArchive
|
||||
{
|
||||
private const string TPAK_MAGIC = "TPAK";
|
||||
private const int TPAK_MAX_PATH = 255;
|
||||
|
||||
private readonly string m_ArchiveFile;
|
||||
private readonly List<TpakTocEntry> m_Entries = new();
|
||||
|
||||
public TpakArchive(string archiveFile)
|
||||
{
|
||||
m_ArchiveFile = archiveFile;
|
||||
}
|
||||
|
||||
public void AddDirectory(string directory)
|
||||
{
|
||||
AddDirectory_Recursive(directory, null);
|
||||
}
|
||||
|
||||
public void AddFile(string filePath, string filenameInTpak)
|
||||
{
|
||||
m_Entries.Add(new()
|
||||
{
|
||||
Path = filenameInTpak,
|
||||
SourcePath = filePath,
|
||||
FileLength = (int)(new FileInfo(filePath).Length)
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<bool> UnpackAsync(string folder)
|
||||
{
|
||||
StreamReadIO pakIn = new(m_ArchiveFile);
|
||||
if (!pakIn.ReadString(4).EqualsInvariant(TPAK_MAGIC, caseSensitive: true))
|
||||
{
|
||||
Debug.LogError($"Invalid magic reading tpak '{m_ArchiveFile}'!");
|
||||
return false;
|
||||
}
|
||||
|
||||
int numEntries = pakIn.ReadInt32();
|
||||
for (int entryIdx = 0; entryIdx < numEntries; entryIdx++)
|
||||
{
|
||||
int pathLength = pakIn.ReadInt32();
|
||||
|
||||
TpakTocEntry entry = new()
|
||||
{
|
||||
Path = pakIn.ReadString(pathLength),
|
||||
FileLength = pakIn.ReadInt32(),
|
||||
};
|
||||
entry.SourcePath = Path.Combine(folder, entry.Path);
|
||||
DirectoryUtil.CreateAllDirectories(entry.SourcePath);
|
||||
|
||||
m_Entries.Add(entry);
|
||||
}
|
||||
|
||||
foreach (TpakTocEntry entry in m_Entries)
|
||||
{
|
||||
if (File.Exists(entry.SourcePath))
|
||||
{
|
||||
pakIn.SkipBytes(entry.FileLength);
|
||||
continue;
|
||||
}
|
||||
|
||||
byte[] file = pakIn.ReadBytes(entry.FileLength);
|
||||
await File.WriteAllBytesAsync(entry.SourcePath, file);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task PackAsync()
|
||||
{
|
||||
await using FileStream pakOutStream = new(m_ArchiveFile, FileMode.Create, FileAccess.Write);
|
||||
|
||||
using StreamWriteIO pakOut = new(pakOutStream);
|
||||
pakOut.WriteString(TPAK_MAGIC, 4);
|
||||
pakOut.WriteInt32(m_Entries.Count);
|
||||
|
||||
foreach (TpakTocEntry entry in m_Entries)
|
||||
{
|
||||
pakOut.WriteInt32(entry.Path.Length);
|
||||
pakOut.WriteString(entry.Path);
|
||||
pakOut.WriteInt32(entry.FileLength);
|
||||
}
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
foreach (TpakTocEntry entry in m_Entries)
|
||||
{
|
||||
await using FileStream entryFile = new(entry.SourcePath, FileMode.Open, FileAccess.Read);
|
||||
using BinaryReader entryIn = new(entryFile);
|
||||
|
||||
int readBytes;
|
||||
do
|
||||
{
|
||||
readBytes = entryIn.Read(buffer, 0, buffer.Length);
|
||||
pakOut.WriteBytes(buffer, readBytes);
|
||||
} while (readBytes > 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddDirectory_Recursive(string directory, string currentPath)
|
||||
{
|
||||
foreach (string file in Directory.EnumerateFiles(directory))
|
||||
{
|
||||
string path = currentPath == null ? Path.GetFileName(file) : Path.Combine(currentPath, Path.GetFileName(file));
|
||||
AddFile(file, path);
|
||||
}
|
||||
|
||||
foreach (string dir in Directory.EnumerateDirectories(directory))
|
||||
{
|
||||
string newCurrentPath = currentPath == null ? Path.GetFileName(dir) : Path.Combine(currentPath, Path.GetFileName(dir));
|
||||
AddDirectory_Recursive(dir, newCurrentPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fd52ece1f19743039da2022e11fbe16c
|
||||
timeCreated: 1728651734
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Types/TpakArchive.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,149 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace TinyGoose.Tremble
|
||||
{
|
||||
[Serializable]
|
||||
public struct StoredTrembleTimer
|
||||
{
|
||||
public string Context;
|
||||
public long LastMillis;
|
||||
}
|
||||
|
||||
public struct TrembleTimerScope : IDisposable
|
||||
{
|
||||
private readonly TrembleTimer m_Timer;
|
||||
private bool m_Disposed;
|
||||
|
||||
public TrembleTimerScope(Type type)
|
||||
{
|
||||
m_Timer = TrembleTimer.GetTimer(type);
|
||||
m_Timer.BeginCapture();
|
||||
|
||||
m_Disposed = false;
|
||||
}
|
||||
public TrembleTimerScope(TrembleTimer.Context context)
|
||||
{
|
||||
m_Timer = TrembleTimer.GetTimer(context);
|
||||
m_Timer.BeginCapture();
|
||||
|
||||
m_Disposed = false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (m_Disposed)
|
||||
return;
|
||||
|
||||
m_Disposed = true;
|
||||
m_Timer.EndCapture();
|
||||
}
|
||||
}
|
||||
|
||||
public class TrembleTimer
|
||||
{
|
||||
public enum Context
|
||||
{
|
||||
// Import
|
||||
ExportMapToStaging,
|
||||
RunQ3Map2,
|
||||
ParseBsp,
|
||||
CreateGameObjects,
|
||||
SplitMesh,
|
||||
SmoothMeshNormals,
|
||||
SimplifyCollisionMeshes,
|
||||
GenerateUV2,
|
||||
RunMapProcessors,
|
||||
|
||||
// Sync
|
||||
CreateTypeLookups,
|
||||
ExportEntities,
|
||||
GatherDataAssets,
|
||||
ExportMaterials,
|
||||
WriteEntitiesFgdAndGameConfig,
|
||||
Cleanup,
|
||||
ExportAddressableDataForStandalone,
|
||||
}
|
||||
|
||||
private static readonly Dictionary<string, TrembleTimer> s_CurrentTimers = new();
|
||||
private static string s_SessionContext;
|
||||
private static DateTime s_SessionStart;
|
||||
|
||||
private DateTime m_CaptureStart;
|
||||
private long m_TotalMilliseconds;
|
||||
|
||||
public long TotalMilliseconds => m_TotalMilliseconds;
|
||||
|
||||
public static void BeginSession(string sessionContext)
|
||||
{
|
||||
s_SessionStart = DateTime.Now;
|
||||
s_SessionContext = sessionContext;
|
||||
s_CurrentTimers.Clear();
|
||||
}
|
||||
|
||||
public static void EndSession()
|
||||
{
|
||||
if (TrembleSyncSettings.Get().LogOnImportAndSync)
|
||||
{
|
||||
float seconds = (float)(DateTime.Now - s_SessionStart).TotalSeconds;
|
||||
Debug.Log($"{s_SessionContext} complete in {seconds:F3}s!");
|
||||
}
|
||||
|
||||
foreach ((string name, TrembleTimer timer) in s_CurrentTimers)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
EditorPrefs.SetInt($"TrembleTimer_{name}", (int)timer.TotalMilliseconds);
|
||||
#endif
|
||||
|
||||
if (TrembleSyncSettings.Get().LogOnImportAndSync)
|
||||
{
|
||||
Debug.Log($" {name} took {timer.TotalMilliseconds}ms");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static TrembleTimer GetTimer(Type processorType) => GetTimer(processorType.FullName);
|
||||
public static TrembleTimer GetTimer(Context context) => GetTimer(context.ToString());
|
||||
|
||||
private static TrembleTimer GetTimer(string name)
|
||||
{
|
||||
if (!s_CurrentTimers.TryGetValue(name, out TrembleTimer timer))
|
||||
{
|
||||
timer = new();
|
||||
s_CurrentTimers[name] = timer;
|
||||
}
|
||||
|
||||
return timer;
|
||||
}
|
||||
|
||||
public static long GetLastTime(Type processorType) => GetLastTime(processorType.FullName);
|
||||
public static long GetLastTime(Context context) => GetLastTime(context.ToString());
|
||||
|
||||
private static long GetLastTime(string name)
|
||||
#if UNITY_EDITOR
|
||||
=> EditorPrefs.GetInt($"TrembleTimer_{name}", -1);
|
||||
#else
|
||||
=> 0L;
|
||||
#endif
|
||||
|
||||
|
||||
public void BeginCapture()
|
||||
{
|
||||
m_CaptureStart = DateTime.Now;
|
||||
}
|
||||
public void EndCapture()
|
||||
{
|
||||
m_TotalMilliseconds += (long)(DateTime.Now - m_CaptureStart).TotalMilliseconds;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fcf63be3ebf546e598559701514185f6
|
||||
timeCreated: 1728729960
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Types/TrembleTimer.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace TinyGoose.Tremble
|
||||
{
|
||||
public class TwoWayDictionary<TKey, TValue>
|
||||
{
|
||||
private readonly Dictionary<TKey, TValue> m_Lookup;
|
||||
private readonly Dictionary<TValue, TKey> m_ReverseLookup;
|
||||
|
||||
public TwoWayDictionary()
|
||||
{
|
||||
m_Lookup = new();
|
||||
m_ReverseLookup = new();
|
||||
}
|
||||
|
||||
public TwoWayDictionary(int capacity)
|
||||
{
|
||||
m_Lookup = new(capacity);
|
||||
m_ReverseLookup = new(capacity);
|
||||
}
|
||||
|
||||
public TValue GetValue(TKey key)
|
||||
{
|
||||
return m_Lookup[key];
|
||||
}
|
||||
public TKey GetKey(TValue value)
|
||||
{
|
||||
return m_ReverseLookup[value];
|
||||
}
|
||||
|
||||
public bool ContainsKey(TKey key) => m_Lookup.ContainsKey(key);
|
||||
public bool ContainsValue(TValue value) => m_ReverseLookup.ContainsKey(value);
|
||||
|
||||
public bool TryGetValue(TKey key, out TValue value) => m_Lookup.TryGetValue(key, out value);
|
||||
public bool TryGetKey(TValue value, out TKey key) => m_ReverseLookup.TryGetValue(value, out key);
|
||||
|
||||
public IEnumerable<TKey> Keys => m_Lookup.Keys;
|
||||
public IEnumerable<TValue> Values => m_Lookup.Values;
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
m_Lookup.Clear();
|
||||
m_ReverseLookup.Clear();
|
||||
}
|
||||
|
||||
public TValue this[TKey key]
|
||||
{
|
||||
get => GetValue(key);
|
||||
set
|
||||
{
|
||||
m_Lookup[key] = value;
|
||||
m_ReverseLookup[value] = key;
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(TKey key, TValue value)
|
||||
{
|
||||
m_Lookup.Add(key, value);
|
||||
m_ReverseLookup.Add(value, key);
|
||||
}
|
||||
|
||||
public void Remove(TKey key)
|
||||
{
|
||||
if (m_Lookup.TryGetValue(key, out TValue value))
|
||||
{
|
||||
m_ReverseLookup.Remove(value);
|
||||
}
|
||||
m_Lookup.Remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab6c6d9d07924bbebafee07655e56466
|
||||
timeCreated: 1740748009
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Types/TwoWayDictionary.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble
|
||||
{
|
||||
[Serializable]
|
||||
public class WorldspawnScript
|
||||
{
|
||||
private static readonly int DEFAULT_TYPE_HASHCODE = typeof(Worldspawn).FullName?.GetHashCode() ?? 0;
|
||||
private static readonly int EMPTY_STRING_HASHCODE = "".GetHashCode();
|
||||
|
||||
public WorldspawnScript(string scriptName = null)
|
||||
{
|
||||
m_ScriptName = scriptName;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// Serialised
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
[SerializeField] private string m_ScriptName;
|
||||
|
||||
public string ScriptName => m_ScriptName;
|
||||
public Type Class => TypeDatabase.GetType(m_ScriptName);
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int hash = m_ScriptName.GetHashCode();
|
||||
return hash == DEFAULT_TYPE_HASHCODE ? EMPTY_STRING_HASHCODE : hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b44834781104ac6941bd9a435d8dae3
|
||||
timeCreated: 1710152777
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Types/WorldspawnScript.cs
|
||||
uploadId: 939664
|
||||
Reference in new issue
Block a user