Second commit

This commit is contained in:
ThomasCharester committed 2026-09-20 15:26:03 +03:00
commit 36840f3ad4
999 files changed
+61364

No files matched your search

@@ -0,0 +1,37 @@
//
// 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;
namespace TinyGoose.Tremble.Editor
{
internal static class AssetDatabaseUtil
{
internal static List<string> GetAllTrembleMapPaths()
{
List<string> allMaps = new();
string[] assetPaths = AssetDatabase.GetAllAssetPaths();
foreach (string assetPath in assetPaths)
{
if (!IsTrembleMapFile(assetPath))
continue;
if (assetPath.Contains("autosave/"))
continue;
allMaps.Add(assetPath);
}
return allMaps;
}
internal static bool IsTrembleMapFile(string assetPath)
=> Path.GetExtension(assetPath).EqualsInvariant(".map");
}
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: ee00bb59f3db43ceb0674202088a8b91
timeCreated: 1707729646
AssetOrigin:
serializedVersion: 1
productId: 277805
packageName: Tremble - Map Importer
packageVersion: 1.11.1
assetPath: Assets/Tremble/Editor/Utils/AssetDatabaseUtil.cs
uploadId: 939664
@@ -0,0 +1,113 @@
//
// This file is part of the Tremble package by Tiny Goose.
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
//
using System;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;
namespace TinyGoose.Tremble.Editor
{
public static class EditorCompileUtil
{
private static readonly EditorPrefsBackedString s_CompileList = new("Tremble_PostCompileActions");
/// <summary>
/// Compile scripts, then call a static method.
/// Method MUST be static.
/// Method can be private or public.
/// Method must take 0 args, or any number of STRING args only.
/// </summary>
/// <param name="type">Type containing method</param>
/// <param name="staticFunctionName">Method name (use nameof)</param>
/// <param name="stringArgs">Optional list of STRING only args to pass (must not contain ',')</param>
public static void CompileThen(Type type, string staticFunctionName, params string[] stringArgs)
{
foreach (string stringArg in stringArgs)
{
if (stringArg.Contains(','))
{
Debug.LogError($"Cannot schedule call to {type.Name}.{staticFunctionName} - arg contains ',' :(");
return;
}
}
// Add to compile list, backed by editor prefs
string[] existing = s_CompileList.Values;
string[] newList = new string[existing.Length + 1];
if (existing.Length > 0)
{
Array.Copy(existing, newList, existing.Length);
}
newList[^1] = $"{type.FullName}.{staticFunctionName}({String.Join(',', stringArgs)})";
s_CompileList.Values = newList;
// Now recompile
AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport | ImportAssetOptions.ForceUpdate);
}
[UnityEditor.Callbacks.DidReloadScripts]
private static void PostCompile()
{
try
{
// Get list of calls and call each one
string[] calls = s_CompileList.Values;
foreach (string call in calls)
{
RunCall(call);
}
}
finally
{
// Finally clear!
s_CompileList.Values = null;
}
}
private static void RunCall(string call)
{
Match match = Regex.Match(call, @"(.+)\.(.+?)\((.+?)?\)");
if (match.Groups.Count < 4)
{
Debug.LogError($"Call '{call}' was not in the correct format :(");
return;
}
string className = match.Groups[1].Captures[0].Value;
string methodName = match.Groups[2].Captures[0].Value;
string argString = match.Groups[3].Captures.Count > 0 ? match.Groups[3].Captures[0].Value : null;
string[] args = argString.IsNullOrEmpty() ? Array.Empty<string>() : argString.Split(',');
Type finalType = Unsupported.GetTypeFromFullName(className);
if (finalType == null)
{
Debug.LogError($"Couldn't find type {className}!");
return;
}
MethodInfo method = finalType.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
if (method == null)
{
Debug.LogError($"Couldn't find static method {finalType.Name}.{methodName}!");
return;
}
int numDeclaringParams = method.GetParameters().Length;
if (numDeclaringParams != args.Length)
{
Debug.LogError($"Couldn't call static method {finalType.Name}.{methodName} with {args.Length} args (expected: {numDeclaringParams}!");
return;
}
method.Invoke(null, args.Select(s => (object)s).ToArray());
}
}
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 024f8fc5df2a44c288a85b38e4688027
timeCreated: 1725008201
AssetOrigin:
serializedVersion: 1
productId: 277805
packageName: Tremble - Map Importer
packageVersion: 1.11.1
assetPath: Assets/Tremble/Editor/Utils/EditorCompileUtil.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.
//
using System;
using UnityEditor;
namespace TinyGoose.Tremble.Editor
{
public class EditorPrefsBackedString
{
private readonly string m_Key;
private string m_Value;
public EditorPrefsBackedString(string key)
{
m_Key = key;
}
public string Value
{
get
{
if (m_Value == null)
{
if (!EditorPrefs.HasKey(m_Key))
return null;
m_Value = EditorPrefs.GetString(m_Key);
}
return m_Value;
}
set
{
m_Value = value;
if (value == null)
{
EditorPrefs.DeleteKey(m_Key);
return;
}
EditorPrefs.SetString(m_Key, value);
}
}
public string[] Values
{
get
{
if (m_Value == null)
{
if (!EditorPrefs.HasKey(m_Key))
return Array.Empty<string>();
m_Value = EditorPrefs.GetString(m_Key);
}
return m_Value.IsNullOrEmpty() ? Array.Empty<string>() : m_Value.Split(';');
}
set
{
if (value == null)
{
m_Value = null;
EditorPrefs.DeleteKey(m_Key);
return;
}
string joinedValue = String.Join(';', value);
m_Value = joinedValue;
EditorPrefs.SetString(m_Key, joinedValue);
}
}
}
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: c91b5487d0aa4bd1ab8350151bb0e544
timeCreated: 1724773115
AssetOrigin:
serializedVersion: 1
productId: 277805
packageName: Tremble - Map Importer
packageVersion: 1.11.1
assetPath: Assets/Tremble/Editor/Utils/EditorPrefsBackedString.cs
uploadId: 939664
+158
View File
@@ -0,0 +1,158 @@
//
// 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;
using Object = UnityEngine.Object;
namespace TinyGoose.Tremble.Editor
{
public class ModTimeDB
{
private readonly string m_DbFile;
private readonly Dictionary<string, ulong> m_Data = new();
public ModTimeDB(string dbFile)
{
m_DbFile = dbFile;
ReadFromFile();
}
public ulong GetFileModifiedTime(Object asset)
{
string assetDatabasePath = AssetDatabase.GetAssetPath(asset);
if (assetDatabasePath.IsNullOrEmpty() || !m_Data.TryGetValue(assetDatabasePath, out ulong time))
return 0ul;
return time;
}
public void SetFileModifiedTime(Object asset, ulong time)
{
string assetDatabasePath = AssetDatabase.GetAssetPath(asset);
if (assetDatabasePath.IsNullOrEmpty())
return;
m_Data[assetDatabasePath] = time;
}
public static ulong CalcModelModifiedTime(GameObject gameObject)
{
ulong time = 0ul;
// Prefab time
AppendObjectModifiedTime(gameObject, ref time);
// Materials
foreach (Renderer renderer in gameObject.GetComponentsInChildren<Renderer>())
{
foreach (Material material in renderer.sharedMaterials)
{
if (!material)
continue;
ulong matTime = CalcMaterialModifiedTime(material);
if (matTime > time)
{
time = matTime;
}
}
}
// Meshes
foreach (MeshFilter filter in gameObject.GetComponentsInChildren<MeshFilter>())
{
if (!filter.sharedMesh)
continue;
AppendObjectModifiedTime(filter.sharedMesh, ref time);
}
return time;
}
public static ulong CalcMaterialModifiedTime(Material material)
{
ulong time = 0ul;
// Material time
AppendObjectModifiedTime(material, ref time);
if (material.shader)
{
// Shader time
AppendObjectModifiedTime(material.shader, ref time);
foreach (string texName in material.GetTexturePropertyNames())
{
// Texture times
Texture texture = material.GetTexture(texName);
if (!texture)
continue;
AppendObjectModifiedTime(texture, ref time);
}
}
return time;
}
private void ReadFromFile()
{
if (!File.Exists(m_DbFile))
return;
string data = File.ReadAllText(m_DbFile);
TokenParser tp = new(data);
while (!tp.IsAtEnd)
{
ReadOnlySpan<char> file = tp.ReadToken(supportCommentsAndQuotes: true);
ulong time = tp.ReadUlong();
m_Data[file.ToString()] = time;
}
}
public void WriteToFile()
{
using FileStream stream = new(m_DbFile, FileMode.Create, FileAccess.Write);
using StreamWriter writer = new(stream);
foreach ((string file, ulong time) in m_Data)
{
writer.WriteLine($"\"{file}\" {time}");
}
}
public static ulong GetObjectModifiedTime(Object unityObject)
{
string objectPath = AssetDatabase.GetAssetPath(unityObject);
if (objectPath.IsNullOrEmpty())
return 0ul;
AssetImporter importer = AssetImporter.GetAtPath(objectPath);
if (!importer)
return 0ul;
return importer.assetTimeStamp;
}
private static void AppendObjectModifiedTime(Object unityObject, ref ulong time)
{
ulong thisTime = GetObjectModifiedTime(unityObject);
if (thisTime > time)
{
time = thisTime;
}
}
}
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 9ad6c3317444439e821b6999629b97e0
timeCreated: 1711965846
AssetOrigin:
serializedVersion: 1
productId: 277805
packageName: Tremble - Map Importer
packageVersion: 1.11.1
assetPath: Assets/Tremble/Editor/Utils/ModTimeDB.cs
uploadId: 939664
@@ -0,0 +1,169 @@
//
// 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;
using Object = UnityEngine.Object;
namespace TinyGoose.Tremble.Editor
{
internal static class SerializedObjectUtil
{
internal static void Modify(this Component component, Action<SerializedObject> actions) => Modify(new SerializedObject(component), actions);
internal static void Modify(this Object obj, Action<SerializedObject> actions) => Modify(new SerializedObject(obj), actions);
private static void Modify(SerializedObject so, Action<SerializedObject> actions)
{
actions?.Invoke(so);
so.ApplyModifiedPropertiesWithoutUndo();
}
internal static SerializedProperty FindBackedProperty(this SerializedObject obj, string name) => obj.FindProperty("m_" + name);
internal static SerializedProperty FindBackedRelativeProperty(this SerializedProperty obj, string name) => obj.FindPropertyRelative("m_" + name);
internal static SerializedProperty AppendArrayElement(this SerializedProperty prop)
{
int elemIdx = prop.arraySize;
prop.InsertArrayElementAtIndex(elemIdx);
return prop.GetArrayElementAtIndex(elemIdx);
}
internal static uint GetHashOfContent(this SerializedProperty prop)
{
#if UNITY_2022_1_OR_NEWER
if (prop.propertyType == SerializedPropertyType.Generic && !prop.isArray)
return (uint)prop.boxedValue.GetHashCode();
return prop.contentHash;
#else
switch (prop.propertyType)
{
case SerializedPropertyType.Integer:
return (uint)prop.intValue.GetHashCode();
case SerializedPropertyType.Boolean:
return (uint)prop.boolValue.GetHashCode();
case SerializedPropertyType.Float:
return (uint)prop.floatValue.GetHashCode();
case SerializedPropertyType.String:
return (uint)prop.stringValue.GetHashCode();
case SerializedPropertyType.Color:
return (uint)prop.colorValue.GetHashCode();
case SerializedPropertyType.ObjectReference:
return (uint)(prop.objectReferenceValue ? prop.objectReferenceValue.GetHashCode() : 0);
case SerializedPropertyType.LayerMask:
return (uint)prop.intValue.GetHashCode();
case SerializedPropertyType.Enum:
return (uint)prop.enumValueIndex.GetHashCode();
case SerializedPropertyType.Vector2:
return (uint)prop.vector2Value.GetHashCode();
case SerializedPropertyType.Vector3:
return (uint)prop.vector3Value.GetHashCode();
case SerializedPropertyType.Vector4:
return (uint)prop.vector4Value.GetHashCode();
case SerializedPropertyType.Rect:
return (uint)prop.rectValue.GetHashCode();
case SerializedPropertyType.Character:
return (uint)prop.intValue.GetHashCode();
case SerializedPropertyType.AnimationCurve:
return (uint)prop.animationCurveValue.GetHashCode();
case SerializedPropertyType.Bounds:
return (uint)prop.boundsValue.GetHashCode();
case SerializedPropertyType.Generic:
return (uint)(prop.isArray ? prop.arraySize : 0);
default:
Debug.LogWarning("Unsupported property type: " + prop.propertyType + $" '{prop.name}'");
return 0u;
}
#endif
}
internal static void SetTo(this SerializedProperty prop, SerializedProperty other)
{
switch (other.propertyType)
{
case SerializedPropertyType.Integer:
prop.intValue = other.intValue;
break;
case SerializedPropertyType.Boolean:
prop.boolValue = other.boolValue;
break;
case SerializedPropertyType.Float:
prop.floatValue = other.floatValue;
break;
case SerializedPropertyType.String:
prop.stringValue = other.stringValue;
break;
case SerializedPropertyType.Color:
prop.colorValue = other.colorValue;
break;
case SerializedPropertyType.ObjectReference:
prop.objectReferenceValue = other.objectReferenceValue;
break;
case SerializedPropertyType.LayerMask:
prop.intValue = other.intValue;
break;
case SerializedPropertyType.Enum:
prop.enumValueIndex = other.enumValueIndex;
break;
case SerializedPropertyType.Vector2:
prop.vector2Value = other.vector2Value;
break;
case SerializedPropertyType.Vector3:
prop.vector3Value = other.vector3Value;
break;
case SerializedPropertyType.Vector4:
prop.vector4Value = other.vector4Value;
break;
case SerializedPropertyType.Rect:
prop.rectValue = other.rectValue;
break;
case SerializedPropertyType.Character:
prop.intValue = other.intValue;
break;
case SerializedPropertyType.AnimationCurve:
prop.animationCurveValue = other.animationCurveValue;
break;
case SerializedPropertyType.Bounds:
prop.boundsValue = other.boundsValue;
break;
case SerializedPropertyType.Generic:
if (prop.isArray)
{
prop.ClearArray();
for (int i = 0; i < other.arraySize; i++)
{
prop.AppendArrayElement().SetTo(prop.GetArrayElementAtIndex(i));
}
}
else
{
#if UNITY_2022_1_OR_NEWER
prop.boxedValue = other.boxedValue;
#endif
}
break;
#if UNITY_2022_1_OR_NEWER
case SerializedPropertyType.Gradient:
prop.gradientValue = other.gradientValue;
break;
#endif
default:
Debug.LogWarning("Unsupported property type: " + prop.propertyType + $" '{prop.name}'");
break;
}
}
internal static bool EqualByValue(this SerializedProperty prop, SerializedProperty other)
=> prop.GetHashOfContent() == other.GetHashOfContent();
}
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 3865af53ccaf4f119a7f26638a8a9234
timeCreated: 1707730421
AssetOrigin:
serializedVersion: 1
productId: 277805
packageName: Tremble - Map Importer
packageVersion: 1.11.1
assetPath: Assets/Tremble/Editor/Utils/SerializedObjectUtil.cs
uploadId: 939664
+152
View File
@@ -0,0 +1,152 @@
//
// This file is part of the Tremble package by Tiny Goose.
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
//
using System;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Serialization;
namespace TinyGoose.Tremble.Editor
{
[Serializable]
public record Changeset
{
public string Version;
public string[] Changes;
}
[Serializable]
public record VersionsFile
{
public Changeset[] Changes;
}
public static class VersionCheck
{
// -----------------------------------------------------------------------------------------------------------------------------
// Consts
// -----------------------------------------------------------------------------------------------------------------------------
private const string VERSION_CHECK_URL = "https://tinygoose.com/data/tremble_version.json";
// -----------------------------------------------------------------------------------------------------------------------------
// State
// -----------------------------------------------------------------------------------------------------------------------------
private static VersionsFile s_Versions;
// -----------------------------------------------------------------------------------------------------------------------------
// Public API
// -----------------------------------------------------------------------------------------------------------------------------
public static bool HasData => s_Versions?.Changes is { Length: > 0 };
private static Changeset LatestChange => s_Versions.Changes[0];
public static Changeset CurrentInstalledVersion
{
get
{
int currentVersion = GetVersion(TrembleConsts.VERSION_STRING);
if (HasData)
{
Changeset versionInfo = s_Versions.Changes.FirstOrDefault(c => GetVersion(c.Version) == currentVersion);
if (versionInfo != null)
return versionInfo;
}
// Make an empty version info
return new()
{
Changes = new[] { "Development Version"},
Version = TrembleConsts.VERSION_STRING,
};
}
}
public static Changeset NewestAvailableVersion => HasData ? LatestChange : default;
// -----------------------------------------------------------------------------------------------------------------------------
// Checking and prompting
// -----------------------------------------------------------------------------------------------------------------------------
public static void FetchLatestVersionsInBackground(Action thenMainThread = null)
{
// Start web request on main thread
UnityWebRequest request = UnityWebRequest.Get(VERSION_CHECK_URL);
UnityWebRequestAsyncOperation async = request.SendWebRequest();
async.completed += operation =>
{
if (request.responseCode != 200)
return;
s_Versions = JsonUtility.FromJson<VersionsFile>(request.downloadHandler.text);
thenMainThread?.Invoke();
};
}
public static bool IsNewerVersionAvailable
{
get
{
if (!HasData)
return false;
int latestVersion = GetVersion(s_Versions.Changes[0].Version);
int currentVersion = GetVersion(TrembleConsts.VERSION_STRING);
return latestVersion > currentVersion;
}
}
public static void PromptToUpgradeIfAvailable(bool showEvenIfDeclined = false)
{
// First prompt to upgrade Tremble itself
bool showMainVersionUpgrade = IsNewerVersionAvailable && (showEvenIfDeclined || !HasPromptedForVersion(LatestChange.Version));
if (showMainVersionUpgrade)
{
SetHasPromptedForVersion(LatestChange.Version);
EditorUtility.DisplayDialog(
title: "New Tremble Version",
message: $"A newer version of Tremble (v{LatestChange.Version}) is available! "
+ "Open Window > Package Manager to update. You won't be reminded about this version again.",
ok: "Cool!");
}
}
public static string[] ChangesSinceCurrentVersion => HasData
? s_Versions.Changes
.Where(c => GetVersion(c.Version) > GetVersion(TrembleConsts.VERSION_STRING))
.SelectMany(c => c.Changes)
.ToArray()
: Array.Empty<string>();
public static int NumVersionsBehind => HasData
? s_Versions.Changes.Count(c => GetVersion(c.Version) > GetVersion(TrembleConsts.VERSION_STRING))
: 0;
// -----------------------------------------------------------------------------------------------------------------------------
// Editor prefs
// -----------------------------------------------------------------------------------------------------------------------------
private static string GetPromptKey(string version) => $"Tremble_{Application.productName}_PromptedFor_{version}";
private static bool HasPromptedForVersion(string version) => EditorPrefs.HasKey(GetPromptKey(version));
private static void SetHasPromptedForVersion(string version) => EditorPrefs.SetBool(GetPromptKey(version), true);
// -----------------------------------------------------------------------------------------------------------------------------
// Utils
// -----------------------------------------------------------------------------------------------------------------------------
private static int GetVersion(string versionString)
{
if (versionString.IsNullOrEmpty())
return 0;
string[] parts = versionString.Split(".");
if (parts.Length != 3)
return 0;
int[] intParts = parts.Select(p => int.TryParse(p, out int intPart) ? intPart : 0).ToArray();
return intParts[0] * 1000000 + intParts[1] * 1000 + intParts[2];
}
}
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: ff8e7fdbe35c46b1a9b0d0dc4b4757ac
timeCreated: 1720202784
AssetOrigin:
serializedVersion: 1
productId: 277805
packageName: Tremble - Map Importer
packageVersion: 1.11.1
assetPath: Assets/Tremble/Editor/Utils/VersionCheck.cs
uploadId: 939664