Second commit
This commit is contained in:
commit
36840f3ad4
999 files changed
+61364
No files matched your search
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 874b1f1fda434715b9e8cb37b2936050
|
||||
timeCreated: 1716200660
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8b895dc7f3a74ac1a27fec3a77248e5d
|
||||
timeCreated: 1716201044
|
||||
@@ -0,0 +1,159 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
#if ADDRESSABLES_INSTALLED
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
using Debug = UnityEngine.Debug;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace TinyGoose.Tremble
|
||||
{
|
||||
public class AddressablesLoaderAdaptor : IAssetLoaderAdaptor
|
||||
{
|
||||
public bool SupportsPreloading => true;
|
||||
|
||||
private readonly List<AsyncOperationHandle> m_OwnedHandles = new(1024);
|
||||
private readonly Dictionary<string, object> m_LoadedAssets = new(1024);
|
||||
|
||||
public string[] FindAssetPaths(Type type, string name = "")
|
||||
{
|
||||
return TrembleAssetLoader.FindAssetDataMany(a => a.Path.ContainsInvariant(name))
|
||||
.Where(a => a.FullTypeName.EqualsInvariant(type.FullName))
|
||||
.Select(a => a.Path)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public TAsset LoadAssetByPath<TAsset>(string path) where TAsset : Object
|
||||
{
|
||||
if (path.IsNullOrEmpty())
|
||||
return null;
|
||||
|
||||
if (!TrembleAssetLoader.TryGetAssetDataFromPath(path, out AssetMetadata assetData))
|
||||
{
|
||||
Debug.LogError($"Not loading invalid addressable: {path}");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (m_LoadedAssets.TryGetValue(assetData.AddressableName, out object existingAsset) &&
|
||||
existingAsset is TAsset tAsset)
|
||||
{
|
||||
return tAsset;
|
||||
}
|
||||
|
||||
AsyncOperationHandle<TAsset> handle = Addressables.LoadAssetAsync<TAsset>(assetData.AddressableName);
|
||||
TAsset asset = handle.WaitForCompletion();
|
||||
if (!asset)
|
||||
{
|
||||
Addressables.Release(handle);
|
||||
return null;
|
||||
}
|
||||
|
||||
m_OwnedHandles.Add(handle);
|
||||
m_LoadedAssets[path] = handle;
|
||||
return asset;
|
||||
}
|
||||
|
||||
public async Task PreloadAssetsByPaths(IList<string> paths)
|
||||
{
|
||||
if (paths.Count == 0)
|
||||
return;
|
||||
|
||||
List<string> addresses = new(paths.Count);
|
||||
|
||||
// First, remove dupes, invalid and ones we already loaded
|
||||
for (int i = 0; i < paths.Count; i++)
|
||||
{
|
||||
string path = paths[i];
|
||||
|
||||
if (path.IsNullOrEmpty() || !TrembleAssetLoader.TryGetAssetDataFromPath(path, out AssetMetadata assetData))
|
||||
{
|
||||
Debug.LogError($"Not loading invalid addressable: {path}");
|
||||
paths.RemoveAt(i--);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_LoadedAssets.ContainsKey(assetData.AddressableName))
|
||||
{
|
||||
paths.RemoveAt(i--);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (paths.IndexOf(path) != i)
|
||||
{
|
||||
paths.RemoveAt(i--);
|
||||
continue;
|
||||
}
|
||||
|
||||
// This is valid - add to list of addresses
|
||||
addresses.Add(assetData.AddressableName);
|
||||
}
|
||||
|
||||
if (addresses.Count == 0)
|
||||
return;
|
||||
|
||||
AsyncOperationHandle<IList<Object>> resultsHandle = Addressables.LoadAssetsAsync<Object>(addresses, null, Addressables.MergeMode.Union);
|
||||
await resultsHandle.Task;
|
||||
|
||||
for (int i = 0; i < paths.Count; i++)
|
||||
{
|
||||
string path = paths[i];
|
||||
if (TrembleAssetLoader.TryGetAssetDataFromPath(path, out AssetMetadata assetData))
|
||||
{
|
||||
m_LoadedAssets[assetData.AddressableName] = resultsHandle.Result[i];
|
||||
}
|
||||
}
|
||||
m_OwnedHandles.Add(resultsHandle);
|
||||
}
|
||||
|
||||
public string GetPath(Object obj)
|
||||
{
|
||||
Debug.LogError("GetPath is not implemented in Addressables (yet!)");
|
||||
return null;
|
||||
}
|
||||
|
||||
public TrembleSyncSettings LoadSyncSettings()
|
||||
{
|
||||
return Addressables
|
||||
.LoadAssetAsync<TrembleSyncSettings>(TrembleSyncSettings.ADDRESSABLE_KEY)
|
||||
.WaitForCompletion();
|
||||
}
|
||||
|
||||
public Material LoadClipMaterial()
|
||||
{
|
||||
return Addressables.LoadAssetAsync<Material>("M_NullRender").WaitForCompletion();
|
||||
}
|
||||
|
||||
public void ReleaseAll()
|
||||
{
|
||||
foreach (AsyncOperationHandle handle in m_OwnedHandles)
|
||||
{
|
||||
Addressables.Release(handle);
|
||||
}
|
||||
m_OwnedHandles.Clear();
|
||||
}
|
||||
|
||||
private static bool IsAddressablePathValid(string path)
|
||||
{
|
||||
if (path == null)
|
||||
return false;
|
||||
|
||||
AsyncOperationHandle<IList<IResourceLocation>> locationLoadOperation = Addressables.LoadResourceLocationsAsync(path);
|
||||
IList<IResourceLocation> results = locationLoadOperation.WaitForCompletion();
|
||||
bool isValidPath = results is { Count: > 0 };
|
||||
Addressables.Release(locationLoadOperation);
|
||||
|
||||
return isValidPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f4959867e61442c2aa78844ff6cd8e06
|
||||
timeCreated: 1716201342
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/AssetLoading/Adaptors/AddressablesLoaderAdaptor.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,105 @@
|
||||
//
|
||||
// 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.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
||||
namespace TinyGoose.Tremble
|
||||
{
|
||||
public class EditorLoaderAdaptor : IAssetLoaderAdaptor
|
||||
{
|
||||
public bool SupportsPreloading => false;
|
||||
|
||||
private static readonly Dictionary<string, string[]> s_CachedQueryResults = new(1024);
|
||||
|
||||
public string[] FindAssetPaths(Type type, string name = "")
|
||||
{
|
||||
string typeString = type == typeof(GameObject) ? "prefab" : type.Name;
|
||||
string fullQuery = $"t:{typeString} {name}";
|
||||
|
||||
if (!s_CachedQueryResults.TryGetValue(fullQuery, out string[] results))
|
||||
{
|
||||
results = AssetDatabase
|
||||
.FindAssets(fullQuery, new[] { "Assets" })
|
||||
.Select(AssetDatabase.GUIDToAssetPath)
|
||||
.ToArray();
|
||||
|
||||
if (results.Length > 0)
|
||||
{
|
||||
s_CachedQueryResults[fullQuery] = results;
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public TAsset LoadAssetByPath<TAsset>(string path) where TAsset : Object
|
||||
=> AssetDatabase.LoadAssetAtPath<TAsset>(path);
|
||||
|
||||
public Task PreloadAssetsByPaths(IList<string> paths)
|
||||
{
|
||||
// We don't need to preload in Editor ;)
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task PreloadAssetsByPathsAsync(IList<string> paths)
|
||||
{
|
||||
// We don't need to preload in Editor ;)
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public string GetPath(Object obj) => AssetDatabase.GetAssetPath(obj);
|
||||
|
||||
|
||||
public TrembleSyncSettings GetSyncSettings() => TrembleSyncSettings.Get();
|
||||
|
||||
public Material LoadClipMaterial()
|
||||
{
|
||||
string clipPath = Path.Combine(TrembleConsts.EDITOR_GetTrembleInstallFolder(), "Materials", "M_NullRender.mat");
|
||||
return LoadAssetByPath<Material>(clipPath);
|
||||
}
|
||||
|
||||
public TrembleSyncSettings LoadSyncSettings()
|
||||
{
|
||||
string[] paths = FindAssetPaths(typeof(TrembleSyncSettings));
|
||||
|
||||
switch (paths.Length)
|
||||
{
|
||||
case 0:
|
||||
return null;
|
||||
|
||||
case >1:
|
||||
Debug.LogError("More than one Tremble Sync Settings file found!");
|
||||
foreach (string path in paths)
|
||||
{
|
||||
Debug.LogWarning($"Found at: {path}", AssetDatabase.LoadAssetAtPath<TrembleSyncSettings>(path));
|
||||
}
|
||||
Debug.LogError("There should be only one! Picking one arbitrarily for now.");
|
||||
|
||||
goto default;
|
||||
default:
|
||||
return AssetDatabase.LoadAssetAtPath<TrembleSyncSettings>(paths[0]);
|
||||
}
|
||||
}
|
||||
|
||||
public void ReleaseAll() { }
|
||||
|
||||
|
||||
public static void DropCachedAssetPaths()
|
||||
{
|
||||
s_CachedQueryResults.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a410384015ae43959c21d5c273d941a0
|
||||
timeCreated: 1716201389
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/AssetLoading/Adaptors/EditorLoaderAdaptor.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 System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace TinyGoose.Tremble
|
||||
{
|
||||
public interface IAssetLoaderAdaptor
|
||||
{
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// Finding & loading assets
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
string[] FindAssetPaths(Type type, string name = "");
|
||||
TAsset LoadAssetByPath<TAsset>(string path) where TAsset : Object;
|
||||
Task PreloadAssetsByPaths(IList<string> paths);
|
||||
bool SupportsPreloading { get; }
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// Getting path for a loaded asset
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
string GetPath(Object obj);
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// Misc
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
TrembleSyncSettings LoadSyncSettings();
|
||||
Material LoadClipMaterial();
|
||||
void ReleaseAll();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7271c3afa0854533a18a87ea7a9690c8
|
||||
timeCreated: 1716201055
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/AssetLoading/Adaptors/IAssetLoaderAdaptor.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// 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.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace TinyGoose.Tremble
|
||||
{
|
||||
public class NullLoaderAdaptor : IAssetLoaderAdaptor
|
||||
{
|
||||
public bool SupportsPreloading => false;
|
||||
|
||||
public string[] FindAssetPaths(Type type, string name = "")
|
||||
{
|
||||
Debug.LogError("No valid loader adaptor - ensure you have Addressables installed or are in editor!");
|
||||
return Array.Empty<string>();
|
||||
}
|
||||
|
||||
public TAsset LoadAssetByPath<TAsset>(string path) where TAsset : Object
|
||||
{
|
||||
Debug.LogError("No valid loader adaptor - ensure you have Addressables installed or are in editor!");
|
||||
return null;
|
||||
}
|
||||
|
||||
public Task PreloadAssetsByPaths(IList<string> paths)
|
||||
{
|
||||
Debug.LogError("No valid loader adaptor - ensure you have Addressables installed or are in editor!");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public string GetPath(Object obj)
|
||||
{
|
||||
Debug.LogError("No valid loader adaptor - ensure you have Addressables installed or are in editor!");
|
||||
return null;
|
||||
}
|
||||
|
||||
public TrembleSyncSettings GetSyncSettings()
|
||||
{
|
||||
Debug.LogError("No valid loader adaptor - ensure you have Addressables installed or are in editor!");
|
||||
return null;
|
||||
}
|
||||
|
||||
public TrembleSyncSettings LoadSyncSettings()
|
||||
{
|
||||
Debug.LogError("No valid loader adaptor - ensure you have Addressables installed or are in editor!");
|
||||
return null;
|
||||
}
|
||||
|
||||
public Material LoadClipMaterial()
|
||||
{
|
||||
Debug.LogError("No valid loader adaptor - ensure you have Addressables installed or are in editor!");
|
||||
return null;
|
||||
}
|
||||
public void ReleaseAll() { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a3c2e961a9234fcb94549e1f5bb3e8f2
|
||||
timeCreated: 1716201662
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/AssetLoading/Adaptors/NullLoaderAdaptor.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,170 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
//#define USE_ADDRESSABLES_IN_EDITOR
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace TinyGoose.Tremble
|
||||
{
|
||||
public static class TrembleAssetLoader
|
||||
{
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// Adaptor
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
private static IAssetLoaderAdaptor s_LoaderAdaptor;
|
||||
|
||||
private static IAssetLoaderAdaptor LoaderAdaptor
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_LoaderAdaptor == null)
|
||||
{
|
||||
#if UNITY_EDITOR && !USE_ADDRESSABLES_IN_EDITOR
|
||||
s_LoaderAdaptor = new EditorLoaderAdaptor();
|
||||
#elif UNITY_SERVER
|
||||
s_LoaderAdaptor = new NullLoaderAdaptor();
|
||||
#elif ADDRESSABLES_INSTALLED
|
||||
s_LoaderAdaptor = new AddressablesLoaderAdaptor();
|
||||
#else
|
||||
s_LoaderAdaptor = new NullLoaderAdaptor();
|
||||
#endif
|
||||
}
|
||||
|
||||
return s_LoaderAdaptor;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// Generic
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
public static string FindAssetPath<TAsset>(string name = "") where TAsset : Object
|
||||
{
|
||||
string[] paths = FindAssetPaths<TAsset>(name);
|
||||
|
||||
switch (paths.Length)
|
||||
{
|
||||
// Nothing matched - return null :(
|
||||
case 0:
|
||||
return null;
|
||||
|
||||
// Multiple matches - check if we have an EXACT match
|
||||
case > 1:
|
||||
{
|
||||
foreach (string path in paths)
|
||||
{
|
||||
string filename = Path.GetFileNameWithoutExtension(path);
|
||||
if (!filename.EqualsInvariant(name))
|
||||
continue;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Only a single match, or couldn't disambiguate - return first
|
||||
return paths[0];
|
||||
}
|
||||
|
||||
public static string[] FindAssetPaths<TAsset>(string name = "") where TAsset : Object => FindAssetPaths(typeof(TAsset), name);
|
||||
|
||||
public static string[] FindAssetPaths(Type type, string name = "") => LoaderAdaptor.FindAssetPaths(type, name);
|
||||
|
||||
public static string GetPath(Object obj) => LoaderAdaptor.GetPath(obj);
|
||||
|
||||
public static GameObject LoadPrefabByName(string name) => LoadAssetByName<GameObject>(name);
|
||||
public static GameObject LoadPrefabByPath(string path) => LoadAssetByPath<GameObject>(path);
|
||||
|
||||
public static TAsset LoadAssetByName<TAsset>(string name) where TAsset : Object
|
||||
{
|
||||
string path = FindAssetPath<TAsset>(name);
|
||||
return LoadAssetByPath<TAsset>(path);
|
||||
}
|
||||
|
||||
public static TAsset LoadAssetByPath<TAsset>(string path) where TAsset : Object
|
||||
=> LoaderAdaptor.LoadAssetByPath<TAsset>(path);
|
||||
|
||||
public static async Task PreloadAssetsByPaths(IList<string> paths)
|
||||
=> await LoaderAdaptor.PreloadAssetsByPaths(paths);
|
||||
|
||||
public static bool SupportsPreloading => LoaderAdaptor.SupportsPreloading;
|
||||
|
||||
public static void ReleaseAll() => LoaderAdaptor.ReleaseAll();
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// Queries
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
private static int s_NumAssetMetadatas;
|
||||
private static readonly Dictionary<string, int> s_MapNameToMetadataIndex = new();
|
||||
private static readonly Dictionary<string, int> s_PathToMetadataIndex = new();
|
||||
|
||||
public static bool TryGetAssetDataFromMapName(string mapName, out AssetMetadata foundMetadata)
|
||||
{
|
||||
TrembleSyncSettings syncSettings = TrembleSyncSettings.Get();
|
||||
CreateLookups(syncSettings);
|
||||
|
||||
bool found = s_MapNameToMetadataIndex.TryGetValue(mapName, out int index);
|
||||
foundMetadata = found ? syncSettings.AssetMetadatas[index] : default;
|
||||
return found;
|
||||
}
|
||||
|
||||
public static bool TryGetAssetDataFromPath(string path, out AssetMetadata foundMetadata)
|
||||
{
|
||||
TrembleSyncSettings syncSettings = TrembleSyncSettings.Get();
|
||||
CreateLookups(syncSettings);
|
||||
|
||||
bool found = s_PathToMetadataIndex.TryGetValue(path, out int index);
|
||||
foundMetadata = found ? syncSettings.AssetMetadatas[index] : default;
|
||||
return found;
|
||||
}
|
||||
|
||||
private static void CreateLookups(TrembleSyncSettings syncSettings)
|
||||
{
|
||||
if (syncSettings.AssetMetadatas == null)
|
||||
return;
|
||||
|
||||
if (s_NumAssetMetadatas == syncSettings.AssetMetadatas.Length)
|
||||
return;
|
||||
|
||||
s_NumAssetMetadatas = syncSettings.AssetMetadatas.Length;
|
||||
s_MapNameToMetadataIndex.Clear();
|
||||
s_PathToMetadataIndex.Clear();
|
||||
|
||||
for (int i = 0; i < syncSettings.AssetMetadatas.Length; i++)
|
||||
{
|
||||
s_MapNameToMetadataIndex[syncSettings.AssetMetadatas[i].MapName] = i;
|
||||
s_PathToMetadataIndex[syncSettings.AssetMetadatas[i].Path] = i;
|
||||
}
|
||||
}
|
||||
|
||||
public static AssetMetadata[] FindAssetDataMany(Func<AssetMetadata, bool> filter)
|
||||
{
|
||||
TrembleSyncSettings syncSettings = TrembleSyncSettings.Get();
|
||||
return syncSettings.AssetMetadatas != null
|
||||
? syncSettings.AssetMetadatas.Where(filter).ToArray()
|
||||
: Array.Empty<AssetMetadata>();
|
||||
}
|
||||
public static bool TryFindAssetData(Func<AssetMetadata, bool> filter, out AssetMetadata found)
|
||||
{
|
||||
AssetMetadata[] results = FindAssetDataMany(filter);
|
||||
found = results.Length > 0 ? results[0] : default;
|
||||
return results.Length > 0;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// Specifics
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
public static Material LoadClipMaterial() => LoaderAdaptor.LoadClipMaterial();
|
||||
public static TrembleSyncSettings LoadSyncSettings() => LoaderAdaptor.LoadSyncSettings();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fe12c1abce564e1d8163e2f1197f500b
|
||||
timeCreated: 1715666874
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/AssetLoading/TrembleAssetLoader.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aef5a15ddfbd44629a019e803c317adf
|
||||
timeCreated: 1698412693
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c60f610e41f242fca42d8547953f86a0
|
||||
timeCreated: 1711702716
|
||||
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// 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
|
||||
{
|
||||
public enum CheckerboardStyle
|
||||
{
|
||||
None,
|
||||
Light,
|
||||
Dark,
|
||||
}
|
||||
|
||||
public enum BrushType
|
||||
{
|
||||
// Solid brush with a texture (default)
|
||||
Solid,
|
||||
|
||||
// Liquid brush (trigger collision) with a texture
|
||||
Liquid,
|
||||
|
||||
// An invisible brush which is a Unity trigger
|
||||
Trigger,
|
||||
|
||||
// An invisible (but solid) brush
|
||||
Invisible
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marks this MonoBehaviour as a component which can be added to arbitrary Brush entities from a map.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class BrushEntityAttribute : EntityAttributeBase
|
||||
{
|
||||
/// <summary>
|
||||
/// A Tremble-compatible Brush entity.
|
||||
/// </summary>
|
||||
/// <param name="trenchBroomName">The name in TrenchBroom. e.g. "cool_entity".</param>
|
||||
/// <param name="category">The category for TrenchBroom. e.g. "ent".</param>
|
||||
/// <param name="type">The brush type. e.g. Trigger, Solid, Liquid.</param>
|
||||
/// <param name="colour">The colour of this brush's texture.</param>
|
||||
/// <param name="checkerStyle">The type of checkerboard for this brush's texture.</param>
|
||||
/// <param name="layer">The layer name to put this brush on.</param>
|
||||
public BrushEntityAttribute(
|
||||
string trenchBroomName = null,
|
||||
string category = null,
|
||||
BrushType type = BrushType.Solid,
|
||||
string colour = "",
|
||||
CheckerboardStyle checkerStyle = CheckerboardStyle.None,
|
||||
string layer = "")
|
||||
: base(trenchBroomName, category)
|
||||
{
|
||||
m_BrushType = type;
|
||||
m_Colour = colour.TryParseQ3Colour(out Color value) ? value : null;
|
||||
m_CheckerStyle = checkerStyle;
|
||||
m_LayerName = layer;
|
||||
}
|
||||
|
||||
private readonly BrushType m_BrushType;
|
||||
private readonly Color? m_Colour;
|
||||
private readonly CheckerboardStyle m_CheckerStyle;
|
||||
private readonly string m_LayerName;
|
||||
|
||||
public BrushType BrushType => m_BrushType;
|
||||
public Color? Colour => m_Colour;
|
||||
public CheckerboardStyle CheckerStyle => m_CheckerStyle;
|
||||
public string LayerName => m_LayerName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 36b1eeadd99b4fd9bfd817b15f131f87
|
||||
timeCreated: 1711702807
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Attributes/Classes/BrushEntityAttribute.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// 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
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public abstract class EntityAttributeBase : SelectionBaseAttribute
|
||||
{
|
||||
protected EntityAttributeBase(string trenchBroomName = null, string category = null)
|
||||
{
|
||||
m_TrenchBroomName = trenchBroomName.Sanitise();
|
||||
m_Category = category.Sanitise();
|
||||
}
|
||||
|
||||
private readonly string m_TrenchBroomName;
|
||||
private readonly string m_Category;
|
||||
|
||||
public string TrenchBroomName => m_TrenchBroomName;
|
||||
public string Category => m_Category;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 84c2d0a79b3844d98271142f9df938e3
|
||||
timeCreated: 1711702912
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Attributes/Classes/EntityAttributeBase.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// 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
|
||||
{
|
||||
/// <summary>
|
||||
/// Marks this MonoBehaviour as a component which can be added to empty GameObjects as a Point entity.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class PointEntityAttribute : EntityAttributeBase
|
||||
{
|
||||
/// <summary>
|
||||
/// A Tremble-compatible Point entity.
|
||||
/// </summary>
|
||||
/// <param name="trenchBroomName">The name in TrenchBroom. e.g. "cool_entity".</param>
|
||||
/// <param name="category">The category for TrenchBroom. e.g. "ent".</param>
|
||||
/// <param name="colour">The colour of the entity in TrenchBroom. e.g. green is "0.0 1.0 0.0".</param>
|
||||
/// <param name="sprite">The sprite to show in TrenchBroom. Must be the name of a texture in your project. e.g. "T_MyTexture".</param>
|
||||
/// <param name="size">The size of the cube for this entity in TrenchBroom. e.g. 5.</param>
|
||||
public PointEntityAttribute(string trenchBroomName = null, string category = null, string colour = null, string sprite = null, float size = 0.25f)
|
||||
: base(trenchBroomName, category)
|
||||
{
|
||||
m_Size = size;
|
||||
m_Sprite = sprite;
|
||||
m_Colour = colour.TryParseQ3Colour(out Color value) ? value : Color.white;
|
||||
}
|
||||
|
||||
private readonly Color? m_Colour;
|
||||
private readonly string m_Sprite;
|
||||
private readonly float m_Size;
|
||||
|
||||
public Color Colour => m_Colour ?? Color.white;
|
||||
public string Sprite => m_Sprite;
|
||||
public float Size => m_Size;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ac6bd87f35f74bf6b78590e9038c0ee4
|
||||
timeCreated: 1711702870
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Attributes/Classes/PointEntityAttribute.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TinyGoose.Tremble
|
||||
{
|
||||
/// <summary>
|
||||
/// Marks this MonoBehaviour as being usable as a Point entity in TrenchBroom, using one or more prefabs in the project.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class PrefabEntityAttribute : EntityAttributeBase
|
||||
{
|
||||
/// <summary>
|
||||
/// A Tremble-compatible Prefab entity.
|
||||
/// </summary>
|
||||
/// <param name="trenchBroomName">The name in TrenchBroom. e.g. "P_MyPrefab".</param>
|
||||
/// <param name="category">The category for TrenchBroom. e.g. "game".</param>
|
||||
/// <param name="excludePrefabs">Which prefabs containing this script to exclude. e.g. "P_BaseCoinPrefab".</param>
|
||||
/// <param name="onlyIncludePrefabs">Which prefabs containing this script to include. e.g. "P_TrembleCoinPrefab".</param>
|
||||
/// <param name="excludePrefab">Which prefabs containing this script to exclude. e.g. "P_BasePrefab".</param>
|
||||
/// <param name="onlyIncludePrefab">Which prefabs containing this script to include. e.g. "P_TrembleCoinPrefab".</param>
|
||||
/// <param name="onlyVariants">Only export variants, not root prefabs</param>
|
||||
public PrefabEntityAttribute(string trenchBroomName = null, string category = null, string[] excludePrefabs = null, string[] onlyIncludePrefabs = null, string excludePrefab = null, string onlyIncludePrefab = null, bool onlyVariants = false, string overrideSprite = null)
|
||||
: base(trenchBroomName: trenchBroomName, category: category)
|
||||
{
|
||||
m_ExcludedPrefabNames = excludePrefab != null ? new [] { excludePrefab } : excludePrefabs;
|
||||
m_OnlyIncludedPrefabNames = onlyIncludePrefab != null ? new [] { onlyIncludePrefab } : onlyIncludePrefabs;
|
||||
|
||||
m_OverrideSprite = overrideSprite;
|
||||
m_OnlyVariants = onlyVariants;
|
||||
}
|
||||
|
||||
private readonly string[] m_ExcludedPrefabNames;
|
||||
private readonly string[] m_OnlyIncludedPrefabNames;
|
||||
|
||||
private readonly string m_OverrideSprite;
|
||||
private readonly bool m_OnlyVariants;
|
||||
|
||||
public bool IsPrefabIncluded(string prefabName)
|
||||
{
|
||||
// Is excluded explicitly?
|
||||
if (m_ExcludedPrefabNames != null)
|
||||
{
|
||||
foreach (string excluded in m_ExcludedPrefabNames)
|
||||
{
|
||||
if (excluded.ToSimpleRegex().IsMatch(prefabName))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Include everything?
|
||||
if (m_OnlyIncludedPrefabNames == null)
|
||||
return true;
|
||||
|
||||
// See if it's on the whitelist
|
||||
foreach (string included in m_OnlyIncludedPrefabNames)
|
||||
{
|
||||
if (included.ToSimpleRegex().IsMatch(prefabName))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public string OverrideSprite => m_OverrideSprite;
|
||||
public bool OnlyVariants => m_OnlyVariants;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7573313e4df24673a7c5cbbc3763e392
|
||||
timeCreated: 1711702750
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Attributes/Classes/PrefabEntityAttribute.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace TinyGoose.Tremble
|
||||
{
|
||||
public static class SimpleRegexUtil
|
||||
{
|
||||
public static Regex ToSimpleRegex(this string pattern)
|
||||
{
|
||||
// This is overly simplistic. But essentially, changes a pattern like
|
||||
// "my*thing" into a Regex like "^my.+thing$"
|
||||
return new($"^{pattern.Replace("*", ".+")}$");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eab674612dfd47fd833e72b6bbd5f974
|
||||
timeCreated: 1713786722
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Attributes/Classes/SimpleRegexUtil.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5fa882a49b914d46a6bdb96c4d52677a
|
||||
timeCreated: 1711702720
|
||||
@@ -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;
|
||||
|
||||
namespace TinyGoose.Tremble
|
||||
{
|
||||
/// <summary>
|
||||
/// Marks this boolean as being a spawnflags field.
|
||||
/// You can either provide an explicit bit to use, or omit and let the system guess based on order.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
|
||||
public class SpawnFlagsAttribute : Attribute
|
||||
{
|
||||
public SpawnFlagsAttribute(int bit = -1)
|
||||
{
|
||||
//NOTE: Change MapBspGetters if this changes!!
|
||||
m_Bit = bit;
|
||||
}
|
||||
|
||||
private readonly int m_Bit;
|
||||
public int Bit => m_Bit;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marks this boolean as never being a spawnflags field.
|
||||
/// Use this is you have the auto-spawnflags flag set for booleans.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public class NoSpawnFlagsAttribute : Attribute
|
||||
{
|
||||
//NOTE: Change MapBspGetters if this changes!!
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0102725e5aa1439cbb30a9675ce4513d
|
||||
timeCreated: 1705750006
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Attributes/Fields/SpawnFlagsAttribute.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TinyGoose.Tremble
|
||||
{
|
||||
/// <summary>
|
||||
/// Marks a field as being serialised for maps (even if [SerializeField] is absent)
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
|
||||
public class TrembleAttribute : Attribute
|
||||
{
|
||||
public TrembleAttribute(string name = null, bool isRotation = false)
|
||||
{
|
||||
//NOTE: Change MapBspGetters if this changes!!
|
||||
m_OverrideName = name;
|
||||
m_IsRotation = isRotation;
|
||||
}
|
||||
|
||||
private readonly string m_OverrideName;
|
||||
private readonly bool m_IsRotation;
|
||||
|
||||
public string OverrideName => m_OverrideName;
|
||||
public bool IsRotation => m_IsRotation;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Marks a field as NEVER being serialised for maps (even if [SerializeField] is on)
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public class NoTrembleAttribute : Attribute
|
||||
{
|
||||
//NOTE: Change MapBspGetters if this changes!!
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 071a562d7c7647a18ebeb57869dfad3a
|
||||
timeCreated: 1711702937
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Attributes/Fields/TrembleAttribute.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0a01f5c71da3c76438e49ca9f447b5a1
|
||||
folderAsset: yes
|
||||
timeCreated: 1628505674
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 613ba1a10f2f46bf811791d8497c3047
|
||||
timeCreated: 1715620765
|
||||
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using UnityEditor.AssetImporters;
|
||||
using UnityEngine;
|
||||
using System.IO;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
[ScriptedImporter(1, "fgd", -1000)]
|
||||
public class FgdFileAssetImporter : ScriptedImporter
|
||||
{
|
||||
[SerializeField] private bool m_Test;
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// Entry Point
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
public override void OnImportAsset(AssetImportContext ctx)
|
||||
{
|
||||
string assetName = Path.GetFileNameWithoutExtension(ctx.assetPath);
|
||||
|
||||
FgdFileAsset wadAsset = ScriptableObject.CreateInstance<FgdFileAsset>();
|
||||
wadAsset.name = assetName;
|
||||
|
||||
ctx.AddObjectToAsset(assetName, wadAsset);
|
||||
ctx.SetMainObject(wadAsset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fa734ddeb7244212a39e586474ae10a2
|
||||
timeCreated: 1724694974
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/AssetImporters/FgdFileAssetImporter.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,231 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
// This class based on BSP Map Tools for Unity by John Evans (evans3d512@gmail.com)
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor.AssetImporters;
|
||||
using UnityEngine;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
[ScriptedImporter(1, "map", importQueueOffset: 20000)]
|
||||
public class TrembleMapAssetImporter : ScriptedImporter
|
||||
{
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// Exposed
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
[SerializeField, Tooltip("The Map Processors to use (or none). Used to perform logic for individual entities from the map or on the map as a whole.")]
|
||||
private MapProcessorClass[] m_Processors;
|
||||
|
||||
[SerializeField, Tooltip("Whether to split the mesh when surface area is too large?")]
|
||||
private bool m_SplitMesh = true;
|
||||
|
||||
[SerializeField, Tooltip("Maximum surface area (in m^2) before splitting meshes")]
|
||||
private float m_MaxMeshSurfaceArea = 3000;
|
||||
|
||||
[SerializeField, Tooltip("The angle above which to smooth edges.")]
|
||||
private float m_SmoothingAngle = 45;
|
||||
|
||||
[SerializeField, Tooltip("Extra commandline to pass to Q3Map2 - see https://en.wikibooks.org/wiki/Q3Map2 for more details")]
|
||||
private string m_ExtraCommandLineArgs = "";
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// Entry Point
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
public override async void OnImportAsset(AssetImportContext ctx)
|
||||
{
|
||||
// Check autosave and bail
|
||||
if (String.Equals(Path.GetFileName(Path.GetDirectoryName(ctx.assetPath)), "autosave", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Check we have a functioning setup (not first import, for example)
|
||||
if (!Directory.Exists(TrembleConsts.BASEQ3_PATH))
|
||||
{
|
||||
ctx.LogImportWarning($"Can't import map {Path.GetFileName(ctx.assetPath)}. Please sync first.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (MapRepairWindow.IsMapForeign(ctx.assetPath, out string gameName))
|
||||
{
|
||||
gameName ??= "Quake(?)";
|
||||
|
||||
bool repairNow = EditorUtility.DisplayDialog(
|
||||
title: "Map Repair Required",
|
||||
message: $"You are trying to import a map from '{gameName}'. Before you can use this map, " +
|
||||
"we'll need to repair it. This converts it for use with Tremble " +
|
||||
$"and '{TrembleConsts.GAME_NAME}'. Shall we?",
|
||||
"Repair and Resave", "Not Now");
|
||||
|
||||
if (repairNow)
|
||||
{
|
||||
MapRepairWindow.OpenMapRepair(ctx.assetPath);
|
||||
}
|
||||
|
||||
ctx.LogImportError($"Map '{Path.GetFileNameWithoutExtension(ctx.assetPath)}' needs repair to function with Tremble. Right-click the map and select 'Repair Map'.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear our cached asset lists
|
||||
UnityObjectFieldConverterStatics.s_CachedAssetLists.Clear();
|
||||
|
||||
MapProcessorClass[] allProcessors = TrembleSyncSettings.Get().PipelineRunMapProcessors // global processors
|
||||
? TrembleSyncSettings.Get().EnabledMapProcessors
|
||||
: Array.Empty<MapProcessorClass>();
|
||||
|
||||
if (m_Processors != null)
|
||||
{
|
||||
allProcessors = allProcessors.Concat(m_Processors).Distinct().ToArray(); // map-based processors
|
||||
}
|
||||
|
||||
TrembleMapImport importer = new(new()
|
||||
{
|
||||
ProcessorClasses = allProcessors,
|
||||
SplitMesh = m_SplitMesh,
|
||||
MaxMeshSurfaceArea = m_MaxMeshSurfaceArea,
|
||||
SmoothingAngle = m_SmoothingAngle,
|
||||
ExtraCommandLineArgs = m_ExtraCommandLineArgs,
|
||||
AssetGUID = AssetDatabase.GUIDFromAssetPath(ctx.assetPath).ToString(),
|
||||
|
||||
OnObjectAdded = ctx.AddObjectToAsset,
|
||||
OnDependencyAdded = o =>
|
||||
{
|
||||
if (TrembleSyncSettings.Get().AutomaticallyReimportWhenDependencyChanges)
|
||||
{
|
||||
ctx.DependsOnSourceAsset(AssetDatabase.GetAssetPath(o));
|
||||
}
|
||||
},
|
||||
OnWadsFound = OnWadsFound,
|
||||
OnEntityAdded = OnEntityAdded,
|
||||
|
||||
OnError = err => ctx.LogImportError(err),
|
||||
OnWarning = warn => ctx.LogImportWarning(warn),
|
||||
OnQ3Map2Result = OnQ3Map2Result
|
||||
});
|
||||
|
||||
TrembleTimer.BeginSession($"Tremble Map Import for {Path.GetFileNameWithoutExtension(ctx.assetPath)}");
|
||||
MapDocument document = await importer.ImportMapAndCreatePrefab(ctx.assetPath);
|
||||
TrembleTimer.EndSession();
|
||||
|
||||
ctx.AddObjectToAsset("map", document.gameObject);
|
||||
ctx.SetMainObject(document.gameObject);
|
||||
}
|
||||
|
||||
private void OnEntityAdded(GameObject gameObject, Type entityType)
|
||||
{
|
||||
if (entityType == null)
|
||||
return;
|
||||
|
||||
// Point entity with explicit icon?
|
||||
entityType.GetCustomAttributes(out PointEntityAttribute pea);
|
||||
|
||||
if (pea is { Sprite: not null })
|
||||
{
|
||||
string spritePath = TrembleAssetLoader.FindAssetPath<Texture2D>(pea.Sprite);
|
||||
Texture2D texture = AssetDatabase.LoadAssetAtPath<Texture2D>(spritePath);
|
||||
|
||||
EditorGUIUtility.SetIconForObject(gameObject, texture);
|
||||
return;
|
||||
}
|
||||
|
||||
// Implicit
|
||||
TrembleSyncSettings syncSettings = TrembleSyncSettings.Get();
|
||||
if (syncSettings.EntityIconStyle == EntityIconStyle.Nothing)
|
||||
return;
|
||||
|
||||
if (entityType.FullName == null)
|
||||
return;
|
||||
|
||||
int hash = Math.Abs(entityType.FullName.GetHashCode());
|
||||
|
||||
switch (syncSettings.EntityIconStyle)
|
||||
{
|
||||
case EntityIconStyle.ColouredDiamondShapes:
|
||||
int shapeIdx = hash % (int)EditorGameObjectIconUtil.EditorIcon.MAX;
|
||||
gameObject.SetEditorIcon((EditorGameObjectIconUtil.EditorIcon)shapeIdx);
|
||||
break;
|
||||
case EntityIconStyle.ColouredLabels:
|
||||
int labelIdx = hash % (int)EditorGameObjectIconUtil.EditorLabel.MAX;
|
||||
gameObject.SetEditorIcon((EditorGameObjectIconUtil.EditorLabel)labelIdx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnWadsFound(string[] allWads)
|
||||
{
|
||||
string[] validWads = allWads.Where(File.Exists).ToArray();
|
||||
|
||||
foreach (string wad in validWads)
|
||||
{
|
||||
Debug.LogWarning($"Wad file found in map: {Path.GetFileName(wad)}. You should drop this file into your Unity project in order to use its materials!");
|
||||
}
|
||||
|
||||
// bool copyThem = false;
|
||||
//
|
||||
// if (validWads.Length == 0)
|
||||
// {
|
||||
// EditorUtility.DisplayDialog(
|
||||
// title: "Wad Files",
|
||||
// message: $"Your map contains {allWads.Length} unknown wad file reference(s). " +
|
||||
// "These are not directly supported by Tremble. If you want to use the textures " +
|
||||
// "from your wad file(s), drag them into your Unity project and extract them.", "Ahh, okay");
|
||||
// }
|
||||
// else if (validWads.Length == allWads.Length)
|
||||
// {
|
||||
// copyThem = EditorUtility.DisplayDialog(
|
||||
// title: "Wad Files",
|
||||
// message: $"Your map contains {validWads.Length} wad file reference(s). " +
|
||||
// "These are not directly supported by Tremble. If you want to use the textures " +
|
||||
// "from your wad file(s), they need extracting into your Unity project. Want to import them now?", "Yup!", "Nope");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// int numMissing = allWads.Length - validWads.Length;
|
||||
//
|
||||
// copyThem = EditorUtility.DisplayDialog(
|
||||
// title: "Wad Files",
|
||||
// message: $"Your map contains {validWads.Length} valid wad file reference(s), and {numMissing} which Tremble couldn't locate. " +
|
||||
// "These are not directly supported by Tremble. If you want to use the textures " +
|
||||
// "from your wad file(s), they need extracting into your Unity project. Want to import the ones we could find now?", "Yup!", "Nope");
|
||||
// }
|
||||
//
|
||||
// if (copyThem)
|
||||
// {
|
||||
// string folderName = Path.GetDirectoryName(assetPath);
|
||||
//
|
||||
// foreach (string existingPath in validWads)
|
||||
// {
|
||||
// string filename = Path.GetFileName(existingPath);
|
||||
// File.Copy(existingPath, Path.Combine(folderName, filename));
|
||||
// }
|
||||
//
|
||||
// EditorApplication.delayCall += () => AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
|
||||
// }
|
||||
}
|
||||
|
||||
private void OnQ3Map2Result(Q3Map2Result result, List<string> output)
|
||||
{
|
||||
// Show results?
|
||||
TrembleSyncSettings syncSettings = TrembleSyncSettings.Get();
|
||||
|
||||
bool alwaysShowResult = syncSettings.Q3Map2ResultDisplayType == Q3Map2ResultDisplayType.AlwaysShow;
|
||||
bool showWarnings = syncSettings.Q3Map2ResultDisplayType == Q3Map2ResultDisplayType.ShowWhenWarningsOccur;
|
||||
|
||||
bool showWindow = result is Q3Map2Result.Failed or Q3Map2Result.FailedWithMissingTextures;
|
||||
showWindow |= (result is Q3Map2Result.SucceededWithWarnings && showWarnings);
|
||||
showWindow |= alwaysShowResult;
|
||||
|
||||
if (showWindow)
|
||||
{
|
||||
Q3Map2OutputWindow.Open(output, alwaysShowResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab79840212e84ded961df5ef93736275
|
||||
timeCreated: 1698136122
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/AssetImporters/TrembleMapAssetImporter.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using UnityEditor.AssetImporters;
|
||||
using UnityEngine;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
[ScriptedImporter(1, "wad", -1000)]
|
||||
public class WadFileAssetImporter : ScriptedImporter
|
||||
{
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// Entry Point
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
public override void OnImportAsset(AssetImportContext ctx)
|
||||
{
|
||||
string assetName = Path.GetFileNameWithoutExtension(ctx.assetPath);
|
||||
|
||||
WadFileAsset wadAsset = ScriptableObject.CreateInstance<WadFileAsset>();
|
||||
wadAsset.Modify(so =>
|
||||
{
|
||||
SerializedProperty materials = so.FindBackedProperty(nameof(wadAsset.MaterialNames));
|
||||
|
||||
WadParser parser = new(ctx.assetPath);
|
||||
WadFile wadFile = parser.Parse();
|
||||
|
||||
foreach (WadEntry entry in wadFile.Entries)
|
||||
{
|
||||
materials.AppendArrayElement().stringValue = entry.Name;
|
||||
}
|
||||
});
|
||||
wadAsset.name = assetName;
|
||||
|
||||
ctx.AddObjectToAsset(assetName, wadAsset);
|
||||
ctx.SetMainObject(wadAsset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aa9cb8112a5643be99429353283f1858
|
||||
timeCreated: 1722847571
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/AssetImporters/WadFileAssetImporter.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab61355f926040629a80ee28e5683483
|
||||
timeCreated: 1709458791
|
||||
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using System;
|
||||
using UnityEditor;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
public class FgdFileAssetPostprocessor : AssetPostprocessor
|
||||
{
|
||||
private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
|
||||
{
|
||||
foreach (string requestFileName in importedAssets)
|
||||
{
|
||||
// We imported something, but not a MapFileAsset
|
||||
if (AssetDatabase.GetMainAssetTypeAtPath(requestFileName) != typeof(FgdFileAsset))
|
||||
continue;
|
||||
|
||||
bool success = false;
|
||||
|
||||
try
|
||||
{
|
||||
FgdParser.Import(requestFileName);
|
||||
success = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!success)
|
||||
{
|
||||
EditorUtility.DisplayDialog("Import Failed!", "Failed to import FGD file :(, try again!", "Okay");
|
||||
}
|
||||
AssetDatabase.DeleteAsset(requestFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 04f793041d9e49d7822ba5068a727bb7
|
||||
timeCreated: 1724694689
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/AssetProcessors/FgdFileAssetPostprocessor.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,146 @@
|
||||
//
|
||||
// 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.Linq;
|
||||
using System.Text;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
public class MapFileAssetPostprocessor : AssetPostprocessor
|
||||
{
|
||||
private static readonly Stack<string> s_MapsToConvert = new();
|
||||
private static string s_LastMapPath;
|
||||
|
||||
private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
|
||||
{
|
||||
foreach (string requestFileName in importedAssets)
|
||||
{
|
||||
// We imported something, but not a MapFileAsset
|
||||
if (AssetDatabase.GetMainAssetTypeAtPath(requestFileName) != typeof(MapFileAsset))
|
||||
continue;
|
||||
|
||||
// Check we haven't already processed this map, or already plan to
|
||||
string mapFileName = GetMapFileName(requestFileName);
|
||||
if (File.Exists(mapFileName) || s_MapsToConvert.Contains(requestFileName))
|
||||
continue;
|
||||
|
||||
// Add to the work queue
|
||||
s_MapsToConvert.Push(requestFileName);
|
||||
|
||||
// Start conversion process
|
||||
EditorApplication.update -= PerformConversionOnUpdate;
|
||||
EditorApplication.update += PerformConversionOnUpdate;
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetMapFileName(string requestFileName) => requestFileName.Replace(".asset", ".map");
|
||||
|
||||
private static void PerformConversionOnUpdate()
|
||||
{
|
||||
// Nothing left to do - stop!
|
||||
if (s_MapsToConvert.Count == 0)
|
||||
{
|
||||
EditorApplication.update -= PerformConversionOnUpdate;
|
||||
return;
|
||||
}
|
||||
|
||||
string requestFileName = s_MapsToConvert.Pop();
|
||||
|
||||
// Delete the request file
|
||||
string mapFileName = GetMapFileName(requestFileName);
|
||||
AssetDatabase.DeleteAsset(requestFileName);
|
||||
|
||||
// Open new file for write
|
||||
using FileStream file = File.Create(mapFileName);
|
||||
using StreamWriter sw = new(file, Encoding.ASCII);
|
||||
|
||||
// Write a blank map, or copy template
|
||||
TrembleSyncSettings trembleSyncSettings = TrembleSyncSettings.Get();
|
||||
if (trembleSyncSettings.TemplateMap && trembleSyncSettings.TemplateMap.TryGetComponent(out MapDocument _))
|
||||
{
|
||||
string templatePath = AssetDatabase.GetAssetPath(trembleSyncSettings.TemplateMap);
|
||||
|
||||
using FileStream templateFile = File.OpenRead(templatePath);
|
||||
using StreamReader sr = new(templateFile, Encoding.ASCII);
|
||||
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
sw.WriteLine(sr.ReadLine());
|
||||
}
|
||||
sr.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
// New file
|
||||
sw.WriteLine($"// Game: {TrembleConsts.GAME_NAME}");
|
||||
sw.WriteLine("// Format: Quake3 (Valve)");
|
||||
sw.WriteLine("// entity 0");
|
||||
sw.WriteLine("{");
|
||||
sw.WriteLine("\"mapversion\" \"220\"");
|
||||
|
||||
sw.Write("\"_tb_textures\" \"");
|
||||
List<MaterialGroup> materialGroups = trembleSyncSettings.GetMaterialGroupsOrDefault();
|
||||
sw.Write(String.Join(';', materialGroups.Select(mg => $"textures/{mg.Name}")));
|
||||
sw.WriteLine("\"");
|
||||
|
||||
sw.WriteLine("\"classname\" \"worldspawn\"");
|
||||
sw.WriteLine("// brush 0");
|
||||
sw.WriteLine("{");
|
||||
sw.WriteLine("( -128 -128 -64 ) ( -128 -127 -64 ) ( -128 -128 -63 ) __TB_empty [ 0 -1 0 0 ] [ 0 0 -1 0 ] 0 0.5 0.5");
|
||||
sw.WriteLine("( -128 -128 -64 ) ( -128 -128 -63 ) ( -127 -128 -64 ) __TB_empty [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 0.5 0.5");
|
||||
sw.WriteLine("( -128 -128 -64 ) ( -127 -128 -64 ) ( -128 -127 -64 ) __TB_empty [ -1 0 0 0 ] [ 0 -1 0 0 ] 0 0.5 0.5");
|
||||
sw.WriteLine("( 128 128 64 ) ( 128 129 64 ) ( 129 128 64 ) __TB_empty [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 0.5 0.5");
|
||||
sw.WriteLine("( 128 128 64 ) ( 129 128 64 ) ( 128 128 65 ) __TB_empty [ -1 0 0 0 ] [ 0 0 -1 0 ] 0 0.5 0.5");
|
||||
sw.WriteLine("( 128 128 64 ) ( 128 128 65 ) ( 128 129 64 ) __TB_empty [ 0 1 0 0 ] [ 0 0 -1 0 ] 0 0.5 0.5");
|
||||
sw.WriteLine("}");
|
||||
sw.WriteLine("}");
|
||||
}
|
||||
|
||||
sw.Close();
|
||||
|
||||
// Open in TB?
|
||||
if (EditorUtility.DisplayDialog("Map Created!", "Want to open it now in TrenchBroom?", "Yep!", "Not now..."))
|
||||
{
|
||||
TrembleEditorAPI.SyncToTrenchBroom();
|
||||
TrenchBroomUtil.OpenWithTrenchBroom(mapFileName);
|
||||
|
||||
s_LastMapPath = mapFileName;
|
||||
|
||||
EditorApplication.update -= PromptToOpenMapOnFocus;
|
||||
EditorApplication.update += PromptToOpenMapOnFocus;
|
||||
}
|
||||
}
|
||||
|
||||
private static void PromptToOpenMapOnFocus()
|
||||
{
|
||||
#if UNITY_2022_1_OR_NEWER
|
||||
if (!EditorApplication.isFocused)
|
||||
return;
|
||||
#endif
|
||||
|
||||
EditorApplication.update -= PromptToOpenMapOnFocus;
|
||||
|
||||
// Place in world?
|
||||
if (EditorUtility.DisplayDialog("Welcome back!", "Want to place your brand new map in this Unity scene?", "Yep!", "No thanks"))
|
||||
{
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
GameObject mapPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(s_LastMapPath);
|
||||
if (!mapPrefab)
|
||||
{
|
||||
EditorUtility.DisplayDialog("Oh no!", "Your new map failed to import. You may need to restart Unity and then reimport it. (this is a rare bug)", "Okay :(");
|
||||
return;
|
||||
}
|
||||
GameObject mapObject = (GameObject)PrefabUtility.InstantiatePrefab(mapPrefab);
|
||||
mapObject.transform.position = Vector3.zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6642958d88f3475995ac5c15d631af2d
|
||||
timeCreated: 1707842798
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/AssetProcessors/MapFileAssetPostprocessor.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,202 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using Debug = UnityEngine.Debug;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
public class MapLiveUpdatePostprocessor : AssetPostprocessor
|
||||
{
|
||||
private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
|
||||
{
|
||||
if (!Application.isPlaying || !TrembleSyncSettings.Get().UseLiveUpdate)
|
||||
return;
|
||||
|
||||
// Get list of imported GUIDs as strings
|
||||
string[] importedGUIDs = importedAssets
|
||||
.Select(path => AssetDatabase.GUIDFromAssetPath(path).ToString())
|
||||
.ToArray();
|
||||
|
||||
// If we reimport during gameplay, disable and re-enable the map to refresh the collision
|
||||
Scene scene = SceneManager.GetActiveScene();
|
||||
MapDocument[] updatedMaps = scene.GetRootGameObjects()
|
||||
.SelectMany(go => go.GetComponentsInChildren<MapDocument>())
|
||||
.Where(doc => importedGUIDs.Contains(doc.OriginalAssetGuid))
|
||||
.ToArray();
|
||||
|
||||
foreach (MapDocument map in updatedMaps)
|
||||
{
|
||||
Stopwatch timer = new();
|
||||
timer.Start();
|
||||
|
||||
string assetPath = AssetDatabase.GUIDToAssetPath(map.OriginalAssetGuid);
|
||||
GameObject prefabMap = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
|
||||
MapDocument prefabMapDocument = prefabMap.GetComponent<MapDocument>();
|
||||
|
||||
// Re-instance worldspawn
|
||||
GameObject newWorldspawn = InstanceNewWorldspawn(map, prefabMapDocument);
|
||||
|
||||
// Spawn any new objects, and transfer vars to existing
|
||||
int numNewlySpawned = 0;
|
||||
int numUpdated = 0;
|
||||
foreach (Transform prefabChild in prefabMap.transform)
|
||||
{
|
||||
if (prefabChild.gameObject == prefabMapDocument.WorldspawnObject)
|
||||
continue;
|
||||
|
||||
bool isNew = true;
|
||||
foreach (Transform mapChild in map.transform)
|
||||
{
|
||||
if (mapChild.name != prefabChild.name)
|
||||
continue;
|
||||
|
||||
numUpdated++;
|
||||
|
||||
// Object is static :( grab it from the map instead
|
||||
if (mapChild.gameObject.isStatic && HasEntityMoved(mapChild, prefabChild))
|
||||
{
|
||||
Debug.LogWarning($"Tremble LiveUpdate: Replacing static object '{mapChild.name}' with new copy. This could cause issues!");
|
||||
GameObject.Destroy(mapChild.gameObject);
|
||||
break;
|
||||
}
|
||||
|
||||
if (TryFindTrembleComponent(prefabChild.gameObject, out Component prefabComp) &&
|
||||
TryFindTrembleComponent(mapChild.gameObject, out Component mapComp))
|
||||
{
|
||||
// Disable, copy across data, re-enable
|
||||
mapComp.gameObject.SetActive(false);
|
||||
CopySafeSerialisedData(from: prefabComp, to: mapComp);
|
||||
mapComp.gameObject.SetActive(true);
|
||||
|
||||
// Handle live update callbacks
|
||||
switch (mapComp)
|
||||
{
|
||||
case IOnLiveUpdate_Simple:
|
||||
mapComp.SendMessage("OnDestroy", SendMessageOptions.DontRequireReceiver);
|
||||
mapComp.SendMessage("Awake", SendMessageOptions.DontRequireReceiver);
|
||||
mapComp.SendMessage("Start", SendMessageOptions.DontRequireReceiver);
|
||||
break;
|
||||
|
||||
case IOnLiveUpdate liveUpdateable:
|
||||
liveUpdateable.OnLiveUpdated();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
isNew = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (isNew)
|
||||
{
|
||||
numNewlySpawned++;
|
||||
GameObject.Instantiate(prefabChild.gameObject, newWorldspawn.transform);
|
||||
}
|
||||
}
|
||||
|
||||
timer.Stop();
|
||||
|
||||
TryShowGameViewNotification($"Tremble LiveUpdate:\n{numNewlySpawned} new ents\n{numUpdated} updates\nin {timer.ElapsedMilliseconds}ms");
|
||||
}
|
||||
}
|
||||
|
||||
private static bool HasEntityMoved(Transform mapChild, Transform prefabChild)
|
||||
{
|
||||
if (Vector3.SqrMagnitude(mapChild.position - prefabChild.position) > 0f)
|
||||
return true;
|
||||
|
||||
if (Vector3.SqrMagnitude(mapChild.rotation.eulerAngles - prefabChild.rotation.eulerAngles) > 0f)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static GameObject InstanceNewWorldspawn(MapDocument map, MapDocument prefabMapDocument)
|
||||
{
|
||||
// Remove worldspawn
|
||||
GameObject.Destroy(map.WorldspawnObject);
|
||||
|
||||
// Reinstance worldspawn
|
||||
GameObject newWorldspawn = GameObject.Instantiate(prefabMapDocument.WorldspawnObject, map.transform, true);
|
||||
newWorldspawn.transform.localPosition = Vector3.zero;
|
||||
newWorldspawn.transform.localRotation = Quaternion.identity;
|
||||
map.Modify(so => so.FindProperty("m_WorldspawnObject").objectReferenceValue = newWorldspawn);
|
||||
newWorldspawn.transform.SetAsFirstSibling();
|
||||
|
||||
// Disable and re-enable - if you don't do this, Unity does not update the colliders
|
||||
map.gameObject.SetActive(false);
|
||||
map.gameObject.SetActive(true);
|
||||
return newWorldspawn;
|
||||
}
|
||||
|
||||
private static bool TryShowGameViewNotification(string note)
|
||||
{
|
||||
Type gameViewT = typeof(EditorWindow).Assembly.GetType("UnityEditor.GameView");
|
||||
|
||||
EditorWindow[] windows = Resources.FindObjectsOfTypeAll(gameViewT).Cast<EditorWindow>().ToArray();
|
||||
foreach (EditorWindow win in windows)
|
||||
{
|
||||
win.ShowNotification(new(note), 1f);
|
||||
}
|
||||
|
||||
return windows.Length > 0;
|
||||
}
|
||||
|
||||
private static bool TryFindTrembleComponent(GameObject go, out Component component)
|
||||
{
|
||||
foreach (Component c in go.GetComponents<Component>())
|
||||
{
|
||||
if (!c.GetType().HasCustomAttribute<EntityAttributeBase>())
|
||||
continue;
|
||||
|
||||
component = c;
|
||||
return true;
|
||||
}
|
||||
|
||||
component = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void CopySafeSerialisedData(Component from, Component to)
|
||||
{
|
||||
// For now, we just copy simple data - floats, colours, vectors etc.
|
||||
// References and assets are a bit spoopier and we can't do too much there sadly!
|
||||
|
||||
SerializedObject fromObject = new(from);
|
||||
SerializedObject toObject = new(to);
|
||||
|
||||
SerializedProperty iterator = fromObject.GetIterator();
|
||||
iterator.NextVisible(true);
|
||||
|
||||
do
|
||||
{
|
||||
if (iterator.propertyType
|
||||
is SerializedPropertyType.ObjectReference
|
||||
or SerializedPropertyType.ManagedReference)
|
||||
{
|
||||
if (iterator.objectReferenceValue is Component)
|
||||
continue;
|
||||
}
|
||||
|
||||
toObject.CopyFromSerializedProperty(iterator);
|
||||
} while (iterator.NextVisible(false));
|
||||
|
||||
toObject.ApplyModifiedPropertiesWithoutUndo();
|
||||
|
||||
// Also copy basic positioning information
|
||||
Transform fromTransform = from.transform;
|
||||
Transform toTransform = to.transform;
|
||||
|
||||
toTransform.localPosition = fromTransform.localPosition;
|
||||
toTransform.localRotation = fromTransform.localRotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de0e937a05b84f928a4e0c9ff6d32146
|
||||
timeCreated: 1708536137
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/AssetProcessors/MapLiveUpdatePostprocessor.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using UnityEditor;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
public class TrembleCacheDropperPostprocessor : AssetPostprocessor
|
||||
{
|
||||
private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
|
||||
{
|
||||
if (!TrembleSyncSettings.Get().AutomaticallyReimportWhenDependencyChanges)
|
||||
{
|
||||
MapHierarchyIcons.ResetModifiedTimes();
|
||||
}
|
||||
|
||||
EditorLoaderAdaptor.DropCachedAssetPaths();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5e639ddfe46c434eb843b1bd7ee8259c
|
||||
timeCreated: 1713956404
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/AssetProcessors/TrembleCacheDropperPostprocessor.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using UnityEditor;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
public class WadFileAssetPostprocessor : AssetPostprocessor
|
||||
{
|
||||
private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
|
||||
{
|
||||
foreach (string requestFileName in importedAssets)
|
||||
{
|
||||
// We imported something, but not a WadFileAsset
|
||||
if (AssetDatabase.GetMainAssetTypeAtPath(requestFileName) != typeof(WadFileAsset))
|
||||
continue;
|
||||
|
||||
bool success = false;
|
||||
|
||||
try
|
||||
{
|
||||
WadAssetImporterEditor.Extract(requestFileName);
|
||||
success = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!success)
|
||||
{
|
||||
EditorUtility.DisplayDialog("Import Failed!", "Failed to import WAD file :(, try again!", "Okay");
|
||||
}
|
||||
AssetDatabase.DeleteAsset(requestFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c83945126e2c4fa9aa009f1463530bad
|
||||
timeCreated: 1722936486
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/AssetProcessors/WadFileAssetPostprocessor.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b41c2b89aca249e7a68bc85e07f144ed
|
||||
timeCreated: 1707741796
|
||||
@@ -0,0 +1,146 @@
|
||||
//
|
||||
// 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;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
public class DiagnosticsWindow : EditorWindow
|
||||
{
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// Menu Items
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
[MenuItem("Tools/Tremble/Advanced/Debug/Diagnostics")]
|
||||
public static void OpenDiagnosticsWindow()
|
||||
{
|
||||
DiagnosticsWindow window = GetWindow<DiagnosticsWindow>(true, "Tremble Diagnostics", true);
|
||||
|
||||
Vector2 size = new(900f, 800f);
|
||||
window.minSize = size;
|
||||
window.position = new(EditorGUIUtility.GetMainWindowPosition().center - size / 2f, size);
|
||||
window.Show();
|
||||
}
|
||||
|
||||
private Vector2 m_ScrollPosition = Vector2.zero;
|
||||
private FgdWriter m_FgdWriter;
|
||||
private string m_TrenchbroomInstallPath;
|
||||
private Q3Map2VersionInfo m_Q3Map2VersionInfo;
|
||||
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
m_Q3Map2VersionInfo = Q3Map2Dll.GetTinyGooseVersionInfo();
|
||||
m_FgdWriter = TrembleSync.GatherEntities();
|
||||
m_TrenchbroomInstallPath = Path.GetFullPath(TrenchBroomUtil.TrenchBroomPath);
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
m_ScrollPosition = GUILayout.BeginScrollView(m_ScrollPosition);
|
||||
{
|
||||
Header("Basic Info");
|
||||
{
|
||||
Diagnostic("Tremble Version", () => TrembleConsts.VERSION_STRING);
|
||||
Diagnostic("Unity Version", () => Application.unityVersion);
|
||||
Diagnostic("Configured TB Version", () => TrembleSyncSettings.Get().TrenchBroomVersion);
|
||||
Diagnostic("OS", () => Application.platform.ToString());
|
||||
Diagnostic("OS Locale", () => CultureInfo.CurrentCulture.DisplayName);
|
||||
}
|
||||
|
||||
Header("Project Info");
|
||||
{
|
||||
Diagnostic("Project Name", () => Application.productName);
|
||||
Diagnostic("Company Name", () => Application.companyName);
|
||||
Diagnostic("TB Game Name", () => TrembleConsts.GAME_NAME);
|
||||
}
|
||||
|
||||
Header("Paths");
|
||||
{
|
||||
Diagnostic("User Path", () => Environment.GetFolderPath(Environment.SpecialFolder.Personal));
|
||||
Diagnostic("Map Staging Path", () => Application.temporaryCachePath);
|
||||
Diagnostic("Project Path", () => Path.GetFullPath(Directory.GetCurrentDirectory()));
|
||||
Diagnostic("BaseQ3 Path", () => TrembleConsts.BASEQ3_PATH);
|
||||
Diagnostic("TB Game Path", () => Path.GetFullPath(TrenchBroomUtil.GetGameFolder()));
|
||||
Diagnostic("TB Install Path", () => m_TrenchbroomInstallPath);
|
||||
}
|
||||
|
||||
Header("Q3Map2");
|
||||
{
|
||||
Diagnostic("Q3Map2 Loaded?", () => Q3Map2Dll.IsLoaded);
|
||||
Diagnostic("Q3Map2 Version", () => $"{m_Q3Map2VersionInfo.Major}.{m_Q3Map2VersionInfo.Minor}.{m_Q3Map2VersionInfo.Patch}");
|
||||
Diagnostic("Q3Map2 Hash", () => m_Q3Map2VersionInfo.GitHash);
|
||||
Diagnostic("Q3Map2 Cmdline", () => TrembleSyncSettings.Get().ExtraCommandLineArgs);
|
||||
}
|
||||
|
||||
Header("Game");
|
||||
{
|
||||
Diagnostic("Worldspawn Entity", () => m_FgdWriter.WorldspawnClass.Name);
|
||||
Diagnostic("Map Processors", () => TrembleSyncSettings.Get().EnabledMapProcessors.Select(m => m.Class.Name));
|
||||
|
||||
int numMaterials = TrembleSyncSettings.Get().MaterialGroups.Sum(mg => mg.Materials.Length);
|
||||
Diagnostic("Material Groups", () => TrembleSyncSettings.Get().MaterialGroups.Select(mg => $"{mg.Name} ({mg.Materials.Length})").Append($"= {numMaterials} total materials"));
|
||||
|
||||
int numBases = m_FgdWriter.BaseClasses.Count;
|
||||
int numPoints = m_FgdWriter.Classes.Count(e => e.Type == FgdClassType.Point);
|
||||
int numBrushes = m_FgdWriter.Classes.Count(e => e.Type == FgdClassType.Brush);
|
||||
Diagnostic("Entity Counts", () => $"{numBases} base(s), {numPoints} point(s), {numBrushes} brush(es)");
|
||||
}
|
||||
}
|
||||
GUILayout.EndScrollView();
|
||||
}
|
||||
|
||||
private void Header(string header)
|
||||
{
|
||||
GUILayout.Space(20f);
|
||||
GUILayout.Label(header, EditorStyles.boldLabel);
|
||||
}
|
||||
|
||||
private void Diagnostic(string labelTitle, Func<object> contents)
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
GUILayout.Space(20f);
|
||||
GUILayout.Label(labelTitle, GUILayout.Width(200f));
|
||||
|
||||
try
|
||||
{
|
||||
object contentObject = contents();
|
||||
if (contentObject is IEnumerable contentObjects and not string)
|
||||
{
|
||||
GUILayout.BeginVertical();
|
||||
{
|
||||
IEnumerator objectEnumerator = contentObjects.GetEnumerator();
|
||||
using IDisposable _ = objectEnumerator as IDisposable; // ensure disposed
|
||||
|
||||
while (objectEnumerator.MoveNext())
|
||||
{
|
||||
GUILayout.Label(objectEnumerator.Current?.ToString() ?? "<null>", ManualStyles.Styles.Code, GUILayout.ExpandWidth(true));
|
||||
}
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
else
|
||||
{
|
||||
GUILayout.Label(contentObject.ToString(), ManualStyles.Styles.Code, GUILayout.ExpandWidth(true));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
GUI.color = Color.red;
|
||||
GUILayout.Label($"FAILED: {ex.Message}", ManualStyles.Styles.Code, GUILayout.ExpandWidth(true));
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: da8c52d53f104a499424ec4d338cb7d1
|
||||
timeCreated: 1740735928
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/EditorUI/DiagnosticsWindow.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de5403ed015546f98e39cd02b728ba9b
|
||||
timeCreated: 1710244760
|
||||
@@ -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 System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
public abstract class BaseClassPickerDrawer<TClassType> : PropertyDrawer
|
||||
{
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// Consts
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
private const string INDENT_STRING = " ";
|
||||
private const string NONE_STRING = "(none)";
|
||||
|
||||
protected abstract string ClassNamePropertyName { get; }
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// State
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
private List<Type> m_AllClasses;
|
||||
private int m_SelectedClass;
|
||||
|
||||
private bool m_Inited;
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
// Lazy-load class catalog if needed
|
||||
if (!m_Inited)
|
||||
{
|
||||
m_Inited = true;
|
||||
GenerateClassCatalog();
|
||||
}
|
||||
|
||||
// Draw label & icon
|
||||
position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
|
||||
EditorGUI.indentLevel = 0;
|
||||
|
||||
// Generate class list
|
||||
string[] classDisplayNames = m_AllClasses.Select(t => GetHumanClassName(t)).ToArray();
|
||||
|
||||
// Calculate current index
|
||||
SerializedProperty classProperty = property.FindPropertyRelative(ClassNamePropertyName);
|
||||
int prevSelectedClass = m_AllClasses.FindIndex(c => c.FullName == classProperty.stringValue);
|
||||
if (prevSelectedClass == -1)
|
||||
{
|
||||
prevSelectedClass = 0;
|
||||
}
|
||||
|
||||
m_SelectedClass = EditorGUI.Popup(position, "", prevSelectedClass, classDisplayNames);
|
||||
|
||||
EditorGUI.BeginProperty(position, GUIContent.none, property);
|
||||
classProperty.stringValue = m_AllClasses[m_SelectedClass].FullName;
|
||||
EditorGUI.EndProperty();
|
||||
|
||||
// Draw icon overlay
|
||||
Rect iconRect = position;
|
||||
iconRect.width = position.height;
|
||||
iconRect.x += 2f;
|
||||
iconRect.y += 2f;
|
||||
iconRect.width -= 4f;
|
||||
iconRect.height -= 4f;
|
||||
|
||||
position.x += position.height;
|
||||
position.width -= position.height;
|
||||
|
||||
GUI.DrawTexture(iconRect, EditorGUIUtility.FindTexture("cs Script Icon"));
|
||||
}
|
||||
|
||||
private void GenerateClassCatalog()
|
||||
{
|
||||
List<Type> allClasses = TypeCache.GetTypesDerivedFrom(typeof(TClassType)).ToList();
|
||||
m_AllClasses = new(allClasses.Count + 1);
|
||||
|
||||
if (!typeof(TClassType).IsAbstract)
|
||||
{
|
||||
m_AllClasses.Add(typeof(TClassType));
|
||||
}
|
||||
m_AllClasses.AddRange(allClasses);
|
||||
}
|
||||
|
||||
private static string GetHumanClassName(Type type, bool indent = true)
|
||||
{
|
||||
string fullClassName = type.FullName;
|
||||
if (fullClassName == null)
|
||||
return indent ? (INDENT_STRING + NONE_STRING) : NONE_STRING;
|
||||
|
||||
int lastDot = fullClassName.LastIndexOf('.');
|
||||
|
||||
// If it ends in dot (?!) or has no dot - return class as-is
|
||||
if (lastDot == -1 || lastDot == fullClassName.Length - 1)
|
||||
return fullClassName;
|
||||
|
||||
string shortClassName = fullClassName.Substring(lastDot + 1);
|
||||
|
||||
if (shortClassName.StartsWithInvariant("Null", caseSensitive: true))
|
||||
{
|
||||
return indent ? (INDENT_STRING + NONE_STRING) : NONE_STRING;
|
||||
}
|
||||
|
||||
bool doneFirst = false;
|
||||
List<char> output = new(shortClassName.Length + 10);
|
||||
|
||||
foreach (char c in shortClassName)
|
||||
{
|
||||
if (Char.IsUpper(c) && doneFirst)
|
||||
{
|
||||
output.Add(' ');
|
||||
}
|
||||
|
||||
output.Add(c);
|
||||
doneFirst = true;
|
||||
}
|
||||
|
||||
string humanName = new(output.ToArray());
|
||||
return indent ? (INDENT_STRING + humanName) : humanName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7b7aeb7420ec45cda02dea687dbd8e57
|
||||
timeCreated: 1710244772
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/EditorUI/Drawers/BaseClassPickerDrawer.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using UnityEditor;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(MapProcessorClass), useForChildren: true)]
|
||||
public class MapProcessorClassDrawer : BaseClassPickerDrawer<MapProcessorBase>
|
||||
{
|
||||
protected override string ClassNamePropertyName => "m_MapClassName";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 85a89c98c61044e08811ba3fb0fbe957
|
||||
timeCreated: 1707730234
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/EditorUI/Drawers/MapProcessorClassDrawer.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using UnityEditor;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(WorldspawnScript), useForChildren: true)]
|
||||
public class WorldspawnScriptDrawer : BaseClassPickerDrawer<Worldspawn>
|
||||
{
|
||||
protected override string ClassNamePropertyName => "m_ScriptName";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 513c5345701d4a0894054ae3c25184fb
|
||||
timeCreated: 1710152511
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/EditorUI/Drawers/WorldspawnScriptDrawer.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d4361d4c49a24bea8a532781a1d0119f
|
||||
timeCreated: 1722851165
|
||||
@@ -0,0 +1,139 @@
|
||||
//
|
||||
// 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;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
[CustomEditor(typeof(WadFileAssetImporter))]
|
||||
public class WadAssetImporterEditor : UnityEditor.Editor
|
||||
{
|
||||
private Vector2 m_ScrollPos = Vector2.zero;
|
||||
private bool m_Running = false;
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
if (target is not WadFileAssetImporter wadAssetImporter)
|
||||
return;
|
||||
|
||||
WadFileAsset wadAsset = AssetDatabase.LoadAssetAtPath<WadFileAsset>(wadAssetImporter.assetPath);
|
||||
|
||||
GUILayout.Label($"{wadAsset.MaterialNames.Length} material(s):");
|
||||
|
||||
GUI.color = new Color(0.8f, 0.8f, 0.8f);
|
||||
{
|
||||
m_ScrollPos = GUILayout.BeginScrollView(m_ScrollPos, GUILayout.Height(100f));
|
||||
{
|
||||
foreach (string material in wadAsset.MaterialNames)
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
GUIContent materialIcon = EditorGUIUtility.IconContent("Material Icon");
|
||||
GUILayout.Label(materialIcon, GUILayout.Width(16f), GUILayout.Height(16f));
|
||||
GUILayout.Label(material);
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
GUILayout.EndScrollView();
|
||||
}
|
||||
GUI.color = Color.white;
|
||||
|
||||
GUI.enabled = !m_Running;
|
||||
if (GUILayout.Button("Extract Wad Materials"))
|
||||
{
|
||||
m_Running = true;
|
||||
Extract(wadAssetImporter.assetPath);
|
||||
m_Running = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Extract(string wadFilePath)
|
||||
{
|
||||
WadParser parser = new(wadFilePath);
|
||||
WadFile wadFile = parser.Parse();
|
||||
|
||||
// Create folder
|
||||
string folderPath = Path.ChangeExtension(wadFilePath, null);
|
||||
string texturesPath = Path.Combine(folderPath, "Textures");
|
||||
string materialsPath = Path.Combine(folderPath, "Materials");
|
||||
DirectoryUtil.EmptyAndCreateDirectory(texturesPath);
|
||||
DirectoryUtil.EmptyAndCreateDirectory(materialsPath);
|
||||
|
||||
// Step 1: write textures
|
||||
try
|
||||
{
|
||||
AssetDatabase.StartAssetEditing();
|
||||
EditorUtility.DisplayProgressBar("Extracting Wad Textures", "One mo..", 0f);
|
||||
|
||||
for (int entryIdx = 0; entryIdx < wadFile.Entries.Count; entryIdx++)
|
||||
{
|
||||
WadEntry entry = wadFile.Entries[entryIdx];
|
||||
|
||||
float progress = (float)entryIdx / wadFile.Entries.Count;
|
||||
EditorUtility.DisplayProgressBar("Extracting Wad Textures", $"{entry.Name} ({entryIdx + 1} of {wadFile.Entries.Count}) - {progress * 100:F0}%", progress);
|
||||
|
||||
string texturePath = Path.Combine(texturesPath, $"T_{entry.Name}.png");
|
||||
parser.WriteTextureToFile(entry, texturePath);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
AssetDatabase.StopAssetEditing();
|
||||
}
|
||||
|
||||
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
|
||||
EditorApplication.delayCall += () => CreateMaterials(materialsPath, wadFilePath, wadFile);
|
||||
}
|
||||
|
||||
private static void CreateMaterials(string materialFolderPath, string wadFilePath, WadFile wadFile)
|
||||
{
|
||||
List<Material> createdMaterials = new(wadFile.Entries.Count);
|
||||
|
||||
// Step 2: Create materials
|
||||
try
|
||||
{
|
||||
AssetDatabase.StartAssetEditing();
|
||||
EditorUtility.DisplayProgressBar("Creating Materials", "One mo..", 0f);
|
||||
|
||||
string texturesPath = Path.Combine(Path.GetDirectoryName(materialFolderPath), "Textures");
|
||||
|
||||
for (int entryIdx = 0; entryIdx < wadFile.Entries.Count; entryIdx++)
|
||||
{
|
||||
WadEntry entry = wadFile.Entries[entryIdx];
|
||||
|
||||
float progress = (float)entryIdx / wadFile.Entries.Count;
|
||||
EditorUtility.DisplayProgressBar("Creating Materials", $"{entry.Name} ({entryIdx + 1} of {wadFile.Entries.Count}) - {progress * 100:F0}%", progress);
|
||||
|
||||
string texturePath = Path.Combine(texturesPath, $"T_{entry.Name}.png");
|
||||
string materialPath = Path.Combine(materialFolderPath, $"{entry.Name}.mat");
|
||||
|
||||
Material mat = TrembleMapImport.CreateEditorMaterial(texturePath, smoothness: 0.1f, metallic: 0f);
|
||||
AssetDatabase.CreateAsset(mat, materialPath);
|
||||
|
||||
createdMaterials.Add(mat);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
AssetDatabase.StopAssetEditing();
|
||||
}
|
||||
|
||||
// Add to material group, if project is using them
|
||||
if (TrembleSyncSettings.Get().MaterialGroups.Length > 0)
|
||||
{
|
||||
string wadName = Path.GetFileNameWithoutExtension(wadFilePath);
|
||||
MaterialGroupUtil.MoveMaterialsToGroup(createdMaterials.ToArray(), wadName, createIfNotExist: true);
|
||||
}
|
||||
|
||||
TrembleEditorAPI.SyncToTrenchBroom();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eaf1a772c03e4686be2389348cf42bf1
|
||||
timeCreated: 1722851222
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/EditorUI/Editors/WadAssetImporterEditor.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,141 @@
|
||||
//
|
||||
// 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 UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
[InitializeOnLoad]
|
||||
public static class MapHierarchyIcons
|
||||
{
|
||||
static MapHierarchyIcons()
|
||||
{
|
||||
TrembleEditorUtility.RegisterOnHierarchyItem(OnHierarchyItem);
|
||||
}
|
||||
public static void ResetModifiedTimes() => s_CachedModifiedTimes.Clear();
|
||||
|
||||
private static readonly Dictionary<GameObject, ulong> s_CachedModifiedTimes = new();
|
||||
|
||||
private static void OnHierarchyItem(GameObject go, Rect selectionRect)
|
||||
{
|
||||
Rect r = new(selectionRect);
|
||||
r.x -= 28;
|
||||
r.width = 20;
|
||||
|
||||
bool areDependenciesUpToDate = TrembleSyncSettings.Get().AutomaticallyReimportWhenDependencyChanges;
|
||||
|
||||
if (go.TryGetComponent(out MapDocument thisMap))
|
||||
{
|
||||
if (!areDependenciesUpToDate)
|
||||
{
|
||||
ulong maxTimestamp = 0ul;
|
||||
List<string> outOfDate = new(512);
|
||||
|
||||
for (int childIdx = 0; childIdx < thisMap.transform.childCount; childIdx++)
|
||||
{
|
||||
Transform child = thisMap.transform.GetChild(childIdx);
|
||||
if (!IsGameObjectOutOfDate(thisMap, child.gameObject, out ulong time))
|
||||
continue;
|
||||
|
||||
outOfDate.Add(child.name);
|
||||
maxTimestamp = Math.Max(time, maxTimestamp);
|
||||
}
|
||||
|
||||
if (outOfDate.Count > 0)
|
||||
{
|
||||
const string PREFIX = "\n * ";
|
||||
string oodPrefabs = String.Join(PREFIX, outOfDate);
|
||||
GUI.Label(r, MakeWarningIcon($"Map may require reimport ({FormatTimespanSince(maxTimestamp)} out of date)! Possible out of date entities are:{PREFIX}{oodPrefabs}"));
|
||||
}
|
||||
}
|
||||
|
||||
// Edit button
|
||||
Rect buttonRect = new(selectionRect);
|
||||
buttonRect.width = 62;
|
||||
buttonRect.x = selectionRect.width;
|
||||
|
||||
if (GUI.Button(buttonRect, "edit map", EditorStyles.miniButton))
|
||||
{
|
||||
string mapPath = Path.GetFullPath(AssetDatabase.GUIDToAssetPath(thisMap.OriginalAssetGuid));
|
||||
TrenchBroomUtil.OpenWithTrenchBroom(mapPath);
|
||||
}
|
||||
}
|
||||
else if (!areDependenciesUpToDate)
|
||||
{
|
||||
MapDocument parentMap = go.GetComponentInParent<MapDocument>();
|
||||
if (!parentMap)
|
||||
return;
|
||||
|
||||
if (!IsGameObjectOutOfDate(parentMap, go, out ulong timestamp))
|
||||
return;
|
||||
|
||||
string tooltip = $"This entity may be using an older version of its prefab, from {FormatTimespanSince(timestamp)} ago - reimport the map!";
|
||||
GUI.Label(r, MakeWarningIcon(tooltip));
|
||||
}
|
||||
}
|
||||
|
||||
private static GUIContent MakeWarningIcon(string tooltip) => new(EditorGUIUtility.IconContent("console.warnicon.sml").image, tooltip);
|
||||
|
||||
private static bool IsGameObjectOutOfDate(MapDocument map, GameObject objectInstance, out ulong timestamp)
|
||||
{
|
||||
foreach (Transform child in objectInstance.transform)
|
||||
{
|
||||
if (IsGameObjectOutOfDate(map, child.gameObject, out timestamp))
|
||||
return true;
|
||||
}
|
||||
|
||||
GameObject prefab = objectInstance;
|
||||
while (prefab)
|
||||
{
|
||||
prefab = PrefabUtility.GetCorrespondingObjectFromSource(prefab);
|
||||
|
||||
if (!prefab)
|
||||
{
|
||||
timestamp = 0ul;
|
||||
return false;
|
||||
}
|
||||
|
||||
ulong mapTime = map.MapImportedTime;
|
||||
|
||||
if (!s_CachedModifiedTimes.TryGetValue(prefab, out ulong time))
|
||||
{
|
||||
time = ModTimeDB.CalcModelModifiedTime(prefab);
|
||||
s_CachedModifiedTimes[prefab] = time;
|
||||
}
|
||||
|
||||
if (mapTime < time)
|
||||
{
|
||||
timestamp = time;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
timestamp = 0ul;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static string FormatTimespanSince(ulong timestamp)
|
||||
{
|
||||
DateTime fileTime = new DateTime((long)timestamp).ToLocalTime();
|
||||
DateTime now = DateTime.Now;
|
||||
|
||||
TimeSpan span = now - fileTime;
|
||||
if (span.TotalDays >= 1.0)
|
||||
return $"{(int)span.TotalDays} day(s)";
|
||||
|
||||
if (span.TotalHours >= 1.0)
|
||||
return $"{(int)span.TotalHours} hour(s)";
|
||||
|
||||
if (span.TotalMinutes >= 1.0)
|
||||
return $"{(int)span.TotalMinutes} min(s)";
|
||||
|
||||
return "mere moments";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 986da32076bc407e9d805d1b0de7da27
|
||||
timeCreated: 1713948862
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/EditorUI/MapHierarchyIcons.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,642 @@
|
||||
//
|
||||
// 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.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
public class MapRepairWindow : EditorWindow
|
||||
{
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// Menu Items
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
[MenuItem("Tools/Tremble/Repair Map...")]
|
||||
public static void OpenMapRepair() => OpenMapRepairImpl();
|
||||
public static void OpenMapRepair(string mapPath) => OpenMapRepairImpl(mapPath);
|
||||
|
||||
[MenuItem("Assets/Repair Map")]
|
||||
private static void RepairMap()
|
||||
{
|
||||
string assetPath = AssetDatabase.GetAssetPath(Selection.activeObject);
|
||||
OpenMapRepairImpl(assetPath);
|
||||
}
|
||||
[MenuItem("Assets/Repair Map", true)]
|
||||
private static bool RepairMap_Validation()
|
||||
{
|
||||
string assetPath = AssetDatabase.GetAssetPath(Selection.activeObject);
|
||||
return AssetDatabaseUtil.GetAllTrembleMapPaths().Contains(assetPath);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// Utility
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
public static string GetGameNameFromMap(string mapPath)
|
||||
{
|
||||
Dictionary<string, string> metadata = MapParser.ParseMetadataOnly(mapPath);
|
||||
return metadata.GetValueOrDefault("Game");
|
||||
}
|
||||
|
||||
public static bool IsMapForeign(string mapPath, out string gameName)
|
||||
{
|
||||
gameName = GetGameNameFromMap(mapPath);
|
||||
if (gameName == null)
|
||||
return true;
|
||||
|
||||
return !gameName.EqualsInvariant(TrembleConsts.GAME_NAME, caseSensitive: true) &&
|
||||
!gameName.EqualsInvariant(TrembleConsts.ASSET_STORE_GAME_NAME, caseSensitive: true);
|
||||
}
|
||||
|
||||
private static void OpenMapRepairImpl(string mapPath = null)
|
||||
{
|
||||
MapRepairWindow window = GetWindow<MapRepairWindow>(true, "Map Repair", true);
|
||||
window.m_MapPath = mapPath;
|
||||
|
||||
Vector2 size = new(520f, 640f);
|
||||
window.minSize = size;
|
||||
window.position = new(EditorGUIUtility.GetMainWindowPosition().center - size / 2f, size);
|
||||
window.Show();
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// Consts
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
record ClassData(string MappedClassname, FgdClass GeneratedClass);
|
||||
|
||||
private const float PADDING_SIZE = 10f;
|
||||
private GUIStyle m_TitleStyle;
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// State
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
private readonly List<string> m_AvailableMapPaths = new();
|
||||
private readonly List<string> m_AvailableTrembleEntityClassnames = new();
|
||||
private readonly List<string> m_AvailableTextureNames = new();
|
||||
|
||||
private readonly Dictionary<string, ClassData> m_MapClassToData = new();
|
||||
private readonly Dictionary<string, string> m_MapTextureNameToMappedName = new();
|
||||
|
||||
private TrembleSyncSettings m_SyncSettings;
|
||||
private MapTypeLookup m_MapTypeLookup;
|
||||
private PrefabNameLookup m_PrefabNameLookup;
|
||||
private MaterialNameLookup m_MaterialNameLookup;
|
||||
|
||||
private int m_EditingMapIdx;
|
||||
private string m_MapPath;
|
||||
private Map m_EditingMap;
|
||||
private bool m_ClassSettingsFoldOutOpen;
|
||||
|
||||
private string m_OutputPath= "Code/Entities";
|
||||
private string m_GeneratedNamespace = "TrembleEntities";
|
||||
|
||||
private readonly string[] m_Tabs = { "Textures/Materials", "Entities" };
|
||||
private int m_SelectedTab;
|
||||
private Vector2 m_ScrollPosition = Vector2.zero;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
m_SyncSettings = TrembleSyncSettings.Get();
|
||||
m_MapTypeLookup = new(m_SyncSettings);
|
||||
m_PrefabNameLookup = new(m_SyncSettings);
|
||||
m_MaterialNameLookup = new(m_SyncSettings);
|
||||
|
||||
m_AvailableTrembleEntityClassnames.Clear();
|
||||
foreach (Type entityType in m_MapTypeLookup.AllTypes)
|
||||
{
|
||||
if (!m_MapTypeLookup.TryGetMapNameFromClass(entityType, out string mapName))
|
||||
continue;
|
||||
|
||||
m_AvailableTrembleEntityClassnames.Add(mapName);
|
||||
}
|
||||
|
||||
foreach (string prefabPath in m_PrefabNameLookup.AllPrefabPaths)
|
||||
{
|
||||
if (!m_PrefabNameLookup.TryGetMapNameFromPrefabPath(prefabPath, out string prefabName))
|
||||
continue;
|
||||
|
||||
m_AvailableTrembleEntityClassnames.Add(prefabName);
|
||||
}
|
||||
|
||||
m_AvailableTextureNames.Clear();
|
||||
foreach (MaterialGroup matGroup in m_SyncSettings.GetMaterialGroupsOrDefault())
|
||||
{
|
||||
foreach (Material material in matGroup.Materials)
|
||||
{
|
||||
string matPath = AssetDatabase.GetAssetPath(material);
|
||||
|
||||
if (matPath.IsNullOrEmpty() || !m_MaterialNameLookup.TryGetMapNameFromMaterialPath(matPath, out string mapName))
|
||||
continue;
|
||||
|
||||
m_AvailableTextureNames.Add(mapName);
|
||||
}
|
||||
}
|
||||
|
||||
m_AvailableTrembleEntityClassnames.Sort();
|
||||
m_AvailableTrembleEntityClassnames.Insert(0, "(generate new entity class)");
|
||||
|
||||
m_AvailableTextureNames.Sort();
|
||||
m_AvailableTextureNames.Insert(0, "(leave as is)");
|
||||
|
||||
m_AvailableMapPaths.Add("(select a map)");
|
||||
m_AvailableMapPaths.AddRange(AssetDatabaseUtil.GetAllTrembleMapPaths());
|
||||
|
||||
if (m_EditingMapIdx != 0)
|
||||
{
|
||||
Init(m_EditingMapIdx); // Re-init
|
||||
}
|
||||
}
|
||||
|
||||
private void Init(int mapIndex)
|
||||
{
|
||||
if (mapIndex == 0)
|
||||
{
|
||||
m_EditingMap = null;
|
||||
return;
|
||||
}
|
||||
|
||||
TrembleSyncSettings syncSettings = TrembleSyncSettings.Get();
|
||||
m_EditingMap = MapParser.Parse(m_AvailableMapPaths[mapIndex]);
|
||||
m_EditingMapIdx = mapIndex;
|
||||
|
||||
// Format title
|
||||
string mapFilename = Path.GetFileName(m_AvailableMapPaths[mapIndex]);
|
||||
titleContent = new($"Repairing '{mapFilename}' - {GetGameOriginInfo()}");
|
||||
|
||||
// Parse!
|
||||
m_MapClassToData.Clear();
|
||||
m_MapTextureNameToMappedName.Clear();
|
||||
|
||||
foreach (MapEntity entity in m_EditingMap.Entities)
|
||||
{
|
||||
bool isBrushEntity = entity.Brushes.Count > 0;
|
||||
|
||||
if (!entity.Classname.EqualsInvariant("worldspawn", caseSensitive: true)
|
||||
&& !entity.Classname.EqualsInvariant("func_group", caseSensitive: true))
|
||||
{
|
||||
// Find or create class
|
||||
if (!m_MapClassToData.TryGetValue(entity.Classname, out ClassData classData))
|
||||
{
|
||||
FgdClass newClass = new(isBrushEntity ? FgdClassType.Brush : FgdClassType.Point, entity.Classname, $"Class {entity.Classname}");
|
||||
newClass.AddBaseClass(FgdConsts.CLASS_MAP_BASE);
|
||||
|
||||
if (!isBrushEntity)
|
||||
{
|
||||
newClass.AddBaseClass(FgdConsts.CLASS_MAP_POINT_BASE);
|
||||
}
|
||||
|
||||
string existingClassname = entity.Classname;
|
||||
if (!m_MapTypeLookup.TryGetClassFromMapName(entity.Classname, out _) &&
|
||||
!m_PrefabNameLookup.TryGetPrefabPathFromMapName(entity.Classname, out _))
|
||||
{
|
||||
existingClassname = null;
|
||||
}
|
||||
classData = new(GeneratedClass: newClass, MappedClassname: existingClassname);
|
||||
m_MapClassToData[entity.Classname] = classData;
|
||||
}
|
||||
|
||||
foreach ((string key, string value) in entity.Entries)
|
||||
{
|
||||
if (key.EqualsInvariant("classname"))
|
||||
continue;
|
||||
|
||||
if (classData.GeneratedClass.HasField(key))
|
||||
continue;
|
||||
|
||||
classData.GeneratedClass.TryAddInferredField(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (MapBrush brush in entity.Brushes)
|
||||
{
|
||||
foreach (MapBrushFace face in brush.Faces)
|
||||
{
|
||||
if (m_MapTextureNameToMappedName.ContainsKey(face.TextureName))
|
||||
continue;
|
||||
|
||||
if (face.TextureName.EqualsInvariant(TBConsts.EMPTY_TEXTURE, caseSensitive: true))
|
||||
continue;
|
||||
|
||||
// Try to find material
|
||||
string group = null;
|
||||
string textureName = face.TextureName;
|
||||
int slashIdx = textureName.IndexOf('/');
|
||||
|
||||
if (slashIdx != -1)
|
||||
{
|
||||
group = face.TextureName.Substring(0, slashIdx);
|
||||
textureName = face.TextureName.Substring(slashIdx + 1);
|
||||
|
||||
if (group.EqualsInvariant(TBConsts.SPECIAL_TEXTURE, caseSensitive: true))
|
||||
continue;
|
||||
}
|
||||
|
||||
MaterialGroup materialGroup = MaterialGroup.CreateDefault();
|
||||
if (!group.IsNullOrEmpty())
|
||||
{
|
||||
MaterialGroup[] mg = syncSettings.MaterialGroups
|
||||
.Where(mg => mg.Name.EqualsInvariant(group))
|
||||
.ToArray();
|
||||
|
||||
if (mg.Length > 0)
|
||||
{
|
||||
materialGroup = mg[0];
|
||||
}
|
||||
}
|
||||
|
||||
string matchingMaterialPath;
|
||||
Material matchingMaterial = materialGroup.Materials.FirstOrDefault(m => m && m.name.ContainsInvariant(textureName));
|
||||
|
||||
if (matchingMaterial)
|
||||
{
|
||||
matchingMaterialPath = AssetDatabase.GetAssetPath(matchingMaterial);
|
||||
}
|
||||
else
|
||||
{
|
||||
matchingMaterialPath = AssetDatabase.FindAssets($"t:material {textureName}")
|
||||
.Select(AssetDatabase.GUIDToAssetPath)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
if (!matchingMaterialPath.IsNullOrEmpty() && m_MaterialNameLookup.TryGetMapNameFromMaterialPath(matchingMaterialPath, out string mapName))
|
||||
{
|
||||
m_MapTextureNameToMappedName.Add(face.TextureName, mapName);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_MapTextureNameToMappedName.Add(face.TextureName, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
if (m_EditingMapIdx == 0)
|
||||
{
|
||||
m_TitleStyle ??= new(EditorStyles.boldLabel)
|
||||
{
|
||||
fontSize = EditorStyles.boldLabel.fontSize + 5
|
||||
};
|
||||
|
||||
if (m_MapPath.IsNullOrEmpty())
|
||||
{
|
||||
GUILayout.Label("Select a map to repair:", m_TitleStyle);
|
||||
|
||||
int currentMapIdx = EditorGUILayout.Popup(m_EditingMapIdx, m_AvailableMapPaths.ToArray());
|
||||
Init(currentMapIdx);
|
||||
|
||||
GUILayout.Label("Choose a map above to repair it. Repairing a map allows you to fix up broken"
|
||||
+ " materials and entity references.\n\nIt can also be used to try to import \"foreign\" maps from"
|
||||
+ " other games, although using it in this way is experimental - particularly you may find that"
|
||||
+ " texture UVs are completely incorrect for foreign maps.\n\nTremble will however attempt to"
|
||||
+ " generate new MonoBehaviour classes for any missing entities - but these are best-guesses"
|
||||
+ " based on the map file and will need manual editing.", EditorStyles.helpBox);
|
||||
}
|
||||
else
|
||||
{
|
||||
int mapIdx = Math.Max(0, m_AvailableMapPaths.IndexOf(m_MapPath));
|
||||
Init(mapIdx);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_SelectedTab = GUILayout.Toolbar(m_SelectedTab, m_Tabs, "LargeButton");
|
||||
|
||||
using (EditorGUILayout.ScrollViewScope scroll = new(m_ScrollPosition, GUILayout.ExpandHeight(true)))
|
||||
{
|
||||
EditorGUILayoutUtil.Pad(PADDING_SIZE, () =>
|
||||
{
|
||||
switch (m_SelectedTab)
|
||||
{
|
||||
case 0: OnTexturesGUI(); break;
|
||||
case 1: OnClassesGUI(); break;
|
||||
}
|
||||
});
|
||||
m_ScrollPosition = scroll.scrollPosition;
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Repair and Resave!", GUILayout.Height(50f)))
|
||||
{
|
||||
RepairAndSave();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTexturesGUI()
|
||||
{
|
||||
bool hasMissingTextures = m_MapTextureNameToMappedName.Any(kv => kv.Value == null);
|
||||
if (hasMissingTextures)
|
||||
{
|
||||
GUI.color = Color.yellow;
|
||||
{
|
||||
GUILayout.BeginVertical(EditorStyles.helpBox);
|
||||
{
|
||||
GUILayout.Label("If you have a WAD file for this game, you should first import that to generate Materials for the map's textures.", EditorStyles.wordWrappedLabel);
|
||||
if (GUILayout.Button("Import WAD"))
|
||||
{
|
||||
string wadFilePath = EditorUtility.OpenFilePanel("Select WAD file", "Assets", "wad");
|
||||
if (wadFilePath.IsNullOrEmpty())
|
||||
return;
|
||||
|
||||
string mapBasePath = Path.GetDirectoryName(m_AvailableMapPaths[m_EditingMapIdx]);
|
||||
File.Copy(wadFilePath, Path.Combine(mapBasePath, Path.GetFileName(wadFilePath)));
|
||||
|
||||
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate | ImportAssetOptions.ForceSynchronousImport);
|
||||
|
||||
EditorApplication.delayCall += () =>
|
||||
{
|
||||
EditorUtility.DisplayDialog("WAD Imported!", "The WAD file was imported successfully!", "Okay");
|
||||
OnEnable();
|
||||
};
|
||||
}
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
|
||||
GUILayout.Space(20f);
|
||||
}
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
|
||||
GUILayoutOption fixedHalfWidth = GUILayout.Width(position.width / 2f - PADDING_SIZE * 2f);
|
||||
GUILayoutOption smallerHalfWidth = GUILayout.Width(position.width / 2f - PADDING_SIZE * 2f - 25f);
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
GUILayout.Label("Texture from Map:", EditorStyles.boldLabel, fixedHalfWidth);
|
||||
GUILayout.Label("Unity Material:", EditorStyles.boldLabel, fixedHalfWidth);
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(5f);
|
||||
|
||||
foreach (string textureName in m_MapTextureNameToMappedName.Keys.OrderBy(mt => mt))
|
||||
{
|
||||
if (textureName.EqualsInvariant(TBConsts.CLIP_TEXTURE) ||
|
||||
textureName.EqualsInvariant(TBConsts.SKIP_TEXTURE) ||
|
||||
textureName.EqualsInvariant(TBConsts.TRIGGER_TEXTURE) ||
|
||||
textureName.StartsWithInvariant(TBConsts.SPECIAL_TEXTURE))
|
||||
continue;
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
GUILayout.Label(textureName, fixedHalfWidth);
|
||||
|
||||
Color colour = Color.white;
|
||||
|
||||
int prevSelectedIdx = Math.Max(0, m_AvailableTextureNames.IndexOf(m_MapTextureNameToMappedName[textureName]));
|
||||
if (prevSelectedIdx == 0)
|
||||
{
|
||||
colour = Color.red;
|
||||
}
|
||||
else if (!m_MapTextureNameToMappedName[textureName].EqualsInvariant(textureName, caseSensitive: true))
|
||||
{
|
||||
colour = Color.yellow;
|
||||
}
|
||||
|
||||
GUI.color = colour;
|
||||
int selectedIdx = EditorGUILayout.Popup(prevSelectedIdx, m_AvailableTextureNames.ToArray(), smallerHalfWidth);
|
||||
GUI.color = Color.white;
|
||||
|
||||
if (prevSelectedIdx != selectedIdx)
|
||||
{
|
||||
m_MapTextureNameToMappedName[textureName] = m_AvailableTextureNames[selectedIdx];
|
||||
}
|
||||
|
||||
if (GUILayout.Button(new GUIContent("!", "Copy to all missing"), GUILayout.Width(20f), GUILayout.Height(20f)))
|
||||
{
|
||||
foreach (string mapTextureName in m_MapTextureNameToMappedName.Keys.ToArray())
|
||||
{
|
||||
if (m_MapTextureNameToMappedName[mapTextureName].IsNullOrEmpty())
|
||||
{
|
||||
m_MapTextureNameToMappedName[mapTextureName] = m_AvailableTextureNames[selectedIdx];
|
||||
}
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
return;
|
||||
}
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnClassesGUI()
|
||||
{
|
||||
bool hasMissingClasses = m_MapClassToData.Any(kv => !kv.Key.EqualsInvariant(kv.Value.MappedClassname));
|
||||
if (hasMissingClasses)
|
||||
{
|
||||
GUI.color = Color.yellow;
|
||||
{
|
||||
GUILayout.BeginVertical(EditorStyles.helpBox);
|
||||
{
|
||||
GUILayout.Label("If you have an FGD file for this game, you should first import that to generate MonoBehaviours for the game's entities. If you do this, the classes generated from Map Repair will have much more accurate names and descriptions!", EditorStyles.wordWrappedLabel);
|
||||
if (GUILayout.Button("Import FGD"))
|
||||
{
|
||||
string fgdFilePath = EditorUtility.OpenFilePanel("Select FGD file", "Assets", "fgd");
|
||||
if (fgdFilePath.IsNullOrEmpty())
|
||||
return;
|
||||
|
||||
string mapBasePath = Path.GetDirectoryName(m_AvailableMapPaths[m_EditingMapIdx]);
|
||||
File.Copy(fgdFilePath, Path.Combine(mapBasePath, Path.GetFileName(fgdFilePath)));
|
||||
EditorCompileUtil.CompileThen(typeof(MapRepairWindow), nameof(OnPostCompileAfterFGDImport));
|
||||
}
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
|
||||
GUILayout.Space(20f);
|
||||
}
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
|
||||
GUILayoutOption fixedHalfWidth = GUILayout.Width(position.width / 2f - PADDING_SIZE * 2f - 10f);
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
GUILayout.Label("Entity Class from Map:", EditorStyles.boldLabel, fixedHalfWidth);
|
||||
GUILayout.Label("MonoBehaviour:", EditorStyles.boldLabel, fixedHalfWidth);
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(5f);
|
||||
|
||||
foreach (string className in m_MapClassToData.Keys.OrderBy(cn => cn))
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
GUILayout.Label(className, fixedHalfWidth);
|
||||
|
||||
Color colour = Color.white;
|
||||
|
||||
int prevSelectedIdx = Math.Max(0, m_AvailableTrembleEntityClassnames.IndexOf(m_MapClassToData[className].MappedClassname));
|
||||
if (prevSelectedIdx == 0)
|
||||
{
|
||||
colour = Color.green;
|
||||
}
|
||||
else if (!m_MapClassToData[className].MappedClassname.EqualsInvariant(className, caseSensitive: true))
|
||||
{
|
||||
colour = Color.yellow;
|
||||
}
|
||||
|
||||
GUI.color = colour;
|
||||
int selectedIdx = EditorGUILayout.Popup(prevSelectedIdx, m_AvailableTrembleEntityClassnames.ToArray(), fixedHalfWidth);
|
||||
GUI.color = Color.white;
|
||||
|
||||
if (prevSelectedIdx != selectedIdx)
|
||||
{
|
||||
m_MapClassToData[className] = m_MapClassToData[className] with
|
||||
{
|
||||
MappedClassname = m_AvailableTrembleEntityClassnames[selectedIdx]
|
||||
};
|
||||
}
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(10f);
|
||||
|
||||
m_ClassSettingsFoldOutOpen = EditorGUILayout.Foldout(m_ClassSettingsFoldOutOpen, "Class Generation Settings", true);
|
||||
if (m_ClassSettingsFoldOutOpen)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
m_OutputPath = EditorGUILayout.TextField("Save To", m_OutputPath);
|
||||
GUILayout.Label("There is the folder where Tremble will store any new classes for the entities found in the map. This path is relative to your Assets folder. If it doesn't exist, it'll be created!", EditorStyles.helpBox);
|
||||
|
||||
m_GeneratedNamespace = EditorGUILayout.TextField("C# Namespace", m_GeneratedNamespace);
|
||||
GUILayout.Label("This namespace is only applied to newly-generated entity MonoBehaviours.", EditorStyles.helpBox);
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
}
|
||||
|
||||
private string GetGameOriginInfo()
|
||||
{
|
||||
string gameName = m_EditingMap.Metadata.GetValueOrDefault("Game");
|
||||
|
||||
if (gameName.IsNullOrEmpty())
|
||||
return "map from Quake(?)";
|
||||
|
||||
if (gameName.EqualsInvariant(TrembleConsts.GAME_NAME, caseSensitive: true))
|
||||
return "map from this game";
|
||||
|
||||
if (gameName.EqualsInvariant(TrembleConsts.ASSET_STORE_GAME_NAME, caseSensitive: true))
|
||||
return "map from Tremble sample";
|
||||
|
||||
if (gameName.ContainsInvariant("unity:"))
|
||||
return "map from another Tremble game";
|
||||
|
||||
return $"map from {gameName}";
|
||||
}
|
||||
|
||||
private void RepairAndSave()
|
||||
{
|
||||
if (m_EditingMap == null)
|
||||
return;
|
||||
|
||||
string mapFilename = Path.GetFileName(m_AvailableMapPaths[m_EditingMapIdx]);
|
||||
|
||||
if (TrenchBroomUtil.IsTrenchBroomRunning)
|
||||
{
|
||||
EditorUtility.DisplayDialog(
|
||||
title: "Uh oh - TrenchBroom appears to be running!",
|
||||
message: $"Hey - if you have {mapFilename} open in TrenchBroom right now, you should "
|
||||
+ "close it before repairing the map",
|
||||
"Closed, continue repairing!");
|
||||
}
|
||||
|
||||
bool generatedAnyNewClasses = false;
|
||||
|
||||
// Write out classes for any missing entities
|
||||
foreach ((string _, ClassData classData) in m_MapClassToData)
|
||||
{
|
||||
if (!classData.MappedClassname.IsNullOrEmpty())
|
||||
continue;
|
||||
|
||||
string rootFolder = Path.Combine("Assets", m_OutputPath);
|
||||
classData.GeneratedClass.Name.Split('_', out string category, out string classname);
|
||||
|
||||
// Use category as folder
|
||||
if (!category.IsNullOrEmpty())
|
||||
{
|
||||
rootFolder = Path.Combine(rootFolder, category.ToNamingConvention(NamingConvention.UpperCamelCase));
|
||||
}
|
||||
|
||||
string fileName = classname.ToNamingConvention(NamingConvention.UpperCamelCase) + ".cs";
|
||||
|
||||
string filePath = Path.Combine(rootFolder, fileName);
|
||||
DirectoryUtil.CreateAllDirectories(filePath);
|
||||
classData.GeneratedClass.WriteCSharp(filePath, namespaceName: m_GeneratedNamespace);
|
||||
|
||||
generatedAnyNewClasses = true;
|
||||
}
|
||||
|
||||
// Pass 1: remap entity classes & strip 'wad' from worldspawn
|
||||
foreach (MapEntity entity in m_EditingMap.Entities)
|
||||
{
|
||||
// Remove Wad files
|
||||
if (entity.Classname.EqualsInvariant("worldspawn", caseSensitive: true) && entity.Entries.ContainsKey("wad"))
|
||||
{
|
||||
entity.Entries.Remove("wad");
|
||||
}
|
||||
|
||||
if (!m_MapClassToData.TryGetValue(entity.Classname, out ClassData classData))
|
||||
continue;
|
||||
|
||||
// Not remapped?
|
||||
if (classData.MappedClassname.IsNullOrEmpty())
|
||||
continue;
|
||||
|
||||
entity.Entries["classname"] = classData.MappedClassname;
|
||||
}
|
||||
|
||||
// Pass 2: remap textures
|
||||
foreach (MapEntity entity in m_EditingMap.Entities)
|
||||
{
|
||||
foreach (MapBrush brush in entity.Brushes)
|
||||
{
|
||||
foreach (MapBrushFace face in brush.Faces)
|
||||
{
|
||||
// Ignore if not mapped, or mapped texture is something like "(leave as is)"
|
||||
if (m_MapTextureNameToMappedName.TryGetValue(face.TextureName, out string mappedTexture) &&
|
||||
!mappedTexture.IsNullOrEmpty() && !mappedTexture.ContainsInvariant("("))
|
||||
{
|
||||
face.TextureName = mappedTexture;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Rebuild new code
|
||||
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate | ImportAssetOptions.ForceSynchronousImport);
|
||||
|
||||
// Import fixed map
|
||||
string mapPath = m_AvailableMapPaths[m_EditingMapIdx];
|
||||
m_EditingMap.WriteTo(mapPath);
|
||||
AssetDatabase.ImportAsset(mapPath);
|
||||
|
||||
// Warn about re-importing
|
||||
if (generatedAnyNewClasses)
|
||||
{
|
||||
EditorUtility.DisplayDialog("New Classes Generated", "Tremble has generated new MonoBehaviours for your map entities. You might need to manually Reimport the map file once in order for these to be picked up.", "Sure thing!");
|
||||
}
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
private static void OnPostCompileAfterFGDImport()
|
||||
{
|
||||
EditorUtility.DisplayDialog("FGD Imported!", "The FGD file was imported successfully!", "Okay");
|
||||
|
||||
MapRepairWindow mrw = GetWindow<MapRepairWindow>();
|
||||
mrw.OnEnable();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 75858ce0fbcd4493a482f6081646f26a
|
||||
timeCreated: 1712045460
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/EditorUI/MapRepairWindow.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3b73ae349f8c4f7dbebc23a21f5ab8e2
|
||||
timeCreated: 1710848964
|
||||
@@ -0,0 +1,198 @@
|
||||
//
|
||||
// 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 UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
[InitializeOnLoad]
|
||||
public class MaterialInspectorGUI
|
||||
{
|
||||
static MaterialInspectorGUI()
|
||||
{
|
||||
UnityEditor.Editor.finishedDefaultHeaderGUI -= OnPostHeaderGUI;
|
||||
UnityEditor.Editor.finishedDefaultHeaderGUI += OnPostHeaderGUI;
|
||||
}
|
||||
|
||||
private static bool s_IsFoldoutOpen;
|
||||
|
||||
static void OnPostHeaderGUI(UnityEditor.Editor editor)
|
||||
{
|
||||
if (editor is not MaterialEditor)
|
||||
return;
|
||||
|
||||
GUIContent content = new("Material Settings for Tremble");
|
||||
Rect rect = GUILayoutUtility.GetRect(content, EditorStyles.foldoutHeader);
|
||||
rect.x += 20f;
|
||||
s_IsFoldoutOpen = EditorGUI.BeginFoldoutHeaderGroup(rect, s_IsFoldoutOpen, content, menuIcon: EditorStyles.foldoutHeaderIcon);
|
||||
|
||||
if (s_IsFoldoutOpen)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
TrembleSyncSettings trembleSyncSettings = TrembleSyncSettings.Get();
|
||||
|
||||
// Get selected materials and their groups
|
||||
Material[] selectedMaterials = editor.targets.Cast<Material>().ToArray();
|
||||
HashSet<string> uniqueGroups = new(selectedMaterials.Select(m => GetMaterialGroupName(trembleSyncSettings, m)));
|
||||
|
||||
// Gather list of material groups
|
||||
List<MaterialGroup> groups = trembleSyncSettings.MaterialGroups.ToList();
|
||||
|
||||
List<string> titles = new() { "(none)" };
|
||||
titles.AddRange(groups.Select(g => g.Name));
|
||||
titles.Add(" + Create New Group");
|
||||
|
||||
EditorGUI.showMixedValue = uniqueGroups.Count > 1;
|
||||
{
|
||||
int selectedIdx = uniqueGroups.Count > 1 ? -1 : titles.IndexOf(uniqueGroups.First());
|
||||
int newSelectedIdx = EditorGUILayout.Popup("Material Group", selectedIdx, titles.ToArray(), EditorStyles.miniPullDown);
|
||||
|
||||
if (selectedIdx != newSelectedIdx)
|
||||
{
|
||||
if (newSelectedIdx > groups.Count)
|
||||
{
|
||||
Rect targetRect = new()
|
||||
{
|
||||
x = Event.current.mousePosition.x,
|
||||
y = Event.current.mousePosition.y,
|
||||
width = 400f,
|
||||
height = 50f
|
||||
};
|
||||
|
||||
//Add new?
|
||||
NewMaterialGroupWindow newGroup = EditorWindow.GetWindow<NewMaterialGroupWindow>(true, "New Material Group Name", true);
|
||||
newGroup.Show(targetRect, groups.ToArray(), (groupName) => MaterialGroupUtil.MoveMaterialsToGroup(selectedMaterials, groupName, createIfNotExist: true));
|
||||
return;
|
||||
}
|
||||
|
||||
// Shift from 1-based to 0-based, with -1 meaning none
|
||||
int index = newSelectedIdx - 1;
|
||||
if (index == -1)
|
||||
{
|
||||
MaterialGroupUtil.RemoveMaterialsFromGroups(selectedMaterials);
|
||||
}
|
||||
else
|
||||
{
|
||||
string groupName = groups[index].Name;
|
||||
MaterialGroupUtil.MoveMaterialsToGroup(selectedMaterials, groupName);
|
||||
}
|
||||
}
|
||||
}
|
||||
EditorGUI.showMixedValue = false;
|
||||
|
||||
|
||||
MaterialRenderData[] datas = selectedMaterials.Select(trembleSyncSettings.GetMaterialRenderData).ToArray();
|
||||
MaterialRenderData data = trembleSyncSettings.GetMaterialRenderData(selectedMaterials[0]);
|
||||
|
||||
EditorGUI.showMixedValue = datas.Select(x => x.ExportMode).Distinct().Count() > 1;
|
||||
{
|
||||
int mode = (int)(data?.ExportMode ?? MaterialImportMode.FixedSize);
|
||||
EditorGUI.BeginChangeCheck();
|
||||
int newMode = EditorGUILayout.Popup("Render Mode", mode, Enum.GetNames(typeof(MaterialImportMode)), EditorStyles.miniPullDown);
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
foreach (Material mat in selectedMaterials)
|
||||
{
|
||||
mat.SetMaterialImportMode((MaterialImportMode)newMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (datas.Any(x => x.ExportMode == MaterialImportMode.Dynamic))
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
{
|
||||
EditorGUILayout.LabelField(new GUIContent
|
||||
{
|
||||
text = "Resolution",
|
||||
tooltip = "Override this to force the texture to render at a certain resolution."
|
||||
}, GUILayout.MaxWidth(82));
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
GUIStyle miniLabel = EditorStyles.centeredGreyMiniLabel;
|
||||
miniLabel.alignment = TextAnchor.MiddleRight;
|
||||
|
||||
EditorGUILayout.LabelField("Override", EditorStyles.centeredGreyMiniLabel);
|
||||
|
||||
bool overrideRes = EditorGUILayout.Toggle(data?.IsResolutionOverridden ?? false, GUILayout.MinWidth(0));
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
foreach (Material mat in selectedMaterials)
|
||||
{
|
||||
mat.SetMaterialResolutionOverridden(overrideRes);
|
||||
}
|
||||
}
|
||||
|
||||
string[] resolutionLabels = MaterialExportSizeUtils.Names;
|
||||
if (data?.IsResolutionOverridden ?? false)
|
||||
{
|
||||
MaterialExportSize sizeX = data?.ResolutionX ?? MaterialExportSizeUtils.GetDefault();
|
||||
MaterialExportSize sizeY = data?.ResolutionY ?? MaterialExportSizeUtils.GetDefault();
|
||||
|
||||
// X Resolution
|
||||
EditorGUI.BeginChangeCheck();
|
||||
sizeX = (MaterialExportSize)EditorGUILayout.Popup((int)sizeX, resolutionLabels, EditorStyles.miniPullDown);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
foreach (Material mat in selectedMaterials)
|
||||
{
|
||||
mat.SetMaterialResolutionX(sizeX);
|
||||
}
|
||||
}
|
||||
|
||||
GUI.contentColor = Color.gray;
|
||||
GUILayout.Label(" x ");
|
||||
GUI.contentColor = Color.white;
|
||||
|
||||
// Y Resolution
|
||||
EditorGUI.BeginChangeCheck();
|
||||
sizeY = (MaterialExportSize)EditorGUILayout.Popup((int)sizeY, resolutionLabels, EditorStyles.miniPullDown);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
foreach (Material mat in selectedMaterials)
|
||||
{
|
||||
mat.SetMaterialResolutionY(sizeY);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int[] widths = selectedMaterials.Select(m => m.mainTexture?.width ?? 0).Where(w => w > 0).Distinct().ToArray();
|
||||
int[] heights = selectedMaterials.Select(m => m.mainTexture?.height ?? 0).Where(h => h > 0).Distinct().ToArray();
|
||||
|
||||
string widthStr = widths.Length > 0 ? widths[0].ToString() : "(multiple)";
|
||||
string heightStr = heights.Length > 0 ? heights[0].ToString() : "(multiple)";
|
||||
|
||||
GUI.contentColor = Color.gray;
|
||||
GUILayout.Label($"{widthStr} x {heightStr}");
|
||||
GUI.contentColor = Color.white;
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
}
|
||||
|
||||
private static string GetMaterialGroupName(TrembleSyncSettings trembleSyncSettings, Material material)
|
||||
{
|
||||
foreach (MaterialGroup group in trembleSyncSettings.MaterialGroups)
|
||||
{
|
||||
if (group.Materials.Contains(material))
|
||||
return group.Name;
|
||||
}
|
||||
|
||||
return "(none)";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a398d54cc0ba4b90af4093ec13fa6bec
|
||||
timeCreated: 1709455118
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/EditorUI/Materials/MaterialInspectorGUI.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,90 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
internal class NewMaterialGroupWindow : EditorWindow
|
||||
{
|
||||
private const string MAT_NAME_ID = "MatNameField";
|
||||
|
||||
private MaterialGroup[] m_ExistingGroups;
|
||||
private Action<string> m_OnAdded;
|
||||
|
||||
private string m_Name;
|
||||
|
||||
internal void Show(Rect fromRect, MaterialGroup[] existingGroups, Action<string> onAdded)
|
||||
{
|
||||
position = fromRect;
|
||||
|
||||
m_ExistingGroups = existingGroups;
|
||||
m_OnAdded = onAdded;
|
||||
|
||||
m_Name = "Group " + m_ExistingGroups.Length;
|
||||
ShowModalUtility();
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
GUI.SetNextControlName(MAT_NAME_ID);
|
||||
m_Name = EditorGUILayout.TextField("Name", m_Name);
|
||||
|
||||
GUI.FocusControl(MAT_NAME_ID);
|
||||
|
||||
bool escaped = Event.current.keyCode == KeyCode.Escape;
|
||||
bool entered = Event.current.keyCode == KeyCode.Return;
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
escaped |= GUILayout.Button("Cancel");
|
||||
entered |= GUILayout.Button("Create");
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
|
||||
if (Event.current.type is EventType.Repaint or EventType.Layout)
|
||||
return;
|
||||
|
||||
if (escaped)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
else if (entered)
|
||||
{
|
||||
TrembleSyncSettings trembleSyncSettings = TrembleSyncSettings.Get();
|
||||
if (trembleSyncSettings.MaterialGroups.Length == 0)
|
||||
{
|
||||
string text = "You are adding your first Material Group, which is a great idea to organise your materials. However, you will need to manually assign each material to a material group for it to be available in TrenchBroom. All good?";
|
||||
int selection = EditorUtility.DisplayDialogComplex("Material Groups", text, "Understood, Continue", "Oh, No Thanks!", "Okay but add all materials into a group");
|
||||
switch (selection)
|
||||
{
|
||||
case 0: //ok
|
||||
{
|
||||
break;
|
||||
}
|
||||
case 1: // cancel
|
||||
{
|
||||
return;
|
||||
}
|
||||
case 2: // ok but add
|
||||
{
|
||||
// Quickly add a "user" group with current mats, and then continue
|
||||
MaterialGroup defaultGroup = MaterialGroup.CreateDefault();
|
||||
MaterialGroupUtil.MoveMaterialsToGroup(defaultGroup.Materials, defaultGroup.Name, createIfNotExist: true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return new name back
|
||||
m_OnAdded(m_Name);
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be384b78cb984abd86673e4aca0d4ea2
|
||||
timeCreated: 1709543387
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/EditorUI/Materials/NewMaterialGroupWindow.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,142 @@
|
||||
//
|
||||
// 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 UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
public class Q3Map2OutputWindow : EditorWindow
|
||||
{
|
||||
private IList<string> m_Lines;
|
||||
private Vector2 m_Scroll;
|
||||
|
||||
private bool m_ShowErrors = true;
|
||||
private bool m_ShowWarnings = true;
|
||||
private bool m_ShowInfo = false;
|
||||
|
||||
private string m_Filter = "";
|
||||
private bool m_HasErrors;
|
||||
private bool m_HasWarnings;
|
||||
|
||||
public static void Open(IList<string> output, bool showAllInfo = false)
|
||||
{
|
||||
Q3Map2OutputWindow window = GetWindow<Q3Map2OutputWindow>(true, "Map Conversion Output", true);
|
||||
Vector2 size = new(700f, 350f);
|
||||
window.minSize = size;
|
||||
window.position = new(EditorGUIUtility.GetMainWindowPosition().center - size / 2f, size);
|
||||
window.m_Lines = output;
|
||||
|
||||
if (showAllInfo)
|
||||
{
|
||||
window.m_ShowInfo = true;
|
||||
}
|
||||
|
||||
window.Show();
|
||||
}
|
||||
|
||||
private bool IsWarning(string line) => line.ContainsInvariant("warning") && !line.ContainsInvariant("__TB_");
|
||||
private bool IsError(string line) => line.ContainsInvariant("error") && !line.ContainsInvariant("__TB_");
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
if (m_Lines == null)
|
||||
{
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_HasErrors)
|
||||
{
|
||||
GUI.color = Color.red;
|
||||
GUILayout.Label("Q3Map2 produced error(s)!", EditorStyles.largeLabel);
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
else if (m_HasWarnings)
|
||||
{
|
||||
GUI.color = Color.yellow;
|
||||
GUILayout.Label("Q3Map2 produced warning(s)!", EditorStyles.largeLabel);
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
else
|
||||
{
|
||||
GUILayout.Label("Q3Map2 Output", EditorStyles.largeLabel);
|
||||
|
||||
}
|
||||
|
||||
GUILayout.Space(10f);
|
||||
GUILayout.Box(" ", GUILayout.ExpandWidth(true), GUILayout.Height(2f));
|
||||
|
||||
using (EditorGUILayout.ScrollViewScope scroll = new(m_Scroll))
|
||||
{
|
||||
foreach (string line in m_Lines)
|
||||
{
|
||||
if (m_Filter.Length > 0 && !line.ContainsInvariant(m_Filter))
|
||||
continue;
|
||||
|
||||
if (IsError(line))
|
||||
{
|
||||
if (!m_ShowErrors)
|
||||
continue;
|
||||
|
||||
GUI.color = Color.red;
|
||||
m_HasErrors = true;
|
||||
}
|
||||
else if (IsWarning(line))
|
||||
{
|
||||
if (!m_ShowWarnings)
|
||||
continue;
|
||||
|
||||
GUI.color = Color.yellow;
|
||||
m_HasWarnings = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_ShowInfo)
|
||||
continue;
|
||||
|
||||
GUI.color = new Color(0.8f, 0.8f, 0.8f);
|
||||
}
|
||||
|
||||
GUILayout.Label(" " + line, EditorStyles.wordWrappedLabel);
|
||||
}
|
||||
|
||||
m_Scroll = scroll.scrollPosition;
|
||||
}
|
||||
|
||||
GUI.color = Color.white;
|
||||
|
||||
GUILayout.Box(" ", GUILayout.ExpandWidth(true), GUILayout.Height(2f));
|
||||
|
||||
using (EditorGUILayout.HorizontalScope _ = new())
|
||||
{
|
||||
GUILayout.Label("Show:");
|
||||
|
||||
GUI.color = Color.red;
|
||||
m_ShowErrors = GUILayout.Toggle(m_ShowErrors, "Errors");
|
||||
GUI.color = Color.yellow;
|
||||
m_ShowWarnings = GUILayout.Toggle(m_ShowWarnings, "Warnings");
|
||||
GUI.color = Color.white;
|
||||
m_ShowInfo = GUILayout.Toggle(m_ShowInfo, "Info");
|
||||
|
||||
GUILayout.Label("\ud83d\udd0e", GUILayout.Width(40f));
|
||||
m_Filter = GUILayout.TextArea(m_Filter, GUILayout.Width(150f));
|
||||
|
||||
GUI.enabled = m_Filter.Length > 0;
|
||||
|
||||
if (GUILayout.Button("x", GUILayout.Width(20f)))
|
||||
{
|
||||
m_Filter = "";
|
||||
}
|
||||
|
||||
GUI.enabled = true;
|
||||
}
|
||||
|
||||
GUILayout.Space(10f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c6c93bcb039a346b586b77785874827f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/EditorUI/Q3Map2OutputWindow.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3399abca45114db19b7cb0a3de6cd661
|
||||
timeCreated: 1721666624
|
||||
@@ -0,0 +1,126 @@
|
||||
//
|
||||
// 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 UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
public static class TrembleProjectSettingsProvider
|
||||
{
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// Entry Points
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
[SettingsProvider] public static SettingsProvider ProvideAboutGUI()
|
||||
=> ProvideTrembleTab(s => s.OnAboutGUI());
|
||||
|
||||
[SettingsProvider] public static SettingsProvider ProvideSettingsGUI()
|
||||
=> ProvideTrembleTab(order: 1, "Basic Settings", s => s.OnSettingsGUI(isEmbedded: true));
|
||||
|
||||
[SettingsProvider] public static SettingsProvider ProvideNamingConventionsGUI()
|
||||
=> ProvideTrembleTab(order: 2, "Naming Conventions", s => s.OnNamingConventionsGUI(isEmbedded: true));
|
||||
|
||||
[SettingsProvider] public static SettingsProvider ProvideMaterialsGUI()
|
||||
=> ProvideTrembleTab(order: 3, "Materials", s => s.OnMaterialsGUI(isEmbedded: true));
|
||||
|
||||
[SettingsProvider] public static SettingsProvider ProvidePipelineGUI()
|
||||
=> ProvideTrembleTab(order: 4, "Pipeline", s => s.OnPipelineGUI(isEmbedded: true));
|
||||
|
||||
[SettingsProvider] public static SettingsProvider ProvideAdvancedGUI()
|
||||
=> ProvideTrembleTab(order: 5, "Advanced", s => GUILayout.Label("Here be dragons! Most users should not need to change these options. But, if you're brave - select a subcategory on the left...", EditorStyles.wordWrappedLabel), dontCaptureKeywords: true);
|
||||
|
||||
[SettingsProvider] public static SettingsProvider ProvideAdvancedGUI_Features()
|
||||
=> ProvideTrembleTab(order: 5, "Advanced", subOrder: 0, "Features", s => s.OnAdvancedGUI_Features());
|
||||
[SettingsProvider] public static SettingsProvider ProvideAdvancedGUI_Debugging()
|
||||
=> ProvideTrembleTab(order: 5, "Advanced", subOrder: 1, "Debugging", s => s.OnAdvancedGUI_Debugging());
|
||||
[SettingsProvider] public static SettingsProvider ProvideAdvancedGUI_SyncImport()
|
||||
=> ProvideTrembleTab(order: 5, "Advanced", subOrder: 2, "Sync & Import", s => s.OnAdvancedGUI_SyncImport());
|
||||
[SettingsProvider] public static SettingsProvider ProvideAdvancedGUI_Materials()
|
||||
=> ProvideTrembleTab(order: 5, "Advanced", subOrder: 3, "Materials", s => s.OnAdvancedGUI_Materials());
|
||||
[SettingsProvider] public static SettingsProvider ProvideAdvancedGUI_ImportScale()
|
||||
=> ProvideTrembleTab(order: 5, "Advanced", subOrder: 4, "Import Scale", s => s.OnAdvancedGUI_ImportScale());
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// State
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
private static TrembleSyncSettingsEditor s_SettingsEditor;
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
// Internals
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
private static SettingsProvider ProvideTrembleTab(Action<TrembleSyncSettingsEditor> onGui, bool dontCaptureKeywords = false)
|
||||
=> ProvideTrembleTab(null, "Tremble", onGui, dontCaptureKeywords);
|
||||
private static SettingsProvider ProvideTrembleTab(int order, string categoryName, Action<TrembleSyncSettingsEditor> onGui, bool dontCaptureKeywords = false)
|
||||
=> ProvideTrembleTab($"{order} {categoryName}", categoryName, onGui, dontCaptureKeywords);
|
||||
|
||||
private static SettingsProvider ProvideTrembleTab(int order, string categoryName, int subOrder, string subCategoryName, Action<TrembleSyncSettingsEditor> onGui, bool dontCaptureKeywords = false)
|
||||
=> ProvideTrembleTab($"{order} {categoryName}/{subOrder} {subCategoryName}", subCategoryName, onGui, dontCaptureKeywords);
|
||||
|
||||
private static SettingsProvider ProvideTrembleTab(string path, string label, Action<TrembleSyncSettingsEditor> onGui, bool dontCaptureKeywords = false)
|
||||
{
|
||||
// Create an editor (or used cached)
|
||||
TrembleSyncSettings settings = TrembleSyncSettings.Get();
|
||||
|
||||
if (!s_SettingsEditor)
|
||||
{
|
||||
s_SettingsEditor = (TrembleSyncSettingsEditor)UnityEditor.Editor.CreateEditor(settings);
|
||||
}
|
||||
|
||||
// Prepend root to path
|
||||
string fullPath = "Project/Tremble";
|
||||
if (path != null)
|
||||
{
|
||||
fullPath += $"/{path}";
|
||||
}
|
||||
|
||||
// Capture keywords
|
||||
List<string> keywords = new(64) { "Tremble", label };
|
||||
|
||||
if (!dontCaptureKeywords)
|
||||
{
|
||||
s_SettingsEditor.EnsureInit(onlyKeywordsCapture: true);
|
||||
|
||||
TrembleSettingsGUI.BeginKeywordCapture();
|
||||
{
|
||||
try
|
||||
{
|
||||
onGui(s_SettingsEditor);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogException(ex);
|
||||
}
|
||||
}
|
||||
keywords.AddRange(TrembleSettingsGUI.EndKeywordCapture());
|
||||
}
|
||||
|
||||
// Register path with order embedded :)
|
||||
return new(path: fullPath, SettingsScope.Project)
|
||||
{
|
||||
label = label,
|
||||
guiHandler = (searchContext) =>
|
||||
{
|
||||
s_SettingsEditor.EnsureInit();
|
||||
EditorGUILayoutUtil.Pad(10f, () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
onGui(s_SettingsEditor);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogException(ex);
|
||||
GUILayout.Label($"An error occurred rendering this page: {ex.Message}", EditorStyles.wordWrappedLabel);
|
||||
}
|
||||
});
|
||||
s_SettingsEditor.ResetLabelWidth();
|
||||
},
|
||||
keywords = keywords
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 898680ff76b449889b5d52a2011c13e9
|
||||
timeCreated: 1721384604
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/EditorUI/Settings/TrembleProjectSettingsProvider.cs
|
||||
uploadId: 939664
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c36699011d4c4cbda4b3dd2392a60bf6
|
||||
timeCreated: 1707738241
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/EditorUI/Settings/TrembleSyncSettingsEditor.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,226 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
public class EditorTexture
|
||||
{
|
||||
public EditorTexture(string textureName, params byte[] data)
|
||||
{
|
||||
m_TextureName = textureName;
|
||||
m_Data = data;
|
||||
}
|
||||
|
||||
private readonly string m_TextureName;
|
||||
private readonly byte[] m_Data;
|
||||
|
||||
public Texture2D Get()
|
||||
{
|
||||
// This sucks. On first import, we can't find the textures. So, to preserve the
|
||||
// initial experience, we also supply the textures as byte arrays.
|
||||
// If we can find the asset, use that. If not, create a texture on the fly from
|
||||
// the byte data.
|
||||
// Once the textures are available, the byte arrays also no longer work - hence the
|
||||
// double data. Luckily they're only 20x20 PNGs so they're very small.
|
||||
|
||||
Texture2D packedTexture = TrembleAssetLoader.LoadAssetByName<Texture2D>(m_TextureName);
|
||||
if (packedTexture)
|
||||
{
|
||||
return packedTexture;
|
||||
}
|
||||
|
||||
Texture2D texture = new(TrembleIcons.ICON_SIZE, TrembleIcons.ICON_SIZE);
|
||||
texture.LoadImage(m_Data, true);
|
||||
|
||||
return texture;
|
||||
}
|
||||
}
|
||||
|
||||
public static class TrembleIcons
|
||||
{
|
||||
internal const int ICON_SIZE = 20;
|
||||
|
||||
[MenuItem("Tools/Tremble/Advanced/Debug/Export TB Icon")]
|
||||
private static void Export()
|
||||
{
|
||||
if (Selection.activeObject is not Texture2D tex)
|
||||
{
|
||||
Debug.LogError($"{Selection.activeObject?.name ?? "none"} is not a texture!");
|
||||
return;
|
||||
}
|
||||
|
||||
string path = AssetDatabase.GetAssetPath(Selection.activeObject);
|
||||
string filename = Path.GetFileNameWithoutExtension(path);
|
||||
string shoutName = filename.Split('_')[^1].ToUpperInvariant();
|
||||
|
||||
StringBuilder snippet = new();
|
||||
snippet.AppendLine($"public static readonly EditorTexture {shoutName}_PNG = new(\"{filename}\",");
|
||||
|
||||
int rowCounter = 0;
|
||||
foreach (byte b in File.ReadAllBytes(path))
|
||||
{
|
||||
if (rowCounter > 0)
|
||||
{
|
||||
snippet.Append(", ");
|
||||
}
|
||||
|
||||
if (rowCounter > 16)
|
||||
{
|
||||
rowCounter = 0;
|
||||
snippet.AppendLine();
|
||||
snippet.Append('\t');
|
||||
}
|
||||
|
||||
snippet.Append($"0x{b:X2}");
|
||||
rowCounter++;
|
||||
}
|
||||
snippet.AppendLine(");");
|
||||
|
||||
EditorGUIUtility.systemCopyBuffer = snippet.ToString();
|
||||
|
||||
Debug.Log($"{Selection.activeObject.name} copied to clipboard!");
|
||||
}
|
||||
|
||||
public static readonly EditorTexture IMPORT_PNG = new("T_TB_Import",
|
||||
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
|
||||
0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x08, 0x06, 0x00, 0x00, 0x00, 0x8D, 0x89, 0x1D,
|
||||
0x0D, 0x00, 0x00, 0x02, 0x05, 0x49, 0x44, 0x41, 0x54, 0x38, 0x11, 0x8D, 0x94, 0xBF, 0x6A, 0x55,
|
||||
0x41, 0x10, 0xC6, 0x73, 0x6E, 0x12, 0x0D, 0xF1, 0x0F, 0xA2, 0x95, 0xAD, 0x56, 0xD6, 0x76, 0x8A,
|
||||
0x96, 0x8A, 0x95, 0x8D, 0xA4, 0x14, 0x04, 0xDF, 0x23, 0x68, 0xA1, 0x36, 0x82, 0x08, 0x36, 0xFA,
|
||||
0x0C, 0xBE, 0x82, 0x8D, 0xAF, 0x60, 0x21, 0x01, 0x6D, 0x44, 0x5B, 0x0B, 0x41, 0xA3, 0xC9, 0xCD,
|
||||
0xF1, 0xF7, 0x9B, 0xBB, 0xDF, 0x65, 0x73, 0xEF, 0x45, 0xFC, 0xE0, 0x3B, 0x33, 0x3B, 0x33, 0x3B,
|
||||
0x3B, 0x3B, 0xBB, 0x7B, 0x86, 0x71, 0x1C, 0xD7, 0x82, 0x61, 0x18, 0xA2, 0xAE, 0xF5, 0xF6, 0x18,
|
||||
0xE3, 0xEF, 0x7C, 0x93, 0xE6, 0x3B, 0x52, 0xEA, 0x8F, 0xA1, 0xEC, 0x5D, 0x60, 0x8B, 0x9B, 0x89,
|
||||
0x15, 0x89, 0x74, 0x6C, 0x42, 0x13, 0xC9, 0x8B, 0xB0, 0xB0, 0x11, 0x45, 0x99, 0x89, 0xBD, 0x2D,
|
||||
0x7A, 0xE7, 0x73, 0x1B, 0xCE, 0x3B, 0x68, 0xBE, 0xB7, 0xC8, 0xEF, 0xF0, 0x21, 0x5C, 0xAF, 0xAD,
|
||||
0x51, 0xD9, 0x04, 0x0E, 0x56, 0xB8, 0x8A, 0x4E, 0x6C, 0xF6, 0xCD, 0xCE, 0x7F, 0x13, 0xFD, 0x1B,
|
||||
0x3C, 0x84, 0xE7, 0x9B, 0x7D, 0x62, 0x60, 0x12, 0xB9, 0xF2, 0xBC, 0x89, 0x06, 0x74, 0x30, 0x26,
|
||||
0xC9, 0x5C, 0xFC, 0x05, 0x0C, 0xEE, 0xA0, 0x98, 0xA7, 0xFC, 0x59, 0xF9, 0x92, 0xC6, 0x86, 0x4A,
|
||||
0xDA, 0x82, 0xF4, 0x6F, 0x74, 0xFA, 0x35, 0xF4, 0x3D, 0x18, 0xBC, 0x41, 0x39, 0x16, 0x93, 0x84,
|
||||
0xBB, 0x38, 0x5E, 0xEB, 0x04, 0xEB, 0xD0, 0x8A, 0xFA, 0xAA, 0x8C, 0x7B, 0x06, 0x7B, 0x7C, 0x61,
|
||||
0xB0, 0x0D, 0xF5, 0x59, 0x75, 0xE5, 0x4A, 0xC2, 0x07, 0x18, 0xC4, 0x23, 0xA8, 0xCD, 0xAA, 0x4C,
|
||||
0xA8, 0x7E, 0x15, 0x7E, 0x80, 0x62, 0x0A, 0x7F, 0x97, 0x36, 0x8E, 0xB7, 0x90, 0xFA, 0xD3, 0x8A,
|
||||
0xCA, 0x55, 0x1F, 0x8C, 0xF7, 0x5A, 0x90, 0xE2, 0x29, 0x8C, 0xDD, 0x05, 0x82, 0x3F, 0x28, 0xFB,
|
||||
0x6D, 0xF0, 0x0A, 0xB9, 0x94, 0x4C, 0x5B, 0x26, 0xDE, 0x6E, 0x81, 0x59, 0xFD, 0x25, 0xE3, 0x77,
|
||||
0xCD, 0x76, 0x84, 0x3C, 0x80, 0x9E, 0xA6, 0xF8, 0x04, 0x67, 0x07, 0xD0, 0x1D, 0xA2, 0xBD, 0xC2,
|
||||
0x3E, 0x4F, 0x78, 0xDD, 0x48, 0xE0, 0x96, 0x32, 0xD1, 0xB1, 0x55, 0x99, 0x50, 0xE8, 0x13, 0x37,
|
||||
0xA0, 0x93, 0xFB, 0xC3, 0x4A, 0x61, 0xF3, 0x97, 0xF2, 0xC3, 0x15, 0x80, 0x2F, 0x47, 0x1E, 0xC2,
|
||||
0x29, 0xF4, 0x35, 0x78, 0xEA, 0x5E, 0x62, 0xED, 0xCF, 0xE1, 0x7B, 0xA8, 0xDD, 0x98, 0x65, 0xB4,
|
||||
0xD5, 0x2E, 0x23, 0x53, 0x59, 0x2A, 0xC2, 0x54, 0x70, 0xBB, 0xE2, 0x23, 0xAC, 0x83, 0x22, 0xCB,
|
||||
0xFC, 0xBE, 0x2E, 0x66, 0xCC, 0xD3, 0xFB, 0x89, 0x63, 0x1F, 0x9E, 0x5A, 0x0C, 0x60, 0xEC, 0x35,
|
||||
0x12, 0x3B, 0xD0, 0x7B, 0x65, 0xFF, 0xF2, 0xEC, 0xB4, 0x1F, 0x43, 0x7E, 0x0E, 0x26, 0xFC, 0xD5,
|
||||
0x3C, 0x75, 0x19, 0xBB, 0xA8, 0x8C, 0xEF, 0x36, 0xDB, 0x94, 0x77, 0x2D, 0xEA, 0xED, 0x2F, 0xCA,
|
||||
0x34, 0x73, 0x8B, 0x55, 0x3F, 0x43, 0xE1, 0xD5, 0x70, 0x9B, 0x8B, 0xD4, 0x97, 0x7B, 0x6A, 0x21,
|
||||
0xAB, 0xB7, 0x4D, 0x90, 0x49, 0xED, 0xCD, 0x57, 0xF8, 0x3F, 0x78, 0x42, 0x50, 0x0A, 0xA9, 0x9E,
|
||||
0x66, 0xEC, 0x0E, 0xD2, 0x64, 0xF5, 0xFB, 0xF0, 0x0A, 0xDC, 0x82, 0xE7, 0xE0, 0xD9, 0xC6, 0x33,
|
||||
0xC8, 0xD3, 0xD0, 0xFE, 0x9E, 0x84, 0xFE, 0xFB, 0x76, 0xE1, 0x63, 0x68, 0xA5, 0xF5, 0x73, 0x45,
|
||||
0x16, 0xFA, 0x84, 0xB1, 0xCD, 0x1C, 0xF4, 0xC8, 0x95, 0xED, 0x51, 0xC3, 0x09, 0xC6, 0x26, 0xDC,
|
||||
0x86, 0x17, 0xE0, 0x1E, 0x5C, 0xBA, 0x3A, 0x7D, 0x42, 0x4F, 0xDC, 0xD9, 0x75, 0x08, 0x24, 0x62,
|
||||
0x3E, 0xBD, 0x40, 0xC6, 0xC6, 0x10, 0xF5, 0xDF, 0xF8, 0x0B, 0x1C, 0x07, 0xCE, 0xEF, 0xA8, 0x1B,
|
||||
0x38, 0x53, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82);
|
||||
|
||||
public static readonly EditorTexture SYNC_PNG = new("T_TB_Sync",
|
||||
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
|
||||
0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x08, 0x06, 0x00, 0x00, 0x00, 0x8D, 0x89, 0x1D,
|
||||
0x0D, 0x00, 0x00, 0x01, 0xE8, 0x49, 0x44, 0x41, 0x54, 0x38, 0x11, 0x8D, 0x93, 0xBB, 0x6A, 0x54,
|
||||
0x51, 0x14, 0x86, 0xE7, 0xC4, 0x09, 0x24, 0x31, 0x20, 0xD8, 0xD9, 0x5A, 0xE8, 0x03, 0xD8, 0x29,
|
||||
0xA6, 0x0C, 0xD8, 0xE7, 0x05, 0x7C, 0x10, 0x91, 0x34, 0x2A, 0xD8, 0x08, 0x92, 0x46, 0x2D, 0xC4,
|
||||
0x32, 0x90, 0xC2, 0x27, 0xF0, 0x25, 0x02, 0x01, 0x0B, 0x1B, 0x51, 0x0B, 0x11, 0xC4, 0x1B, 0x89,
|
||||
0xB9, 0x9C, 0x7C, 0xDF, 0x9E, 0xFD, 0x0F, 0x7B, 0x8E, 0x47, 0x74, 0xC1, 0x3F, 0xEB, 0xFE, 0xEF,
|
||||
0xBD, 0xF6, 0x59, 0xD3, 0xF5, 0x7D, 0x3F, 0xF9, 0x97, 0x74, 0x5D, 0x97, 0x92, 0x8E, 0x7A, 0xDC,
|
||||
0xAE, 0xE8, 0x1A, 0x34, 0x29, 0xC9, 0x89, 0xFE, 0xD4, 0x9F, 0x11, 0x31, 0x7E, 0x0D, 0x7C, 0x01,
|
||||
0xBF, 0xC0, 0x11, 0xF8, 0x0D, 0x99, 0x8D, 0x55, 0x61, 0x8D, 0xC8, 0x18, 0xE1, 0x12, 0x75, 0x9E,
|
||||
0xB6, 0x05, 0xB6, 0xC1, 0x27, 0x18, 0x24, 0xFC, 0x09, 0x7E, 0x80, 0xEF, 0xE0, 0x5B, 0xC5, 0x57,
|
||||
0xF4, 0x21, 0x38, 0x00, 0xAF, 0xC0, 0x4C, 0x3C, 0xB8, 0x81, 0xE3, 0xC4, 0x7F, 0x80, 0xFD, 0x3F,
|
||||
0xF2, 0x81, 0xA2, 0xD2, 0x17, 0xCE, 0xA1, 0x36, 0xB9, 0x04, 0x24, 0xDE, 0x06, 0xCA, 0xF1, 0x08,
|
||||
0x0E, 0x4B, 0xA6, 0xEF, 0xDF, 0xA1, 0x57, 0xC0, 0x90, 0x67, 0xC1, 0x6F, 0x49, 0xEF, 0xD5, 0xC6,
|
||||
0xD3, 0xAA, 0xA3, 0xE2, 0x7F, 0x26, 0x70, 0x09, 0x4C, 0x72, 0x8B, 0x8C, 0xD8, 0x6A, 0x8F, 0xBB,
|
||||
0x50, 0x8F, 0x78, 0x5D, 0xF5, 0xFC, 0x73, 0x0F, 0xFC, 0x55, 0xFC, 0x35, 0x63, 0xD3, 0x66, 0x25,
|
||||
0x6A, 0xCD, 0x5C, 0xD9, 0xEC, 0x98, 0xEA, 0xDD, 0x1A, 0x3D, 0x45, 0x8F, 0x7D, 0xC8, 0x15, 0xE2,
|
||||
0x33, 0x42, 0xAF, 0xF9, 0x17, 0xB1, 0xF1, 0x18, 0x3C, 0x06, 0xD7, 0xAB, 0xBD, 0x8C, 0x56, 0x24,
|
||||
0x6E, 0x27, 0x70, 0x92, 0x8B, 0x26, 0xDA, 0x11, 0x5B, 0x7B, 0xEA, 0x41, 0xE0, 0x36, 0x50, 0xF2,
|
||||
0x56, 0x67, 0xD8, 0x65, 0x1F, 0x4B, 0xB4, 0xEF, 0x4F, 0x9A, 0xDC, 0x2D, 0xEC, 0x89, 0x3B, 0x37,
|
||||
0x71, 0xEC, 0x06, 0x98, 0x9D, 0x7B, 0xE8, 0x6D, 0x5E, 0x02, 0xC5, 0xDB, 0x94, 0x7F, 0x02, 0xDA,
|
||||
0xF8, 0x1B, 0xF0, 0x14, 0x78, 0xB3, 0xC4, 0xD7, 0xB1, 0x47, 0x6F, 0xB8, 0xEC, 0x49, 0x60, 0x07,
|
||||
0x28, 0xAE, 0x46, 0x7B, 0x2B, 0xD7, 0x28, 0xD3, 0x3C, 0xB4, 0xA0, 0xCA, 0x16, 0xFA, 0x0F, 0xC2,
|
||||
0x90, 0x6D, 0xD6, 0xA2, 0x23, 0x74, 0xC6, 0xDD, 0xC7, 0xBE, 0x61, 0x13, 0x70, 0xA5, 0xF2, 0x2C,
|
||||
0xD9, 0xD3, 0xBB, 0xE6, 0x72, 0x92, 0x3A, 0x2B, 0xB4, 0x86, 0xFD, 0x1E, 0xB4, 0xF2, 0x08, 0x27,
|
||||
0xB5, 0x1E, 0xEA, 0x97, 0x17, 0x65, 0xAD, 0xF0, 0x9F, 0x81, 0xFB, 0x60, 0x81, 0x30, 0x27, 0x3E,
|
||||
0x27, 0x11, 0x79, 0x8B, 0x71, 0x13, 0x84, 0x2C, 0x35, 0xBE, 0x96, 0x22, 0x69, 0x72, 0x57, 0xAD,
|
||||
0x8B, 0x93, 0x51, 0xEF, 0x84, 0x09, 0xFD, 0x04, 0xE4, 0xD6, 0x7E, 0x88, 0xD2, 0x1C, 0x02, 0x75,
|
||||
0x15, 0xC7, 0x17, 0x72, 0x75, 0xFE, 0xA4, 0xE9, 0x32, 0xB6, 0x6B, 0xF0, 0x11, 0x6C, 0x80, 0x85,
|
||||
0xC3, 0x6C, 0x6E, 0x62, 0x43, 0x5B, 0xC2, 0xC2, 0x63, 0x5D, 0xDE, 0xE1, 0x05, 0xC1, 0xBD, 0xA6,
|
||||
0x69, 0xE1, 0x56, 0x43, 0x42, 0xFD, 0x48, 0xD3, 0x33, 0x0B, 0xD5, 0xC0, 0x95, 0x26, 0x51, 0x9E,
|
||||
0xC0, 0x6C, 0x62, 0xAD, 0x6D, 0x2C, 0x92, 0x7C, 0xF4, 0xFC, 0x51, 0x6B, 0x41, 0x59, 0x74, 0xEC,
|
||||
0x33, 0x7D, 0x97, 0x5D, 0x69, 0x09, 0x4A, 0x80, 0x9F, 0xE4, 0x86, 0xF9, 0x73, 0x83, 0xE5, 0xF3,
|
||||
0x69, 0xCF, 0x05, 0x29, 0x55, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60,
|
||||
0x82);
|
||||
|
||||
public static readonly EditorTexture CONFIG_PNG = new("T_TB_Config",
|
||||
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
|
||||
0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x08, 0x06, 0x00, 0x00, 0x00, 0x8D, 0x89, 0x1D,
|
||||
0x0D, 0x00, 0x00, 0x01, 0xA8, 0x49, 0x44, 0x41, 0x54, 0x38, 0x11, 0xAD, 0x94, 0x3B, 0x2F, 0x04,
|
||||
0x51, 0x14, 0xC7, 0xC7, 0xAB, 0xB1, 0xBB, 0xB2, 0x44, 0xA2, 0x41, 0x48, 0x68, 0x49, 0x48, 0xF4,
|
||||
0x6C, 0x54, 0x3A, 0x89, 0x42, 0xC5, 0x37, 0x10, 0xA2, 0xF3, 0x31, 0x94, 0xE2, 0xD1, 0x53, 0x4A,
|
||||
0x24, 0x7A, 0xAD, 0x44, 0xEB, 0x55, 0xE8, 0xBC, 0xD6, 0x62, 0x45, 0xE1, 0xB1, 0x7E, 0xFF, 0x99,
|
||||
0x3B, 0xD7, 0xC9, 0x5D, 0x8F, 0x89, 0x38, 0xC9, 0x6F, 0xCF, 0x63, 0xEE, 0xFC, 0xE7, 0xDC, 0x7B,
|
||||
0x66, 0xB6, 0xA1, 0x56, 0xAB, 0x45, 0xFF, 0x69, 0x8D, 0x19, 0xC5, 0x4A, 0xAC, 0x5B, 0x82, 0xE1,
|
||||
0x5F, 0xD7, 0xAB, 0x43, 0x43, 0x13, 0xF1, 0x18, 0x8C, 0x98, 0x5A, 0x89, 0xF8, 0x00, 0x64, 0x3B,
|
||||
0x30, 0x0C, 0xBA, 0xA7, 0x03, 0xBA, 0xA0, 0xC5, 0xE5, 0xB1, 0x4E, 0x28, 0x36, 0xC1, 0x45, 0xD9,
|
||||
0x03, 0x48, 0x34, 0x07, 0x7B, 0x60, 0x6D, 0x81, 0x44, 0x62, 0x47, 0xAE, 0x38, 0x89, 0xF7, 0xA2,
|
||||
0x56, 0xB0, 0xE8, 0x16, 0xA4, 0xEE, 0x89, 0xE0, 0x36, 0x4D, 0x8C, 0xBF, 0x27, 0x3E, 0x37, 0xB9,
|
||||
0xC2, 0x51, 0x88, 0xB5, 0xEC, 0x19, 0xBE, 0x71, 0x3E, 0x87, 0xEE, 0x8C, 0x34, 0xA9, 0x56, 0xE8,
|
||||
0x70, 0xB9, 0x75, 0x6D, 0x24, 0xFD, 0xF0, 0xEE, 0x8A, 0x65, 0xFC, 0x8B, 0x8B, 0x23, 0xDB, 0xA1,
|
||||
0xE2, 0x02, 0x9C, 0x42, 0x56, 0xAB, 0xB0, 0x70, 0x08, 0xBC, 0x4E, 0xB3, 0x57, 0x8E, 0x22, 0xC5,
|
||||
0xEA, 0xB8, 0xDD, 0xD4, 0x14, 0x3E, 0xC2, 0xB6, 0xAB, 0xCD, 0xE0, 0x0B, 0x2E, 0x96, 0xD3, 0x4E,
|
||||
0xD4, 0x71, 0x11, 0x2A, 0xE0, 0x3B, 0xEC, 0x73, 0x2D, 0xDD, 0x04, 0xAD, 0x69, 0x38, 0x83, 0xA6,
|
||||
0x03, 0xC5, 0xAA, 0x85, 0xB6, 0x4C, 0x41, 0x33, 0x88, 0x05, 0x7B, 0xC2, 0xAB, 0x26, 0x5F, 0xD7,
|
||||
0xA2, 0x00, 0xD5, 0xBE, 0xB2, 0x69, 0x8A, 0xF1, 0x16, 0xD5, 0xF6, 0x6B, 0xDC, 0xEE, 0xDF, 0x7F,
|
||||
0xCE, 0xB8, 0xF5, 0x2E, 0xBE, 0x5D, 0xAA, 0xD0, 0x0D, 0x2F, 0x70, 0x09, 0xD6, 0xB2, 0x6C, 0x59,
|
||||
0x43, 0x1C, 0x87, 0x78, 0x27, 0x0D, 0x0A, 0x8C, 0xE5, 0x88, 0x2F, 0xC0, 0xBE, 0x2E, 0x3F, 0x0D,
|
||||
0x45, 0xAF, 0x4C, 0x2F, 0x3C, 0x41, 0x62, 0xA9, 0xB2, 0xF1, 0x8B, 0xC4, 0x59, 0x6D, 0x8B, 0x85,
|
||||
0x76, 0x68, 0x7E, 0xCA, 0xE9, 0xC1, 0x0F, 0xB0, 0x60, 0x37, 0xA3, 0xDA, 0xB5, 0x5B, 0xB7, 0x89,
|
||||
0xF7, 0xA2, 0xA9, 0x50, 0xEA, 0x37, 0x02, 0xB1, 0x6A, 0x90, 0x2B, 0x2D, 0xC3, 0x41, 0x50, 0x9F,
|
||||
0x25, 0x8F, 0x35, 0xEC, 0xA7, 0xA7, 0x33, 0xD0, 0xB4, 0xAE, 0x92, 0xC3, 0x88, 0x4E, 0xF1, 0x73,
|
||||
0xF0, 0xF9, 0x59, 0x25, 0x17, 0x06, 0x71, 0x6B, 0x70, 0x92, 0xA4, 0xD1, 0x3E, 0xFE, 0xD8, 0xC5,
|
||||
0x75, 0x5B, 0xD6, 0x53, 0x56, 0x5C, 0x07, 0x53, 0xEE, 0xA9, 0x79, 0xFC, 0x33, 0xC8, 0x3A, 0x21,
|
||||
0xDD, 0xCD, 0x3C, 0xF1, 0x2A, 0xF8, 0x3F, 0x06, 0x5D, 0x0B, 0xA7, 0xEC, 0x1F, 0x14, 0x04, 0x79,
|
||||
0x97, 0x57, 0x83, 0x7A, 0x5D, 0x9A, 0x55, 0xB0, 0xEE, 0xC6, 0xEF, 0x0A, 0x1F, 0x71, 0x03, 0x2D,
|
||||
0x56, 0xEC, 0x1B, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60,
|
||||
0x82);
|
||||
|
||||
public static readonly EditorTexture MANUAL_PNG = new("T_TB_Manual",
|
||||
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, 0x00,
|
||||
0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x08, 0x04, 0x00, 0x00, 0x00, 0x27, 0x80, 0xD5, 0x86, 0x00,
|
||||
0x00, 0x00, 0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xAE, 0xCE, 0x1C, 0xE9, 0x00, 0x00, 0x01, 0x4F, 0x49,
|
||||
0x44, 0x41, 0x54, 0x28, 0xCF, 0xBD, 0xD2, 0xBF, 0x4B, 0x95, 0x51, 0x1C, 0xC7, 0xF1, 0xAF, 0xBF, 0xA2,
|
||||
0xAE, 0x21, 0x14, 0x28, 0x2E, 0xD1, 0xE8, 0x10, 0x09, 0x85, 0x43, 0xD0, 0x10, 0x82, 0x58, 0x54, 0x44,
|
||||
0x0D, 0x49, 0x81, 0x6B, 0x4B, 0x8B, 0x43, 0xD0, 0x60, 0x08, 0x82, 0x70, 0xFF, 0x01, 0xF1, 0x1F, 0x68,
|
||||
0x6E, 0x6B, 0xCB, 0x4D, 0x5D, 0x6E, 0x54, 0x90, 0x8B, 0x38, 0x18, 0x21, 0xA1, 0x68, 0x6A, 0x57, 0xF3,
|
||||
0xDE, 0xD2, 0xE7, 0xDE, 0xFB, 0x72, 0x78, 0xD4, 0xFB, 0x18, 0x78, 0x71, 0xEA, 0x4C, 0xE7, 0xF0, 0x79,
|
||||
0x73, 0x0E, 0xDF, 0xF7, 0xE7, 0x44, 0xFC, 0x97, 0x25, 0x67, 0xCA, 0xBC, 0x82, 0x51, 0x6D, 0x8D, 0xB0,
|
||||
0xA7, 0x7E, 0xDB, 0x55, 0x50, 0x50, 0xB1, 0x73, 0x3A, 0xF6, 0x5A, 0xC5, 0xAC, 0x5C, 0x44, 0x84, 0x5B,
|
||||
0xAA, 0x3A, 0xB2, 0xE1, 0x88, 0x55, 0x45, 0xFB, 0x7E, 0x79, 0xA7, 0x2A, 0x1F, 0xA1, 0xCB, 0xA4, 0x09,
|
||||
0x1D, 0xF6, 0xBC, 0xAC, 0x63, 0x4F, 0x54, 0xCC, 0x79, 0x61, 0xC8, 0x5B, 0x89, 0x9F, 0x9A, 0x22, 0xAC,
|
||||
0xF8, 0x63, 0x4B, 0x9F, 0x05, 0x1F, 0xEA, 0xE0, 0x77, 0x33, 0xC7, 0xFB, 0x2B, 0x12, 0xFD, 0x6E, 0x4B,
|
||||
0xF4, 0x44, 0x44, 0x78, 0xA3, 0xE4, 0x62, 0x1A, 0xB5, 0x2A, 0x1B, 0x88, 0xF0, 0x4C, 0x51, 0x49, 0xCE,
|
||||
0xA2, 0x82, 0x2E, 0xF7, 0x5C, 0x36, 0x23, 0xEF, 0x9C, 0xB2, 0xF1, 0x14, 0xBC, 0xA3, 0xE6, 0xAA, 0x1B,
|
||||
0x6A, 0x3E, 0x7B, 0xA0, 0xD9, 0x98, 0xBF, 0xDA, 0x22, 0x7C, 0x53, 0xF6, 0x25, 0xC2, 0x27, 0xCB, 0x29,
|
||||
0xD8, 0xA9, 0xE8, 0xBD, 0x71, 0x8B, 0x87, 0x8F, 0xB7, 0x4B, 0xBC, 0x8A, 0x50, 0xD4, 0x1F, 0x11, 0xE1,
|
||||
0x91, 0xC4, 0xA5, 0x34, 0x7A, 0x6E, 0xDF, 0xF5, 0x08, 0xD7, 0xAC, 0xAB, 0x18, 0x34, 0x6B, 0xFE, 0x84,
|
||||
0xF6, 0x5D, 0xF7, 0x53, 0xB0, 0xC9, 0x82, 0xE5, 0x08, 0x5F, 0x6D, 0x78, 0xEC, 0x82, 0x41, 0x25, 0xB9,
|
||||
0x8C, 0xF6, 0x4D, 0xF9, 0xA3, 0x59, 0x7B, 0xEC, 0x19, 0xF6, 0xD0, 0xCD, 0xC3, 0xF3, 0x8E, 0xB9, 0x8C,
|
||||
0xF6, 0x56, 0x2D, 0x75, 0x45, 0xD3, 0x96, 0x32, 0xDA, 0xD7, 0x38, 0xBE, 0xE5, 0x9F, 0xE2, 0x7A, 0x55,
|
||||
0x4F, 0x68, 0xDF, 0x3E, 0xBD, 0xE3, 0x9A, 0x1F, 0x67, 0xF9, 0x58, 0x2D, 0x3E, 0x66, 0x5A, 0x6D, 0x00,
|
||||
0x76, 0xBB, 0xAB, 0xF9, 0x2C, 0xE0, 0x79, 0xED, 0x8D, 0x89, 0x03, 0xDB, 0x0E, 0x1A, 0x97, 0x4F, 0xCA,
|
||||
0x84, 0x01, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b6cd1e1a8fb4d328fbb09d76179a619
|
||||
timeCreated: 1711455760
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/EditorUI/TrembleIcons.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEditor.Overlays;
|
||||
using UnityEditor.Toolbars;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
#if UNITY_2022_1_OR_NEWER
|
||||
[Overlay(typeof(SceneView), "Tremble Sync", true, id = ID)]
|
||||
#else
|
||||
[Overlay(typeof(SceneView), "Tremble Sync", true)]
|
||||
#endif
|
||||
public class TrembleSyncOverlay : ToolbarOverlay
|
||||
{
|
||||
private const string ID = "TrembleSync";
|
||||
|
||||
public TrembleSyncOverlay() : base(ReimportMapButton.ID, SyncButton.ID, ConfigButton.ID, ManualButton.ID)
|
||||
{
|
||||
}
|
||||
|
||||
protected override Layout supportedLayouts => Layout.HorizontalToolbar | Layout.VerticalToolbar;
|
||||
}
|
||||
|
||||
[EditorToolbarElement(ID, typeof(SceneView))]
|
||||
public class ReimportMapButton : EditorToolbarButton
|
||||
{
|
||||
public const string ID = "Tremble/Reimport";
|
||||
|
||||
public ReimportMapButton()
|
||||
{
|
||||
icon = TrembleIcons.IMPORT_PNG.Get();
|
||||
tooltip = "Reimport Current Map";
|
||||
clicked += TrembleEditorAPI.ReimportCurrentMap;
|
||||
}
|
||||
}
|
||||
|
||||
[EditorToolbarElement(ID, typeof(SceneView))]
|
||||
public class SyncButton : EditorToolbarButton
|
||||
{
|
||||
public const string ID = "Tremble/Sync";
|
||||
|
||||
public SyncButton()
|
||||
{
|
||||
icon = TrembleIcons.SYNC_PNG.Get();
|
||||
tooltip = "Sync to TrenchBroom";
|
||||
clicked += TrembleEditorAPI.SyncToTrenchBroom;
|
||||
}
|
||||
}
|
||||
|
||||
[EditorToolbarElement(ID, typeof(SceneView))]
|
||||
public class ConfigButton : EditorToolbarButton
|
||||
{
|
||||
public const string ID = "Tremble/Config";
|
||||
|
||||
public ConfigButton()
|
||||
{
|
||||
icon = TrembleIcons.CONFIG_PNG.Get();
|
||||
tooltip = "Tremble Settings";
|
||||
clicked += TrembleEditorAPI.OpenSettings;
|
||||
}
|
||||
}
|
||||
|
||||
[EditorToolbarElement(ID, typeof(SceneView))]
|
||||
public class ManualButton : EditorToolbarButton
|
||||
{
|
||||
public const string ID = "Tremble/Manual";
|
||||
|
||||
public ManualButton()
|
||||
{
|
||||
icon = TrembleIcons.MANUAL_PNG.Get();
|
||||
tooltip = "Tremble Manual";
|
||||
clicked += () => TrembleEditorAPI.OpenManual();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a930a79e3a324c35b20894fac9d8b4a2
|
||||
timeCreated: 1706013427
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/EditorUI/TrembleSyncOverlay.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c63360b568474474a397794178a8f00a
|
||||
timeCreated: 1721666903
|
||||
@@ -0,0 +1,117 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
internal static class EditorGUILayoutUtil
|
||||
{
|
||||
internal static void Pad(float pad, Action content) => Pad(pad, pad, content);
|
||||
internal static void Pad(float hPad, float vPad, Action content)
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
GUILayout.Space(hPad);
|
||||
GUILayout.BeginVertical();
|
||||
{
|
||||
GUILayout.Space(vPad);
|
||||
|
||||
try
|
||||
{
|
||||
content();
|
||||
}
|
||||
catch (ExitGUIException)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogException(ex);
|
||||
}
|
||||
|
||||
GUILayout.Space(vPad);
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
GUILayout.Space(hPad);
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
private static readonly Dictionary<string, bool> s_CollapsibleHeaderStates = new();
|
||||
|
||||
internal static void Indent(Action inside)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
inside();
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
|
||||
internal static bool FoldoutArrow(bool isOpen)
|
||||
{
|
||||
bool toggle = GUILayout.Button(GUIContent.none, EditorStyles.label, GUILayout.Width(20f));
|
||||
|
||||
Rect buttonRect = GUILayoutUtility.GetLastRect();
|
||||
buttonRect.x += 5f;
|
||||
|
||||
if (Event.current.type == EventType.Repaint)
|
||||
{
|
||||
EditorStyles.foldout.Draw(buttonRect, false, false, isOpen, false);
|
||||
}
|
||||
|
||||
return toggle;
|
||||
}
|
||||
|
||||
internal static bool CollapsibleHeader(string header, bool isOpen, Action inside)
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
bool toggle = FoldoutArrow(isOpen);
|
||||
toggle |= GUILayout.Button(header, EditorStyles.label);
|
||||
|
||||
if (toggle)
|
||||
{
|
||||
isOpen = !isOpen;
|
||||
}
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
if (isOpen)
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
GUILayout.Space(20f);
|
||||
GUILayout.BeginVertical();
|
||||
{
|
||||
inside();
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
return isOpen;
|
||||
}
|
||||
|
||||
internal static void CollapsibleHeader(string header, string id, bool defaultOpen, Action inside)
|
||||
{
|
||||
bool wasOpen = s_CollapsibleHeaderStates.GetValueOrDefault(id, defaultOpen);
|
||||
s_CollapsibleHeaderStates[id] = CollapsibleHeader(header, wasOpen, inside);
|
||||
}
|
||||
|
||||
internal static void CollapsibleHeader(string header, string id, Action inside)
|
||||
=> CollapsibleHeader(header, id, defaultOpen: false, inside);
|
||||
|
||||
internal static void SetHeaderOpen(string id, bool isOpened)
|
||||
{
|
||||
s_CollapsibleHeaderStates[id] = isOpened;
|
||||
}
|
||||
internal static bool IsHeaderOpen(string id) => s_CollapsibleHeaderStates.GetValueOrDefault(id, false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4c018a50074942338e9d90803f43545a
|
||||
timeCreated: 1712049970
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/EditorUI/Utils/EditorGUILayoutUtil.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,81 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
// Adapted from Unity3D-IconManager by Thundernerd.
|
||||
// This is only a tiny portion of the original code, but in the interest of attributing to his good work,
|
||||
// I'll include his licence and a link to the original.
|
||||
|
||||
// https://github.com/Thundernerd/Unity3D-IconManager/
|
||||
|
||||
// Original Licence follows:
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) [2020] [Christiaan Bloemendaal]
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
// associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
// including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||
// portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
public static class EditorGameObjectIconUtil
|
||||
{
|
||||
public enum EditorIcon
|
||||
{
|
||||
GrayDiamond,
|
||||
BlueDiamond,
|
||||
TealDiamond,
|
||||
GreenDiamond,
|
||||
YellowDiamond,
|
||||
OrangeDiamond,
|
||||
RedDiamond,
|
||||
PurpleDiamond,
|
||||
|
||||
MAX
|
||||
}
|
||||
|
||||
public enum EditorLabel
|
||||
{
|
||||
Gray,
|
||||
Blue,
|
||||
Teal,
|
||||
Green,
|
||||
Yellow,
|
||||
Orange,
|
||||
Red,
|
||||
Purple,
|
||||
|
||||
MAX
|
||||
}
|
||||
|
||||
public static void SetEditorIcon(this GameObject go, EditorIcon icon)
|
||||
{
|
||||
//TODO(jwf): cache these!
|
||||
Texture2D texture = EditorGUIUtility.FindTexture($"sv_icon_dot{(int)icon+8}_pix16_gizmo");
|
||||
EditorGUIUtility.SetIconForObject(go, texture);
|
||||
}
|
||||
|
||||
public static void SetEditorIcon(this GameObject go, EditorLabel label)
|
||||
{
|
||||
//TODO(jwf): cache these!
|
||||
Texture2D texture = EditorGUIUtility.FindTexture($"sv_label_{(int)label}");
|
||||
EditorGUIUtility.SetIconForObject(go, texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 053deb05101c4cf29d8d760aa74f619f
|
||||
timeCreated: 1724832500
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/EditorUI/Utils/EditorGameObjectIconUtil.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,154 @@
|
||||
//
|
||||
// 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 UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
public static class MaterialGroupUtil
|
||||
{
|
||||
public static bool RemoveMaterialsFromGroups(Material[] materials)
|
||||
=> MoveMaterialsToGroupIdx(materials, -1);
|
||||
|
||||
public static bool MoveMaterialsToGroup(Material[] materials, string groupName, bool createIfNotExist = false)
|
||||
{
|
||||
int index = GetMaterialGroupIndex(groupName);
|
||||
if (index == -1 && !createIfNotExist)
|
||||
{
|
||||
Debug.LogError($"Could not move materials to non-existent group '{groupName}'!");
|
||||
return false;
|
||||
}
|
||||
|
||||
TrembleSyncSettings syncSettings = TrembleSyncSettings.Get();
|
||||
|
||||
// New group - create and add
|
||||
if (index == -1)
|
||||
{
|
||||
syncSettings.Modify(so =>
|
||||
{
|
||||
SerializedProperty materialGroupsArray = so.FindBackedProperty(nameof(TrembleSyncSettings.MaterialGroups));
|
||||
materialGroupsArray.AppendArrayElement();
|
||||
});
|
||||
|
||||
MaterialGroup[] mgs = syncSettings.MaterialGroups;
|
||||
mgs[^1].Name = groupName;
|
||||
mgs[^1].Materials = Array.Empty<Material>();
|
||||
|
||||
index = mgs.Length - 1;
|
||||
}
|
||||
|
||||
return MoveMaterialsToGroupIdx(materials, index);
|
||||
}
|
||||
|
||||
public static int GetMaterialGroupIndexForMaterial(Material material)
|
||||
{
|
||||
TrembleSyncSettings syncSettings = TrembleSyncSettings.Get();
|
||||
|
||||
for (int materialGroupIdx = 0; materialGroupIdx < syncSettings.MaterialGroups.Length; materialGroupIdx++)
|
||||
{
|
||||
MaterialGroup mg = syncSettings.MaterialGroups[materialGroupIdx];
|
||||
|
||||
foreach (Material m in mg.Materials)
|
||||
{
|
||||
if (material == m)
|
||||
return materialGroupIdx;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static bool IsMaterialPartOfAnyMaterialGroup(Material material)
|
||||
=> GetMaterialGroupIndexForMaterial(material) != -1;
|
||||
|
||||
private static bool MoveMaterialsToGroupIdx(Material[] materials, int index)
|
||||
{
|
||||
TrembleSyncSettings syncSettings = TrembleSyncSettings.Get();
|
||||
MaterialGroup[] mgs = syncSettings.MaterialGroups;
|
||||
|
||||
for (int groupIdx = 0; groupIdx < mgs.Length; groupIdx++)
|
||||
{
|
||||
if (groupIdx == index)
|
||||
{
|
||||
// Our target group - remove these mats, and add to end
|
||||
mgs[groupIdx].Materials = mgs[groupIdx].Materials
|
||||
.Where(m => !materials.Contains(m))
|
||||
.Concat(materials)
|
||||
.ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not our target group - remove these mats
|
||||
mgs[groupIdx].Materials = mgs[groupIdx].Materials
|
||||
.Where(m => !materials.Contains(m))
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
CleanupMissingMaterials(mgs);
|
||||
CleanupEmptyGroups(mgs);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void CleanupMissingMaterials(MaterialGroup[] mgs)
|
||||
{
|
||||
for (int groupIdx = 0; groupIdx < mgs.Length; groupIdx++)
|
||||
{
|
||||
mgs[groupIdx].Materials = mgs[groupIdx].Materials
|
||||
.Where(m => m)
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private static void CleanupEmptyGroups(MaterialGroup[] mgs)
|
||||
{
|
||||
// Now check for empty groups
|
||||
List<int> removeIndexes = new();
|
||||
for (int groupIdx = 0; groupIdx < mgs.Length; groupIdx++)
|
||||
{
|
||||
if (mgs[groupIdx].Materials.Length != 0)
|
||||
continue;
|
||||
|
||||
bool remove = EditorUtility.DisplayDialog("Empty Material Group", $"Material Group '{mgs[groupIdx].Name}' is empty - delete it?", "Yup", "No - keep it!");
|
||||
if (!remove)
|
||||
continue;
|
||||
|
||||
removeIndexes.Add(groupIdx);
|
||||
}
|
||||
|
||||
int numRemoved = 0;
|
||||
foreach (int idx in removeIndexes)
|
||||
{
|
||||
int removeIdx = idx - numRemoved;
|
||||
numRemoved++;
|
||||
|
||||
TrembleSyncSettings.Get().Modify(so =>
|
||||
{
|
||||
SerializedProperty groupsProp = so.FindBackedProperty(nameof(TrembleSyncSettings.MaterialGroups));
|
||||
groupsProp.DeleteArrayElementAtIndex(removeIdx);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static int GetMaterialGroupIndex(string groupName)
|
||||
{
|
||||
TrembleSyncSettings syncSettings = TrembleSyncSettings.Get();
|
||||
|
||||
for (int mgIdx = 0; mgIdx < syncSettings.MaterialGroups.Length; mgIdx++)
|
||||
{
|
||||
if (syncSettings.MaterialGroups[mgIdx].Name.EqualsInvariant(groupName))
|
||||
return mgIdx;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bfca730eb4364517a3fa6aafb28dc837
|
||||
timeCreated: 1722943294
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/EditorUI/Utils/MaterialGroupUtil.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
public static class MaterialRenderDataUtil
|
||||
{
|
||||
public static void SetMaterialImportMode(this Material mat, MaterialImportMode mode)
|
||||
=> ModifyRenderData(mat, mrd => mrd.ExportMode = mode);
|
||||
|
||||
public static void SetMaterialResolutionOverridden(this Material mat, bool overrideResolution)
|
||||
=> ModifyRenderData(mat, mrd => mrd.IsResolutionOverridden = overrideResolution);
|
||||
|
||||
public static void SetMaterialResolutionX(this Material mat, MaterialExportSize size)
|
||||
=> ModifyRenderData(mat, mrd => mrd.ResolutionX = size);
|
||||
|
||||
public static void SetMaterialResolutionY(this Material mat, MaterialExportSize size)
|
||||
=> ModifyRenderData(mat, mrd => mrd.ResolutionY = size);
|
||||
|
||||
|
||||
private static void ModifyRenderData(Material mat, Action<MaterialRenderData> action)
|
||||
{
|
||||
TrembleSyncSettings syncSettings = TrembleSyncSettings.Get();
|
||||
MaterialRenderData renderData = TrembleSyncSettings.Get().GetMaterialRenderData(mat);
|
||||
|
||||
action(renderData);
|
||||
EditorUtility.SetDirty(syncSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 808c02ac921b9e4638fdb31dd490d61c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/EditorUI/Utils/MaterialRenderDataUtil.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,391 @@
|
||||
//
|
||||
// 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 UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
// This wraps EditorGUI, EditorGUILayout, GUI, and GUILayout calls.
|
||||
// The purpose is that you can call them in "normal" mode, which forwards the calls on to Unity,
|
||||
// or "keywords capture" mode, which performs no GUI work at all but captures a list of
|
||||
// keywords to expose to the Project Settings window's search.
|
||||
public static class TrembleSettingsGUI
|
||||
{
|
||||
private static readonly List<string> s_Keywords = new(256);
|
||||
private static bool s_IsCapturingKeywords = false;
|
||||
|
||||
private static GUIStyle s_LineStyle;
|
||||
|
||||
private static readonly Dictionary<string, bool> s_FoldoutStates = new();
|
||||
|
||||
public static void BeginKeywordCapture()
|
||||
{
|
||||
s_IsCapturingKeywords = true;
|
||||
s_Keywords.Clear();
|
||||
}
|
||||
|
||||
public static List<string> EndKeywordCapture()
|
||||
{
|
||||
s_IsCapturingKeywords = false;
|
||||
return s_Keywords;
|
||||
}
|
||||
|
||||
public static void Space(float size)
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
return;
|
||||
|
||||
GUILayout.Space(size);
|
||||
}
|
||||
|
||||
public static void FlexibleSpace()
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
return;
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
}
|
||||
|
||||
public static void LabelledHyperlink(string label, string buttonText, string url)
|
||||
=> LabelledHyperlink(label, buttonText, () => Application.OpenURL(url));
|
||||
|
||||
public static void LabelledHyperlink(string label, string buttonText, Action action)
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
{
|
||||
s_Keywords.Add(label);
|
||||
s_Keywords.Add(buttonText);
|
||||
return;
|
||||
}
|
||||
|
||||
BeginHorizontal();
|
||||
{
|
||||
Label(label + ":");
|
||||
if (Button(buttonText, GUILayout.Width(250f)))
|
||||
{
|
||||
action();
|
||||
}
|
||||
}
|
||||
EndHorizontal();
|
||||
}
|
||||
|
||||
public static void BeginHorizontal(GUIStyle style, params GUILayoutOption[] options)
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
return;
|
||||
|
||||
GUILayout.BeginHorizontal(style, options);
|
||||
}
|
||||
public static void BeginHorizontal(params GUILayoutOption[] options)
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
return;
|
||||
|
||||
GUILayout.BeginHorizontal(options);
|
||||
}
|
||||
|
||||
public static void EndHorizontal()
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
return;
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public static void BeginVertical(GUIStyle style, params GUILayoutOption[] options)
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
return;
|
||||
|
||||
GUILayout.BeginVertical(style, options);
|
||||
}
|
||||
|
||||
public static void BeginVertical(params GUILayoutOption[] options)
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
return;
|
||||
|
||||
GUILayout.BeginVertical(options);
|
||||
}
|
||||
|
||||
public static void EndVertical()
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
return;
|
||||
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
public static void BeginScrollView(ref Vector2 scrollPosition, params GUILayoutOption[] options)
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
return;
|
||||
|
||||
scrollPosition = GUILayout.BeginScrollView(scrollPosition, options);
|
||||
}
|
||||
|
||||
public static void EndScrollView()
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
return;
|
||||
|
||||
GUILayout.EndScrollView();
|
||||
}
|
||||
|
||||
public static void MakeLastRectClickable(Action onClick)
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
return;
|
||||
|
||||
Rect verticalRect = GUILayoutUtility.GetLastRect();
|
||||
if (Event.current.type == EventType.MouseDown && verticalRect.Contains(Event.current.mousePosition))
|
||||
{
|
||||
onClick();
|
||||
Event.current.Use(); // consume
|
||||
}
|
||||
}
|
||||
|
||||
public static void HelpBox(string message, MessageType type)
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
{
|
||||
s_Keywords.Add(message);
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.HelpBox(message, type);
|
||||
}
|
||||
|
||||
public static void Separator(float height = 1f)
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
return;
|
||||
|
||||
s_LineStyle ??= new() { normal = new() { background = Texture2D.grayTexture } };
|
||||
GUILayout.Box(Texture2D.grayTexture, s_LineStyle, GUILayout.ExpandWidth(true), GUILayout.Height(height));
|
||||
}
|
||||
|
||||
public static void Label(string text, params GUILayoutOption[] options)
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
{
|
||||
s_Keywords.Add(text);
|
||||
return;
|
||||
}
|
||||
|
||||
GUILayout.Label(text, GUI.skin.label, options);
|
||||
}
|
||||
|
||||
public static void Label(string text, GUIStyle style, params GUILayoutOption[] options)
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
{
|
||||
s_Keywords.Add(text);
|
||||
return;
|
||||
}
|
||||
|
||||
GUILayout.Label(text, style, options);
|
||||
}
|
||||
|
||||
public static bool Button(string text, params GUILayoutOption[] options)
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
{
|
||||
s_Keywords.Add(text);
|
||||
return false;
|
||||
}
|
||||
|
||||
return GUILayout.Button(text, options);
|
||||
}
|
||||
|
||||
public static bool Button(GUIContent content, GUIStyle style, params GUILayoutOption[] options)
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
{
|
||||
s_Keywords.Add(content.text);
|
||||
return false;
|
||||
}
|
||||
|
||||
return GUILayout.Button(content, style, options);
|
||||
}
|
||||
|
||||
public static bool Toggle(bool value, GUIContent content)
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
{
|
||||
s_Keywords.Add(content.text);
|
||||
return value;
|
||||
}
|
||||
|
||||
return GUILayout.Toggle(value, content);
|
||||
}
|
||||
|
||||
public static bool Toggle(bool value, GUIContent content, params GUILayoutOption[] options)
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
{
|
||||
s_Keywords.Add(content.text);
|
||||
return value;
|
||||
}
|
||||
|
||||
return GUILayout.Toggle(value, content, options);
|
||||
}
|
||||
|
||||
public static float FloatField(float value)
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
return value;
|
||||
|
||||
return EditorGUILayout.FloatField(value);
|
||||
}
|
||||
|
||||
|
||||
public static void PropertyField(SerializedProperty sp, params GUILayoutOption[] options)
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
return;
|
||||
|
||||
EditorGUILayout.PropertyField(sp, GUIContent.none, options);
|
||||
}
|
||||
|
||||
public static void Image(Texture2D texture, float width, float height)
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
return;
|
||||
|
||||
GUILayout.Box(texture, GUILayout.Width(width), GUILayout.Height(height));
|
||||
}
|
||||
|
||||
public static bool Foldout(bool foldout, string content, bool toggleOnLabelClick)
|
||||
=> Foldout(foldout, content, toggleOnLabelClick, EditorStyles.foldout);
|
||||
|
||||
public static bool Foldout(bool foldout, string content, bool toggleOnLabelClick, GUIStyle style)
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
return foldout;
|
||||
|
||||
return EditorGUILayout.Foldout(foldout, content, toggleOnLabelClick, style);
|
||||
}
|
||||
|
||||
public static void Foldout(string title, Action contents)
|
||||
=> Foldout(title, contents, EditorStyles.foldout);
|
||||
|
||||
public static void Foldout(string title, Action contents, GUIStyle style)
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
return;
|
||||
|
||||
bool foldout = s_FoldoutStates.GetValueOrDefault(title, false);
|
||||
foldout = Foldout(foldout, title, true, style);
|
||||
|
||||
if (foldout)
|
||||
{
|
||||
Space(10f);
|
||||
|
||||
BeginHorizontal();
|
||||
{
|
||||
Space(20f);
|
||||
|
||||
BeginVertical();
|
||||
{
|
||||
contents();
|
||||
}
|
||||
EndVertical();
|
||||
}
|
||||
EndHorizontal();
|
||||
|
||||
Space(10f);
|
||||
}
|
||||
|
||||
s_FoldoutStates[title] = foldout;
|
||||
}
|
||||
|
||||
public static void PrefixLabel(string text, string tooltip)
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
{
|
||||
s_Keywords.Add(text);
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.PrefixLabel(new GUIContent(text, tooltip));
|
||||
}
|
||||
|
||||
public static int Popup(int value, string[] options)
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
{
|
||||
s_Keywords.AddRange(options);
|
||||
return value;
|
||||
}
|
||||
|
||||
return EditorGUILayout.Popup(value, options);
|
||||
}
|
||||
public static int Popup(int value, string[] options, GUIStyle style)
|
||||
{
|
||||
if (s_IsCapturingKeywords)
|
||||
{
|
||||
s_Keywords.AddRange(options);
|
||||
return value;
|
||||
}
|
||||
|
||||
return EditorGUILayout.Popup(value, options, style);
|
||||
}
|
||||
|
||||
public static void UseDisabled(bool disabled, Action inside)
|
||||
{
|
||||
bool prevDisabled = false;
|
||||
|
||||
if (!s_IsCapturingKeywords)
|
||||
{
|
||||
prevDisabled = !GUI.enabled;
|
||||
GUI.enabled = !disabled;
|
||||
}
|
||||
|
||||
inside();
|
||||
|
||||
if (!s_IsCapturingKeywords)
|
||||
{
|
||||
GUI.enabled = !prevDisabled;
|
||||
}
|
||||
}
|
||||
|
||||
public static void UseColour(Color c, Action inside)
|
||||
{
|
||||
Color previousColour = Color.white;
|
||||
|
||||
if (!s_IsCapturingKeywords)
|
||||
{
|
||||
previousColour = GUI.color;
|
||||
GUI.color = c;
|
||||
}
|
||||
|
||||
inside();
|
||||
|
||||
if (!s_IsCapturingKeywords)
|
||||
{
|
||||
GUI.color = previousColour;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Indent(Action inside)
|
||||
{
|
||||
if (!s_IsCapturingKeywords)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
}
|
||||
|
||||
inside();
|
||||
|
||||
if (!s_IsCapturingKeywords)
|
||||
{
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4aa6428101b54401a08834d76320438b
|
||||
timeCreated: 1721666909
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/EditorUI/Utils/TrembleSettingsGUI.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f20e9f4a105af4a71a347271c79ea536
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,176 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c459dc1c802f7437c980e9dd45061327
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 4
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: iOS
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Android
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: WindowsStoreApps
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: tvOS
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
customData:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Icons/T_TB_Config.png
|
||||
uploadId: 939664
|
||||
Binary file not shown.
@@ -0,0 +1,160 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e900b833b9fae460ea0bc74e646c43c8
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: iPhone
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Android
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Windows Store Apps
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Icons/T_TB_Import.png
|
||||
uploadId: 939664
|
||||
Binary file not shown.
@@ -0,0 +1,176 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d7da2c0fbbbc7469ca79b005587b60f3
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 2
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 4
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: iPhone
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Android
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Windows Store Apps
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: tvOS
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
customData:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Icons/T_TB_Manual.png
|
||||
uploadId: 939664
|
||||
Binary file not shown.
Loaded 100 of 999 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user