KikkaSSP il y a 1 mois
Parent
commit
074f7c16e4
100 fichiers modifiés avec 3190 ajouts et 1 suppressions
  1. 7 0
      .gitignore
  2. 0 1
      666.md
  3. BIN
      DataTables/Datas/#demo.item.xlsx
  4. BIN
      DataTables/Datas/__beans__.xlsx
  5. BIN
      DataTables/Datas/__enums__.xlsx
  6. BIN
      DataTables/Datas/__tables__.xlsx
  7. BIN
      DataTables/Datas/~$#demo.item.xlsx
  8. BIN
      DataTables/Datas/~$__beans__.xlsx
  9. BIN
      DataTables/Datas/~$__enums__.xlsx
  10. BIN
      DataTables/Datas/~$__tables__.xlsx
  11. 18 0
      DataTables/Defines/builtin.xml
  12. 18 0
      DataTables/UpdateTable.bat
  13. 13 0
      DataTables/gen.bat
  14. 11 0
      DataTables/gen.sh
  15. 26 0
      DataTables/luban.conf
  16. 1 0
      DataTables/readme.md
  17. 2 0
      GameProject/.gitattributes
  18. 3 0
      GameProject/.gitignore
  19. BIN
      GameProject/1.tableCollection.res
  20. 7 0
      GameProject/AvatarDoll.csproj
  21. 8 0
      GameProject/AvatarDoll.csproj.old
  22. 19 0
      GameProject/AvatarDoll.sln
  23. 15 0
      GameProject/AvatarDoll.sln.DotSettings.user
  24. 73 0
      GameProject/AvatarDoll/AvatarDollAdapter.cs
  25. 1 0
      GameProject/AvatarDoll/AvatarDollAdapter.cs.uid
  26. 279 0
      GameProject/AvatarDoll/Struct/AvatarDollConst.cs
  27. 1 0
      GameProject/AvatarDoll/Struct/AvatarDollConst.cs.uid
  28. 460 0
      GameProject/AvatarDoll/Struct/AvatarDollStruct.cs
  29. 1 0
      GameProject/AvatarDoll/Struct/AvatarDollStruct.cs.uid
  30. 1 0
      GameProject/AvatarDoll/Struct/Const.cs.uid
  31. BIN
      GameProject/Resources/A.png
  32. 34 0
      GameProject/Resources/A.png.import
  33. BIN
      GameProject/Resources/B.png
  34. 34 0
      GameProject/Resources/B.png.import
  35. 25 0
      GameProject/Resources/Shader/CanvasBackground.gdshader
  36. 1 0
      GameProject/Resources/Shader/CanvasBackground.gdshader.uid
  37. 230 0
      GameProject/Resources/Shader/CanvasRuler.gdshader
  38. 1 0
      GameProject/Resources/Shader/CanvasRuler.gdshader.uid
  39. 100 0
      GameProject/Resources/Shader/FreeTransform.gdshader
  40. 1 0
      GameProject/Resources/Shader/FreeTransform.gdshader.uid
  41. 395 0
      GameProject/Resources/Shader/TexturePalette.gdshader
  42. 1 0
      GameProject/Resources/Shader/TexturePalette.gdshader.uid
  43. 401 0
      GameProject/Resources/Theme/basic_theme.tres
  44. 29 0
      GameProject/Resources/Theme/check_button_theme.tres
  45. 56 0
      GameProject/Resources/Theme/scope_check_button_theme.tres
  46. BIN
      GameProject/Resources/UI/Collapse.png
  47. 34 0
      GameProject/Resources/UI/Collapse.png.import
  48. BIN
      GameProject/Resources/UI/Down.png
  49. 34 0
      GameProject/Resources/UI/Down.png.import
  50. BIN
      GameProject/Resources/UI/Expands.png
  51. 34 0
      GameProject/Resources/UI/Expands.png.import
  52. BIN
      GameProject/Resources/UI/IconView.png
  53. 34 0
      GameProject/Resources/UI/IconView.png.import
  54. BIN
      GameProject/Resources/UI/LayerArrow.png
  55. 34 0
      GameProject/Resources/UI/LayerArrow.png.import
  56. BIN
      GameProject/Resources/UI/ListView.png
  57. 34 0
      GameProject/Resources/UI/ListView.png.import
  58. BIN
      GameProject/Resources/UI/OpenFolder.png
  59. 34 0
      GameProject/Resources/UI/OpenFolder.png.import
  60. BIN
      GameProject/Resources/UI/Save.png
  61. 34 0
      GameProject/Resources/UI/Save.png.import
  62. BIN
      GameProject/Resources/UI/SaveAs.png
  63. 34 0
      GameProject/Resources/UI/SaveAs.png.import
  64. BIN
      GameProject/Resources/UI/Trash.png
  65. 34 0
      GameProject/Resources/UI/Trash.png.import
  66. BIN
      GameProject/Resources/UI/Up.png
  67. 34 0
      GameProject/Resources/UI/Up.png.import
  68. BIN
      GameProject/Resources/UI/add.png
  69. 34 0
      GameProject/Resources/UI/add.png.import
  70. BIN
      GameProject/Resources/UI/bg_transparent.png
  71. 34 0
      GameProject/Resources/UI/bg_transparent.png.import
  72. BIN
      GameProject/Resources/UI/body.png
  73. 34 0
      GameProject/Resources/UI/body.png.import
  74. BIN
      GameProject/Resources/UI/checked.png
  75. 34 0
      GameProject/Resources/UI/checked.png.import
  76. BIN
      GameProject/Resources/UI/checkmark.png
  77. 34 0
      GameProject/Resources/UI/checkmark.png.import
  78. BIN
      GameProject/Resources/UI/cursor_Icons.png
  79. 34 0
      GameProject/Resources/UI/cursor_Icons.png.import
  80. BIN
      GameProject/Resources/UI/dressing.png
  81. 34 0
      GameProject/Resources/UI/dressing.png.import
  82. BIN
      GameProject/Resources/UI/logo.png
  83. 34 0
      GameProject/Resources/UI/logo.png.import
  84. BIN
      GameProject/Resources/UI/missing_file.png
  85. 34 0
      GameProject/Resources/UI/missing_file.png.import
  86. BIN
      GameProject/Resources/UI/missing_image.png
  87. 34 0
      GameProject/Resources/UI/missing_image.png.import
  88. BIN
      GameProject/Resources/UI/msgbox_error.png
  89. 34 0
      GameProject/Resources/UI/msgbox_error.png.import
  90. BIN
      GameProject/Resources/UI/msgbox_infomation.png
  91. 34 0
      GameProject/Resources/UI/msgbox_infomation.png.import
  92. BIN
      GameProject/Resources/UI/msgbox_question.png
  93. 34 0
      GameProject/Resources/UI/msgbox_question.png.import
  94. BIN
      GameProject/Resources/UI/msgbox_warning.png
  95. 34 0
      GameProject/Resources/UI/msgbox_warning.png.import
  96. BIN
      GameProject/Resources/UI/palette.png
  97. 34 0
      GameProject/Resources/UI/palette.png.import
  98. BIN
      GameProject/Resources/UI/refresh.png
  99. 34 0
      GameProject/Resources/UI/refresh.png.import
  100. BIN
      GameProject/Resources/UI/replace.png

+ 7 - 0
.gitignore

@@ -0,0 +1,7 @@
+# Godot 4+ specific ignores
+GameProject/.godot/
+GameProject/.idea/
+GameProject/.vscode/
+
+DataTables/output/
+GameProject/android/

+ 0 - 1
666.md

@@ -1 +0,0 @@
-aaabbb

BIN
DataTables/Datas/#demo.item.xlsx


BIN
DataTables/Datas/__beans__.xlsx


BIN
DataTables/Datas/__enums__.xlsx


BIN
DataTables/Datas/__tables__.xlsx


BIN
DataTables/Datas/~$#demo.item.xlsx


BIN
DataTables/Datas/~$__beans__.xlsx


BIN
DataTables/Datas/~$__enums__.xlsx


BIN
DataTables/Datas/~$__tables__.xlsx


+ 18 - 0
DataTables/Defines/builtin.xml

@@ -0,0 +1,18 @@
+<module name="">
+    <bean name="vector2" valueType="1" sep=",">
+        <var name="x" type="float"/>
+        <var name="y" type="float"/>
+    </bean>
+    <bean name="vector3" valueType="1" sep=",">
+        <var name="x" type="float"/>
+        <var name="y" type="float"/>
+        <var name="z" type="float"/>
+    </bean>
+    <bean name="vector4" valueType="1" sep=",">
+        <var name="x" type="float"/>
+        <var name="y" type="float"/>
+        <var name="z" type="float"/>
+        <var name="w" type="float"/>
+    </bean>
+
+</module>

+ 18 - 0
DataTables/UpdateTable.bat

@@ -0,0 +1,18 @@
+set WORKSPACE=..
+set LUBAN_DLL=%WORKSPACE%\Tools\Luban\Luban.dll
+set CONF_ROOT=.
+
+dotnet %LUBAN_DLL% ^
+    -t all ^
+    -c cs-dotnet-json ^
+    -d json2 ^
+    --conf %CONF_ROOT%\luban.conf ^
+    --customTemplateDir %CONF_ROOT%\CustomTemplate ^
+    -x outputCodeDir=output\Code ^
+    -x outputDataDir=output\Table
+
+robocopy /E /Z /MT:16 output\Code ..\GameProject\DataTables\Code
+robocopy /E /Z /MT:16 output\Table ..\GameProject\DataTables\Table
+
+
+pause

+ 13 - 0
DataTables/gen.bat

@@ -0,0 +1,13 @@
+set WORKSPACE=..
+set LUBAN_DLL=%WORKSPACE%\Tools\Luban\Luban.dll
+set CONF_ROOT=.
+
+dotnet %LUBAN_DLL% ^
+    -t all ^
+    -c cs-editor-json ^
+    -d json ^
+    --conf %CONF_ROOT%\luban.conf ^
+    -x outputCodeDir=output\Code ^
+    -x outputDataDir=output\Table
+
+pause

+ 11 - 0
DataTables/gen.sh

@@ -0,0 +1,11 @@
+#!/bin/bash
+
+WORKSPACE=..
+LUBAN_DLL=$WORKSPACE/Tools/Luban/Luban.dll
+CONF_ROOT=.
+
+dotnet $LUBAN_DLL \
+    -t all \
+    -d json \
+    --conf $CONF_ROOT/luban.conf \
+    -x outputDataDir=output

+ 26 - 0
DataTables/luban.conf

@@ -0,0 +1,26 @@
+{
+	"groups":
+	[
+		{"names":["c"], "default":true},
+		{"names":["s"], "default":true},
+		{"names":["e"], "default":true}
+	],
+	"schemaFiles":
+	[
+		{"fileName":"Defines", "type":""},
+		{"fileName":"Datas/__tables__.xlsx", "type":"table"},
+		{"fileName":"Datas/__beans__.xlsx", "type":"bean"},
+		{"fileName":"Datas/__enums__.xlsx", "type":"enum"}
+	],
+	"dataDir": "Datas",
+	"targets":
+	[
+		{"name":"server", "manager":"Tables", "groups":["s"], "topModule":"cfg"},
+		{"name":"client", "manager":"Tables", "groups":["c"], "topModule":"cfg"},
+		{"name":"all", "manager":"Tables", "groups":["c","s","e"], "topModule":"cfg"}
+	],
+    "xargs":
+    [
+    
+    ]
+}

+ 1 - 0
DataTables/readme.md

@@ -0,0 +1 @@
+[Luban](https://www.datable.cn/docs/intro)

+ 2 - 0
GameProject/.gitattributes

@@ -0,0 +1,2 @@
+# Normalize EOL for all files that Git considers text files.
+* text=auto eol=lf

+ 3 - 0
GameProject/.gitignore

@@ -0,0 +1,3 @@
+# Godot 4+ specific ignores
+.godot/
+/android/

BIN
GameProject/1.tableCollection.res


+ 7 - 0
GameProject/AvatarDoll.csproj

@@ -0,0 +1,7 @@
+<Project Sdk="Godot.NET.Sdk/4.4.1">
+  <PropertyGroup>
+    <TargetFramework>net8.0</TargetFramework>
+    <EnableDynamicLoading>true</EnableDynamicLoading>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+</Project>

+ 8 - 0
GameProject/AvatarDoll.csproj.old

@@ -0,0 +1,8 @@
+<Project Sdk="Godot.NET.Sdk/4.3.0">
+  <PropertyGroup>
+    <TargetFramework>net6.0</TargetFramework>
+    <TargetFramework Condition=" '$(GodotTargetPlatform)' == 'android' ">net7.0</TargetFramework>
+    <TargetFramework Condition=" '$(GodotTargetPlatform)' == 'ios' ">net8.0</TargetFramework>
+    <EnableDynamicLoading>true</EnableDynamicLoading>
+  </PropertyGroup>
+</Project>

+ 19 - 0
GameProject/AvatarDoll.sln

@@ -0,0 +1,19 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AvatarDoll", "AvatarDoll.csproj", "{0BF6C748-FF94-40CA-97F5-6CD82B33FB13}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+	Debug|Any CPU = Debug|Any CPU
+	ExportDebug|Any CPU = ExportDebug|Any CPU
+	ExportRelease|Any CPU = ExportRelease|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{0BF6C748-FF94-40CA-97F5-6CD82B33FB13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{0BF6C748-FF94-40CA-97F5-6CD82B33FB13}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{0BF6C748-FF94-40CA-97F5-6CD82B33FB13}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU
+		{0BF6C748-FF94-40CA-97F5-6CD82B33FB13}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU
+		{0BF6C748-FF94-40CA-97F5-6CD82B33FB13}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU
+		{0BF6C748-FF94-40CA-97F5-6CD82B33FB13}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU
+	EndGlobalSection
+EndGlobal

+ 15 - 0
GameProject/AvatarDoll.sln.DotSettings.user

@@ -0,0 +1,15 @@
+<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
+	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AColor_002Ecs_002Fl_003AC_0021_003FUsers_003FAA_002DPC_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F69e3acf0074a4ef8afaea275d4055b96522800_003F3e_003F4e583059_003FColor_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
+	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACSharpInstanceBridge_002Ecs_002Fl_003AC_0021_003FUsers_003FAA_002DPC_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F4cff0a608e114644b749bd11413a95c6583e00_003Fe8_003F0bf18d92_003FCSharpInstanceBridge_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
+	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFileAccess_002Ecs_002Fl_003AC_0021_003FUsers_003FAA_002DPC_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fe3c542efe8ea2c9c8670ffd2706052aec0fb3d6a604a4da5408162ee28e1f7_003FFileAccess_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
+	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AHashCode_002Ecs_002Fl_003AC_0021_003FUsers_003FAA_002DPC_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F114a0a5677ac4113980497cab0663b2dc90930_003Fe8_003F5c0d2c10_003FHashCode_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
+	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AJsonDocument_002Ecs_002Fl_003AC_0021_003FUsers_003FAA_002DPC_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F5296259dcdd466ded101281ba9722e292f8c674aedea41ad8ce728a1cdff6f2_003FJsonDocument_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
+	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AJsonElement_002Ecs_002Fl_003AC_0021_003FUsers_003FAA_002DPC_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fdee9fd754b909095948823227825a711db338e2e4015658a627cddbf6091a1_003FJsonElement_002Ecs_002Fz_003A2_002D1/@EntryIndexedValue">ForceIncluded</s:String>
+	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AJsonElement_002EObjectEnumerator_002Ecs_002Fl_003AC_0021_003FUsers_003FAA_002DPC_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fa0ebc9716bc94d7773dfcf9d1bff54af2282f1a2093ea529edcb137cfd63180_003FJsonElement_002EObjectEnumerator_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
+	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AList_002Ecs_002Fl_003AC_0021_003FUsers_003FAA_002DPC_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F1b81cb3be224213a6a73519b6e340a628d9a1fb8629c351a186a26f6376669_003FList_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
+	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AObject_002Ecs_002Fl_003AC_0021_003FUsers_003FAA_002DPC_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F9a6b1457cbcf17db31a383ba49ef9bcc786cf3ef77146d997eee499b27a46d_003FObject_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
+	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AString_002EComparison_002Ecs_002Fl_003AC_0021_003FUsers_003FAA_002DPC_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F415912dcbf24e76247dde1798c725ce64f23be667aecfc1dd5492e67214b6_003FString_002EComparison_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
+	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003AC_0021_003FUsers_003FAA_002DPC_003FAppData_003FLocal_003FSymbols_003Fsrc_003Fdotnet_003Fruntime_003F831d23e56149cd59c40fc00c7feb7c5334bd19c4_003Fsrc_003Flibraries_003FSystem_002EText_002EJson_003Fsrc_003FSystem_003FText_003FJson_003FThrowHelper_002Ecs_002Fz_003A2_002D1/@EntryIndexedValue">ForceIncluded</s:String>
+	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003AC_0021_003FUsers_003FAA_002DPC_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fc7102cd0ffb8973777e61b1942c3fffac7e14016a511d055c3adf73ff91748_003FThrowHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
+	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002ESerialization_002Ecs_002Fl_003AC_0021_003FUsers_003FAA_002DPC_003FAppData_003FLocal_003FSymbols_003Fsrc_003Fdotnet_003Fruntime_003F831d23e56149cd59c40fc00c7feb7c5334bd19c4_003Fsrc_003Flibraries_003FSystem_002EText_002EJson_003Fsrc_003FSystem_003FText_003FJson_003FThrowHelper_002ESerialization_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
+	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AValueType_002Ecs_002Fl_003AC_0021_003FUsers_003FAA_002DPC_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F3bf9ddbdca76837aff182b568ea612623121c0901c6c73de35e5c9b14a81a_003FValueType_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>

+ 73 - 0
GameProject/AvatarDoll/AvatarDollAdapter.cs

@@ -0,0 +1,73 @@
+using Godot;
+using System;
+using System.Text.Json;
+
+using AvatarDoll;
+
+public partial class AvatarDollAdapter : Node
+{
+    private static AvatarDollAdapter _instance;
+    
+    public static AvatarDollAdapter Instance
+    {
+        get
+        {
+            if (_instance == null)
+            {
+                GD.Print("AvatarDollAdapter instance is null!");
+            }
+            return _instance;
+        }
+    }
+
+    private AvatarDollData data;
+    
+    public override void _Ready()
+    {
+        if (_instance == null)
+        {
+            _instance = this;
+            // 确保单例在场景切换时不被销毁
+            // GetTree().Root.AddChild(this);
+            Owner = GetTree().Root;
+            GD.Print("C# AvatarDollAdapter initialized");
+        }
+        else
+        {
+            QueueFree();
+        }
+    }
+
+    public void LoadJson(string jsonPath)
+    {
+        using var file = FileAccess.Open(jsonPath, FileAccess.ModeFlags.Read);
+        string jsonString = file.GetAsText();
+        data = JsonSerializer.Deserialize<AvatarDollData>(jsonString);
+    }
+
+    public void SaveJson(string jsonPath)
+    {
+        using var file = FileAccess.Open(jsonPath, FileAccess.ModeFlags.Write);
+        string jsonString = JsonSerializer.Serialize(data);
+        file.StoreString(jsonString);
+    }
+    
+    public void ParseJson(string jsonPath, string jsonString2)
+    {
+        using var file = FileAccess.Open(jsonPath, FileAccess.ModeFlags.Read);
+        string jsonString1 = file.GetAsText();
+        AvatarDollData deData1 = JsonSerializer.Deserialize<AvatarDollData>(jsonString1);
+        AvatarDollData deData2 = JsonSerializer.Deserialize<AvatarDollData>(jsonString2);
+        string jsonString3 = JsonSerializer.Serialize(deData1);
+        string jsonString4 = JsonSerializer.Serialize(deData2);
+        AvatarDollData deData3 = JsonSerializer.Deserialize<AvatarDollData>(jsonString3);
+        AvatarDollData deData4 = JsonSerializer.Deserialize<AvatarDollData>(jsonString4);
+        
+        bool b2 = deData1.Equals(deData2);
+        bool b3 = deData1.Equals(deData3);
+        bool b4 = deData1.Equals(deData4);
+        if (b2 && b3 && b4)
+            GD.Print("Equals !!!!");
+    }
+    
+}

+ 1 - 0
GameProject/AvatarDoll/AvatarDollAdapter.cs.uid

@@ -0,0 +1 @@
+uid://bk5an1xldhefn

+ 279 - 0
GameProject/AvatarDoll/Struct/AvatarDollConst.cs

@@ -0,0 +1,279 @@
+using Godot;
+using System;
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
+
+namespace AvatarDoll
+{
+	[Flags]
+	public enum PartScope : short
+	{
+		Body = 1 << 0,
+		Head = 1 << 1,
+		Hair = 1 << 2,
+		Face = 1 << 3,
+		Cloth = 1 << 4,
+		
+		All = Body | Head | Hair | Face | Cloth
+	}
+	
+	#region BodySlot
+	// ##############################################################################
+
+	public enum EBodySlot_Type1 : short
+	{
+		_头发 = 0, // BodySlot_Type2_Hair
+		_脸部 = 1, // BodySlot_Type2_Face
+		_颈部 = 2, // BodySlot_Type2_Neck
+		_上身 = 3, // BodySlot_Type2_UpperBody
+		_手部 = 4, // BodySlot_Type2_Hand
+		_下身 = 5, // BodySlot_Type2_LowerBody
+		_腿部 = 6, // BodySlot_Type2_Leg
+		_脚部 = 7, // BodySlot_Type2_Foot
+		_漂浮物 = 8, // BodySlot_Type2_Floating
+	}
+
+	public enum EBodySlot_Type2_Hair : short
+	{
+		_发型 = 0,
+		_头顶 = 1,
+		_发侧L = 2,
+		_发侧R = 3,
+		_发后 = 4,
+		_额头 = 5,
+	}
+
+	public enum EBodySlot_Type2_Face : short
+	{
+		_眼L = 0,
+		_眼R = 1,
+		_耳廓L = 2,
+		_耳廓R = 3,
+		_耳垂L = 4,
+		_耳垂R = 5,
+		_鼻子 = 6,
+		_嘴巴 = 7,
+		_下巴 = 8,
+		_脸颊L = 9,
+		_脸颊R = 10,
+	}
+
+	public enum EBodySlot_Type2_Neck : short
+	{
+		_脖子 = 0,
+		_胸前 = 1,
+	}
+
+	public enum EBodySlot_Type2_UpperBody : short
+	{
+		_前胸L = 0,
+		_前胸R = 1,
+		_肩膀L = 2,
+		_肩膀R = 3,
+		_后背L = 4,
+		_后背R = 5,
+		_大臂L = 6,
+		_大臂R = 7,
+		_小臂L = 8,
+		_小臂R = 9,
+	}
+
+	public enum EBodySlot_Type2_Hand : short
+	{
+		_手腕L = 0,
+		_手背L = 1,
+		_手掌L = 2,
+		_手上L = 3,
+		_手指L_拇指 = 4,
+		_手指L_食指 = 5,
+		_手指L_中指 = 6,
+		_手指L_无名指 = 7,
+		_手指L_尾指 = 8,
+		_指甲L_拇指 = 9,
+		_指甲L_食指 = 10,
+		_指甲L_中指 = 11,
+		_指甲L_无名指 = 12,
+		_指甲L_尾指 = 13,
+
+		_手腕R = 14,
+		_手背R = 15,
+		_手掌R = 16,
+		_手上R = 17,
+		_手指R_拇指 = 18,
+		_手指R_食指 = 19,
+		_手指R_中指 = 20,
+		_手指R_无名指 = 21,
+		_手指R_尾指 = 22,
+		_指甲R_拇指 = 23,
+		_指甲R_食指 = 24,
+		_指甲R_中指 = 25,
+		_指甲R_无名指 = 26,
+		_指甲R_尾指 = 27,
+	}
+
+	public enum EBodySlot_Type2_LowerBody : short
+	{
+		_腰部 = 0,
+		_后腰 = 1,
+		_腹部 = 2,
+		_胯部 = 3,
+	}
+
+	public enum EBodySlot_Type2_Leg : short
+	{
+		_大腿L = 0,
+		_大腿R = 1,
+		_膝盖L = 2,
+		_膝盖R = 3,
+		_小腿L = 4,
+		_小腿R = 5,
+	}
+
+	public enum EBodySlot_Type2_Foot : short
+	{
+		_脚踝L = 0,
+		_脚背L = 1,
+		_脚底L = 2,
+		_趾甲L = 3,
+		_脚踝R = 4,
+		_脚背R = 5,
+		_脚底R = 6,
+		_趾甲R = 7,
+	}
+
+	public enum EBodySlot_Type2_Floating : short
+	{
+		_头顶上方 = 0,
+		_头后方 = 1,
+		_背后方 = 2,
+		_背景 = 3,
+		_前方 = 4,
+		_前景 = 5,
+	}
+
+	public struct BodySlot
+	{
+		private int _hash;
+
+		public EBodySlot_Type1 Type1
+		{
+			get => (EBodySlot_Type1)((_hash >> 16) & 0xFFFF);
+			set => _hash = ((_hash & 0x0000FFFF) | (((short)value & 0xFFFF) << 16));
+		}
+
+		public short Type2
+		{
+			get => (short)(_hash & 0xFFFF);
+			set => _hash = (int)((_hash & 0xFFFF0000u) | (uint)(value & 0xFFFF));
+		}
+
+		public int Hash => _hash;
+
+		public BodySlot(EClothClasses_Type1 type1, short type2)
+		{
+			_hash = (((short)type1 & 0xFFFF) << 16) | (type2 & 0xFFFF);
+		}
+
+		public override bool Equals(object obj)
+		{
+			return obj is BodySlot other && this._hash == other._hash;
+		}
+
+		public override int GetHashCode() => _hash;
+	}
+
+	#endregion
+
+	# region ClothClasses
+	// ##############################################################################
+	
+	public enum EClothClasses_Type1 : short
+	{
+		_纹身 = 0, // ClothClasses_Type2_Tattoo
+		_衣服 = 1, // ClothClasses_Type2_Cloth
+		_饰品 = 2, // ClothClasses_Type2_Accessory
+		_武器 = 3, // ClothClasses_Type2_Weapon
+		_特效装饰 = 4, // ClothClasses_Type2_Effect
+	}
+
+	public enum EClothClasses_Type2_Tattoo : short
+	{
+		_脸部纹身 = 0,
+		_身体纹身 = 1,
+	}
+
+	public enum EClothClasses_Type2_Cloth : short
+	{
+		_套服 = 0,
+		_上衣 = 1,
+		_裤子 = 2,
+		_裙子 = 3,
+		_手套 = 4,
+		_袜子 = 5,
+		_鞋子 = 6,
+		_披风 = 7,
+	}
+
+	public enum EClothClasses_Type2_Accessory : short
+	{
+		_发饰 = 0,
+		_耳饰 = 1,
+		_脸饰 = 2,
+		_首饰 = 3,
+		_手饰 = 4,
+		_脚饰 = 5,
+		_指甲 = 6,
+		_趾甲 = 7,
+	}
+
+	public enum EClothClasses_Type2_Weapon : short
+	{
+		_单手武器 = 0,
+		_双手武器 = 1,
+	}
+
+	public enum EClothClasses_Type2_Effect : short
+	{
+		_光环 = 0,
+		_翅膀 = 1,
+		_特效 = 2,
+		_前景 = 3,
+		_背景 = 4,
+	}
+
+	#endregion
+
+	public enum ThemeColor: byte
+	{
+		Black = 0,			// 黑色		000000	0,0,0
+		White = 1,			// 白色		ffffff	255,255,255
+		Grey = 2,			// 灰色		808080	128,128,128
+		Red = 3,			// 红色		cc0000	204,0,0
+		Orange = 4,			// 橙色		ff9900	255,153,0
+		Yellow = 5,			// 黄色		ffcc00	255,204,0
+		AppleGreen = 6,		// 嫩绿		99cc33	153,204,51
+		GrassGreen = 7,		// 草绿		009944	0,153,68
+		MikuGreen = 8,		// 葱绿		009999	0,153,153
+		SkyBlue = 9,		// 天蓝		0099ff	0,153,255
+		Blue = 10,			// 蓝色		0000cc	0,0,204
+		NavyBlue = 11,		// 深蓝		003366	0,51,102
+		BlueViolet = 12,	// 蓝紫色	6633ff	102,51,255
+		Purple = 13,		// 紫色		660099	102,0,153
+		DarkPurple = 14,	// 葡萄紫	990099	153,0,153
+		HotPink = 15,		// 爱心粉	ff99cc	255,153,204
+		LightPink = 16,		// 淡粉色	FFCCCC	255,204,204
+		Brown = 17,			// 棕色		663300	102,51,0
+	}
+
+	public enum ClothTag
+	{
+		_基础款,
+		
+	}
+	
+	public enum ClothSetTheme
+	{
+		_基础款,
+		
+	}
+} 

+ 1 - 0
GameProject/AvatarDoll/Struct/AvatarDollConst.cs.uid

@@ -0,0 +1 @@
+uid://ua5hu5uekave

+ 460 - 0
GameProject/AvatarDoll/Struct/AvatarDollStruct.cs

@@ -0,0 +1,460 @@
+using Godot;
+using System;
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
+
+namespace AvatarDoll
+{
+    /// <summary>
+    /// Avatar作者的元信息
+    /// </summary>
+    [Serializable]
+    public struct Metadata
+    {
+        [JsonInclude] public string Author { get; set; }
+        [JsonInclude] public string Introduction { get; set; }
+        [JsonInclude] public string Version { get; set; }
+        [JsonInclude] public string Link { get; set; }
+    }
+
+    
+    [Serializable]
+    public struct PartState
+    {
+        public PartState() { }
+        
+        [JsonInclude] public string Name { get; set; } = "";
+        [JsonInclude] public PartScope Scope { get; set; } = 0;
+        [JsonInclude] public byte Default { get; set; } = 0;
+        [JsonInclude] public List<string> Values { get; set; } = new();
+        [JsonInclude] public List<bool> Required { get; set; } = new();
+        
+        public override bool Equals(object obj)
+        {
+            return obj is PartState state && Equals(state);
+        }
+        
+        public bool Equals(PartState other)
+        {
+            return Name == other.Name &&
+                   Scope == other.Scope &&
+                   Default == other.Default &&
+                   System.Linq.Enumerable.SequenceEqual(Values, other.Values) &&
+                   System.Linq.Enumerable.SequenceEqual(Required, other.Required);
+        }
+    }
+    
+    /// <summary>
+    /// Avatar配置项
+    /// </summary>
+    [Serializable]
+    public struct ProjectSettings
+    {
+        public ProjectSettings() { }
+
+        [JsonInclude] public int MaxBodySlotCost { get; set; } = 5;
+        [JsonInclude] public List<PartState> States { get; set; } = new();
+        
+        public static int GetStatusesCode(ProjectSettings settings)
+        {
+            int finalHash = 0;
+            foreach (var state in settings.States)
+            {
+                int listHash = 0;
+                foreach (var value in state.Required)
+                {
+                    int valueHash = value ? 1 : 0;
+                    listHash = CombineHashes(listHash, valueHash);
+                }
+                finalHash = CombineHashes(finalHash, listHash);
+            }
+            return finalHash;
+        }
+
+        private static int CombineHashes(int h1, int h2)
+        {
+            long hash = 2166136261L;
+    
+            hash = (hash ^ (h1 & 0xFF)) * 16777619;
+            hash = (hash ^ ((h1 >> 8) & 0xFF)) * 16777619;
+            hash = (hash ^ ((h1 >> 16) & 0xFF)) * 16777619;
+            hash = (hash ^ ((h1 >> 24) & 0xFF)) * 16777619;
+    
+            hash = (hash ^ (h2 & 0xFF)) * 16777619;
+            hash = (hash ^ ((h2 >> 8) & 0xFF)) * 16777619;
+            hash = (hash ^ ((h2 >> 16) & 0xFF)) * 16777619;
+            hash = (hash ^ ((h2 >> 24) & 0xFF)) * 16777619;
+    
+            return (int)(hash & 0x7FFFFFFF);
+        }
+        
+        public override bool Equals(object obj)
+        {
+            return obj is ProjectSettings settings && Equals(settings);
+        }
+        
+        public bool Equals(ProjectSettings other)
+        {
+            bool equal = MaxBodySlotCost == other.MaxBodySlotCost
+                         && States.Count == other.States.Count;
+            if (equal == false) return false;
+            
+            for (int i = 0; i < States.Count; i++)
+                equal &= States[i].Equals(other.States[i]);
+            return equal;
+        }
+        
+        public override int GetHashCode()
+        {
+            return GetStatusesCode(this);
+        }
+    }
+    
+    /// <summary>
+    /// 
+    /// </summary>
+    [Serializable]
+    public struct PaletteColor
+    {
+        [JsonInclude] public float R { get; set; }
+        [JsonInclude] public float G { get; set; }
+        [JsonInclude] public float B { get; set; }
+        [JsonInclude] public float A { get; set; }
+        
+        public PaletteColor(float r, float g, float b, float a = 1.0f) { R = r; G = g; B = b; A = a; }
+        public PaletteColor(Godot.Color color) { R = color.R; G = color.G; B = color.B; A = color.A; }
+        
+        public static implicit operator Godot.Color(PaletteColor color) { return new Godot.Color(color.R, color.G, color.B, color.A); }
+        public static implicit operator PaletteColor(Godot.Color color) { return new PaletteColor(color); }
+        
+        public override bool Equals(object obj) 
+        {
+            if (obj is PaletteColor other)
+            {
+                return (double) this.R == (double) other.R && (double) this.G == (double) other.G && (double) this.B == (double) other.B && (double) this.A == (double) other.A;
+            }
+            return false;
+        }
+        
+        public override int GetHashCode()
+        {
+            return HashCode.Combine(R, G, B, A);
+        }
+    }
+    
+    /// <summary>
+    /// 图片调色参数
+    /// </summary>
+    [Serializable]
+    public struct PaletteParam()
+    {
+        [JsonInclude] public int ElementIndex = -1;
+        [JsonInclude] public PaletteColor BasicColor { get; set; } = new PaletteColor(0,0,0,0);
+        [JsonInclude] public int Tolerance = 0;
+        [JsonInclude] public PaletteColor ModulateColor { get; set; } = new PaletteColor(0,0,0,0);
+        [JsonInclude] public int BlendMode = 0;
+        
+        public override bool Equals(object obj)
+        {
+            return obj is PaletteParam other && Equals(other);
+        }
+
+        public bool Equals(PaletteParam other)
+        {
+            return BasicColor.Equals(other.BasicColor) &&
+                   ModulateColor.Equals(other.ModulateColor) &&
+                   Tolerance == other.Tolerance &&
+                   BlendMode == other.BlendMode;
+        }
+        
+        public override int GetHashCode()
+        {
+            return HashCode.Combine(ElementIndex, Tolerance, BlendMode, BasicColor.GetHashCode(), ModulateColor.GetHashCode());
+        }
+    }
+
+        
+    /// <summary>
+    /// 调色板。用于保存其他上色方案,且可以指定不同配色下的别名
+    /// </summary>
+    [Serializable]
+    public struct Palette()
+    {
+        [JsonInclude] public uint Guid { get; set; } = 0;
+        [JsonInclude] public string Name { get; set; }
+        [JsonInclude] public string Introduction { get; set; }
+        
+        [JsonInclude] public List<ThemeColor> ThemeColors { get; set; } = [];
+        [JsonInclude] public List<PaletteParam> IconPaletteParams { get; set; } = [];
+        [JsonInclude] public List<PaletteParam> ElementPaletteParams { get; set; } = [];
+    }
+
+    
+    /// <summary>
+    /// Avatar的某个元素的集合,可以是一个身形,或者一个脸型,一件服装等
+    /// 例如对于头发,就是一个发型在所有Pose下的样子的集合。脸型、服装等同理
+    /// </summary>
+    [Serializable]
+    public class AvatarPart()
+    {
+        [JsonInclude] public uint Guid { get; set; } = 0;
+        [JsonInclude] public string Name { get; set; }
+        [JsonInclude] public int IconAssetId { get; set; }
+        [JsonInclude] public string Introduction { get; set; }
+        
+        [JsonInclude] public List<ThemeColor> ThemeColors { get; set; } = [];
+
+        /// <summary>
+        /// 调色板。如果该服装有除了默认颜色外的其他上色方案,可以在这里保存
+        /// </summary>
+        [JsonInclude] public List<Palette> Palettes { get; set; } = [];
+        
+        /// <summary>
+        /// 每个pose的数据
+        /// key: PoseID
+        /// value: AvatarPoses是个AvatarPosePart数组。 例如一个装备在站立状态下的pose图可能由多张图片组合而成
+        /// </summary>
+        [JsonInclude] public Dictionary<string, List<AvatarElement>> Elements { get; set; } = new();
+
+        public override bool Equals(object obj)
+        {
+            return obj is AvatarPart other && Equals(other);
+        }
+
+        public bool Equals(AvatarPart obj)
+        {
+            bool equal = true;
+            equal &= Name == obj.Name;
+            equal &= IconAssetId == obj.IconAssetId;
+            equal &= Introduction == obj.Introduction;
+            equal &= Palettes.Count == obj.Palettes.Count;
+            if (equal == false) return false;
+            for (int i = 0; i < Palettes.Count; ++i)
+            {
+                equal &= Palettes[i].Guid == obj.Palettes[i].Guid;
+                equal &= Palettes[i].Name == obj.Palettes[i].Name;
+                equal &= Palettes[i].Introduction == obj.Palettes[i].Introduction;
+                equal &= Palettes[i].IconPaletteParams.Count == obj.Palettes[i].IconPaletteParams.Count;
+                equal &= Palettes[i].ElementPaletteParams.Count == obj.Palettes[i].ElementPaletteParams.Count;
+                if (equal == false) return false;
+                
+                for (int j = 0; j < Palettes[i].IconPaletteParams.Count; ++j)
+                    equal &= Palettes[i].IconPaletteParams[j].Equals(obj.Palettes[i].IconPaletteParams[j]);
+                for (int j = 0; j < Palettes[i].ElementPaletteParams.Count; ++j)
+                    equal &= Palettes[i].ElementPaletteParams[j].Equals(obj.Palettes[i].ElementPaletteParams[j]);
+                
+                if (equal == false) return false;
+            }
+
+            equal &= Elements.Count == obj.Elements.Count;
+            foreach (var pair in Elements)
+            {
+                equal &= obj.Elements.ContainsKey(pair.Key);
+                equal &= pair.Value.Count == obj.Elements[pair.Key].Count;
+                if (equal == false) return false;
+                
+                for (int i = 0; i < pair.Value.Count; ++i)
+                    equal &= obj.Elements[pair.Key][i].Equals(pair.Value[i]);
+                if (equal == false) return false;
+            }
+            return equal;
+        }
+        
+        public override int GetHashCode() { return (int)Guid; }
+    }
+
+    /// <summary>
+    /// 一张Asset图片在pose中的偏移和层级等数据
+    /// </summary>
+    [Serializable]
+    public struct AvatarElement
+    {
+        [JsonInclude] public int AssetId { get; set; }
+        [JsonInclude] public int Layer { get; set; }
+        [JsonInclude] public int LayerOffset { get; set; }
+
+        [JsonInclude] public float PositionX { get; set; }
+        [JsonInclude] public float PositionY { get; set; }
+        [JsonInclude] public float Rotation { get; set; }
+        [JsonInclude] public float ScaleX { get; set; }
+        [JsonInclude] public float ScaleY { get; set; }
+        [JsonInclude] public float Skew { get; set; }
+
+    }
+    
+    [Serializable]
+    public class AvatarBody() : AvatarPart { }
+    
+    [Serializable]
+    public class AvatarHead(): AvatarPart { }
+    
+    [Serializable]
+    public class AvatarHair(): AvatarPart { }
+    
+    [Serializable]
+    public class AvatarFace() : AvatarPart { }
+    
+    [Serializable]
+    public struct ClothClasses : IEquatable<ClothClasses>
+    {
+        [JsonInclude] public int Hash { get; set; }
+		
+        public EClothClasses_Type1 Type1()
+        {
+            return (EClothClasses_Type1)((Hash >> 16) & 0xFFFF);
+        }
+
+        public void SetType1(EClothClasses_Type1 value)
+        {
+            Hash = ((Hash & 0x0000FFFF) | (((short)value & 0xFFFF) << 16));
+        }
+
+        public short Type2()
+        {
+            return (short)(Hash & 0xFFFF);
+        }
+        
+        public void SetType2(short value)
+        {
+            Hash = (int)((Hash & 0xFFFF0000u) | (uint)(value & 0xFFFF));
+        }
+
+        public ClothClasses(int hash)
+        {
+            Hash = hash;
+        }
+        
+        public ClothClasses(EClothClasses_Type1 type1, short type2)
+        {
+            Hash = (((short)type1 & 0xFFFF) << 16) | (type2 & 0xFFFF);
+        }
+
+        public static implicit operator ClothClasses(int hash) => new ClothClasses(hash);
+    
+        public static implicit operator int(ClothClasses clothClasses) => clothClasses.Hash;
+        
+        public override bool Equals(object obj)
+        {
+            return obj is ClothClasses other && this.Hash == other.Hash;
+        }
+        public bool Equals(ClothClasses other)
+        {
+            return Hash == other.Hash;
+        }
+        public override int GetHashCode() => Hash;
+
+        public static bool operator ==(ClothClasses left, ClothClasses right)
+        {
+            return left.Equals(right);
+        }
+
+        public static bool operator !=(ClothClasses left, ClothClasses right)
+        {
+            return !(left == right);
+        }
+    }
+    
+    /// <summary>
+    /// 角色服装数据
+    /// </summary>
+    [Serializable]
+    public class AvatarCloth() : AvatarPart
+    {
+        /// <summary>
+        /// 服装分类
+        /// </summary>
+        [JsonInclude] public ClothClasses ClothClasses = new();
+        
+        /// <summary>
+        /// 占用的身体槽。例如连衣裙会同时占用上身和下身的槽位,使得不能再穿其他上衣。
+        /// key: BodySlot.Hash
+        /// value: cost
+        /// </summary>
+        [JsonInclude] public Dictionary<int, int> BodySlotCost { get; set; } = new();
+        
+        public override bool Equals(object obj) { return obj is AvatarCloth other && Equals(other); }
+        public bool Equals(AvatarCloth obj)
+        {
+            bool equal = base.Equals(obj);
+            equal &= ClothClasses.Equals(obj.ClothClasses);
+            equal &= BodySlotCost.Count == obj.BodySlotCost.Count;
+            if (equal == false) return false;
+            
+            equal &= BodySlotCost.Count == obj.BodySlotCost.Count;
+            foreach (var pair in BodySlotCost)
+            {
+                equal &= obj.BodySlotCost.ContainsKey(pair.Key);
+                if (equal == false) return false;
+                
+                equal &= obj.BodySlotCost[pair.Key] == pair.Value;
+                if (equal == false) return false;
+            }
+            return equal;
+        }
+        
+        public override int GetHashCode() { return (int)Guid; }
+
+    }
+    
+    [Serializable]
+    public struct AvatarDollData()
+    {
+        [JsonInclude] public int FormatVersion { get; set; } = 0;
+
+        [JsonInclude] public Metadata Metadata = new();
+
+        [JsonInclude] public ProjectSettings Settings = new();
+        
+        /// <summary>
+        /// Asset资源映射表
+        /// 把AssetID对应到文件
+        /// </summary>
+        [JsonInclude] public Dictionary<int, string> AssetMap { get; set; } = new();
+
+        [JsonInclude] public List<AvatarBody> Bodies { get; set; } = [];
+        [JsonInclude] public List<AvatarHead> Heads { get; set; } = [];
+        [JsonInclude] public List<AvatarHair> Hairs { get; set; } = [];
+        [JsonInclude] public List<AvatarFace> Faces { get; set; } = [];
+        [JsonInclude] public List<AvatarCloth> Clothes { get; set; } = [];
+        
+        public override bool Equals(object obj)
+        {
+            return obj is AvatarDollData other && Equals(other);
+        }
+
+        public bool Equals(AvatarDollData data)
+        {
+            bool equal = true;
+            equal &= FormatVersion == data.FormatVersion;
+            equal &= Metadata.Equals(data.Metadata);
+
+            equal &= AssetMap.Count == data.AssetMap.Count;
+            foreach (var pair in AssetMap)
+            {
+                equal &= data.AssetMap.ContainsKey(pair.Key);
+                equal &= pair.Value == data.AssetMap[pair.Key];
+            }
+            
+            equal &= Bodies.Count == data.Bodies.Count;
+            for (int i = 0; i < data.Bodies.Count; ++i)
+                equal &= Bodies[i].Equals(data.Bodies[i]);
+			
+            equal &= Faces.Count == data.Faces.Count;
+            for (int i = 0; i < data.Faces.Count; ++i)
+                equal &= Faces[i].Equals(data.Faces[i]);
+
+            equal &= Hairs.Count == data.Hairs.Count;
+            for (int i = 0; i < data.Hairs.Count; ++i)
+                equal &= Hairs[i].Equals(data.Hairs[i]);
+			
+            equal &= Clothes.Count == data.Clothes.Count;
+            for (int i = 0; i < data.Clothes.Count; ++i)
+                equal &= Clothes[i].Equals(data.Clothes[i]);
+            return equal;
+        }
+        
+        
+    }
+    
+}
+

+ 1 - 0
GameProject/AvatarDoll/Struct/AvatarDollStruct.cs.uid

@@ -0,0 +1 @@
+uid://bar0ktsy4pyum

+ 1 - 0
GameProject/AvatarDoll/Struct/Const.cs.uid

@@ -0,0 +1 @@
+uid://dxqeslhdrq7co

BIN
GameProject/Resources/A.png


+ 34 - 0
GameProject/Resources/A.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cc0ft316ioagu"
+path="res://.godot/imported/A.png-b991189a159674b59b096c12d5e7200c.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/A.png"
+dest_files=["res://.godot/imported/A.png-b991189a159674b59b096c12d5e7200c.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/B.png


+ 34 - 0
GameProject/Resources/B.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b6xdkebkevb1u"
+path="res://.godot/imported/B.png-26d26576eae5c98d28d5b6aeb5d90638.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/B.png"
+dest_files=["res://.godot/imported/B.png-26d26576eae5c98d28d5b6aeb5d90638.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

+ 25 - 0
GameProject/Resources/Shader/CanvasBackground.gdshader

@@ -0,0 +1,25 @@
+shader_type canvas_item;
+
+uniform vec4 bg_color: source_color;
+uniform float zoom;
+
+const vec4 grid_gray = vec4(0.8, 0.8, 0.8, 1.0);
+const vec4 grid_white = vec4(1.0, 1.0, 1.0, 1.0);
+
+varying vec2 pixel_pos;
+
+
+void vertex() {
+	pixel_pos = (MODEL_MATRIX * vec4(VERTEX, 0.0, 1.0)).xy;
+}
+
+void fragment() {
+	float grid_size = pow(2.0, ceil(log2((16.0 / zoom))));
+    
+    vec2 grid_coord = floor(pixel_pos / grid_size);
+    bool is_dark_cell = mod(grid_coord.x + grid_coord.y, 2.0) == 0.0;
+    COLOR = is_dark_cell ? grid_gray : grid_white;
+    if (bg_color.a > 0.0) {
+        COLOR = mix(COLOR, bg_color, bg_color.a);
+    }
+}

+ 1 - 0
GameProject/Resources/Shader/CanvasBackground.gdshader.uid

@@ -0,0 +1 @@
+uid://cc1o2iqoutd7i

+ 230 - 0
GameProject/Resources/Shader/CanvasRuler.gdshader

@@ -0,0 +1,230 @@
+shader_type canvas_item;
+
+const float line_width = 1.0f;
+const float interval_step[8] = float[8](10.0, 50.0, 100.0, 200.0, 500.0, 1000.0, 5000.0, 10000.0);
+
+// 标尺参数
+uniform bool is_horizontal;
+uniform vec2 ruler_size;
+uniform vec4 ruler_range;
+uniform vec4 highlight_range;
+uniform vec2 mouse_pos;
+uniform vec4 mouse_line_color : source_color = vec4(0.5, 0.5, 0.5, 1.0);
+uniform vec4 line_color : source_color = vec4(0.5, 0.5, 0.5, 1.0);
+uniform vec4 highlight_color : source_color = vec4(0.5, 0.5, 0.5, 1.0);
+uniform vec4 bg_color : source_color = vec4(0.2, 0.2, 0.2, 1.0);
+
+varying vec2 pixel_pos;
+
+int quick_digit_count(int number) {
+    int absNum = abs(number);
+    int count = 0;
+	
+    if (absNum >= 100000) count = 6;
+    else if (absNum >= 10000) count = 5;
+    else if (absNum >= 1000) count = 4;
+    else if (absNum >= 100) count = 3;
+    else if (absNum >= 10) count = 2;
+    else count = 1;
+    if (number < 0) count++;
+    return count;
+}
+
+// ###########################################################################
+// Printing numbers
+// Modify according to the https://www.shadertoy.com/view/XllSWl
+
+float DigitBin(const in int x) {
+    return x==0?480599.0:x==1?139810.0:x==2?476951.0:x==3?476999.0:x==4?350020.0:x==5?464711.0:x==6?464727.0:x==7?476228.0:x==8?481111.0:x==9?481095.0:0.0;
+}
+
+float PrintValue(const in vec2 fragCoord, const in vec2 vPixelCoords, const in vec2 vFontSize, const in float fValue) {
+    vec2 vStringCharCoords = (vec2(fragCoord.x, 1.0 - fragCoord.y).xy - vPixelCoords) / vFontSize;
+    if ((vStringCharCoords.y < 0.0) || (vStringCharCoords.y >= 1.0)) return 0.0;
+    
+    float fLog10Value = log2(abs(fValue)) / log2(10.0);
+    float fBiggestIndex = max(floor(fLog10Value), 0.0);
+    float fDigitIndex = floor(vStringCharCoords.x);
+    float fCharBin = 0.0;
+    float fNumStartIndex = (fValue < 0.0) ? 1.0 : 0.0;
+    
+    if(fValue < 0.0 && fDigitIndex == 0.0) {
+        fCharBin = 1792.0; 
+    }
+    else if (fDigitIndex >= fNumStartIndex && fDigitIndex <= fBiggestIndex + fNumStartIndex) {
+        float fActualDigitIndex = fBiggestIndex - (fDigitIndex - fNumStartIndex);
+        float fDigitValue = abs(fValue / pow(10.0, fActualDigitIndex));
+        fCharBin = DigitBin(int(floor(mod(0.0001 + fDigitValue, 10.0))));
+    } else {
+        return 0.0;
+    }
+    return floor(mod((fCharBin / pow(2.0, floor(fract(vStringCharCoords.x) * 4.0) + (floor(vStringCharCoords.y * 5.0) * 4.0))), 2.0));
+}
+
+// ###########################################################################
+
+float affine_transform(float x, float a, float b, float p, float q) {
+    return p + (x - a) * (q - p) / (b - a);
+}
+
+float grid_align_floor(float x, int step_size) {
+    return floor(x / float(step_size)) * float(step_size);
+}
+
+float interval_round(float input_value) {
+    float closest = interval_step[0];
+    for (int i = 1; i < 8; i++) {
+        if (abs(input_value - interval_step[i]) < abs(input_value - closest)) {
+            closest = interval_step[i];
+        }
+    }
+    return closest;
+}
+
+int in_line(vec2 p1, vec2 p2, vec2 m) {
+    vec2 v = p2 - p1, w = m - p1;
+    float sq_len = dot(v, v);
+    if (sq_len < 0.001) return length(w) <= line_width ? 0 : -1;
+    float t = clamp(dot(w, v) / sq_len, 0.0, 1.0);
+    return length(m - (p1 + t * v)) <= line_width ? 0 : -1;
+}
+
+float[21] get_mark_line_1(float min_value, float max_value, float interval) {
+	float result[21];
+	float pin = grid_align_floor(min_value - interval, int(interval));
+	for(int i = 0; i < 21; i++) {
+		result[i] = pin + interval * float(i);
+	}
+	return result;
+}
+
+float[20] get_mark_line_2(float[21] mark_line_1) {
+	float result[20];
+	for(int i = 0; i < 20; i++) {
+		result[i] = (mark_line_1[i] + mark_line_1[i + 1]) / 2.0;
+	}
+	return result;
+}
+
+float[160] get_mark_line_3(float[21] mark_line_1, float[20] mark_line_2) {
+	float mark_line[41];
+    int i = 0, j = 0, k = 0;
+    while (i < 21 && j < 20) {
+        if (mark_line_1[i] < mark_line_2[j]) {
+            mark_line[k++] = mark_line_1[i++];
+        } else {
+            mark_line[k++] = mark_line_2[j++];
+        }
+    }
+    while (i < 21) mark_line[k++] = mark_line_1[i++];
+    while (j < 20) mark_line[k++] = mark_line_2[j++];
+	
+	
+	float result[160];
+	for(int i = 0; i < 40; i++) {
+		result[i * 4] = mark_line[i] + (mark_line[i + 1] - mark_line[i]) * 0.2;
+		result[i * 4 + 1] = mark_line[i] + (mark_line[i + 1] - mark_line[i]) * 0.4;
+		result[i * 4 + 2] = mark_line[i] + (mark_line[i + 1] - mark_line[i]) * 0.6;
+		result[i * 4 + 3] = mark_line[i] + (mark_line[i + 1] - mark_line[i]) * 0.8;
+	}
+	return result;
+}
+
+int detect_ruler_pixel(vec2 pos) {
+    // 选择坐标轴相关的参数
+    float mouse_coord = is_horizontal ? mouse_pos.x : mouse_pos.y;
+    float range_start = is_horizontal ? ruler_range.x : ruler_range.y;
+    float range_end = is_horizontal ? ruler_range.z : ruler_range.w;
+    float ruler_length = is_horizontal ? ruler_size.x : ruler_size.y;
+    float highlight_start = is_horizontal ? highlight_range.x : highlight_range.y;
+    float highlight_end = is_horizontal ? highlight_range.z : highlight_range.w;
+    
+    // 鼠标位置线检测
+    float t = affine_transform(mouse_coord, range_start, range_end, 0.0, ruler_length);
+    if (is_horizontal) {
+        if (in_line(vec2(t, 0.0), vec2(t, ruler_size.y), pos) >= 0) return 2;
+    } else {
+        if (in_line(vec2(0.0, t), vec2(ruler_size.x, t), pos) >= 0) return 2;
+    }
+    
+    // 标记线检测, 标线间隔根据横向范围决定
+    float interval = interval_round(abs(ruler_range.z - ruler_range.x) / 7.0); 
+    float detect_mark1[21] = get_mark_line_1(range_start, range_end, interval);
+    
+    for (int i = 0; i < 21; i++) {
+        // 主线检测
+        t = affine_transform(detect_mark1[i], range_start, range_end, 0.0, ruler_length);
+        if (is_horizontal) {
+            if (in_line(vec2(t, 0.0), vec2(t, ruler_size.y), pos) >= 0) return 1;
+        } else {
+            if (in_line(vec2(0.0, t), vec2(ruler_size.x, t), pos) >= 0) return 1;
+        }
+        
+        // 标签检测
+        float fIsDigit1;
+        if (is_horizontal) {
+			vec2 vFontSize = vec2(8.0, 15.0);
+            fIsDigit1 = PrintValue(pos, vec2(t + 4.0, -vFontSize.y - 2.0), vFontSize, detect_mark1[i]);
+        } else {
+            int d = quick_digit_count(int(detect_mark1[i]));
+			vec2 vFontSize;
+			if (d <= 3) vFontSize = vec2(8.0, 15.0);
+			else if (d <= 5) vFontSize = vec2(6.0, 15.0);
+			else vFontSize = vec2(5.0, 15.0);
+            fIsDigit1 = PrintValue(pos, vec2(2.0, -t - vFontSize.y - 2.0), vFontSize, detect_mark1[i]);
+			
+        }
+        if (fIsDigit1 > 0.0) return 1;
+    }
+    
+    // 二级标记线
+    float detect_mark2[20] = get_mark_line_2(detect_mark1);
+    for (int i = 0; i < 20; i++) {
+        if (detect_mark2[i] < range_start || detect_mark2[i] > range_end) continue;
+        
+        t = affine_transform(detect_mark2[i], range_start, range_end, 0.0, ruler_length);
+        if (is_horizontal) {
+            if (in_line(vec2(t, ruler_size.y * 0.5), vec2(t, ruler_size.y), pos) >= 0) return 1;
+        } else {
+            if (in_line(vec2(ruler_size.x * 0.5, t), vec2(ruler_size.x, t), pos) >= 0) return 1;
+        }
+    }
+    
+    // 三级标记线
+    float detect_mark3[160] = get_mark_line_3(detect_mark1, detect_mark2);
+    for (int i = 0; i < 160; i++) {
+        if (detect_mark3[i] < range_start || detect_mark3[i] > range_end) continue;
+        
+        t = affine_transform(detect_mark3[i], range_start, range_end, 0.0, ruler_length);
+        if (is_horizontal) {
+            if (in_line(vec2(t, ruler_size.y * 0.75), vec2(t, ruler_size.y), pos) >= 0) return 1;
+        } else {
+            if (in_line(vec2(ruler_size.x * 0.75, t), vec2(ruler_size.x, t), pos) >= 0) return 1;
+        }
+    }
+    
+    // 高亮区域检测
+    float coord = is_horizontal ? affine_transform(pos.x, 0.0, ruler_size.x, range_start, range_end)
+                               : affine_transform(pos.y, 0.0, ruler_size.y, range_start, range_end);
+    if (highlight_start <= coord && coord <= highlight_end) return 0;
+    
+    // 背景
+    return -1;
+}
+
+// ###########################################################################
+// ###########################################################################
+// ###########################################################################
+// ###########################################################################
+
+void vertex() {
+    pixel_pos = (CANVAS_MATRIX * vec4(VERTEX, 0.0, 1.0)).xy;
+}
+
+void fragment() {
+	int point_mode = detect_ruler_pixel(pixel_pos);
+	if (point_mode == 2)			COLOR = mouse_line_color;
+	else if (point_mode == 1)	COLOR = line_color;
+	else if (point_mode == 0)	COLOR = highlight_color;
+	else							COLOR = bg_color;
+}

+ 1 - 0
GameProject/Resources/Shader/CanvasRuler.gdshader.uid

@@ -0,0 +1 @@
+uid://cnsq1ra38csil

+ 100 - 0
GameProject/Resources/Shader/FreeTransform.gdshader

@@ -0,0 +1,100 @@
+shader_type canvas_item;
+
+const float base_line_width = 2.0f;
+const float base_square_size = 11.0f;
+const float base_center_size = 11.0f;
+
+// 使用数组传递点
+uniform vec2 points[4];
+uniform vec4 square_color: source_color;
+uniform vec4 square_line_color: source_color;
+uniform bool editable;
+
+varying vec2 pixel_pos;
+varying float line_width;
+varying float square_size;
+varying float center_size;
+
+int in_square(vec2 center, vec2 m) {
+    float dx = abs(m.x - center.x);
+    float dy = abs(m.y - center.y);
+    bool on_edge = (abs(dx - square_size) <= line_width && dy <= square_size) ||
+                   (abs(dy - square_size) <= line_width && dx <= square_size);
+    bool inside = dx <= square_size && dy <= square_size;
+    return on_edge ? 0 : (inside ? 1 : -1);
+}
+
+int in_line(vec2 p1, vec2 p2, vec2 m) {
+    vec2 v = p2 - p1, w = m - p1;
+    float sq_len = dot(v, v);
+    if (sq_len < 0.001) return length(w) <= line_width ? 0 : -1;
+    float t = clamp(dot(w, v) / sq_len, 0.0, 1.0);
+    return length(m - (p1 + t * v)) <= line_width ? 0 : -1;
+}
+
+int in_center(vec2 center, vec2 m)
+{
+	float dis = distance(center, m);
+	if (dis < line_width * 2.0)
+		return 0;
+	if (center_size - line_width < dis && dis < center_size + line_width)
+		return 0;
+	return -1;
+}
+
+int detect_pixel(vec2 check_points[9], vec2 pos) {
+    for (int i = 0; i < 8; i++) {  // 前8个是正方形检测
+        int result = in_square(check_points[i], pos);
+        if (result >= 0)
+			return result;
+    }
+
+    for (int i = 0; i < 4; i++) {  // 边线检测
+        int result = in_line(points[i], points[(i + 1) % 4], pos);
+        if (result >= 0)
+			return result;
+    }
+
+    // 中心区域检测
+    return in_center(check_points[8], pos);
+}
+
+
+void vertex() {
+    pixel_pos = (MODEL_MATRIX * vec4(VERTEX, 0.0, 1.0)).xy;
+
+	float scale = length(vec2(CANVAS_MATRIX[0][0], CANVAS_MATRIX[1][1]));
+	line_width = base_line_width / scale;
+	square_size = base_square_size / scale;
+	center_size = base_center_size / scale;
+}
+
+void fragment() {
+    vec2 check_points[9] = {
+		// 角点
+		points[0], points[1], points[2], points[3],
+		// 边中点
+		(points[0] + points[1]) / 2.0, (points[1] + points[2]) / 2.0,
+		(points[2] + points[3]) / 2.0, (points[3] + points[0]) / 2.0,
+		// 中心点
+		(points[0] + points[2]) / 2.0
+    };
+
+    int point_mode = -1;
+	if (editable)
+		point_mode = detect_pixel(check_points, pixel_pos);
+	else
+		for (int i = 0; i < 4; i++) {  // 边线检测
+			int result = in_line(check_points[i], check_points[(i + 1) % 4], pixel_pos);
+			if (result >= 0)
+				point_mode = 0;
+	    }
+
+
+	if (point_mode == 0)
+		COLOR = square_line_color;
+	else if(point_mode == 1)
+		COLOR = square_color;
+	else
+    	COLOR = texture(TEXTURE, UV);
+}

+ 1 - 0
GameProject/Resources/Shader/FreeTransform.gdshader.uid

@@ -0,0 +1 @@
+uid://cqg7diaaf5j6

+ 395 - 0
GameProject/Resources/Shader/TexturePalette.gdshader

@@ -0,0 +1,395 @@
+shader_type canvas_item;
+
+// 输入参数
+uniform int PaletteCount;
+uniform vec4 BasicColor[8] : source_color;
+uniform vec4 ModulateColor[8] : source_color;
+uniform float Tolerance[8];
+uniform int BlendMode[8];
+
+//#define DEBUG
+#ifdef DEBUG
+uniform sampler2D BlendTexture : source_color;
+#endif
+
+// ################################################################################################
+// ################################################################################################
+// ################################################################################################
+// ClusteringColor by CIEDE2000
+// https://www.shadertoy.com/view/msXyz8
+const float epsilon = 0.00001;
+float my_sin(float x) { return sin(radians(x)); }
+float my_cos(float x) { return cos(radians(x)); }
+float my_atan(float y, float x) {
+    float v = degrees(atan(y, x));
+    return (v < 0.0) ? v + 360.0 : v;
+}
+
+float get_h(float a, float b) {
+    bool a_and_b_are_zeros = (abs(a) < epsilon)&&(abs(b) < epsilon);
+    return a_and_b_are_zeros ? 0.0 : my_atan(b, a);
+}
+
+float get_delta_h(float C1, float C2, float h1, float h2) {
+    float diff = h2 - h1;
+    return (C1 * C2 < epsilon) ? 0.0 :
+    (abs(diff) <= 180.0) ? diff :
+    (diff > 180.0) ? diff - 360.0 :
+    diff + 360.0;
+}
+
+float get_h_bar(float C1, float C2, float h1, float h2) {
+    float dist = abs(h1 - h2);
+    float sum = h1 + h2;
+    return (C1 * C2 < epsilon) ? h1 + h2 :
+    (dist <= 180.0) ? 0.5 * sum :
+    (sum < 360.0) ? 0.5 * (sum + 360.0) :
+    0.5 * (sum - 360.0);
+
+}
+
+float calculate_CIEDE2000(vec3 Lab1, vec3 Lab2) {
+    float L1 = Lab1.x;
+    float a1 = Lab1.y;
+    float b1 = Lab1.z;
+    float L2 = Lab2.x;
+    float a2 = Lab2.y;
+    float b2 = Lab2.z;
+
+    float C1_ab = sqrt(a1 * a1 + b1 * b1);
+    float C2_ab = sqrt(a2 * a2 + b2 * b2);
+    float C_ab_bar = 0.5 * (C1_ab + C2_ab);
+    float G = 0.5 * (1.0 - sqrt(pow(C_ab_bar, 7.0) / (pow(C_ab_bar, 7.0) + pow(25.0, 7.0))));
+    float a_1 = (1.0 + G) * a1;
+    float a_2 = (1.0 + G) * a2;
+    float C1 = sqrt(a_1 * a_1 + b1 * b1);
+    float C2 = sqrt(a_2 * a_2 + b2 * b2);
+    float h1 = get_h(a_1, b1);
+    float h2 = get_h(a_2, b2);
+
+    float delta_L = L2 - L1;
+    float delta_C = C2 - C1;
+    float delta_h = get_delta_h(C1, C2, h1, h2);
+    float delta_H = 2.0 * sqrt(C1 * C2) * my_sin(0.5 * delta_h);
+
+    float L_bar = 0.5 * (L1 + L2);
+    float C_bar = 0.5 * (C1 + C2);
+    float h_bar = get_h_bar(C1, C2, h1, h2);
+
+    float T = 1.0 - 0.17 * my_cos(h_bar - 30.0) + 0.24 * my_cos(2.0 * h_bar) +
+    0.32 * my_cos(3.0 * h_bar + 6.0) - 0.20 * my_cos(4.0 * h_bar - 63.0);
+
+    float delta_theta = 30.0 * exp(-((h_bar - 275.0) / 25.0) * ((h_bar - 275.0) / 25.0));
+
+    float R_C = 2.0 * sqrt(pow(C_bar, 7.0) / (pow(C_bar, 7.0) + pow(25.0, 7.0)));
+    float S_L = 1.0 + (0.015 * (L_bar - 50.0) * (L_bar - 50.0)) / sqrt(20.0 + (L_bar - 50.0) * (L_bar - 50.0));
+    float S_C = 1.0 + 0.045 * C_bar;
+    float S_H = 1.0 + 0.015 * C_bar * T;
+    float R_T = -my_sin(2.0 * delta_theta) * R_C;
+
+    const float k_L = 1.0;
+    const float k_C = 1.0;
+    const float k_H = 1.0;
+
+    float deltaL = delta_L / (k_L * S_L);
+    float deltaC = delta_C / (k_C * S_C);
+    float deltaH = delta_H / (k_H * S_H);
+
+    float delta_E_squared = deltaL * deltaL + deltaC * deltaC + deltaH * deltaH + R_T * deltaC * deltaH;
+
+    return sqrt(delta_E_squared);
+}
+
+//--- RGB2Lab
+vec3 rgb2xyz(vec3 c) {
+    vec3 tmp;
+    tmp.x = (c.r > 0.04045) ? pow((c.r + 0.055) / 1.055, 2.4) : c.r / 12.92;
+    tmp.y = (c.g > 0.04045) ? pow((c.g + 0.055) / 1.055, 2.4) : c.g / 12.92;
+    tmp.z = (c.b > 0.04045) ? pow((c.b + 0.055) / 1.055, 2.4) : c.b / 12.92;
+    return 100.0 * tmp * mat3(vec3(0.4124, 0.3576, 0.1805), vec3(0.2126, 0.7152, 0.0722), vec3(0.0193, 0.1192, 0.9505));
+}
+vec3 xyz2lab(vec3 c) {
+    vec3 n = c / vec3(95.047, 100.0, 108.883);
+    vec3 v;
+    v.x = (n.x > 0.008856) ? pow(n.x, 1.0 / 3.0) : (7.787 * n.x) + (16.0 / 116.0);
+    v.y = (n.y > 0.008856) ? pow(n.y, 1.0 / 3.0) : (7.787 * n.y) + (16.0 / 116.0);
+    v.z = (n.z > 0.008856) ? pow(n.z, 1.0 / 3.0) : (7.787 * n.z) + (16.0 / 116.0);
+    return vec3((116.0 * v.y) - 16.0, 500.0 * (v.x - v.y), 200.0 * (v.y - v.z));
+}
+
+vec3 rgb2lab(vec3 c) {
+    vec3 lab = xyz2lab(rgb2xyz(c));
+    return vec3(lab.x / 100.0, 0.5 + 0.5 * (lab.y / 127.0), 0.5 + 0.5 * (lab.z / 127.0));
+}
+
+float colorCompare(vec3 rgb1, vec3 rgb2) {
+    vec3 lab1 = rgb2lab(rgb1);
+    vec3 lab2 = rgb2lab(rgb2);
+    return calculate_CIEDE2000(lab1, lab2);
+}
+
+// ################################################################################################
+// ################################################################################################
+// ################################################################################################
+// blends modes
+// https://en.wikipedia.org/wiki/Blend_modes
+// pdf page 389 blend mode: https://developer.adobe.com/document-services/docs/assets/5b15559b96303194340b99820d3a70fa/PDF_ISO_32000-2.pdf
+
+// functions
+#define VEC3(C, FUNC) vec3(FUNC(C.r), FUNC(C.g), FUNC(C.b))
+#define MAKE_VEC3(BASE, BLEND, FUNC) vec3(FUNC(BASE.r, BLEND.r), FUNC(BASE.g, BLEND.g), FUNC(BASE.b, BLEND.b))
+#define CMIN(C) min(C.r, min(C.g, C.b))
+#define CMAX(C) max(C.r, max(C.g, C.b))
+
+float unionAlpha(float b, float s) { return b + s * (1.0 - b); }
+
+float getLum(vec3 c) { return 0.3 * c.r + 0.59 * c.g + 0.11 * c.b; } // Luminosity
+
+vec3 clipColor(vec3 c)
+{
+	float l = getLum(c);
+	float n = CMIN(c);
+	float x = CMAX(c);
+	if (n < 0.0) return l + (((c - l) * l) / (l - n));
+	if (x > 1.0) return l + (((c - l) * (1.0 - l)) / (l - n));
+	return c;
+}
+
+vec3 setLum(vec3 c, float l)
+{
+    float d = l - getLum(c);
+    c += d;
+	return clipColor(c);
+}
+
+float getSat(vec3 c) { return CMAX(c) - CMIN(c); } // Saturation
+
+vec3 setSat(vec3 C, float s)
+{
+	// subscripts for Cmin, Cmid, and Cmax
+	int indices[3];
+    if (C.x <= C.y) {
+		if (C.y <= C.z) indices = int[3](0, 1, 2); 		// x <= y <= z
+		else if (C.x <= C.z) indices = int[3](0, 2, 1); 	// x <= z < y
+		else indices = int[3](2, 0, 1); 					// z < x <= y
+    } else {
+        if (C.x <= C.z) indices = int[3](1, 0, 2); 		// y < x <= z
+        else if (C.y <= C.z)indices = int[3](1, 2, 0); 	// y <= z < x
+        else indices = int[3](2, 1, 0); 					// z < y < x
+    }
+
+	// set Saturation
+	if (C[indices[2]] > C[indices[0]])
+	{
+		C[indices[1]] = (((C[indices[1]] - C[indices[0]]) * s) / (C[indices[2]] - C[indices[0]]));
+		C[indices[2]] = s;
+	} else {
+		C[indices[1]] = 0.0;
+		C[indices[2]] = 0.0;
+	}
+	C[indices[0]] = 0.0;
+
+	return C;
+}
+
+// 正常
+vec3 normal( vec3 Cb, vec3 Cs ) { return Cs; }
+
+// 正片叠底
+float _multiply( float Cb, float Cs ) {	return Cb * Cs; }
+vec3 multiply( vec3 Cb, vec3 Cs ) {	return Cb * Cs; }
+
+// 滤色
+float _screen( float Cb, float Cs ) { return Cb + Cs - Cb * Cs; }
+vec3 screen( vec3 Cb, vec3 Cs ) { return Cb + Cs - Cb * Cs; }
+
+// 变暗
+vec3 darken( vec3 Cb, vec3 Cs ) { return min(Cb, Cs); }
+
+// 变亮
+vec3 lighten( vec3 Cb, vec3 Cs ) { return max(Cb, Cs); }
+
+// 颜色减淡
+float _colorDodge( float Cb, float Cs )
+{
+	if(Cb <= 0.0) return 0.0;
+	else if (Cb >= (1.0 - Cs)) return 1.0;
+	else return Cb / (1.0 - Cs);
+}
+vec3 colorDodge( vec3 Cb, vec3 Cs ) { return MAKE_VEC3(Cb, Cs, _colorDodge); }
+
+// 颜色加深
+float _colorBurn(float Cb, float Cs)
+{
+	if (Cb >= 1.0) return 1.0;
+	if ((1.0 - Cb) >= Cs) return 0.0;
+	else return 1.0 - ((1.0 - Cb) / Cs);
+}
+vec3 colorBurn( vec3 Cb, vec3 Cs) { return MAKE_VEC3(Cb, Cs, _colorBurn); }
+
+// 强光
+float _hardLight( float Cb, float Cs ) { return (Cs <= 0.5) ? _multiply(Cb, 2.0 * Cs): _screen(Cb, 2.0 * Cs - 1.0); }
+vec3 hardLight( vec3 Cb, vec3 Cs ) { return MAKE_VEC3(Cb, Cs, _hardLight); }
+
+// 柔光
+float _softLight( float Cb, float Cs )
+{
+	if(Cs <= 0.5) return Cb - (1.0 - 2.0 * Cs) * Cb * (1.0 - Cb);
+	else
+	{
+		float d = (Cb <= 0.25) ? ((16.0 * Cb - 12.0) * Cb + 4.0) * Cb : sqrt(Cb);
+		return Cb + (2.0 * Cs - 1.0) * (d - Cb);
+	}
+}
+vec3 softLight( vec3 Cb, vec3 Cs ) { return MAKE_VEC3(Cb, Cs, _softLight); }
+
+// 叠加
+vec3 overlay( vec3 Cb, vec3 Cs ) { return hardLight(Cs, Cb);  }
+
+// 差值
+vec3 difference( vec3 Cb, vec3 Cs ) { return abs(Cb - Cs); }
+
+// 排除
+vec3 exclusion( vec3 Cb, vec3 Cs ) { return Cb + Cs - 2.0 * Cb * Cs; }
+
+// 色相
+vec3 hue( vec3 Cb, vec3 Cs ) { return setLum(setSat(Cs, getSat(Cb)), getLum(Cb)); }
+
+// 颜色
+vec3 color( vec3 Cb, vec3 Cs ) { return setLum(Cs, getLum(Cb)); }
+
+// 饱和度
+vec3 saturation( vec3 Cb, vec3 Cs ) { return setLum(setSat(Cb, getSat(Cs)), getLum(Cb)); }
+
+// 明度
+vec3 luminosity( vec3 Cb, vec3 Cs ) { return setLum(Cb, getLum(Cs)); }
+
+
+// 剩下的不在pdf标准中
+
+// 线性加深
+float _linearBurn(float Cb, float Cs) { return max(0, Cb + Cs - 1.0); }
+vec3 linearBurn( vec3 Cb, vec3 Cs ) { return MAKE_VEC3(Cb, Cs, _linearBurn); }
+
+// 深色
+vec3 darkerColor( vec3 Cb, vec3 Cs ) { return getLum(Cb) < getLum(Cs)? Cb: Cs; }
+
+// 线性减淡(添加)
+float _linearDodge(float Cb, float Cs) { return min(1.0, Cb + Cs); }
+vec3 linearDodge( vec3 Cb, vec3 Cs ) { return MAKE_VEC3(Cb, Cs, _linearDodge); }
+
+// 浅色
+vec3 lighterColor( vec3 Cb, vec3 Cs ) { return getLum(Cb) > getLum(Cs)? Cb: Cs; }
+
+// 亮光
+float _vividLight( float Cb, float Cs ) { return (Cs <= 0.5) ? _colorBurn(Cb, 2.0 * Cs): _colorDodge(Cb, 2.0 * (Cs - 0.5)); }
+vec3 vividLight( vec3 Cb, vec3 Cs ) { return MAKE_VEC3(Cb, Cs, _vividLight); }
+
+// 线性光
+float _linearLight( float Cb, float Cs ) { return (Cs <= 0.5) ? _linearBurn(Cb, 2.0 * Cs): _linearDodge(Cb, 2.0 * (Cs - 0.5)); }
+vec3 linearLight( vec3 Cb, vec3 Cs ) { return MAKE_VEC3(Cb, Cs, _linearLight); }
+
+// 点光
+float _pinLight( float Cb, float Cs ) { return (Cs <= 0.5) ? min(Cb,2.0 * Cs) : max(Cb,2.0 * (Cs - 0.5)); }
+vec3 pinLight( vec3 Cb, vec3 Cs ) { return MAKE_VEC3(Cb, Cs, _pinLight); }
+
+// 实色混合
+float _hardMix( float Cb, float Cs ) { return (Cb + Cs >= 1.0) ? 1.0 : 0.0; }
+vec3 hardMix( vec3 Cb, vec3 Cs ) { return MAKE_VEC3(Cb, Cs, _hardMix); }
+
+// 减去
+vec3 subtract( vec3 Cb, vec3 Cs ) { return max(vec3(0.0), Cb - Cs); }
+
+// 划分
+float _divide( float Cb, float Cs ) { return Cs > 0.0 ? min(1.0, Cb / Cs) : 1.0; }
+vec3 divide( vec3 Cb, vec3 Cs ) { return MAKE_VEC3(Cb, Cs, _divide); }
+
+
+
+vec3 blendFunctions( vec3 Cb, vec3 Cs, int id )
+{
+	if(id==0)	return normal(Cb,Cs);        // 正常
+
+	if(id==1)	return darken(Cb,Cs);        // 变暗
+	if(id==2)	return multiply(Cb,Cs);      // 正片叠底
+	if(id==3)	return colorBurn(Cb,Cs);     // 颜色加深
+	if(id==4)	return linearBurn(Cb,Cs);    // 线性加深
+	if(id==5)	return darkerColor(Cb,Cs);   // 深色
+
+	if(id==6)	return lighten(Cb,Cs);       // 变亮
+	if(id==7)	return screen(Cb,Cs);        // 滤色
+	if(id==8)	return colorDodge(Cb,Cs);    // 颜色减淡
+	if(id==9)	return linearDodge(Cb,Cs);   // 线性减淡(添加)
+	if(id==10)	return lighterColor(Cb,Cs);  // 浅色
+
+	if(id==11)	return overlay(Cb,Cs);       // 叠加
+	if(id==12)	return softLight(Cb,Cs);     // 柔光
+	if(id==13)	return hardLight(Cb,Cs);     // 强光
+	if(id==14)	return vividLight(Cb,Cs);    // 亮光
+	if(id==15)	return linearLight(Cb,Cs);   // 线性光
+	if(id==16)	return pinLight(Cb,Cs);      // 点光
+	if(id==17)	return hardMix(Cb,Cs);       // 实色混合
+
+	if(id==18)	return difference(Cb,Cs);    // 差值
+	if(id==19)	return exclusion(Cb,Cs);     // 排除
+	if(id==20)	return subtract(Cb,Cs);      // 减去
+	if(id==21)	return divide(Cb,Cs);        // 划分
+
+	if(id==22)	return hue(Cb,Cs);           // 色相
+	if(id==23)	return saturation(Cb,Cs);    // 饱和度
+	if(id==24)	return color(Cb,Cs);         // 颜色
+	if(id==25)	return luminosity(Cb,Cs);    // 明度
+
+    return vec3(0.0);
+}
+
+
+
+// ################################################################################################
+// ################################################################################################
+// ################################################################################################
+// gd shader script
+void fragment() {
+	COLOR = texture(TEXTURE, UV);
+
+	for (int i =0; i< PaletteCount; i++)
+	{
+		vec4 modulate_color = ModulateColor[i];
+		vec4 basic_color = BasicColor[i];
+		int blend_mode = BlendMode[i];
+		float tolerance = Tolerance[i];
+
+	    // 将容差转换为0-1范围的阈值
+	    float tolerance_factor = tolerance / 100.0;
+
+		// Backdrop colour 背景色
+	    vec3 Cb = COLOR.rgb;
+		float Ab = COLOR.a;
+
+		// Source colour 混合色
+#ifdef DEBUG
+		vec4 source_colour = texture(BlendTexture, UV);
+	    vec3 Cs = source_colour.rgb;
+		float As = source_colour.a;
+#else
+		vec4 source_colour = modulate_color;
+	    vec3 Cs = source_colour.rgb;
+		float As = Ab > 0.0? source_colour.a: 0.0;
+#endif
+
+		// Result colour
+		float Ar = unionAlpha(Ab, As);
+		vec3 Cr = (1.0 - As / Ar) * Cb + As / Ar * ((1.0 - Ab) * Cs + Ab * blendFunctions(Cb, Cs, blend_mode));
+
+	    // 混合原始颜色和调制后的颜色
+		if (tolerance_factor >= 1.0)
+			COLOR = vec4(Cr, Ar);
+		else
+		{
+		    // 计算颜色差异
+	    	float dis = colorCompare(Cb, basic_color.rgb);
+			if (dis < tolerance_factor)
+		    	COLOR = vec4(Cr, Ar);
+		}
+	}
+}

+ 1 - 0
GameProject/Resources/Shader/TexturePalette.gdshader.uid

@@ -0,0 +1 @@
+uid://muay5jeyd64p

+ 401 - 0
GameProject/Resources/Theme/basic_theme.tres

@@ -0,0 +1,401 @@
+[gd_resource type="Theme" load_steps=40 format=3 uid="uid://dmgdeh6kw3b7u"]
+
+[ext_resource type="Texture2D" uid="uid://dbgwel7glmmbc" path="res://Resources/UI/checkmark.png" id="1_g2lka"]
+[ext_resource type="Texture2D" uid="uid://b8yayq1snap10" path="res://Resources/__blank__.png" id="2_20yrs"]
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_frdby"]
+content_margin_left = 8.0
+content_margin_top = 4.0
+content_margin_right = 8.0
+content_margin_bottom = 4.0
+bg_color = Color(0.168627, 0.168627, 0.168627, 1)
+corner_radius_top_left = 4
+corner_radius_top_right = 4
+corner_radius_bottom_right = 4
+corner_radius_bottom_left = 4
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_3y7p3"]
+content_margin_left = 8.0
+content_margin_top = 4.0
+content_margin_right = 8.0
+content_margin_bottom = 4.0
+bg_color = Color(0.278431, 0.278431, 0.278431, 0)
+corner_radius_top_left = 4
+corner_radius_top_right = 4
+corner_radius_bottom_right = 4
+corner_radius_bottom_left = 4
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_drp83"]
+content_margin_left = 8.0
+content_margin_top = 4.0
+content_margin_right = 8.0
+content_margin_bottom = 4.0
+bg_color = Color(0.160784, 0.160784, 0.160784, 1)
+corner_radius_top_left = 4
+corner_radius_top_right = 4
+corner_radius_bottom_right = 4
+corner_radius_bottom_left = 4
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_bsxcp"]
+content_margin_left = 8.0
+content_margin_top = 4.0
+content_margin_right = 8.0
+content_margin_bottom = 4.0
+bg_color = Color(0.278431, 0.278431, 0.278431, 1)
+corner_radius_top_left = 4
+corner_radius_top_right = 4
+corner_radius_bottom_right = 4
+corner_radius_bottom_left = 4
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_tnytw"]
+bg_color = Color(0.6, 0.6, 0.6, 0)
+border_width_left = 1
+border_width_top = 1
+border_width_right = 1
+border_width_bottom = 1
+corner_radius_top_left = 4
+corner_radius_top_right = 4
+corner_radius_bottom_right = 4
+corner_radius_bottom_left = 4
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_8rspo"]
+bg_color = Color(0.196078, 0.196078, 0.196078, 1)
+border_width_left = 1
+border_width_top = 1
+border_width_right = 1
+border_width_bottom = 1
+corner_radius_top_left = 4
+corner_radius_top_right = 4
+corner_radius_bottom_right = 4
+corner_radius_bottom_left = 4
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_5gcxw"]
+bg_color = Color(0, 0.67451, 0.858824, 1)
+border_width_left = 1
+border_width_top = 1
+border_width_right = 1
+border_width_bottom = 1
+corner_radius_top_left = 4
+corner_radius_top_right = 4
+corner_radius_bottom_right = 4
+corner_radius_bottom_left = 4
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ihynx"]
+bg_color = Color(0.196078, 0.196078, 0.196078, 1)
+draw_center = false
+border_width_left = 1
+border_width_top = 1
+border_width_right = 1
+border_width_bottom = 1
+corner_radius_top_left = 4
+corner_radius_top_right = 4
+corner_radius_bottom_right = 4
+corner_radius_bottom_left = 4
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_20yrs"]
+bg_color = Color(0, 0.67451, 0.858824, 1)
+border_width_left = 1
+border_width_top = 1
+border_width_right = 1
+border_width_bottom = 1
+corner_radius_top_left = 4
+corner_radius_top_right = 4
+corner_radius_bottom_right = 4
+corner_radius_bottom_left = 4
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ek5qo"]
+bg_color = Color(0.278431, 0.278431, 0.278431, 0)
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_uldmd"]
+bg_color = Color(0.168627, 0.168627, 0.168627, 1)
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_g2lka"]
+bg_color = Color(0.6, 0.6, 0.6, 0)
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_amlv4"]
+content_margin_left = 8.0
+content_margin_top = 4.0
+content_margin_right = 8.0
+content_margin_bottom = 4.0
+bg_color = Color(0.247059, 0.247059, 0.247059, 1)
+corner_radius_top_left = 4
+corner_radius_top_right = 4
+corner_radius_bottom_right = 4
+corner_radius_bottom_left = 4
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_cpawf"]
+content_margin_left = 8.0
+content_margin_top = 4.0
+content_margin_right = 8.0
+content_margin_bottom = 4.0
+bg_color = Color(0.168627, 0.168627, 0.168627, 1)
+border_width_bottom = 2
+border_color = Color(0.137255, 0.137255, 0.137255, 1)
+corner_radius_top_left = 4
+corner_radius_top_right = 4
+corner_radius_bottom_right = 4
+corner_radius_bottom_left = 4
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_4p1b7"]
+content_margin_left = 32.0
+content_margin_right = 32.0
+bg_color = Color(0.243137, 0.243137, 0.243137, 1)
+corner_radius_top_left = 1
+corner_radius_top_right = 1
+corner_radius_bottom_right = 1
+corner_radius_bottom_left = 1
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_78ylj"]
+content_margin_left = 32.0
+content_margin_right = 32.0
+bg_color = Color(0, 0, 0, 0)
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_gf2og"]
+content_margin_left = 32.0
+content_margin_top = 1.0
+content_margin_right = 32.0
+content_margin_bottom = 1.0
+bg_color = Color(0.243137, 0.243137, 0.243137, 1)
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_syf6d"]
+content_margin_left = 8.0
+content_margin_top = 4.0
+content_margin_right = 8.0
+content_margin_bottom = 4.0
+bg_color = Color(0.0705882, 0.0705882, 0.0705882, 1)
+corner_radius_top_left = 4
+corner_radius_top_right = 4
+corner_radius_bottom_right = 4
+corner_radius_bottom_left = 4
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_kpnqv"]
+bg_color = Color(0.168627, 0.168627, 0.168627, 1)
+border_width_left = 2
+border_width_top = 2
+border_width_right = 2
+border_width_bottom = 2
+border_color = Color(0.129412, 0.129412, 0.129412, 1)
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_50tw5"]
+content_margin_left = 32.0
+content_margin_top = 8.0
+content_margin_right = 32.0
+content_margin_bottom = 8.0
+bg_color = Color(0.196078, 0.196078, 0.196078, 1)
+border_width_left = 1
+border_width_top = 1
+border_width_right = 1
+border_width_bottom = 1
+border_color = Color(0.129412, 0.129412, 0.129412, 1)
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_owfym"]
+content_margin_left = 32.0
+content_margin_top = 8.0
+content_margin_right = 32.0
+content_margin_bottom = 8.0
+bg_color = Color(0.180392, 0.180392, 0.180392, 1)
+border_width_left = 1
+border_width_top = 1
+border_width_right = 1
+border_width_bottom = 1
+border_color = Color(0.129412, 0.129412, 0.129412, 1)
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_64m1p"]
+content_margin_left = 32.0
+content_margin_top = 8.0
+content_margin_right = 32.0
+content_margin_bottom = 8.0
+bg_color = Color(0.196078, 0.196078, 0.196078, 1)
+border_width_left = 1
+border_width_top = 1
+border_width_right = 1
+border_width_bottom = 1
+border_color = Color(0.129412, 0.129412, 0.129412, 1)
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_gscau"]
+content_margin_left = 32.0
+content_margin_top = 8.0
+content_margin_right = 32.0
+content_margin_bottom = 8.0
+bg_color = Color(0.14902, 0.14902, 0.14902, 1)
+border_width_left = 1
+border_width_top = 1
+border_width_right = 1
+border_width_bottom = 1
+border_color = Color(0.129412, 0.129412, 0.129412, 1)
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_pfqjd"]
+bg_color = Color(0.0627451, 0.0627451, 0.0627451, 1)
+corner_detail = 1
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_nkfox"]
+content_margin_left = 32.0
+content_margin_top = 8.0
+content_margin_right = 32.0
+content_margin_bottom = 8.0
+bg_color = Color(0.168627, 0.168627, 0.168627, 1)
+border_width_left = 1
+border_width_top = 1
+border_width_right = 1
+border_width_bottom = 1
+border_color = Color(0.129412, 0.129412, 0.129412, 1)
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_aggjg"]
+content_margin_left = 32.0
+content_margin_top = 8.0
+content_margin_right = 32.0
+content_margin_bottom = 8.0
+bg_color = Color(0.196078, 0.196078, 0.196078, 1)
+border_width_left = 1
+border_width_top = 1
+border_width_right = 1
+border_width_bottom = 1
+border_color = Color(0.129412, 0.129412, 0.129412, 1)
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_nft0o"]
+content_margin_left = 32.0
+content_margin_top = 8.0
+content_margin_right = 32.0
+content_margin_bottom = 8.0
+bg_color = Color(0.180392, 0.180392, 0.180392, 1)
+border_width_left = 1
+border_width_top = 1
+border_width_right = 1
+border_width_bottom = 1
+border_color = Color(0.196078, 0.196078, 0.196078, 1)
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_0xefo"]
+content_margin_left = 32.0
+content_margin_top = 8.0
+content_margin_right = 32.0
+content_margin_bottom = 8.0
+bg_color = Color(0.196078, 0.196078, 0.196078, 1)
+border_width_left = 1
+border_width_top = 1
+border_width_right = 1
+border_width_bottom = 1
+border_color = Color(0.129412, 0.129412, 0.129412, 1)
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_i66g5"]
+content_margin_left = 32.0
+content_margin_top = 8.0
+content_margin_right = 32.0
+content_margin_bottom = 8.0
+bg_color = Color(0.14902, 0.14902, 0.14902, 1)
+border_width_left = 1
+border_width_top = 1
+border_width_right = 1
+border_width_bottom = 1
+border_color = Color(0.129412, 0.129412, 0.129412, 1)
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_gopvb"]
+bg_color = Color(0.14902, 0.14902, 0.14902, 1)
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_j2q5q"]
+content_margin_left = 8.0
+content_margin_top = 4.0
+content_margin_right = 8.0
+content_margin_bottom = 4.0
+bg_color = Color(0.247059, 0.247059, 0.247059, 1)
+corner_radius_top_left = 4
+corner_radius_top_right = 4
+corner_radius_bottom_right = 4
+corner_radius_bottom_left = 4
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_a0awj"]
+content_margin_left = 8.0
+content_margin_top = 4.0
+content_margin_right = 8.0
+content_margin_bottom = 4.0
+bg_color = Color(0.168627, 0.168627, 0.168627, 1)
+border_width_bottom = 2
+border_color = Color(0.137255, 0.137255, 0.137255, 1)
+corner_radius_top_left = 4
+corner_radius_top_right = 4
+corner_radius_bottom_right = 4
+corner_radius_bottom_left = 4
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_8iapp"]
+bg_color = Color(0.6, 0.6, 0.6, 0)
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_37gq2"]
+bg_color = Color(0.168627, 0.168627, 0.168627, 1)
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_lyb8g"]
+content_margin_left = 8.0
+content_margin_top = 4.0
+content_margin_right = 8.0
+content_margin_bottom = 4.0
+bg_color = Color(0.168627, 0.168627, 0.168627, 1)
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_i7eh4"]
+content_margin_left = 8.0
+content_margin_top = 4.0
+content_margin_right = 8.0
+content_margin_bottom = 4.0
+bg_color = Color(0.168627, 0.168627, 0.168627, 1)
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_lnu2b"]
+content_margin_left = 8.0
+content_margin_top = 4.0
+content_margin_right = 8.0
+content_margin_bottom = 4.0
+bg_color = Color(0.168627, 0.168627, 0.168627, 1)
+
+[resource]
+Button/styles/disabled = SubResource("StyleBoxFlat_frdby")
+Button/styles/focus = SubResource("StyleBoxFlat_3y7p3")
+Button/styles/hover = SubResource("StyleBoxFlat_drp83")
+Button/styles/normal = SubResource("StyleBoxFlat_bsxcp")
+CheckBox/icons/checked = ExtResource("1_g2lka")
+CheckBox/icons/unchecked = ExtResource("2_20yrs")
+CheckBox/styles/focus = SubResource("StyleBoxFlat_tnytw")
+CheckBox/styles/hover = SubResource("StyleBoxFlat_8rspo")
+CheckBox/styles/hover_pressed = SubResource("StyleBoxFlat_5gcxw")
+CheckBox/styles/normal = SubResource("StyleBoxFlat_ihynx")
+CheckBox/styles/pressed = SubResource("StyleBoxFlat_20yrs")
+ItemList/colors/font_color = Color(1, 1, 1, 1)
+ItemList/styles/focus = SubResource("StyleBoxFlat_ek5qo")
+ItemList/styles/panel = SubResource("StyleBoxFlat_uldmd")
+LineEdit/styles/focus = SubResource("StyleBoxFlat_g2lka")
+LineEdit/styles/normal = SubResource("StyleBoxFlat_amlv4")
+LineEdit/styles/read_only = SubResource("StyleBoxFlat_cpawf")
+MarginContainer/constants/margin_bottom = 8
+MarginContainer/constants/margin_left = 8
+MarginContainer/constants/margin_right = 8
+MarginContainer/constants/margin_top = 8
+MenuBar/font_sizes/font_size = 18
+MenuBar/styles/hover = SubResource("StyleBoxFlat_4p1b7")
+MenuBar/styles/normal = SubResource("StyleBoxFlat_78ylj")
+MenuBar/styles/pressed = SubResource("StyleBoxFlat_gf2og")
+OptionButton/styles/pressed = SubResource("StyleBoxFlat_syf6d")
+PanelContainer/styles/panel = SubResource("StyleBoxFlat_kpnqv")
+PopupMenu/font_sizes/font_size = 20
+PopupMenu/font_sizes/title_font_size = 20
+TabBar/styles/tab_focus = SubResource("StyleBoxFlat_50tw5")
+TabBar/styles/tab_hovered = SubResource("StyleBoxFlat_owfym")
+TabBar/styles/tab_selected = SubResource("StyleBoxFlat_64m1p")
+TabBar/styles/tab_unselected = SubResource("StyleBoxFlat_gscau")
+TabContainer/colors/font_hovered_color = Color(0.529412, 0.529412, 0.529412, 1)
+TabContainer/colors/font_selected_color = Color(0.882353, 0.882353, 0.882353, 1)
+TabContainer/colors/font_unselected_color = Color(0.529412, 0.529412, 0.529412, 1)
+TabContainer/constants/side_margin = 0
+TabContainer/font_sizes/font_size = 16
+TabContainer/styles/panel = SubResource("StyleBoxFlat_pfqjd")
+TabContainer/styles/tab_disabled = SubResource("StyleBoxFlat_nkfox")
+TabContainer/styles/tab_focus = SubResource("StyleBoxFlat_aggjg")
+TabContainer/styles/tab_hovered = SubResource("StyleBoxFlat_nft0o")
+TabContainer/styles/tab_selected = SubResource("StyleBoxFlat_0xefo")
+TabContainer/styles/tab_unselected = SubResource("StyleBoxFlat_i66g5")
+TabContainer/styles/tabbar_background = SubResource("StyleBoxFlat_gopvb")
+TextEdit/styles/normal = SubResource("StyleBoxFlat_j2q5q")
+TextEdit/styles/read_only = SubResource("StyleBoxFlat_a0awj")
+Tree/constants/button_margin = 0
+Tree/font_sizes/title_button_font_size = 20
+Tree/styles/button_hover = null
+Tree/styles/button_pressed = null
+Tree/styles/focus = SubResource("StyleBoxFlat_8iapp")
+Tree/styles/panel = SubResource("StyleBoxFlat_37gq2")
+Tree/styles/title_button_hover = SubResource("StyleBoxFlat_lyb8g")
+Tree/styles/title_button_normal = SubResource("StyleBoxFlat_i7eh4")
+Tree/styles/title_button_pressed = SubResource("StyleBoxFlat_lnu2b")

+ 29 - 0
GameProject/Resources/Theme/check_button_theme.tres

@@ -0,0 +1,29 @@
+[gd_resource type="Theme" load_steps=5 format=3 uid="uid://cwtfo6s86vv46"]
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_i2k3q"]
+bg_color = Color(0.121569, 0.121569, 0.121569, 1)
+border_width_left = 1
+border_width_top = 1
+border_width_right = 1
+border_width_bottom = 1
+border_color = Color(0.243137, 0.243137, 0.243137, 1)
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ubknm"]
+bg_color = Color(0.121569, 0.121569, 0.121569, 1)
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_eb670"]
+bg_color = Color(0.196078, 0.196078, 0.196078, 1)
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_acw6a"]
+bg_color = Color(0.121569, 0.121569, 0.121569, 1)
+border_width_left = 1
+border_width_top = 1
+border_width_right = 1
+border_width_bottom = 1
+border_color = Color(0.243137, 0.243137, 0.243137, 1)
+
+[resource]
+Button/styles/focus = SubResource("StyleBoxFlat_i2k3q")
+Button/styles/hover = SubResource("StyleBoxFlat_ubknm")
+Button/styles/normal = SubResource("StyleBoxFlat_eb670")
+Button/styles/pressed = SubResource("StyleBoxFlat_acw6a")

+ 56 - 0
GameProject/Resources/Theme/scope_check_button_theme.tres

@@ -0,0 +1,56 @@
+[gd_resource type="Theme" load_steps=5 format=3 uid="uid://dg14k5tu0s0mq"]
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_i2k3q"]
+content_margin_left = 4.0
+content_margin_right = 4.0
+bg_color = Color(0, 0, 0, 0)
+border_width_left = 1
+border_width_top = 1
+border_width_right = 1
+border_width_bottom = 1
+corner_radius_top_left = 9
+corner_radius_top_right = 9
+corner_radius_bottom_right = 9
+corner_radius_bottom_left = 9
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_pmwt0"]
+border_width_left = 1
+border_width_top = 1
+border_width_right = 1
+border_width_bottom = 1
+corner_radius_top_left = 9
+corner_radius_top_right = 9
+corner_radius_bottom_right = 9
+corner_radius_bottom_left = 9
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_eb670"]
+content_margin_left = 8.0
+content_margin_right = 8.0
+bg_color = Color(0.196078, 0.196078, 0.196078, 1)
+border_width_left = 1
+border_width_top = 1
+border_width_right = 1
+border_width_bottom = 1
+corner_radius_top_left = 9
+corner_radius_top_right = 9
+corner_radius_bottom_right = 9
+corner_radius_bottom_left = 9
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_acw6a"]
+content_margin_left = 4.0
+content_margin_right = 4.0
+bg_color = Color(0, 0.67451, 0.858824, 1)
+border_width_left = 1
+border_width_top = 1
+border_width_right = 1
+border_width_bottom = 1
+corner_radius_top_left = 9
+corner_radius_top_right = 9
+corner_radius_bottom_right = 9
+corner_radius_bottom_left = 9
+
+[resource]
+Button/styles/focus = SubResource("StyleBoxFlat_i2k3q")
+Button/styles/hover = SubResource("StyleBoxFlat_pmwt0")
+Button/styles/normal = SubResource("StyleBoxFlat_eb670")
+Button/styles/pressed = SubResource("StyleBoxFlat_acw6a")

BIN
GameProject/Resources/UI/Collapse.png


+ 34 - 0
GameProject/Resources/UI/Collapse.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cfxsgw26y5to2"
+path="res://.godot/imported/Collapse.png-2ea422fc46be5cf02e92bfc1d3146ca2.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/Collapse.png"
+dest_files=["res://.godot/imported/Collapse.png-2ea422fc46be5cf02e92bfc1d3146ca2.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/Down.png


+ 34 - 0
GameProject/Resources/UI/Down.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://wu26xc4o1g5d"
+path="res://.godot/imported/Down.png-aee552d477a42dba4ac369272521d601.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/Down.png"
+dest_files=["res://.godot/imported/Down.png-aee552d477a42dba4ac369272521d601.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/Expands.png


+ 34 - 0
GameProject/Resources/UI/Expands.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dfehigjgwe6u4"
+path="res://.godot/imported/Expands.png-1166f64a6a40117a18b2e2f570e7d2b6.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/Expands.png"
+dest_files=["res://.godot/imported/Expands.png-1166f64a6a40117a18b2e2f570e7d2b6.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/IconView.png


+ 34 - 0
GameProject/Resources/UI/IconView.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://glgfr62yi22i"
+path="res://.godot/imported/IconView.png-aefe1992b6b157e415aa3f14fc80dd86.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/IconView.png"
+dest_files=["res://.godot/imported/IconView.png-aefe1992b6b157e415aa3f14fc80dd86.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/LayerArrow.png


+ 34 - 0
GameProject/Resources/UI/LayerArrow.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cubag4vubjuki"
+path="res://.godot/imported/LayerArrow.png-7f99186a10ca67722c0ba916821de615.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/LayerArrow.png"
+dest_files=["res://.godot/imported/LayerArrow.png-7f99186a10ca67722c0ba916821de615.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/ListView.png


+ 34 - 0
GameProject/Resources/UI/ListView.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bl03w0pwgqv8i"
+path="res://.godot/imported/ListView.png-86b157b1ebe0f02c291a35024986fb90.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/ListView.png"
+dest_files=["res://.godot/imported/ListView.png-86b157b1ebe0f02c291a35024986fb90.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/OpenFolder.png


+ 34 - 0
GameProject/Resources/UI/OpenFolder.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ceybxsaijqkri"
+path="res://.godot/imported/OpenFolder.png-6d78637210b01c37c725bd0eb2beb811.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/OpenFolder.png"
+dest_files=["res://.godot/imported/OpenFolder.png-6d78637210b01c37c725bd0eb2beb811.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/Save.png


+ 34 - 0
GameProject/Resources/UI/Save.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bh2v51pbp4rd1"
+path="res://.godot/imported/Save.png-f97b1c73e190211af751aa489e8fd289.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/Save.png"
+dest_files=["res://.godot/imported/Save.png-f97b1c73e190211af751aa489e8fd289.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/SaveAs.png


+ 34 - 0
GameProject/Resources/UI/SaveAs.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://d3rxyldtqb1kd"
+path="res://.godot/imported/SaveAs.png-b9c58ca14ef5ef4c3973adfac96c7318.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/SaveAs.png"
+dest_files=["res://.godot/imported/SaveAs.png-b9c58ca14ef5ef4c3973adfac96c7318.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/Trash.png


+ 34 - 0
GameProject/Resources/UI/Trash.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b5em08tni20uv"
+path="res://.godot/imported/Trash.png-47be27d686b29059d350248307dfe6dd.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/Trash.png"
+dest_files=["res://.godot/imported/Trash.png-47be27d686b29059d350248307dfe6dd.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/Up.png


+ 34 - 0
GameProject/Resources/UI/Up.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cb6s0gsfwk0uq"
+path="res://.godot/imported/Up.png-e11317c61843df7fed282ce5c51a51cd.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/Up.png"
+dest_files=["res://.godot/imported/Up.png-e11317c61843df7fed282ce5c51a51cd.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/add.png


+ 34 - 0
GameProject/Resources/UI/add.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c7ikn8lahv8qm"
+path="res://.godot/imported/add.png-dca76c6535a8af9ba4f888387d064eea.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/add.png"
+dest_files=["res://.godot/imported/add.png-dca76c6535a8af9ba4f888387d064eea.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/bg_transparent.png


+ 34 - 0
GameProject/Resources/UI/bg_transparent.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://daprdynsx6da8"
+path="res://.godot/imported/bg_transparent.png-f6b6b21e1fce71ccb6197d6da01fe6a0.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/bg_transparent.png"
+dest_files=["res://.godot/imported/bg_transparent.png-f6b6b21e1fce71ccb6197d6da01fe6a0.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/body.png


+ 34 - 0
GameProject/Resources/UI/body.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://py1mcw7llkot"
+path="res://.godot/imported/body.png-2d71cc6ac818cd3450ca942d4c98bfe9.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/body.png"
+dest_files=["res://.godot/imported/body.png-2d71cc6ac818cd3450ca942d4c98bfe9.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/checked.png


+ 34 - 0
GameProject/Resources/UI/checked.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cy7cxbry62l4p"
+path="res://.godot/imported/checked.png-5ae1a75a087fa63b0d52f2a64a2231f6.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/checked.png"
+dest_files=["res://.godot/imported/checked.png-5ae1a75a087fa63b0d52f2a64a2231f6.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/checkmark.png


+ 34 - 0
GameProject/Resources/UI/checkmark.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dbgwel7glmmbc"
+path="res://.godot/imported/checkmark.png-b8a9306120aef81957bb818ebff26993.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/checkmark.png"
+dest_files=["res://.godot/imported/checkmark.png-b8a9306120aef81957bb818ebff26993.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/cursor_Icons.png


+ 34 - 0
GameProject/Resources/UI/cursor_Icons.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ds6hd5355oio8"
+path="res://.godot/imported/cursor_Icons.png-e055ffeda1b98c889e83d0d4f6d20d98.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/cursor_Icons.png"
+dest_files=["res://.godot/imported/cursor_Icons.png-e055ffeda1b98c889e83d0d4f6d20d98.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/dressing.png


+ 34 - 0
GameProject/Resources/UI/dressing.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://opgktj3w73x7"
+path="res://.godot/imported/dressing.png-616fc8714bb9980c0923278b8ff75058.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/dressing.png"
+dest_files=["res://.godot/imported/dressing.png-616fc8714bb9980c0923278b8ff75058.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/logo.png


+ 34 - 0
GameProject/Resources/UI/logo.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dccg3gcdgq757"
+path="res://.godot/imported/logo.png-f556e4fe4fd589af6deb821341e0408d.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/logo.png"
+dest_files=["res://.godot/imported/logo.png-f556e4fe4fd589af6deb821341e0408d.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/missing_file.png


+ 34 - 0
GameProject/Resources/UI/missing_file.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://brisj8burribb"
+path="res://.godot/imported/missing_file.png-605ceec065dc37749b14e0fa2f879e93.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/missing_file.png"
+dest_files=["res://.godot/imported/missing_file.png-605ceec065dc37749b14e0fa2f879e93.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/missing_image.png


+ 34 - 0
GameProject/Resources/UI/missing_image.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dpk8erf7xl1oe"
+path="res://.godot/imported/missing_image.png-589d13983b8f969bed010650966115fd.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/missing_image.png"
+dest_files=["res://.godot/imported/missing_image.png-589d13983b8f969bed010650966115fd.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/msgbox_error.png


+ 34 - 0
GameProject/Resources/UI/msgbox_error.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://yep4pecgqbaf"
+path="res://.godot/imported/msgbox_error.png-b96d2ae00b7ab1ebc32e071fdc0452bd.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/msgbox_error.png"
+dest_files=["res://.godot/imported/msgbox_error.png-b96d2ae00b7ab1ebc32e071fdc0452bd.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/msgbox_infomation.png


+ 34 - 0
GameProject/Resources/UI/msgbox_infomation.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://5klm38apu0x4"
+path="res://.godot/imported/msgbox_infomation.png-afc5a46e03eecac74c539e52b24e6ba9.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/msgbox_infomation.png"
+dest_files=["res://.godot/imported/msgbox_infomation.png-afc5a46e03eecac74c539e52b24e6ba9.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/msgbox_question.png


+ 34 - 0
GameProject/Resources/UI/msgbox_question.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dihfigmj6cs4p"
+path="res://.godot/imported/msgbox_question.png-135cc95f772c692cd9ba19e23ea0beaf.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/msgbox_question.png"
+dest_files=["res://.godot/imported/msgbox_question.png-135cc95f772c692cd9ba19e23ea0beaf.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/msgbox_warning.png


+ 34 - 0
GameProject/Resources/UI/msgbox_warning.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bx838vcl68fpq"
+path="res://.godot/imported/msgbox_warning.png-5c6f95b659de9fd6119b7ed8e7478e20.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/msgbox_warning.png"
+dest_files=["res://.godot/imported/msgbox_warning.png-5c6f95b659de9fd6119b7ed8e7478e20.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/palette.png


+ 34 - 0
GameProject/Resources/UI/palette.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bch055uf605ie"
+path="res://.godot/imported/palette.png-92f503294cc661b4bcdf0b7397675829.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/palette.png"
+dest_files=["res://.godot/imported/palette.png-92f503294cc661b4bcdf0b7397675829.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/refresh.png


+ 34 - 0
GameProject/Resources/UI/refresh.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dxpdxw5opo110"
+path="res://.godot/imported/refresh.png-bef05425e7b0fc23b6e8807f66f49e16.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Resources/UI/refresh.png"
+dest_files=["res://.godot/imported/refresh.png-bef05425e7b0fc23b6e8807f66f49e16.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1

BIN
GameProject/Resources/UI/replace.png


Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff