Factory Modal 개발중. UTKLoading 개발 완료
This commit is contained in:
@@ -36,7 +36,8 @@
|
||||
"Bash(/bin/rm:*)",
|
||||
"WebFetch(domain:docs.unity3d.com)",
|
||||
"Bash(ls:*)",
|
||||
"WebFetch(domain:discussions.unity.com)"
|
||||
"WebFetch(domain:discussions.unity.com)",
|
||||
"mcp__ai-game-developer__screenshot-game-view"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"UnityMCP": {
|
||||
"ai-game-developer": {
|
||||
"type": "http",
|
||||
"url": "http://localhost:8080/mcp"
|
||||
"url": "http://localhost:55726"
|
||||
}
|
||||
}
|
||||
}
|
||||
423
Assets/Resources/AI-Game-Developer-Config.json
Normal file
423
Assets/Resources/AI-Game-Developer-Config.json
Normal file
@@ -0,0 +1,423 @@
|
||||
{
|
||||
"logLevel": 3,
|
||||
"keepServerRunning": true,
|
||||
"transportMethod": 2,
|
||||
"tools": [
|
||||
{
|
||||
"name": "assets-copy",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "assets-create-folder",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "assets-delete",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "assets-find",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "assets-find-built-in",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "assets-get-data",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "assets-material-create",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "assets-modify",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "assets-move",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "assets-refresh",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "assets-prefab-close",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "assets-prefab-create",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "assets-prefab-instantiate",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "assets-prefab-open",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "assets-prefab-save",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "assets-shader-list-all",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "console-get-logs",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "editor-application-get-state",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "editor-application-set-state",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "editor-selection-get",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "editor-selection-set",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "gameobject-component-add",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "gameobject-component-destroy",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "gameobject-component-get",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "gameobject-component-list-all",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "gameobject-component-modify",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "gameobject-create",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "gameobject-destroy",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "gameobject-duplicate",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "gameobject-find",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "gameobject-modify",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "gameobject-set-parent",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "object-get-data",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "object-modify",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "package-add",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "package-list",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "package-remove",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "package-search",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "reflection-method-call",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "reflection-method-find",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "scene-create",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "scene-get-data",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "scene-list-opened",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "scene-open",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "scene-save",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "scene-set-active",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "scene-unload",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "screenshot-camera",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "screenshot-game-view",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "screenshot-scene-view",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "script-delete",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "script-execute",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "script-read",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "script-update-or-create",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "tests-run",
|
||||
"enabled": true
|
||||
}
|
||||
],
|
||||
"prompts": [
|
||||
{
|
||||
"name": "setup-animator-controller",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "create-simple-tweening",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "setup-timeline-sequence",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "add-animation-events",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "create-procedural-animation",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "setup-sprite-animation",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "add-ik-system",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "create-animation-blending",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "organize-project-structure",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "import-setup-sprites",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "setup-audio-manager",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "configure-build-settings",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "create-material-library",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "setup-asset-bundles",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "optimize-texture-settings",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "setup-addressables",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "add-debug-visualization",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "setup-performance-profiling",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "create-test-scene",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "add-logging-system",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "create-unit-tests",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "setup-debug-ui",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "add-assertion-checks",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "create-automated-tests",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "add-standard-components",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "setup-player-controller",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "create-ui-canvas",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "add-physics-interactions",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "create-interactive-object",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "setup-audio-source",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "create-particle-effects",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "setup-animator-component",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "setup-basic-scene",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "organize-scene-hierarchy",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "add-lighting-setup",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "create-prefab-from-selection",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "setup-scene-camera",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "create-environment-template",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "generate-monobehaviour-template",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "add-event-system",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "create-singleton-manager",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "setup-coroutine-framework",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "create-scriptableobject-data",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "implement-object-pooling",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "add-state-machine",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "setup-dependency-injection",
|
||||
"enabled": true
|
||||
}
|
||||
],
|
||||
"resources": [
|
||||
{
|
||||
"name": "GameObject from Current Scene by Path",
|
||||
"enabled": true
|
||||
}
|
||||
],
|
||||
"host": "http://localhost:55726",
|
||||
"timeoutMs": 10000,
|
||||
"keepConnected": true,
|
||||
"token": null
|
||||
}
|
||||
7
Assets/Resources/AI-Game-Developer-Config.json.meta
Normal file
7
Assets/Resources/AI-Game-Developer-Config.json.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ecf6949f73508f49ba3a0633329a219
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -139,7 +139,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 1, y: 1}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: -12, y: -1}
|
||||
m_AnchoredPosition: {x: -20, y: -1}
|
||||
m_SizeDelta: {x: 22, y: 22}
|
||||
m_Pivot: {x: 1, y: 1}
|
||||
--- !u!222 &5485997075992529675
|
||||
@@ -246,7 +246,7 @@ PrefabInstance:
|
||||
m_Modifications:
|
||||
- target: {fileID: 1375483911066562825, guid: 963f47de712c3844183989c7fc7fbd8a, type: 3}
|
||||
propertyPath: m_SizeDelta.x
|
||||
value: 238
|
||||
value: -65
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 5097404189591199700, guid: 963f47de712c3844183989c7fc7fbd8a, type: 3}
|
||||
propertyPath: m_AnchorMax.x
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 62b1c6b38fe308748b808fb2b576e6e2
|
||||
guid: 35623d99e7e18de4c9218b9878efaac6
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9210d67d228d2814eb32cc841227db5b
|
||||
guid: 9ffd6459fed612148ac685b6329657a1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
@@ -0,0 +1,5 @@
|
||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xmlns:utk="UVC.UIToolkit" editor-extension-mode="False">
|
||||
<ui:VisualElement name="root" style="padding-left: 20px;">
|
||||
<utk:UTKLabel text="알람 정보"/>
|
||||
</ui:VisualElement>
|
||||
</ui:UXML>
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 92f820b7de9d43c428503b7c574c9e69
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
@@ -0,0 +1,5 @@
|
||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xmlns:utk="UVC.UIToolkit" editor-extension-mode="False">
|
||||
<ui:VisualElement name="root" style="padding-left: 20px;">
|
||||
<utk:UTKReordableTabList name="tab-list" />
|
||||
</ui:VisualElement>
|
||||
</ui:UXML>
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: db6157353e844a84fabf731aed504f56
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
@@ -0,0 +1,5 @@
|
||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xmlns:utk="UVC.UIToolkit" editor-extension-mode="False">
|
||||
<ui:VisualElement name="root" style="padding-left: 20px;">
|
||||
<utk:UTKLabel text="일반 정보"/>
|
||||
</ui:VisualElement>
|
||||
</ui:UXML>
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7b805d40178aceb48b21275834afbb24
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
@@ -0,0 +1,5 @@
|
||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xmlns:utk="UVC.UIToolkit" editor-extension-mode="False">
|
||||
<ui:VisualElement name="root" style="padding-left: 20px;">
|
||||
<utk:UTKLabel text="입력 정보"/>
|
||||
</ui:VisualElement>
|
||||
</ui:UXML>
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5224fd32ba226a340aaac4e6dc070861
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
68
Assets/Resources/UIToolkit/List/UTKReordableTabListUss.uss
Normal file
68
Assets/Resources/UIToolkit/List/UTKReordableTabListUss.uss
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* ===================================
|
||||
* UTKReordableTabListUss.uss
|
||||
* 탭 기반 재정렬 가능 리스트 스타일
|
||||
* ===================================
|
||||
*/
|
||||
|
||||
/* ===================================
|
||||
Base Container
|
||||
=================================== */
|
||||
|
||||
.reordable-tab-list {
|
||||
flex-grow: 1;
|
||||
padding: 8px;
|
||||
background-color: var(--color-bg-secondary);
|
||||
border-radius: var(--radius-s);
|
||||
border-width: var(--border-width);
|
||||
border-color: var(--color-border);
|
||||
}
|
||||
|
||||
/* ===================================
|
||||
TabView 내부 스타일 오버라이드
|
||||
외부 utk-tabview--align-left 등 align 클래스가
|
||||
descendant selector로 내부 TabView에 영향을 주지 않도록 리셋
|
||||
=================================== */
|
||||
|
||||
.reordable-tab-list > .utk-tabview {
|
||||
flex-grow: 1;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.reordable-tab-list > .utk-tabview > .unity-tab-view__header-container {
|
||||
flex-direction: row;
|
||||
border-right-width: 0;
|
||||
border-top-width: 0;
|
||||
border-left-width: 0;
|
||||
border-bottom-width: var(--border-width);
|
||||
border-bottom-color: var(--color-border);
|
||||
}
|
||||
|
||||
.reordable-tab-list > .utk-tabview > .unity-tab-view__content-container {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.reordable-tab-list > .utk-tabview .unity-tab__header {
|
||||
margin-right: var(--space-s);
|
||||
margin-bottom: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.reordable-tab-list > .utk-tabview .unity-tab__header-underline {
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
top: auto;
|
||||
width: auto;
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
/* ===================================
|
||||
탭 콘텐츠 내부 ReordableList 스타일 오버라이드
|
||||
=================================== */
|
||||
|
||||
.reordable-tab-list .reordable-list {
|
||||
border-width: 0;
|
||||
border-radius: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 360ccda715f15bc479dec409d0ed87cf
|
||||
guid: 5e72692fcb817e14e8fbcaaf9b4f6b17
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* ===================================
|
||||
* UTKSettingDisplayInfoTabViewUss.uss
|
||||
* 설정 표시 정보 탭 뷰 컨테이너 스타일
|
||||
* ===================================
|
||||
*/
|
||||
|
||||
/* ===================================
|
||||
Base Container
|
||||
=================================== */
|
||||
|
||||
.setting-display-tab-view {
|
||||
flex-grow: 1;
|
||||
background-color: var(--color-bg-secondary);
|
||||
border-radius: var(--radius-s);
|
||||
border-width: var(--border-width);
|
||||
border-color: var(--color-border);
|
||||
}
|
||||
|
||||
/* ===================================
|
||||
ListView 내부 여백 조정
|
||||
=================================== */
|
||||
|
||||
.setting-display-tab-view .utk-listview {
|
||||
flex-grow: 1;
|
||||
border-width: 0;
|
||||
border-radius: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/* ===================================
|
||||
드래그 중 아이템 스타일 (Unity 내장 클래스)
|
||||
=================================== */
|
||||
|
||||
.setting-display-tab-view .unity-list-view__reorderable-item__container {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* ===================================
|
||||
드래그 핸들 바 (Unity 내장 reorder handle)
|
||||
커스텀 드래그 핸들 사용하므로 기본 숨김
|
||||
=================================== */
|
||||
|
||||
.setting-display-tab-view .unity-list-view__reorderable-handle-bar {
|
||||
display: none;
|
||||
}
|
||||
16
Assets/Resources/UIToolkit/Modal/UTKLoadingUss.uss
Normal file
16
Assets/Resources/UIToolkit/Modal/UTKLoadingUss.uss
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* ===================================
|
||||
* UTKLoadingUss.uss
|
||||
* 회전 로딩 스피너 스타일
|
||||
* ===================================
|
||||
*
|
||||
* 색상은 C#에서 CustomStyleResolvedEvent로 --color-primary 값을 읽어 처리합니다.
|
||||
* 두께/크기는 C# 속성(Thickness, Size) 또는 UXML 태그(thickness, size)로 설정하세요.
|
||||
*/
|
||||
|
||||
.utk-loading {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
11
Assets/Resources/UIToolkit/Modal/UTKLoadingUss.uss.meta
Normal file
11
Assets/Resources/UIToolkit/Modal/UTKLoadingUss.uss.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 21b7e91639030834c94d38263ad773ae
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
|
||||
disableValidation: 0
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<UXML xmlns="UnityEngine.UIElements" xmlns:utk="UVC.UIToolkit">
|
||||
<Style src="../UTKSampleCommon.uss" />
|
||||
<Style src="UTKListSample.uss" />
|
||||
|
||||
<VisualElement class="utk-sample-container">
|
||||
<Label class="utk-sample-desc" text="드래그로 항목 순서를 변경할 수 있는 리스트 컴포넌트 (체크박스 + 입력 필드)" />
|
||||
|
||||
<VisualElement class="utk-sample-section">
|
||||
<Label class="utk-sample-section__title" text="ReordableList" />
|
||||
<utk:UTKReordableList name="reordable-list-sample" style="height: 250px; width: 350px;" />
|
||||
</VisualElement>
|
||||
|
||||
<!-- Code Sample -->
|
||||
<VisualElement class="utk-code-sample-container">
|
||||
<utk:UTKCodeBlock name="code-csharp" title="C#" />
|
||||
<utk:UTKCodeBlock name="code-uxml" title="UXML" />
|
||||
</VisualElement>
|
||||
</VisualElement>
|
||||
</UXML>
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cb106aca3db68c845acaa7b480de76e7
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<UXML xmlns="UnityEngine.UIElements" xmlns:utk="UVC.UIToolkit">
|
||||
<Style src="../UTKSampleCommon.uss" />
|
||||
<Style src="UTKListSample.uss" />
|
||||
|
||||
<VisualElement class="utk-sample-container">
|
||||
<Label class="utk-sample-desc" text="탭별로 독립적인 재정렬 가능 리스트를 제공하는 컴포넌트 (UTKTabView + UTKReordableList)" />
|
||||
|
||||
<VisualElement class="utk-sample-section">
|
||||
<Label class="utk-sample-section__title" text="ReordableTabList" />
|
||||
<utk:UTKReordableTabList name="reordable-tab-list-sample" style="height: 300px;" />
|
||||
</VisualElement>
|
||||
|
||||
<!-- Code Sample -->
|
||||
<VisualElement class="utk-code-sample-container">
|
||||
<utk:UTKCodeBlock name="code-csharp" title="C#" />
|
||||
<utk:UTKCodeBlock name="code-uxml" title="UXML" />
|
||||
</VisualElement>
|
||||
</VisualElement>
|
||||
</UXML>
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c0ae1e70887e1a4429de0c54e6d69c18
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<UXML xmlns="UnityEngine.UIElements" xmlns:utk="UVC.UIToolkit">
|
||||
<Style src="../UTKSampleCommon.uss" />
|
||||
|
||||
<VisualElement class="utk-sample-container">
|
||||
<Label class="utk-sample-desc" text="회전하면서 호가 길어졌다 짧아지는 원형 로딩 스피너" />
|
||||
|
||||
<!-- Static API: 전체 화면 로딩 + Blocker -->
|
||||
<VisualElement class="utk-sample-section">
|
||||
<Label class="utk-sample-section__title" text="Static API (전체 화면 로딩 + Blocker)" />
|
||||
<VisualElement class="utk-sample-row">
|
||||
<utk:UTKButton name="btn-show" text="Show (기본 속도)" variant="Primary" />
|
||||
<utk:UTKButton name="btn-show-fast" text="Show (빠르게 x2)" variant="Normal" />
|
||||
<utk:UTKButton name="btn-show-slow" text="Show (느리게 x0.5)" variant="Normal" />
|
||||
<utk:UTKButton name="btn-hide" text="Hide" variant="Danger" />
|
||||
</VisualElement>
|
||||
</VisualElement>
|
||||
|
||||
<!-- UXML 인라인 배치 -->
|
||||
<VisualElement class="utk-sample-section">
|
||||
<Label class="utk-sample-section__title" text="UXML 인라인 배치 (Blocker 없음, auto-play)" />
|
||||
<VisualElement class="utk-sample-row" style="align-items: center; justify-content: flex-start; gap: 24px;">
|
||||
<!-- 기본 크기 -->
|
||||
<VisualElement style="align-items: center; gap: 4px;">
|
||||
<utk:UTKLoading speed="1.0" auto-play="true" />
|
||||
<Label text="기본 (48px)" style="font-size: 10px; color: rgba(255,255,255,0.5);" />
|
||||
</VisualElement>
|
||||
<!-- 작은 크기 -->
|
||||
<VisualElement style="align-items: center; gap: 4px;">
|
||||
<utk:UTKLoading name="loading-small" speed="1.0" auto-play="true" />
|
||||
<Label text="Small (32px)" style="font-size: 10px; color: rgba(255,255,255,0.5);" />
|
||||
</VisualElement>
|
||||
<!-- 큰 크기 -->
|
||||
<VisualElement style="align-items: center; gap: 4px;">
|
||||
<utk:UTKLoading name="loading-large" speed="1.0" auto-play="true" />
|
||||
<Label text="Large (72px)" style="font-size: 10px; color: rgba(255,255,255,0.5);" />
|
||||
</VisualElement>
|
||||
<!-- 빠른 속도 -->
|
||||
<VisualElement style="align-items: center; gap: 4px;">
|
||||
<utk:UTKLoading speed="2.5" auto-play="true" />
|
||||
<Label text="Fast (x2.5)" style="font-size: 10px; color: rgba(255,255,255,0.5);" />
|
||||
</VisualElement>
|
||||
</VisualElement>
|
||||
</VisualElement>
|
||||
|
||||
<!-- Code Sample -->
|
||||
<VisualElement class="utk-code-sample-container">
|
||||
<utk:UTKCodeBlock name="code-csharp" title="C#" />
|
||||
<utk:UTKCodeBlock name="code-uxml" title="UXML" />
|
||||
</VisualElement>
|
||||
</VisualElement>
|
||||
</UXML>
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 99a140d3bee776941b1e6c197b653811
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
@@ -18,6 +18,7 @@ public class UTKReordableListSample : MonoBehaviour
|
||||
|
||||
private UTKToggle _themeToggle;
|
||||
private UTKReordableList _reordableList;
|
||||
private UTKReordableTabList _reordableTabList;
|
||||
|
||||
void Start()
|
||||
{
|
||||
@@ -48,6 +49,14 @@ public class UTKReordableListSample : MonoBehaviour
|
||||
return;
|
||||
}
|
||||
|
||||
// ReordableTabList
|
||||
_reordableTabList = root.Q<UTKReordableTabList>("tab-list");
|
||||
if (_reordableTabList == null)
|
||||
{
|
||||
Debug.LogError("UXML에서 UTKReordableTabList를 찾을 수 없습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 테마 초기화
|
||||
UTKThemeManager.Instance.RegisterRoot(root);
|
||||
UTKThemeManager.Instance.SetTheme(initialTheme);
|
||||
@@ -63,6 +72,13 @@ public class UTKReordableListSample : MonoBehaviour
|
||||
|
||||
// 샘플 데이터 설정 (Dictionary 방식)
|
||||
SetSampleData();
|
||||
SetTabListSampleData();
|
||||
|
||||
// 이벤트 핸들러 등록 (TabList)
|
||||
_reordableTabList.OnOrderChanged += (tabName, tabIndex) =>
|
||||
Debug.Log($"[TabList] [{tabName}] (탭 {tabIndex}) 순서 변경됨");
|
||||
_reordableTabList.OnDataChanged += (tabName, tabIndex) =>
|
||||
Debug.Log($"[TabList] [{tabName}] (탭 {tabIndex}) 데이터 변경됨");
|
||||
|
||||
// 하단 버튼 영역 생성
|
||||
CreateButtons(root);
|
||||
@@ -84,6 +100,35 @@ public class UTKReordableListSample : MonoBehaviour
|
||||
_reordableList.SetData(listDict);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UTKReordableTabList에 탭별 샘플 데이터를 설정합니다.
|
||||
/// </summary>
|
||||
private void SetTabListSampleData()
|
||||
{
|
||||
var data = new Dictionary<string, List<Dictionary<string, string>>>
|
||||
{
|
||||
["센서"] = new()
|
||||
{
|
||||
new() { ["order"] = "0", ["active"] = "True", ["text"] = "온도 센서" },
|
||||
new() { ["order"] = "1", ["active"] = "True", ["text"] = "습도 센서" },
|
||||
new() { ["order"] = "2", ["active"] = "False", ["text"] = "압력 센서" },
|
||||
},
|
||||
["장비"] = new()
|
||||
{
|
||||
new() { ["order"] = "0", ["active"] = "True", ["text"] = "컨베이어" },
|
||||
new() { ["order"] = "1", ["active"] = "False", ["text"] = "로봇암" },
|
||||
new() { ["order"] = "2", ["active"] = "True", ["text"] = "CNC" },
|
||||
new() { ["order"] = "3", ["active"] = "True", ["text"] = "AGV" },
|
||||
},
|
||||
["알림"] = new()
|
||||
{
|
||||
new() { ["order"] = "0", ["active"] = "True", ["text"] = "경고" },
|
||||
new() { ["order"] = "1", ["active"] = "True", ["text"] = "에러" },
|
||||
}
|
||||
};
|
||||
_reordableTabList.SetData(data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 테스트 버튼들을 생성합니다.
|
||||
/// </summary>
|
||||
@@ -112,6 +157,18 @@ public class UTKReordableListSample : MonoBehaviour
|
||||
addBtn.OnClicked += OnAddItemClicked;
|
||||
buttonContainer.Add(addBtn);
|
||||
|
||||
// TabList ToDictionary 버튼
|
||||
var tabDictBtn = new UTKButton("TabList ToDictionary", variant: UTKButton.ButtonVariant.Primary);
|
||||
tabDictBtn.OnClicked += OnTabListToDictionaryClicked;
|
||||
tabDictBtn.style.marginLeft = 16;
|
||||
tabDictBtn.style.marginRight = 4;
|
||||
buttonContainer.Add(tabDictBtn);
|
||||
|
||||
// TabList 리셋 버튼
|
||||
var tabResetBtn = new UTKButton("TabList 리셋", variant: UTKButton.ButtonVariant.Normal);
|
||||
tabResetBtn.OnClicked += () => SetTabListSampleData();
|
||||
buttonContainer.Add(tabResetBtn);
|
||||
|
||||
root.Add(buttonContainer);
|
||||
}
|
||||
|
||||
@@ -128,6 +185,23 @@ public class UTKReordableListSample : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TabList의 ToDictionary를 호출하여 탭별 데이터를 콘솔에 출력합니다.
|
||||
/// </summary>
|
||||
private void OnTabListToDictionaryClicked()
|
||||
{
|
||||
var result = _reordableTabList.ToDictionary();
|
||||
Debug.Log($"[TabList] ToDictionary 결과 ({result.Count}개 탭):");
|
||||
foreach (var kvp in result)
|
||||
{
|
||||
Debug.Log($" 탭 [{kvp.Key}] ({kvp.Value.Count}건):");
|
||||
foreach (var dict in kvp.Value)
|
||||
{
|
||||
Debug.Log($" order={dict["order"]}, active={dict["active"]}, text={dict["text"]}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 새 아이템을 추가합니다.
|
||||
/// </summary>
|
||||
@@ -148,5 +222,6 @@ public class UTKReordableListSample : MonoBehaviour
|
||||
private void OnDestroy()
|
||||
{
|
||||
_reordableList?.Dispose();
|
||||
_reordableTabList?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
<UXML xmlns="UnityEngine.UIElements" xmlns:utk="UVC.UIToolkit" editor-extension-mode="False">
|
||||
<VisualElement style="width: 100%; height: 100%;">
|
||||
<utk:UTKReordableList name="window" style="width: 300px; height: 200px;" />
|
||||
<VisualElement style="width: 100%; height: 100%; flex-direction: row; padding: 16px;">
|
||||
<!-- 기존 UTKReordableList 샘플 -->
|
||||
<VisualElement style="width: 300px; margin-right: 16px;">
|
||||
<Label text="UTKReordableList" style="font-size: 14px; -unity-font-style: bold; margin-bottom: 8px;" />
|
||||
<utk:UTKReordableList name="window" style="height: 200px;" />
|
||||
</VisualElement>
|
||||
|
||||
<!-- UTKReordableTabList 샘플 -->
|
||||
<VisualElement style="width: 400px;">
|
||||
<Label text="UTKReordableTabList" style="font-size: 14px; -unity-font-style: bold; margin-bottom: 8px;" />
|
||||
<utk:UTKReordableTabList name="tab-list" style="height: 300px;" />
|
||||
</VisualElement>
|
||||
|
||||
<utk:UTKToggle name="toggle" label="테마 변경" style="position: absolute; top: 10px; right: 10px;" />
|
||||
</VisualElement>
|
||||
</UXML>
|
||||
@@ -6,6 +6,7 @@ using UVC.UIToolkit;
|
||||
using UVC.UI.Commands;
|
||||
using UVC.Log;
|
||||
using UVC.Studio.UIToolkit.Modal;
|
||||
using Factory.UIToolkit.Modal;
|
||||
|
||||
namespace UVC.Sample.UIToolkit
|
||||
{
|
||||
@@ -26,6 +27,11 @@ namespace UVC.Sample.UIToolkit
|
||||
private UTKButton? _openButton0;
|
||||
private UTKButton? _openButton1;
|
||||
private UTKButton? _openButton2;
|
||||
|
||||
private UTKButton? _openButton10;
|
||||
private UTKButton? _openButton11;
|
||||
private UTKButton? _openButton12;
|
||||
private UTKButton? _openButton13;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
@@ -85,6 +91,49 @@ namespace UVC.Sample.UIToolkit
|
||||
};
|
||||
}
|
||||
|
||||
_openButton10 = _root.Q<UTKButton>("openButton10");
|
||||
if (_openButton10 != null) {
|
||||
_openButton10.OnClicked += async () =>
|
||||
{
|
||||
var modal = UTKModal.Create("Settings", UTKModal.ModalSize.Large);
|
||||
var content = new UTKFactorySettingModalContent(0); // 초기 탭 인덱스 설정
|
||||
modal.Add(content);
|
||||
await modal.ShowAsync();
|
||||
};
|
||||
}
|
||||
|
||||
_openButton11 = _root.Q<UTKButton>("openButton11");
|
||||
if (_openButton11 != null) {
|
||||
_openButton11.OnClicked += async () =>
|
||||
{
|
||||
var modal = UTKModal.Create("Settings", UTKModal.ModalSize.Large);
|
||||
var content = new UTKFactorySettingModalContent(1); // 초기 탭 인덱스 설정
|
||||
modal.Add(content);
|
||||
await modal.ShowAsync();
|
||||
};
|
||||
}
|
||||
|
||||
_openButton12 = _root.Q<UTKButton>("openButton12");
|
||||
if (_openButton12 != null) {
|
||||
_openButton12.OnClicked += async () =>
|
||||
{
|
||||
var modal = UTKModal.Create("Settings", UTKModal.ModalSize.Large);
|
||||
var content = new UTKFactorySettingModalContent(2); // 초기 탭 인덱스 설정
|
||||
modal.Add(content);
|
||||
await modal.ShowAsync();
|
||||
};
|
||||
}
|
||||
|
||||
_openButton13 = _root.Q<UTKButton>("openButton13");
|
||||
if (_openButton13 != null) {
|
||||
_openButton13.OnClicked += async () =>
|
||||
{
|
||||
var modal = UTKModal.Create("Settings", UTKModal.ModalSize.Large);
|
||||
var content = new UTKFactorySettingModalContent(3); // 초기 탭 인덱스 설정
|
||||
modal.Add(content);
|
||||
await modal.ShowAsync();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
|
||||
@@ -4,5 +4,10 @@
|
||||
<utk:UTKButton name="openButton0" text="Open0" style="position: absolute; top: 8px; left: 10px; z-index: 10;" />
|
||||
<utk:UTKButton name="openButton1" text="Open1" style="position: absolute; top: 38px; left: 10px; z-index: 10;" />
|
||||
<utk:UTKButton name="openButton2" text="Open2" style="position: absolute; top: 68px; left: 10px; z-index: 10;" />
|
||||
<utk:UTKButton name="openButton10" text="Open10" style="position: absolute; top: 108px; left: 10px; z-index: 10;" />
|
||||
<utk:UTKButton name="openButton11" text="Open11" style="position: absolute; top: 138px; left: 10px; z-index: 10;" />
|
||||
<utk:UTKButton name="openButton12" text="Open12" style="position: absolute; top: 168px; left: 10px; z-index: 10;" />
|
||||
<utk:UTKButton name="openButton13" text="Open13" style="position: absolute; top: 198px; left: 10px; z-index: 10;" />
|
||||
|
||||
</VisualElement>
|
||||
</UXML>
|
||||
|
||||
@@ -519,6 +519,166 @@ list.SetData(current);",
|
||||
<!-- 고정 크기 -->
|
||||
<utk:UTKShortcutList style=""height: 300px;"" />
|
||||
|
||||
<!-- 데이터와 이벤트는 C#에서 설정 -->");
|
||||
}
|
||||
|
||||
private void InitializeReordableListSample(VisualElement root)
|
||||
{
|
||||
var reordableList = root.Q<UTKReordableList>("reordable-list-sample");
|
||||
if (reordableList != null)
|
||||
{
|
||||
var listDict = new List<Dictionary<string, string>>
|
||||
{
|
||||
new() { ["order"] = "0", ["active"] = "True", ["text"] = "온도" },
|
||||
new() { ["order"] = "1", ["active"] = "False", ["text"] = "습도" },
|
||||
new() { ["order"] = "2", ["active"] = "True", ["text"] = "압력" },
|
||||
new() { ["order"] = "3", ["active"] = "True", ["text"] = "풍속" },
|
||||
new() { ["order"] = "4", ["active"] = "False", ["text"] = "조도" },
|
||||
};
|
||||
reordableList.SetData(listDict);
|
||||
|
||||
reordableList.OnOrderChanged += () =>
|
||||
Debug.Log("[StyleGuide] ReordableList 순서 변경됨");
|
||||
reordableList.OnDataChanged += () =>
|
||||
Debug.Log("[StyleGuide] ReordableList 데이터 변경됨");
|
||||
}
|
||||
|
||||
SetCodeSamples(root,
|
||||
csharpCode:
|
||||
@"// 리스트 생성
|
||||
var list = new UTKReordableList();
|
||||
|
||||
// ReordableListItemData로 직접 설정
|
||||
var items = new List<ReordableListItemData>
|
||||
{
|
||||
new() { Order = 0, IsActive = true, DisplayText = ""온도"" },
|
||||
new() { Order = 1, IsActive = false, DisplayText = ""습도"" },
|
||||
new() { Order = 2, IsActive = true, DisplayText = ""압력"" },
|
||||
};
|
||||
list.SetData(items);
|
||||
|
||||
// Dictionary<string, string> 형식으로도 설정 가능
|
||||
var listDict = new List<Dictionary<string, string>>
|
||||
{
|
||||
new() { [""order""] = ""0"", [""active""] = ""True"", [""text""] = ""온도"" },
|
||||
new() { [""order""] = ""1"", [""active""] = ""False"", [""text""] = ""습도"" },
|
||||
};
|
||||
list.SetData(listDict);
|
||||
|
||||
// 데이터 가져오기
|
||||
var data = list.GetData();
|
||||
|
||||
// Dictionary 형식으로 변환
|
||||
var dictResult = list.ToDictionary();
|
||||
|
||||
// 이벤트 구독
|
||||
list.OnOrderChanged += () => Debug.Log(""순서 변경됨"");
|
||||
list.OnDataChanged += () => Debug.Log(""데이터 변경됨"");
|
||||
|
||||
// 정리
|
||||
list.Dispose();",
|
||||
uxmlCode:
|
||||
@"<!-- 기본 사용 -->
|
||||
<utk:UTKReordableList name=""reordable-list"" />
|
||||
|
||||
<!-- 고정 크기 -->
|
||||
<utk:UTKReordableList style=""height: 250px; width: 350px;"" />
|
||||
|
||||
<!-- 데이터와 이벤트는 C#에서 설정 -->");
|
||||
}
|
||||
|
||||
private void InitializeReordableTabListSample(VisualElement root)
|
||||
{
|
||||
var tabList = root.Q<UTKReordableTabList>("reordable-tab-list-sample");
|
||||
if (tabList != null)
|
||||
{
|
||||
var data = new Dictionary<string, List<Dictionary<string, string>>>
|
||||
{
|
||||
["센서"] = new()
|
||||
{
|
||||
new() { ["order"] = "0", ["active"] = "True", ["text"] = "온도 센서" },
|
||||
new() { ["order"] = "1", ["active"] = "True", ["text"] = "습도 센서" },
|
||||
new() { ["order"] = "2", ["active"] = "False", ["text"] = "압력 센서" },
|
||||
},
|
||||
["장비"] = new()
|
||||
{
|
||||
new() { ["order"] = "0", ["active"] = "True", ["text"] = "컨베이어" },
|
||||
new() { ["order"] = "1", ["active"] = "False", ["text"] = "로봇암" },
|
||||
new() { ["order"] = "2", ["active"] = "True", ["text"] = "CNC" },
|
||||
new() { ["order"] = "3", ["active"] = "True", ["text"] = "AGV" },
|
||||
},
|
||||
["알림"] = new()
|
||||
{
|
||||
new() { ["order"] = "0", ["active"] = "True", ["text"] = "경고" },
|
||||
new() { ["order"] = "1", ["active"] = "True", ["text"] = "에러" },
|
||||
}
|
||||
};
|
||||
tabList.SetData(data);
|
||||
|
||||
tabList.OnOrderChanged += (tabName, tabIndex) =>
|
||||
Debug.Log($"[StyleGuide] [{tabName}] (탭 {tabIndex}) 순서 변경됨");
|
||||
tabList.OnDataChanged += (tabName, tabIndex) =>
|
||||
Debug.Log($"[StyleGuide] [{tabName}] (탭 {tabIndex}) 데이터 변경됨");
|
||||
}
|
||||
|
||||
SetCodeSamples(root,
|
||||
csharpCode:
|
||||
@"// 탭별 데이터 설정
|
||||
var tabList = new UTKReordableTabList();
|
||||
var data = new Dictionary<string, List<ReordableListItemData>>
|
||||
{
|
||||
[""센서""] = new()
|
||||
{
|
||||
new() { Order = 0, IsActive = true, DisplayText = ""온도 센서"" },
|
||||
new() { Order = 1, IsActive = true, DisplayText = ""습도 센서"" },
|
||||
new() { Order = 2, IsActive = false, DisplayText = ""압력 센서"" },
|
||||
},
|
||||
[""장비""] = new()
|
||||
{
|
||||
new() { Order = 0, IsActive = true, DisplayText = ""컨베이어"" },
|
||||
new() { Order = 1, IsActive = false, DisplayText = ""로봇암"" },
|
||||
}
|
||||
};
|
||||
tabList.SetData(data);
|
||||
|
||||
// Dictionary<string, string> 형식도 지원
|
||||
var dictData = new Dictionary<string, List<Dictionary<string, string>>>
|
||||
{
|
||||
[""탭1""] = new()
|
||||
{
|
||||
new() { [""order""] = ""0"", [""active""] = ""True"", [""text""] = ""항목1"" },
|
||||
}
|
||||
};
|
||||
tabList.SetData(dictData);
|
||||
|
||||
// 전체 데이터 가져오기
|
||||
var allData = tabList.GetData();
|
||||
|
||||
// 특정 탭 데이터 가져오기 (이름 또는 인덱스)
|
||||
var sensorData = tabList.GetData(""센서"");
|
||||
var firstTabData = tabList.GetData(0);
|
||||
|
||||
// Dictionary 형식으로 변환
|
||||
var dictResult = tabList.ToDictionary();
|
||||
|
||||
// 이벤트 구독 (탭 이름, 탭 인덱스 전달)
|
||||
tabList.OnOrderChanged += (tabName, tabIndex) =>
|
||||
Debug.Log($""[{tabName}] (탭 {tabIndex}) 순서 변경됨"");
|
||||
tabList.OnDataChanged += (tabName, tabIndex) =>
|
||||
Debug.Log($""[{tabName}] (탭 {tabIndex}) 데이터 변경됨"");
|
||||
|
||||
// SetData 재호출 시 기존 구성 제거 후 재생성
|
||||
tabList.SetData(newData);
|
||||
|
||||
// 정리
|
||||
tabList.Dispose();",
|
||||
uxmlCode:
|
||||
@"<!-- 기본 사용 -->
|
||||
<utk:UTKReordableTabList name=""tab-list"" />
|
||||
|
||||
<!-- 고정 크기 -->
|
||||
<utk:UTKReordableTabList style=""height: 300px;"" />
|
||||
|
||||
<!-- 데이터와 이벤트는 C#에서 설정 -->");
|
||||
}
|
||||
|
||||
|
||||
@@ -701,6 +701,103 @@ if (result != null)
|
||||
|
||||
#endregion
|
||||
|
||||
#region Loading Initializers
|
||||
|
||||
private void InitializeLoadingSample(VisualElement root)
|
||||
{
|
||||
if (_root == null) return;
|
||||
|
||||
UTKLoading.SetRoot(_root);
|
||||
|
||||
// Static API 버튼
|
||||
var btnShow = root.Q<UTKButton>("btn-show");
|
||||
btnShow?.RegisterCallback<ClickEvent>(_ => UTKLoading.Show());
|
||||
|
||||
var btnShowFast = root.Q<UTKButton>("btn-show-fast");
|
||||
btnShowFast?.RegisterCallback<ClickEvent>(_ => UTKLoading.Show(speed: 2f));
|
||||
|
||||
var btnShowSlow = root.Q<UTKButton>("btn-show-slow");
|
||||
btnShowSlow?.RegisterCallback<ClickEvent>(_ => UTKLoading.Show(speed: 0.5f));
|
||||
|
||||
var btnHide = root.Q<UTKButton>("btn-hide");
|
||||
btnHide?.RegisterCallback<ClickEvent>(_ => UTKLoading.Hide());
|
||||
|
||||
// UXML 인라인 스피너 크기 커스터마이징 (Size 속성으로 지정)
|
||||
var loadingSmall = root.Q<UTKLoading>("loading-small");
|
||||
if (loadingSmall != null)
|
||||
{
|
||||
loadingSmall.Size = 32f;
|
||||
loadingSmall.Thickness = 3f;
|
||||
}
|
||||
|
||||
var loadingLarge = root.Q<UTKLoading>("loading-large");
|
||||
if (loadingLarge != null)
|
||||
{
|
||||
loadingLarge.Size = 72f;
|
||||
loadingLarge.Thickness = 6f;
|
||||
}
|
||||
|
||||
SetCodeSamples(root,
|
||||
csharpCode: @"// ========================================
|
||||
// Static API (전체 화면 로딩 + Blocker)
|
||||
// ========================================
|
||||
|
||||
// Root 설정 (한 번만)
|
||||
UTKLoading.SetRoot(rootVisualElement);
|
||||
|
||||
// 기본 속도로 표시 (색상은 테마 --color-primary 자동 적용)
|
||||
UTKLoading.Show();
|
||||
|
||||
// 속도 배율 지정 (1.0 = 기본 속도)
|
||||
UTKLoading.Show(speed: 2.0f); // 빠르게
|
||||
UTKLoading.Show(speed: 0.5f); // 느리게
|
||||
|
||||
// 이미 표시 중이면 중복 생성 없이 기존 인스턴스 반환
|
||||
var loading = UTKLoading.Show();
|
||||
|
||||
// 숨기기 (애니메이션 정지 + 제거)
|
||||
UTKLoading.Hide();
|
||||
|
||||
// 현재 표시 여부 확인
|
||||
bool isShowing = UTKLoading.IsShowing;
|
||||
|
||||
// ========================================
|
||||
// 실제 사용 예시
|
||||
// ========================================
|
||||
|
||||
public async UniTask LoadDataAsync(CancellationToken ct)
|
||||
{
|
||||
UTKLoading.Show();
|
||||
try
|
||||
{
|
||||
await FetchDataFromServerAsync(ct);
|
||||
}
|
||||
finally
|
||||
{
|
||||
UTKLoading.Hide(); // 성공/실패 모두 숨김
|
||||
}
|
||||
}",
|
||||
uxmlCode: @"<!-- UXML 인라인 배치 (Blocker 없음, 레이아웃 내 배치) -->
|
||||
|
||||
<!-- 기본 (48px, speed=1.0, 테마 색상 자동 적용) -->
|
||||
<utk:UTKLoading />
|
||||
|
||||
<!-- 빠른 회전 -->
|
||||
<utk:UTKLoading speed=""2.5"" />
|
||||
|
||||
<!-- 크기/두께 커스터마이징 -->
|
||||
<utk:UTKLoading size=""32"" thickness=""3"" />
|
||||
<utk:UTKLoading size=""72"" thickness=""6"" />
|
||||
|
||||
<!-- 색상 직접 지정 (테마 색상 무시) -->
|
||||
<utk:UTKLoading arc-color=""#73C991"" size=""64"" thickness=""6"" />
|
||||
|
||||
<!-- 수동 제어 (auto-play 끔) -->
|
||||
<utk:UTKLoading name=""my-loading"" auto-play=""false"" />");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Notification Initializers
|
||||
|
||||
private void InitializeNotificationSample(VisualElement root)
|
||||
|
||||
@@ -89,6 +89,8 @@ public partial class UTKStyleGuideSample : MonoBehaviour
|
||||
["UTKFoldout"] = "UIToolkit/Sample/List/UTKFoldoutSample",
|
||||
["UTKScrollView"] = "UIToolkit/Sample/List/UTKScrollViewSample",
|
||||
["UTKShortcutList"] = "UIToolkit/Sample/List/UTKShortcutListSample",
|
||||
["UTKReordableList"] = "UIToolkit/Sample/List/UTKReordableListSample",
|
||||
["UTKReordableTabList"] = "UIToolkit/Sample/List/UTKReordableTabListSample",
|
||||
// Card
|
||||
["UTKCard"] = "UIToolkit/Sample/Card/UTKCardSample",
|
||||
["UTKPanel"] = "UIToolkit/Sample/Card/UTKPanelSample",
|
||||
@@ -100,6 +102,7 @@ public partial class UTKStyleGuideSample : MonoBehaviour
|
||||
["UTKTooltip"] = "UIToolkit/Sample/Modal/UTKTooltipSample",
|
||||
["UTKNotification"] = "UIToolkit/Sample/Modal/UTKNotificationSample",
|
||||
["UTKModal"] = "UIToolkit/Sample/Modal/UTKModalSample",
|
||||
["UTKLoading"] = "UIToolkit/Sample/Modal/UTKLoadingSample",
|
||||
// Picker
|
||||
["UTKColorPicker"] = "UIToolkit/Sample/Picker/UTKColorPickerSample",
|
||||
["UTKDatePicker"] = "UIToolkit/Sample/Picker/UTKDatePickerSample",
|
||||
@@ -124,10 +127,10 @@ public partial class UTKStyleGuideSample : MonoBehaviour
|
||||
["Slider"] = new[] { "UTKSlider", "UTKSliderInt", "UTKMinMaxSlider", "UTKProgressBar" },
|
||||
["Dropdown"] = new[] { "UTKDropdown", "UTKEnumDropDown", "UTKMultiSelectDropdown" },
|
||||
["Label"] = new[] { "UTKLabel", "UTKHelpBox" },
|
||||
["List"] = new[] { "UTKListView", "UTKTreeView", "UTKMultiColumnListView", "UTKMultiColumnTreeView", "UTKFoldout", "UTKScrollView", "UTKShortcutList" },
|
||||
["List"] = new[] { "UTKListView", "UTKTreeView", "UTKMultiColumnListView", "UTKMultiColumnTreeView", "UTKFoldout", "UTKScrollView", "UTKShortcutList", "UTKReordableList", "UTKReordableTabList" },
|
||||
["Card"] = new[] { "UTKCard", "UTKPanel" },
|
||||
["Tab"] = new[] { "UTKTabView" },
|
||||
["Modal"] = new[] { "UTKAlert", "UTKToast", "UTKTooltip", "UTKNotification", "UTKModal" },
|
||||
["Modal"] = new[] { "UTKAlert", "UTKToast", "UTKTooltip", "UTKNotification", "UTKModal", "UTKLoading" },
|
||||
["Picker"] = new[] { "UTKColorPicker", "UTKDatePicker" },
|
||||
["Menu"] = new[] { "UTKTopMenu" },
|
||||
["ToolBar"] = new[] { "UTKToolBar" },
|
||||
@@ -531,6 +534,12 @@ public partial class UTKStyleGuideSample : MonoBehaviour
|
||||
case "UTKShortcutList":
|
||||
InitializeShortcutListSample(root);
|
||||
break;
|
||||
case "UTKReordableList":
|
||||
InitializeReordableListSample(root);
|
||||
break;
|
||||
case "UTKReordableTabList":
|
||||
InitializeReordableTabListSample(root);
|
||||
break;
|
||||
// Card
|
||||
case "UTKCard":
|
||||
InitializeCardSample(root);
|
||||
@@ -558,6 +567,9 @@ public partial class UTKStyleGuideSample : MonoBehaviour
|
||||
case "UTKModal":
|
||||
InitializeModalSample(root);
|
||||
break;
|
||||
case "UTKLoading":
|
||||
InitializeLoadingSample(root);
|
||||
break;
|
||||
// Picker
|
||||
case "UTKColorPicker":
|
||||
InitializeColorPickerSample(root);
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using UVC.UIToolkit;
|
||||
|
||||
namespace Factory.UIToolkit.Modal
|
||||
{
|
||||
/// <summary>
|
||||
/// 설정 표시 정보 탭 뷰.
|
||||
/// UTKReordableList를 사용하여 표시 항목의 순서, 사용 유무, 내용을 관리합니다.
|
||||
/// </summary>
|
||||
[UxmlElement]
|
||||
public partial class UTKFactorySettingModalContent : VisualElement, IDisposable, IUTKModalContent<object>
|
||||
{
|
||||
private UTKTabView tabView;
|
||||
|
||||
public UTKFactorySettingModalContent()
|
||||
{
|
||||
style.flexGrow = 1;
|
||||
|
||||
tabView = new UTKTabView();
|
||||
tabView.style.flexGrow = 1;
|
||||
tabView.TabWidth = 140; // 탭 너비 설정
|
||||
|
||||
// 탭 정렬 방향 설정
|
||||
tabView.Align = TabAlign.Left; // 탭을 왼쪽에 세로로 배치
|
||||
|
||||
// 탭 추가
|
||||
var tab1 = tabView.AddUTKTab("일반정보");
|
||||
tab1.Add(new UTKFactorySettingModalContentGeneral());
|
||||
|
||||
var tab2 = tabView.AddUTKTab("표시정보");
|
||||
tab2.Add(new UTKFactorySettingModalContentDisplay());
|
||||
|
||||
var tab3 = tabView.AddUTKTab("알람설정");
|
||||
tab3.Add(new UTKFactorySettingModalContentAlarm());
|
||||
|
||||
var tab4 = tabView.AddUTKTab("입력설정");
|
||||
tab4.Add(new UTKFactorySettingModalContentInput());
|
||||
|
||||
tabView.OnTabChanged += OnTabChanged;
|
||||
tabView.tabClosed += OnTabClosed;
|
||||
Add(tabView);
|
||||
}
|
||||
|
||||
public UTKFactorySettingModalContent(int tabIndex = 0, object? data = null) : this()
|
||||
{
|
||||
// 생성자에서 탭 인덱스를 받아서 초기 탭 설정
|
||||
tabView.SelectedIndex = tabIndex;
|
||||
}
|
||||
|
||||
private void OnTabChanged(int index, UnityEngine.UIElements.Tab? tab)
|
||||
{
|
||||
Debug.Log($"Selected Tab Index: {index}");
|
||||
|
||||
}
|
||||
|
||||
private void OnTabClosed(UnityEngine.UIElements.Tab tab, int index)
|
||||
{
|
||||
Debug.Log($"Closed Tab Index: {index}");
|
||||
}
|
||||
|
||||
public object? GetResult()
|
||||
{
|
||||
IUTKTabContent? content = UTKTabView.FindTabContent(tabView.activeTab);
|
||||
if (content != null) {
|
||||
return content.Hide();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// 필요한 경우 리소스 정리
|
||||
tabView.OnTabChanged -= OnTabChanged;
|
||||
tabView.tabClosed -= OnTabClosed;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
#nullable enable
|
||||
using Cysharp.Threading.Tasks;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using UVC.UIToolkit;
|
||||
|
||||
namespace Factory.UIToolkit.Modal
|
||||
{
|
||||
/// <summary>
|
||||
/// 설정 모달 - Alarm 탭 콘텐츠
|
||||
/// </summary>
|
||||
[UxmlElement]
|
||||
public partial class UTKFactorySettingModalContentAlarm : VisualElement, IDisposable, IUTKTabContent
|
||||
{
|
||||
#region Constants
|
||||
private const string UXML_PATH = "Factory/UIToolkit/Modal/UTKFactorySettingModalContentAlarmUXML";
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
private bool _disposed;
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
public UTKFactorySettingModalContentAlarm()
|
||||
{
|
||||
var asset = Resources.Load<VisualTreeAsset>(UXML_PATH);
|
||||
if (asset != null)
|
||||
{
|
||||
var root = asset.Instantiate();
|
||||
root.style.flexGrow = 1;
|
||||
|
||||
Add(root);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public void Show(object? data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public async UniTask Hide()
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 69e3bac5218612948a3c387aabbfac97
|
||||
@@ -0,0 +1,114 @@
|
||||
#nullable enable
|
||||
using Cysharp.Threading.Tasks;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using UVC.UIToolkit;
|
||||
|
||||
namespace Factory.UIToolkit.Modal
|
||||
{
|
||||
/// <summary>
|
||||
/// 설정 모달 - Display 탭 콘텐츠
|
||||
/// </summary>
|
||||
[UxmlElement]
|
||||
public partial class UTKFactorySettingModalContentDisplay : VisualElement, IDisposable, IUTKTabContent
|
||||
{
|
||||
#region Constants
|
||||
private const string UXML_PATH = "Factory/UIToolkit/Modal/UTKFactorySettingModalContentDisplayUXML";
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
private bool _disposed;
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
private UTKReordableTabList? _reordableTabList;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
public UTKFactorySettingModalContentDisplay()
|
||||
{
|
||||
var asset = Resources.Load<VisualTreeAsset>(UXML_PATH);
|
||||
if (asset != null)
|
||||
{
|
||||
var root = asset.Instantiate();
|
||||
root.style.flexGrow = 1;
|
||||
_reordableTabList = root.Q<UTKReordableTabList>("tab-list");
|
||||
if(_reordableTabList != null)
|
||||
{
|
||||
_reordableTabList.OnDataChanged += OnDataChanged;
|
||||
_reordableTabList.OnOrderChanged += OnOrderChanged;
|
||||
SetTabListSampleData();
|
||||
}
|
||||
|
||||
Add(root);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDataChanged(string tabName, int tabIndex)
|
||||
{
|
||||
Debug.Log($"Tab '{tabName}' at index {tabIndex} has changed.");
|
||||
}
|
||||
|
||||
private void OnOrderChanged(string tabName, int tabIndex)
|
||||
{
|
||||
Debug.Log($"Tab '{tabName}' moved index {tabIndex}.");
|
||||
}
|
||||
|
||||
private void SetTabListSampleData()
|
||||
{
|
||||
var data = new Dictionary<string, List<Dictionary<string, string>>>
|
||||
{
|
||||
["센서"] = new()
|
||||
{
|
||||
new() { ["order"] = "0", ["active"] = "True", ["text"] = "온도 센서" },
|
||||
new() { ["order"] = "1", ["active"] = "True", ["text"] = "습도 센서" },
|
||||
new() { ["order"] = "2", ["active"] = "False", ["text"] = "압력 센서" },
|
||||
},
|
||||
["장비"] = new()
|
||||
{
|
||||
new() { ["order"] = "0", ["active"] = "True", ["text"] = "컨베이어" },
|
||||
new() { ["order"] = "1", ["active"] = "False", ["text"] = "로봇암" },
|
||||
new() { ["order"] = "2", ["active"] = "True", ["text"] = "CNC" },
|
||||
new() { ["order"] = "3", ["active"] = "True", ["text"] = "AGV" },
|
||||
},
|
||||
["알림"] = new()
|
||||
{
|
||||
new() { ["order"] = "0", ["active"] = "True", ["text"] = "경고" },
|
||||
new() { ["order"] = "1", ["active"] = "True", ["text"] = "에러" },
|
||||
}
|
||||
};
|
||||
_reordableTabList?.SetData(data);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public void Show(object? data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public async UniTask Hide()
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
|
||||
if (_reordableTabList != null)
|
||||
{
|
||||
_reordableTabList.OnDataChanged -= OnDataChanged;
|
||||
_reordableTabList.OnOrderChanged -= OnOrderChanged;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0c06814030527b647a47600c3f5ca0ab
|
||||
@@ -0,0 +1,61 @@
|
||||
#nullable enable
|
||||
using Cysharp.Threading.Tasks;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using UVC.UIToolkit;
|
||||
|
||||
namespace Factory.UIToolkit.Modal
|
||||
{
|
||||
/// <summary>
|
||||
/// 설정 모달 - General 탭 콘텐츠
|
||||
/// </summary>
|
||||
[UxmlElement]
|
||||
public partial class UTKFactorySettingModalContentGeneral : VisualElement, IDisposable, IUTKTabContent
|
||||
{
|
||||
#region Constants
|
||||
private const string UXML_PATH = "Factory/UIToolkit/Modal/UTKFactorySettingModalContentGeneralUXML";
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
private bool _disposed;
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
public UTKFactorySettingModalContentGeneral()
|
||||
{
|
||||
var asset = Resources.Load<VisualTreeAsset>(UXML_PATH);
|
||||
if (asset != null)
|
||||
{
|
||||
var root = asset.Instantiate();
|
||||
root.style.flexGrow = 1;
|
||||
|
||||
Add(root);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public void Show(object? data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public async UniTask Hide()
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be3d3c94c420c364e80b63ff4f383352
|
||||
@@ -0,0 +1,61 @@
|
||||
#nullable enable
|
||||
using Cysharp.Threading.Tasks;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using UVC.UIToolkit;
|
||||
|
||||
namespace Factory.UIToolkit.Modal
|
||||
{
|
||||
/// <summary>
|
||||
/// 설정 모달 - Input 탭 콘텐츠
|
||||
/// </summary>
|
||||
[UxmlElement]
|
||||
public partial class UTKFactorySettingModalContentInput : VisualElement, IDisposable, IUTKTabContent
|
||||
{
|
||||
#region Constants
|
||||
private const string UXML_PATH = "Factory/UIToolkit/Modal/UTKFactorySettingModalContentInputUXML";
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
private bool _disposed;
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
public UTKFactorySettingModalContentInput()
|
||||
{
|
||||
var asset = Resources.Load<VisualTreeAsset>(UXML_PATH);
|
||||
if (asset != null)
|
||||
{
|
||||
var root = asset.Instantiate();
|
||||
root.style.flexGrow = 1;
|
||||
|
||||
Add(root);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public void Show(object? data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public async UniTask Hide()
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 74b285c2c1dbdd24d9eb94f943ac251a
|
||||
360
Assets/Scripts/UVC/UIToolkit/List/UTKReordableTabList.cs
Normal file
360
Assets/Scripts/UVC/UIToolkit/List/UTKReordableTabList.cs
Normal file
@@ -0,0 +1,360 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace UVC.UIToolkit
|
||||
{
|
||||
/// <summary>
|
||||
/// 탭 기반 재정렬 가능 리스트.
|
||||
/// UTKTabView와 UTKReordableList를 조합하여 탭별로 독립적인 재정렬 리스트를 제공합니다.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para><b>구조:</b></para>
|
||||
/// <code>
|
||||
/// UTKReordableTabList
|
||||
/// └─ UTKTabView
|
||||
/// ├─ UTKTab "탭1" → UTKReordableList (인스턴스 1)
|
||||
/// ├─ UTKTab "탭2" → UTKReordableList (인스턴스 2)
|
||||
/// └─ UTKTab "탭N" → UTKReordableList (인스턴스 N)
|
||||
/// </code>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <para><b>C# 코드에서 사용:</b></para>
|
||||
/// <code>
|
||||
/// var tabList = new UTKReordableTabList();
|
||||
/// tabList.SetData(new Dictionary<string, List<ReordableListItemData>>
|
||||
/// {
|
||||
/// { "일반", generalItems },
|
||||
/// { "고급", advancedItems }
|
||||
/// });
|
||||
///
|
||||
/// // 전체 데이터 가져오기
|
||||
/// var allData = tabList.GetData();
|
||||
///
|
||||
/// // 특정 탭 데이터 가져오기
|
||||
/// var generalData = tabList.GetData("일반");
|
||||
/// var firstTabData = tabList.GetData(0);
|
||||
///
|
||||
/// // 이벤트 구독
|
||||
/// tabList.OnOrderChanged += (tabName, tabIndex) =>
|
||||
/// {
|
||||
/// Debug.Log($"[{tabName}] (탭 {tabIndex}) 순서 변경됨");
|
||||
/// };
|
||||
/// tabList.OnDataChanged += (tabName, tabIndex) =>
|
||||
/// {
|
||||
/// Debug.Log($"[{tabName}] (탭 {tabIndex}) 데이터 변경됨");
|
||||
/// };
|
||||
/// </code>
|
||||
/// <para><b>UXML에서 사용:</b></para>
|
||||
/// <code>
|
||||
/// <ui:UXML xmlns:utk="UVC.UIToolkit">
|
||||
/// <utk:UTKReordableTabList />
|
||||
/// </ui:UXML>
|
||||
/// </code>
|
||||
/// </example>
|
||||
[UxmlElement]
|
||||
public partial class UTKReordableTabList : VisualElement, IDisposable
|
||||
{
|
||||
#region Constants
|
||||
private const string USS_PATH = "UIToolkit/List/UTKReordableTabListUss";
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
private bool _disposed;
|
||||
private UTKTabView? _tabView;
|
||||
|
||||
/// <summary>탭 이름 → UTKReordableList 매핑</summary>
|
||||
private readonly Dictionary<string, UTKReordableList> _tabLists = new();
|
||||
|
||||
/// <summary>탭 이름 순서 보존용</summary>
|
||||
private readonly List<string> _tabNames = new();
|
||||
|
||||
/// <summary>리스트별 이벤트 콜백 참조 (해제용)</summary>
|
||||
private readonly Dictionary<string, TabListCallbackInfo> _callbackInfos = new();
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
/// <summary>순서 변경 시 발생 (탭 이름, 탭 인덱스)</summary>
|
||||
public event Action<string, int>? OnOrderChanged;
|
||||
|
||||
/// <summary>데이터(체크/텍스트) 변경 시 발생 (탭 이름, 탭 인덱스)</summary>
|
||||
public event Action<string, int>? OnDataChanged;
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
public UTKReordableTabList() : base()
|
||||
{
|
||||
// 1. 테마 적용
|
||||
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
||||
|
||||
// 2. USS 로드
|
||||
var uss = Resources.Load<StyleSheet>(USS_PATH);
|
||||
if (uss != null)
|
||||
{
|
||||
styleSheets.Add(uss);
|
||||
}
|
||||
|
||||
// 3. UI 생성
|
||||
CreateUI();
|
||||
|
||||
// 4. 테마 변경 구독
|
||||
SubscribeToThemeChanges();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Setup
|
||||
private void CreateUI()
|
||||
{
|
||||
AddToClassList("reordable-tab-list");
|
||||
|
||||
_tabView = new UTKTabView();
|
||||
_tabView.AddToClassList("reordable-tab-list__tabview");
|
||||
Add(_tabView);
|
||||
}
|
||||
|
||||
private void SubscribeToThemeChanges()
|
||||
{
|
||||
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
|
||||
RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
|
||||
RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
|
||||
}
|
||||
|
||||
private void OnAttachToPanelForTheme(AttachToPanelEvent evt)
|
||||
{
|
||||
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
|
||||
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
|
||||
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
||||
}
|
||||
|
||||
private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt)
|
||||
{
|
||||
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
|
||||
}
|
||||
|
||||
private void OnThemeChanged(UTKTheme theme)
|
||||
{
|
||||
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public API - SetData
|
||||
/// <summary>
|
||||
/// 탭별 데이터를 설정합니다. 기존 구성을 모두 제거하고 재생성합니다.
|
||||
/// </summary>
|
||||
/// <param name="data">탭 이름 → 아이템 데이터 목록 매핑.</param>
|
||||
public void SetData(Dictionary<string, List<ReordableListItemData>> data)
|
||||
{
|
||||
// 기존 구성 제거
|
||||
ClearAll();
|
||||
|
||||
if (data == null || _tabView == null) return;
|
||||
|
||||
foreach (var kvp in data)
|
||||
{
|
||||
var tabName = kvp.Key;
|
||||
var items = kvp.Value ?? new List<ReordableListItemData>();
|
||||
|
||||
_tabNames.Add(tabName);
|
||||
|
||||
// UTKReordableList 생성
|
||||
var reordableList = new UTKReordableList();
|
||||
reordableList.AddToClassList("reordable-tab-list__list");
|
||||
reordableList.SetData(items);
|
||||
|
||||
// 이벤트 연결 (콜백 참조 보관하여 해제 가능하게)
|
||||
var capturedName = tabName;
|
||||
var capturedIndex = _tabNames.Count - 1;
|
||||
Action onOrder = () => OnOrderChanged?.Invoke(capturedName, capturedIndex);
|
||||
Action onData = () => OnDataChanged?.Invoke(capturedName, capturedIndex);
|
||||
reordableList.OnOrderChanged += onOrder;
|
||||
reordableList.OnDataChanged += onData;
|
||||
_callbackInfos[tabName] = new TabListCallbackInfo(onOrder, onData);
|
||||
|
||||
_tabLists[tabName] = reordableList;
|
||||
|
||||
// 탭 추가
|
||||
_tabView.AddUTKTab(tabName, reordableList);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dictionary 형식의 데이터를 변환하여 설정합니다.
|
||||
/// Dictionary 키: "order" (순서), "active" (사용 유무), "text" (표시 내용)
|
||||
/// </summary>
|
||||
/// <param name="data">탭 이름 → Dictionary 목록 매핑.</param>
|
||||
public void SetData(Dictionary<string, List<Dictionary<string, string>>> data)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
ClearAll();
|
||||
return;
|
||||
}
|
||||
|
||||
var converted = new Dictionary<string, List<ReordableListItemData>>(data.Count);
|
||||
|
||||
foreach (var kvp in data)
|
||||
{
|
||||
var items = new List<ReordableListItemData>();
|
||||
|
||||
if (kvp.Value != null)
|
||||
{
|
||||
for (int i = 0; i < kvp.Value.Count; i++)
|
||||
{
|
||||
var dict = kvp.Value[i];
|
||||
var item = new ReordableListItemData();
|
||||
|
||||
item.Order = dict.TryGetValue("order", out var orderStr) && int.TryParse(orderStr, out var order)
|
||||
? order
|
||||
: i;
|
||||
|
||||
item.IsActive = dict.TryGetValue("active", out var activeStr) && bool.TryParse(activeStr, out var active)
|
||||
? active
|
||||
: true;
|
||||
|
||||
item.DisplayText = dict.TryGetValue("text", out var text)
|
||||
? text ?? ""
|
||||
: "";
|
||||
|
||||
items.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
converted[kvp.Key] = items;
|
||||
}
|
||||
|
||||
SetData(converted);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public API - GetData
|
||||
/// <summary>
|
||||
/// 모든 탭의 데이터를 반환합니다.
|
||||
/// </summary>
|
||||
/// <returns>탭 이름 → 아이템 데이터 목록 매핑.</returns>
|
||||
public Dictionary<string, List<ReordableListItemData>> GetData()
|
||||
{
|
||||
var result = new Dictionary<string, List<ReordableListItemData>>(_tabLists.Count);
|
||||
|
||||
foreach (var tabName in _tabNames)
|
||||
{
|
||||
if (_tabLists.TryGetValue(tabName, out var list))
|
||||
{
|
||||
result[tabName] = list.GetData();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 특정 탭의 데이터를 이름으로 반환합니다.
|
||||
/// </summary>
|
||||
/// <param name="tabName">탭 이름.</param>
|
||||
/// <returns>아이템 데이터 목록 또는 null.</returns>
|
||||
public List<ReordableListItemData>? GetData(string tabName)
|
||||
{
|
||||
return _tabLists.TryGetValue(tabName, out var list) ? list.GetData() : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 특정 탭의 데이터를 인덱스로 반환합니다.
|
||||
/// </summary>
|
||||
/// <param name="tabIndex">탭 인덱스.</param>
|
||||
/// <returns>아이템 데이터 목록 또는 null.</returns>
|
||||
public List<ReordableListItemData>? GetData(int tabIndex)
|
||||
{
|
||||
if (tabIndex < 0 || tabIndex >= _tabNames.Count) return null;
|
||||
return GetData(_tabNames[tabIndex]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 모든 탭의 데이터를 Dictionary 형식으로 변환하여 반환합니다.
|
||||
/// Dictionary 키: "order" (순서), "active" (사용 유무), "text" (표시 내용)
|
||||
/// </summary>
|
||||
/// <returns>탭 이름 → Dictionary 목록 매핑.</returns>
|
||||
public Dictionary<string, List<Dictionary<string, string>>> ToDictionary()
|
||||
{
|
||||
var result = new Dictionary<string, List<Dictionary<string, string>>>(_tabLists.Count);
|
||||
|
||||
foreach (var tabName in _tabNames)
|
||||
{
|
||||
if (_tabLists.TryGetValue(tabName, out var list))
|
||||
{
|
||||
result[tabName] = list.ToDictionary();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Internal
|
||||
/// <summary>
|
||||
/// 기존 탭과 리스트를 모두 제거합니다.
|
||||
/// </summary>
|
||||
private void ClearAll()
|
||||
{
|
||||
// 이벤트 콜백 해제 후 리스트 Dispose
|
||||
foreach (var tabName in _tabNames)
|
||||
{
|
||||
if (_tabLists.TryGetValue(tabName, out var list))
|
||||
{
|
||||
if (_callbackInfos.TryGetValue(tabName, out var info))
|
||||
{
|
||||
list.OnOrderChanged -= info.OnOrderHandler;
|
||||
list.OnDataChanged -= info.OnDataHandler;
|
||||
}
|
||||
list.Dispose();
|
||||
}
|
||||
}
|
||||
_tabLists.Clear();
|
||||
_tabNames.Clear();
|
||||
_callbackInfos.Clear();
|
||||
|
||||
// 탭 제거
|
||||
_tabView?.ClearTabs();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Internal Types
|
||||
/// <summary>리스트 이벤트 콜백 참조 추적</summary>
|
||||
private class TabListCallbackInfo
|
||||
{
|
||||
public readonly Action OnOrderHandler;
|
||||
public readonly Action OnDataHandler;
|
||||
|
||||
public TabListCallbackInfo(Action onOrderHandler, Action onDataHandler)
|
||||
{
|
||||
OnOrderHandler = onOrderHandler;
|
||||
OnDataHandler = onDataHandler;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
|
||||
// 테마 구독 해제
|
||||
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
|
||||
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
|
||||
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
|
||||
|
||||
// 리스트 정리
|
||||
ClearAll();
|
||||
|
||||
// TabView 정리
|
||||
_tabView?.Dispose();
|
||||
_tabView = null;
|
||||
|
||||
// 이벤트 정리
|
||||
OnOrderChanged = null;
|
||||
OnDataChanged = null;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9aff9465689e6be42a8814509b1dc848
|
||||
@@ -1,193 +0,0 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace UVC.UIToolkit
|
||||
{
|
||||
/// <summary>
|
||||
/// 설정 표시 정보 탭 뷰.
|
||||
/// UTKReordableList를 사용하여 표시 항목의 순서, 사용 유무, 내용을 관리합니다.
|
||||
/// </summary>
|
||||
[UxmlElement]
|
||||
public partial class UTKSettingDisplayInfoTabView : VisualElement, IDisposable
|
||||
{
|
||||
#region Constants
|
||||
private const string USS_PATH = "UIToolkit/Modal/Setting/UTKSettingDisplayInfoTabViewUss";
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
private bool _disposed;
|
||||
private UTKReordableList? _reordableList;
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
/// <summary>순서 변경 시 발생</summary>
|
||||
public event Action? OnOrderChanged;
|
||||
|
||||
/// <summary>데이터(체크/텍스트) 변경 시 발생</summary>
|
||||
public event Action? OnDataChanged;
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
public UTKSettingDisplayInfoTabView() : base()
|
||||
{
|
||||
// 1. 테마 적용
|
||||
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
||||
|
||||
// 2. USS 로드
|
||||
var uss = Resources.Load<StyleSheet>(USS_PATH);
|
||||
if (uss != null)
|
||||
{
|
||||
styleSheets.Add(uss);
|
||||
}
|
||||
|
||||
// 3. UI 생성
|
||||
CreateUI();
|
||||
|
||||
// 4. 테마 변경 구독
|
||||
SubscribeToThemeChanges();
|
||||
|
||||
SampleSetAndGetWithDictionary();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Setup
|
||||
private void CreateUI()
|
||||
{
|
||||
AddToClassList("setting-display-tab-view");
|
||||
|
||||
_reordableList = new UTKReordableList();
|
||||
_reordableList.style.flexGrow = 1;
|
||||
_reordableList.OnOrderChanged += () => OnOrderChanged?.Invoke();
|
||||
_reordableList.OnDataChanged += () => OnDataChanged?.Invoke();
|
||||
Add(_reordableList);
|
||||
|
||||
// 하단 버튼 영역
|
||||
var buttonContainer = new VisualElement();
|
||||
buttonContainer.style.flexDirection = FlexDirection.Row;
|
||||
buttonContainer.style.justifyContent = Justify.FlexEnd;
|
||||
buttonContainer.style.paddingTop = 8;
|
||||
|
||||
var saveBtn = new UTKButton("저장", variant: UTKButton.ButtonVariant.Primary);
|
||||
saveBtn.OnClicked += OnSaveButtonClicked;
|
||||
buttonContainer.Add(saveBtn);
|
||||
|
||||
Add(buttonContainer);
|
||||
}
|
||||
|
||||
private void OnSaveButtonClicked()
|
||||
{
|
||||
List<Dictionary<string, string>> result = ToDictionary();
|
||||
foreach (var dict in result)
|
||||
{
|
||||
Debug.Log($"order={dict["order"]}, active={dict["active"]}, text={dict["text"]}");
|
||||
}
|
||||
}
|
||||
|
||||
private void SubscribeToThemeChanges()
|
||||
{
|
||||
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
|
||||
RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
|
||||
RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
|
||||
}
|
||||
|
||||
private void OnAttachToPanelForTheme(AttachToPanelEvent evt)
|
||||
{
|
||||
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
|
||||
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
|
||||
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
||||
}
|
||||
|
||||
private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt)
|
||||
{
|
||||
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
|
||||
}
|
||||
|
||||
private void OnThemeChanged(UTKTheme theme)
|
||||
{
|
||||
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public API
|
||||
/// <summary>
|
||||
/// 데이터를 설정하고 리스트를 갱신합니다.
|
||||
/// </summary>
|
||||
/// <param name="items">표시할 아이템 데이터 목록.</param>
|
||||
public void SetData(List<ReordableListItemData> items)
|
||||
{
|
||||
_reordableList?.SetData(items);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List<Dictionary>로부터 데이터를 변환하여 설정합니다.
|
||||
/// Dictionary 키: "order" (순서), "active" (사용 유무), "text" (표시 내용)
|
||||
/// </summary>
|
||||
/// <param name="listDict">변환할 Dictionary 목록.</param>
|
||||
public void SetData(List<Dictionary<string, string>> listDict)
|
||||
{
|
||||
_reordableList?.SetData(listDict);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Order 값이 동기화된 데이터 목록을 반환합니다.
|
||||
/// </summary>
|
||||
/// <returns>현재 리스트 순서가 반영된 데이터 목록.</returns>
|
||||
public List<ReordableListItemData> GetData()
|
||||
{
|
||||
return _reordableList?.GetData() ?? new List<ReordableListItemData>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 전체 아이템을 List<Dictionary<string, string>>로 변환하여 반환합니다.
|
||||
/// Dictionary 키: "order" (순서), "active" (사용 유무), "text" (표시 내용)
|
||||
/// </summary>
|
||||
/// <returns>각 아이템을 Dictionary로 변환한 목록.</returns>
|
||||
public List<Dictionary<string, string>> ToDictionary()
|
||||
{
|
||||
return _reordableList?.ToDictionary() ?? new List<Dictionary<string, string>>();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Sample
|
||||
/// <summary>
|
||||
/// Dictionary 기반 데이터 설정 및 조회 샘플.
|
||||
/// </summary>
|
||||
public void SampleSetAndGetWithDictionary()
|
||||
{
|
||||
// 1. Dictionary 데이터로 설정
|
||||
var listDict = new List<Dictionary<string, string>>
|
||||
{
|
||||
new() { ["order"] = "0", ["active"] = "True", ["text"] = "온도" },
|
||||
new() { ["order"] = "1", ["active"] = "False", ["text"] = "습도" },
|
||||
new() { ["order"] = "2", ["active"] = "True", ["text"] = "압력" },
|
||||
};
|
||||
SetData(listDict);
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
|
||||
// 테마 구독 해제
|
||||
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
|
||||
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
|
||||
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
|
||||
|
||||
// ReordableList 정리
|
||||
_reordableList?.Dispose();
|
||||
_reordableList = null;
|
||||
|
||||
// 이벤트 정리
|
||||
OnOrderChanged = null;
|
||||
OnDataChanged = null;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
464
Assets/Scripts/UVC/UIToolkit/Modal/UTKLoading.cs
Normal file
464
Assets/Scripts/UVC/UIToolkit/Modal/UTKLoading.cs
Normal file
@@ -0,0 +1,464 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace UVC.UIToolkit
|
||||
{
|
||||
/// <summary>
|
||||
/// 회전하면서 호가 길어졌다 짧아지는 원형 로딩 스피너 컴포넌트.
|
||||
/// Painter2D Drawing API로 자연스러운 원호를 직접 그립니다.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para><b>두 가지 사용 방식 비교:</b></para>
|
||||
/// <list type="table">
|
||||
/// <listheader>
|
||||
/// <term>항목</term>
|
||||
/// <description>Static API / UXML 태그</description>
|
||||
/// </listheader>
|
||||
/// <item>
|
||||
/// <term>배치 위치</term>
|
||||
/// <description>Static: panel.visualTree 최상단 / UXML: 레이아웃 내 인라인</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>Blocker</term>
|
||||
/// <description>Static: 있음 (전체 클릭 차단) / UXML: 없음</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>위치</term>
|
||||
/// <description>Static: 화면 정중앙 고정 / UXML: CSS 레이아웃 따름</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>시작</term>
|
||||
/// <description>Static: Show() 호출 시 / UXML: AttachToPanel 자동 (auto-play=true)</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>정지</term>
|
||||
/// <description>Static: Hide() 호출 시 / UXML: DetachFromPanel 자동</description>
|
||||
/// </item>
|
||||
/// </list>
|
||||
///
|
||||
/// <para><b>색상·두께·크기 설정:</b></para>
|
||||
/// <list type="bullet">
|
||||
/// <item><description>기본 색상은 현재 테마의 <c>--color-primary</c>를 자동 적용합니다.</description></item>
|
||||
/// <item><description><c>arc-color</c> 속성을 지정하면 테마 색상을 무시하고 해당 색상을 사용합니다.</description></item>
|
||||
/// <item><description><c>thickness</c>: 선 두께 (px, 기본값: 4)</description></item>
|
||||
/// <item><description><c>size</c>: 스피너 크기 (px, 기본값: 48)</description></item>
|
||||
/// <item><description><c>speed</c>: 회전 속도 배율 (기본값: 1.0)</description></item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <para><b>Static API (전체 화면 로딩 + Blocker):</b></para>
|
||||
/// <code>
|
||||
/// UTKLoading.SetRoot(rootVisualElement);
|
||||
/// UTKLoading.Show(); // 기본 속도
|
||||
/// UTKLoading.Show(speed: 2f); // 빠른 회전
|
||||
/// UTKLoading.Hide();
|
||||
/// </code>
|
||||
/// <para><b>UXML 태그 (인라인 배치, Blocker 없음):</b></para>
|
||||
/// <code>
|
||||
/// <utk:UTKLoading speed="1.5" auto-play="true" />
|
||||
/// <utk:UTKLoading arc-color="#73C991" thickness="6" size="64" auto-play="true" />
|
||||
/// </code>
|
||||
/// </example>
|
||||
[UxmlElement]
|
||||
public partial class UTKLoading : VisualElement, IDisposable
|
||||
{
|
||||
#region Constants
|
||||
private const string USS_PATH = "UIToolkit/Modal/UTKLoadingUss";
|
||||
|
||||
// 애니메이션 업데이트 간격 (16ms ≈ 60fps)
|
||||
private const long UPDATE_INTERVAL_MS = 16;
|
||||
|
||||
// 기본 회전 속도 (도/초) — 180도/초 = 0.5바퀴/초
|
||||
private const float DEFAULT_SPEED_DEG = 270f;
|
||||
|
||||
// 호 최대 길이 (도) — 360도
|
||||
private const float ARC_MAX_DEG = 360f;
|
||||
|
||||
// 호 길이 변화 주기 (라디안/초) — 0~2π 사이클용 시간 누적 (내부 phase 계산용)
|
||||
// 0.8π ≈ 한 사이클 약 2.5초
|
||||
private const float ARC_CYCLE_SPEED = Mathf.PI * 0.8f;
|
||||
|
||||
// 기본 크기/두께
|
||||
private const float DEFAULT_SIZE = 48f;
|
||||
private const float DEFAULT_THICKNESS = 4f;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
private static VisualElement? _root;
|
||||
private static UTKLoading? _activeInstance;
|
||||
|
||||
private bool _disposed;
|
||||
private bool _isAnimating;
|
||||
private float _speedDeg = DEFAULT_SPEED_DEG;
|
||||
private bool _autoPlay = true;
|
||||
|
||||
// 애니메이션 상태
|
||||
private float _rotation = 0f; // 현재 회전 각도 (도, 계속 누적)
|
||||
private float _cycleTime = 0f; // 0~2π 범위 phase 누적 (라디안)
|
||||
|
||||
// 렌더링 파라미터
|
||||
private Color? _arcColorOverride; // null이면 테마 색상 사용
|
||||
private Color _resolvedThemeColor = UTKStyleGuide.Blue05; // OnCustomStyleResolved에서 갱신
|
||||
private float _thickness = DEFAULT_THICKNESS;
|
||||
private float _size = DEFAULT_SIZE;
|
||||
|
||||
// 클릭 차단 레이어 (Static Show()에서만 사용)
|
||||
private VisualElement? _blocker;
|
||||
|
||||
// 스케줄 핸들
|
||||
private IVisualElementScheduledItem? _animationSchedule;
|
||||
#endregion
|
||||
|
||||
#region UxmlAttributes
|
||||
/// <summary>회전 속도 배율. 1.0 = 기본 속도</summary>
|
||||
[UxmlAttribute("speed")]
|
||||
public float Speed
|
||||
{
|
||||
get => _speedDeg / DEFAULT_SPEED_DEG;
|
||||
set => _speedDeg = DEFAULT_SPEED_DEG * Mathf.Max(0.1f, value);
|
||||
}
|
||||
|
||||
/// <summary>패널에 연결될 때 자동으로 애니메이션을 시작할지 여부</summary>
|
||||
[UxmlAttribute("auto-play")]
|
||||
public bool AutoPlay
|
||||
{
|
||||
get => _autoPlay;
|
||||
set => _autoPlay = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 스피너 색상. 지정하지 않으면 현재 테마의 --color-primary가 적용됩니다.
|
||||
/// </summary>
|
||||
[UxmlAttribute("arc-color")]
|
||||
public Color ArcColor
|
||||
{
|
||||
get => _arcColorOverride ?? _resolvedThemeColor;
|
||||
set
|
||||
{
|
||||
_arcColorOverride = value;
|
||||
MarkDirtyRepaint();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>선 두께 (px)</summary>
|
||||
[UxmlAttribute("thickness")]
|
||||
public float Thickness
|
||||
{
|
||||
get => _thickness;
|
||||
set
|
||||
{
|
||||
_thickness = Mathf.Max(1f, value);
|
||||
MarkDirtyRepaint();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>스피너 전체 크기 (px)</summary>
|
||||
[UxmlAttribute("size")]
|
||||
public float Size
|
||||
{
|
||||
get => _size;
|
||||
set
|
||||
{
|
||||
_size = Mathf.Max(8f, value);
|
||||
style.width = _size;
|
||||
style.height = _size;
|
||||
MarkDirtyRepaint();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
/// <summary>
|
||||
/// UTKLoading 기본 생성자.
|
||||
/// UXML 태그로 배치하면 패널에 연결될 때 auto-play 설정에 따라 자동 시작됩니다.
|
||||
/// </summary>
|
||||
public UTKLoading()
|
||||
{
|
||||
// 테마 스타일시트 적용 (--color-primary 변수 상속용)
|
||||
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
||||
|
||||
var uss = Resources.Load<StyleSheet>(USS_PATH);
|
||||
if (uss != null)
|
||||
styleSheets.Add(uss);
|
||||
|
||||
AddToClassList("utk-loading");
|
||||
|
||||
// 고정 크기 지정 (Drawing API는 contentRect 기준)
|
||||
style.width = _size;
|
||||
style.height = _size;
|
||||
style.flexShrink = 0;
|
||||
|
||||
// customStyle 변경 시 테마 색상 갱신
|
||||
RegisterCallback<CustomStyleResolvedEvent>(OnCustomStyleResolved);
|
||||
|
||||
// Drawing API 콜백 등록
|
||||
generateVisualContent += OnGenerateVisualContent;
|
||||
|
||||
SubscribeToThemeChanges();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Static API
|
||||
/// <summary>
|
||||
/// 기본 루트 요소 설정.
|
||||
/// 로딩 스피너는 이 루트의 panel.visualTree에 표시됩니다.
|
||||
/// </summary>
|
||||
public static void SetRoot(VisualElement root) => _root = root;
|
||||
|
||||
/// <summary>기본 루트 요소 반환</summary>
|
||||
public static VisualElement? GetRoot() => _root;
|
||||
|
||||
/// <summary>
|
||||
/// 로딩 스피너 표시.
|
||||
/// 이미 표시 중이면 중복 생성하지 않고 기존 인스턴스를 반환합니다.
|
||||
/// </summary>
|
||||
/// <param name="speed">회전 속도 배율 (기본값 1.0)</param>
|
||||
public static UTKLoading Show(float speed = 1.0f)
|
||||
{
|
||||
ValidateRoot();
|
||||
|
||||
if (_activeInstance != null)
|
||||
return _activeInstance;
|
||||
|
||||
var loading = new UTKLoading
|
||||
{
|
||||
_speedDeg = DEFAULT_SPEED_DEG * Mathf.Max(0.1f, speed),
|
||||
_blocker = CreateBlocker(),
|
||||
};
|
||||
var visualTree = _root!.panel?.visualTree ?? _root!;
|
||||
visualTree.Add(loading._blocker);
|
||||
visualTree.Add(loading);
|
||||
|
||||
// 화면 중앙 고정
|
||||
loading.style.position = Position.Absolute;
|
||||
loading.style.left = Length.Percent(50);
|
||||
loading.style.top = Length.Percent(50);
|
||||
loading.style.translate = new Translate(Length.Percent(-50), Length.Percent(-50));
|
||||
|
||||
loading.StartAnimation();
|
||||
|
||||
_activeInstance = loading;
|
||||
return loading;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 로딩 스피너 숨기기 및 제거.
|
||||
/// </summary>
|
||||
public static void Hide()
|
||||
{
|
||||
if (_activeInstance == null) return;
|
||||
var instance = _activeInstance;
|
||||
_activeInstance = null;
|
||||
instance.Close();
|
||||
}
|
||||
|
||||
/// <summary>현재 로딩이 표시 중인지 여부</summary>
|
||||
public static bool IsShowing => _activeInstance != null;
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
/// <summary>이 인스턴스를 닫고 계층에서 제거합니다.</summary>
|
||||
public void Close()
|
||||
{
|
||||
StopAnimation();
|
||||
|
||||
if (_blocker is not null)
|
||||
{
|
||||
_blocker.RemoveFromHierarchy();
|
||||
_blocker = null;
|
||||
}
|
||||
|
||||
RemoveFromHierarchy();
|
||||
Dispose();
|
||||
|
||||
if (ReferenceEquals(_activeInstance, this))
|
||||
_activeInstance = null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Drawing
|
||||
/// <summary>
|
||||
/// Painter2D로 트랙 원과 로딩 호를 직접 그립니다.
|
||||
/// </summary>
|
||||
private void OnGenerateVisualContent(MeshGenerationContext ctx)
|
||||
{
|
||||
var painter = ctx.painter2D;
|
||||
var rect = contentRect;
|
||||
var center = new Vector2(rect.width * 0.5f, rect.height * 0.5f);
|
||||
float radius = Mathf.Min(rect.width, rect.height) * 0.5f - _thickness * 0.5f;
|
||||
|
||||
if (radius <= 0f) return;
|
||||
|
||||
// arc-color 미지정 시 OnCustomStyleResolved에서 캐싱된 테마 색상 사용
|
||||
var color = _arcColorOverride ?? _resolvedThemeColor;
|
||||
|
||||
// --- 로딩 호 ---
|
||||
// _cycleTime을 0~2π 한 사이클로 사용:
|
||||
// Phase 1 (0~π): head가 0→1로 달려나감, tail은 0 고정 → 호가 늘어남
|
||||
// Phase 2 (π~2π): head는 1 고정, tail이 0→1로 따라잡음 → 호가 줄어듦
|
||||
// 두 페이즈 경계(0, π, 2π)에서 arc length = 0 이 보장됨
|
||||
float cycle = _cycleTime; // 이미 0~2π 범위로 유지됨
|
||||
float headT, tailT;
|
||||
if (cycle < Mathf.PI)
|
||||
{
|
||||
// Phase 1: 호 늘어남
|
||||
headT = EaseInOut(cycle / Mathf.PI);
|
||||
tailT = 0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Phase 2: 호 줄어듦
|
||||
headT = 1f;
|
||||
tailT = EaseInOut((cycle - Mathf.PI) / Mathf.PI);
|
||||
}
|
||||
|
||||
float baseAngle = _rotation - 90f; // 12시 방향 기준 (도)
|
||||
float startRad = baseAngle + tailT * ARC_MAX_DEG;
|
||||
float endRad = baseAngle + headT * ARC_MAX_DEG;
|
||||
|
||||
painter.BeginPath();
|
||||
painter.Arc(center, radius, startRad, endRad);
|
||||
painter.strokeColor = color;
|
||||
painter.lineWidth = _thickness;
|
||||
painter.lineCap = LineCap.Round;
|
||||
painter.Stroke();
|
||||
}
|
||||
|
||||
// cubic ease-in-out: 0→0, 1→1, 가운데 S커브
|
||||
private static float EaseInOut(float t) => t * t * (3f - 2f * t);
|
||||
#endregion
|
||||
|
||||
#region Animation
|
||||
private void StartAnimation()
|
||||
{
|
||||
if (_isAnimating) return;
|
||||
|
||||
_isAnimating = true;
|
||||
_rotation = 0f;
|
||||
_cycleTime = 0f;
|
||||
|
||||
_animationSchedule = schedule
|
||||
.Execute(UpdateAnimation)
|
||||
.Every(UPDATE_INTERVAL_MS);
|
||||
}
|
||||
|
||||
private void StopAnimation()
|
||||
{
|
||||
if (!_isAnimating) return;
|
||||
|
||||
_isAnimating = false;
|
||||
_animationSchedule?.Pause();
|
||||
_animationSchedule = null;
|
||||
}
|
||||
|
||||
private void UpdateAnimation(TimerState timerState)
|
||||
{
|
||||
if (!_isAnimating) return;
|
||||
|
||||
// timerState.deltaTime: 이전 콜백 이후 실제 경과 시간 (ms, long) 16ms 나옴
|
||||
float deltaSeconds = timerState.deltaTime / 1000f;
|
||||
|
||||
// 회전 각도 누적 (도, 범위 제한 없이 누적해도 float 정밀도 안전)
|
||||
_rotation += _speedDeg * deltaSeconds;
|
||||
_cycleTime += ARC_CYCLE_SPEED * deltaSeconds;
|
||||
|
||||
// 오버플로우 방지
|
||||
if (_rotation > 360f * 1000f) _rotation -= 360f * 1000f;
|
||||
// _cycleTime은 0~2π 범위로 유지 (% 연산으로 순간 점프 방지)
|
||||
if (_cycleTime >= Mathf.PI * 2f) _cycleTime -= Mathf.PI * 2f;
|
||||
|
||||
// 다시 그리기 요청
|
||||
MarkDirtyRepaint();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Blocker
|
||||
private static VisualElement CreateBlocker()
|
||||
{
|
||||
var blocker = new VisualElement();
|
||||
blocker.style.position = Position.Absolute;
|
||||
blocker.style.left = 0;
|
||||
blocker.style.top = 0;
|
||||
blocker.style.right = 0;
|
||||
blocker.style.bottom = 0;
|
||||
blocker.style.backgroundColor = new Color(0, 0, 0, 0);
|
||||
|
||||
blocker.RegisterCallback<ClickEvent>(evt => evt.StopPropagation());
|
||||
blocker.RegisterCallback<PointerDownEvent>(evt => evt.StopPropagation());
|
||||
blocker.RegisterCallback<PointerUpEvent>(evt => evt.StopPropagation());
|
||||
|
||||
return blocker;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Theme
|
||||
private void OnCustomStyleResolved(CustomStyleResolvedEvent evt)
|
||||
{
|
||||
// --color-primary 값을 읽어 캐싱. arc-color 미지정 시 다음 프레임부터 반영됨
|
||||
if (evt.customStyle.TryGetValue(UTKStyleGuide.VarColorPrimary, out var color))
|
||||
_resolvedThemeColor = color;
|
||||
|
||||
if (_arcColorOverride == null)
|
||||
MarkDirtyRepaint();
|
||||
}
|
||||
|
||||
private void SubscribeToThemeChanges()
|
||||
{
|
||||
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
|
||||
RegisterCallback<AttachToPanelEvent>(OnAttachToPanel);
|
||||
RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanel);
|
||||
}
|
||||
|
||||
private void OnAttachToPanel(AttachToPanelEvent evt)
|
||||
{
|
||||
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
|
||||
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
|
||||
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
||||
|
||||
if (_autoPlay)
|
||||
StartAnimation();
|
||||
}
|
||||
|
||||
private void OnDetachFromPanel(DetachFromPanelEvent evt)
|
||||
{
|
||||
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
|
||||
StopAnimation();
|
||||
}
|
||||
|
||||
private void OnThemeChanged(UTKTheme theme)
|
||||
{
|
||||
// ApplyThemeToElement가 스타일시트를 교체하면
|
||||
// UI Toolkit이 CustomStyleResolvedEvent를 자동 발생 → OnCustomStyleResolved에서 색상 갱신
|
||||
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Static Helper
|
||||
private static void ValidateRoot()
|
||||
{
|
||||
if (_root == null)
|
||||
throw new InvalidOperationException(
|
||||
"UTKLoading.SetRoot()를 먼저 호출하여 기본 루트 요소를 설정해야 합니다.");
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
|
||||
StopAnimation();
|
||||
generateVisualContent -= OnGenerateVisualContent;
|
||||
|
||||
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
|
||||
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanel);
|
||||
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanel);
|
||||
UnregisterCallback<CustomStyleResolvedEvent>(OnCustomStyleResolved);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/UVC/UIToolkit/Modal/UTKLoading.cs.meta
Normal file
2
Assets/Scripts/UVC/UIToolkit/Modal/UTKLoading.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c5a3987766008cd40a03cb1c615f03a6
|
||||
@@ -34,6 +34,9 @@ namespace UVC.UIToolkit
|
||||
public static class UTKStyleGuide
|
||||
{
|
||||
#region USS Variable Names - for customStyle access
|
||||
// Primary Colors
|
||||
public static readonly CustomStyleProperty<Color> VarColorPrimary = new("--color-primary");
|
||||
|
||||
// Text Colors
|
||||
public static readonly CustomStyleProperty<Color> VarTextPrimary = new("--color-text-primary");
|
||||
public static readonly CustomStyleProperty<Color> VarTextSecondary = new("--color-text-secondary");
|
||||
|
||||
8
Assets/com.IvanMurzak.meta
Normal file
8
Assets/com.IvanMurzak.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cd76a1d460524d746bee1cf9a5a2151e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/com.IvanMurzak/AI Game Dev Installer.meta
Normal file
8
Assets/com.IvanMurzak/AI Game Dev Installer.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f9b8ea68f545b1442b81375cc40c1d22
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ Author: Ivan Murzak (https://github.com/IvanMurzak) │
|
||||
│ Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP) │
|
||||
│ Copyright (c) 2025 Ivan Murzak │
|
||||
│ Licensed under the Apache License, Version 2.0. │
|
||||
│ See the LICENSE file in the project root for more information. │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
*/
|
||||
#nullable enable
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using com.IvanMurzak.Unity.MCP.Installer.SimpleJSON;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("com.IvanMurzak.Unity.MCP.Installer.Tests")]
|
||||
namespace com.IvanMurzak.Unity.MCP.Installer
|
||||
{
|
||||
public static partial class Installer
|
||||
{
|
||||
static string ManifestPath => Path.Combine(Application.dataPath, "../Packages/manifest.json");
|
||||
|
||||
// Property names
|
||||
public const string Dependencies = "dependencies";
|
||||
public const string ScopedRegistries = "scopedRegistries";
|
||||
public const string Name = "name";
|
||||
public const string Url = "url";
|
||||
public const string Scopes = "scopes";
|
||||
|
||||
// Property values
|
||||
public const string RegistryName = "package.openupm.com";
|
||||
public const string RegistryUrl = "https://package.openupm.com";
|
||||
public static readonly string[] PackageIds = new string[] {
|
||||
"com.ivanmurzak", // Ivan Murzak's OpenUPM packages
|
||||
"extensions.unity", // Ivan Murzak's OpenUPM packages (older)
|
||||
"org.nuget.com.ivanmurzak", // Ivan Murzak's NuGet packages
|
||||
"org.nuget.microsoft", // Microsoft NuGet packages
|
||||
"org.nuget.system", // Microsoft NuGet packages
|
||||
"org.nuget.r3" // R3 package NuGet package
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the version should be updated. Only update if installer version is higher than current version.
|
||||
/// </summary>
|
||||
/// <param name="currentVersion">Current package version string</param>
|
||||
/// <param name="installerVersion">Installer version string</param>
|
||||
/// <returns>True if version should be updated (installer version is higher), false otherwise</returns>
|
||||
|
||||
internal static bool ShouldUpdateVersion(string currentVersion, string installerVersion)
|
||||
{
|
||||
if (string.IsNullOrEmpty(currentVersion))
|
||||
return true; // No current version, should install
|
||||
|
||||
if (string.IsNullOrEmpty(installerVersion))
|
||||
return false; // No installer version, don't change
|
||||
|
||||
try
|
||||
{
|
||||
// Try to parse as System.Version (semantic versioning)
|
||||
var current = new System.Version(currentVersion);
|
||||
var installer = new System.Version(installerVersion);
|
||||
|
||||
// Only update if installer version is higher than current version
|
||||
return installer > current;
|
||||
}
|
||||
catch (System.Exception)
|
||||
{
|
||||
Debug.LogWarning($"Failed to parse versions '{currentVersion}' or '{installerVersion}' as System.Version.");
|
||||
// If version parsing fails, fall back to string comparison
|
||||
// This ensures we don't break if version format is unexpected
|
||||
return string.Compare(installerVersion, currentVersion, System.StringComparison.OrdinalIgnoreCase) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddScopedRegistryIfNeeded(string manifestPath, int indent = 2)
|
||||
{
|
||||
if (!File.Exists(manifestPath))
|
||||
{
|
||||
Debug.LogError($"{manifestPath} not found!");
|
||||
return;
|
||||
}
|
||||
var jsonText = File.ReadAllText(manifestPath)
|
||||
.Replace("{ }", "{\n}")
|
||||
.Replace("{}", "{\n}")
|
||||
.Replace("[ ]", "[\n]")
|
||||
.Replace("[]", "[\n]");
|
||||
|
||||
var manifestJson = JSONObject.Parse(jsonText);
|
||||
if (manifestJson == null)
|
||||
{
|
||||
Debug.LogError($"Failed to parse {manifestPath} as JSON.");
|
||||
return;
|
||||
}
|
||||
|
||||
var modified = false;
|
||||
|
||||
// --- Add scoped registries if needed
|
||||
var scopedRegistries = manifestJson[ScopedRegistries];
|
||||
if (scopedRegistries == null)
|
||||
{
|
||||
manifestJson[ScopedRegistries] = new JSONArray();
|
||||
modified = true;
|
||||
}
|
||||
|
||||
// --- Add OpenUPM registry if needed
|
||||
var openUpmRegistry = scopedRegistries!.Linq
|
||||
.Select(kvp => kvp.Value)
|
||||
.Where(r => r.Linq
|
||||
.Any(p => p.Key == Name && p.Value == RegistryName))
|
||||
.FirstOrDefault();
|
||||
|
||||
if (openUpmRegistry == null)
|
||||
{
|
||||
scopedRegistries.Add(openUpmRegistry = new JSONObject
|
||||
{
|
||||
[Name] = RegistryName,
|
||||
[Url] = RegistryUrl,
|
||||
[Scopes] = new JSONArray()
|
||||
});
|
||||
modified = true;
|
||||
}
|
||||
|
||||
// --- Add missing scopes
|
||||
var scopes = openUpmRegistry[Scopes];
|
||||
if (scopes == null)
|
||||
{
|
||||
openUpmRegistry[Scopes] = scopes = new JSONArray();
|
||||
modified = true;
|
||||
}
|
||||
foreach (var packageId in PackageIds)
|
||||
{
|
||||
var existingScope = scopes!.Linq
|
||||
.Select(kvp => kvp.Value)
|
||||
.Where(value => value == packageId)
|
||||
.FirstOrDefault();
|
||||
if (existingScope == null)
|
||||
{
|
||||
scopes.Add(packageId);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Package Dependency (Version-aware installation)
|
||||
// Only update version if installer version is higher than current version
|
||||
// This prevents downgrades when users manually update to newer versions
|
||||
var dependencies = manifestJson[Dependencies];
|
||||
if (dependencies == null)
|
||||
{
|
||||
manifestJson[Dependencies] = dependencies = new JSONObject();
|
||||
modified = true;
|
||||
}
|
||||
|
||||
// Only update version if installer version is higher than current version
|
||||
var currentVersion = dependencies[PackageId];
|
||||
if (currentVersion == null || ShouldUpdateVersion(currentVersion, Version))
|
||||
{
|
||||
dependencies[PackageId] = Version;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
// --- Write changes back to manifest
|
||||
if (modified)
|
||||
File.WriteAllText(manifestPath, manifestJson.ToString(indent).Replace("\" : ", "\": "));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 888edfe7699cca7478a863e50be3566d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
28
Assets/com.IvanMurzak/AI Game Dev Installer/Installer.cs
Normal file
28
Assets/com.IvanMurzak/AI Game Dev Installer/Installer.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ Author: Ivan Murzak (https://github.com/IvanMurzak) │
|
||||
│ Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP) │
|
||||
│ Copyright (c) 2025 Ivan Murzak │
|
||||
│ Licensed under the Apache License, Version 2.0. │
|
||||
│ See the LICENSE file in the project root for more information. │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
*/
|
||||
#nullable enable
|
||||
using UnityEditor;
|
||||
|
||||
namespace com.IvanMurzak.Unity.MCP.Installer
|
||||
{
|
||||
[InitializeOnLoad]
|
||||
public static partial class Installer
|
||||
{
|
||||
public const string PackageId = "com.ivanmurzak.unity.mcp";
|
||||
public const string Version = "0.48.1";
|
||||
|
||||
static Installer()
|
||||
{
|
||||
#if !IVAN_MURZAK_INSTALLER_PROJECT
|
||||
AddScopedRegistryIfNeeded(ManifestPath);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b81812993f383a34a950af84d081945d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,27 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.IO;
|
||||
|
||||
namespace com.IvanMurzak.Unity.MCP.Installer
|
||||
{
|
||||
public static class PackageExporter
|
||||
{
|
||||
public static void ExportPackage()
|
||||
{
|
||||
var packagePath = "Assets/com.IvanMurzak/AI Game Dev Installer";
|
||||
var outputPath = "build/AI-Game-Dev-Installer.unitypackage";
|
||||
|
||||
// Ensure build directory exists
|
||||
var buildDir = Path.GetDirectoryName(outputPath);
|
||||
if (!Directory.Exists(buildDir))
|
||||
{
|
||||
Directory.CreateDirectory(buildDir);
|
||||
}
|
||||
|
||||
// Export the package
|
||||
AssetDatabase.ExportPackage(packagePath, outputPath, ExportPackageOptions.Recurse);
|
||||
|
||||
Debug.Log($"Package exported to: {outputPath}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b1b6d684272a1e24097921598fd2cd0e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
289
Assets/com.IvanMurzak/AI Game Dev Installer/README.md
Normal file
289
Assets/com.IvanMurzak/AI Game Dev Installer/README.md
Normal file
@@ -0,0 +1,289 @@
|
||||
<div align="center">
|
||||
<h1>✨ AI Game Developer — <i>Unity MCP</i></h1>
|
||||
|
||||
[](https://hub.docker.com/r/ivanmurzakdev/unity-mcp-server)
|
||||
[](https://modelcontextprotocol.io/introduction)
|
||||
[](https://github.com/IvanMurzak/Unity-MCP/actions/workflows/release.yml)
|
||||
[](https://u3d.as/3wsw)
|
||||
[](https://unity.com/releases/editor/archive)
|
||||
[](https://unity.com/releases/editor/archive)
|
||||
[](https://openupm.com/packages/com.ivanmurzak.unity.mcp/)</br>
|
||||
[](https://discord.gg/cfbdMZX99G)
|
||||
[](https://github.com/IvanMurzak/Unity-MCP/stargazers)
|
||||
[](https://github.com/IvanMurzak/Unity-MCP/blob/main/LICENSE)
|
||||
[](https://stand-with-ukraine.pp.ua)
|
||||
|
||||
AI helper which does wide range of tasks in Unity Editor and even in a running game compiled to any platform. It connects to AI using TCP connection, that is why it is so flexible.
|
||||
|
||||
💬 **Join our community:** [Discord Server](https://discord.gg/cfbdMZX99G) - Ask questions, showcase your work, and connect with other developers!
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
<details>
|
||||
<summary><b>Made with AI — samples (click to see)</b></summary>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="https://github.com/IvanMurzak/Unity-MCP/blob/main/docs/img/flying-orbs.gif" alt="Animation" title="Animation" /></td>
|
||||
<td><img src="https://github.com/IvanMurzak/Unity-MCP/blob/main/docs/img/golden-sphere.gif" alt="Animation" title="Animation" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://github.com/IvanMurzak/Unity-MCP/blob/main/docs/img/runner.gif" alt="Runner Game" title="Runner Game" /></td>
|
||||
<td><img src="https://github.com/IvanMurzak/Unity-MCP/blob/main/docs/img/procedural-terrain.gif" alt="Procedural Terrain" title="Procedural Terrain" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://github.com/IvanMurzak/Unity-MCP/blob/main/docs/img/create-material.gif" alt="Material creating" title="Material creating" /></td>
|
||||
<td><img src="https://github.com/IvanMurzak/Unity-MCP/blob/main/docs/img/playing-maze.gif" alt="Maze Game" title="Maze Game" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</details>
|
||||
|
||||
## Features for a human
|
||||
|
||||
- ✅ Chat with AI like with a human
|
||||
- ✅ Local and Remote usage supported
|
||||
- ✅ `stdio` and `streamableHttp` protocols supported
|
||||
- ✅ Wide range of default [AI tools](https://github.com/IvanMurzak/Unity-MCP/blob/main/docs/ai-tools.md)
|
||||
- ✅ Use `Description` attribute in C# code to provide detailed information for `class`, `field`, `property` or `method`.
|
||||
- ✅ Customizable reflection convertors, inspired by `System.Text.Json` convertors
|
||||
- do you have something extremely custom in your project? Make custom reflection convertor to let LLM be able to read and write into that data
|
||||
- ✅ Remote AI units setup using docker containers,
|
||||
- make a team of AI workers which work on your project simultaneously
|
||||
|
||||
## Features for LLM
|
||||
|
||||
- ✅ Agent ready tools, find anything you need in 1-2 steps
|
||||
- ✅ Instant C# code compilation & execution using `Roslyn`, iterate faster
|
||||
- ✅ Assets access (read / write), C# scripts access (read / write)
|
||||
- ✅ Well described positive and negative feedback for proper understanding of an issue
|
||||
- ✅ Provide references to existed objects for the instant C# code using `Reflection`
|
||||
- ✅ Get full access to entire project data in a readable shape using `Reflection`
|
||||
- ✅ Populate & Modify any granular piece of data in the project using `Reflection`
|
||||
- ✅ Find any `method` in the entire codebase, including compiled DLL files using `Reflection`
|
||||
- ✅ Call any `method` in the entire codebase using `Reflection`
|
||||
- ✅ Provide any property into `method` call, even if it is a reference to existed object in memory using `Reflection` and advanced reflection convertors
|
||||
- ✅ Unity API instantly available for usage, even if Unity changes something you will get fresh API using `Reflection`.
|
||||
- ✅ Get access to human readable description of any `class`, `method`, `field`, `property` by reading it's `Description` attribute.
|
||||
|
||||
### Stability status
|
||||
|
||||
| Unity Version | Editmode | Playmode | Standalone |
|
||||
| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| 2022.3.62f3 | [](https://github.com/IvanMurzak/Unity-MCP/actions/workflows/release.yml) | [](https://github.com/IvanMurzak/Unity-MCP/actions/workflows/release.yml) | [](https://github.com/IvanMurzak/Unity-MCP/actions/workflows/release.yml) |
|
||||
| 2023.2.22f1 | [](https://github.com/IvanMurzak/Unity-MCP/actions/workflows/release.yml) | [](https://github.com/IvanMurzak/Unity-MCP/actions/workflows/release.yml) | [](https://github.com/IvanMurzak/Unity-MCP/actions/workflows/release.yml) |
|
||||
| 6000.3.1f1 | [](https://github.com/IvanMurzak/Unity-MCP/actions/workflows/release.yml) | [](https://github.com/IvanMurzak/Unity-MCP/actions/workflows/release.yml) | [](https://github.com/IvanMurzak/Unity-MCP/actions/workflows/release.yml) |
|
||||
|
||||
## Requirements
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **Project path cannot contain spaces**
|
||||
>
|
||||
> - ✅ `C:/MyProjects/Project`
|
||||
> - ❌ `C:/My Projects/Project`
|
||||
|
||||
### Install `MCP Client`
|
||||
|
||||
Choose `MCP Client` you prefer, don't need to install all of them. This is will be your main chat window to talk with LLM.
|
||||
|
||||
- [Claude Code](https://github.com/anthropics/claude-code)
|
||||
- [Claude Desktop](https://claude.ai/download)
|
||||
- [GitHub Copilot in VS Code](https://code.visualstudio.com/docs/copilot/overview)
|
||||
- [Cursor](https://www.cursor.com/)
|
||||
- [Windsurf](https://windsurf.com)
|
||||
- Any other supported
|
||||
|
||||
> MCP protocol is quite universal, that is why you may any MCP client you prefer, it will work as smooth as anyone else. The only important thing, that the MCP client has to support dynamic tool update.
|
||||
|
||||
# Installation
|
||||
|
||||
## Step 1: Install `Unity Plugin`
|
||||
|
||||
- **[⬇️ Download Installer](https://github.com/IvanMurzak/Unity-MCP/releases/download/0.17.2/AI-Game-Dev-Installer.unitypackage)**
|
||||
- **📂 Import installer into Unity project**
|
||||
> - You may use double click on the file - Unity will open it
|
||||
> - OR: You may open Unity Editor first, then click on `Assets/Import Package/Custom Package`, then choose the file
|
||||
|
||||
<details>
|
||||
<summary><b>Alternative: Install <code>Unity Plugin</code> via OpenUPM</b></summary>
|
||||
|
||||
- [Install OpenUPM-CLI](https://github.com/openupm/openupm-cli#installation)
|
||||
- Open command line in Unity project folder
|
||||
- Run the command
|
||||
|
||||
```bash
|
||||
openupm add com.ivanmurzak.unity.mcp
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Step 2: Configure `MCP Client`
|
||||
|
||||
### Automatic configuration
|
||||
|
||||
- Open Unity project
|
||||
- Open `Window/AI Connector (Unity-MCP)`
|
||||
- Click `Configure` at your MCP client
|
||||
|
||||

|
||||
|
||||
> If MCP client is not in the list, use the raw JSON below in the window, to inject it into your MCP client. Read instructions for your MCP client how to do that.
|
||||
|
||||
### Manual configuration
|
||||
|
||||
If Automatic configuration doesn't work for you for any reason. Use JSON from `AI Connector (Unity-MCP)` window to configure any `MCP Client` on your own.
|
||||
|
||||
<details>
|
||||
<summary>Add Unity-MCP to <code>Claude Code</code> (Windows)</summary>
|
||||
|
||||
Replace `unityProjectPath` with your real project path
|
||||
|
||||
```bash
|
||||
claude mcp add Unity-MCP "<unityProjectPath>/Library/mcp-server/win-x64/unity-mcp-server.exe" client-transport=stdio
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Add Unity-MCP to <code>Claude Code</code> (MacOS Apple-Silicon)</summary>
|
||||
|
||||
Replace `unityProjectPath` with your real project path
|
||||
|
||||
```bash
|
||||
claude mcp add Unity-MCP "<unityProjectPath>/Library/mcp-server/osx-arm64/unity-mcp-server" client-transport=stdio
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Add Unity-MCP to <code>Claude Code</code> (MacOS Apple-Intel)</summary>
|
||||
|
||||
Replace `unityProjectPath` with your real project path
|
||||
|
||||
```bash
|
||||
claude mcp add Unity-MCP "<unityProjectPath>/Library/mcp-server/osx-x64/unity-mcp-server" client-transport=stdio
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Add Unity-MCP to <code>Claude Code</code> (Linux x64)</summary>
|
||||
|
||||
Replace `unityProjectPath` with your real project path
|
||||
|
||||
```bash
|
||||
claude mcp add Unity-MCP "<unityProjectPath>/Library/mcp-server/linux-x64/unity-mcp-server" client-transport=stdio
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Add Unity-MCP to <code>Claude Code</code> (Linux arm64)</summary>
|
||||
|
||||
Replace `unityProjectPath` with your real project path
|
||||
|
||||
```bash
|
||||
claude mcp add Unity-MCP "<unityProjectPath>/Library/mcp-server/linux-arm64/unity-mcp-server" client-transport=stdio
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
# Use AI
|
||||
|
||||
Talk with AI (LLM) in your `MCP Client`. Ask it to do anything you want. As better you describe your task / idea - as better it will do the job.
|
||||
|
||||
Some `MCP Clients` allow to chose different LLM models. Take an eye on it, some model may work much better.
|
||||
|
||||
```text
|
||||
Explain my scene hierarchy
|
||||
```
|
||||
|
||||
```text
|
||||
Create 3 cubes in a circle with radius 2
|
||||
```
|
||||
|
||||
```text
|
||||
Create metallic golden material and attach it to a sphere gameObject
|
||||
```
|
||||
|
||||
> Make sure `Agent` mode is turned on in MCP client
|
||||
|
||||
---
|
||||
|
||||
# How it works
|
||||
|
||||
**[Unity-MCP](https://github.com/IvanMurzak/Unity-MCP)** is a bridge between LLM and Unity. It exposes and explains to LLM Unity's tools. LLM understands the interface and utilizes the tools in the way a user asks.
|
||||
|
||||
Connect **[Unity-MCP](https://github.com/IvanMurzak/Unity-MCP)** to LLM client such as [Claude](https://claude.ai/download) or [Cursor](https://www.cursor.com/) using integrated `AI Connector` window. Custom clients are supported as well.
|
||||
|
||||
The project is designed to let developers to add custom tools soon. After that the next goal is to enable the same features in player's build. For not it works only in Unity Editor.
|
||||
|
||||
The system is extensible: you can define custom `tool`s directly in your Unity project codebase, exposing new capabilities to the AI or automation clients. This makes Unity-MCP a flexible foundation for building advanced workflows, rapid prototyping, or integrating AI-driven features into your development process.
|
||||
|
||||
---
|
||||
|
||||
# Advanced MCP server setup
|
||||
|
||||
Unity-MCP server supports many different launch options and docker docker deployment. Both transport protocol are supported `streamableHttp` and `stdio`. [Read more...](https://github.com/IvanMurzak/Unity-MCP/blob/main/docs/mcp-server.md)
|
||||
|
||||
# Add custom `tool`
|
||||
|
||||
> ⚠️ It only works with MCP client that supports dynamic tool list update.
|
||||
|
||||
Unity-MCP is designed to support custom `tool` development by project owner. MCP server takes data from Unity plugin and exposes it to a Client. So anyone in the MCP communication chain would receive the information about a new `tool`. Which LLM may decide to call at some point.
|
||||
|
||||
To add a custom `tool` you need:
|
||||
|
||||
1. To have a class with attribute `McpPluginToolType`.
|
||||
2. To have a method in the class with attribute `McpPluginTool`.
|
||||
3. [optional] Add `Description` attribute to each method argument to let LLM to understand it.
|
||||
4. [optional] Use `string? optional = null` properties with `?` and default value to mark them as `optional` for LLM.
|
||||
|
||||
> Take a look that the line `MainThread.Instance.Run(() =>` it allows to run the code in Main thread which is needed to interact with Unity API. If you don't need it and running the tool in background thread is fine for the tool, don't use Main thread for efficiency purpose.
|
||||
|
||||
```csharp
|
||||
[McpPluginToolType]
|
||||
public class Tool_GameObject
|
||||
{
|
||||
[McpPluginTool
|
||||
(
|
||||
"MyCustomTask",
|
||||
Title = "Create a new GameObject"
|
||||
)]
|
||||
[Description("Explain here to LLM what is this, when it should be called.")]
|
||||
public string CustomTask
|
||||
(
|
||||
[Description("Explain to LLM what is this.")]
|
||||
string inputData
|
||||
)
|
||||
{
|
||||
// do anything in background thread
|
||||
|
||||
return MainThread.Instance.Run(() =>
|
||||
{
|
||||
// do something in main thread if needed
|
||||
|
||||
return $"[Success] Operation completed.";
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Add custom in-game `tool`
|
||||
|
||||
> ⚠️ Not yet supported. The work is in progress
|
||||
|
||||
---
|
||||
|
||||
# Contribution 💙💛
|
||||
|
||||
Contribution is highly appreciated. Brings your ideas and lets make the game development as simple as never before! Do you have an idea of a new `tool`, feature or did you spot a bug and know how to fix it.
|
||||
|
||||
1. 👉 [Fork the project](https://github.com/IvanMurzak/Unity-MCP/fork)
|
||||
2. Clone the fork and open the `./Unity-MCP-Plugin` folder in Unity
|
||||
3. Implement new things in the project, commit, push it to GitHub
|
||||
4. Create Pull Request targeting original [Unity-MCP](https://github.com/IvanMurzak/Unity-MCP) repository, `main` branch.
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: badb67057628e444fb9ecfbf2246ad10
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1434
Assets/com.IvanMurzak/AI Game Dev Installer/SimpleJSON.cs
Normal file
1434
Assets/com.IvanMurzak/AI Game Dev Installer/SimpleJSON.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9fbdd5383371516498e4fd0ba51f3845
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/com.IvanMurzak/AI Game Dev Installer/Tests.meta
Normal file
8
Assets/com.IvanMurzak/AI Game Dev Installer/Tests.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 75e3d8b42387c80479161a91b0a310f8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a6babde583d2f114c9f1756e71e0ac7d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d82937626fc136e489d066690bcccd3d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"com.unity.ide.visualstudio": "2.0.23",
|
||||
"com.unity.test-framework": "1.1.33",
|
||||
"com.unity.toolchain.win-x86_64-linux-x86_64": "2.0.10",
|
||||
"org.nuget.microsoft.aspnetcore.signalr.client": "9.0.7",
|
||||
"org.nuget.microsoft.aspnetcore.signalr.protocols.json": "9.0.7",
|
||||
"org.nuget.microsoft.bcl.memory": "9.0.7",
|
||||
"org.nuget.microsoft.codeanalysis.csharp": "4.13.0",
|
||||
"org.nuget.microsoft.extensions.caching.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.dependencyinjection.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.hosting": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.hosting.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.logging.abstractions": "9.0.7",
|
||||
"org.nuget.r3": "1.3.0",
|
||||
"org.nuget.system.text.json": "9.0.7",
|
||||
"PACKAGE_ID": "PACKAGE_VERSION"
|
||||
},
|
||||
"scopedRegistries": [
|
||||
{
|
||||
"name": "package.openupm.com",
|
||||
"url": "https://package.openupm.com",
|
||||
"scopes": [
|
||||
"com.ivanmurzak",
|
||||
"extensions.unity",
|
||||
"org.nuget.com.ivanmurzak",
|
||||
"org.nuget.microsoft",
|
||||
"org.nuget.system",
|
||||
"org.nuget.r3"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3d5b79cfeddb2f04f8bb70ff73000dd7
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"com.unity.ide.visualstudio": "2.0.23",
|
||||
"com.unity.test-framework": "1.1.33",
|
||||
"com.unity.toolchain.win-x86_64-linux-x86_64": "2.0.10",
|
||||
"org.nuget.microsoft.aspnetcore.signalr.client": "9.0.7",
|
||||
"org.nuget.microsoft.aspnetcore.signalr.protocols.json": "9.0.7",
|
||||
"org.nuget.microsoft.bcl.memory": "9.0.7",
|
||||
"org.nuget.microsoft.codeanalysis.csharp": "4.13.0",
|
||||
"org.nuget.microsoft.extensions.caching.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.dependencyinjection.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.hosting": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.hosting.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.logging.abstractions": "9.0.7",
|
||||
"org.nuget.r3": "1.3.0",
|
||||
"org.nuget.system.text.json": "9.0.7",
|
||||
"PACKAGE_ID": "PACKAGE_VERSION"
|
||||
},
|
||||
"scopedRegistries": []
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 16c14e4a40eafcb418d9966639fefded
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"com.unity.ide.visualstudio": "2.0.23",
|
||||
"com.unity.test-framework": "1.1.33",
|
||||
"com.unity.toolchain.win-x86_64-linux-x86_64": "2.0.10",
|
||||
"org.nuget.microsoft.aspnetcore.signalr.client": "9.0.7",
|
||||
"org.nuget.microsoft.aspnetcore.signalr.protocols.json": "9.0.7",
|
||||
"org.nuget.microsoft.bcl.memory": "9.0.7",
|
||||
"org.nuget.microsoft.codeanalysis.csharp": "4.13.0",
|
||||
"org.nuget.microsoft.extensions.caching.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.dependencyinjection.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.hosting": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.hosting.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.logging.abstractions": "9.0.7",
|
||||
"org.nuget.r3": "1.3.0",
|
||||
"org.nuget.system.text.json": "9.0.7",
|
||||
"PACKAGE_ID": "PACKAGE_VERSION"
|
||||
},
|
||||
"scopedRegistries": []
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ddb8439b851dacf458f1c25cf9895ddc
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"com.unity.ide.visualstudio": "2.0.23",
|
||||
"com.unity.test-framework": "1.1.33",
|
||||
"com.unity.toolchain.win-x86_64-linux-x86_64": "2.0.10",
|
||||
"org.nuget.microsoft.aspnetcore.signalr.client": "9.0.7",
|
||||
"org.nuget.microsoft.aspnetcore.signalr.protocols.json": "9.0.7",
|
||||
"org.nuget.microsoft.bcl.memory": "9.0.7",
|
||||
"org.nuget.microsoft.codeanalysis.csharp": "4.13.0",
|
||||
"org.nuget.microsoft.extensions.caching.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.dependencyinjection.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.hosting": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.hosting.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.logging.abstractions": "9.0.7",
|
||||
"org.nuget.r3": "1.3.0",
|
||||
"org.nuget.system.text.json": "9.0.7",
|
||||
"PACKAGE_ID": "PACKAGE_VERSION"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0dc4a1c3c2fa1b141b5f60b9f16fd725
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"com.unity.ide.visualstudio": "2.0.23",
|
||||
"com.unity.test-framework": "1.1.33",
|
||||
"com.unity.toolchain.win-x86_64-linux-x86_64": "2.0.10",
|
||||
"org.nuget.microsoft.aspnetcore.signalr.client": "9.0.7",
|
||||
"org.nuget.microsoft.aspnetcore.signalr.protocols.json": "9.0.7",
|
||||
"org.nuget.microsoft.bcl.memory": "9.0.7",
|
||||
"org.nuget.microsoft.codeanalysis.csharp": "4.13.0",
|
||||
"org.nuget.microsoft.extensions.caching.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.dependencyinjection.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.hosting": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.hosting.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.logging.abstractions": "9.0.7",
|
||||
"org.nuget.r3": "1.3.0",
|
||||
"org.nuget.system.text.json": "9.0.7",
|
||||
"PACKAGE_ID": "PACKAGE_VERSION"
|
||||
},
|
||||
"scopedRegistries": [
|
||||
{
|
||||
"name": "package.openupm.com",
|
||||
"url": "https://package.openupm.com",
|
||||
"scopes": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 43ffd2c523a1fa643b984aeb51def7d9
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"com.unity.ide.visualstudio": "2.0.23",
|
||||
"com.unity.test-framework": "1.1.33",
|
||||
"com.unity.toolchain.win-x86_64-linux-x86_64": "2.0.10",
|
||||
"org.nuget.microsoft.aspnetcore.signalr.client": "9.0.7",
|
||||
"org.nuget.microsoft.aspnetcore.signalr.protocols.json": "9.0.7",
|
||||
"org.nuget.microsoft.bcl.memory": "9.0.7",
|
||||
"org.nuget.microsoft.codeanalysis.csharp": "4.13.0",
|
||||
"org.nuget.microsoft.extensions.caching.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.dependencyinjection.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.hosting": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.hosting.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.logging.abstractions": "9.0.7",
|
||||
"org.nuget.r3": "1.3.0",
|
||||
"org.nuget.system.text.json": "9.0.7",
|
||||
"PACKAGE_ID": "PACKAGE_VERSION"
|
||||
},
|
||||
"scopedRegistries": [
|
||||
{
|
||||
"name": "package.openupm.com",
|
||||
"url": "https://package.openupm.com"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 30d120107a842394eb6b6d35500b70c0
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"com.unity.ide.visualstudio": "2.0.23",
|
||||
"com.unity.test-framework": "1.1.33",
|
||||
"com.unity.toolchain.win-x86_64-linux-x86_64": "2.0.10",
|
||||
"org.nuget.microsoft.aspnetcore.signalr.client": "9.0.7",
|
||||
"org.nuget.microsoft.aspnetcore.signalr.protocols.json": "9.0.7",
|
||||
"org.nuget.microsoft.bcl.memory": "9.0.7",
|
||||
"org.nuget.microsoft.codeanalysis.csharp": "4.13.0",
|
||||
"org.nuget.microsoft.extensions.caching.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.dependencyinjection.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.hosting": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.hosting.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.logging.abstractions": "9.0.7",
|
||||
"org.nuget.r3": "1.3.0",
|
||||
"org.nuget.system.text.json": "9.0.7",
|
||||
"PACKAGE_ID": "PACKAGE_VERSION"
|
||||
},
|
||||
"scopedRegistries": [
|
||||
{
|
||||
"name": "package.openupm.com",
|
||||
"url": "https://package.openupm.com",
|
||||
"scopes": [
|
||||
"com.ivanmurzak",
|
||||
"extensions.unity",
|
||||
"org.nuget.com.ivanmurzak",
|
||||
"org.nuget.microsoft",
|
||||
"org.nuget.system"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 610ca5c6100bb9042937f4d5cf7c6160
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"com.unity.ide.visualstudio": "2.0.23",
|
||||
"com.unity.test-framework": "1.1.33",
|
||||
"com.unity.toolchain.win-x86_64-linux-x86_64": "2.0.10",
|
||||
"org.nuget.microsoft.aspnetcore.signalr.client": "9.0.7",
|
||||
"org.nuget.microsoft.aspnetcore.signalr.protocols.json": "9.0.7",
|
||||
"org.nuget.microsoft.bcl.memory": "9.0.7",
|
||||
"org.nuget.microsoft.codeanalysis.csharp": "4.13.0",
|
||||
"org.nuget.microsoft.extensions.caching.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.dependencyinjection.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.hosting": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.hosting.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.logging.abstractions": "9.0.7",
|
||||
"org.nuget.r3": "1.3.0",
|
||||
"org.nuget.system.text.json": "9.0.7",
|
||||
"PACKAGE_ID": "PACKAGE_VERSION"
|
||||
},
|
||||
"scopedRegistries": [
|
||||
{
|
||||
"name": "package.openupm.com",
|
||||
"url": "https://package.openupm.com",
|
||||
"scopes": [
|
||||
"com.ivanmurzak",
|
||||
"extensions.unity",
|
||||
"org.nuget.com.ivanmurzak",
|
||||
"org.nuget.microsoft"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9d0579095e1400946814f12371bae605
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"com.unity.ide.visualstudio": "2.0.23",
|
||||
"com.unity.test-framework": "1.1.33",
|
||||
"com.unity.toolchain.win-x86_64-linux-x86_64": "2.0.10",
|
||||
"org.nuget.microsoft.aspnetcore.signalr.client": "9.0.7",
|
||||
"org.nuget.microsoft.aspnetcore.signalr.protocols.json": "9.0.7",
|
||||
"org.nuget.microsoft.bcl.memory": "9.0.7",
|
||||
"org.nuget.microsoft.codeanalysis.csharp": "4.13.0",
|
||||
"org.nuget.microsoft.extensions.caching.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.dependencyinjection.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.hosting": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.hosting.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.logging.abstractions": "9.0.7",
|
||||
"org.nuget.r3": "1.3.0",
|
||||
"org.nuget.system.text.json": "9.0.7",
|
||||
"PACKAGE_ID": "PACKAGE_VERSION"
|
||||
},
|
||||
"scopedRegistries": [
|
||||
{
|
||||
"name": "package.openupm.com",
|
||||
"url": "https://package.openupm.com",
|
||||
"scopes": [
|
||||
"com.ivanmurzak",
|
||||
"extensions.unity",
|
||||
"org.nuget.com.ivanmurzak"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 69acf9fb81183764fabb07cae63a55a1
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"com.unity.ide.visualstudio": "2.0.23",
|
||||
"com.unity.test-framework": "1.1.33",
|
||||
"com.unity.toolchain.win-x86_64-linux-x86_64": "2.0.10",
|
||||
"org.nuget.microsoft.aspnetcore.signalr.client": "9.0.7",
|
||||
"org.nuget.microsoft.aspnetcore.signalr.protocols.json": "9.0.7",
|
||||
"org.nuget.microsoft.bcl.memory": "9.0.7",
|
||||
"org.nuget.microsoft.codeanalysis.csharp": "4.13.0",
|
||||
"org.nuget.microsoft.extensions.caching.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.dependencyinjection.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.hosting": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.hosting.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.logging.abstractions": "9.0.7",
|
||||
"org.nuget.r3": "1.3.0",
|
||||
"org.nuget.system.text.json": "9.0.7",
|
||||
"PACKAGE_ID": "PACKAGE_VERSION"
|
||||
},
|
||||
"scopedRegistries": [
|
||||
{
|
||||
"name": "package.openupm.com",
|
||||
"url": "https://package.openupm.com",
|
||||
"scopes": [
|
||||
"com.ivanmurzak",
|
||||
"extensions.unity"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ba3279b66694744399935ac96421b6f
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"com.unity.ide.visualstudio": "2.0.23",
|
||||
"com.unity.test-framework": "1.1.33",
|
||||
"com.unity.toolchain.win-x86_64-linux-x86_64": "2.0.10",
|
||||
"org.nuget.microsoft.aspnetcore.signalr.client": "9.0.7",
|
||||
"org.nuget.microsoft.aspnetcore.signalr.protocols.json": "9.0.7",
|
||||
"org.nuget.microsoft.bcl.memory": "9.0.7",
|
||||
"org.nuget.microsoft.codeanalysis.csharp": "4.13.0",
|
||||
"org.nuget.microsoft.extensions.caching.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.dependencyinjection.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.hosting": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.hosting.abstractions": "9.0.7",
|
||||
"org.nuget.microsoft.extensions.logging.abstractions": "9.0.7",
|
||||
"org.nuget.r3": "1.3.0",
|
||||
"org.nuget.system.text.json": "9.0.7",
|
||||
"PACKAGE_ID": "PACKAGE_VERSION"
|
||||
},
|
||||
"scopedRegistries": [
|
||||
{
|
||||
"name": "package.openupm.com",
|
||||
"url": "https://package.openupm.com",
|
||||
"scopes": [
|
||||
"com.ivanmurzak"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 112f17f3f25d40e469604e858090eacd
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ Author: Ivan Murzak (https://github.com/IvanMurzak) │
|
||||
│ Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP) │
|
||||
│ Copyright (c) 2025 Ivan Murzak │
|
||||
│ Licensed under the Apache License, Version 2.0. │
|
||||
│ See the LICENSE file in the project root for more information. │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
*/
|
||||
using System.IO;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
|
||||
namespace com.IvanMurzak.Unity.MCP.Installer.Tests
|
||||
{
|
||||
public class ManifestInstallerTests
|
||||
{
|
||||
const string PackageIdTag = "PACKAGE_ID";
|
||||
const string PackageVersionTag = "PACKAGE_VERSION";
|
||||
const string FilesRoot = "Assets/com.IvanMurzak/AI Game Dev Installer/Tests/Files";
|
||||
const string FilesCopyRoot = "Temp/com.IvanMurzak/AI Game Dev Installer/Tests/Files";
|
||||
static string CorrectManifestPath => $"{FilesRoot}/Correct/correct_manifest.json";
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
Debug.Log($"[{nameof(ManifestInstallerTests)}] SetUp");
|
||||
Directory.CreateDirectory(FilesCopyRoot);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
Debug.Log($"[{nameof(ManifestInstallerTests)}] TearDown");
|
||||
|
||||
// var files = Directory.GetFiles(FilesCopyRoot, "*.json", SearchOption.TopDirectoryOnly);
|
||||
// foreach (var file in files)
|
||||
// File.Delete(file);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void All()
|
||||
{
|
||||
var files = Directory.GetFiles(FilesRoot, "*.json", SearchOption.TopDirectoryOnly);
|
||||
var correctManifest = File.ReadAllText(CorrectManifestPath)
|
||||
.Replace(PackageVersionTag, Installer.Version)
|
||||
.Replace(PackageIdTag, Installer.PackageId);
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
Debug.Log($"Found JSON file: {file}");
|
||||
|
||||
// Copy the file
|
||||
var fileCopy = Path.Combine(FilesCopyRoot, Path.GetFileName(file));
|
||||
File.Copy(file, fileCopy, overwrite: true);
|
||||
|
||||
// Arrange
|
||||
File.WriteAllText(fileCopy, File.ReadAllText(fileCopy)
|
||||
.Replace(PackageVersionTag, Installer.Version)
|
||||
.Replace(PackageIdTag, Installer.PackageId));
|
||||
|
||||
// Act
|
||||
Installer.AddScopedRegistryIfNeeded(fileCopy);
|
||||
|
||||
// Assert
|
||||
var modifiedManifest = File.ReadAllText(fileCopy);
|
||||
Assert.AreEqual(correctManifest, modifiedManifest, $"Modified manifest from {file} does not match the correct manifest.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4f0df7dc33708f34ca0ab943a7176b3d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ Author: Ivan Murzak (https://github.com/IvanMurzak) │
|
||||
│ Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP) │
|
||||
│ Copyright (c) 2025 Ivan Murzak │
|
||||
│ Licensed under the Apache License, Version 2.0. │
|
||||
│ See the LICENSE file in the project root for more information. │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
*/
|
||||
using System.IO;
|
||||
using NUnit.Framework;
|
||||
using com.IvanMurzak.Unity.MCP.Installer.SimpleJSON;
|
||||
|
||||
namespace com.IvanMurzak.Unity.MCP.Installer.Tests
|
||||
{
|
||||
public class VersionComparisonTests
|
||||
{
|
||||
const string TestManifestPath = "Temp/com.IvanMurzak/Unity.MCP.Installer.Tests/test_manifest.json";
|
||||
const string PackageId = "com.ivanmurzak.unity.mcp";
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
var dir = Path.GetDirectoryName(TestManifestPath);
|
||||
if (!Directory.Exists(dir))
|
||||
Directory.CreateDirectory(dir);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
if (File.Exists(TestManifestPath))
|
||||
File.Delete(TestManifestPath);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShouldUpdateVersion_PatchVersionHigher_ReturnsTrue()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.IsTrue(
|
||||
condition: Installer.ShouldUpdateVersion(
|
||||
currentVersion: "1.5.1",
|
||||
installerVersion: "1.5.2"
|
||||
),
|
||||
message: "Should update when patch version is higher"
|
||||
);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShouldUpdateVersion_PatchVersionLower_ReturnsFalse()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.IsFalse(
|
||||
condition: Installer.ShouldUpdateVersion(
|
||||
currentVersion: "1.5.2",
|
||||
installerVersion: "1.5.1"
|
||||
),
|
||||
message: "Should not downgrade when patch version is lower"
|
||||
);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShouldUpdateVersion_MinorVersionHigher_ReturnsTrue()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.IsTrue(
|
||||
condition: Installer.ShouldUpdateVersion(
|
||||
currentVersion: "1.5.0",
|
||||
installerVersion: "1.6.0"
|
||||
),
|
||||
message: "Should update when minor version is higher"
|
||||
);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShouldUpdateVersion_MinorVersionLower_ReturnsFalse()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.IsFalse(
|
||||
condition: Installer.ShouldUpdateVersion(
|
||||
currentVersion: "1.6.0",
|
||||
installerVersion: "1.5.0"
|
||||
),
|
||||
message: "Should not downgrade when minor version is lower"
|
||||
);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShouldUpdateVersion_MajorVersionHigher_ReturnsTrue()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.IsTrue(
|
||||
condition: Installer.ShouldUpdateVersion(
|
||||
currentVersion: "1.5.0",
|
||||
installerVersion: "2.0.0"
|
||||
),
|
||||
message: "Should update when major version is higher"
|
||||
);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShouldUpdateVersion_MajorVersionLower_ReturnsFalse()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.IsFalse(
|
||||
condition: Installer.ShouldUpdateVersion(
|
||||
currentVersion: "2.0.0",
|
||||
installerVersion: "1.5.0"
|
||||
),
|
||||
message: "Should not downgrade when major version is lower"
|
||||
);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShouldUpdateVersion_SameVersion_ReturnsFalse()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.IsFalse(
|
||||
condition: Installer.ShouldUpdateVersion(
|
||||
currentVersion: "1.5.2",
|
||||
installerVersion: "1.5.2"
|
||||
),
|
||||
message: "Should not update when versions are the same"
|
||||
);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShouldUpdateVersion_EmptyCurrentVersion_ReturnsTrue()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.IsTrue(
|
||||
condition: Installer.ShouldUpdateVersion(
|
||||
currentVersion: "",
|
||||
installerVersion: "1.5.2"
|
||||
),
|
||||
message: "Should install when no current version exists"
|
||||
);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShouldUpdateVersion_NullCurrentVersion_ReturnsTrue()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.IsTrue(
|
||||
condition: Installer.ShouldUpdateVersion(
|
||||
currentVersion: null,
|
||||
installerVersion: "1.5.2"
|
||||
),
|
||||
message: "Should install when current version is null"
|
||||
);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddScopedRegistryIfNeeded_PreventVersionDowngrade_Integration()
|
||||
{
|
||||
// Arrange - Create manifest with higher version
|
||||
var versionParts = Installer.Version.Split('.');
|
||||
var majorVersion = int.Parse(versionParts[0]);
|
||||
var higherVersion = $"{majorVersion + 10}.0.0";
|
||||
var manifest = new JSONObject
|
||||
{
|
||||
[Installer.Dependencies] = new JSONObject
|
||||
{
|
||||
[PackageId] = higherVersion
|
||||
},
|
||||
[Installer.ScopedRegistries] = new JSONArray()
|
||||
};
|
||||
File.WriteAllText(TestManifestPath, manifest.ToString(2));
|
||||
|
||||
// Act - Run installer (should NOT downgrade)
|
||||
Installer.AddScopedRegistryIfNeeded(TestManifestPath);
|
||||
|
||||
// Assert - Version should remain unchanged
|
||||
var updatedContent = File.ReadAllText(TestManifestPath);
|
||||
var updatedManifest = JSONObject.Parse(updatedContent);
|
||||
var actualVersion = updatedManifest[Installer.Dependencies][PackageId];
|
||||
|
||||
Assert.AreEqual(higherVersion, actualVersion.ToString().Trim('"'),
|
||||
"Version should not be downgraded from higher version");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddScopedRegistryIfNeeded_AllowVersionUpgrade_Integration()
|
||||
{
|
||||
// Arrange - Create manifest with lower version (0.0.1 is always lower)
|
||||
var lowerVersion = "0.0.1";
|
||||
var manifest = new JSONObject
|
||||
{
|
||||
[Installer.Dependencies] = new JSONObject
|
||||
{
|
||||
[PackageId] = lowerVersion
|
||||
},
|
||||
[Installer.ScopedRegistries] = new JSONArray()
|
||||
};
|
||||
File.WriteAllText(TestManifestPath, manifest.ToString(2));
|
||||
|
||||
// Act - Run installer (should upgrade)
|
||||
Installer.AddScopedRegistryIfNeeded(TestManifestPath);
|
||||
|
||||
// Assert - Version should be upgraded to installer version
|
||||
var updatedContent = File.ReadAllText(TestManifestPath);
|
||||
var updatedManifest = JSONObject.Parse(updatedContent);
|
||||
var actualVersion = updatedManifest[Installer.Dependencies][PackageId];
|
||||
|
||||
Assert.AreEqual(Installer.Version, actualVersion.ToString().Trim('"'),
|
||||
"Version should be upgraded to installer version");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddScopedRegistryIfNeeded_NoExistingDependency_InstallsNewVersion()
|
||||
{
|
||||
// Arrange - Create manifest without the package
|
||||
var manifest = new JSONObject
|
||||
{
|
||||
[Installer.Dependencies] = new JSONObject(),
|
||||
[Installer.ScopedRegistries] = new JSONArray()
|
||||
};
|
||||
File.WriteAllText(TestManifestPath, manifest.ToString(2));
|
||||
|
||||
// Act - Run installer
|
||||
Installer.AddScopedRegistryIfNeeded(TestManifestPath);
|
||||
|
||||
// Assert - Package should be added with installer version
|
||||
var updatedContent = File.ReadAllText(TestManifestPath);
|
||||
var updatedManifest = JSONObject.Parse(updatedContent);
|
||||
var actualVersion = updatedManifest[Installer.Dependencies][PackageId];
|
||||
|
||||
Assert.AreEqual(Installer.Version, actualVersion.ToString().Trim('"'),
|
||||
"New package should be installed with installer version");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ece21aef0b677a246b2e4d410e769d3b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "com.IvanMurzak.Unity.MCP.Installer.Tests",
|
||||
"rootNamespace": "com.IvanMurzak.Unity.MCP.Installer.Tests",
|
||||
"references": [
|
||||
"com.IvanMurzak.Unity.MCP.Installer"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": true,
|
||||
"precompiledReferences": [
|
||||
"nunit.framework.dll"
|
||||
],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [
|
||||
"UNITY_INCLUDE_TESTS"
|
||||
],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 62688e1a637d08f4583b4de5fdce7fc4
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "com.IvanMurzak.Unity.MCP.Installer",
|
||||
"rootNamespace": "com.IvanMurzak.Unity.MCP.Installer",
|
||||
"references": [],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ba51295843cc38b4ab50bce94c164333
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"com.coplaydev.unity-mcp": "https://github.com/CoplayDev/unity-mcp.git?path=/MCPForUnity",
|
||||
"com.cysharp.unitask": "https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask",
|
||||
"com.github-glitchenzo.nugetforunity": "https://github.com/GlitchEnzo/NuGetForUnity.git?path=/src/NuGetForUnity",
|
||||
"com.unity.2d.sprite": "1.0.0",
|
||||
@@ -48,6 +47,21 @@
|
||||
"com.unity.modules.video": "1.0.0",
|
||||
"com.unity.modules.vr": "1.0.0",
|
||||
"com.unity.modules.wind": "1.0.0",
|
||||
"com.unity.modules.xr": "1.0.0"
|
||||
}
|
||||
}
|
||||
"com.unity.modules.xr": "1.0.0",
|
||||
"com.ivanmurzak.unity.mcp": "0.48.1"
|
||||
},
|
||||
"scopedRegistries": [
|
||||
{
|
||||
"name": "package.openupm.com",
|
||||
"url": "https://package.openupm.com",
|
||||
"scopes": [
|
||||
"com.ivanmurzak",
|
||||
"extensions.unity",
|
||||
"org.nuget.com.ivanmurzak",
|
||||
"org.nuget.microsoft",
|
||||
"org.nuget.system",
|
||||
"org.nuget.r3"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,15 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"com.coplaydev.unity-mcp": {
|
||||
"version": "https://github.com/CoplayDev/unity-mcp.git?path=/MCPForUnity",
|
||||
"depth": 0,
|
||||
"source": "git",
|
||||
"dependencies": {
|
||||
"com.unity.nuget.newtonsoft-json": "3.0.2",
|
||||
"com.unity.test-framework": "1.1.31"
|
||||
},
|
||||
"hash": "12dd9bd516aba822a9206209880a0b650f60ccfa"
|
||||
},
|
||||
"com.cysharp.unitask": {
|
||||
"version": "https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask",
|
||||
"depth": 0,
|
||||
@@ -24,6 +14,28 @@
|
||||
"dependencies": {},
|
||||
"hash": "a7c6b49a0141a5bff9b1983e38137522ef61977d"
|
||||
},
|
||||
"com.ivanmurzak.unity.mcp": {
|
||||
"version": "0.48.1",
|
||||
"depth": 0,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"com.unity.modules.uielements": "1.0.0",
|
||||
"com.unity.test-framework": "1.1.33",
|
||||
"extensions.unity.playerprefsex": "2.1.2",
|
||||
"org.nuget.microsoft.aspnetcore.signalr.client": "10.0.3",
|
||||
"org.nuget.microsoft.aspnetcore.signalr.protocols.json": "10.0.3",
|
||||
"org.nuget.microsoft.bcl.memory": "10.0.3",
|
||||
"org.nuget.microsoft.codeanalysis.csharp": "4.14.0",
|
||||
"org.nuget.microsoft.extensions.caching.abstractions": "10.0.3",
|
||||
"org.nuget.microsoft.extensions.dependencyinjection.abstractions": "10.0.3",
|
||||
"org.nuget.microsoft.extensions.hosting.abstractions": "10.0.3",
|
||||
"org.nuget.microsoft.extensions.logging": "10.0.3",
|
||||
"org.nuget.microsoft.extensions.logging.abstractions": "10.0.3",
|
||||
"org.nuget.r3": "1.3.0",
|
||||
"org.nuget.system.text.json": "10.0.3"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"com.unity.2d.sprite": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
@@ -247,6 +259,450 @@
|
||||
},
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"extensions.unity.playerprefsex": {
|
||||
"version": "2.1.2",
|
||||
"depth": 1,
|
||||
"source": "registry",
|
||||
"dependencies": {},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.microsoft.aspnetcore.connections.abstractions": {
|
||||
"version": "10.0.3",
|
||||
"depth": 3,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.microsoft.extensions.features": "10.0.3",
|
||||
"org.nuget.microsoft.bcl.asyncinterfaces": "10.0.3",
|
||||
"org.nuget.system.io.pipelines": "10.0.3"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.microsoft.aspnetcore.http.connections.client": {
|
||||
"version": "10.0.3",
|
||||
"depth": 2,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.microsoft.aspnetcore.http.connections.common": "10.0.3",
|
||||
"org.nuget.microsoft.extensions.logging.abstractions": "10.0.3",
|
||||
"org.nuget.microsoft.extensions.options": "10.0.3",
|
||||
"org.nuget.system.net.serversentevents": "10.0.3"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.microsoft.aspnetcore.http.connections.common": {
|
||||
"version": "10.0.3",
|
||||
"depth": 3,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.microsoft.aspnetcore.connections.abstractions": "10.0.3",
|
||||
"org.nuget.system.text.json": "10.0.3"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.microsoft.aspnetcore.signalr.client": {
|
||||
"version": "10.0.3",
|
||||
"depth": 1,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.microsoft.aspnetcore.signalr.client.core": "10.0.3",
|
||||
"org.nuget.microsoft.aspnetcore.http.connections.client": "10.0.3"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.microsoft.aspnetcore.signalr.client.core": {
|
||||
"version": "10.0.3",
|
||||
"depth": 2,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.microsoft.aspnetcore.signalr.protocols.json": "10.0.3",
|
||||
"org.nuget.microsoft.aspnetcore.signalr.common": "10.0.3",
|
||||
"org.nuget.microsoft.bcl.timeprovider": "10.0.3",
|
||||
"org.nuget.microsoft.extensions.dependencyinjection": "10.0.3",
|
||||
"org.nuget.microsoft.extensions.logging": "10.0.3",
|
||||
"org.nuget.system.threading.channels": "10.0.3"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.microsoft.aspnetcore.signalr.common": {
|
||||
"version": "10.0.3",
|
||||
"depth": 2,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.microsoft.aspnetcore.connections.abstractions": "10.0.3",
|
||||
"org.nuget.microsoft.extensions.options": "10.0.3",
|
||||
"org.nuget.system.text.json": "10.0.3"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.microsoft.aspnetcore.signalr.protocols.json": {
|
||||
"version": "10.0.3",
|
||||
"depth": 1,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.microsoft.aspnetcore.signalr.common": "10.0.3"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.microsoft.bcl.asyncinterfaces": {
|
||||
"version": "10.0.3",
|
||||
"depth": 2,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.system.threading.tasks.extensions": "4.6.3"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.microsoft.bcl.memory": {
|
||||
"version": "10.0.3",
|
||||
"depth": 1,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.system.memory": "4.6.3",
|
||||
"org.nuget.system.runtime.compilerservices.unsafe": "6.1.2"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.microsoft.bcl.timeprovider": {
|
||||
"version": "10.0.3",
|
||||
"depth": 3,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.microsoft.bcl.asyncinterfaces": "10.0.3"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.microsoft.codeanalysis.analyzers": {
|
||||
"version": "3.11.0",
|
||||
"depth": 2,
|
||||
"source": "registry",
|
||||
"dependencies": {},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.microsoft.codeanalysis.common": {
|
||||
"version": "4.14.0",
|
||||
"depth": 2,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.microsoft.codeanalysis.analyzers": "3.11.0",
|
||||
"org.nuget.system.collections.immutable": "9.0.0",
|
||||
"org.nuget.system.memory": "4.5.5",
|
||||
"org.nuget.system.reflection.metadata": "9.0.0",
|
||||
"org.nuget.system.runtime.compilerservices.unsafe": "6.0.0",
|
||||
"org.nuget.system.text.encoding.codepages": "7.0.0",
|
||||
"org.nuget.system.threading.tasks.extensions": "4.5.4",
|
||||
"org.nuget.system.buffers": "4.5.1",
|
||||
"org.nuget.system.numerics.vectors": "4.5.0"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.microsoft.codeanalysis.csharp": {
|
||||
"version": "4.14.0",
|
||||
"depth": 1,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.microsoft.codeanalysis.common": "4.14.0",
|
||||
"org.nuget.microsoft.codeanalysis.analyzers": "3.11.0",
|
||||
"org.nuget.system.buffers": "4.5.1",
|
||||
"org.nuget.system.collections.immutable": "9.0.0",
|
||||
"org.nuget.system.memory": "4.5.5",
|
||||
"org.nuget.system.numerics.vectors": "4.5.0",
|
||||
"org.nuget.system.reflection.metadata": "9.0.0",
|
||||
"org.nuget.system.runtime.compilerservices.unsafe": "6.0.0",
|
||||
"org.nuget.system.text.encoding.codepages": "7.0.0",
|
||||
"org.nuget.system.threading.tasks.extensions": "4.5.4"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.microsoft.extensions.caching.abstractions": {
|
||||
"version": "10.0.3",
|
||||
"depth": 1,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.microsoft.extensions.primitives": "10.0.3",
|
||||
"org.nuget.system.threading.tasks.extensions": "4.6.3"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.microsoft.extensions.configuration.abstractions": {
|
||||
"version": "10.0.3",
|
||||
"depth": 2,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.microsoft.extensions.primitives": "10.0.3"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.microsoft.extensions.dependencyinjection": {
|
||||
"version": "10.0.3",
|
||||
"depth": 2,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.microsoft.bcl.asyncinterfaces": "10.0.3",
|
||||
"org.nuget.microsoft.extensions.dependencyinjection.abstractions": "10.0.3",
|
||||
"org.nuget.system.threading.tasks.extensions": "4.6.3"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.microsoft.extensions.dependencyinjection.abstractions": {
|
||||
"version": "10.0.3",
|
||||
"depth": 1,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.microsoft.bcl.asyncinterfaces": "10.0.3",
|
||||
"org.nuget.system.threading.tasks.extensions": "4.6.3"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.microsoft.extensions.diagnostics.abstractions": {
|
||||
"version": "10.0.3",
|
||||
"depth": 2,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.microsoft.extensions.dependencyinjection.abstractions": "10.0.3",
|
||||
"org.nuget.microsoft.extensions.options": "10.0.3",
|
||||
"org.nuget.system.diagnostics.diagnosticsource": "10.0.3",
|
||||
"org.nuget.system.buffers": "4.6.1",
|
||||
"org.nuget.system.memory": "4.6.3"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.microsoft.extensions.features": {
|
||||
"version": "10.0.3",
|
||||
"depth": 4,
|
||||
"source": "registry",
|
||||
"dependencies": {},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.microsoft.extensions.fileproviders.abstractions": {
|
||||
"version": "10.0.3",
|
||||
"depth": 2,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.microsoft.extensions.primitives": "10.0.3"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.microsoft.extensions.hosting.abstractions": {
|
||||
"version": "10.0.3",
|
||||
"depth": 1,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.microsoft.bcl.asyncinterfaces": "10.0.3",
|
||||
"org.nuget.microsoft.extensions.configuration.abstractions": "10.0.3",
|
||||
"org.nuget.microsoft.extensions.dependencyinjection.abstractions": "10.0.3",
|
||||
"org.nuget.microsoft.extensions.diagnostics.abstractions": "10.0.3",
|
||||
"org.nuget.microsoft.extensions.fileproviders.abstractions": "10.0.3",
|
||||
"org.nuget.microsoft.extensions.logging.abstractions": "10.0.3",
|
||||
"org.nuget.system.threading.tasks.extensions": "4.6.3"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.microsoft.extensions.logging": {
|
||||
"version": "10.0.3",
|
||||
"depth": 1,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.microsoft.bcl.asyncinterfaces": "10.0.3",
|
||||
"org.nuget.microsoft.extensions.dependencyinjection": "10.0.3",
|
||||
"org.nuget.microsoft.extensions.logging.abstractions": "10.0.3",
|
||||
"org.nuget.microsoft.extensions.options": "10.0.3",
|
||||
"org.nuget.system.diagnostics.diagnosticsource": "10.0.3"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.microsoft.extensions.logging.abstractions": {
|
||||
"version": "10.0.3",
|
||||
"depth": 1,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.microsoft.extensions.dependencyinjection.abstractions": "10.0.3",
|
||||
"org.nuget.system.diagnostics.diagnosticsource": "10.0.3",
|
||||
"org.nuget.system.buffers": "4.6.1",
|
||||
"org.nuget.system.memory": "4.6.3"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.microsoft.extensions.options": {
|
||||
"version": "10.0.3",
|
||||
"depth": 2,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.microsoft.extensions.dependencyinjection.abstractions": "10.0.3",
|
||||
"org.nuget.microsoft.extensions.primitives": "10.0.3",
|
||||
"org.nuget.system.componentmodel.annotations": "5.0.0"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.microsoft.extensions.primitives": {
|
||||
"version": "10.0.3",
|
||||
"depth": 2,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.system.memory": "4.6.3",
|
||||
"org.nuget.system.runtime.compilerservices.unsafe": "6.1.2"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.r3": {
|
||||
"version": "1.3.0",
|
||||
"depth": 1,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.microsoft.bcl.timeprovider": "8.0.0",
|
||||
"org.nuget.system.buffers": "4.5.1",
|
||||
"org.nuget.system.componentmodel.annotations": "5.0.0",
|
||||
"org.nuget.system.memory": "4.5.5",
|
||||
"org.nuget.system.runtime.compilerservices.unsafe": "6.0.0",
|
||||
"org.nuget.system.threading.channels": "8.0.0"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.system.buffers": {
|
||||
"version": "4.6.1",
|
||||
"depth": 2,
|
||||
"source": "registry",
|
||||
"dependencies": {},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.system.collections.immutable": {
|
||||
"version": "9.0.0",
|
||||
"depth": 2,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.system.memory": "4.5.5",
|
||||
"org.nuget.system.runtime.compilerservices.unsafe": "6.0.0"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.system.componentmodel.annotations": {
|
||||
"version": "5.0.0",
|
||||
"depth": 2,
|
||||
"source": "registry",
|
||||
"dependencies": {},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.system.diagnostics.diagnosticsource": {
|
||||
"version": "10.0.3",
|
||||
"depth": 2,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.system.memory": "4.6.3",
|
||||
"org.nuget.system.runtime.compilerservices.unsafe": "6.1.2"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.system.io.pipelines": {
|
||||
"version": "10.0.3",
|
||||
"depth": 2,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.system.buffers": "4.6.1",
|
||||
"org.nuget.system.memory": "4.6.3",
|
||||
"org.nuget.system.threading.tasks.extensions": "4.6.3"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.system.memory": {
|
||||
"version": "4.6.3",
|
||||
"depth": 2,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.system.buffers": "4.6.1",
|
||||
"org.nuget.system.numerics.vectors": "4.6.1",
|
||||
"org.nuget.system.runtime.compilerservices.unsafe": "6.1.2"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.system.net.serversentevents": {
|
||||
"version": "10.0.3",
|
||||
"depth": 3,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.microsoft.bcl.asyncinterfaces": "10.0.3",
|
||||
"org.nuget.system.memory": "4.6.3",
|
||||
"org.nuget.system.threading.tasks.extensions": "4.6.3"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.system.numerics.vectors": {
|
||||
"version": "4.6.1",
|
||||
"depth": 3,
|
||||
"source": "registry",
|
||||
"dependencies": {},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.system.reflection.metadata": {
|
||||
"version": "9.0.0",
|
||||
"depth": 2,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.system.collections.immutable": "9.0.0",
|
||||
"org.nuget.system.memory": "4.5.5"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.system.runtime.compilerservices.unsafe": {
|
||||
"version": "6.1.2",
|
||||
"depth": 2,
|
||||
"source": "registry",
|
||||
"dependencies": {},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.system.text.encoding.codepages": {
|
||||
"version": "7.0.0",
|
||||
"depth": 2,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.system.memory": "4.5.5",
|
||||
"org.nuget.system.runtime.compilerservices.unsafe": "6.0.0"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.system.text.encodings.web": {
|
||||
"version": "10.0.3",
|
||||
"depth": 2,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.system.buffers": "4.6.1",
|
||||
"org.nuget.system.memory": "4.6.3",
|
||||
"org.nuget.system.runtime.compilerservices.unsafe": "6.1.2"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.system.text.json": {
|
||||
"version": "10.0.3",
|
||||
"depth": 1,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.microsoft.bcl.asyncinterfaces": "10.0.3",
|
||||
"org.nuget.system.io.pipelines": "10.0.3",
|
||||
"org.nuget.system.text.encodings.web": "10.0.3",
|
||||
"org.nuget.system.buffers": "4.6.1",
|
||||
"org.nuget.system.memory": "4.6.3",
|
||||
"org.nuget.system.runtime.compilerservices.unsafe": "6.1.2",
|
||||
"org.nuget.system.threading.tasks.extensions": "4.6.3"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.system.threading.channels": {
|
||||
"version": "10.0.3",
|
||||
"depth": 3,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.microsoft.bcl.asyncinterfaces": "10.0.3",
|
||||
"org.nuget.system.threading.tasks.extensions": "4.6.3"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"org.nuget.system.threading.tasks.extensions": {
|
||||
"version": "4.6.3",
|
||||
"depth": 2,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"org.nuget.system.runtime.compilerservices.unsafe": "6.1.2"
|
||||
},
|
||||
"url": "https://package.openupm.com"
|
||||
},
|
||||
"com.unity.modules.accessibility": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
|
||||
@@ -12,11 +12,13 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_EnablePreviewPackages: 0
|
||||
m_EnablePackageDependencies: 0
|
||||
m_EnablePreReleasePackages: 0
|
||||
m_AdvancedSettingsExpanded: 1
|
||||
m_ScopedRegistriesSettingsExpanded: 1
|
||||
m_SeeAllPackageVersions: 0
|
||||
m_DismissPreviewPackagesInUse: 0
|
||||
oneTimeWarningShown: 0
|
||||
oneTimeDeprecatedPopUpShown: 0
|
||||
m_Registries:
|
||||
- m_Id: main
|
||||
m_Name:
|
||||
@@ -24,20 +26,31 @@ MonoBehaviour:
|
||||
m_Scopes: []
|
||||
m_IsDefault: 1
|
||||
m_Capabilities: 7
|
||||
m_UserSelectedRegistryName:
|
||||
m_ConfigSource: 0
|
||||
m_Compliance:
|
||||
m_Status: 0
|
||||
m_Violations: []
|
||||
- m_Id: scoped:project:package.openupm.com
|
||||
m_Name: package.openupm.com
|
||||
m_Url: https://package.openupm.com
|
||||
m_Scopes:
|
||||
- com.ivanmurzak
|
||||
- extensions.unity
|
||||
- org.nuget.com.ivanmurzak
|
||||
- org.nuget.microsoft
|
||||
- org.nuget.system
|
||||
- org.nuget.r3
|
||||
m_IsDefault: 0
|
||||
m_Capabilities: 0
|
||||
m_ConfigSource: 4
|
||||
m_Compliance:
|
||||
m_Status: 0
|
||||
m_Violations: []
|
||||
m_UserSelectedRegistryName: package.openupm.com
|
||||
m_UserAddingNewScopedRegistry: 0
|
||||
m_RegistryInfoDraft:
|
||||
m_ErrorMessage:
|
||||
m_Original:
|
||||
m_Id:
|
||||
m_Name:
|
||||
m_Url:
|
||||
m_Scopes: []
|
||||
m_IsDefault: 0
|
||||
m_Capabilities: 0
|
||||
m_Modified: 0
|
||||
m_Name:
|
||||
m_Url:
|
||||
m_Scopes:
|
||||
-
|
||||
m_SelectedScopeIndex: 0
|
||||
m_ErrorMessage:
|
||||
m_UserModificationsInstanceId: -868
|
||||
m_OriginalInstanceId: -870
|
||||
m_LoadAssets: 0
|
||||
|
||||
@@ -9,10 +9,12 @@
|
||||
<Project Path="AssetUsageDetector.Editor.csproj" />
|
||||
<Project Path="com.Tivadar.Best.WebSockets.csproj" />
|
||||
<Project Path="EPODemo.csproj" />
|
||||
<Project Path="com.IvanMurzak.Unity.MCP.Installer.Tests.csproj" />
|
||||
<Project Path="Assembly-CSharp-firstpass.csproj" />
|
||||
<Project Path="EPOUtilities.csproj" />
|
||||
<Project Path="EPOEditor.csproj" />
|
||||
<Project Path="SimpleFileBrowser.Runtime.csproj" />
|
||||
<Project Path="com.IvanMurzak.Unity.MCP.Installer.csproj" />
|
||||
<Project Path="Assembly-CSharp-Editor-firstpass.csproj" />
|
||||
<Project Path="com.Tivadar.Best.HTTP.Profiler.Editor.csproj" />
|
||||
<Project Path="EPOURP.csproj" />
|
||||
|
||||
Reference in New Issue
Block a user