feat: initial commit

This commit is contained in:
2025-12-01 12:36:01 +08:00
commit ee78bf2cb5
221 changed files with 56853 additions and 0 deletions

60
.gitattributes vendored Normal file
View File

@@ -0,0 +1,60 @@
## Unity ##
*.cs diff=csharp text
*.cginc text
*.shader text
*.mat merge=unityyamlmerge eol=lf
*.anim merge=unityyamlmerge eol=lf
*.unity merge=unityyamlmerge eol=lf
*.prefab merge=unityyamlmerge eol=lf
*.physicsMaterial2D merge=unityyamlmerge eol=lf
*.physicMaterial merge=unityyamlmerge eol=lf
*.meta merge=unityyamlmerge eol=lf
*.controller merge=unityyamlmerge eol=lf
## git-lfs ##
*.asset filter=lfs diff=lfs merge=lfs -text
#Image
*.jpg filter=lfs diff=lfs merge=lfs -text
*.jpeg filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.gif filter=lfs diff=lfs merge=lfs -text
*.psd filter=lfs diff=lfs merge=lfs -text
*.ai filter=lfs diff=lfs merge=lfs -text
*.tif filter=lfs diff=lfs merge=lfs -text
#Audio
*.mp3 filter=lfs diff=lfs merge=lfs -text
*.wav filter=lfs diff=lfs merge=lfs -text
*.ogg filter=lfs diff=lfs merge=lfs -text
#Video
*.mp4 filter=lfs diff=lfs merge=lfs -text
*.mov filter=lfs diff=lfs merge=lfs -text
#3D Object
*.FBX filter=lfs diff=lfs merge=lfs -text
*.fbx filter=lfs diff=lfs merge=lfs -text
*.blend filter=lfs diff=lfs merge=lfs -text
*.obj filter=lfs diff=lfs merge=lfs -text
#ETC
*.a filter=lfs diff=lfs merge=lfs -text
*.exr filter=lfs diff=lfs merge=lfs -text
*.tga filter=lfs diff=lfs merge=lfs -text
*.tgz filter=lfs diff=lfs merge=lfs -text
*.pdf filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text
*.dll filter=lfs diff=lfs merge=lfs -text
*.unitypackage filter=lfs diff=lfs merge=lfs -text
*.aif filter=lfs diff=lfs merge=lfs -text
*.ttf filter=lfs diff=lfs merge=lfs -text
*.rns filter=lfs diff=lfs merge=lfs -text
*.reason filter=lfs diff=lfs merge=lfs -text
*.lxo filter=lfs diff=lfs merge=lfs -text
*.wasm filter=lfs diff=lfs merge=lfs -text
*.br filter=lfs diff=lfs merge=lfs -text
*.rtf filter=lfs diff=lfs merge=lfs -text

72
.gitignore vendored Normal file
View File

@@ -0,0 +1,72 @@
# This .gitignore file should be placed at the root of your Unity project directory
#
# Get latest from https://github.com/github/gitignore/blob/main/Unity.gitignore
#
/[Ll]ibrary/
/[Tt]emp/
/[Oo]bj/
/[Bb]uild/
/[Bb]uilds/
/[Ll]ogs/
/[Uu]ser[Ss]ettings/
# MemoryCaptures can get excessive in size.
# They also could contain extremely sensitive data
/[Mm]emoryCaptures/
# Recordings can get excessive in size
/[Rr]ecordings/
# Uncomment this line if you wish to ignore the asset store tools plugin
# /[Aa]ssets/AssetStoreTools*
# Autogenerated Jetbrains Rider plugin
/[Aa]ssets/Plugins/Editor/JetBrains*
# Visual Studio cache directory
.vs/
# Gradle cache directory
.gradle/
# Autogenerated VS/MD/Consulo solution and project files
ExportedObj/
.consulo/
*.csproj
*.unityproj
*.sln
*.suo
*.tmp
*.user
*.userprefs
*.pidb
*.booproj
*.svd
*.pdb
*.mdb
*.opendb
*.VC.db
# Unity3D generated meta files
*.pidb.meta
*.pdb.meta
*.mdb.meta
# Unity3D generated file on crash reports
sysinfo.txt
# Builds
*.apk
*.aab
*.unitypackage
*.app
# Crashlytics generated file
crashlytics-build.properties
# Packed Addressables
/[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin*
# Temporary auto-generated Android Assets
/[Aa]ssets/[Ss]treamingAssets/aa.meta
/[Aa]ssets/[Ss]treamingAssets/aa/*

15
.idea/.idea.UnityPackages/.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,15 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/contentModel.xml
/modules.xml
/projectSettingsUpdater.xml
/.idea.UnityPackages.iml
# Ignored default folder with query files
/queries/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

8
Assets/Common.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9e1df7120ddeadc4e94b14619dd59199
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f44b2cdebe2740b68f5b0015217c7c8d
timeCreated: 1763912104

61
Assets/Common/Infrastructure/.gitignore vendored Normal file
View File

@@ -0,0 +1,61 @@
# This .gitignore file should be placed at the root of your Unity project directory
#
# Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore
#
/[Ll]ibrary/
/[Tt]emp/
/[Oo]bj/
/[Bb]uild/
/[Bb]uilds/
/[Ll]ogs/
/[Mm]emoryCaptures/
# Asset meta data should only be ignored when the corresponding asset is also ignored
!/[Aa]ssets/**/*.meta
# Uncomment this line if you wish to ignore the asset store tools plugin
# /[Aa]ssets/AssetStoreTools*
# Autogenerated Jetbrains Rider plugin
[Aa]ssets/Plugins/Editor/JetBrains*
# Visual Studio cache directory
.vs/
.config
# Gradle cache directory
.gradle/
# Autogenerated VS/MD/Consulo solution and project files
ExportedObj/
.consulo/
*.csproj
*.unityproj
*.sln
*.suo
*.tmp
*.user
*.userprefs
*.pidb
*.booproj
*.svd
*.pdb
*.mdb
*.opendb
*.VC.db
# Unity3D generated meta files
*.pidb.meta
*.pdb.meta
*.mdb.meta
# Unity3D generated file on crash reports
sysinfo.txt
# Builds
*.apk
*.unitypackage
# Crashlytics generated file
crashlytics-build.properties

View File

@@ -0,0 +1,12 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.0.0] - 20XX-XX-XX
### Added
- Initial release of the Unity package.

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c45fd6fc3f2b416ca5f97e7d1603e504
timeCreated: 1763912104

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Joe Siu
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: af50d1333b664215ba84f17d6ce050d3
timeCreated: 1763912104

View File

@@ -0,0 +1,8 @@
# com.joesiu.common.infrastructure
## Installation
1. Open `Package Manager`
2. Click `+`
3. Select `Add package from git URL...`
4. Paste `https://github.com/JoeSiu/UnityPackages.git?path=Assets/Common/Infrastructure`

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c83dd7f87dd941cc9eaac8240b529a90
timeCreated: 1763912104

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: bd1d08d357a7453ea2c6973bf965d749
timeCreated: 1763912104

View File

@@ -0,0 +1,12 @@
using UnityEngine;
namespace JoeSiu.Common.Infrastructure.Runtime
{
public class DontDestroyOnLoad : MonoBehaviour
{
private void Awake()
{
DontDestroyOnLoad(gameObject);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e6bbe0c45eed41ba9edaeb03c27d1af7
timeCreated: 1763915394

View File

@@ -0,0 +1,14 @@
{
"name": "Common.Infrastructure.Runtime",
"rootNamespace": "JoeSiu",
"references": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 70e478b7eb804446bc79813af716d369
timeCreated: 1763912104

View File

@@ -0,0 +1,87 @@
using UnityEngine;
namespace JoeSiu.Common.Infrastructure.Runtime
{
public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T>
{
private static T _instance;
public static T Instance
{
get
{
if (_instance) return _instance;
var objs = FindObjectsByType<T>(FindObjectsSortMode.None);
if (objs.Length > 0)
{
AssignInstance(objs[0]);
}
if (objs.Length > 1)
{
for (var index = 1; index < objs.Length; index++)
{
var obj = objs[index];
DestroyDuplicate(obj);
}
}
if (!_instance)
{
Debug.LogWarning(
$"[MonoSingleton] No instance of type '{typeof(T).Name}' is found, make sure to add it in the scene!");
}
return _instance;
}
}
public static T GetInstance() => _instance;
public static void CreateInstance(bool dontDestroyOnLoad = true)
{
var go = new GameObject(typeof(T).Name);
var instance = go.AddComponent<T>();
if (dontDestroyOnLoad) DontDestroyOnLoad(go);
Debug.Log(
$"[MonoSingleton] Created game object '{go.name}' {(dontDestroyOnLoad ? "(DontDestroyOnLoad)" : "")} for type '{typeof(T).Name}'",
go);
AssignInstance(instance);
}
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
public static void RemoveInstance()
{
_instance = null;
Debug.Log($"[MonoSingleton] Removed instance of type '{typeof(T).Name}'");
}
protected virtual void Awake()
{
if (!_instance) AssignInstance(this as T);
else if (_instance != this) DestroyDuplicate(this as T);
}
private static void AssignInstance(T instance)
{
if (!instance) return;
_instance = instance;
Debug.Log($"[MonoSingleton] Assigned instance of type '{typeof(T).Name}' to object '{instance.gameObject.name}'",
instance.gameObject);
}
private static void DestroyDuplicate(T instance)
{
if (!_instance) return;
if (!instance) return;
Debug.LogError(
$"[MonoSingleton] Instance of type '{typeof(T).Name}' is already assigned to object '{_instance.gameObject.name}', destroying duplicate instance '{instance.gameObject.name}'...",
instance.gameObject);
if (Application.isPlaying) Destroy(instance);
else DestroyImmediate(instance);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7fdcac9d0a5a415c8fb702b32809e649
timeCreated: 1763913277

View File

@@ -0,0 +1,57 @@
using UnityEngine;
namespace JoeSiu.Common.Infrastructure.Runtime
{
/// <summary>
/// <see href="https://youtu.be/6kWUGEQiMUI"/>
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class ScriptableObjectSingleton<T> : ScriptableObject where T : ScriptableObjectSingleton<T>
{
private static T _instance;
public static T Instance
{
get
{
if (_instance != null) return _instance;
var assets = Resources.LoadAll<T>("");
if (assets.Length > 0)
{
AssignInstance(assets[0]);
}
if (assets.Length > 1)
{
Debug.LogError(
$"[ScriptableObjectSingleton] More than 1 instance of Singleton Scriptable Object of type: {typeof(T)} found");
}
if (!_instance)
{
Debug.LogWarning(
$"[ScriptableObjectSingleton] No instance of type '{typeof(T).Name}' is found, make sure to add it to the Resources folder!");
}
return _instance;
}
}
public static T GetInstance() => _instance;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
public static void RemoveInstance()
{
_instance = null;
Debug.Log($"[ScriptableObjectSingleton] Removed instance of type '{typeof(T).Name}'");
}
private static void AssignInstance(T instance)
{
if (!instance) return;
_instance = instance;
Debug.Log($"[ScriptableObjectSingleton] Assigned instance of type '{typeof(T).Name}' to object '{instance.name}'", instance);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e2616e8d08c645498cb1486552014786
timeCreated: 1763915451

View File

@@ -0,0 +1,16 @@
{
"name": "com.joesiu.common.infrastructure",
"version": "1.0.0",
"description": "Common scripts for core infrastructure.",
"displayName": "Infrastructure",
"unity": "2019.4",
"author": {
"name": "Joe Siu",
"url": "https://github.com/JoeSiu"
},
"changelogUrl": "https://github.com/JoeSiu/UnityPackages/blob/main/CHANGELOG.md",
"dependencies": {},
"documentationUrl": "https://github.com/JoeSiu/UnityPackages/",
"keywords": [],
"licensesUrl": "https://github.com/JoeSiu/UnityPackages/blob/main/LICENSE.md"
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c0c0741ec91f4e83b31c3346f9ba5e6a
timeCreated: 1763912104

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b29cafa929b60184fa189b4cb045828b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

61
Assets/Common/Serialization/.gitignore vendored Normal file
View File

@@ -0,0 +1,61 @@
# This .gitignore file should be placed at the root of your Unity project directory
#
# Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore
#
/[Ll]ibrary/
/[Tt]emp/
/[Oo]bj/
/[Bb]uild/
/[Bb]uilds/
/[Ll]ogs/
/[Mm]emoryCaptures/
# Asset meta data should only be ignored when the corresponding asset is also ignored
!/[Aa]ssets/**/*.meta
# Uncomment this line if you wish to ignore the asset store tools plugin
# /[Aa]ssets/AssetStoreTools*
# Autogenerated Jetbrains Rider plugin
[Aa]ssets/Plugins/Editor/JetBrains*
# Visual Studio cache directory
.vs/
.config
# Gradle cache directory
.gradle/
# Autogenerated VS/MD/Consulo solution and project files
ExportedObj/
.consulo/
*.csproj
*.unityproj
*.sln
*.suo
*.tmp
*.user
*.userprefs
*.pidb
*.booproj
*.svd
*.pdb
*.mdb
*.opendb
*.VC.db
# Unity3D generated meta files
*.pidb.meta
*.pdb.meta
*.mdb.meta
# Unity3D generated file on crash reports
sysinfo.txt
# Builds
*.apk
*.unitypackage
# Crashlytics generated file
crashlytics-build.properties

View File

@@ -0,0 +1,12 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.0.0] - 2025-11-24
### Added
- Initial release of the Unity package.

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 6aab4fa9da7c1124a96e9c0838a1b12e
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Joe Siu
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 6333dc7bfd551ae4c82c1586a89dbc41
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
# com.joesiu.common.serialization
## Installation
1. Open `Package Manager`
2. Click `+`
3. Select `Add package from git URL...`
4. Paste `https://github.com/JoeSiu/UnityPackages.git?path=Assets/Common/Serialization`

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9396f0bf3b325ff48ba7029d107c30fa
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 98bbeb42106339546b8f985f042e2a8f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,14 @@
{
"name": "Common.Serialization.Runtime",
"rootNamespace": "JoeSiu",
"references": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d7f6647327e7fa54faec2c8e2a49621d
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,138 @@
#region License and Information
/*****
* Provides a serializable wrapper that allows you to store a reference to
* a serialized UnityEngine.Object that implement a certain interface.
* The "Instance" property provides direct easy access to the serialized reference.
* This should work with Components as well as ScriptableObjects.
* It ships with a convenient property drawer that should streamline the usage.
*
* Copyright (c) 2023 Bunny83
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*****/
#endregion License and Information
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
namespace JoeSiu.Common.Serialization.Runtime
{
[Serializable]
public class SerializableInterface<T> where T : class
{
[SerializeField]
private Object _obj;
private T _value;
public SerializableInterface()
{
}
public SerializableInterface(T value)
{
SetValue(value);
}
public T Value
{
get => GetValue();
set => SetValue(value);
}
public T GetValue()
{
if (_value != null && (object)_value == _obj) return _value;
if (_obj == null) SetValue(null);
else if (_obj is T inst || _obj is GameObject go && go.TryGetComponent(out inst)) _value = inst;
else SetValue(null);
return _value;
}
private void SetValue(T value)
{
_value = value;
_obj = _value as Object;
}
}
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(SerializableInterface<>), true)]
public class SerializableInterfacePropertyDrawer : PropertyDrawer
{
private Type _genericType;
private readonly List<Component> _list = new();
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
if (_genericType == null)
{
var fieldType = fieldInfo.FieldType;
if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(List<>))
// when used in a List<>, grab the actual type from the generic argument of the List
fieldType = fieldInfo.FieldType.GetGenericArguments()[0];
else if (fieldType.IsArray)
// when used in an array, grab the actual type from the element type.
fieldType = fieldType.GetElementType();
var types = fieldType?.GetGenericArguments();
if (types is { Length: 1 }) _genericType = types[0];
}
var obj = property.FindPropertyRelative("_obj");
EditorGUI.BeginChangeCheck();
var newObj = EditorGUI.ObjectField(position, label, obj.objectReferenceValue, typeof(Object), true);
if (!EditorGUI.EndChangeCheck()) return;
if (newObj == null) obj.objectReferenceValue = null;
else if (_genericType != null && _genericType.IsAssignableFrom(newObj.GetType())) obj.objectReferenceValue = newObj;
else if (newObj is GameObject go)
{
_list.Clear();
go.GetComponents(_genericType, _list);
if (_list.Count == 1)
{
obj.objectReferenceValue = _list[0];
}
else
{
var m = new GenericMenu();
var n = 1;
foreach (var item in _list)
m.AddItem(new GUIContent(n++ + " " + item.GetType().Name), false, a =>
{
obj.objectReferenceValue = (Object)a;
obj.serializedObject.ApplyModifiedProperties();
}, item);
m.ShowAsContext();
}
}
else
{
Debug.LogWarning("Dragged object is not compatible with " + _genericType?.Name);
}
}
}
#endif
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: c8df361f2765f214eba36fc0fb21a063

View File

@@ -0,0 +1,16 @@
{
"name": "com.joesiu.common.serialization",
"version": "1.0.0",
"description": "Common scripts for serialization.",
"displayName": "Serialization",
"unity": "2019.4",
"author": {
"name": "Joe Siu",
"url": "https://github.com/JoeSiu"
},
"changelogUrl": "https://github.com/JoeSiu/UnityPackages/blob/main/CHANGELOG.md",
"dependencies": {},
"documentationUrl": "https://github.com/JoeSiu/UnityPackages/",
"keywords": [],
"licensesUrl": "https://github.com/JoeSiu/UnityPackages/blob/main/LICENSE.md"
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 10f90d0d9e83df748a3118d0fd3a1560
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
Assets/Common/Timer.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9337a80e883c06b43bb8045f50ce8fc8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

61
Assets/Common/Timer/.gitignore vendored Normal file
View File

@@ -0,0 +1,61 @@
# This .gitignore file should be placed at the root of your Unity project directory
#
# Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore
#
/[Ll]ibrary/
/[Tt]emp/
/[Oo]bj/
/[Bb]uild/
/[Bb]uilds/
/[Ll]ogs/
/[Mm]emoryCaptures/
# Asset meta data should only be ignored when the corresponding asset is also ignored
!/[Aa]ssets/**/*.meta
# Uncomment this line if you wish to ignore the asset store tools plugin
# /[Aa]ssets/AssetStoreTools*
# Autogenerated Jetbrains Rider plugin
[Aa]ssets/Plugins/Editor/JetBrains*
# Visual Studio cache directory
.vs/
.config
# Gradle cache directory
.gradle/
# Autogenerated VS/MD/Consulo solution and project files
ExportedObj/
.consulo/
*.csproj
*.unityproj
*.sln
*.suo
*.tmp
*.user
*.userprefs
*.pidb
*.booproj
*.svd
*.pdb
*.mdb
*.opendb
*.VC.db
# Unity3D generated meta files
*.pidb.meta
*.pdb.meta
*.mdb.meta
# Unity3D generated file on crash reports
sysinfo.txt
# Builds
*.apk
*.unitypackage
# Crashlytics generated file
crashlytics-build.properties

View File

@@ -0,0 +1,12 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.0.0] - 2025-11-24
### Added
- Initial release of the Unity package.

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b59e8b83170e79e49bb382cbd8bb2e47
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Joe Siu
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 26de4860f9f29e146a42655c17acb7a8
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
# com.joesiu.common.timer
## Installation
1. Open `Package Manager`
2. Click `+`
3. Select `Add package from git URL...`
4. Paste `https://github.com/JoeSiu/UnityPackages.git?path=Assets/Common/Timer`

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 5ba592ce62241954c91a14eb83c32366
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2fab66aac1f04504db2f990f40887a73
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,20 @@
using System;
namespace Common.Timer.Runtime
{
public interface IStopwatch : ITimer
{
public float Duration { get; set; }
public bool DeactivateOnTimeReached { get; set; }
public float RemainingTime { get; set; }
public float Progress { get; set; }
public bool IsTimeReached => CurrentTime >= Duration;
public event Action OnTimeReached;
public void SetDuration(float value);
public void SetRemainingTime(float value);
public void SetProgress(float value);
public void EndTime();
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 7d400d4cccd55e94088df52dfd4cbb96

View File

@@ -0,0 +1,23 @@
using System;
namespace Common.Timer.Runtime
{
public interface ITimer
{
public bool IsActive { get; }
public float CurrentTime { get; set; }
public float DeltaTime { get; }
public void Tick();
public void Activate(bool resetTime = false);
public void Deactivate();
public void ResetTime();
public void SetTime(float value);
public event Action OnTick;
public event Action OnActivate;
public event Action OnDeactivate;
public event Action OnTimeReset;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 166ad9d07eff7ce409885714f6cddd55

View File

@@ -0,0 +1,20 @@
{
"name": "Common.Timer.Runtime",
"rootNamespace": "JoeSiu",
"references": [
"GUID:75469ad4d38634e559750d17036d5f7c",
"GUID:6055be8ebefd69e48b49212b09b47b2f",
"GUID:324caed91501a9c47a04ebfd87b68794",
"GUID:d7f6647327e7fa54faec2c8e2a49621d",
"GUID:70e478b7eb804446bc79813af716d369"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 4867374f8b89f5b4587d9170bed9e856
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,104 @@
using System;
using TriInspector;
using UnityEngine;
namespace Common.Timer.Runtime
{
public class MonoStopwatch : MonoTimer, IStopwatch
{
public override float CurrentTime
{
get
{
currentTime = Mathf.Clamp(currentTime, 0f, Duration);
return currentTime;
}
set => currentTime = Mathf.Clamp(value, 0f, Duration);
}
[Title("Settings (Stopwatch)")]
[SerializeField]
protected float duration;
[Group("Internal"), ShowInInspector, DisableInEditMode]
public virtual float Duration
{
get
{
duration = Mathf.Max(0.001f, duration);
return duration;
}
set => duration = Mathf.Max(0.001f, value);
}
[SerializeField]
protected bool deactivateOnTimeReached;
public bool DeactivateOnTimeReached
{
get => deactivateOnTimeReached;
set => deactivateOnTimeReached = value;
}
[Group("Internal"), ShowInInspector, DisableInEditMode]
public virtual float RemainingTime
{
get => Mathf.Clamp(Duration - CurrentTime, 0f, Duration);
set => CurrentTime = Mathf.Clamp(Duration - value, 0f, Duration);
}
[Group("Internal"), ShowInInspector, DisableInEditMode]
public virtual float Progress
{
get => Duration == 0f ? 0f : Mathf.Clamp(CurrentTime / Duration, 0f, 1f);
set => CurrentTime = Mathf.Clamp(Duration * value, 0f, Duration);
}
[Group("Internal"), ReadOnly, ShowInInspector, DisableInEditMode]
public virtual bool IsTimeReached => CurrentTime >= Duration;
public event Action OnTimeReached;
public override void Tick()
{
if (IsTimeReached) return;
base.Tick();
if (!IsActive) return;
if (CurrentTime >= Duration) EndTime();
}
public virtual void SetDuration(float value)
{
Duration = value;
if (IsTimeReached) EndTime();
}
public virtual void SetRemainingTime(float value)
{
RemainingTime = value;
if (IsTimeReached) EndTime();
}
public virtual void SetProgress(float value)
{
Progress = value;
if (IsTimeReached) EndTime();
}
public virtual void EndTime()
{
currentTime = Duration;
InvokeOnTimeReached();
if (DeactivateOnTimeReached) Deactivate();
}
protected virtual void InvokeOnTimeReached()
{
OnTimeReached?.Invoke();
}
#if UNITY_EDITOR
[Group("Debug"), Button("End Time"), HideInEditMode]
private void EndTimer_Editor() => EndTime();
#endif
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 7152de60fabb33c41aebca0a58b2096b

View File

@@ -0,0 +1,109 @@
using System;
using TriInspector;
using UnityEngine;
namespace Common.Timer.Runtime
{
[DeclareBoxGroup("Debug")]
[DeclareBoxGroup("Internal")]
// TODO: Create a MonoTimerBase similar to TimerBaseSO instead
public class MonoTimer : MonoBehaviour, ITimer
{
[Title("Settings")]
[SerializeField]
protected bool isActive;
public virtual bool IsActive
{
get => isActive;
protected set => isActive = value;
}
protected float currentTime;
[Group("Internal"), ShowInInspector, DisableInEditMode]
public virtual float CurrentTime
{
get
{
currentTime = Mathf.Max(currentTime, 0f);
return currentTime;
}
set => currentTime = Mathf.Max(value, 0f);
}
[Group("Internal"), ShowInInspector, DisableInEditMode]
public virtual float DeltaTime => Time.deltaTime;
public event Action OnTick;
public event Action OnActivate;
public event Action OnDeactivate;
public event Action OnTimeReset;
protected virtual void Update()
{
Tick();
}
#region Public Methods
public virtual void Tick()
{
if (!IsActive) return;
CurrentTime += DeltaTime;
InvokeOnTick();
}
public virtual void Activate(bool resetTime = false)
{
IsActive = true;
InvokeOnActivate();
if (resetTime) ResetTime();
}
public virtual void Deactivate()
{
IsActive = false;
InvokeOnDeactivate();
}
public virtual void ResetTime()
{
CurrentTime = 0f;
InvokeOnTimeReset();
}
public virtual void SetTime(float value)
{
CurrentTime = value;
}
#endregion
#region Protected Methods
protected virtual void InvokeOnTick() => OnTick?.Invoke();
protected virtual void InvokeOnActivate() => OnActivate?.Invoke();
protected virtual void InvokeOnDeactivate() => OnDeactivate?.Invoke();
protected virtual void InvokeOnTimeReset() => OnTimeReset?.Invoke();
#endregion
#if UNITY_EDITOR
[Group("Debug"), Button("Activate"), HideInEditMode]
private void Activate_Editor() => Activate(false);
[Group("Debug"), Button("Activate (Reset Time)"), HideInEditMode]
private void ActivateResetTime_Editor() => Activate(true);
[Group("Debug"), Button("Deactivate"), HideInEditMode]
private void Deactivate_Editor() => Deactivate();
[Group("Debug"), Button("Tick"), HideInEditMode]
private void Tick_Editor() => Tick();
[Group("Debug"), Button("Reset Time"), HideInEditMode]
private void ResetTime_Editor() => ResetTime();
#endif
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 34fac720fb4287843aea355b0594eda1

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 84762aa781ebe084290160322bc621e3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,62 @@
using System;
using TriInspector;
using UnityEngine;
namespace Common.Timer.Runtime.ScriptableObjects
{
[CreateAssetMenu(fileName = "Stopwatch", menuName = "JoeSiu/Common/Stopwatch")]
public class StopwatchSO : TimerBaseSO, IStopwatch
{
protected override ITimer Timer => _stopwatch;
[SerializeField, InlineProperty, HideLabel]
[InfoBox("The stopwatch in ScriptableObject will be deactivated by default")]
private Stopwatch _stopwatch = new(false, 10f);
public float Duration
{
get => _stopwatch.Duration;
set => _stopwatch.Duration = value;
}
public float RemainingTime
{
get => _stopwatch.RemainingTime;
set => _stopwatch.RemainingTime = value;
}
public float Progress
{
get => _stopwatch.Progress;
set => _stopwatch.Progress = value;
}
public bool IsTimeReached => _stopwatch.IsTimeReached;
public bool DeactivateOnTimeReached
{
get => _stopwatch.DeactivateOnTimeReached;
set => _stopwatch.DeactivateOnTimeReached = value;
}
public event Action OnTimeReached
{
add => _stopwatch.OnTimeReached += value;
remove => _stopwatch.OnTimeReached -= value;
}
protected override void Activate_Internal(bool resetTime = false)
{
_stopwatch.Activate(resetTime);
}
public virtual void SetDuration(float value) => _stopwatch.SetDuration(value);
public virtual void SetRemainingTime(float value) => _stopwatch.SetRemainingTime(value);
public virtual void SetProgress(float value) => _stopwatch.SetProgress(value);
public void EndTime() => _stopwatch.EndTime();
public override void Reinitialize()
{
_stopwatch = new(false, _stopwatch.Duration);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: bef3fff7f3888464aab61a599e9a460a

View File

@@ -0,0 +1,113 @@
using System;
using TriInspector;
using UnityEditor;
using UnityEngine;
namespace Common.Timer.Runtime.ScriptableObjects
{
public abstract class TimerBaseSO : ScriptableObject, ITimer
{
protected abstract ITimer Timer { get; }
public bool IsActive => Timer.IsActive;
public float CurrentTime
{
get => Timer.CurrentTime;
set => Timer.CurrentTime = value;
}
public float DeltaTime => Timer.DeltaTime;
public void Tick() => Timer.Tick();
public void Activate(bool resetTime = false)
{
AddToManager();
Activate_Internal(resetTime);
}
public void Deactivate() => Timer.Deactivate();
public void ResetTime() => Timer.ResetTime();
public virtual void SetTime(float value)
{
CurrentTime = value;
}
public event Action OnTick
{
add => Timer.OnTick += value;
remove => Timer.OnTick -= value;
}
public event Action OnActivate
{
add => Timer.OnActivate += value;
remove => Timer.OnActivate -= value;
}
public event Action OnDeactivate
{
add => Timer.OnDeactivate += value;
remove => Timer.OnDeactivate -= value;
}
public event Action OnTimeReset
{
add => Timer.OnTimeReset += value;
remove => Timer.OnTimeReset -= value;
}
protected abstract void Activate_Internal(bool resetTime = false);
private void AddToManager()
{
if (!TimerManager.GetInstance()) TimerManager.CreateInstance();
TimerManager.Instance.Add(this);
}
private void RemoveFromManager()
{
if (!TimerManager.GetInstance()) return;
TimerManager.Instance.Remove(this);
}
#if UNITY_EDITOR
protected virtual void OnPlayModeStateChanged(PlayModeStateChange state)
{
if (state == PlayModeStateChange.ExitingPlayMode)
{
Reinitialize();
}
}
#endif
#if UNITY_EDITOR
protected virtual void OnValidate()
{
if (!EditorApplication.isPlaying) Timer.Deactivate();
}
#endif
protected virtual void OnEnable()
{
#if UNITY_EDITOR
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
#endif
}
protected virtual void OnDisable()
{
#if UNITY_EDITOR
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
#endif
}
protected virtual void OnDestroy()
{
#if UNITY_EDITOR
Reinitialize();
#endif
}
[Button]
public abstract void Reinitialize();
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 312c8c00ee578df428063b28e6322aed

View File

@@ -0,0 +1,25 @@
using TriInspector;
using UnityEngine;
namespace Common.Timer.Runtime.ScriptableObjects
{
[CreateAssetMenu(fileName = "Timer", menuName = "JoeSiu/Common/Timer")]
public class TimerSO : TimerBaseSO
{
protected override ITimer Timer => _timer;
[SerializeField, InlineProperty, HideLabel]
[InfoBox("The timer in ScriptableObject will be deactivated by default")]
private Timer _timer = new(false);
protected override void Activate_Internal(bool resetTime = false)
{
_timer.Activate(resetTime);
}
public override void Reinitialize()
{
_timer = new(false);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: cc4e8df518cd7244dbdfc3464c604bed

View File

@@ -0,0 +1,120 @@
using System;
using TriInspector;
using UnityEngine;
using UnityEngine.Serialization;
namespace Common.Timer.Runtime
{
[Serializable]
public class Stopwatch : Timer, IStopwatch
{
public override float CurrentTime
{
get
{
currentTime = Mathf.Clamp(currentTime, 0f, Duration);
return currentTime;
}
set => currentTime = Mathf.Clamp(value, 0f, Duration);
}
[Title("Settings (Stopwatch)")]
[SerializeField]
[FormerlySerializedAs("_duration")]
protected float duration;
[Group("Internal"), ShowInInspector, DisableInEditMode]
public virtual float Duration
{
get
{
duration = Mathf.Max(0.001f, duration);
return duration;
}
set => duration = Mathf.Max(0.001f, value);
}
[SerializeField]
[FormerlySerializedAs("_deactivateOnTimeReached")]
protected bool deactivateOnTimeReached;
public bool DeactivateOnTimeReached
{
get => deactivateOnTimeReached;
set => deactivateOnTimeReached = value;
}
[Group("Internal"), ShowInInspector, DisableInEditMode]
public virtual float RemainingTime
{
get => Mathf.Clamp(Duration - CurrentTime, 0f, Duration);
set => CurrentTime = Mathf.Clamp(Duration - value, 0f, Duration);
}
[Group("Internal"), ShowInInspector, DisableInEditMode]
public virtual float Progress
{
get => Duration == 0f ? 0f : Mathf.Clamp(CurrentTime / Duration, 0f, 1f);
set => CurrentTime = Mathf.Clamp(Duration * value, 0f, Duration);
}
[Group("Internal"), ReadOnly, ShowInInspector, DisableInEditMode]
public virtual bool IsTimeReached => CurrentTime >= Duration;
public event Action OnTimeReached;
public Stopwatch(bool isActive, float duration, bool deactivateOnTimeReached = false) : base(isActive)
{
this.duration = duration;
this.deactivateOnTimeReached = deactivateOnTimeReached;
}
public override void Tick()
{
if (IsTimeReached) return;
base.Tick();
if (!IsActive) return;
if (IsTimeReached) EndTime();
}
public override void SetTime(float value)
{
CurrentTime = value;
if (IsTimeReached) EndTime();
}
public virtual void SetDuration(float value)
{
Duration = value;
if (IsTimeReached) EndTime();
}
public virtual void SetRemainingTime(float value)
{
RemainingTime = value;
if (IsTimeReached) EndTime();
}
public virtual void SetProgress(float value)
{
Progress = value;
if (IsTimeReached) EndTime();
}
public virtual void EndTime()
{
currentTime = Duration;
InvokeOnTimeReached();
if (DeactivateOnTimeReached) Deactivate();
}
protected virtual void InvokeOnTimeReached()
{
OnTimeReached?.Invoke();
}
#if UNITY_EDITOR
[Group("Debug"), Button("End Time"), HideInEditMode]
private void EndTimer_Editor() => EndTime();
#endif
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: deafc70d1d6a826429baf2f506837603

View File

@@ -0,0 +1,114 @@
using System;
using TriInspector;
using UnityEngine;
using UnityEngine.Serialization;
namespace Common.Timer.Runtime
{
/// <summary>
/// C# implementation of a timer. Remember to call Tick() on this Timer object via script!
/// </summary>
[Serializable]
[DeclareBoxGroup("Debug")]
[DeclareBoxGroup("Internal")]
public class Timer : ITimer
{
[Title("Settings")]
[SerializeField]
[FormerlySerializedAs("_isActive")]
protected bool isActive;
public virtual bool IsActive
{
get => isActive;
protected set => isActive = value;
}
protected float currentTime;
[Group("Internal"), ShowInInspector, DisableInEditMode]
public virtual float CurrentTime
{
get
{
currentTime = Mathf.Max(currentTime, 0f);
return currentTime;
}
set => currentTime = Mathf.Max(value, 0f);
}
[Group("Internal"), ShowInInspector, DisableInEditMode]
public virtual float DeltaTime => Time.deltaTime;
public event Action OnTick;
public event Action OnActivate;
public event Action OnDeactivate;
public event Action OnTimeReset;
public Timer(bool isActive)
{
this.isActive = isActive;
}
#region Public Methods
public virtual void Tick()
{
if (!IsActive) return;
CurrentTime += DeltaTime;
InvokeOnTick();
}
public virtual void Activate(bool resetTime = false)
{
IsActive = true;
InvokeOnActivate();
if (resetTime) ResetTime();
}
public virtual void Deactivate()
{
IsActive = false;
InvokeOnDeactivate();
}
public virtual void ResetTime()
{
CurrentTime = 0f;
InvokeOnTimeReset();
}
public virtual void SetTime(float value)
{
CurrentTime = value;
}
#endregion
#region Protected Methods
protected virtual void InvokeOnTick() => OnTick?.Invoke();
protected virtual void InvokeOnActivate() => OnActivate?.Invoke();
protected virtual void InvokeOnDeactivate() => OnDeactivate?.Invoke();
protected virtual void InvokeOnTimeReset() => OnTimeReset?.Invoke();
#endregion
#if UNITY_EDITOR
[Group("Debug"), Button("Activate"), HideInEditMode]
private void Activate_Editor() => Activate(false);
[Group("Debug"), Button("Activate (Reset Time)"), HideInEditMode]
private void ActivateResetTime_Editor() => Activate(true);
[Group("Debug"), Button("Deactivate"), HideInEditMode]
private void Deactivate_Editor() => Deactivate();
[Group("Debug"), Button("Tick"), HideInEditMode]
private void Tick_Editor() => Tick();
[Group("Debug"), Button("Reset Time"), HideInEditMode]
private void ResetTime_Editor() => ResetTime();
#endif
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 64b5ad6c3a3b3934892167377d2ff419

View File

@@ -0,0 +1,41 @@
using System.Collections.Generic;
using Common.Timer.Runtime.ScriptableObjects;
using JoeSiu.Common.Infrastructure.Runtime;
using TriInspector;
using UnityEngine;
namespace Common.Timer.Runtime
{
public class TimerManager : MonoSingleton<TimerManager>
{
[InfoBox("As ScriptableObject doesn't have Update() function, use this class to control the ScriptableObject timer's tick")]
[SerializeField]
private List<TimerBaseSO> _timerSOs = new();
public IReadOnlyList<TimerBaseSO> TimerSOs => _timerSOs.AsReadOnly();
protected override void Awake()
{
base.Awake();
DontDestroyOnLoad(this);
}
private void Update()
{
_timerSOs.ForEach(so => so?.Tick());
}
public void Add(TimerBaseSO timerBaseSO)
{
if (_timerSOs.Contains(timerBaseSO)) return;
_timerSOs.Add(timerBaseSO);
Debug.Log($"Added TimerBaseSO '{timerBaseSO.name}' to {nameof(TimerManager)}", this);
}
public void Remove(TimerBaseSO timerBaseSO)
{
if (!_timerSOs.Contains(timerBaseSO)) return;
_timerSOs.Remove(timerBaseSO);
Debug.Log( $"Removed TimerBaseSO '{timerBaseSO.name}' from {nameof(TimerManager)}", this);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 477f0034741527640a767bbcb0c42a01

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6346ab71a8da1784c84e99bf10a88384
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,68 @@
using System;
using JoeSiu.Common.Serialization.Runtime;
using TMPro;
using UnityEditor;
using UnityEngine;
namespace Common.Timer.Runtime.UI
{
public class TimerDebugText : MonoBehaviour
{
[SerializeField]
private SerializableInterface<ITimer> _timer = new();
public TMP_Text text;
public string prefix;
public int decimalPlaces = 2;
public ITimer Timer
{
get => _timer.Value;
set => _timer.Value = value;
}
private void Reset()
{
text = GetComponent<TMP_Text>();
}
private void OnValidate()
{
#if UNITY_EDITOR
if (!EditorApplication.isPlaying && Selection.Contains(gameObject)) UpdateText(Timer);
#endif
}
private void Update()
{
UpdateText(Timer);
}
public void UpdateText(ITimer timer)
{
if (!text) return;
if (timer == null) return;
var format = $"F{decimalPlaces}";
var info = string.IsNullOrEmpty(prefix) ? "" : $"{prefix}\n";
if (timer is Behaviour behaviour) info += $"enabled: {behaviour.enabled}\n";
info += $"active: {timer.IsActive}\n";
switch (timer)
{
// Check if timer implements IStopwatch
case IStopwatch stopwatch:
info += $"isTimeReached: {stopwatch.IsTimeReached}\n";
info += $"{Math.Round(stopwatch.CurrentTime, decimalPlaces).ToString(format)}s / " +
$"{Math.Round(stopwatch.Duration, decimalPlaces).ToString(format)}s " +
$"(remain: {Math.Round(stopwatch.RemainingTime, decimalPlaces).ToString(format)}s)\n";
break;
// Fallback for base Timer class
default:
info += $"{Math.Round(timer.CurrentTime, decimalPlaces).ToString(format)}s\n";
break;
}
text.text = info;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 9449292013eda4945bf3f8bc3ba3b52d

View File

@@ -0,0 +1,79 @@
using System;
using JoeSiu.Common.Serialization.Runtime;
using TMPro;
using TriInspector;
using UnityEditor;
using UnityEngine;
namespace Common.Timer.Runtime.UI
{
[ExecuteAlways]
public class TimerDurationText : MonoBehaviour
{
public TMP_Text text;
[SerializeField]
private SerializableInterface<ITimer> _timer = new();
#if UNITY_EDITOR
[ShowIf(nameof(IsStopwatch))]
#endif
public bool useRemainingTimeForStopwatch = true;
[Range(0, 15)]
public int precision = 0;
[Range(0, 15)]
public int padLeft = 0;
[Range(0, 15)]
public int padRight = 0;
#if UNITY_EDITOR
private bool IsStopwatch => Timer is IStopwatch;
#endif
public ITimer Timer
{
get => _timer?.Value;
set => _timer.Value = value;
}
private void Reset()
{
text = GetComponent<TMP_Text>();
}
private void OnValidate()
{
#if UNITY_EDITOR
if (!EditorApplication.isPlaying && Selection.Contains(gameObject)) UpdateText(Timer);
#endif
}
private void Update()
{
UpdateText(Timer);
}
public void UpdateText(ITimer timer)
{
if (!text) return;
if (timer == null) return;
float time;
if (useRemainingTimeForStopwatch && timer is IStopwatch stopwatch)
{
time = stopwatch.RemainingTime;
}
else
{
time = timer.CurrentTime;
}
time = (float)Math.Round(time, precision);
var timeString = time.ToString();
// TODO: PadLeft / PadRight doesn't work in all cases (e.g., given time of 1, it can't turn into 01.00)
// TODO: Use a custom user defined formatter instead?
if (padLeft > 0) timeString = timeString.PadLeft(padLeft, '0');
if (padRight > 0) timeString = timeString.PadRight(padRight, '0');
text.SetText(timeString);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a872f72d4d5d8e94895cff23a747e3f0

View File

@@ -0,0 +1,20 @@
{
"name": "com.joesiu.common.timer",
"version": "1.0.0",
"description": "Set of timer and stopwatch components.",
"displayName": "Timer",
"unity": "2019.4",
"author": {
"name": "Joe Siu",
"url": "https://github.com/JoeSiu"
},
"changelogUrl": "https://github.com/JoeSiu/UnityPackages/blob/main/CHANGELOG.md",
"dependencies": {
"com.codewriter.triinspector": "https://github.com/codewriter-packages/Tri-Inspector.git",
"com.joesiu.common.infrastructure": "https://github.com/JoeSiu/UnityPackages.git?path=Assets/Common/Infrastructure",
"com.joesiu.common.serialization": "https://github.com/JoeSiu/UnityPackages.git?path=Assets/Common/Serialization"
},
"documentationUrl": "https://github.com/JoeSiu/UnityPackages/",
"keywords": [],
"licensesUrl": "https://github.com/JoeSiu/UnityPackages/blob/main/LICENSE.md"
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: cb89a7fa74c613b41b84b47ad22e88aa
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,61 @@
@echo off
setlocal enabledelayedexpansion
:: Default values
set "company_name=joesiu"
set "package_name=common.package-name"
set "package_display_name=Package Display Name"
set "package_description=This is an example package description."
set "git_url=https://github.com/JoeSiu/UnityPackages"
set "package_path=Assets/Common/"
set "author_name=Joe Siu"
set "author_url=https://github.com/JoeSiu"
:: Get user input with defaults
echo.
set /p "input_company_name=Enter company_name [%company_name%]: "
if not "!input_company_name!"=="" set "company_name=!input_company_name!"
echo.
set /p "input_package_name=Enter package_name [%package_name%]: "
if not "!input_package_name!"=="" set "package_name=!input_package_name!"
echo.
set /p "input_package_display_name=Enter package_display_name [%package_display_name%]: "
if not "!input_package_display_name!"=="" set "package_display_name=!input_package_display_name!"
echo.
set /p "input_package_description=Enter package_description [%package_description%]: "
if not "!input_package_description!"=="" set "package_description=!input_package_description!"
echo.
set /p "input_git_url=Enter git_url [%git_url%]: "
if not "!input_git_url!"=="" set "git_url=!input_git_url!"
echo.
set /p "input_package_path=Enter package_path [%package_path%]: "
if not "!input_package_path!"=="" set "package_path=!input_package_path!"
echo.
set /p "input_author_name=Enter author_name [%author_name%]: "
if not "!input_author_name!"=="" set "author_name=!input_author_name!"
echo.
set /p "input_author_url=Enter author_url [%author_url%]: "
if not "!input_author_url!"=="" set "author_url=!input_author_url!"
:: Update files
echo.
echo Updating variables ^& filenames...
:: Use PowerShell to update file contents (excluding .git folder and batch files)
powershell -Command "$companyName='%company_name%'; $packageName='%package_name%'; $displayName='%package_display_name%'; $description='%package_description%'; $gitUrl='%git_url%'; $packagePath='%package_path%'; $authorName='%author_name%'; $authorUrl='%author_url%'; Get-ChildItem -Recurse -File | Where-Object { $_.FullName -notmatch '\\.git' -and $_.Extension -ne '.bat' } | ForEach-Object { $content = [System.IO.File]::ReadAllText($_.FullName); $content = $content -replace '\[company-name\]', $companyName -replace '\[package-name\]', $packageName -replace '\[package-display-name\]', $displayName -replace '\[package-description\]', $description -replace '\[git-url\]', $gitUrl -replace '\[package-path\]', $packagePath -replace '\[author-name\]', $authorName -replace '\[author_name\]', $authorName -replace '\[author-url\]', $authorUrl; [System.IO.File]::WriteAllText($_.FullName, $content) }"
:: Rename files (excluding .git folder and batch files)
powershell -Command "$companyName='%company_name%'; $packageName='%package_name%'; Get-ChildItem -Recurse -File | Where-Object { $_.FullName -notmatch '\\.git' -and $_.Extension -ne '.bat' -and ($_.Name -match '\[company-name\]\.\[package-name\]' -or $_.Name -match '^\[package-name\]') } | ForEach-Object { $dir = $_.DirectoryName; $newName = $_.Name -replace '\[company-name\]\.\[package-name\]', ($companyName + '.' + $packageName) -replace '^\[package-name\]', $packageName; Rename-Item -LiteralPath $_.FullName -NewName $newName }"
echo.
echo DONE!
echo.
pause

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,14 @@
fileFormatVersion: 2
guid: 052faaac586de48259a63d0c4782560b
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 11500000, guid: 8404be70184654265930450def6a9037, type: 3}
generateWrapperCode: 0
wrapperCodePath:
wrapperClassName:
wrapperCodeNamespace:

8
Assets/Scenes.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 66b0ddf5b73dc514e8b995ed94b4235e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,432 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!29 &1
OcclusionCullingSettings:
m_ObjectHideFlags: 0
serializedVersion: 2
m_OcclusionBakeSettings:
smallestOccluder: 5
smallestHole: 0.25
backfaceThreshold: 100
m_SceneGUID: 00000000000000000000000000000000
m_OcclusionCullingData: {fileID: 0}
--- !u!104 &2
RenderSettings:
m_ObjectHideFlags: 0
serializedVersion: 10
m_Fog: 0
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
m_FogMode: 3
m_FogDensity: 0.01
m_LinearFogStart: 0
m_LinearFogEnd: 300
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
m_AmbientIntensity: 1
m_AmbientMode: 0
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
m_HaloStrength: 0.5
m_FlareStrength: 1
m_FlareFadeSpeed: 3
m_HaloTexture: {fileID: 0}
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
m_DefaultReflectionMode: 0
m_DefaultReflectionResolution: 128
m_ReflectionBounces: 1
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0}
m_IndirectSpecularColor: {r: 0.18028378, g: 0.22571412, b: 0.30692285, a: 1}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
m_ObjectHideFlags: 0
serializedVersion: 12
m_GISettings:
serializedVersion: 2
m_BounceScale: 1
m_IndirectOutputScale: 1
m_AlbedoBoost: 1
m_EnvironmentLightingMode: 0
m_EnableBakedLightmaps: 1
m_EnableRealtimeLightmaps: 0
m_LightmapEditorSettings:
serializedVersion: 12
m_Resolution: 2
m_BakeResolution: 40
m_AtlasSize: 1024
m_AO: 0
m_AOMaxDistance: 1
m_CompAOExponent: 1
m_CompAOExponentDirect: 0
m_ExtractAmbientOcclusion: 0
m_Padding: 2
m_LightmapParameters: {fileID: 0}
m_LightmapsBakeMode: 1
m_TextureCompression: 1
m_ReflectionCompression: 2
m_MixedBakeMode: 2
m_BakeBackend: 1
m_PVRSampling: 1
m_PVRDirectSampleCount: 32
m_PVRSampleCount: 512
m_PVRBounces: 2
m_PVREnvironmentSampleCount: 256
m_PVREnvironmentReferencePointCount: 2048
m_PVRFilteringMode: 1
m_PVRDenoiserTypeDirect: 1
m_PVRDenoiserTypeIndirect: 1
m_PVRDenoiserTypeAO: 1
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVREnvironmentMIS: 1
m_PVRCulling: 1
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 5
m_PVRFilteringGaussRadiusAO: 2
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigmaAO: 1
m_ExportTrainingData: 0
m_TrainingDataDestination: TrainingData
m_LightProbeSampleCountMultiplier: 4
m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0}
m_LightingSettings: {fileID: 0}
--- !u!196 &4
NavMeshSettings:
serializedVersion: 2
m_ObjectHideFlags: 0
m_BuildSettings:
serializedVersion: 3
agentTypeID: 0
agentRadius: 0.5
agentHeight: 2
agentSlope: 45
agentClimb: 0.4
ledgeDropHeight: 0
maxJumpAcrossDistance: 0
minRegionArea: 2
manualCellSize: 0
cellSize: 0.16666667
manualTileSize: 0
tileSize: 256
buildHeightMesh: 0
maxJobWorkers: 0
preserveTilesOutsideBounds: 0
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!1 &330585543
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 330585546}
- component: {fileID: 330585545}
- component: {fileID: 330585544}
- component: {fileID: 330585547}
m_Layer: 0
m_Name: Main Camera
m_TagString: MainCamera
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!81 &330585544
AudioListener:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 330585543}
m_Enabled: 1
--- !u!20 &330585545
Camera:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 330585543}
m_Enabled: 1
serializedVersion: 2
m_ClearFlags: 1
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
m_projectionMatrixMode: 1
m_GateFitMode: 2
m_FOVAxisMode: 0
m_Iso: 200
m_ShutterSpeed: 0.005
m_Aperture: 16
m_FocusDistance: 10
m_FocalLength: 50
m_BladeCount: 5
m_Curvature: {x: 2, y: 11}
m_BarrelClipping: 0.25
m_Anamorphism: 0
m_SensorSize: {x: 36, y: 24}
m_LensShift: {x: 0, y: 0}
m_NormalizedViewPortRect:
serializedVersion: 2
x: 0
y: 0
width: 1
height: 1
near clip plane: 0.3
far clip plane: 1000
field of view: 60
orthographic: 0
orthographic size: 5
m_Depth: -1
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_RenderingPath: -1
m_TargetTexture: {fileID: 0}
m_TargetDisplay: 0
m_TargetEye: 3
m_HDR: 1
m_AllowMSAA: 1
m_AllowDynamicResolution: 0
m_ForceIntoRT: 0
m_OcclusionCulling: 1
m_StereoConvergence: 10
m_StereoSeparation: 0.022
--- !u!4 &330585546
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 330585543}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 1, z: -10}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &330585547
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 330585543}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3}
m_Name:
m_EditorClassIdentifier:
m_RenderShadows: 1
m_RequiresDepthTextureOption: 2
m_RequiresOpaqueTextureOption: 2
m_CameraType: 0
m_Cameras: []
m_RendererIndex: -1
m_VolumeLayerMask:
serializedVersion: 2
m_Bits: 1
m_VolumeTrigger: {fileID: 0}
m_VolumeFrameworkUpdateModeOption: 2
m_RenderPostProcessing: 1
m_Antialiasing: 0
m_AntialiasingQuality: 2
m_StopNaN: 0
m_Dithering: 0
m_ClearDepth: 1
m_AllowXRRendering: 1
m_AllowHDROutput: 1
m_UseScreenCoordOverride: 0
m_ScreenSizeOverride: {x: 0, y: 0, z: 0, w: 0}
m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0}
m_RequiresDepthTexture: 0
m_RequiresColorTexture: 0
m_Version: 2
m_TaaSettings:
quality: 3
frameInfluence: 0.1
jitterScale: 1
mipBias: 0
varianceClampScale: 0.9
contrastAdaptiveSharpening: 0
--- !u!1 &410087039
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 410087041}
- component: {fileID: 410087040}
- component: {fileID: 410087042}
m_Layer: 0
m_Name: Directional Light
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!108 &410087040
Light:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 410087039}
m_Enabled: 1
serializedVersion: 11
m_Type: 1
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_Intensity: 2
m_Range: 10
m_SpotAngle: 30
m_InnerSpotAngle: 21.80208
m_CookieSize: 10
m_Shadows:
m_Type: 2
m_Resolution: -1
m_CustomResolution: -1
m_Strength: 1
m_Bias: 0.05
m_NormalBias: 0.4
m_NearPlane: 0.2
m_CullingMatrixOverride:
e00: 1
e01: 0
e02: 0
e03: 0
e10: 0
e11: 1
e12: 0
e13: 0
e20: 0
e21: 0
e22: 1
e23: 0
e30: 0
e31: 0
e32: 0
e33: 1
m_UseCullingMatrixOverride: 0
m_Cookie: {fileID: 0}
m_DrawHalo: 0
m_Flare: {fileID: 0}
m_RenderMode: 0
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_RenderingLayerMask: 1
m_Lightmapping: 4
m_LightShadowCasterMode: 0
m_AreaSize: {x: 1, y: 1}
m_BounceIntensity: 1
m_ColorTemperature: 5000
m_UseColorTemperature: 1
m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
m_UseBoundingSphereOverride: 0
m_UseViewFrustumForShadowCasterCull: 1
m_ForceVisible: 0
m_ShadowRadius: 0
m_ShadowAngle: 0
--- !u!4 &410087041
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 410087039}
serializedVersion: 2
m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
m_LocalPosition: {x: 0, y: 3, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
--- !u!114 &410087042
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 410087039}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Version: 3
m_UsePipelineSettings: 1
m_AdditionalLightsShadowResolutionTier: 2
m_LightLayerMask: 1
m_RenderingLayers: 1
m_CustomShadowLayers: 0
m_ShadowLayerMask: 1
m_ShadowRenderingLayers: 1
m_LightCookieSize: {x: 1, y: 1}
m_LightCookieOffset: {x: 0, y: 0}
m_SoftShadowQuality: 1
--- !u!1 &832575517
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 832575519}
- component: {fileID: 832575518}
m_Layer: 0
m_Name: Global Volume
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &832575518
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 832575517}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 172515602e62fb746b5d573b38a5fe58, type: 3}
m_Name:
m_EditorClassIdentifier:
m_IsGlobal: 1
priority: 0
blendDistance: 0
weight: 1
sharedProfile: {fileID: 11400000, guid: 10fc4df2da32a41aaa32d77bc913491c, type: 2}
--- !u!4 &832575519
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 832575517}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1660057539 &9223372036854775807
SceneRoots:
m_ObjectHideFlags: 0
m_Roots:
- {fileID: 330585546}
- {fileID: 410087041}
- {fileID: 832575519}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 99c9720ab356a0642a771bea13969a05
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
Assets/Settings.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 709f11a7f3c4041caa4ef136ea32d874
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ab09877e2e707104187f6f83e2f62510
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5e6cbd92db86f4b18aec3ed561671858
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 65bc7dbf4170f435aa868c779acfb082
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/Settings/PC_RPAsset.asset LFS Normal file

Binary file not shown.

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4b83569d67af61e458304325a23e5dfd
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/Settings/PC_Renderer.asset LFS Normal file

Binary file not shown.

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f288ae1f4751b564a96ac7587541f7a2
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 10fc4df2da32a41aaa32d77bc913491c
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More