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: 4a10d864747e4870a69b944b49fb0f57
|
||||
timeCreated: 1723448980
|
||||
@@ -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
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cbb8db30e0c04bceaa04fcd01ce6d5c1
|
||||
timeCreated: 1723137362
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// 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("Basics/Create Map", "Create your first map")]
|
||||
public class CreateMapPage : ManualPageBase
|
||||
{
|
||||
protected override void OnGUI()
|
||||
{
|
||||
Number(
|
||||
"In the project window, right-click and select 'Create' > 'Tremble Map'. Give your map a name,",
|
||||
"then hit enter."
|
||||
);
|
||||
|
||||
ActionBar_SingleAction("Create new map called 'Test' in Assets", () =>
|
||||
{
|
||||
MapFileAsset mapFileAsset = MapFileAsset.CreateInstance<MapFileAsset>();
|
||||
|
||||
AssetDatabase.CreateAsset(mapFileAsset, "Assets/MAP_Test.asset");
|
||||
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
|
||||
});
|
||||
|
||||
Number(
|
||||
"TrenchBroom will open the new map for you to edit, with your project's materials",
|
||||
"available to use."
|
||||
);
|
||||
|
||||
Number(
|
||||
"Since you have not yet marked any Unity scripts as entities, you will not see any",
|
||||
"in TrenchBroom yet and can only create worldspawn brushes for now. See",
|
||||
"the 'Entities' section to get started!"
|
||||
);
|
||||
ActionBar_SingleAction("Read about Entities", () => GoToPage(typeof(EntitiesOverviewPage)));
|
||||
|
||||
Number("When you're ready, save the map and return to Unity.");
|
||||
Number("You should see a prompt - click 'Yep!'. Your new map is added to your current Unity scene.");
|
||||
|
||||
Image("T_Manual_CreateMap", width: 300f);
|
||||
|
||||
Callout("If the prompt doesn't show, or you want to add it to another scene, manually drag your",
|
||||
"new map file into the scene.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 43b737fff371496b807982db7eb1e9ad
|
||||
timeCreated: 1723137369
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/Basics/CreateMapPage.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 UnityEditor;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
[ManualPage("Basics/Live Update", "Using Live Update")]
|
||||
public class LiveUpdatePage : ManualPageBase
|
||||
{
|
||||
private static readonly string[] REFRESH_MODES = { "Disabled", "Enabled", "Enabled Outside Playmode" };
|
||||
|
||||
protected override void OnGUI()
|
||||
{
|
||||
Experimental();
|
||||
|
||||
int autoRefreshMode = EditorPrefs.GetInt("kAutoRefreshMode");
|
||||
if (autoRefreshMode != 1)
|
||||
{
|
||||
Callout($"Your project uses Auto Refresh Mode: {REFRESH_MODES[autoRefreshMode]}. This",
|
||||
$"will mean that Live Update will not function. Change it to {REFRESH_MODES[1]} to",
|
||||
"use Live Update!");
|
||||
ActionBar_SingleAction("Enable Auto Refresh during playmode", () => EditorPrefs.SetInt("kAutoRefreshMode", 1));
|
||||
}
|
||||
|
||||
Text(
|
||||
"Tremble supports Live Editing - the act of editing a map while in Unity Editor's playmode.",
|
||||
"All you need to do is save changes to your map file while the game is running in editor playmode.",
|
||||
"The map is imported as normal, and then Tremble will try to 'reinstance' the map in memory."
|
||||
);
|
||||
|
||||
Foldout("Wait, what's reinstancing?", () =>
|
||||
{
|
||||
Text("What this means is, Tremble will:");
|
||||
|
||||
Bullet("Destroy all worldspawn geometry, and copy the new geometry from the new map");
|
||||
Bullet("For entities:");
|
||||
Indent(() =>
|
||||
{
|
||||
Bullet(
|
||||
"If an entity is not present in the running game, spawn it (note: this may mean, for example,",
|
||||
"that if you kill an enemy and then save the map, the enemy may get respawned)."
|
||||
);
|
||||
Bullet(
|
||||
"If an entity is present in the running game, but not in the map, it is removed",
|
||||
"(this does not work in all cases!)"
|
||||
);
|
||||
Bullet(
|
||||
"If any entity properties have changed, and are simple properties",
|
||||
"(floats, ints, Vector3s), these are updated."
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
H1("Handling Live Update logic");
|
||||
{
|
||||
H2("General Usage");
|
||||
|
||||
Text(
|
||||
"If you need to re-run some logic in an entity after it is LiveUpdated, you can implement",
|
||||
$"the {nameof(IOnLiveUpdate)} interface, and override the OnLiveUpdate() method to perform any custom",
|
||||
"logic."
|
||||
);
|
||||
|
||||
Text(
|
||||
"For example, finding the list of entities of a certain type (as these may have",
|
||||
"changed as a result of the map changing)."
|
||||
);
|
||||
|
||||
Image("T_Manual_LiveUpdate1");
|
||||
|
||||
H2("Simpler Usage");
|
||||
|
||||
Text(
|
||||
"If this logic is identical to what would usually happen in your Start or Awake methods,",
|
||||
$"you can instead implement the {nameof(IOnLiveUpdate_Simple)} interface."
|
||||
);
|
||||
|
||||
Text(
|
||||
"This will signal to Tremble that after a LiveUpdate occurs, it should call OnDestroy,",
|
||||
"followed by Awake and Start (in that order) on your entity. That way, as long as your",
|
||||
"Awake/Start methods set your entity up, and OnDestroy removes any state, it will 'just work'!"
|
||||
);
|
||||
|
||||
Image("T_Manual_LiveUpdate2");
|
||||
}
|
||||
|
||||
H2("Warnings!");
|
||||
{
|
||||
Text(
|
||||
"If LiveUpdate goes wrong or breaks, your game may be left in a broken state.",
|
||||
"To recover from this, you'll need to stop playmode, and start it again."
|
||||
);
|
||||
|
||||
Callout(
|
||||
"Known bug: Sometimes, after LiveUpdate has failed, the map is left in a broken state",
|
||||
"outside of playmode too. This is a rare bug that I've only seen a handful of times.",
|
||||
"Of course, if this occurs, simply re-import your map again after exiting playmode to fix it."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5da16a3f20f7452f92a7f6ca768bb67b
|
||||
timeCreated: 1723449031
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/Basics/LiveUpdatePage.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// 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("Basics/Settings", "Tremble's Settings")]
|
||||
public class SettingsPage : ManualPageBase
|
||||
{
|
||||
protected override void OnGUI()
|
||||
{
|
||||
Text(
|
||||
"Tremble's default settings are designed to be suitable for most users, and most games.",
|
||||
"If you're a bit more advanced, or just want to tweak various things - click ''Tools'' > ",
|
||||
"''Tremble'' > ''Open Settings...'' in the Unity menu."
|
||||
);
|
||||
|
||||
Text(
|
||||
"Each tab shows settings for a different aspect of Tremble.",
|
||||
"Help text is provided for each option."
|
||||
);
|
||||
|
||||
ActionBar_SingleAction("Open Settings for me", TrembleEditorAPI.OpenSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 00222940e88a45a3ac88a8fa87192328
|
||||
timeCreated: 1723137185
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/Basics/SettingsPage.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 UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
[ManualPage("Basics/Sync Toolbar")]
|
||||
public class SyncOverlayPage : ManualPageBase
|
||||
{
|
||||
private bool m_ShowAlreadyHere;
|
||||
|
||||
protected override void OnGUI()
|
||||
{
|
||||
Text(
|
||||
"By default, Tremble adds a toolbar to your scene view to quickly sync settings to",
|
||||
"TrenchBroom, or to (re)import your map."
|
||||
);
|
||||
|
||||
Text(
|
||||
"You can reopen it with \"Tools\" > \"Tremble\" > \"Show Sync Toolbar\" (Unity 2022+)",
|
||||
"if you lose it, or by right-clicking on your scene tab and clicking \"Overlay Menu\"",
|
||||
"(or hitting [`] on your keyboard) and selecting \"Tremble Sync\".");
|
||||
|
||||
#if UNITY_2022_1_OR_NEWER
|
||||
ActionBar_SingleAction("Open the Sync Toolbar for me", () => SceneView.AddOverlayToActiveView(new TrembleSyncOverlay()));
|
||||
#endif
|
||||
|
||||
H1("Toolbar Buttons");
|
||||
Text("The sync toolbar looks like this:");
|
||||
ToolbarButtonDescription("T_TB_Import", "Re-import map(s) in current scene from TrenchBroom");
|
||||
ToolbarButtonDescription("T_TB_Sync", "Sync Unity prefabs and materials to TrenchBroom");
|
||||
ToolbarButtonDescription("T_TB_Config", "Open Tremble's Settings");
|
||||
ToolbarButtonDescription("T_TB_Manual", "Open the Tremble Manual (this!)");
|
||||
|
||||
ActionBar(() =>
|
||||
{
|
||||
Action("Import", TrembleEditorAPI.ReimportCurrentMap);
|
||||
Action("Sync", TrembleEditorAPI.SyncToTrenchBroom);
|
||||
Action("Settings", TrembleEditorAPI.OpenSettings);
|
||||
Action("Manual", () => m_ShowAlreadyHere = true);
|
||||
});
|
||||
|
||||
if (m_ShowAlreadyHere)
|
||||
{
|
||||
Text("You silly! You're already in the manual!");
|
||||
}
|
||||
}
|
||||
|
||||
private void ToolbarButtonDescription(string textureName, string description)
|
||||
{
|
||||
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
|
||||
{
|
||||
Image(textureName, 30f, centred: false);
|
||||
GUILayout.BeginVertical();
|
||||
{
|
||||
GUILayout.Space(10f * ManualStyles.Scale);
|
||||
GUILayout.Label(description, ManualStyles.Styles.Text);
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
GUILayout.FlexibleSpace();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
SmallSpace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b7dbe33a0d0446e381e8d0316f066317
|
||||
timeCreated: 1723117770
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/Basics/SyncOverlayPage.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9d822fe9fde64471bed45f0c6381719e
|
||||
timeCreated: 1726388519
|
||||
@@ -0,0 +1,181 @@
|
||||
//
|
||||
// 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
|
||||
{
|
||||
[ManualPage("Debug/Sanity Check")]
|
||||
public class DebugSanityCheckPage : ManualPageBase
|
||||
{
|
||||
private PrefabNameLookup m_PrefabNameLookup;
|
||||
private MapTypeLookup m_MapTypeLookup;
|
||||
|
||||
private readonly Dictionary<Type, MonoScript> m_TypeToMonoScript = new();
|
||||
|
||||
private int m_SelectedTabIdx = 0;
|
||||
private readonly string[] m_TabNames = new[] { "Basics", "Entities" };
|
||||
|
||||
protected override void OnInit()
|
||||
{
|
||||
TrembleSyncSettings syncSettings = TrembleSyncSettings.Get();
|
||||
m_PrefabNameLookup = new(syncSettings);
|
||||
m_MapTypeLookup = new(syncSettings);
|
||||
}
|
||||
|
||||
protected override void OnGUI()
|
||||
{
|
||||
Tabs(ref m_SelectedTabIdx, m_TabNames);
|
||||
|
||||
switch (m_SelectedTabIdx)
|
||||
{
|
||||
case 0:
|
||||
OnBasicsGUI();
|
||||
break;
|
||||
case 1:
|
||||
OnEntitiesGUI();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnBasicsGUI()
|
||||
{
|
||||
Text("This page will verify that Tremble is installed and working correctly!");
|
||||
|
||||
// TB?
|
||||
bool trenchBroomInstalled = !TrenchBroomUtil.TrenchBroomPath.IsNullOrEmpty();
|
||||
CheckListItem("TrenchBroom installed and detected?", trenchBroomInstalled);
|
||||
|
||||
if (!trenchBroomInstalled)
|
||||
{
|
||||
Callout("If TrenchBroom is installed, but not detected here, open it",
|
||||
"and Tremble should detect its location!");
|
||||
}
|
||||
|
||||
// Installed game into TB?
|
||||
bool gameFolderExists = Directory.Exists(TrenchBroomUtil.GetGameFolder());
|
||||
CheckListItem("TrenchBroom game folder exists?", gameFolderExists, "Sync to create it!", TrembleEditorAPI.SyncToTrenchBroom);
|
||||
|
||||
bool gameInstalledInTBPrefs = TrenchBroomUtil.DoesEnginePathExistInTrenchBroomPrefs();
|
||||
CheckListItem("TrenchBroom knows game location?", gameInstalledInTBPrefs, "Sync to create it!", TrembleEditorAPI.SyncToTrenchBroom);
|
||||
|
||||
// BaseQ3 folder
|
||||
bool baseQ3FolderExists = Directory.Exists(TrembleConsts.BASEQ3_PATH);
|
||||
CheckListItem("BaseQ3 folder exists in Library?", baseQ3FolderExists, "Sync to create it!", TrembleEditorAPI.SyncToTrenchBroom);
|
||||
|
||||
// DLL loaded?
|
||||
bool dllIsLoaded = Q3Map2Dll.IsLoaded;
|
||||
CheckListItem("Q3Map2 DLL loaded successfully?", dllIsLoaded);
|
||||
}
|
||||
|
||||
private void OnEntitiesGUI()
|
||||
{
|
||||
Foldout("Prefab Entities", () =>
|
||||
{
|
||||
Text("The following are the prefabs that Tremble knows about:");
|
||||
|
||||
EditorGUI.BeginDisabledGroup(true);
|
||||
{
|
||||
foreach (string prefabPath in m_PrefabNameLookup.AllPrefabPaths)
|
||||
{
|
||||
GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
|
||||
|
||||
m_PrefabNameLookup.TryGetMapNameFromPrefabPath(prefabPath, out string mapName);
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
EditorGUILayout.PrefixLabel(mapName);
|
||||
EditorGUILayout.ObjectField(prefab, typeof(GameObject), false);
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
EditorGUI.EndDisabledGroup();
|
||||
});
|
||||
|
||||
Foldout("Point Entities", () =>
|
||||
{
|
||||
Text("The following are the [PointEntity] MonoBehaviours that Tremble knows about:");
|
||||
|
||||
bool wasAnyPresent = false;
|
||||
|
||||
foreach (Type type in m_MapTypeLookup.AllTypes)
|
||||
{
|
||||
if (!m_MapTypeLookup.TryGetMapNameFromClass(type, out string mapName))
|
||||
{
|
||||
Text($"Invalid: '{type.Name}' - no map name known!");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!m_MapTypeLookup.TryGetEntityTypeFromMapName(mapName, out EntityType entityType) || entityType != EntityType.Point)
|
||||
continue;
|
||||
|
||||
DisabledTypeField(type, mapName);
|
||||
wasAnyPresent = true;
|
||||
}
|
||||
|
||||
if (!wasAnyPresent)
|
||||
{
|
||||
Text("There are none (which might be fine)!");
|
||||
}
|
||||
});
|
||||
|
||||
Foldout("Brush Entities", () =>
|
||||
{
|
||||
Text("The following are the [BrushEntity] MonoBehaviours that Tremble knows about:");
|
||||
bool wasAnyPresent = false;
|
||||
|
||||
foreach (Type type in m_MapTypeLookup.AllTypes)
|
||||
{
|
||||
if (!m_MapTypeLookup.TryGetMapNameFromClass(type, out string mapName))
|
||||
{
|
||||
Text($"Invalid: '{type.Name}' - no map name known!");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!m_MapTypeLookup.TryGetEntityTypeFromMapName(mapName, out EntityType entityType) || entityType != EntityType.Brush)
|
||||
continue;
|
||||
|
||||
DisabledTypeField(type, mapName);
|
||||
wasAnyPresent = true;
|
||||
}
|
||||
|
||||
if (!wasAnyPresent)
|
||||
{
|
||||
Text("There are none (which might be fine)!");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void DisabledTypeField(Type type, string label)
|
||||
{
|
||||
EditorGUI.BeginDisabledGroup(true);
|
||||
{
|
||||
if (!m_TypeToMonoScript.TryGetValue(type, out MonoScript monoScript))
|
||||
{
|
||||
GameObject go = new("Tester");
|
||||
MonoBehaviour mb = (MonoBehaviour)go.AddComponent(type);
|
||||
monoScript = MonoScript.FromMonoBehaviour(mb);
|
||||
m_TypeToMonoScript[type] = monoScript;
|
||||
|
||||
GameObject.DestroyImmediate(go);
|
||||
}
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
EditorGUILayout.PrefixLabel(label);
|
||||
EditorGUILayout.ObjectField(monoScript, typeof(MonoScript), false);
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
EditorGUI.EndDisabledGroup();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a7c8885112604038b963d644ebbb4ead
|
||||
timeCreated: 1726483054
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/Debug/DebugSanityCheckPage.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEditor;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
[ManualPage("Debug/Entity Explorer")]
|
||||
public class DebugShowEntitiesPage : ManualPageBase
|
||||
{
|
||||
private FgdWriter m_FgdWriter;
|
||||
|
||||
private string[] m_ClassList;
|
||||
private int m_SelectedClassIdx = 0;
|
||||
|
||||
protected override void OnInit()
|
||||
{
|
||||
m_FgdWriter = TrembleSync.GatherEntities();
|
||||
|
||||
m_ClassList = m_FgdWriter.BaseClasses
|
||||
.Select(bc => $"@BaseClass {bc.Name}")
|
||||
.Concat(m_FgdWriter.Classes.Select(c => $"@{c.Type}Class {c.Name}"))
|
||||
.Prepend("(select a class...)")
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
protected override void OnGUI()
|
||||
{
|
||||
m_SelectedClassIdx = EditorGUILayout.Popup(m_SelectedClassIdx, m_ClassList);
|
||||
|
||||
int selectedClassIdx = m_SelectedClassIdx - 1;
|
||||
if (selectedClassIdx < 0)
|
||||
{
|
||||
Text("Select a class above to see its entity definition!");
|
||||
return;
|
||||
}
|
||||
|
||||
FgdClass entityClass = (selectedClassIdx < m_FgdWriter.BaseClasses.Count)
|
||||
? m_FgdWriter.BaseClasses[selectedClassIdx]
|
||||
: m_FgdWriter.Classes[selectedClassIdx - m_FgdWriter.BaseClasses.Count];
|
||||
|
||||
MemoryStream memoryStream = new();
|
||||
|
||||
// Write to memory
|
||||
using StreamWriter writer = new(memoryStream, Encoding.ASCII);
|
||||
entityClass.WriteFgd(writer, TrembleSyncSettings.Get().ImportScale);
|
||||
writer.Flush();
|
||||
|
||||
// Rewind and read
|
||||
memoryStream.Position = 0;
|
||||
using StreamReader reader = new(memoryStream, Encoding.ASCII);
|
||||
string snippet = reader.ReadToEnd().Replace("\t", " ");
|
||||
|
||||
CodeWithHeader($"[{entityClass.Type}] {entityClass.Name}", snippet);
|
||||
|
||||
Text("Above is how the entity is passed to TrenchBroom. If you're familiar with FGD files,",
|
||||
"this will look very familiar! If not, you basically are looking to make sure the name",
|
||||
"is what you would expect, and any fields that you wish to edit on entities of that",
|
||||
"class are present.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2dc49cc1fab340b8a6d97e6fbff9fe66
|
||||
timeCreated: 1726387089
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/Debug/DebugShowEntitiesPage.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,112 @@
|
||||
//
|
||||
// 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 System.Linq;
|
||||
using System.Text;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
[ManualPage("Debug/Material Explorer")]
|
||||
public class DebugShowMaterialsPage : ManualPageBase
|
||||
{
|
||||
private readonly Dictionary<string, List<Texture>> m_Textures = new();
|
||||
|
||||
protected override void OnInit()
|
||||
{
|
||||
int texSize = TrembleSyncSettings.Get().MaterialExportSize.ToIntSize();
|
||||
|
||||
string texturesPath = TrembleConsts.BASE_MATERIALS_PATH;
|
||||
foreach (string dir in Directory.GetDirectories(texturesPath))
|
||||
{
|
||||
string[] pngFiles = Directory.GetFiles(dir, "*.png");
|
||||
if (pngFiles.Length == 0)
|
||||
continue;
|
||||
|
||||
List<Texture> textures = new(pngFiles.Length);
|
||||
|
||||
foreach (string textureFile in pngFiles)
|
||||
{
|
||||
byte[] textureBytes = File.ReadAllBytes(textureFile);
|
||||
|
||||
Texture2D texture = new(texSize, texSize);
|
||||
texture.name = Path.GetFileNameWithoutExtension(textureFile);
|
||||
texture.LoadImage(textureBytes);
|
||||
|
||||
textures.Add(texture);
|
||||
}
|
||||
|
||||
m_Textures[Path.GetFileName(dir)] = textures;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDeInit()
|
||||
{
|
||||
foreach (List<Texture> textures in m_Textures.Values)
|
||||
{
|
||||
foreach (Texture texture in textures)
|
||||
{
|
||||
Texture.DestroyImmediate(texture);
|
||||
}
|
||||
}
|
||||
|
||||
m_Textures.Clear();
|
||||
}
|
||||
|
||||
protected override void OnGUI()
|
||||
{
|
||||
float thumbnailSize = 64f * ManualStyles.Scale;
|
||||
float labelSize = thumbnailSize + 40f * ManualStyles.Scale;
|
||||
int numWide = Mathf.Max(1, Mathf.FloorToInt(PageWidth / labelSize) - 2);
|
||||
|
||||
foreach (string textureFolder in m_Textures.Keys)
|
||||
{
|
||||
H1(textureFolder);
|
||||
{
|
||||
int cell = 0;
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
foreach (Texture texture in m_Textures[textureFolder])
|
||||
{
|
||||
GUILayout.BeginVertical();
|
||||
{
|
||||
GUILayout.BeginHorizontal(GUILayout.Width(labelSize));
|
||||
{
|
||||
GUILayout.Space((labelSize - thumbnailSize) / 2f);
|
||||
GUIContent content = new(texture, texture.name);
|
||||
GUILayout.Box(content, GUILayout.Width(thumbnailSize), GUILayout.Height(thumbnailSize));
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Label(texture.name, ManualStyles.Styles.CenteredGreyMiniLabel, GUILayout.Width(labelSize));
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
|
||||
// New row?
|
||||
if (++cell >= numWide)
|
||||
{
|
||||
cell = 0;
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.Space(1f);
|
||||
GUILayout.BeginHorizontal();
|
||||
}
|
||||
}
|
||||
|
||||
if (cell <= numWide)
|
||||
{
|
||||
GUILayout.FlexibleSpace();
|
||||
}
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d1d737f97a4f45c193f15ac0551af98e
|
||||
timeCreated: 1726390246
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/Debug/DebugShowMaterialsPage.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: efd666aa9a5c4579a55f666673349d69
|
||||
timeCreated: 1723201715
|
||||
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// 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("Entities/Brush Entities")]
|
||||
public class BrushEntitiesPage : ManualPageBase
|
||||
{
|
||||
protected override void OnGUI()
|
||||
{
|
||||
Text(
|
||||
"Brush Entities are brushes (models/shapes) in the map, which you want to apply a",
|
||||
"MonoBehaviour script to. For example, a moving platform whose shape you design in",
|
||||
"your TrenchBroom. Or, a trigger box which kills players on entry (see below).");
|
||||
|
||||
Image("T_Manual_BrushEntity");
|
||||
|
||||
Text("The following properties are available:");
|
||||
|
||||
PropertyDescription("name",
|
||||
"The name of the entity in TrenchBroom.",
|
||||
"If omitted, we convert your MonoBehaviour name according to your Naming Convention in settings."
|
||||
);
|
||||
|
||||
PropertyDescription("category",
|
||||
"The menu category to show the entity under, for example 'solid'.",
|
||||
$"If omitted, we use the default prefix, '{FgdConsts.BRUSH_PREFIX}'."
|
||||
);
|
||||
|
||||
PropertyDescription("type",
|
||||
"Which brush type to use, which defines how the brush appears and how its collision",
|
||||
"functions."
|
||||
);
|
||||
|
||||
Foldout("Available Brush Types", () =>
|
||||
{
|
||||
PropertyDescription("Solid",
|
||||
"A Solid brush with a texture.",
|
||||
"Example: a moving platform.");
|
||||
PropertyDescription("Liquid",
|
||||
"A brush with a texture, but with a trigger collision instead of a solid one.",
|
||||
"Example: a volume of water/lava, which damages players when entering.");
|
||||
PropertyDescription("Trigger",
|
||||
"A completely invisible brush which has a trigger collision.",
|
||||
"Example: a volume which triggers an event when players walk into the area.");
|
||||
PropertyDescription("Invisible",
|
||||
"A completely invisible brush which has solid collision.",
|
||||
"Example: an invisible wall to stop players going out of bounds.");
|
||||
});
|
||||
|
||||
H1("Brush Entity Wizard");
|
||||
Text(
|
||||
"Tremble can guide you through creating the correct attribute code for your entity,",
|
||||
"to help you get up and running quickly."
|
||||
);
|
||||
|
||||
ActionBar_SingleAction("Build Brush Entity", () => GoToPage(typeof(BrushBuilderPage)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 468269cf35e449789a6062b8bcf8066f
|
||||
timeCreated: 1723201757
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/Entities/BrushEntitiesPage.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,94 @@
|
||||
//
|
||||
// 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.Eventing.Reader;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
public abstract class BuilderPageBase<TDataClass> : ManualPageBase
|
||||
where TDataClass : ScriptableObject
|
||||
{
|
||||
private TDataClass m_Sample;
|
||||
private SerializedObject m_SampleSO;
|
||||
private TrembleSyncSettings m_SyncSettings;
|
||||
|
||||
protected virtual bool HasInitialQuestions { get; } = false;
|
||||
|
||||
private bool m_DoneInitialQuestions = false;
|
||||
|
||||
protected TDataClass Sample => m_Sample;
|
||||
protected SerializedObject SampleSO => m_SampleSO;
|
||||
protected TrembleSyncSettings SyncSettings => m_SyncSettings;
|
||||
|
||||
protected override void OnInit()
|
||||
{
|
||||
m_Sample = ScriptableObject.CreateInstance<TDataClass>();
|
||||
m_SampleSO = new(m_Sample);
|
||||
|
||||
m_SyncSettings = TrembleSyncSettings.Get();
|
||||
}
|
||||
|
||||
protected sealed override void OnGUI()
|
||||
{
|
||||
if (HasInitialQuestions && !m_DoneInitialQuestions)
|
||||
{
|
||||
OnInitialQuestionsGUI();
|
||||
return;
|
||||
}
|
||||
|
||||
OnPrePropertiesGUI();
|
||||
m_SampleSO.Update();
|
||||
{
|
||||
OnPropertiesGUI();
|
||||
}
|
||||
m_SampleSO.ApplyModifiedPropertiesWithoutUndo();
|
||||
OnPostPropertiesGUI();
|
||||
}
|
||||
|
||||
protected virtual void OnInitialQuestionsGUI() { }
|
||||
protected virtual void OnPrePropertiesGUI() { }
|
||||
protected virtual void OnPropertiesGUI() { }
|
||||
protected virtual void OnPostPropertiesGUI() { }
|
||||
|
||||
protected void MarkInitialQuestionsDone() => m_DoneInitialQuestions = true;
|
||||
|
||||
protected bool RenderProperty(string propName, string title, string description, Type objectReferenceType = null, Action extraContent = null)
|
||||
{
|
||||
SerializedProperty prop = m_SampleSO.FindProperty(propName);
|
||||
uint hash = prop.GetHashOfContent();
|
||||
|
||||
GUILayout.BeginVertical(EditorStyles.helpBox);
|
||||
{
|
||||
if (prop.propertyType == SerializedPropertyType.ObjectReference)
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
EditorGUILayout.PrefixLabel(new GUIContent(title));
|
||||
prop.objectReferenceValue = EditorGUILayout.ObjectField(prop.objectReferenceValue, objectReferenceType ?? typeof(GameObject), allowSceneObjects: false);
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
|
||||
m_SampleSO.ApplyModifiedProperties();
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.PropertyField(prop, new GUIContent(title));
|
||||
}
|
||||
|
||||
GUILayout.Label(description, ManualStyles.Styles.Text);
|
||||
|
||||
extraContent?.Invoke();
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
|
||||
GUILayout.Space(5f);
|
||||
|
||||
return hash != prop.GetHashOfContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 41ce3b3d48ed40cbbf56dd2e637d5e9e
|
||||
timeCreated: 1723225850
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/Entities/BuilderPageBase.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f14b29b54b344b7b0aa40f206a78b41
|
||||
timeCreated: 1723226299
|
||||
@@ -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;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
[ManualPage("Entities/Brush Entity Builder", showInTree: false)]
|
||||
public class BrushBuilderPage : BuilderPageBase<BrushBuilderPage.SampleData>
|
||||
{
|
||||
public class SampleData : ScriptableObject
|
||||
{
|
||||
[SerializeField] internal string m_UnityName = "MyCoolBrush";
|
||||
[SerializeField] internal string m_MapName = "";
|
||||
[SerializeField] internal string m_Category = "";
|
||||
[SerializeField] internal BrushType m_Type = BrushType.Solid;
|
||||
}
|
||||
|
||||
protected override void OnPropertiesGUI()
|
||||
{
|
||||
RenderProperty(nameof(SampleData.m_UnityName),
|
||||
title: "MonoBehaviour Name",
|
||||
description: "The name of the main MonoBehaviour script for your brush entity.");
|
||||
|
||||
RenderProperty(nameof(SampleData.m_MapName),
|
||||
title: "TrenchBroom name",
|
||||
description: "(optional) The entity name to use in TrenchBroom. Leave this blank to use the default.");
|
||||
|
||||
RenderProperty(nameof(SampleData.m_Category),
|
||||
title: "Category Name",
|
||||
description: "(optional) The category/group name to use in TrenchBroom. Leave this blank to use the default.");
|
||||
|
||||
RenderProperty(nameof(SampleData.m_Type),
|
||||
title: "Brush Type",
|
||||
description: "The brush type to use. Defaults to 'Solid'.",
|
||||
extraContent: () =>
|
||||
{
|
||||
Foldout("Available Brush Types", () =>
|
||||
{
|
||||
PropertyDescription("Solid",
|
||||
"A Solid brush with a texture.",
|
||||
"Example: a moving platform.");
|
||||
PropertyDescription("Liquid",
|
||||
"A brush with a texture, but with a trigger collision instead of a solid one.",
|
||||
"Example: a volume of water/lava, which damages players when entering.");
|
||||
PropertyDescription("Trigger",
|
||||
"A completely invisible brush which has a trigger collision.",
|
||||
"Example: a volume which triggers an event when players walk into the area.");
|
||||
PropertyDescription("Invisible",
|
||||
"A completely invisible brush which has solid collision.",
|
||||
"Example: an invisible wall to stop players going out of bounds.");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
protected override void OnPostPropertiesGUI()
|
||||
{
|
||||
List<string> attributeParts = new(16);
|
||||
|
||||
if (!Sample.m_MapName.IsNullOrEmpty())
|
||||
{
|
||||
attributeParts.Add($"\"{Sample.m_MapName}\"");
|
||||
}
|
||||
|
||||
if (!Sample.m_Category.IsNullOrEmpty())
|
||||
{
|
||||
attributeParts.Add($"category: \"{Sample.m_Category}\"");
|
||||
}
|
||||
|
||||
if (Sample.m_Type != BrushType.Solid)
|
||||
{
|
||||
attributeParts.Add($"type: {nameof(BrushType)}.{Sample.m_Type}");
|
||||
}
|
||||
|
||||
string attrName = FormatAttributeName(typeof(BrushEntityAttribute));
|
||||
string attributeLine = attributeParts.Count == 0
|
||||
? $"[{attrName}]"
|
||||
: $"[{attrName}({String.Join(", ", attributeParts)})]";
|
||||
|
||||
string unityName = Sample.m_UnityName.IsNullOrEmpty()
|
||||
? "<error>"
|
||||
: Sample.m_UnityName;
|
||||
|
||||
string catName = Sample.m_Category.IsNullOrEmpty() ? FgdConsts.BRUSH_PREFIX : Sample.m_Category;
|
||||
string entName = Sample.m_MapName.IsNullOrEmpty() ? Sample.m_UnityName.ToNamingConvention(SyncSettings.TypeNamingConvention) : Sample.m_MapName;
|
||||
|
||||
HorizontalLine();
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
GUILayout.BeginVertical();
|
||||
{
|
||||
H3("Create New Entity");
|
||||
|
||||
string code =
|
||||
"// Generated by Tremble v1.7.0\n" +
|
||||
$"// Brush entity '{catName}_{entName}'\n" +
|
||||
"\n" +
|
||||
"using UnityEngine;\n" +
|
||||
$"using {nameof(TinyGoose)}.{nameof(Tremble)};\n" +
|
||||
"\n" +
|
||||
attributeLine + "\n" +
|
||||
$"public class {unityName} : MonoBehaviour\n" +
|
||||
"{\n" +
|
||||
" // Your cool class here ;)\n" +
|
||||
"}";
|
||||
|
||||
CodeWithHeaderNoCopy($"Full source for {unityName}.cs", code);
|
||||
|
||||
ActionBar_SingleAction("Save to new MonoBehaviour class", () =>
|
||||
{
|
||||
string assetsFolder = Path.Combine(Directory.GetCurrentDirectory(), "Assets");
|
||||
|
||||
string filename = EditorUtility.SaveFilePanel($"Choose where to save {unityName}", assetsFolder, $"{unityName}.cs", "cs");
|
||||
if (!filename.IsNullOrEmpty())
|
||||
{
|
||||
File.WriteAllText(filename, code);
|
||||
EditorCompileUtil.CompileThen(typeof(BrushBuilderPage), nameof(OnPostCompile));
|
||||
}
|
||||
});
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
|
||||
GUILayout.Label("-or-", EditorStyles.centeredGreyMiniLabel, GUILayout.ExpandHeight(true));
|
||||
|
||||
GUILayout.BeginVertical();
|
||||
{
|
||||
H3("Add to existing MonoBehaviour");
|
||||
CodeWithHeaderNoCopy("Attribute line only (for existing MonoBehaviour)", attributeLine);
|
||||
ActionBar_SingleAction("Copy to clipboard", () => EditorGUIUtility.systemCopyBuffer = attributeLine);
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
private static void OnPostCompile()
|
||||
{
|
||||
string message = TrenchBroomUtil.IsTrenchBroomRunning
|
||||
? "Be sure to press F6 in TrenchBroom to reload entity definitions, so that your new entity appears!"
|
||||
: "All done!";
|
||||
EditorUtility.DisplayDialog("MonoBehaviour created!", message, "Great!");
|
||||
|
||||
ManualWindow mw = EditorWindow.GetWindow<ManualWindow>();
|
||||
if (mw)
|
||||
{
|
||||
mw.GoToPage(typeof(BrushEntitiesPage));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a19bc95fc7d74231b15345de8d617a86
|
||||
timeCreated: 1723368005
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/Entities/Builders/BrushBuilderPage.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,163 @@
|
||||
//
|
||||
// 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
|
||||
{
|
||||
[ManualPage("Entities/Point Entity Builder", showInTree: false)]
|
||||
public class PointBuilderPage : BuilderPageBase<PointBuilderPage.SampleData>
|
||||
{
|
||||
public class SampleData : ScriptableObject
|
||||
{
|
||||
[SerializeField] internal string m_UnityName = "MyCoolPoint";
|
||||
[SerializeField] internal string m_MapName = "";
|
||||
[SerializeField] internal string m_Category = "";
|
||||
[SerializeField] internal Color m_Colour = Color.white;
|
||||
[SerializeField] internal float m_Size = 0.25f;
|
||||
[SerializeField] internal Texture2D m_Sprite;
|
||||
}
|
||||
|
||||
protected override void OnPropertiesGUI()
|
||||
{
|
||||
RenderProperty(nameof(SampleData.m_UnityName),
|
||||
title: "MonoBehaviour Name",
|
||||
description: "The name of the main MonoBehaviour script of your point entity.");
|
||||
|
||||
RenderProperty(nameof(SampleData.m_MapName),
|
||||
title: "TrenchBroom name",
|
||||
description: "(optional) The entity name to use in TrenchBroom. Leave this blank to use the default.");
|
||||
|
||||
RenderProperty(nameof(SampleData.m_Category),
|
||||
title: "Category Name",
|
||||
description: "(optional) The category/group name to use in TrenchBroom. Leave this blank to use the default.");
|
||||
|
||||
RenderProperty(nameof(SampleData.m_Colour),
|
||||
title: "Preview Colour",
|
||||
description: "The colour of preview cube to represent this Point entity in TrenchBroom.");
|
||||
|
||||
RenderProperty(nameof(SampleData.m_Size),
|
||||
title: "Preview Size",
|
||||
description: "The size of preview cube to represent this Point entity in TrenchBroom.");
|
||||
|
||||
RenderProperty(nameof(SampleData.m_Sprite),
|
||||
title: "Preview Sprite",
|
||||
description: "(optional) A sprite to use to represent this Point entity in TrenchBroom.",
|
||||
objectReferenceType: typeof(Texture2D));
|
||||
}
|
||||
|
||||
protected override void OnPostPropertiesGUI()
|
||||
{
|
||||
List<string> attributeParts = new(16);
|
||||
|
||||
if (!Sample.m_MapName.IsNullOrEmpty())
|
||||
{
|
||||
attributeParts.Add($"\"{Sample.m_MapName}\"");
|
||||
}
|
||||
|
||||
if (!Sample.m_Category.IsNullOrEmpty())
|
||||
{
|
||||
attributeParts.Add($"category: \"{Sample.m_Category}\"");
|
||||
}
|
||||
|
||||
if (Sample.m_Sprite)
|
||||
{
|
||||
attributeParts.Add($"sprite: \"{Sample.m_Sprite.name}\"");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Sample.m_Colour != Color.white)
|
||||
{
|
||||
attributeParts.Add($"colour: \"{Sample.m_Colour.ToStringInvariant()}\"");
|
||||
}
|
||||
|
||||
if (Sample.m_Size != 0.25f)
|
||||
{
|
||||
attributeParts.Add($"size: {Sample.m_Size}");
|
||||
}
|
||||
}
|
||||
|
||||
string attrName = FormatAttributeName(typeof(PointEntityAttribute));
|
||||
|
||||
string attributeLine = attributeParts.Count == 0
|
||||
? $"[{attrName}]"
|
||||
: $"[{attrName}({String.Join(", ", attributeParts)})]";
|
||||
|
||||
string unityName = Sample.m_UnityName.IsNullOrEmpty()
|
||||
? "<error>"
|
||||
: Sample.m_UnityName;
|
||||
|
||||
string catName = Sample.m_Category.IsNullOrEmpty() ? FgdConsts.POINT_PREFIX : Sample.m_Category;
|
||||
string entName = Sample.m_MapName.IsNullOrEmpty() ? Sample.m_UnityName.ToNamingConvention(SyncSettings.TypeNamingConvention) : Sample.m_MapName;
|
||||
HorizontalLine();
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
GUILayout.BeginVertical();
|
||||
{
|
||||
H3("Create New Entity");
|
||||
|
||||
string code =
|
||||
"// Generated by Tremble v1.7.0\n" +
|
||||
$"// Point entity '{catName}_{entName}'\n" +
|
||||
"\n" +
|
||||
"using UnityEngine;\n" +
|
||||
$"using {nameof(TinyGoose)}.{nameof(Tremble)};\n" +
|
||||
"\n" +
|
||||
attributeLine + "\n" +
|
||||
$"public class {unityName} : MonoBehaviour\n" +
|
||||
"{\n" +
|
||||
" // Your cool class here ;)\n" +
|
||||
"}";
|
||||
|
||||
CodeWithHeaderNoCopy($"Full source for {unityName}.cs", code);
|
||||
|
||||
ActionBar_SingleAction("Save to new MonoBehaviour class", () =>
|
||||
{
|
||||
string assetsFolder = Path.Combine(Directory.GetCurrentDirectory(), "Assets");
|
||||
|
||||
string filename = EditorUtility.SaveFilePanel($"Choose where to save {unityName}", assetsFolder, $"{unityName}.cs", "cs");
|
||||
if (!filename.IsNullOrEmpty())
|
||||
{
|
||||
File.WriteAllText(filename, code);
|
||||
EditorCompileUtil.CompileThen(typeof(PointBuilderPage), nameof(OnPostCompile));
|
||||
}
|
||||
});
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
|
||||
GUILayout.Label("-or-", EditorStyles.centeredGreyMiniLabel, GUILayout.ExpandHeight(true));
|
||||
|
||||
GUILayout.BeginVertical();
|
||||
{
|
||||
H3("Add to existing MonoBehaviour");
|
||||
CodeWithHeaderNoCopy("Attribute line only (for existing MonoBehaviour)", attributeLine);
|
||||
ActionBar_SingleAction("Copy to clipboard", () => EditorGUIUtility.systemCopyBuffer = attributeLine);
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
private static void OnPostCompile()
|
||||
{
|
||||
string message = TrenchBroomUtil.IsTrenchBroomRunning
|
||||
? "Be sure to press F6 in TrenchBroom to reload entity definitions, so that your new entity appears!"
|
||||
: "All done!";
|
||||
EditorUtility.DisplayDialog("MonoBehaviour created!", message, "Great!");
|
||||
|
||||
ManualWindow mw = EditorWindow.GetWindow<ManualWindow>();
|
||||
if (mw)
|
||||
{
|
||||
mw.GoToPage(typeof(PointEntitiesPage));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d7c600b3e6a34d8a86cdaab529cef411
|
||||
timeCreated: 1723368625
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/Entities/Builders/PointBuilderPage.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,592 @@
|
||||
//
|
||||
// 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
|
||||
{
|
||||
[ManualPage("Entities/Prefab Entity Builder", showInTree: false)]
|
||||
public class PrefabBuilderPage : BuilderPageBase<PrefabBuilderPage.SampleData>
|
||||
{
|
||||
private static readonly Dictionary<Type, string> s_ScriptFileLookup = new();
|
||||
|
||||
protected override bool HasInitialQuestions => true;
|
||||
|
||||
private bool m_MonoBehaviourListDirty = false;
|
||||
private readonly List<Type> m_CandidateTypes = new();
|
||||
|
||||
private readonly TrembleFieldConverterCollection m_FieldConverterCollection = new();
|
||||
|
||||
private Type m_UnityScriptType;
|
||||
private string m_NewUnityScriptName;
|
||||
private Action m_ResolutionAction;
|
||||
|
||||
private bool m_IsOnlyAddingSpawnablePrefab = false;
|
||||
|
||||
private bool m_IsAlreadyTrembleSpawnable = false;
|
||||
private bool m_IsAlreadyPrefabEntity = false;
|
||||
private bool m_IsMap = false;
|
||||
|
||||
private bool IsNewScript => !m_NewUnityScriptName.IsNullOrEmpty();
|
||||
private string ScriptName => m_UnityScriptType?.Name ?? m_NewUnityScriptName;
|
||||
|
||||
public class SampleData : ScriptableObject
|
||||
{
|
||||
[SerializeField] internal GameObject m_BasePrefab;
|
||||
[SerializeField] internal bool m_WantsData;
|
||||
|
||||
[SerializeField] internal string m_Category = "";
|
||||
[SerializeField] internal GameObject[] m_ExcludedPrefabs = Array.Empty<GameObject>();
|
||||
[SerializeField] internal GameObject[] m_IncludedPrefabs = Array.Empty<GameObject>();
|
||||
[SerializeField] internal bool m_OnlyVariants = false;
|
||||
}
|
||||
|
||||
protected override void OnInitialQuestionsGUI()
|
||||
{
|
||||
Text("Please select a prefab that you want to use in Tremble!");
|
||||
|
||||
m_MonoBehaviourListDirty = RenderProperty(nameof(SampleData.m_BasePrefab),
|
||||
title: "Target Prefab",
|
||||
description: "The prefab to use");
|
||||
|
||||
RenderProperty(nameof(SampleData.m_WantsData),
|
||||
title: "I want to add data",
|
||||
description: "Whether to allow setting fields on the prefab from TrenchBroom. e.g. "+
|
||||
"variables such as Health, Colour, etc?");
|
||||
|
||||
if (Sample.m_BasePrefab)
|
||||
{
|
||||
if (m_MonoBehaviourListDirty)
|
||||
{
|
||||
Type[] monoBehaviours = Sample.m_BasePrefab
|
||||
.GetComponents<MonoBehaviour>()
|
||||
.Select(m => m.GetType())
|
||||
.ToArray();
|
||||
|
||||
m_CandidateTypes.Clear();
|
||||
m_CandidateTypes.AddRange(monoBehaviours
|
||||
.Where(t => t != typeof(TrembleSpawnablePrefab)));
|
||||
|
||||
m_IsAlreadyTrembleSpawnable = monoBehaviours.Contains(typeof(TrembleSpawnablePrefab));
|
||||
m_IsMap = monoBehaviours.Contains(typeof(MapDocument));
|
||||
m_IsAlreadyPrefabEntity = !m_IsAlreadyTrembleSpawnable && monoBehaviours.Any(t => t.HasCustomAttribute<PrefabEntityAttribute>());
|
||||
}
|
||||
|
||||
if (m_IsMap)
|
||||
{
|
||||
Text("Ha! No, that's a map prefab. We better not.");
|
||||
}
|
||||
else if (m_IsAlreadyPrefabEntity)
|
||||
{
|
||||
Text("Well, that's already spawnable in TrenchBroom. Try another prefab!");
|
||||
}
|
||||
else if (m_CandidateTypes.Count == 0)
|
||||
{
|
||||
if (m_IsAlreadyTrembleSpawnable)
|
||||
{
|
||||
Callout("Note, this prefab already has a TrembleSpawnablePrefab component",
|
||||
"allowing it to be spawned from TrenchBroom - but without field support.",
|
||||
"Converting this to a PrefabEntity will remove the TrembleSpawnablePrefab component!");
|
||||
}
|
||||
|
||||
if (m_IsAlreadyTrembleSpawnable)
|
||||
{
|
||||
if (Sample.m_WantsData)
|
||||
{
|
||||
Resolution("Create a new MonoBehaviour to use - this allows",
|
||||
"you to add fields which can be set in TrenchBroom",
|
||||
"- in order to be able to set data (i.e. Health, Type, etc).");
|
||||
ActionBar_SingleAction("Create New MonoBehaviour", () =>
|
||||
{
|
||||
m_NewUnityScriptName = GetScriptNameFromPrefab(Sample.m_BasePrefab);
|
||||
|
||||
if (Sample.m_BasePrefab.TryGetComponent(out TrembleSpawnablePrefab tsp))
|
||||
{
|
||||
Sample.m_Category = tsp.Category;
|
||||
Sample.m_OnlyVariants = tsp.OnlyVariants;
|
||||
}
|
||||
|
||||
SetResolution(Resolve_CreateNewClassAndAdd);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Text("Well, that's already spawnable in TrenchBroom. Tick the box above",
|
||||
"to add data using a [PrefabEntity].");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Sample.m_WantsData)
|
||||
{
|
||||
Resolution("Create a new MonoBehaviour to use - this allows",
|
||||
"you to add fields which can be set in TrenchBroom",
|
||||
"- in order to be able to set data (i.e. Health, Type, etc).");
|
||||
ActionBar_SingleAction("Create New MonoBehaviour", () =>
|
||||
{
|
||||
m_NewUnityScriptName = GetScriptNameFromPrefab(Sample.m_BasePrefab);
|
||||
|
||||
if (Sample.m_BasePrefab.TryGetComponent(out TrembleSpawnablePrefab tsp))
|
||||
{
|
||||
Sample.m_Category = tsp.Category;
|
||||
Sample.m_OnlyVariants = tsp.OnlyVariants;
|
||||
}
|
||||
|
||||
SetResolution(Resolve_CreateNewClassAndAdd);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Resolution("Add a 'TrembleSpawnablePrefab' component - this",
|
||||
"only allows you to spawn this prefab without being able to",
|
||||
"set any data on it.");
|
||||
|
||||
ActionBar_SingleAction("Add TrembleSpawnablePrefab component", () =>
|
||||
{
|
||||
m_IsOnlyAddingSpawnablePrefab = true;
|
||||
SetResolution(Resolve_AddTrembleSpawnablePrefab);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_IsAlreadyTrembleSpawnable)
|
||||
{
|
||||
// Already spawnable, but no candidates for [PrefabEntity] - make a new code class
|
||||
if (Sample.m_WantsData)
|
||||
{
|
||||
Resolution("Upgrade to a [PrefabEntity] - this allows",
|
||||
"you to add fields which can be set in TrenchBroom",
|
||||
"- in order to be able to set data (i.e. Health, Type, etc).");
|
||||
|
||||
foreach (Type type in m_CandidateTypes)
|
||||
{
|
||||
Bullet(type.Name);
|
||||
ActionBar_SingleAction($"Add [PrefabEntity] to {type.Name}", () =>
|
||||
{
|
||||
m_UnityScriptType = type;
|
||||
|
||||
if (Sample.m_BasePrefab.TryGetComponent(out TrembleSpawnablePrefab tsp))
|
||||
{
|
||||
Sample.m_Category = tsp.Category;
|
||||
Sample.m_OnlyVariants = tsp.OnlyVariants;
|
||||
}
|
||||
|
||||
SetResolution(Resolve_AddPrefabEntityAttribute);
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Text("This is already a TrembleSpawnablePrefab. Unless you want to add data,",
|
||||
"you don't need to do anything!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Sample.m_WantsData)
|
||||
{
|
||||
if (m_CandidateTypes.Count == 1)
|
||||
{
|
||||
Type type = m_CandidateTypes[0];
|
||||
|
||||
Resolution($"You can add a [PrefabEntity] attribute to {type.Name} on this",
|
||||
"prefab. This will enable setting the following fields:");
|
||||
|
||||
Indent(() =>
|
||||
{
|
||||
foreach (string fieldName in GetFieldNames(type))
|
||||
{
|
||||
Bullet(fieldName);
|
||||
}
|
||||
});
|
||||
|
||||
ActionBar_SingleAction($"Add [PrefabEntity]", () =>
|
||||
{
|
||||
m_UnityScriptType = type;
|
||||
SetResolution(Resolve_AddPrefabEntityAttribute);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Resolution("This prefab has MonoBehaviours which can be set to be a",
|
||||
"[PrefabEntity]. Select which one to add this attribute to.");
|
||||
|
||||
foreach (Type type in m_CandidateTypes)
|
||||
{
|
||||
string[] fieldNames = GetFieldNames(type);
|
||||
|
||||
string fields = (fieldNames is { Length: > 0 }) ? String.Join(", ", fieldNames) : "no fields";
|
||||
Bullet($"{type.Name} ({fields})");
|
||||
|
||||
ActionBar_SingleAction($"Add [PrefabEntity] to {type.Name}", () =>
|
||||
{
|
||||
m_UnityScriptType = type;
|
||||
SetResolution(Resolve_AddPrefabEntityAttribute);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Resolution("Simply add a TrembleSpawnablePrefab component to it, which will",
|
||||
"allow you to spawn the prefab in TrenchBroom, but not allow you to set any",
|
||||
"data on it.");
|
||||
ActionBar_SingleAction("Add TrembleSpawnablePrefab component", () =>
|
||||
{
|
||||
m_IsOnlyAddingSpawnablePrefab = true;
|
||||
SetResolution(Resolve_AddTrembleSpawnablePrefab);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string[] GetFieldNames(Type type)
|
||||
{
|
||||
List<Type> soTypes= new();
|
||||
FgdClass dummyClass = new(FgdClassType.Point, type.Name, type.Name);
|
||||
TrembleSync.AddExposedFieldsToEntity(type, dummyClass, m_FieldConverterCollection, soTypes);
|
||||
|
||||
// Gather spawnflags
|
||||
NamingConvention spawnFlagNaming = TrembleSyncSettings.Get().SpawnFlagNamingConvention;
|
||||
|
||||
IEnumerable<string> spawnFlagNames = dummyClass.AllSpawnFlags
|
||||
.Select(f =>
|
||||
{
|
||||
string name = f.FieldName.ToNamingConvention(spawnFlagNaming);
|
||||
if (spawnFlagNaming == NamingConvention.HumanFriendly)
|
||||
{
|
||||
name += "?";
|
||||
}
|
||||
|
||||
return $"{name} (Boolean)";
|
||||
});
|
||||
|
||||
return dummyClass.AllFields
|
||||
.Select(f => $"{f.FieldName} ({f.FriendlyTypeName})")
|
||||
.Concat(spawnFlagNames)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
protected override void OnPropertiesGUI()
|
||||
{
|
||||
H2("Optional Extras");
|
||||
|
||||
RenderProperty(nameof(SampleData.m_Category),
|
||||
title: "Category Name",
|
||||
description: "(optional) The category/group name to use in TrenchBroom. Leave this blank to use the default.");
|
||||
|
||||
Foldout("(optional) Include/Exclude specific Prefabs?", () =>
|
||||
{
|
||||
if (!m_IsOnlyAddingSpawnablePrefab)
|
||||
{
|
||||
Text("By default, any other prefabs containing your MonoBehaviour will be exported.");
|
||||
Text("Instead, you can choose to explicitly whitelist prefab(s) here.");
|
||||
Text("Or, you can choose to blacklist certain prefab(s) here.");
|
||||
|
||||
RenderProperty(nameof(SampleData.m_IncludedPrefabs),
|
||||
title: "Included Prefabs",
|
||||
description: $"A whitelist of the ONLY prefab(s) to include, even though others may include your {ScriptName} MonoBehaviour?");
|
||||
|
||||
RenderProperty(nameof(SampleData.m_ExcludedPrefabs),
|
||||
title: "Excluded Prefabs",
|
||||
description: $"A blacklist of any prefab(s) to ignore, even though they include your {ScriptName} MonoBehaviour?");
|
||||
}
|
||||
|
||||
RenderProperty(nameof(SampleData.m_OnlyVariants),
|
||||
title: "Only Prefab Variants?",
|
||||
description: "Whether to only export VARIANTS of the prefab(s) found?");
|
||||
});
|
||||
}
|
||||
|
||||
protected override void OnPostPropertiesGUI()
|
||||
{
|
||||
string catName = Sample.m_Category.IsNullOrEmpty() ? FgdConsts.PREFAB_PREFIX : Sample.m_Category;
|
||||
//string entName = Sample.m_UnityName.ToNamingConvention(SyncSettings.TypeNamingConvention);
|
||||
string fullEntName = $"{catName}_{Sample.m_BasePrefab.name}";
|
||||
|
||||
if (m_IsOnlyAddingSpawnablePrefab)
|
||||
{
|
||||
H2("Tremble Spawnable Prefab Details");
|
||||
PropertyDescription("Prefab Name", labelWidth: 250f, Sample.m_BasePrefab.name);
|
||||
PropertyDescription("Exported TrenchBroom Name", labelWidth: 250f, fullEntName);
|
||||
}
|
||||
else
|
||||
{
|
||||
H2("C# Code");
|
||||
Text($"This is the code that will be used for {Sample.m_BasePrefab.name} if you click Apply below. You don't need to copy",
|
||||
"it manually (unless you want to!)");
|
||||
CodeWithHeader($"C# Script: {ScriptName}.cs (for TrenchBroom Prefab entity '{fullEntName}')", GenerateFullCodeSnippet());
|
||||
}
|
||||
|
||||
Space();
|
||||
|
||||
GUI.color = Color.green;
|
||||
LargeButton("Apply & Finish!", Resolve);
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
|
||||
private void Resolution(params string[] resolution)
|
||||
{
|
||||
HorizontalLine();
|
||||
|
||||
H1("Action to take");
|
||||
Text(resolution);
|
||||
}
|
||||
|
||||
private string GetAttributeLine()
|
||||
{
|
||||
List<string> attributeParts = new(16);
|
||||
|
||||
if (!Sample.m_Category.IsNullOrEmpty())
|
||||
{
|
||||
attributeParts.Add($"category: \"{Sample.m_Category}\"");
|
||||
}
|
||||
|
||||
if (TryFormatPrefabNames("excludePrefab", Sample.m_ExcludedPrefabs, out string excludePart))
|
||||
{
|
||||
attributeParts.Add(excludePart);
|
||||
}
|
||||
|
||||
if (TryFormatPrefabNames("includePrefab", Sample.m_IncludedPrefabs, out string includePart))
|
||||
{
|
||||
attributeParts.Add(includePart);
|
||||
}
|
||||
|
||||
if (Sample.m_OnlyVariants)
|
||||
{
|
||||
attributeParts.Add("onlyVariants: true");
|
||||
}
|
||||
|
||||
string attrName = FormatAttributeName(typeof(PrefabEntityAttribute));
|
||||
|
||||
return attributeParts.Count == 0
|
||||
? $"[{attrName}]"
|
||||
: $"[{attrName}({String.Join(", ", attributeParts)})]";
|
||||
}
|
||||
|
||||
private string GenerateFullCodeSnippet()
|
||||
{
|
||||
return
|
||||
"using UnityEngine;\n" +
|
||||
$"using {nameof(TinyGoose)}.{nameof(Tremble)};\n" +
|
||||
"\n" +
|
||||
GetAttributeLine() + "\n" +
|
||||
$"public class {ScriptName} : MonoBehaviour\n" +
|
||||
"{\n" +
|
||||
(IsNewScript ? $" // Your new {ScriptName} class contents ;)" : $" // (your existing {ScriptName} code)") + "\n" +
|
||||
"}";
|
||||
}
|
||||
|
||||
private bool TryFormatPrefabNames(string propertyName, GameObject[] prefabs, out string formatted)
|
||||
{
|
||||
GameObject[] filteredPrefabs = prefabs.Where(p => p).ToArray();
|
||||
|
||||
switch (filteredPrefabs.Length)
|
||||
{
|
||||
case 1:
|
||||
formatted = $"{propertyName}: \"{filteredPrefabs[0].name}\"";
|
||||
return true;
|
||||
case > 1:
|
||||
{
|
||||
string prefabList = String.Join("\", \"", filteredPrefabs.Select(p => p.name));
|
||||
formatted = $"{propertyName}s: \"{prefabList}\"";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
formatted = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void SetResolution(Action resolutionAction)
|
||||
{
|
||||
m_ResolutionAction = resolutionAction;
|
||||
MarkInitialQuestionsDone();
|
||||
}
|
||||
|
||||
private void Resolve()
|
||||
{
|
||||
m_ResolutionAction.Invoke();
|
||||
GoToPage(typeof(PrefabEntitiesPage));
|
||||
}
|
||||
|
||||
private void Resolve_AddTrembleSpawnablePrefab()
|
||||
{
|
||||
Sample.m_BasePrefab.AddComponent<TrembleSpawnablePrefab>().Modify(so =>
|
||||
{
|
||||
so.FindBackedProperty(nameof(TrembleSpawnablePrefab.OnlyVariants)).boolValue = Sample.m_OnlyVariants;
|
||||
so.FindBackedProperty(nameof(TrembleSpawnablePrefab.Category)).stringValue = Sample.m_Category;
|
||||
});
|
||||
|
||||
EditorUtility.SetDirty(Sample.m_BasePrefab);
|
||||
AssetDatabase.SaveAssets();
|
||||
|
||||
EditorApplication.delayCall += TrembleEditorAPI.SyncToTrenchBroom;
|
||||
|
||||
ShowCompleteDialog(
|
||||
title: "TrembleSpawnablePrefab component added!",
|
||||
message: $"{Sample.m_BasePrefab.name} now has a Tremble Spawnable Prefab component and should be available from TrenchBroom.");
|
||||
}
|
||||
|
||||
private void Resolve_CreateNewClassAndAdd()
|
||||
{
|
||||
// Write code and compile
|
||||
string assetsFolder = Path.Combine(Directory.GetCurrentDirectory(), "Assets");
|
||||
|
||||
string scriptFilePath = EditorUtility.SaveFilePanel($"Choose where to save {ScriptName}", assetsFolder, $"{ScriptName}.cs", "cs");
|
||||
if (scriptFilePath.IsNullOrEmpty())
|
||||
return;
|
||||
|
||||
File.WriteAllText(scriptFilePath, GenerateFullCodeSnippet());
|
||||
|
||||
EditorCompileUtil.CompileThen(typeof(PrefabBuilderPage), nameof(OnPostCompile_AddNewScript),
|
||||
ScriptName, AssetDatabase.GetAssetPath(Sample.m_BasePrefab));
|
||||
}
|
||||
|
||||
private void Resolve_AddPrefabEntityAttribute()
|
||||
{
|
||||
string scriptFileName = GetScriptFilename(m_UnityScriptType);
|
||||
if (scriptFileName.IsNullOrEmpty())
|
||||
{
|
||||
EditorUtility.DisplayDialog(
|
||||
title: "Uh-oh!",
|
||||
message: $"Tremble could not find the source file for {ScriptName}.",
|
||||
"Oh no!");
|
||||
return;
|
||||
}
|
||||
|
||||
bool prefabEntityWasAdded = false;
|
||||
bool usingWasAdded = false;
|
||||
|
||||
string[] lines = File.ReadAllLines(scriptFileName);
|
||||
List<string> outLines = new(lines.Length+2);
|
||||
foreach (string line in lines)
|
||||
{
|
||||
if (!usingWasAdded && !line.ContainsInvariant("using", caseSensitive: true))
|
||||
{
|
||||
outLines.Add("using TinyGoose.Tremble;");
|
||||
usingWasAdded = true;
|
||||
}
|
||||
|
||||
if (line.ContainsInvariant($"class {ScriptName}", caseSensitive: true))
|
||||
{
|
||||
prefabEntityWasAdded = true;
|
||||
outLines.Add($"\t{GetAttributeLine()}");
|
||||
}
|
||||
|
||||
outLines.Add(line);
|
||||
}
|
||||
|
||||
if (!prefabEntityWasAdded)
|
||||
{
|
||||
EditorUtility.DisplayDialog(
|
||||
title: "Uh-oh!",
|
||||
message: $"Tremble could not find the class {ScriptName} in the source file {Path.GetFileName(scriptFileName)}.",
|
||||
"Oh no!");
|
||||
return;
|
||||
}
|
||||
|
||||
File.WriteAllLines(scriptFileName, outLines);
|
||||
|
||||
EditorCompileUtil.CompileThen(typeof(PrefabBuilderPage), nameof(OnPostCompile_AddAttribute), ScriptName);
|
||||
}
|
||||
|
||||
private static string GetScriptNameFromPrefab(GameObject prefab)
|
||||
{
|
||||
string newName = prefab.name;
|
||||
if (newName.StartsWithInvariant("P_", caseSensitive: true))
|
||||
return newName.Substring(2);
|
||||
|
||||
StringBuilder finalName = new(newName.Length);
|
||||
foreach (char c in newName)
|
||||
{
|
||||
if (c is '-')
|
||||
{
|
||||
// Swap characters
|
||||
finalName.Append('_');
|
||||
}
|
||||
else if (c is ' ')
|
||||
{
|
||||
// Omit characters
|
||||
}
|
||||
else
|
||||
{
|
||||
// Allowed characters
|
||||
finalName.Append(c);
|
||||
}
|
||||
}
|
||||
|
||||
return finalName.ToString();
|
||||
}
|
||||
|
||||
private static string GetScriptFilename(Type monoBehaviourType)
|
||||
{
|
||||
if (s_ScriptFileLookup.TryGetValue(monoBehaviourType, out string existingPath))
|
||||
return existingPath;
|
||||
|
||||
foreach (string path in AssetDatabase.GetAllAssetPaths())
|
||||
{
|
||||
// Check if the file name matches exactly (without the full path)
|
||||
if (Path.GetFileNameWithoutExtension(path).EqualsInvariant(monoBehaviourType.Name))
|
||||
{
|
||||
s_ScriptFileLookup[monoBehaviourType] = path;
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void ShowCompleteDialog(string title, string message)
|
||||
{
|
||||
if (TrenchBroomUtil.IsTrenchBroomRunning)
|
||||
{
|
||||
message += "\n\n Note: Press F6 inside TrenchBroom to refresh Entity Definitions for it to appear!";
|
||||
}
|
||||
|
||||
EditorUtility.DisplayDialog(title, message, "Great!");
|
||||
}
|
||||
|
||||
private static void OnPostCompile_AddAttribute(string scriptName)
|
||||
{
|
||||
TrembleEditorAPI.SyncToTrenchBroom();
|
||||
|
||||
ShowCompleteDialog(
|
||||
title: "[PrefabEntity] attribute added!",
|
||||
message: $"{scriptName} now has a [PrefabEntity] attribute and should be available from TrenchBroom.");
|
||||
}
|
||||
|
||||
private static void OnPostCompile_AddNewScript(string scriptName, string prefabPath)
|
||||
{
|
||||
GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
|
||||
|
||||
Type newComponentType = Unsupported.GetTypeFromFullName(scriptName);
|
||||
prefab.AddComponent(newComponentType);
|
||||
|
||||
foreach (TrembleSpawnablePrefab tsp in prefab.GetComponents<TrembleSpawnablePrefab>())
|
||||
{
|
||||
Component.DestroyImmediate(tsp, true);
|
||||
}
|
||||
|
||||
EditorUtility.SetDirty(prefab);
|
||||
AssetDatabase.SaveAssets();
|
||||
|
||||
// Now sync
|
||||
EditorApplication.delayCall += TrembleEditorAPI.SyncToTrenchBroom;
|
||||
|
||||
// And tell the user!
|
||||
ShowCompleteDialog(
|
||||
title: "New Prefab Entity Created!",
|
||||
message: $"{scriptName}.cs was created and attached to {prefab.name}, and should be available from TrenchBroom.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 76e837b79b44474bb99e6e62f09d2af6
|
||||
timeCreated: 1723206660
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/Entities/Builders/PrefabBuilderPage.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// 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("Entities/Overview")]
|
||||
public class EntitiesOverviewPage : ManualPageBase
|
||||
{
|
||||
protected override void OnGUI()
|
||||
{
|
||||
Text(
|
||||
"Entities are used to place objects (for example prefabs, trigger volumes, etc.)",
|
||||
"into your map to make them more interactive."
|
||||
);
|
||||
|
||||
Text("Tremble supports 3 kinds of Entities:");
|
||||
|
||||
Space();
|
||||
|
||||
PropertyDescription("Prefab Entities",
|
||||
"These are 1:1 representations of your Unity prefabs, which can be dropped into a map.",
|
||||
$"You can either use a '{nameof(TrembleSpawnablePrefab)}' component in your prefab to allow it to",
|
||||
"be simply spawned from your map, or you can mark your scripts up with",
|
||||
$"'[{FormatAttributeName(typeof(PrefabEntityAttribute))}]' to synchronise properties and more!");
|
||||
ActionBar(() =>
|
||||
{
|
||||
Action("More about Spawnable Prefabs", () => GoToPage(typeof(SpawnablePrefabEntitiesPage)));
|
||||
Action("More about Prefab Entities", () => GoToPage(typeof(PrefabEntitiesPage)));
|
||||
});
|
||||
|
||||
Space();
|
||||
|
||||
PropertyDescription("Brush Entities",
|
||||
"These are brushes (shapes/meshes) in the map, which you want to apply a MonoBehaviour script to.",
|
||||
"These can be Solids - for example, a moving platform whose shape you design in TrenchBroom,",
|
||||
"Triggers - for example an area which triggers an event, and more!");
|
||||
ActionBar_SingleAction("More about Brush Entities", () => GoToPage(typeof(BrushEntitiesPage)));
|
||||
|
||||
Space();
|
||||
|
||||
PropertyDescription("Point Entities",
|
||||
"These are points in space which contain data - for example a target location for spawning enemies,",
|
||||
"or a goal location for a player to go to.");
|
||||
ActionBar_SingleAction("More about Point Entities", () => GoToPage(typeof(PointEntitiesPage)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 62b4b35600af4819baf0389a9252be03
|
||||
timeCreated: 1723278285
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/Entities/EntitiesOverviewPage.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,51 @@
|
||||
//
|
||||
// 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("Entities/Point Entities")]
|
||||
public class PointEntitiesPage : ManualPageBase
|
||||
{
|
||||
protected override void OnGUI()
|
||||
{
|
||||
Text(
|
||||
"Point Entities are points/positions in space in the map, which you want to apply a",
|
||||
"MonoBehaviour script to. They do not have a visual representation (mesh).",
|
||||
"For example, a target position that an enemy should move to. Or, a position in space",
|
||||
"in which to spawn the player (see below).");
|
||||
|
||||
Image("T_Manual_PointEntity");
|
||||
|
||||
Text("The following properties are available:");
|
||||
|
||||
PropertyDescription("name",
|
||||
"The name of the entity in TrenchBroom.",
|
||||
"If omitted, we convert your MonoBehaviour name according to your Naming Convention in settings."
|
||||
);
|
||||
|
||||
PropertyDescription("category",
|
||||
"The menu category to show the entity under, for example 'solid'.",
|
||||
$"If omitted, we use the default prefix, '{FgdConsts.BRUSH_PREFIX}'."
|
||||
);
|
||||
|
||||
PropertyDescription("colour, size",
|
||||
"Colour and Size define how to display this Point entity's preview cube in TrenchBroom."
|
||||
);
|
||||
|
||||
PropertyDescription("sprite",
|
||||
"(optional) A sprite to show, instead of a coloured cube for this Point entity in TrenchBroom.",
|
||||
"This should be the name of a texture in your project, e.g. 'T_MyTexture'."
|
||||
);
|
||||
|
||||
H1("Point Entity Wizard");
|
||||
Text(
|
||||
"Tremble can guide you through creating the correct attribute code for your entity,",
|
||||
"to help you get up and running quickly."
|
||||
);
|
||||
|
||||
ActionBar_SingleAction("Build Point Entity", () => GoToPage(typeof(PointBuilderPage)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d1a1a3ae162244f1819732c6cb04f4a8
|
||||
timeCreated: 1723201769
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/Entities/PointEntitiesPage.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5dbfda69803f4f39ac23255094985859
|
||||
timeCreated: 1723206454
|
||||
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// 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("Entities/Prefabs/Prefab Entities")]
|
||||
public class PrefabEntitiesPage : ManualPageBase
|
||||
{
|
||||
protected override void OnGUI()
|
||||
{
|
||||
Text(
|
||||
"Prefab Entities are 1:1 representations of your Unity prefabs, which can be dropped into a map.",
|
||||
$"All you have to do is mark up your scripts with '[{FormatAttributeName(typeof(PrefabEntityAttribute))}]' to synchronise properties and more!");
|
||||
|
||||
Image("T_Manual_PrefabEntity");
|
||||
|
||||
Text("The following properties are available:");
|
||||
|
||||
PropertyDescription("category",
|
||||
"The menu category to show the entity under, for example 'player'.",
|
||||
$"If omitted, we use the default prefix, '{FgdConsts.PREFAB_PREFIX}'."
|
||||
);
|
||||
|
||||
PropertyDescription("excludePrefab(s)",
|
||||
"Exclude prefabs with the given name. For example, if your",
|
||||
"script appears on multiple prefabs 'P_Coin' and 'P_CoinSpecial', and you only",
|
||||
" want to show 'P_Coin' in TrenchBroom, you can pass 'P_CoinSpecial' in here."
|
||||
);
|
||||
|
||||
PropertyDescription("includePrefab(s)",
|
||||
"Only include prefabs with the given name. For example, if your",
|
||||
"script appears on multiple prefabs 'P_Coin' and 'P_CoinSpecial', and you only",
|
||||
" want to show 'P_Coin' in TrenchBroom, you can pass 'P_Coin' in here."
|
||||
);
|
||||
|
||||
PropertyDescription("onlyVariants",
|
||||
"Only include variants of this prefab, not the base prefab itself.",
|
||||
"For example, imagine your game has a 'P_Sign' prefab, which is an empty signpost,",
|
||||
"but also has Prefab Variants 'P_Sign_Info' and 'P_Sign_QuestionMark' - ticking",
|
||||
"this box will export those variants but not the base 'P_Sign'."
|
||||
);
|
||||
|
||||
H1("Prefab Entity Wizard");
|
||||
Text(
|
||||
"Tremble can guide you through creating the correct attribute code for your entity,",
|
||||
"to help you get up and running quickly."
|
||||
);
|
||||
|
||||
ActionBar_SingleAction("Build Prefab Entity", () => GoToPage(typeof(PrefabBuilderPage)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fdcea6d257154068a23f70d1bdb72b0a
|
||||
timeCreated: 1723201724
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/Entities/Prefabs/PrefabEntitiesPage.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.
|
||||
//
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
[ManualPage("Entities/Prefabs/Spawnable Prefabs")]
|
||||
public class SpawnablePrefabEntitiesPage : ManualPageBase
|
||||
{
|
||||
protected override void OnGUI()
|
||||
{
|
||||
Text(
|
||||
"Spawnable Prefabs are a quick way to add a single script to ANY prefab in editor, to",
|
||||
"allow your prefab to be instantiated from TrenchBroom without any code changes.",
|
||||
"Note that this method does not allow you to set variables on those prefabs!"
|
||||
);
|
||||
|
||||
Image("T_Manual_SpawnablePrefab");
|
||||
|
||||
Text(
|
||||
$"Add a '{nameof(TrembleSpawnablePrefab)}' component to your prefab. This gives you the following",
|
||||
"options:"
|
||||
);
|
||||
|
||||
PropertyDescription("Category",
|
||||
"You can supply the 'Category' of prefab here, too - the menu category to",
|
||||
"show the entity under, for example 'player'. If omitted, we use the prefix defined in",
|
||||
"the settings (default: 'p')"
|
||||
);
|
||||
|
||||
PropertyDescription("Only Variants",
|
||||
"Only Variants: Tremble will ignore the base prefab and only export Prefab Variants of",
|
||||
"the prefab. See the above explanation about 'onlyVariants' for more information."
|
||||
);
|
||||
|
||||
ActionBar_SingleAction("Build Prefab Entity", () => GoToPage(typeof(PrefabBuilderPage)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7a0a012f06324a7e962feefd29e85628
|
||||
timeCreated: 1723206473
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/Entities/Prefabs/SpawnablePrefabsPage.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// 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("Map Repair")]
|
||||
public class MapRepairOverviewPage : ManualPageBase
|
||||
{
|
||||
protected override void OnGUI()
|
||||
{
|
||||
Text(
|
||||
"Sometimes, after renaming entities or materials, your map might import in a broken state,",
|
||||
"missing materials or functionality. In this case, you can right click the map in Unity,",
|
||||
"and select 'Repair Map' (or, go to Tools > Tremble > Repair Map)."
|
||||
);
|
||||
|
||||
Image("T_Manual_MapRepair");
|
||||
|
||||
ActionBar_SingleAction("Open Map Repair", MapRepairWindow.OpenMapRepair);
|
||||
|
||||
Callout("Note, that you should ensure TrenchBroom does not have your map open while it is repaired.");
|
||||
|
||||
H2("Other uses for map repair");
|
||||
Bullet(
|
||||
"Swap materials around, or reassign entities in the map wholesale - which can",
|
||||
"be far quicker than manually editing them."
|
||||
);
|
||||
Bullet(
|
||||
"Import maps from Quake®, or another game using .map files"
|
||||
);
|
||||
|
||||
ActionBar_SingleAction("Show me how to import maps from other games", () => GoToPage(typeof(MapRepairForeignPage)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 235e96de3d244c26bdf4c5c2e8b833dc
|
||||
timeCreated: 1723448743
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/MapRepairPage.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 966bf55c023a42aa9b1ee89f32290315
|
||||
timeCreated: 1724656265
|
||||
@@ -0,0 +1,138 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
[ManualPage("Materials/Material Groups")]
|
||||
public class MaterialGroupsPage : ManualPageBase
|
||||
{
|
||||
private TrembleSyncSettings m_SyncSettings;
|
||||
private MaterialGroup m_DefaultMaterialGroup;
|
||||
private Material[] m_UnexposedMaterials;
|
||||
|
||||
protected override void OnInit()
|
||||
{
|
||||
m_SyncSettings = TrembleSyncSettings.Get();
|
||||
|
||||
Material[] allMaterials = AssetDatabase
|
||||
.FindAssets("t:material", new[] { "Assets" })
|
||||
.Select(AssetDatabase.GUIDToAssetPath)
|
||||
.Select(AssetDatabase.LoadAssetAtPath<Material>)
|
||||
.ToArray();
|
||||
|
||||
m_DefaultMaterialGroup = MaterialGroup.CreateDefault();
|
||||
|
||||
m_UnexposedMaterials = allMaterials
|
||||
.Where(m => !MaterialGroupUtil.IsMaterialPartOfAnyMaterialGroup(m))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
protected override void OnGUI()
|
||||
{
|
||||
Text(
|
||||
"By default, Tremble will export all of the materials in your project into TrenchBroom.",
|
||||
"If your project has a lot of materials though, this can take some time,",
|
||||
"and there may be materials that you never want to use in TrenchBroom at all."
|
||||
);
|
||||
|
||||
Text(
|
||||
"By using material groups, you can decide which materials to export to TrenchBroom,",
|
||||
"and even organise them into groups!"
|
||||
);
|
||||
|
||||
H1("Assigning material groups");
|
||||
Text("There are 2 ways to set up material groups:");
|
||||
Bullet(
|
||||
"Click an individual material (or a group of materials) in Unity's Project window,",
|
||||
"and select a group from the dropdown at the top of the Inspector view."
|
||||
);
|
||||
Image("T_Manual_MaterialGroups");
|
||||
Bullet(
|
||||
"or, go into Tremble's settings (see Basics > Tremble's Settings), click 'Materials',",
|
||||
"and add one or more groups. Now you can assign materials to each group."
|
||||
);
|
||||
|
||||
H1("How is my project set up?");
|
||||
|
||||
if (m_SyncSettings.MaterialGroups is { Length: > 0 })
|
||||
{
|
||||
Text(
|
||||
$"Your project is using material groups, and you have {m_SyncSettings.MaterialGroups.Length}",
|
||||
"of them:"
|
||||
);
|
||||
|
||||
foreach (MaterialGroup matGroup in m_SyncSettings.MaterialGroups)
|
||||
{
|
||||
Indent(() =>
|
||||
{
|
||||
Foldout($"{matGroup.Name}, {matGroup.Materials.Length} material(s)", () =>
|
||||
{
|
||||
foreach (Material mat in matGroup.Materials)
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
Bullet(mat.name);
|
||||
Button($"select {mat.name}", width: 200f, action: () => Selection.activeObject = mat);
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (m_UnexposedMaterials.Length == 0)
|
||||
{
|
||||
Text("...and that's all your materials!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Text($"There are {m_UnexposedMaterials.Length} materials that are not exposed to TrenchBroom:");
|
||||
Indent(() =>
|
||||
{
|
||||
Foldout($"Unavailable material(s)", () =>
|
||||
{
|
||||
foreach (Material mat in m_UnexposedMaterials)
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
Bullet(mat.name);
|
||||
Button($"select {mat.name}", width: 200f, action: () => Selection.activeObject = mat);
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
Text("To make a Material available for use, select it and use the Inspector to add it",
|
||||
"to a Material Group.");
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Text(
|
||||
$"Your project is not using material groups, and you have {m_DefaultMaterialGroup.Materials.Length}",
|
||||
"compatible material(s) in your project:"
|
||||
);
|
||||
Indent(() =>
|
||||
{
|
||||
Foldout("Show materials", () =>
|
||||
{
|
||||
foreach (Material material in m_DefaultMaterialGroup.Materials)
|
||||
{
|
||||
Bullet(material.name);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
string trembleMaterialsPath = "Project/Tremble/3 Materials";
|
||||
ActionBar_SingleAction("Edit Material Groups", () => SettingsService.OpenProjectSettings(trembleMaterialsPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fcdaf93099d84ea28783d12928ca5055
|
||||
timeCreated: 1723448806
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/Materials/MaterialGroupsPage.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.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
[ManualPage("Materials/Render Settings")]
|
||||
public class MaterialRenderDataPage : ManualPageBase
|
||||
{
|
||||
private TrembleSyncSettings m_SyncSettings;
|
||||
private MaterialGroup m_DefaultMaterialGroup;
|
||||
private Material[] m_UnexposedMaterials;
|
||||
|
||||
protected override void OnInit()
|
||||
{
|
||||
m_SyncSettings = TrembleSyncSettings.Get();
|
||||
}
|
||||
|
||||
protected override void OnGUI()
|
||||
{
|
||||
Text(
|
||||
"When Tremble exports materials, it can convert your materials in a few different ways.",
|
||||
"You can choose a material's render settings by finding that material in the editor,",
|
||||
"and changing the following settings:"
|
||||
);
|
||||
|
||||
Image("T_Manual_RenderSettings");
|
||||
|
||||
H1("Render Mode");
|
||||
|
||||
Bold("Dynamic Mode (\"MainTex\")");
|
||||
Bullet(
|
||||
"Uses the main texture of the material as the texture exported to Trenchbroom.",
|
||||
"This will work fine for most materials. Directly copies the texture to the export folder",
|
||||
"if the resolution is unmodified."
|
||||
);
|
||||
Bullet(
|
||||
"If you're using a custom shader, make sure your material either has a texture named _MainTex,",
|
||||
"or a texture marked as Main Texture. This can be done through ShaderLab markup with [MainTexture]",
|
||||
"for code shaders, or by marking the texture as a Main Texture in Shader Graph shaders.");
|
||||
Bullet(
|
||||
"If the renderer fails to find a matching main texture, it will try a few other texture names",
|
||||
"like _Color, _BaseColor, or other misspellings of _MainTex (just in case).");
|
||||
Bullet(
|
||||
"If that also fails, the renderer will switch to Fixed Size Mode."
|
||||
);
|
||||
|
||||
Bold("Fixed-Size Mode (\"Legacy\")");
|
||||
Bullet(
|
||||
"Renders the material using a camera system. ",
|
||||
"This is useful for procedural materials, or any other material that doesn't have",
|
||||
"a main texture parameter."
|
||||
);
|
||||
Bullet(
|
||||
"Will be automatically used if MainTex mode fails."
|
||||
);
|
||||
|
||||
H1("Resolution");
|
||||
Text(
|
||||
"You can use these settings to set the resolution of a texture.",
|
||||
"This is useful for textures that don't have the same resolution on the X and Y axis.",
|
||||
"Note that the resolution affects UV mapping - in Trenchbroom, one pixel is one unit by default."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b87f0fb523a94356827025cd020dd8d3
|
||||
timeCreated: 1752489026
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/Materials/MaterialRenderDataPage.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// 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.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
[ManualPage("Materials/About")]
|
||||
public class MaterialsAboutPage : ManualPageBase
|
||||
{
|
||||
protected override void OnGUI()
|
||||
{
|
||||
Text(
|
||||
"Tremble uses a novel approach compared to other map import tools.",
|
||||
"Many map import tools will allow users to create their own Textures folder for use",
|
||||
"with TrenchBroom, and will try to create materials based on those on import."
|
||||
);
|
||||
|
||||
Text(
|
||||
"This results in materials in your project which use the built-in 'Standard'",
|
||||
"(or URP/HDRP 'Lit') shader."
|
||||
);
|
||||
|
||||
Text(
|
||||
"Tremble does NOT work in this way. Tremble takes your existing Unity materials,",
|
||||
"and generates a Textures folder for you with an accurate representation of each",
|
||||
"Unity material as a texture."
|
||||
);
|
||||
|
||||
H1("Why?!");
|
||||
Text(
|
||||
"Well, we believe that users don't want to spend time curating textures for",
|
||||
"TrenchBroom when ultimately what they care about is the Material looking good",
|
||||
"in Unity (where your players will see it). It's the same reason Tremble does",
|
||||
"not support Quake®'s lightmapping tech. Your game will use Unity's lighting,",
|
||||
"so this is where you should apply your scene's lighting setup."
|
||||
);
|
||||
|
||||
H1("But really, what benefits does it give me?");
|
||||
Bullet("Your materials and shaders appear exactly how you set them up in Unity, in your game!");
|
||||
Bullet(
|
||||
"You are not restricted to using Standard/Lit shaders for your map materials! You",
|
||||
"can use custom shaders/Shader Graphs, including Unlit, bumpmapped, or entirely HLSL-driven",
|
||||
"materials."
|
||||
);
|
||||
Bullet(
|
||||
"There's no need to worry about how TrenchBroom handles textures - Tremble",
|
||||
"keeps everything in sync automagically!"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0eedd4cad37c4fdca5801d345f060473
|
||||
timeCreated: 1724656293
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/Materials/MaterialsAboutPage.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9168ecc737624c8899cf1cb3474b0b9f
|
||||
timeCreated: 1723449331
|
||||
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// 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("Import from Other Games/Texture FGDs from other games")]
|
||||
public class ImportFgdPage : ManualPageBase
|
||||
{
|
||||
protected override void OnGUI()
|
||||
{
|
||||
Text("When importing maps from other games, Tremble might encounter entities which it does not recognise.");
|
||||
|
||||
Text("For example, if you import a map from Quake®, it will contain (among others) an",
|
||||
"'info_player_start' entity to define where the player should spawn.");
|
||||
|
||||
Text("If you import the map and use Map Repair, you can either:");
|
||||
|
||||
Number("Map an existing MonoBehaviour from your game to this unknown entity, or");
|
||||
Number("Have Tremble generate a new MonoBehaviour, by making assumptions based on what's in the map.");
|
||||
|
||||
Text("However, this can be problematic. If the map doesn't contain data for a given field,",
|
||||
"Tremble will have no knowledge of it and won't generate complete C# script for it.");
|
||||
|
||||
Text("Tremble will never generate anything invalid, but you may be missing functionality.");
|
||||
|
||||
Text("This is where importing an FGD file can help!");
|
||||
|
||||
Foldout("What's an FGD file?", () =>
|
||||
{
|
||||
Text("A Forge Game Data file. It contains a list of all entities in a game, and what",
|
||||
"fields they support.");
|
||||
|
||||
Text("It can also contain helpful tooltips and hints as to how each field is used.");
|
||||
});
|
||||
|
||||
H1("Importing an FGD file");
|
||||
Text("To import an FGD file, simply drag it into your project.");
|
||||
Text("Tremble will extract the FGD classes into a folder of the same name.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e85c2df6351a493aaeea88ae4c9fdae4
|
||||
timeCreated: 1724661376
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/OtherGames/ImportFgdPage.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// 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("Import from Other Games/Texture WADs from other games")]
|
||||
public class ImportWadPage : ManualPageBase
|
||||
{
|
||||
protected override void OnGUI()
|
||||
{
|
||||
Text("Unfortunately, you cannot supply a WAD file in your TrenchBroom map files for Tremble to use.");
|
||||
|
||||
Text("However, Tremble does support extracting WAD files into your Unity project, which in turn",
|
||||
"makes them available to TrenchBroom.");
|
||||
|
||||
Callout("Note: Only WAD2 (Quake) format WAD files are supported at the moment.",
|
||||
"WAD3 (Valve) are not supported (yet?)");
|
||||
|
||||
Text("To get started, simply drop a WAD file into your Unity project.");
|
||||
|
||||
Text("This process can take a while for a large WAD file - up to a minute or two.",
|
||||
"It only needs to be done once.");
|
||||
Image("T_Manual_WadImport2");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 418c0e37fc314aa489c2459b11529dbf
|
||||
timeCreated: 1723449354
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/OtherGames/ImportWadPage.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// 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("Import from Other Games/FGD Comparison", title: "The difference made by importing an FGD file", showInTree: false)]
|
||||
public class MapRepairFgdComparisonPage : ManualPageBase
|
||||
{
|
||||
protected override void OnGUI()
|
||||
{
|
||||
Text("With an FGD file imported, you'll see that Tremble has the proper names and",
|
||||
"descriptions of all the fields of the map classes - rather than just the ones",
|
||||
"that happened to be set in the map.");
|
||||
|
||||
Text("It's recommended to import the FGD whenever importing 'foreign' maps to make",
|
||||
"them easier to work with.");
|
||||
|
||||
CustomPropertyDescription("No FGD File", () =>
|
||||
{
|
||||
Image("T_Manual_MapRepair_NoFGD", width: 700f, centred: false);
|
||||
});
|
||||
CustomPropertyDescription("With FGD File", () =>
|
||||
{
|
||||
Image("T_Manual_MapRepair_WithFGD", width: 700f, centred: false);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 937a21eaecb54e83a8e4180905259474
|
||||
timeCreated: 1723549012
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/OtherGames/MapRepairFgdComparisonPage.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,82 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
[ManualPage("Import from Other Games/Maps from other games")]
|
||||
public class MapRepairForeignPage : ManualPageBase
|
||||
{
|
||||
private static readonly string[] TAB_NAMES = new[]
|
||||
{
|
||||
"Materials/Textures", "Entities"
|
||||
};
|
||||
|
||||
private int m_SelectedTabIdx;
|
||||
|
||||
protected override void OnGUI()
|
||||
{
|
||||
Image("T_Manual_MapRepair_Required", width: 220f);
|
||||
|
||||
Text("You can also use Map Repair to patch up what Tremble terms 'foreign maps' (maps",
|
||||
"from other games) to work with your Tremble/Unity project. This also allows you to",
|
||||
"import/export maps between your own projects, or even import maps from other games",
|
||||
"(such as Quake®!).");
|
||||
|
||||
Text("For any unrecognised entities in maps, Map Repair will generate new MonoBehaviour classes",
|
||||
"to match them. This saves time creating C# classes for brand new entities you've",
|
||||
"added to the map.");
|
||||
|
||||
Text("These generated classes will allow Tremble to import these new entities and will",
|
||||
"bring any values from the map into Unity - but of course, it won't provide any game",
|
||||
"logic such as movement or AI - you'd have to code that yourself.");
|
||||
|
||||
|
||||
H2("Available Tabs");
|
||||
{
|
||||
switch (Tabs(ref m_SelectedTabIdx, TAB_NAMES, width: 420f))
|
||||
{
|
||||
case 0: // Textures
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
Image("T_Manual_MapRepair_Textures", width: 400f);
|
||||
GUILayout.BeginVertical();
|
||||
{
|
||||
Text("This tab shows a list of all of the map's textures, and Tremble’s best guess",
|
||||
"at which project Materials match those textures.");
|
||||
Bullet("You can then change which material each texture maps to manually, if you desire.");
|
||||
Bullet("You can click the small '!' button to apply a given material to all missing materials",
|
||||
"(for example, if you want to apply a single material to all unknown materials in a map)");
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
break;
|
||||
|
||||
case 1: // Entities
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
Image("T_Manual_MapRepair_Entities", width: 400f);
|
||||
GUILayout.BeginVertical();
|
||||
{
|
||||
Text("This tab shows a list of all the map's point and brush entities, and Tremble’s best guess",
|
||||
"at which MonoBehaviour classes match those entities.");
|
||||
Bullet("You can then change which class each entity maps to manually, if you desire.");
|
||||
Bullet("Leave an unknown entity class as 'Generate new class' to ask Tremble to generate",
|
||||
"a new MonoBehaviour class that matches the entity. This may need manual tweaking",
|
||||
"afterwards, but will be valid and able to parse the map supplied.");
|
||||
Bullet("At the bottom of this tab, you are able to designate where new classes",
|
||||
"are generated and an optional namespace to use for them.");
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e510aaa0a33f4bceb10e55cb90bbedd1
|
||||
timeCreated: 1723448767
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/OtherGames/MapRepairForeignPage.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,125 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
[ManualPage("Overview", isHomePage: true)]
|
||||
public class OverviewPage : ManualPageBase
|
||||
{
|
||||
private bool m_GotLatestVersions = false;
|
||||
|
||||
protected override void OnInit()
|
||||
{
|
||||
VersionCheck.FetchLatestVersionsInBackground(() =>
|
||||
{
|
||||
m_GotLatestVersions = true;
|
||||
Repaint();
|
||||
});
|
||||
}
|
||||
|
||||
protected override void OnGUI()
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
Image("T_TrembleLogo", width: 200f, centred: false);
|
||||
|
||||
GUILayout.BeginVertical();
|
||||
{
|
||||
H1("Welcome to the Tremble manual!");
|
||||
Text(
|
||||
"Please click an item on the left to navigate. There are also buttons in the top",
|
||||
"toolbar for navigating back/forwards, and returning here (Home)."
|
||||
);
|
||||
|
||||
|
||||
PropertyDescription("Your version of Tremble", labelWidth: 200f, $"Version {TrembleConsts.VERSION_STRING}");
|
||||
|
||||
if (!m_GotLatestVersions)
|
||||
{
|
||||
GUI.color = Color.yellow;
|
||||
PropertyDescription("Latest version of Tremble", "... checking if there's a newer version ...");
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (VersionCheck.IsNewerVersionAvailable)
|
||||
{
|
||||
GUILayout.BeginVertical(EditorStyles.helpBox);
|
||||
{
|
||||
PropertyDescription("Latest version of Tremble", labelWidth: 200f, $"There's a newer version available, v{VersionCheck.NewestAvailableVersion.Version}",
|
||||
$"({VersionCheck.NumVersionsBehind} versions behind)!");
|
||||
|
||||
ActionBar_SingleAction("Upgrade in Package Manager!", () => EditorApplication.ExecuteMenuItem("Window/Package Manager"));
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
else
|
||||
{
|
||||
PropertyDescription("Latest version of Tremble", labelWidth: 200f, $"Version {VersionCheck.CurrentInstalledVersion.Version} - you're already on the latest and greatest!");
|
||||
}
|
||||
}
|
||||
|
||||
if (TrenchBroomUtil.TrenchBroomPath == null)
|
||||
{
|
||||
PropertyDescription("TrenchBroom", labelWidth: 200f, "(unknown location!)");
|
||||
|
||||
GUI.color = Color.yellow;
|
||||
Text(
|
||||
"Is TrenchBroom installed? Tremble is unsure where to find it. Try",
|
||||
"opening TrenchBroom now - I'll keep checking for it :)"
|
||||
);
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
else
|
||||
{
|
||||
string path = TrenchBroomUtil.TrenchBroomPath;
|
||||
|
||||
#if UNITY_EDITOR_OSX
|
||||
// Under macOS, remove /Contents/MacOS/TrenchBroom
|
||||
int suffix = path.IndexOfInvariant("/Contents", caseSensitive: true);
|
||||
if (suffix != -1)
|
||||
{
|
||||
path = path.Substring(0, suffix);
|
||||
}
|
||||
#endif
|
||||
|
||||
string running = TrenchBroomUtil.IsTrenchBroomRunning ? " (running)" : "";
|
||||
PropertyDescription("TrenchBroom", labelWidth: 200f, $"TrenchBroom was discovered at: {path}{running}");
|
||||
}
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
LargeSpace();
|
||||
|
||||
if (TrenchBroomUtil.TrenchBroomPath == null)
|
||||
{
|
||||
ActionBar_SingleAction("Download TrenchBroom", () => { Application.OpenURL("https://github.com/TrenchBroom/TrenchBroom/releases");});
|
||||
}
|
||||
|
||||
H2("Getting Started");
|
||||
ActionBar(() =>
|
||||
{
|
||||
Action("Create your first map", () => GoToPage(typeof(CreateMapPage)));
|
||||
Action("Set Tremble up for User Generated Content", () => GoToPage(typeof(UgcSetupPage)));
|
||||
Action("Get support!", () => GoToPage(typeof(TroubleshootingGetHelpPage)));
|
||||
});
|
||||
|
||||
H2("Quick Create Entity");
|
||||
ActionBar(() =>
|
||||
{
|
||||
Action("Create a POINT entity", () => GoToPage(typeof(PointEntitiesPage)));
|
||||
Action("Create a BRUSH entity", () => GoToPage(typeof(BrushEntitiesPage)));
|
||||
Action("Create a PREFAB entity", () => GoToPage(typeof(PrefabEntitiesPage)));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7901a6be0c0b40a6bae863067e7c1470
|
||||
timeCreated: 1722961223
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/OverviewPage.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 273698197de74f00b452be8efe988040
|
||||
timeCreated: 1723448826
|
||||
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
[ManualPage("Troubleshooting/'dylib can't be opened' (macOS only)")]
|
||||
public class TroubleshootingDLLPage : ManualPageBase
|
||||
{
|
||||
protected override void OnGUI()
|
||||
{
|
||||
Image("T_Manual_Trouble_DLL1", width: 200f);
|
||||
|
||||
Text(
|
||||
"This can sometimes occur because Q3Map2, the converter which transforms your .map",
|
||||
"file into something Tremble can understand, is not currently signed.",
|
||||
"(this may change in future!)"
|
||||
);
|
||||
|
||||
Text(
|
||||
"It's a warning from macOS that you may not wish to trust the Q3Map2 binary."
|
||||
);
|
||||
|
||||
Foldout("Why should I trust it?", () =>
|
||||
{
|
||||
Bullet("Q3Map2 is distributed with Tremble from the Asset Store and is safe to use");
|
||||
Bullet("You can verify the source code OR build your own Q3Map2 library, if you prefer");
|
||||
|
||||
ActionBar_SingleAction("Verify Q3Map2 source on Github", () => Application.OpenURL("https://github.com/tinygooseuk/q3map2/tree/libq3map2"));
|
||||
});
|
||||
|
||||
H1("To fix the error, do the following:");
|
||||
|
||||
Number("Click 'Done' to close the 'can't be opened' dialogue");
|
||||
Number("Open 'System Settings' on your Mac, and scroll down to 'Privacy & Security' in the left sidebar");
|
||||
Number("Scroll down to 'Security', and click 'Allow Anyway'");
|
||||
|
||||
Image("T_Manual_Trouble_DLL2");
|
||||
|
||||
Number("You may be prompted to enter your password or use Touch ID. Do so");
|
||||
Number("Close System Settings and return to Unity");
|
||||
Number("Try to import the map again. You will see the same error, but this time there will be an 'Open' button. Click 'Open'");
|
||||
|
||||
Text("This should now work!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4dcb872d73a04f568fdea7a559b18319
|
||||
timeCreated: 1723448843
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/Troubleshooting/TroubleshootingDLLPage.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
[ManualPage("Troubleshooting/Get Help & Support")]
|
||||
public class TroubleshootingGetHelpPage : ManualPageBase
|
||||
{
|
||||
protected override void OnGUI()
|
||||
{
|
||||
H1("Discord");
|
||||
Text(
|
||||
"If you need help, please first join us on our Discord server:",
|
||||
"https://discord.gg/aUTmYxbVHZ."
|
||||
);
|
||||
|
||||
ActionBar_SingleAction("Open Discord", () => Application.OpenURL("https://discord.gg/aUTmYxbVHZ"));
|
||||
|
||||
H1("Email Support");
|
||||
Text(
|
||||
"For further assistance, or if you do not have access to Discord, do",
|
||||
"not hesitate to contact us at: hello@tinygoose.com."
|
||||
);
|
||||
|
||||
ActionBar_SingleAction("Send Email", () => Application.OpenURL("mailto:hello@tinygoose.com"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce80159b60eb429c822dbbab4c39d44b
|
||||
timeCreated: 1723448946
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/Troubleshooting/TroubleshootingGetHelpPage.cs
|
||||
uploadId: 939664
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// 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("Troubleshooting/Too dark or too bright materials")]
|
||||
public class TroubleshootingMaterialBrightnessPage : ManualPageBase
|
||||
{
|
||||
protected override void OnGUI()
|
||||
{
|
||||
Image("T_Manual_Trouble_MaterialBrightness");
|
||||
|
||||
Text("Some users experience issues with materials exporting too bright or too dark when",
|
||||
"viewed in TrenchBroom. This can be due to the way Tremble captures Unity Materials to",
|
||||
"texture PNGs - which uses specific lighting, but can sometimes take on the environment",
|
||||
"from your scene.");
|
||||
|
||||
Text("Please note that this does NOT affect how your materials will appear in Unity/your game!");
|
||||
|
||||
Text("As a workaround, you can adjust how Tremble lights your materials in Tremble's Settings,",
|
||||
"under Advanced/Materials.");
|
||||
|
||||
Callout("When changing these settings or force-resyncing below, note that you should",
|
||||
"Refresh Texture Collections (F5) and Refresh Entity Definitions (F6) in TrenchBroom",
|
||||
"to update to the latest data.");
|
||||
|
||||
Image("T_Manual_Trouble_MaterialBrightnessSettings");
|
||||
|
||||
ActionBar_SingleAction("Open in Settings", ()
|
||||
=> SettingsService.OpenProjectSettings("Project/Tremble/4 Advanced/3 Materials"));
|
||||
|
||||
Text("As a last resort, you can also try force-syncing your project to TrenchBroom. You can do this",
|
||||
"by clearing the cache and then re-syncing, from Tools > Tremble > Sync Project to TrenchBroom (Clean, Slow)",
|
||||
"- or by pressing the button below.");
|
||||
|
||||
ActionBar_SingleAction("Force-resync for me", ()=>
|
||||
{
|
||||
TrembleEditorAPI.InvalidateMaterialAndPrefabCache(silent: true);
|
||||
TrembleEditorAPI.SyncToTrenchBroom();
|
||||
|
||||
if (TrenchBroomUtil.IsTrenchBroomRunning)
|
||||
{
|
||||
EditorUtility.DisplayDialog(
|
||||
title: "TrenchBroom is running",
|
||||
message: "You may need to refresh Textures and Entities in TrenchBroom (press F5, then F6 in TrenchBroom)!",
|
||||
|
||||
"Oh, okay!");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ef8cfc4d6b7b43baa6078bbb722dca8f
|
||||
timeCreated: 1723448882
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/Troubleshooting/TroubleshootingMaterialBrightnessPage.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
[ManualPage("Troubleshooting/Missing Geometry")]
|
||||
public class TroubleshootingMissingGeoPage : ManualPageBase
|
||||
{
|
||||
private const float IMAGE_WIDTH = 300f;
|
||||
|
||||
protected override void OnGUI()
|
||||
{
|
||||
Text("If you create an area in a map that is completely enclosed (known in the mapping",
|
||||
"community as being 'sealed'), you might find that Tremble culls the",
|
||||
"inside of these areas entirely!");
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
Bold("TrenchBroom (before):", width: IMAGE_WIDTH);
|
||||
Bold("Unity (before):", width: IMAGE_WIDTH);
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
Image("T_Manual_MissingGeo_TB1", width: IMAGE_WIDTH, centred: false);
|
||||
Image("T_Manual_MissingGeo_Unity1", width: IMAGE_WIDTH, centred: false);
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
Text("This is because Q3Map2 (the map compiler) determines that these areas can never",
|
||||
"be reached, and thus is unnecessary geometry.");
|
||||
|
||||
Text("In order to keep this geometry around, you need to place a Point or Brush entity",
|
||||
"(or a prefab) inside this area. Tremble will no longer cull the area, as it",
|
||||
"determines that there are gameplay elements inside the area and thus it is important.");
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
Bold("TrenchBroom (after):", width: IMAGE_WIDTH);
|
||||
Bold("Unity (after):", width: IMAGE_WIDTH);
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
Image("T_Manual_MissingGeo_TB2", width: IMAGE_WIDTH, centred: false);
|
||||
Image("T_Manual_MissingGeo_Unity2", width: IMAGE_WIDTH, centred: false);
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2319b986770f4d8c9ddcbb9b6d37ba62
|
||||
timeCreated: 1724754283
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/Troubleshooting/TroubleshootingMissingGeoPage.cs
|
||||
uploadId: 939664
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// This file is part of the Tremble package by Tiny Goose.
|
||||
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
|
||||
//
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace TinyGoose.Tremble.Editor
|
||||
{
|
||||
[ManualPage("Troubleshooting/Pink materials in TrenchBroom")]
|
||||
public class TroubleshootingPinkMaterialsPage : ManualPageBase
|
||||
{
|
||||
protected override void OnGUI()
|
||||
{
|
||||
Text("Pink materials can appear in either Unity or TrenchBroom, and they indicate that",
|
||||
"a Material or Shader could not be found.");
|
||||
|
||||
Image("T_Manual_Trouble_PinkMaterials");
|
||||
|
||||
H1("For your own materials/textures not rendering");
|
||||
Text("Try to run Map Repair on the map with pink materials. You will be able to swap the",
|
||||
"missing materials for valid ones.");
|
||||
ActionBar_SingleAction("Open Map Repair", MapRepairWindow.OpenMapRepair);
|
||||
|
||||
H1("For Tremble sample materials not rendering, under URP or HDRP");
|
||||
Text("Tremble's sample project materials are built for the Built-In Render Pipeline.",
|
||||
"This means, if you're using URP or HDRP, you should manually upgrade them to your pipeline.");
|
||||
|
||||
Text("There's a great tutorial for this by SpawnCampGames on YouTube:");
|
||||
Image("T_Manual_Trouble_FixPinkMaterialsVideo");
|
||||
ActionBar_SingleAction("Open Video", () => Application.OpenURL("https://www.youtube.com/watch?v=V_EGF1M3fgY"));
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8a86dbcdd6714f008d781a4d19f04b82
|
||||
timeCreated: 1723453626
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/Troubleshooting/TroubleshootingPinkMaterialsPage.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ed2fb86e7fa34acc930cb86907b49812
|
||||
timeCreated: 1723536800
|
||||
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// 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("User Generated Content/For Players")]
|
||||
public class UgcPlayerHintsPage : ManualPageBase
|
||||
{
|
||||
protected override void OnGUI()
|
||||
{
|
||||
Experimental();
|
||||
|
||||
Text("This page gives a bit more detail on what players need, in order to import maps");
|
||||
|
||||
H2("How do players get the FGD file/textures/etc?");
|
||||
Text(
|
||||
"These are installed onto the user's computer when you call",
|
||||
$"{nameof(TrembleRuntimeAPI)}.{nameof(TrembleRuntimeAPI.Initialise)},",
|
||||
"so there is no need to distribute these yourself."
|
||||
);
|
||||
|
||||
H2("Do players need a copy of my Unity project to import maps?");
|
||||
Text(
|
||||
"Absolutely not! Just a copy of your game with Tremble installed and configured."
|
||||
);
|
||||
|
||||
H2("Do players need to purchase a licence for Tremble, on the Asset Store?");
|
||||
Text(
|
||||
"Again - absolutely not! Just a copy of your game with Tremble installed and configured."
|
||||
);
|
||||
|
||||
H2("What if players want to use their own textures?");
|
||||
Text(
|
||||
"Generally this is discouraged, especially when distributing user-generated maps.",
|
||||
"However - it is possible! Users should place their textures (PNG only!) into your game's",
|
||||
"Library/baseq3/Textures folder (this will be created on first run). When Tremble",
|
||||
"finds these unexpected textures referenced in a map, it will create Unity",
|
||||
"materials on-the-fly to display them."
|
||||
);
|
||||
Text(
|
||||
"Note, that you will need to distribute these textures with the maps, and place",
|
||||
"them into the correct folder at runtime for this to work when sharing maps between",
|
||||
"players."
|
||||
);
|
||||
|
||||
H2("What about if these textures should be PBR materials?");
|
||||
Text(
|
||||
"Yup - you might want to change the metallic and smoothness parameters when",
|
||||
"importing a user's custom texture. To do that, Tremble uses a naming convention."
|
||||
);
|
||||
PropertyDescription("s[0-100]", "Smoothness percent");
|
||||
PropertyDescription("m[0-100]", "Metallic/metalness percent");
|
||||
Text(
|
||||
"For example, a texture which should be 60% smooth and 100% metal could be named: ",
|
||||
"'MyCoolTexture_s60_m100.png'."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 56855e58ea5a449082f0be2069093e76
|
||||
timeCreated: 1723536946
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/UserGeneratedContent/UgcPlayerHintsPage.cs
|
||||
uploadId: 939664
|
||||
@@ -0,0 +1,100 @@
|
||||
//
|
||||
// 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("User Generated Content/Setup", title: "UGC Setup")]
|
||||
public class UgcSetupPage : ManualPageBase
|
||||
{
|
||||
private TrembleSyncSettings m_SyncSettings;
|
||||
|
||||
private bool IsAddressablesInstalled =>
|
||||
#if ADDRESSABLES_INSTALLED
|
||||
true;
|
||||
#else
|
||||
false;
|
||||
#endif
|
||||
|
||||
private bool m_IsInstalling;
|
||||
|
||||
protected override void OnInit()
|
||||
{
|
||||
m_SyncSettings = TrembleSyncSettings.Get();
|
||||
}
|
||||
|
||||
protected override void OnGUI()
|
||||
{
|
||||
Experimental();
|
||||
|
||||
Text(
|
||||
"Tremble now supports importing maps at runtime, which allows players to create their",
|
||||
"own maps in TrenchBroom, and import it into your game themselves."
|
||||
);
|
||||
|
||||
Text(
|
||||
"You could use something like Unity's UGC package, or Steam Workshop to distribute",
|
||||
"maps to players (which is up to you to implement). Tremble just needs the map file",
|
||||
"to load on disk somewhere, and it will import it at runtime."
|
||||
);
|
||||
|
||||
H1("Setup");
|
||||
Text(
|
||||
"There are a few things to set up first, before you can use this feature. This page",
|
||||
"will help you do that."
|
||||
);
|
||||
|
||||
CheckListItem("Install the Addressables package from Unity", m_IsInstalling || IsAddressablesInstalled, "Install", () =>
|
||||
{
|
||||
m_IsInstalling = true;
|
||||
UnityEditor.PackageManager.Client.Add("com.unity.addressables");
|
||||
});
|
||||
|
||||
CheckListItem("Enable the Tremble setting for UGC", m_SyncSettings.AllowStandaloneImport, "Enable", () =>
|
||||
{
|
||||
SerializedObject so = new(m_SyncSettings);
|
||||
so.FindBackedProperty(nameof(m_SyncSettings.AllowStandaloneImport)).boolValue = true;
|
||||
so.ApplyModifiedPropertiesWithoutUndo();
|
||||
|
||||
TrembleEditorAPI.SyncToTrenchBroom();
|
||||
});
|
||||
|
||||
H1("Initialising the system");
|
||||
{
|
||||
Text(
|
||||
"This step will prepare Tremble for loading maps at runtime.",
|
||||
"Unfortunately, it can lock your game up for about 200ms - so the idea is to do",
|
||||
"this during your game's startup code, to allow Tremble to initialise",
|
||||
"without causing your game to hitch during gameplay."
|
||||
);
|
||||
Code("await TrembleRuntimeAPI.Initialise();");
|
||||
}
|
||||
|
||||
H1("Loading a map at runtime");
|
||||
{
|
||||
Text("Loading a map at runtime couldn't be simpler - simply call the following function:");
|
||||
|
||||
Code(
|
||||
$"{nameof(MapDocument)} map = await {nameof(TrembleRuntimeAPI)}.{nameof(TrembleRuntimeAPI.LoadMapAsync)}(\"C:\\somemap.map\");",
|
||||
"",
|
||||
"// Your map is now in the current scene, if loading succeeded.",
|
||||
"// Check `map.Result` to see if it worked, and the `map.gameObject` is the root",
|
||||
"// of your new map!",
|
||||
"Debug.Log($\"Result: {map.Result}\");",
|
||||
"Debug.Log($\"Loaded map: {map.BspName}\");"
|
||||
);
|
||||
|
||||
H2("Notes");
|
||||
{
|
||||
Bullet("You can also provide additional arguments, such as subdivision parameters and smoothing angles.");
|
||||
Bullet("Tremble respects Application.backgroundLoadingPriority, which you can use to signal how",
|
||||
"much time you want Unity to dedicate per frame to async loading. Higher priorities will load",
|
||||
"your map faster, but at the expense of dropping more frames during the load.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f5ecfa2702b44c4b9f03bbacef113cfc
|
||||
timeCreated: 1723448499
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 277805
|
||||
packageName: Tremble - Map Importer
|
||||
packageVersion: 1.11.1
|
||||
assetPath: Assets/Tremble/Editor/Manual/Pages/UserGeneratedContent/UgcSetupPage.cs
|
||||
uploadId: 939664
|
||||
Reference in new issue
Block a user