Kursach_StealthAction/Assets/Tremble/TrembleSyncSettings.cs
2026-10-11 19:16:11 +03:00

400 lines
18 KiB
C#

//
// This file is part of the Tremble package by Tiny Goose.
// Copyright (c) 2024-2026 TinyGoose Ltd., All Rights Reserved.
//
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using System.IO;
using System.Reflection;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace TinyGoose.Tremble
{
public enum TrenchBroomVersion
{
Version2023_1,
Version2024_1,
Version2024_2,
Version2025_3,
Version2026_1,
VersionNext,
}
public enum NamingConvention
{
SnakeCase,
UpperCamelCase,
LowerCamelCase,
PreserveExact,
HumanFriendly,
}
public enum Q3Map2ResultDisplayType
{
NeverShow,
ShowWhenWarningsOccur,
AlwaysShow
}
public enum FgdFormattingStyle
{
Fast,
HumanReadable,
VeryVerbose
}
public enum EntityIconStyle
{
Nothing,
ColouredDiamondShapes,
ColouredLabels,
}
public enum PrefabOverrideHandling
{
AllowOverrides,
WarnOnOverridesFound,
AutomaticallyRevert
}
[Serializable]
public struct MapProcessorEntry
{
public MapProcessorClass Class;
public bool Enabled;
}
[Serializable]
public struct MaterialGroup
{
public string Name;
public Material[] Materials;
public static MaterialGroup CreateDefault()
{
return new()
{
Name = "game",
Materials = TrembleAssetLoader.FindAssetPaths<Material>()
.Where(p => Path.GetExtension(p).EqualsInvariant(".mat"))
.Where(p => !p.ContainsInvariant("M_NullRender"))
.Select(TrembleAssetLoader.LoadAssetByPath<Material>)
.ToArray()
};
}
}
[Serializable]
public struct AssetMetadata
{
public string MapName;
public string Path;
public string FullTypeName;
#if ADDRESSABLES_INSTALLED
public string AddressableName;
#endif
public Vector3 SpawnOffset;
}
public class TrembleSyncSettings : ScriptableObject
{
#if ADDRESSABLES_INSTALLED
public const string ADDRESSABLE_KEY = "TrembleSyncSettings";
#endif
// -----------------------------------------------------------------------------------------------------------------------------
// Singleton
// -----------------------------------------------------------------------------------------------------------------------------
private static TrembleSyncSettings s_TrembleSyncSettings;
public static TrembleSyncSettings Get(bool createIfNotExists = true)
{
// Return cached?
if (s_TrembleSyncSettings)
return s_TrembleSyncSettings;
// Load & cache if possible
s_TrembleSyncSettings = TrembleAssetLoader.LoadSyncSettings();
if (s_TrembleSyncSettings || !createIfNotExists)
return s_TrembleSyncSettings;
// Return, or create temporary
s_TrembleSyncSettings = CreateInstance<TrembleSyncSettings>();
#if UNITY_EDITOR
AssetDatabase.CreateAsset(s_TrembleSyncSettings, Path.Combine("Assets", "Tremble Sync Settings.asset"));
#endif
return s_TrembleSyncSettings;
}
// -----------------------------------------------------------------------------------------------------------------------------
// Basic Settings
// -----------------------------------------------------------------------------------------------------------------------------
[SerializeField, Tooltip("Automagically keep project in-sync with TrenchBroom when compiling sources? Turn off if this is slow for your project.")]
private bool m_AutoSyncOnCompile = true;
[SerializeField, Tooltip("(Experimental!) Allow importing of maps in standalone/retail builds? Requires the Addressables package. Tremble will add Addressable Groups for your materials and entity prefabs to support in-game import, and will package up your entities.fgd and baseq3 data into your game.")]
private bool m_AllowStandaloneImport = false;
[SerializeField, Tooltip("TrenchBroom Version (2023 = GameConfig v4, 2024_1 = GameConfig v8, 2024_2, 2025_3 = GameConfig v9).")]
private TrenchBroomVersion m_TrenchBroomVersion = TrenchBroomVersion.Version2026_1;
public bool IsTrenchBroomVersionAtLeast(TrenchBroomVersion version) => (int)m_TrenchBroomVersion >= (int)version;
[SerializeField, Tooltip("The map to use as a template when creating new ones. Leave blank to generate an empty map.")]
private GameObject m_TemplateMap = null;
[SerializeField, Tooltip("The Worldspawn script to use. Use this to set map-wide variables (such as difficulty level, etc.). This affects all maps in your game.")]
private WorldspawnScript m_WorldspawnScript;
// -----------------------------------------------------------------------------------------------------------------------------
// Naming Conventions
// -----------------------------------------------------------------------------------------------------------------------------
[SerializeField, Tooltip("The naming convention to use for entity classes.")]
private NamingConvention m_TypeNamingConvention = NamingConvention.PreserveExact;
[SerializeField, Tooltip("The naming convention to use for variables in TrenchBroom.")]
private NamingConvention m_FieldNamingConvention = NamingConvention.SnakeCase;
[SerializeField, Tooltip("The naming convention to use for SpawnFlag variables in TrenchBroom.")]
private NamingConvention m_SpawnFlagNamingConvention = NamingConvention.HumanFriendly;
[SerializeField, Tooltip("The naming convention to use for materials in TrenchBroom.")]
private NamingConvention m_MaterialNamingConvention = NamingConvention.PreserveExact;
[SerializeField, Tooltip("The name of the property used to identify entities")]
private string m_IdentityPropertyName = "targetname";
// -----------------------------------------------------------------------------------------------------------------------------
// Material Settings
// -----------------------------------------------------------------------------------------------------------------------------
[SerializeField, Tooltip("How to export materials into groups. Leave the group list blank to export ALL materials in the project.")]
private MaterialGroup[] m_MaterialGroups = Array.Empty<MaterialGroup>();
//TODO(jwf): move into MRD below!
[SerializeField, Tooltip("Render settings for materials")]
private List<MaterialRenderData> m_MaterialRenderData = new();
// -----------------------------------------------------------------------------------------------------------------------------
// Pipeline Settings
// -----------------------------------------------------------------------------------------------------------------------------
[SerializeField, Tooltip("Split mesh into smaller meshes for better rendering performance? Turn off if not needed or too slow.")]
private bool m_PipelineSplitMesh = true;
[SerializeField, Tooltip("Smooth mesh normals based on map settings? Turn off for more of a low-poly aesthetic.")]
private bool m_PipelineSmoothMeshNormals = true;
[SerializeField, Tooltip("Simplify collisions to increase runtime performance? Turn off if your meshes don't need this.")]
private bool m_PipelineSimplifyCollisionMeshes = true;
[SerializeField, Tooltip("Unwrap UV2 so that meshes can be lightmapped? Turn off if your project doesn't use lightbaking.")]
private bool m_PipelineUnwrapUV2 = true;
[SerializeField, Tooltip("Run project-wide map processors? Per-map map processors are always run.")]
private bool m_PipelineRunMapProcessors = true;
[SerializeField, Tooltip("Which custom map processors to run. Use Unity 2022+ to enable a better UI for this!")]
private MapProcessorEntry[] m_MapProcessors;
// -----------------------------------------------------------------------------------------------------------------------------
// Advanced Settings
// -----------------------------------------------------------------------------------------------------------------------------
[SerializeField, Tooltip("Print debug info when syncing and importing?")]
private bool m_LogOnImportAndSync = false;
[SerializeField, Tooltip("Allow live updating of maps while in playmode? Not all changes are supported.")]
private bool m_UseLiveUpdate = true;
[SerializeField, Tooltip("Whether to reimport maps when prefabs/materials inside them change?")]
private bool m_AutomaticallyReimportWhenDependencyChanges = true;
[SerializeField, Tooltip("Which kind of gizmos to add to Entities in editor?")]
private EntityIconStyle m_EntityIconStyle = EntityIconStyle.ColouredDiamondShapes;
[SerializeField, Tooltip("Allow prefab overrides on maps? This can cause hard-to-debug issues with materials and field values - but change this if you have a legitimate reason to use overrides (and know what you're doing!)")]
private PrefabOverrideHandling m_PrefabOverrideHandling = PrefabOverrideHandling.AutomaticallyRevert;
[SerializeField, Tooltip("Use class Quake-style culling? This removes all areas inaccessible by point entities, including exteriors. Maps without point/prefabs entities may import blank!")]
private bool m_UseClassicQuakeCulling = false;
[SerializeField, Tooltip("Under which circumstances would you like to see the output from Q3Map2? This can be used to debug map issues.")]
private Q3Map2ResultDisplayType m_Q3Map2ResultDisplayType = Q3Map2ResultDisplayType.ShowWhenWarningsOccur;
[SerializeField, Tooltip("When writing the entities.fgd file for TrenchBroom, how should it be formatted? Very Verbose will be much slower to parse but great for debugging issues manually. We recommend Human Readable.")]
private FgdFormattingStyle m_FgdFormattingStyle = FgdFormattingStyle.HumanReadable;
[SerializeField, Tooltip("Subdivide worldspawn mesh down to the leaf level, ignoring surface area? This could be faster but less efficient at runtime.")]
private bool m_SubdivideAllLeafs;
[SerializeField, Tooltip("Always pack booleans into spawnflags? If off, booleans will separately appear as 0 or 1 values. You can use [SpawnFlags] or [NoSpawnFlags] to override this on a per-field basis.")]
private bool m_AlwaysPackBoolsIntoSpawnFlags = true;
[SerializeField, Tooltip("Show enum values as strings in TrenchBroom? Turn off to use ints, which is faster but a bit more clunky to work with.")]
private bool m_SyncEnumsAsStringValue = true;
[SerializeField, Tooltip("Show all [SerializeField]s in TrenchBroom by default? Use [NoTremble] to override this on a per-field basis, or [Tremble] to mark fields as map-serialisable.")]
private bool m_SyncSerializedFields = true;
[SerializeField, Tooltip("Automatically sync Unity Prefab and Material properties by default? Use [NoTremble] to override this on a per-field basis, or [Tremble] to mark fields as map-serialisable.")]
private bool m_SyncMaterialsAndPrefabs = true;
[SerializeField, Tooltip("The Unity layer to place Worldspawn brushes on.")]
private string m_WorldspawnLayer = "Default";
[SerializeField, Tooltip("Flatten entities and brushes instead of using the groups that were seen in the map?")]
private bool m_DiscardMapGroups = false;
[SerializeField, Tooltip("The name for the 'worldspawn' brush GameObject(s) in Unity.")]
private string m_MainMeshName = "worldspawn";
[SerializeField, Tooltip("Automagically remove TrenchBroom's autosave backups when syncing?")]
private bool m_AutoDeleteMapBackups = false;
[SerializeField, Tooltip("Extra commandline args to pass to Q3Map2 - see https://en.wikibooks.org/wiki/Q3Map2 for more info.")]
private string m_ExtraCommandLineArgs = "-threads 8 -meta -v";
// -----------------------------------------------------------------------------------------------------------------------------
// Advanced Materials
// -----------------------------------------------------------------------------------------------------------------------------
[SerializeField, Tooltip("Determines the base render resolution for materials rendering with Legacy Mode. PLEASE NOTE: Changing this size will affect UVing on your existing maps!")]
private MaterialExportSize m_MaterialExportSize = MaterialExportSize.Size512;
[SerializeField, Tooltip("The light intensity to use when capturing materials (default = 0.5)"), Range(0f, 1f)]
private float m_MaterialCaptureLightIntensity = 0.5f;
[SerializeField, Tooltip("The light angle to use when capturing materials. 0.0 means a perpendicular light, 1.0 means a parallel light. Purely parallel lights can 'blow out' materials with low roughness, but purely perpendicular lights will not illuminate your materials well. (default = 0.75)"), Range(0f, 1f)]
private float m_MaterialCaptureLightAngle = 0.75f;
[SerializeField, Tooltip("Export clip and skip textures?")]
private bool m_ExportClipSkipTextures = true;
// -----------------------------------------------------------------------------------------------------------------------------
// Import Scale
// -----------------------------------------------------------------------------------------------------------------------------
[SerializeField, Tooltip("The scaling to use when importing maps. Default is 0.015625.")]
private float m_ImportScale = 1f / 64f;
// -----------------------------------------------------------------------------------------------------------------------------
// Addressables metadata storage
// -----------------------------------------------------------------------------------------------------------------------------
[SerializeField] private AssetMetadata[] m_AssetMetadatas = null;
public AssetMetadata[] AssetMetadatas
{
get => m_AssetMetadatas;
#if UNITY_EDITOR
set => m_AssetMetadatas = value;
#endif
}
// -----------------------------------------------------------------------------------------------------------------------------
// Public API
// -----------------------------------------------------------------------------------------------------------------------------
// Basic Settings
public bool AutoSyncOnCompile => m_AutoSyncOnCompile;
public bool AllowStandaloneImport => m_AllowStandaloneImport;
public TrenchBroomVersion TrenchBroomVersion => m_TrenchBroomVersion;
public string TrenchBroomGameConfigVersion => TrenchBroomVersion switch
{
TrenchBroomVersion.Version2023_1 => "4",
TrenchBroomVersion.Version2024_1 => "8",
TrenchBroomVersion.Version2024_2 => "9",
TrenchBroomVersion.Version2025_3 => "9",
TrenchBroomVersion.Version2026_1 => "9",
TrenchBroomVersion.VersionNext => "9",
_ => "0"
};
public GameObject TemplateMap => m_TemplateMap;
public WorldspawnScript WorldspawnScript => m_WorldspawnScript;
// Naming Convention
public NamingConvention TypeNamingConvention => m_TypeNamingConvention;
public NamingConvention FieldNamingConvention => m_FieldNamingConvention;
public NamingConvention SpawnFlagNamingConvention => m_SpawnFlagNamingConvention;
public NamingConvention MaterialNamingConvention => m_MaterialNamingConvention;
public string IdentityPropertyName => m_IdentityPropertyName;
// Material Settings
public MaterialGroup[] MaterialGroups => m_MaterialGroups;
public List<MaterialGroup> GetMaterialGroupsOrDefault()
{
List<MaterialGroup> materialGroups = new();
if (m_MaterialGroups is { Length: > 0 })
{
materialGroups.AddRange(m_MaterialGroups);
}
else
{
materialGroups.Add(MaterialGroup.CreateDefault());
}
return materialGroups;
}
public MaterialRenderData GetMaterialRenderData(Material material)
{
MaterialRenderData existing = m_MaterialRenderData.FirstOrDefault(mrd => mrd.Material == material);
if (existing == null)
{
existing = new(material);
m_MaterialRenderData.Add(existing);
}
return existing;
}
// Pipeline Settings
public bool PipelineSplitMesh => m_PipelineSplitMesh;
public bool PipelineSmoothMeshNormals => m_PipelineSmoothMeshNormals;
public bool PipelineSimplifyCollisionMeshes => m_PipelineSimplifyCollisionMeshes;
public bool PipelineUnwrapUV2 => m_PipelineUnwrapUV2;
public bool PipelineRunMapProcessors => m_PipelineRunMapProcessors;
public MapProcessorEntry[] MapProcessors => m_MapProcessors;
public MapProcessorClass[] EnabledMapProcessors => m_MapProcessors == null ? Array.Empty<MapProcessorClass>() : m_MapProcessors.Where(mp => mp.Enabled).Select(mp => mp.Class).ToArray();
// Advanced Settings
public bool LogOnImportAndSync => m_LogOnImportAndSync;
public bool UseLiveUpdate => m_UseLiveUpdate;
public bool AutomaticallyReimportWhenDependencyChanges => m_AutomaticallyReimportWhenDependencyChanges;
public EntityIconStyle EntityIconStyle => m_EntityIconStyle;
public PrefabOverrideHandling PrefabOverrideHandling => m_PrefabOverrideHandling;
public bool UseClassicQuakeCulling => m_UseClassicQuakeCulling;
public Q3Map2ResultDisplayType Q3Map2ResultDisplayType => m_Q3Map2ResultDisplayType;
public FgdFormattingStyle FgdFormattingStyle => m_FgdFormattingStyle;
public bool SubdivideAllLeafs => m_SubdivideAllLeafs;
public bool AlwaysPackBoolsIntoSpawnFlags => m_AlwaysPackBoolsIntoSpawnFlags;
public bool SyncEnumsAsStringValue => m_SyncEnumsAsStringValue;
public bool SyncSerializedFields => m_SyncSerializedFields;
public bool SyncMaterialsAndPrefabs => m_SyncMaterialsAndPrefabs;
public string WorldspawnLayer => m_WorldspawnLayer;
public bool DiscardMapGroups => m_DiscardMapGroups;
public string MainMeshName => m_MainMeshName;
public bool AutoDeleteMapBackups => m_AutoDeleteMapBackups;
public string ExtraCommandLineArgs => m_ExtraCommandLineArgs;
// Advanced materials
public MaterialExportSize MaterialExportSize => m_MaterialExportSize;
public float MaterialCaptureLightIntensity => m_MaterialCaptureLightIntensity;
public float MaterialCaptureLightAngle => m_MaterialCaptureLightAngle;
public bool ExportClipSkipTextures => m_ExportClipSkipTextures;
// Prefixes and Import Scale
public float ImportScale => m_ImportScale;
}
}