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,90 @@
//
// 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.Editor
{
[ManualPage("Advanced/Base Classes")]
public class BaseClassesPage : ManualPageBase
{
protected override void OnGUI()
{
Text(
"Sometimes, you want to use a field (or a set of fields) across multiple",
"prefabs, point entities, and brush entities. For example, imagine you have a 'team' system,",
"whereby different entities might be on a player 'team' or the enemy 'team'. Entities that",
"you may wish to give a 'team' in this case could be the player prefab, some enemy prefabs,",
"and some doors which can only be interacted with by things on the same 'team'."
);
Text(
$"In this case, you can create a C# interface derived from {nameof(ITrembleBaseClass)}, which",
"those entities or prefabs implement, in order to attach fields to all of",
"them at once."
);
Text("Here's how this might look for our 'teams' example:");
Code(
$"using {nameof(TinyGoose)}.{nameof(Tremble)};",
"",
"// Simple enum to denote which team an entity is on (or for).",
"public enum TeamType",
"{",
" Neutral,",
" Players,",
" Enemies,",
"}",
"",
"// Inherit your interface from ITrembleBaseClass in order to expose it to",
"// Tremble.",
$"public interface ITeam : {nameof(ITrembleBaseClass)}",
"{",
" public TeamType Team => TeamType.Neutral; //you must provide a default!",
"}"
);
Text("Now, attach the interface to your entities, like this:");
Code(
$"using {nameof(TinyGoose)}.{nameof(Tremble)};",
"",
$"[{FormatAttributeName(typeof(PrefabEntityAttribute))}]",
"public class Door : MonoBehaviour, ITeam",
"{",
"",
"}"
);
Text(
"In order to read the data set from this base class, you will need to implement",
"OnImportFromMapEntity. You can then store this data in a variable, or do whatever",
"else you need with it."
);
Code(
$"using {nameof(TinyGoose)}.{nameof(Tremble)};",
"",
$"[{FormatAttributeName(typeof(PrefabEntityAttribute))}]",
$"public class Door : MonoBehaviour, ITeam, {nameof(IOnImportFromMapEntity)}",
"{",
" // [SerializeField] so that Unity stores the result",
" [SerializeField] private TeamType m_Team; ",
" ",
" // We must implement this method and pull the data out manually",
$" public void OnImportFromMapEntity({nameof(MapBsp)} mapBsp, {nameof(BspEntity)} entity)",
" {",
" // Interestingly, because this is named `m_Team`, and our",
" // interface has `Team`, this would have been set",
" // automagically anyway. But it's better to be explicit!",
" m_Team = entity.GetBaseClassData<TeamType>(this, nameof(ITeam.Team));",
" Debug.Log($\"This door is usable by the {m_Team} team!\");",
" }",
"}"
);
}
}
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: c25e8e2e7f7a4efdbc9985c7232a2ed0
timeCreated: 1723449065
AssetOrigin:
serializedVersion: 1
productId: 277805
packageName: Tremble - Map Importer
packageVersion: 1.11.1
assetPath: Assets/Tremble/Editor/Manual/Pages/Advanced/BaseClassesPage.cs
uploadId: 939664
@@ -0,0 +1,120 @@
//
// This file is part of the Tremble package by Tiny Goose.
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
//
namespace TinyGoose.Tremble.Editor
{
[ManualPage("Advanced/Custom Types")]
public class CustomTypesPage : ManualPageBase
{
protected override void OnGUI()
{
Text("Tremble also supports syncing custom data types from your maps.");
Text("For example, imagine you have an enemy that has a random amount of",
"health, chosen between two values that you want to set in a map. You could of course add",
"two fields, like this:"
);
CodeWithHeader("Individual fields sample",
"[SerializeField] private int m_MinHealth = 10;",
"[SerializeField] private int m_MaxHealth = 50;"
);
Text("However, you might prefer a single field of a custom type, something like this:");
CodeWithHeader("Custom type sample",
"[SerializeField] private IntInRange m_HealthRange = new(10, 50);");
Text("To do this, first you need a custom type of course (well, you might already have one!)",
"- in our example something like this:");
CodeWithHeader("IntInRange.cs",
"[Serializable]",
"public struct IntInRange",
"{",
" [SerializeField] public int Min;",
" [SerializeField] public int Max;",
"",
" public override string ToString() => $\"{Min}-{Max}\";",
"}");
Text("Now we have our class to store our data, we just need to tell Tremble how to read/write",
"this data from our map.");
Text("To do this, we create a new class extending TrembleFieldConverter,",
"and add the [TrembleFieldConverter] attribute to it.");
CodeWithHeader("IntInRangeFieldConverter.cs",
"[TrembleFieldConverter(typeof(IntInRange))]",
"public class IntInRangeFieldConverter : TrembleFieldConverter<IntInRange>",
"{",
" ...",
"}");
Text("Next, you need to implement the AddFieldToFgd method which tells TrenchBroom how to",
"display your data. This can be as a string, an integer, a list of values, and more.");
CodeWithHeader("AddFieldToFgd Method",
$"protected override void AddFieldToFgd({nameof(FgdClass)} entityClass, string fieldName, IntInRange defaultValue, MemberInfo target)",
"{",
" // Add a hint to the end of the description to show the format",
" string extraDescription = \" (format: \\\"2-4\\\")\";",
"",
" // Get the [Tooltip] attribute for this field, if it exists",
" target.GetCustomAttributes(out TooltipAttribute existingTooltip);",
" ",
" // Add a \"string\" field to the FGD class (it's not a float or boolean, for example)",
$" entityClass.AddField(new {nameof(FgdStringField)}",
" {",
" Name = fieldName,",
" DefaultValue = defaultValue.ToString(),",
" Description = (existingTooltip?.tooltip ?? $\"IntInRange {target.Name}\") + extraDescription",
" });",
"}");
Text("Finally, you need to implement the TryGetValueFromMap method which reads your custom data",
"from an entity in map. This is used when a map is parsed during import. You can read any data",
"from the 'entity' passed in, in any format. This example reads a string value, but you can",
"also read integers, floats, and others.");
CodeWithHeader("TryGetValueFromMap Method",
"protected override bool TryGetValueFromMap(BspEntity entity, string key, MapProcessorBase mapProcessor, MemberInfo target, out IntInRange value)",
"{",
" // Try to read string value for our field",
" if (!entity.TryGetString(key, out string rangeIntValue))",
" {",
" value = default;",
" return false; // we could not convert the data",
" }",
"",
" // Now parse our range from the string value in the map.",
" // !! NOTE !!: This sample code performs no bounds checking and is",
" thus very unsafe. See IntInRangeFieldConverter.cs",
" in the Tremble Sample for a much better implementation!",
"",
" value.Min = int.Parse(rangeIntValue.Split(\"-\")[0]);",
" value.Max = int.Parse(rangeIntValue.Split(\"-\")[1]);",
" return true; // we succesfully converted the data",
"",
"}");
Text("And that's it! Now Tremble will be able to tell TrenchBroom how to display your custom",
"type, and it will be able to import it from maps without issue.");
Text("Feel free to check out the real 'IntInRange.cs' and 'IntInRangeFieldConverter.cs' classes",
"in the Tremble Sample folder, or look in Tremble's FieldConverters folder to see all the",
"built-in field converters for things like Vector3s, strings, Materials, and more!");
}
private void Test(out MinMax mm)
{
mm.Min = 2;
mm.Max = 2;
}
}
struct MinMax
{
public int Min;
public int Max;
}
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 88bb368f84f84983aa5e46dd6b28b70e
timeCreated: 1725216144
AssetOrigin:
serializedVersion: 1
productId: 277805
packageName: Tremble - Map Importer
packageVersion: 1.11.1
assetPath: Assets/Tremble/Editor/Manual/Pages/Advanced/CustomTypesPage.cs
uploadId: 939664
@@ -0,0 +1,97 @@
//
// 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
{
[ManualPage("Advanced/Map Processors")]
public class MapProcessorPage : ManualPageBase
{
protected override void OnGUI()
{
Text(
$"While {nameof(IOnImportFromMapEntity)} can cover a lot of bases for custom import logic,",
"sometimes you need to either:"
);
Bullet(
"look at the map as a whole - for example, to capture all",
"entities of a certain class into a list, and pass this to some system"
);
Bullet(
"or, you might want to use Editor-only functionality, which can be tricky",
"to write inside an OnImportFromMapEntity callback."
);
Text(
$"For this, you can create your own {nameof(MapProcessorBase)} subclass, and override the",
"functions you need."
);
Text(
"An example of this is provided in SampleMapProcessor.cs. The example finds all",
"the Sheep Spawners in the map, and logs their position. However in a real game",
"you might, for example, take the positions of these and write them into a",
"ScriptableObject which could be later used by a minimap system."
);
Text(
"Map Processors can either be set per-Map or in the Tremble Pipeline settings to affect every",
"map in your project.");
Number("To set a per-Map processor, click your map file in the",
"Project tab, and ensure your map processor class(es) are set, like this:"
);
Image("T_Manual_MapProcessor");
Number("To set Map processors globally for your project, open the Pipeline settings.");
ActionBar_SingleAction("Open Pipeline Settings", () =>
{
const string TREMBLE_PIPELINE_PATH = "Project/Tremble/4 Pipeline";
SettingsService.OpenProjectSettings(TREMBLE_PIPELINE_PATH);
});
H1("Sample Map Processor");
Foldout("Show Code", () =>
{
Code(
$"using {nameof(TinyGoose)}.{nameof(Tremble)};",
"",
$"public class MyCoolMapProcessor : {nameof(MapProcessorBase)}",
"{",
$" public override void OnProcessingStarted({nameof(TrembleMapImportSettings)} context, GameObject root, {nameof(MapBsp)} mapBsp)",
" {",
" Debug.Log($\"Map processing started for {mapBsp.MapName}\");",
" }",
$" public override void OnProcessingCompleted({nameof(TrembleMapImportSettings)} context, GameObject root, {nameof(MapBsp)} mapBsp)",
" {",
" Debug.Log($\"Map processing completed for {mapBsp.MapName} - all entities spawned\");",
" }",
" ",
$" public override void ProcessWorldSpawnProperties({nameof(TrembleMapImportSettings)} context, {nameof(MapBsp)} mapBsp, {nameof(BspEntity)} entity, GameObject rootGameObject)",
" {",
" Debug.Log($\"Worldspawn created for {mapBsp.MapName} - map-wide properties can be read from 'entity'\");",
" }",
" ",
$" public override void ProcessPrefabEntity({nameof(TrembleMapImportSettings)} context, {nameof(MapBsp)} mapBsp, {nameof(BspEntity)} entity, GameObject prefab)",
" {",
" Debug.Log(\"Found a prefab!\");",
" }",
$" public override void ProcessBrushEntity({nameof(TrembleMapImportSettings)} context, {nameof(MapBsp)} mapBsp, {nameof(BspEntity)} entity, GameObject brush)",
" {",
" Debug.Log(\"Found a brush!\");",
" }",
$" public override void ProcessPointEntity({nameof(TrembleMapImportSettings)} context, {nameof(MapBsp)} mapBsp, {nameof(BspEntity)} entity, GameObject point)",
" {",
" Debug.Log(\"Found a point!\");",
" }",
"}");
});
}
}
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 1a71f6a787fc471cbaabca9141e578fe
timeCreated: 1723449126
AssetOrigin:
serializedVersion: 1
productId: 277805
packageName: Tremble - Map Importer
packageVersion: 1.11.1
assetPath: Assets/Tremble/Editor/Manual/Pages/Advanced/MapProcessorPage.cs
uploadId: 939664
@@ -0,0 +1,58 @@
//
// 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.Editor
{
[ManualPage("Advanced/Custom Logic with IOnImportFromMapEntity")]
public class OnImportFromMapEntityPage : ManualPageBase
{
protected override void OnGUI()
{
Text(
"Sometimes, the automated import which takes entity properties from TrenchBroom cannot",
"convert the entity fully, or you need to add custom processing logic to translate the",
"data afterwards."
);
Text(
"You can see an example of this in SheepSpawner.cs in the sample project.",
"In this case, we are importing a Point Entity with various properties,",
"but at runtime we set up a reference to a default prefab to spawn, if not set in TrenchBroom.",
$"So, by using this interface and handling OnImportFromMapEntity({nameof(MapBsp)} mapBsp, {nameof(BspEntity)} entity),",
"we can wire this up before the GameObject is saved into the imported map."
);
Text(
"You might also want to add extra components to a Brush entity - for example,",
"adding a Rigidbody:"
);
H1("Code sample");
Code(
$"[{FormatAttributeName(typeof(BrushEntityAttribute))}(\"rigidbody\", category: \"misc\")]",
$"public class RigidbodyEntity : MonoBehaviour, {nameof(IOnImportFromMapEntity)}",
"{",
" // Customisable mass for the rigidbody - but 1kg by default",
" [SerializeField] private float m_Mass = 1f;",
" ",
" // Called after importing this entity into the map.",
$" public void OnImportFromMapEntity({nameof(MapBsp)} mapBsp, {nameof(BspEntity)} entity)",
" {",
" // Turn all colliders for this mesh convex (required for Rigidbodies)",
" foreach (MeshCollider meshCollider in gameObject.GetComponentsInChildren<MeshCollider>())",
" {",
" meshCollider.convex = true;",
" }",
" ",
" // Finally add the rigidbody to the entity, and set its mass.",
" Rigidbody rb = gameObject.AddComponent<Rigidbody>();",
" rb.mass = m_Mass;",
" }",
"}");
}
}
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 1e143c387f9646d18f3ac2ddbc84093d
timeCreated: 1723449090
AssetOrigin:
serializedVersion: 1
productId: 277805
packageName: Tremble - Map Importer
packageVersion: 1.11.1
assetPath: Assets/Tremble/Editor/Manual/Pages/Advanced/OnImportFromMapEntityPage.cs
uploadId: 939664
@@ -0,0 +1,40 @@
//
// 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
{
[ManualPage("Advanced/Pipeline")]
public class PipelinePage : ManualPageBase
{
protected override void OnGUI()
{
Text("When Tremble imports a map, it performs a number of processing steps on it.");
Text(
"From the Pipeline settings, you can choose which steps to perform, and which",
"custom map processors (if any) you want to run. You can speed up import",
"by disabling any steps which your game does not use."
);
Text("The settings looks like this:");
Image("T_Manual_Pipeline");
Callout(
"Note that each step shows how long it took to run, the last time",
"a map was imported."
);
ActionBar_SingleAction("Open Pipeline Settings", () =>
{
const string TREMBLE_PIPELINE_PATH = "Project/Tremble/4 Pipeline";
SettingsService.OpenProjectSettings(TREMBLE_PIPELINE_PATH);
});
}
}
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 4185f010c3e840a9bff636ae5998e587
timeCreated: 1728887902
AssetOrigin:
serializedVersion: 1
productId: 277805
packageName: Tremble - Map Importer
packageVersion: 1.11.1
assetPath: Assets/Tremble/Editor/Manual/Pages/Advanced/PipelinePage.cs
uploadId: 939664
@@ -0,0 +1,73 @@
//
// This file is part of the Tremble package by Tiny Goose.
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
//
namespace TinyGoose.Tremble.Editor
{
[ManualPage("Advanced/Runtime Querying")]
public class RuntimeQueryingPage : ManualPageBase
{
protected override void OnGUI()
{
Text(
"At runtime, Tremble does not perform any logic and has zero overhead by design.",
"Almost all Tremble functionality only runs in the Editor. However, you may need to query",
"a loaded map to find certain objects at runtime."
);
Text(
"Of course, since entities are just MonoBehaviours, you can use Unity's functionality",
"(such as gameObject.GetComponentsInChildren<T>()) to find all objects of a given type."
);
Text(
"However, if you want to find a specific instance of an entity in the map,",
"you can do the following:"
);
Number(
"Ensure the entity you want to find is marked with a unique",
$"{TrembleSyncSettings.Get().IdentityPropertyName} property in TrenchBroom. You can also have multiple",
$"objects with the same {TrembleSyncSettings.Get().IdentityPropertyName}, but when you query the map",
"you will then get a list of entities back."
);
Indent(() =>
{
Bullet(
"For example, in the worldspawn entity you could have a start_spawn field",
"which names a spawn point to start from. We'll set it to 'my_cool_spawnpoint'.",
$"Then, you give your spawn point entity in the world a {TrembleSyncSettings.Get().IdentityPropertyName}"
,"field, with the value 'my_cool_spawnpoint'."
);
});
Number(
$"Now, given a reference to the {nameof(MapDocument)} for your map (which is added to the root",
$"GameObject), you can query for your {TrembleSyncSettings.Get().IdentityPropertyName} with the Q() method."
);
Code(
"// Get the map document - assumes one map in the scene.",
"// You might store a reference somewhere to this instead.",
"",
$"{nameof(MapDocument)} map = GameObject.FindAnyObjectByType<{nameof(MapDocument)}>();",
"",
$"// 1. Find a single entity with this {TrembleSyncSettings.Get().IdentityPropertyName}",
"if (map.Q(\"my_cool_spawnpoint\", out SpawnPoint spawnPoint))",
"{",
" spawnPoint.DoAThing();",
"}",
"",
$"// 2. Find many entities with this {TrembleSyncSettings.Get().IdentityPropertyName}",
"if (map.Q(\"my_cool_spawnpoint\", out SpawnPoint[] spawnPoints))",
"{",
" foreach (SpawnPoint spawnPoint in spawnPoints)",
" {",
" spawnPoint.DoAThing();",
" }",
"}"
);
}
}
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 7d23c1b332fc42a98456960d6ee4e7de
timeCreated: 1723448990
AssetOrigin:
serializedVersion: 1
productId: 277805
packageName: Tremble - Map Importer
packageVersion: 1.11.1
assetPath: Assets/Tremble/Editor/Manual/Pages/Advanced/RuntimeQueryingPage.cs
uploadId: 939664