Compare commits
8 Commits
3c44aaf2bd
...
3612d00cdc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3612d00cdc | ||
|
|
074b213270 | ||
|
|
27b751fd40 | ||
|
|
da4f1caaa7 | ||
|
|
7d9947e5f0 | ||
|
|
aeb6236f5c | ||
|
|
7921b95a29 | ||
|
|
92ae70ff61 |
4
.gitignore
vendored
4
.gitignore
vendored
@ -32,3 +32,7 @@ sysinfo.txt
|
||||
|
||||
Assets/Plugins.meta
|
||||
Assets/Plugins/**
|
||||
|
||||
.venv
|
||||
AGENTS.md
|
||||
.python-version
|
||||
|
||||
8
Assets/# Prototype/World.meta
Normal file
8
Assets/# Prototype/World.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be54b69524c434f888d7c380a558ccee
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
613
Assets/# Prototype/World/JGraph.asset
Normal file
613
Assets/# Prototype/World/JGraph.asset
Normal file
@ -0,0 +1,613 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fcb661d795ed4088af4ae73e4253f98b, type: 3}
|
||||
m_Name: JGraph
|
||||
m_EditorClassIdentifier: Assembly-CSharp::Intrepid.Gameplay.Journey.JGraphSO
|
||||
sourceWorldLayoutId: 858671c3949e4543b0d68818c9b2e41b
|
||||
publishedAt: 2026-06-20T07:40:11.0297990Z
|
||||
schemaVersion: 1
|
||||
contentHash: 0c6d1b68e944d050c332427770faa770e77fac44b9fc92372e5b1487ff21331c
|
||||
stages:
|
||||
- id: stage_9202fe485eaa408d86e379b3fdafa49b
|
||||
displayName: Stage 1
|
||||
worldLayer: 0
|
||||
occupiedTiles: []
|
||||
tags: []
|
||||
- id: stage_25e8797ce5d9420b97aaf3e06f760b1d
|
||||
displayName: Stage 2
|
||||
worldLayer: 0
|
||||
occupiedTiles: []
|
||||
tags: []
|
||||
- id: stage_f5a0fa8cc3a14a94b8b6fa80c4e2413d
|
||||
displayName: Stage 3
|
||||
worldLayer: 0
|
||||
occupiedTiles:
|
||||
- x: 8
|
||||
y: 8
|
||||
- x: 9
|
||||
y: 8
|
||||
- x: 10
|
||||
y: 8
|
||||
- x: 11
|
||||
y: 8
|
||||
- x: 12
|
||||
y: 8
|
||||
- x: 8
|
||||
y: 9
|
||||
- x: 9
|
||||
y: 9
|
||||
- x: 10
|
||||
y: 9
|
||||
- x: 11
|
||||
y: 9
|
||||
- x: 12
|
||||
y: 9
|
||||
- x: 8
|
||||
y: 10
|
||||
- x: 9
|
||||
y: 10
|
||||
- x: 10
|
||||
y: 10
|
||||
- x: 11
|
||||
y: 10
|
||||
- x: 12
|
||||
y: 10
|
||||
- x: 8
|
||||
y: 11
|
||||
- x: 9
|
||||
y: 11
|
||||
- x: 10
|
||||
y: 11
|
||||
- x: 11
|
||||
y: 11
|
||||
- x: 12
|
||||
y: 11
|
||||
- x: 8
|
||||
y: 12
|
||||
- x: 9
|
||||
y: 12
|
||||
- x: 10
|
||||
y: 12
|
||||
- x: 11
|
||||
y: 12
|
||||
- x: 12
|
||||
y: 12
|
||||
- x: 13
|
||||
y: 9
|
||||
- x: 13
|
||||
y: 10
|
||||
- x: 13
|
||||
y: 11
|
||||
- x: 13
|
||||
y: 12
|
||||
- x: 8
|
||||
y: 7
|
||||
- x: 9
|
||||
y: 7
|
||||
- x: 10
|
||||
y: 7
|
||||
- x: 11
|
||||
y: 7
|
||||
- x: 7
|
||||
y: 7
|
||||
- x: 7
|
||||
y: 8
|
||||
- x: 7
|
||||
y: 9
|
||||
- x: 7
|
||||
y: 10
|
||||
tags: []
|
||||
- id: stage_92bb328658e04aceb915822ac7ff20ae
|
||||
displayName: Stage 4
|
||||
worldLayer: 0
|
||||
occupiedTiles: []
|
||||
tags: []
|
||||
- id: stage_aae8c48d41d84a679c9c52acd567ff30
|
||||
displayName: Stage 5
|
||||
worldLayer: 0
|
||||
occupiedTiles:
|
||||
- x: 8
|
||||
y: 13
|
||||
- x: 9
|
||||
y: 13
|
||||
- x: 10
|
||||
y: 13
|
||||
- x: 11
|
||||
y: 13
|
||||
- x: 12
|
||||
y: 13
|
||||
- x: 8
|
||||
y: 14
|
||||
- x: 9
|
||||
y: 14
|
||||
- x: 10
|
||||
y: 14
|
||||
- x: 11
|
||||
y: 14
|
||||
- x: 12
|
||||
y: 14
|
||||
- x: 8
|
||||
y: 15
|
||||
- x: 9
|
||||
y: 15
|
||||
- x: 10
|
||||
y: 15
|
||||
- x: 11
|
||||
y: 15
|
||||
- x: 12
|
||||
y: 15
|
||||
- x: 8
|
||||
y: 16
|
||||
- x: 9
|
||||
y: 16
|
||||
- x: 10
|
||||
y: 16
|
||||
- x: 11
|
||||
y: 16
|
||||
- x: 12
|
||||
y: 16
|
||||
- x: 13
|
||||
y: 14
|
||||
- x: 13
|
||||
y: 15
|
||||
- x: 13
|
||||
y: 16
|
||||
- x: 11
|
||||
y: 17
|
||||
- x: 12
|
||||
y: 17
|
||||
- x: 13
|
||||
y: 17
|
||||
tags: []
|
||||
- id: stage_526b633d818b4e36b96ad92f540b9415
|
||||
displayName: Stage 6
|
||||
worldLayer: 0
|
||||
occupiedTiles:
|
||||
- x: 17
|
||||
y: 7
|
||||
- x: 18
|
||||
y: 7
|
||||
- x: 19
|
||||
y: 7
|
||||
- x: 17
|
||||
y: 8
|
||||
- x: 18
|
||||
y: 8
|
||||
- x: 19
|
||||
y: 8
|
||||
tags: []
|
||||
- id: stage_3e76ac8acd0447d59b0fbf1a65a25fb3
|
||||
displayName: Stage 7
|
||||
worldLayer: 0
|
||||
occupiedTiles:
|
||||
- x: 13
|
||||
y: 13
|
||||
- x: 14
|
||||
y: 13
|
||||
- x: 16
|
||||
y: 13
|
||||
- x: 17
|
||||
y: 13
|
||||
- x: 15
|
||||
y: 13
|
||||
- x: 14
|
||||
y: 9
|
||||
- x: 15
|
||||
y: 9
|
||||
- x: 16
|
||||
y: 9
|
||||
- x: 17
|
||||
y: 9
|
||||
- x: 18
|
||||
y: 9
|
||||
- x: 19
|
||||
y: 9
|
||||
- x: 14
|
||||
y: 10
|
||||
- x: 15
|
||||
y: 10
|
||||
- x: 16
|
||||
y: 10
|
||||
- x: 17
|
||||
y: 10
|
||||
- x: 18
|
||||
y: 10
|
||||
- x: 19
|
||||
y: 10
|
||||
- x: 14
|
||||
y: 11
|
||||
- x: 15
|
||||
y: 11
|
||||
- x: 16
|
||||
y: 11
|
||||
- x: 17
|
||||
y: 11
|
||||
- x: 18
|
||||
y: 11
|
||||
- x: 19
|
||||
y: 11
|
||||
- x: 14
|
||||
y: 12
|
||||
- x: 15
|
||||
y: 12
|
||||
- x: 16
|
||||
y: 12
|
||||
- x: 17
|
||||
y: 12
|
||||
- x: 18
|
||||
y: 12
|
||||
- x: 19
|
||||
y: 12
|
||||
- x: 18
|
||||
y: 13
|
||||
- x: 19
|
||||
y: 13
|
||||
- x: 14
|
||||
y: 14
|
||||
- x: 15
|
||||
y: 14
|
||||
- x: 16
|
||||
y: 14
|
||||
- x: 17
|
||||
y: 14
|
||||
- x: 18
|
||||
y: 14
|
||||
- x: 19
|
||||
y: 14
|
||||
- x: 14
|
||||
y: 15
|
||||
- x: 15
|
||||
y: 15
|
||||
- x: 16
|
||||
y: 15
|
||||
- x: 17
|
||||
y: 15
|
||||
- x: 18
|
||||
y: 15
|
||||
- x: 19
|
||||
y: 15
|
||||
- x: 14
|
||||
y: 16
|
||||
- x: 15
|
||||
y: 16
|
||||
- x: 16
|
||||
y: 16
|
||||
- x: 17
|
||||
y: 16
|
||||
- x: 18
|
||||
y: 16
|
||||
- x: 19
|
||||
y: 16
|
||||
- x: 14
|
||||
y: 17
|
||||
- x: 15
|
||||
y: 17
|
||||
- x: 16
|
||||
y: 17
|
||||
- x: 17
|
||||
y: 17
|
||||
- x: 18
|
||||
y: 17
|
||||
- x: 19
|
||||
y: 17
|
||||
tags: []
|
||||
- id: stage_1a60b23d8b4c4622905831237c716081
|
||||
displayName: Stage 8
|
||||
worldLayer: 1
|
||||
occupiedTiles:
|
||||
- x: 16
|
||||
y: 8
|
||||
- x: 17
|
||||
y: 8
|
||||
- x: 18
|
||||
y: 8
|
||||
- x: 19
|
||||
y: 8
|
||||
- x: 20
|
||||
y: 8
|
||||
- x: 16
|
||||
y: 9
|
||||
- x: 17
|
||||
y: 9
|
||||
- x: 18
|
||||
y: 9
|
||||
- x: 19
|
||||
y: 9
|
||||
- x: 20
|
||||
y: 9
|
||||
- x: 16
|
||||
y: 10
|
||||
- x: 17
|
||||
y: 10
|
||||
- x: 18
|
||||
y: 10
|
||||
- x: 19
|
||||
y: 10
|
||||
- x: 20
|
||||
y: 10
|
||||
- x: 16
|
||||
y: 11
|
||||
- x: 17
|
||||
y: 11
|
||||
- x: 18
|
||||
y: 11
|
||||
- x: 19
|
||||
y: 11
|
||||
- x: 20
|
||||
y: 11
|
||||
- x: 16
|
||||
y: 12
|
||||
- x: 17
|
||||
y: 12
|
||||
- x: 18
|
||||
y: 12
|
||||
- x: 19
|
||||
y: 12
|
||||
- x: 20
|
||||
y: 12
|
||||
tags: []
|
||||
- id: stage_a980c91d39bc470296289d3ef72636c0
|
||||
displayName: Stage 9
|
||||
worldLayer: -1
|
||||
occupiedTiles:
|
||||
- x: 17
|
||||
y: 8
|
||||
- x: 18
|
||||
y: 8
|
||||
- x: 19
|
||||
y: 8
|
||||
- x: 17
|
||||
y: 9
|
||||
- x: 18
|
||||
y: 9
|
||||
- x: 19
|
||||
y: 9
|
||||
- x: 17
|
||||
y: 10
|
||||
- x: 18
|
||||
y: 10
|
||||
- x: 19
|
||||
y: 10
|
||||
- x: 17
|
||||
y: 11
|
||||
- x: 18
|
||||
y: 11
|
||||
- x: 19
|
||||
y: 11
|
||||
tags: []
|
||||
- id: stage_78ca4be5151f4c60818dce81558ab162
|
||||
displayName: Stage 10
|
||||
worldLayer: -2
|
||||
occupiedTiles:
|
||||
- x: 18
|
||||
y: 10
|
||||
- x: 16
|
||||
y: 8
|
||||
- x: 17
|
||||
y: 8
|
||||
- x: 18
|
||||
y: 8
|
||||
- x: 19
|
||||
y: 8
|
||||
- x: 20
|
||||
y: 8
|
||||
- x: 16
|
||||
y: 9
|
||||
- x: 17
|
||||
y: 9
|
||||
- x: 18
|
||||
y: 9
|
||||
- x: 19
|
||||
y: 9
|
||||
- x: 20
|
||||
y: 9
|
||||
- x: 16
|
||||
y: 10
|
||||
- x: 17
|
||||
y: 10
|
||||
- x: 19
|
||||
y: 10
|
||||
- x: 20
|
||||
y: 10
|
||||
- x: 16
|
||||
y: 11
|
||||
- x: 17
|
||||
y: 11
|
||||
- x: 18
|
||||
y: 11
|
||||
- x: 19
|
||||
y: 11
|
||||
- x: 20
|
||||
y: 11
|
||||
- x: 16
|
||||
y: 12
|
||||
- x: 17
|
||||
y: 12
|
||||
- x: 18
|
||||
y: 12
|
||||
- x: 19
|
||||
y: 12
|
||||
- x: 20
|
||||
y: 12
|
||||
tags: []
|
||||
- id: stage_bfa43a65aced42ceb03f56b11dce0998
|
||||
displayName: Stage 15
|
||||
worldLayer: 0
|
||||
occupiedTiles: []
|
||||
tags: []
|
||||
- id: stage_b24d4774f45444138b8cfda33ed5034e
|
||||
displayName: Stage 16
|
||||
worldLayer: 0
|
||||
occupiedTiles: []
|
||||
tags: []
|
||||
endpoints:
|
||||
- id: endpoint_adc34044a48447d0be41389ba398d5f5
|
||||
stageId: stage_aae8c48d41d84a679c9c52acd567ff30
|
||||
worldTile:
|
||||
x: 10
|
||||
y: 13
|
||||
kind: 0
|
||||
required: 1
|
||||
socketFace: 0
|
||||
- id: endpoint_181357103f5742008cfa73a544a56363
|
||||
stageId: stage_f5a0fa8cc3a14a94b8b6fa80c4e2413d
|
||||
worldTile:
|
||||
x: 10
|
||||
y: 12
|
||||
kind: 0
|
||||
required: 1
|
||||
socketFace: 1
|
||||
- id: endpoint_71bd3851ad2b4d20a90cf3b3f5ade5fb
|
||||
stageId: stage_3e76ac8acd0447d59b0fbf1a65a25fb3
|
||||
worldTile:
|
||||
x: 13
|
||||
y: 13
|
||||
kind: 0
|
||||
required: 1
|
||||
socketFace: 1
|
||||
- id: endpoint_d9121bcc789443548c898106dd5f4c43
|
||||
stageId: stage_aae8c48d41d84a679c9c52acd567ff30
|
||||
worldTile:
|
||||
x: 13
|
||||
y: 14
|
||||
kind: 0
|
||||
required: 1
|
||||
socketFace: 0
|
||||
- id: endpoint_dc223745e7994fbd880f1e93f146d8cf
|
||||
stageId: stage_3e76ac8acd0447d59b0fbf1a65a25fb3
|
||||
worldTile:
|
||||
x: 13
|
||||
y: 13
|
||||
kind: 0
|
||||
required: 1
|
||||
socketFace: 0
|
||||
- id: endpoint_65e01fe22fe44222919c322ea8580a69
|
||||
stageId: stage_f5a0fa8cc3a14a94b8b6fa80c4e2413d
|
||||
worldTile:
|
||||
x: 13
|
||||
y: 12
|
||||
kind: 0
|
||||
required: 1
|
||||
socketFace: 1
|
||||
- id: endpoint_27a37615b51f40cdb39acfc9fbffce22
|
||||
stageId: stage_526b633d818b4e36b96ad92f540b9415
|
||||
worldTile:
|
||||
x: 18
|
||||
y: 8
|
||||
kind: 0
|
||||
required: 1
|
||||
socketFace: 1
|
||||
- id: endpoint_7cf95989e98a4de49edb7e2080e1c5e6
|
||||
stageId: stage_3e76ac8acd0447d59b0fbf1a65a25fb3
|
||||
worldTile:
|
||||
x: 18
|
||||
y: 9
|
||||
kind: 0
|
||||
required: 1
|
||||
socketFace: 0
|
||||
- id: endpoint_34e27be82570488cbcd45531e56f128c
|
||||
stageId: stage_f5a0fa8cc3a14a94b8b6fa80c4e2413d
|
||||
worldTile:
|
||||
x: 10
|
||||
y: 10
|
||||
kind: 1
|
||||
required: 1
|
||||
socketFace: 0
|
||||
- id: endpoint_e6e40c3366564b96825ecf652721a46d
|
||||
stageId: stage_3e76ac8acd0447d59b0fbf1a65a25fb3
|
||||
worldTile:
|
||||
x: 17
|
||||
y: 13
|
||||
kind: 1
|
||||
required: 1
|
||||
socketFace: 0
|
||||
- id: endpoint_9c245891f5734102bc24edb0dcc2c9fd
|
||||
stageId: stage_aae8c48d41d84a679c9c52acd567ff30
|
||||
worldTile:
|
||||
x: 11
|
||||
y: 15
|
||||
kind: 1
|
||||
required: 1
|
||||
socketFace: 0
|
||||
- id: endpoint_0e3b0c016a474adb8fe8b05bdfd79f14
|
||||
stageId: stage_3e76ac8acd0447d59b0fbf1a65a25fb3
|
||||
worldTile:
|
||||
x: 18
|
||||
y: 10
|
||||
kind: 2
|
||||
required: 1
|
||||
socketFace: 0
|
||||
- id: endpoint_6f17b532985e4e908e70b3802eccf8cc
|
||||
stageId: stage_78ca4be5151f4c60818dce81558ab162
|
||||
worldTile:
|
||||
x: 18
|
||||
y: 10
|
||||
kind: 2
|
||||
required: 1
|
||||
socketFace: 0
|
||||
- id: endpoint_ae66297a1c1a4c259e26ea8b51d69851
|
||||
stageId: stage_1a60b23d8b4c4622905831237c716081
|
||||
worldTile:
|
||||
x: 18
|
||||
y: 10
|
||||
kind: 2
|
||||
required: 1
|
||||
socketFace: 0
|
||||
- id: endpoint_263ea59d79614b9b85ed2bb4fe25c9ad
|
||||
stageId: stage_a980c91d39bc470296289d3ef72636c0
|
||||
worldTile:
|
||||
x: 18
|
||||
y: 10
|
||||
kind: 2
|
||||
required: 1
|
||||
socketFace: 0
|
||||
connections:
|
||||
- id: connection_cdf62cf06a20426b88d3987ea8917967
|
||||
endpointAId: endpoint_adc34044a48447d0be41389ba398d5f5
|
||||
endpointBId: endpoint_181357103f5742008cfa73a544a56363
|
||||
directionality: 0
|
||||
- id: connection_3dabe3efe429439bbb49104bed37bb20
|
||||
endpointAId: endpoint_71bd3851ad2b4d20a90cf3b3f5ade5fb
|
||||
endpointBId: endpoint_d9121bcc789443548c898106dd5f4c43
|
||||
directionality: 0
|
||||
- id: connection_ef34c049437c491b80364a034880300d
|
||||
endpointAId: endpoint_dc223745e7994fbd880f1e93f146d8cf
|
||||
endpointBId: endpoint_65e01fe22fe44222919c322ea8580a69
|
||||
directionality: 0
|
||||
- id: connection_2b7aa20f26bd48acb636a37ed1d20ad0
|
||||
endpointAId: endpoint_27a37615b51f40cdb39acfc9fbffce22
|
||||
endpointBId: endpoint_7cf95989e98a4de49edb7e2080e1c5e6
|
||||
directionality: 0
|
||||
- id: connection_d8da15ab563d4bb9ba6f0294cec60341
|
||||
endpointAId: endpoint_e6e40c3366564b96825ecf652721a46d
|
||||
endpointBId: endpoint_34e27be82570488cbcd45531e56f128c
|
||||
directionality: 0
|
||||
- id: connection_335b1c8a1f964b11b72ddf2ef053bd71
|
||||
endpointAId: endpoint_9c245891f5734102bc24edb0dcc2c9fd
|
||||
endpointBId: endpoint_e6e40c3366564b96825ecf652721a46d
|
||||
directionality: 0
|
||||
- id: connection_d0e5d7611be64e31a77bc6d24650a031
|
||||
endpointAId: endpoint_9c245891f5734102bc24edb0dcc2c9fd
|
||||
endpointBId: endpoint_34e27be82570488cbcd45531e56f128c
|
||||
directionality: 0
|
||||
- id: connection_12db74114bf54c8eb5b7038efcae4172
|
||||
endpointAId: endpoint_ae66297a1c1a4c259e26ea8b51d69851
|
||||
endpointBId: endpoint_0e3b0c016a474adb8fe8b05bdfd79f14
|
||||
directionality: 0
|
||||
- id: connection_274434096af24703a063627df527d688
|
||||
endpointAId: endpoint_263ea59d79614b9b85ed2bb4fe25c9ad
|
||||
endpointBId: endpoint_0e3b0c016a474adb8fe8b05bdfd79f14
|
||||
directionality: 0
|
||||
- id: connection_22f10261be3b4a24ada8debf789f9e33
|
||||
endpointAId: endpoint_263ea59d79614b9b85ed2bb4fe25c9ad
|
||||
endpointBId: endpoint_6f17b532985e4e908e70b3802eccf8cc
|
||||
directionality: 0
|
||||
8
Assets/# Prototype/World/JGraph.asset.meta
Normal file
8
Assets/# Prototype/World/JGraph.asset.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0e8c3fc507c9b42e8b1f2df5009b5937
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
638
Assets/# Prototype/World/WorldLayout.asset
Normal file
638
Assets/# Prototype/World/WorldLayout.asset
Normal file
@ -0,0 +1,638 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 8cbbff7dfcc24d2b9030f41f9f2ef718, type: 3}
|
||||
m_Name: WorldLayout
|
||||
m_EditorClassIdentifier: Assembly-CSharp-Editor::Editor.GON.WorldEditor.WorldLayoutSO
|
||||
id: 858671c3949e4543b0d68818c9b2e41b
|
||||
worldTileSize: 24
|
||||
worldLayerHeight: 24
|
||||
minWorldLayer: -2
|
||||
maxWorldLayer: 1
|
||||
stages:
|
||||
- id: stage_9202fe485eaa408d86e379b3fdafa49b
|
||||
displayName: Stage 1
|
||||
stageKind: 0
|
||||
worldLayer: 0
|
||||
color: {r: 0.43435237, g: 0.72672, b: 0.73008716, a: 0.820845}
|
||||
stageDefinition: {fileID: 0}
|
||||
occupiedTiles: []
|
||||
- id: stage_25e8797ce5d9420b97aaf3e06f760b1d
|
||||
displayName: Stage 2
|
||||
stageKind: 0
|
||||
worldLayer: 0
|
||||
color: {r: 0.71619093, g: 0.6632371, b: 0.3653053, a: 0.7631802}
|
||||
stageDefinition: {fileID: 0}
|
||||
occupiedTiles: []
|
||||
- id: stage_f5a0fa8cc3a14a94b8b6fa80c4e2413d
|
||||
displayName: Stage 3
|
||||
stageKind: 0
|
||||
worldLayer: 0
|
||||
color: {r: 0.26295125, g: 0.36055228, b: 0.6102875, a: 0.76864}
|
||||
stageDefinition: {fileID: 0}
|
||||
occupiedTiles:
|
||||
- x: 8
|
||||
y: 8
|
||||
- x: 9
|
||||
y: 8
|
||||
- x: 10
|
||||
y: 8
|
||||
- x: 11
|
||||
y: 8
|
||||
- x: 12
|
||||
y: 8
|
||||
- x: 8
|
||||
y: 9
|
||||
- x: 9
|
||||
y: 9
|
||||
- x: 10
|
||||
y: 9
|
||||
- x: 11
|
||||
y: 9
|
||||
- x: 12
|
||||
y: 9
|
||||
- x: 8
|
||||
y: 10
|
||||
- x: 9
|
||||
y: 10
|
||||
- x: 10
|
||||
y: 10
|
||||
- x: 11
|
||||
y: 10
|
||||
- x: 12
|
||||
y: 10
|
||||
- x: 8
|
||||
y: 11
|
||||
- x: 9
|
||||
y: 11
|
||||
- x: 10
|
||||
y: 11
|
||||
- x: 11
|
||||
y: 11
|
||||
- x: 12
|
||||
y: 11
|
||||
- x: 8
|
||||
y: 12
|
||||
- x: 9
|
||||
y: 12
|
||||
- x: 10
|
||||
y: 12
|
||||
- x: 11
|
||||
y: 12
|
||||
- x: 12
|
||||
y: 12
|
||||
- x: 13
|
||||
y: 9
|
||||
- x: 13
|
||||
y: 10
|
||||
- x: 13
|
||||
y: 11
|
||||
- x: 13
|
||||
y: 12
|
||||
- x: 8
|
||||
y: 7
|
||||
- x: 9
|
||||
y: 7
|
||||
- x: 10
|
||||
y: 7
|
||||
- x: 11
|
||||
y: 7
|
||||
- x: 7
|
||||
y: 7
|
||||
- x: 7
|
||||
y: 8
|
||||
- x: 7
|
||||
y: 9
|
||||
- x: 7
|
||||
y: 10
|
||||
- id: stage_92bb328658e04aceb915822ac7ff20ae
|
||||
displayName: Stage 4
|
||||
stageKind: 0
|
||||
worldLayer: 0
|
||||
color: {r: 0.7052704, g: 0.6072819, b: 0.39938506, a: 0.8043456}
|
||||
stageDefinition: {fileID: 0}
|
||||
occupiedTiles: []
|
||||
- id: stage_aae8c48d41d84a679c9c52acd567ff30
|
||||
displayName: Stage 5
|
||||
stageKind: 0
|
||||
worldLayer: 0
|
||||
color: {r: 0.73909104, g: 0.47607818, b: 0.6006857, a: 0.8447911}
|
||||
stageDefinition: {fileID: 0}
|
||||
occupiedTiles:
|
||||
- x: 8
|
||||
y: 13
|
||||
- x: 9
|
||||
y: 13
|
||||
- x: 10
|
||||
y: 13
|
||||
- x: 11
|
||||
y: 13
|
||||
- x: 12
|
||||
y: 13
|
||||
- x: 8
|
||||
y: 14
|
||||
- x: 9
|
||||
y: 14
|
||||
- x: 10
|
||||
y: 14
|
||||
- x: 11
|
||||
y: 14
|
||||
- x: 12
|
||||
y: 14
|
||||
- x: 8
|
||||
y: 15
|
||||
- x: 9
|
||||
y: 15
|
||||
- x: 10
|
||||
y: 15
|
||||
- x: 11
|
||||
y: 15
|
||||
- x: 12
|
||||
y: 15
|
||||
- x: 8
|
||||
y: 16
|
||||
- x: 9
|
||||
y: 16
|
||||
- x: 10
|
||||
y: 16
|
||||
- x: 11
|
||||
y: 16
|
||||
- x: 12
|
||||
y: 16
|
||||
- x: 13
|
||||
y: 14
|
||||
- x: 13
|
||||
y: 15
|
||||
- x: 13
|
||||
y: 16
|
||||
- x: 11
|
||||
y: 17
|
||||
- x: 12
|
||||
y: 17
|
||||
- x: 13
|
||||
y: 17
|
||||
- id: stage_526b633d818b4e36b96ad92f540b9415
|
||||
displayName: Stage 6
|
||||
stageKind: 0
|
||||
worldLayer: 0
|
||||
color: {r: 0.59988964, g: 0.84526074, b: 0.5487183, a: 0.7954139}
|
||||
stageDefinition: {fileID: 0}
|
||||
occupiedTiles:
|
||||
- x: 17
|
||||
y: 7
|
||||
- x: 18
|
||||
y: 7
|
||||
- x: 19
|
||||
y: 7
|
||||
- x: 17
|
||||
y: 8
|
||||
- x: 18
|
||||
y: 8
|
||||
- x: 19
|
||||
y: 8
|
||||
- id: stage_3e76ac8acd0447d59b0fbf1a65a25fb3
|
||||
displayName: Stage 7
|
||||
stageKind: 0
|
||||
worldLayer: 0
|
||||
color: {r: 0.7086307, g: 0.25315043, b: 0.84043574, a: 0.79866225}
|
||||
stageDefinition: {fileID: 0}
|
||||
occupiedTiles:
|
||||
- x: 13
|
||||
y: 13
|
||||
- x: 14
|
||||
y: 13
|
||||
- x: 16
|
||||
y: 13
|
||||
- x: 17
|
||||
y: 13
|
||||
- x: 15
|
||||
y: 13
|
||||
- x: 14
|
||||
y: 9
|
||||
- x: 15
|
||||
y: 9
|
||||
- x: 16
|
||||
y: 9
|
||||
- x: 17
|
||||
y: 9
|
||||
- x: 18
|
||||
y: 9
|
||||
- x: 19
|
||||
y: 9
|
||||
- x: 14
|
||||
y: 10
|
||||
- x: 15
|
||||
y: 10
|
||||
- x: 16
|
||||
y: 10
|
||||
- x: 17
|
||||
y: 10
|
||||
- x: 18
|
||||
y: 10
|
||||
- x: 19
|
||||
y: 10
|
||||
- x: 14
|
||||
y: 11
|
||||
- x: 15
|
||||
y: 11
|
||||
- x: 16
|
||||
y: 11
|
||||
- x: 17
|
||||
y: 11
|
||||
- x: 18
|
||||
y: 11
|
||||
- x: 19
|
||||
y: 11
|
||||
- x: 14
|
||||
y: 12
|
||||
- x: 15
|
||||
y: 12
|
||||
- x: 16
|
||||
y: 12
|
||||
- x: 17
|
||||
y: 12
|
||||
- x: 18
|
||||
y: 12
|
||||
- x: 19
|
||||
y: 12
|
||||
- x: 18
|
||||
y: 13
|
||||
- x: 19
|
||||
y: 13
|
||||
- x: 14
|
||||
y: 14
|
||||
- x: 15
|
||||
y: 14
|
||||
- x: 16
|
||||
y: 14
|
||||
- x: 17
|
||||
y: 14
|
||||
- x: 18
|
||||
y: 14
|
||||
- x: 19
|
||||
y: 14
|
||||
- x: 14
|
||||
y: 15
|
||||
- x: 15
|
||||
y: 15
|
||||
- x: 16
|
||||
y: 15
|
||||
- x: 17
|
||||
y: 15
|
||||
- x: 18
|
||||
y: 15
|
||||
- x: 19
|
||||
y: 15
|
||||
- x: 14
|
||||
y: 16
|
||||
- x: 15
|
||||
y: 16
|
||||
- x: 16
|
||||
y: 16
|
||||
- x: 17
|
||||
y: 16
|
||||
- x: 18
|
||||
y: 16
|
||||
- x: 19
|
||||
y: 16
|
||||
- x: 14
|
||||
y: 17
|
||||
- x: 15
|
||||
y: 17
|
||||
- x: 16
|
||||
y: 17
|
||||
- x: 17
|
||||
y: 17
|
||||
- x: 18
|
||||
y: 17
|
||||
- x: 19
|
||||
y: 17
|
||||
- id: stage_1a60b23d8b4c4622905831237c716081
|
||||
displayName: Stage 8
|
||||
stageKind: 0
|
||||
worldLayer: 1
|
||||
color: {r: 0.41402355, g: 0.6012687, b: 0.37944123, a: 0.8586461}
|
||||
stageDefinition: {fileID: 0}
|
||||
occupiedTiles:
|
||||
- x: 16
|
||||
y: 8
|
||||
- x: 17
|
||||
y: 8
|
||||
- x: 18
|
||||
y: 8
|
||||
- x: 19
|
||||
y: 8
|
||||
- x: 20
|
||||
y: 8
|
||||
- x: 16
|
||||
y: 9
|
||||
- x: 17
|
||||
y: 9
|
||||
- x: 18
|
||||
y: 9
|
||||
- x: 19
|
||||
y: 9
|
||||
- x: 20
|
||||
y: 9
|
||||
- x: 16
|
||||
y: 10
|
||||
- x: 17
|
||||
y: 10
|
||||
- x: 18
|
||||
y: 10
|
||||
- x: 19
|
||||
y: 10
|
||||
- x: 20
|
||||
y: 10
|
||||
- x: 16
|
||||
y: 11
|
||||
- x: 17
|
||||
y: 11
|
||||
- x: 18
|
||||
y: 11
|
||||
- x: 19
|
||||
y: 11
|
||||
- x: 20
|
||||
y: 11
|
||||
- x: 16
|
||||
y: 12
|
||||
- x: 17
|
||||
y: 12
|
||||
- x: 18
|
||||
y: 12
|
||||
- x: 19
|
||||
y: 12
|
||||
- x: 20
|
||||
y: 12
|
||||
- id: stage_a980c91d39bc470296289d3ef72636c0
|
||||
displayName: Stage 9
|
||||
stageKind: 0
|
||||
worldLayer: -1
|
||||
color: {r: 0.6987197, g: 0.5302855, b: 0.419144, a: 0.76745874}
|
||||
stageDefinition: {fileID: 0}
|
||||
occupiedTiles:
|
||||
- x: 17
|
||||
y: 8
|
||||
- x: 18
|
||||
y: 8
|
||||
- x: 19
|
||||
y: 8
|
||||
- x: 17
|
||||
y: 9
|
||||
- x: 18
|
||||
y: 9
|
||||
- x: 19
|
||||
y: 9
|
||||
- x: 17
|
||||
y: 10
|
||||
- x: 18
|
||||
y: 10
|
||||
- x: 19
|
||||
y: 10
|
||||
- x: 17
|
||||
y: 11
|
||||
- x: 18
|
||||
y: 11
|
||||
- x: 19
|
||||
y: 11
|
||||
- id: stage_78ca4be5151f4c60818dce81558ab162
|
||||
displayName: Stage 10
|
||||
stageKind: 0
|
||||
worldLayer: -2
|
||||
color: {r: 0.58324605, g: 0.27982995, b: 0.5501635, a: 0.85375965}
|
||||
stageDefinition: {fileID: 0}
|
||||
occupiedTiles:
|
||||
- x: 18
|
||||
y: 10
|
||||
- x: 16
|
||||
y: 8
|
||||
- x: 17
|
||||
y: 8
|
||||
- x: 18
|
||||
y: 8
|
||||
- x: 19
|
||||
y: 8
|
||||
- x: 20
|
||||
y: 8
|
||||
- x: 16
|
||||
y: 9
|
||||
- x: 17
|
||||
y: 9
|
||||
- x: 18
|
||||
y: 9
|
||||
- x: 19
|
||||
y: 9
|
||||
- x: 20
|
||||
y: 9
|
||||
- x: 16
|
||||
y: 10
|
||||
- x: 17
|
||||
y: 10
|
||||
- x: 19
|
||||
y: 10
|
||||
- x: 20
|
||||
y: 10
|
||||
- x: 16
|
||||
y: 11
|
||||
- x: 17
|
||||
y: 11
|
||||
- x: 18
|
||||
y: 11
|
||||
- x: 19
|
||||
y: 11
|
||||
- x: 20
|
||||
y: 11
|
||||
- x: 16
|
||||
y: 12
|
||||
- x: 17
|
||||
y: 12
|
||||
- x: 18
|
||||
y: 12
|
||||
- x: 19
|
||||
y: 12
|
||||
- x: 20
|
||||
y: 12
|
||||
- id: stage_bfa43a65aced42ceb03f56b11dce0998
|
||||
displayName: Stage 15
|
||||
stageKind: 0
|
||||
worldLayer: 0
|
||||
color: {r: 0.82491213, g: 0.683962, b: 0.2155831, a: 0.8341453}
|
||||
stageDefinition: {fileID: 0}
|
||||
occupiedTiles: []
|
||||
- id: stage_b24d4774f45444138b8cfda33ed5034e
|
||||
displayName: Stage 16
|
||||
stageKind: 0
|
||||
worldLayer: 0
|
||||
color: {r: 0.44949582, g: 0.6144462, b: 0.7657885, a: 0.82364887}
|
||||
stageDefinition: {fileID: 0}
|
||||
occupiedTiles: []
|
||||
endpoints:
|
||||
- id: endpoint_adc34044a48447d0be41389ba398d5f5
|
||||
stageId: stage_aae8c48d41d84a679c9c52acd567ff30
|
||||
worldTile:
|
||||
x: 10
|
||||
y: 13
|
||||
kind: 0
|
||||
required: 1
|
||||
socketFace: 0
|
||||
- id: endpoint_181357103f5742008cfa73a544a56363
|
||||
stageId: stage_f5a0fa8cc3a14a94b8b6fa80c4e2413d
|
||||
worldTile:
|
||||
x: 10
|
||||
y: 12
|
||||
kind: 0
|
||||
required: 1
|
||||
socketFace: 1
|
||||
- id: endpoint_71bd3851ad2b4d20a90cf3b3f5ade5fb
|
||||
stageId: stage_3e76ac8acd0447d59b0fbf1a65a25fb3
|
||||
worldTile:
|
||||
x: 13
|
||||
y: 13
|
||||
kind: 0
|
||||
required: 1
|
||||
socketFace: 1
|
||||
- id: endpoint_d9121bcc789443548c898106dd5f4c43
|
||||
stageId: stage_aae8c48d41d84a679c9c52acd567ff30
|
||||
worldTile:
|
||||
x: 13
|
||||
y: 14
|
||||
kind: 0
|
||||
required: 1
|
||||
socketFace: 0
|
||||
- id: endpoint_dc223745e7994fbd880f1e93f146d8cf
|
||||
stageId: stage_3e76ac8acd0447d59b0fbf1a65a25fb3
|
||||
worldTile:
|
||||
x: 13
|
||||
y: 13
|
||||
kind: 0
|
||||
required: 1
|
||||
socketFace: 0
|
||||
- id: endpoint_65e01fe22fe44222919c322ea8580a69
|
||||
stageId: stage_f5a0fa8cc3a14a94b8b6fa80c4e2413d
|
||||
worldTile:
|
||||
x: 13
|
||||
y: 12
|
||||
kind: 0
|
||||
required: 1
|
||||
socketFace: 1
|
||||
- id: endpoint_27a37615b51f40cdb39acfc9fbffce22
|
||||
stageId: stage_526b633d818b4e36b96ad92f540b9415
|
||||
worldTile:
|
||||
x: 18
|
||||
y: 8
|
||||
kind: 0
|
||||
required: 1
|
||||
socketFace: 1
|
||||
- id: endpoint_7cf95989e98a4de49edb7e2080e1c5e6
|
||||
stageId: stage_3e76ac8acd0447d59b0fbf1a65a25fb3
|
||||
worldTile:
|
||||
x: 18
|
||||
y: 9
|
||||
kind: 0
|
||||
required: 1
|
||||
socketFace: 0
|
||||
- id: endpoint_34e27be82570488cbcd45531e56f128c
|
||||
stageId: stage_f5a0fa8cc3a14a94b8b6fa80c4e2413d
|
||||
worldTile:
|
||||
x: 10
|
||||
y: 10
|
||||
kind: 1
|
||||
required: 1
|
||||
socketFace: 0
|
||||
- id: endpoint_e6e40c3366564b96825ecf652721a46d
|
||||
stageId: stage_3e76ac8acd0447d59b0fbf1a65a25fb3
|
||||
worldTile:
|
||||
x: 17
|
||||
y: 13
|
||||
kind: 1
|
||||
required: 1
|
||||
socketFace: 0
|
||||
- id: endpoint_9c245891f5734102bc24edb0dcc2c9fd
|
||||
stageId: stage_aae8c48d41d84a679c9c52acd567ff30
|
||||
worldTile:
|
||||
x: 11
|
||||
y: 15
|
||||
kind: 1
|
||||
required: 1
|
||||
socketFace: 0
|
||||
- id: endpoint_0e3b0c016a474adb8fe8b05bdfd79f14
|
||||
stageId: stage_3e76ac8acd0447d59b0fbf1a65a25fb3
|
||||
worldTile:
|
||||
x: 18
|
||||
y: 10
|
||||
kind: 2
|
||||
required: 1
|
||||
socketFace: 0
|
||||
- id: endpoint_6f17b532985e4e908e70b3802eccf8cc
|
||||
stageId: stage_78ca4be5151f4c60818dce81558ab162
|
||||
worldTile:
|
||||
x: 18
|
||||
y: 10
|
||||
kind: 2
|
||||
required: 1
|
||||
socketFace: 0
|
||||
- id: endpoint_ae66297a1c1a4c259e26ea8b51d69851
|
||||
stageId: stage_1a60b23d8b4c4622905831237c716081
|
||||
worldTile:
|
||||
x: 18
|
||||
y: 10
|
||||
kind: 2
|
||||
required: 1
|
||||
socketFace: 0
|
||||
- id: endpoint_263ea59d79614b9b85ed2bb4fe25c9ad
|
||||
stageId: stage_a980c91d39bc470296289d3ef72636c0
|
||||
worldTile:
|
||||
x: 18
|
||||
y: 10
|
||||
kind: 2
|
||||
required: 1
|
||||
socketFace: 0
|
||||
connections:
|
||||
- id: connection_cdf62cf06a20426b88d3987ea8917967
|
||||
endpointAId: endpoint_adc34044a48447d0be41389ba398d5f5
|
||||
endpointBId: endpoint_181357103f5742008cfa73a544a56363
|
||||
directionality: 0
|
||||
- id: connection_3dabe3efe429439bbb49104bed37bb20
|
||||
endpointAId: endpoint_71bd3851ad2b4d20a90cf3b3f5ade5fb
|
||||
endpointBId: endpoint_d9121bcc789443548c898106dd5f4c43
|
||||
directionality: 0
|
||||
- id: connection_ef34c049437c491b80364a034880300d
|
||||
endpointAId: endpoint_dc223745e7994fbd880f1e93f146d8cf
|
||||
endpointBId: endpoint_65e01fe22fe44222919c322ea8580a69
|
||||
directionality: 0
|
||||
- id: connection_2b7aa20f26bd48acb636a37ed1d20ad0
|
||||
endpointAId: endpoint_27a37615b51f40cdb39acfc9fbffce22
|
||||
endpointBId: endpoint_7cf95989e98a4de49edb7e2080e1c5e6
|
||||
directionality: 0
|
||||
- id: connection_d8da15ab563d4bb9ba6f0294cec60341
|
||||
endpointAId: endpoint_e6e40c3366564b96825ecf652721a46d
|
||||
endpointBId: endpoint_34e27be82570488cbcd45531e56f128c
|
||||
directionality: 0
|
||||
- id: connection_335b1c8a1f964b11b72ddf2ef053bd71
|
||||
endpointAId: endpoint_9c245891f5734102bc24edb0dcc2c9fd
|
||||
endpointBId: endpoint_e6e40c3366564b96825ecf652721a46d
|
||||
directionality: 0
|
||||
- id: connection_d0e5d7611be64e31a77bc6d24650a031
|
||||
endpointAId: endpoint_9c245891f5734102bc24edb0dcc2c9fd
|
||||
endpointBId: endpoint_34e27be82570488cbcd45531e56f128c
|
||||
directionality: 0
|
||||
- id: connection_12db74114bf54c8eb5b7038efcae4172
|
||||
endpointAId: endpoint_ae66297a1c1a4c259e26ea8b51d69851
|
||||
endpointBId: endpoint_0e3b0c016a474adb8fe8b05bdfd79f14
|
||||
directionality: 0
|
||||
- id: connection_274434096af24703a063627df527d688
|
||||
endpointAId: endpoint_263ea59d79614b9b85ed2bb4fe25c9ad
|
||||
endpointBId: endpoint_0e3b0c016a474adb8fe8b05bdfd79f14
|
||||
directionality: 0
|
||||
- id: connection_22f10261be3b4a24ada8debf789f9e33
|
||||
endpointAId: endpoint_263ea59d79614b9b85ed2bb4fe25c9ad
|
||||
endpointBId: endpoint_6f17b532985e4e908e70b3802eccf8cc
|
||||
directionality: 0
|
||||
8
Assets/# Prototype/World/WorldLayout.asset.meta
Normal file
8
Assets/# Prototype/World/WorldLayout.asset.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8ec2b6c87674e4b27863ffb69c081b90
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because one or more lines are too long
3
Assets/Scripts/Editor/GON.meta
Normal file
3
Assets/Scripts/Editor/GON.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f13036ba22b24a8c93b188ae40c108a5
|
||||
timeCreated: 1781871128
|
||||
3
Assets/Scripts/Editor/GON/StageEditor.meta
Normal file
3
Assets/Scripts/Editor/GON/StageEditor.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a415e0c7f0ff4b95af8ae97c871a84ef
|
||||
timeCreated: 1781871135
|
||||
@ -5,7 +5,7 @@ using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace Editor.GardensStageEditor.Baker
|
||||
namespace Editor.GON.StageEditor.Baker
|
||||
{
|
||||
namespace Editor.GardensStageEditor
|
||||
{
|
||||
@ -7,7 +7,7 @@ using Intrepid.Gameplay.Prototyping;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Editor.GardensStageEditor.Baker
|
||||
namespace Editor.GON.StageEditor.Baker
|
||||
{
|
||||
public struct StageBuilderRequest
|
||||
{
|
||||
@ -1,7 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Editor.GardensStageEditor.Baker
|
||||
namespace Editor.GON.StageEditor.Baker
|
||||
{
|
||||
public static class StageBuilderHelpers
|
||||
{
|
||||
@ -2,7 +2,7 @@ using Intrepid.Gameplay.Prototyping;
|
||||
using Intrepid.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Editor.GardensStageEditor
|
||||
namespace Editor.GON.StageEditor
|
||||
{
|
||||
[CreateAssetMenu(fileName = "New Prefab Table", menuName = "GON/Editor/Prefab Table")]
|
||||
public class PrefabTable : ScriptableObject
|
||||
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
using Intrepid.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Editor.GardensStageEditor
|
||||
namespace Editor.GON.StageEditor
|
||||
{
|
||||
public enum StageLogicalLayer
|
||||
{
|
||||
@ -1,7 +1,7 @@
|
||||
using Intrepid.Diagnostics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Editor.GardensStageEditor
|
||||
namespace Editor.GON.StageEditor
|
||||
{
|
||||
internal static class StageEditorColors
|
||||
{
|
||||
@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using Intrepid.Gameplay.Prototyping;
|
||||
|
||||
namespace Editor.GardensStageEditor
|
||||
namespace Editor.GON.StageEditor
|
||||
{
|
||||
public sealed class StageEditorState
|
||||
{
|
||||
@ -1,13 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Editor.GardensStageEditor.Baker.Editor.GardensStageEditor;
|
||||
using Editor.GON.StageEditor.Baker.Editor.GardensStageEditor;
|
||||
using UnityEditor;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Editor.GardensStageEditor
|
||||
namespace Editor.GON.StageEditor
|
||||
{
|
||||
public sealed class StageEditorWindow : EditorWindow
|
||||
{
|
||||
@ -1,7 +1,7 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Editor.GardensStageEditor
|
||||
namespace Editor.GON.StageEditor
|
||||
{
|
||||
public sealed class StageInspectorPanel : VisualElement
|
||||
{
|
||||
@ -2,7 +2,7 @@ using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Editor.GardensStageEditor
|
||||
namespace Editor.GON.StageEditor
|
||||
{
|
||||
public sealed class StageMapCanvas : VisualElement
|
||||
{
|
||||
@ -1,7 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Editor.GardensStageEditor
|
||||
namespace Editor.GON.StageEditor
|
||||
{
|
||||
public sealed class StagePaletteEntry
|
||||
{
|
||||
@ -2,7 +2,7 @@ using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Editor.GardensStageEditor
|
||||
namespace Editor.GON.StageEditor
|
||||
{
|
||||
public sealed class StagePalettePanel : VisualElement
|
||||
{
|
||||
@ -1,7 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Editor.GardensStageEditor
|
||||
namespace Editor.GON.StageEditor
|
||||
{
|
||||
public enum StageValidationSeverity
|
||||
{
|
||||
3
Assets/Scripts/Editor/GON/WorldEditor.meta
Normal file
3
Assets/Scripts/Editor/GON/WorldEditor.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 450f645e91eb4e529ce4f7337f11ca15
|
||||
timeCreated: 1781871512
|
||||
160
Assets/Scripts/Editor/GON/WorldEditor/JourneyCommitter.cs
Normal file
160
Assets/Scripts/Editor/GON/WorldEditor/JourneyCommitter.cs
Normal file
@ -0,0 +1,160 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Intrepid.Gameplay.Journey;
|
||||
using UnityEditor;
|
||||
|
||||
namespace Editor.GON.WorldEditor
|
||||
{
|
||||
public static class JourneyCommitter
|
||||
{
|
||||
public static List<WorldValidationMessage> Commit(WorldLayoutSO layout, JGraphSO graph)
|
||||
{
|
||||
var messages = WorldLayoutValidator.Validate(layout);
|
||||
if (WorldLayoutValidator.HasErrors(messages) || graph is null)
|
||||
{
|
||||
if (graph is null)
|
||||
{
|
||||
messages.Add(new WorldValidationMessage(WorldValidationSeverity.Error, "No target JGraphSO selected."));
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
layout.EnsureDefaults();
|
||||
graph.sourceWorldLayoutId = layout.id;
|
||||
graph.publishedAt = DateTime.UtcNow.ToString("O");
|
||||
graph.schemaVersion = 1;
|
||||
graph.stages = BuildStages(layout);
|
||||
graph.endpoints = BuildEndpoints(layout);
|
||||
graph.connections = BuildConnections(layout);
|
||||
graph.contentHash = ComputeContentHash(graph);
|
||||
graph.EnsureDefaults();
|
||||
|
||||
EditorUtility.SetDirty(graph);
|
||||
AssetDatabase.SaveAssets();
|
||||
return messages;
|
||||
}
|
||||
|
||||
private static List<JStage> BuildStages(WorldLayoutSO layout)
|
||||
{
|
||||
var stages = new List<JStage>();
|
||||
foreach (var source in layout.stages)
|
||||
{
|
||||
if (source is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
source.EnsureDefaults();
|
||||
var stage = new JStage
|
||||
{
|
||||
id = source.id,
|
||||
displayName = source.displayName,
|
||||
worldLayer = source.worldLayer,
|
||||
occupiedTiles = new List<JWorldTile>(source.occupiedTiles)
|
||||
};
|
||||
if (source.stageKind == WorldStageKind.SavePoint)
|
||||
{
|
||||
stage.tags.Add(WorldLayoutSO.SavePointTag);
|
||||
}
|
||||
|
||||
stages.Add(stage);
|
||||
}
|
||||
|
||||
return stages;
|
||||
}
|
||||
|
||||
private static List<JEndpoint> BuildEndpoints(WorldLayoutSO layout)
|
||||
{
|
||||
var endpoints = new List<JEndpoint>();
|
||||
foreach (var source in layout.endpoints)
|
||||
{
|
||||
if (source is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
endpoints.Add(new JEndpoint
|
||||
{
|
||||
id = source.id,
|
||||
stageId = source.stageId,
|
||||
worldTile = source.worldTile,
|
||||
kind = source.kind,
|
||||
required = source.required,
|
||||
socketFace = source.socketFace
|
||||
});
|
||||
}
|
||||
|
||||
return endpoints;
|
||||
}
|
||||
|
||||
private static List<JConnection> BuildConnections(WorldLayoutSO layout)
|
||||
{
|
||||
var connections = new List<JConnection>();
|
||||
foreach (var source in layout.connections)
|
||||
{
|
||||
if (source is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
connections.Add(new JConnection
|
||||
{
|
||||
id = source.id,
|
||||
endpointAId = source.endpointAId,
|
||||
endpointBId = source.endpointBId,
|
||||
directionality = source.directionality
|
||||
});
|
||||
}
|
||||
|
||||
return connections;
|
||||
}
|
||||
|
||||
private static string ComputeContentHash(JGraphSO graph)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.Append(graph.sourceWorldLayoutId).Append('|').Append(graph.schemaVersion).AppendLine();
|
||||
|
||||
foreach (var stage in graph.stages)
|
||||
{
|
||||
builder.Append("S|").Append(stage.id).Append('|').Append(stage.displayName).Append('|')
|
||||
.Append(stage.worldLayer).AppendLine();
|
||||
foreach (var tag in stage.tags)
|
||||
{
|
||||
builder.Append("G|").Append(tag).AppendLine();
|
||||
}
|
||||
|
||||
foreach (var tile in stage.occupiedTiles)
|
||||
{
|
||||
builder.Append("T|").Append(tile.x).Append('|').Append(tile.y).AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var endpoint in graph.endpoints)
|
||||
{
|
||||
builder.Append("E|").Append(endpoint.id).Append('|').Append(endpoint.stageId).Append('|')
|
||||
.Append(endpoint.worldTile.x).Append('|').Append(endpoint.worldTile.y).Append('|')
|
||||
.Append(endpoint.kind).Append('|').Append(endpoint.required).Append('|')
|
||||
.Append(endpoint.socketFace).AppendLine();
|
||||
}
|
||||
|
||||
foreach (var connection in graph.connections)
|
||||
{
|
||||
builder.Append("C|").Append(connection.id).Append('|').Append(connection.endpointAId).Append('|')
|
||||
.Append(connection.endpointBId).Append('|').Append(connection.directionality).AppendLine();
|
||||
}
|
||||
|
||||
using var sha = SHA256.Create();
|
||||
var bytes = sha.ComputeHash(Encoding.UTF8.GetBytes(builder.ToString()));
|
||||
var result = new StringBuilder(bytes.Length * 2);
|
||||
foreach (var value in bytes)
|
||||
{
|
||||
result.Append(value.ToString("x2"));
|
||||
}
|
||||
|
||||
return result.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5b08cddf1c414e7b8d1f6ee4d7e67fb7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
19
Assets/Scripts/Editor/GON/WorldEditor/WorldEditorColors.cs
Normal file
19
Assets/Scripts/Editor/GON/WorldEditor/WorldEditorColors.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Editor.GON.WorldEditor
|
||||
{
|
||||
public static class WorldEditorColors
|
||||
{
|
||||
public static readonly Color Background = new(0.08f, 0.09f, 0.1f, 1f);
|
||||
public static readonly Color Grid = new(1f, 1f, 1f, 0.08f);
|
||||
public static readonly Color GridAxis = new(1f, 1f, 1f, 0.18f);
|
||||
public static readonly Color Selected = new(1f, 0.86f, 0.32f, 1f);
|
||||
public static readonly Color EndpointSelected = new(1f, 0.1f, 0.95f, 1f);
|
||||
public static readonly Color Socket = new(0.45f, 0.45f, 0.45f, 1f);
|
||||
public static readonly Color SocketPaired = new(1f, 0.86f, 0.32f, 1f);
|
||||
public static readonly Color SocketConnected = new(0.35f, 0.95f, 0.45f, 1f);
|
||||
public static readonly Color Anchor = new(0.35f, 0.9f, 0.75f, 1f);
|
||||
public static readonly Color Lift = new(0.95f, 0.45f, 0.35f, 1f);
|
||||
public static readonly Color LiftGhost = new(0.95f, 0.45f, 0.35f, 0.35f);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c934ed58cc61487aaf68600c93e0d8b3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
28
Assets/Scripts/Editor/GON/WorldEditor/WorldEditorState.cs
Normal file
28
Assets/Scripts/Editor/GON/WorldEditor/WorldEditorState.cs
Normal file
@ -0,0 +1,28 @@
|
||||
namespace Editor.GON.WorldEditor
|
||||
{
|
||||
using System;
|
||||
using Intrepid.Gameplay.Journey;
|
||||
|
||||
public enum WorldEditorTool
|
||||
{
|
||||
Select = 0,
|
||||
PaintStage = 1,
|
||||
EraseStage = 2,
|
||||
Socket = 3,
|
||||
Anchor = 4,
|
||||
Lift = 5
|
||||
}
|
||||
|
||||
public sealed class WorldEditorState
|
||||
{
|
||||
public int activeLayer;
|
||||
public string selectedStageId;
|
||||
public string selectedEndpointId;
|
||||
public string selectedConnectionId;
|
||||
public WorldEditorTool activeTool = WorldEditorTool.PaintStage;
|
||||
public JWorldTile? hoverTile;
|
||||
public string pendingAnchorEndpointId;
|
||||
public WorldStageKind? pendingStagePlacementKind;
|
||||
public WorldEditorTool toolBeforeStagePlacement;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6782fb3fdb8f49d5939b0c92f86adad9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
942
Assets/Scripts/Editor/GON/WorldEditor/WorldEditorWindow.cs
Normal file
942
Assets/Scripts/Editor/GON/WorldEditor/WorldEditorWindow.cs
Normal file
@ -0,0 +1,942 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Intrepid.Gameplay.Journey;
|
||||
using UnityEditor;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
namespace Editor.GON.WorldEditor
|
||||
{
|
||||
public sealed class WorldEditorWindow : EditorWindow
|
||||
{
|
||||
private WorldLayoutSO layout;
|
||||
private JGraphSO graph;
|
||||
private WorldEditorState state;
|
||||
private VisualElement topBar;
|
||||
private VisualElement layerBar;
|
||||
private VisualElement toolBar;
|
||||
private WorldMapCanvas canvas;
|
||||
private WorldInspectorPanel inspector;
|
||||
private Label infoLabel;
|
||||
|
||||
[MenuItem("Tools/Gardens Of Nil/World Editor")]
|
||||
public static void Open()
|
||||
{
|
||||
var window = GetWindow<WorldEditorWindow>();
|
||||
window.titleContent = new GUIContent("Gardens World Editor");
|
||||
window.minSize = new Vector2(900, 600);
|
||||
window.Show();
|
||||
}
|
||||
|
||||
public void CreateGUI()
|
||||
{
|
||||
state ??= new WorldEditorState();
|
||||
|
||||
rootVisualElement.Clear();
|
||||
rootVisualElement.style.flexDirection = FlexDirection.Column;
|
||||
|
||||
topBar = new VisualElement
|
||||
{
|
||||
style =
|
||||
{
|
||||
flexDirection = FlexDirection.Row,
|
||||
alignItems = Align.Center,
|
||||
paddingLeft = 8,
|
||||
paddingRight = 8,
|
||||
paddingTop = 6,
|
||||
paddingBottom = 6,
|
||||
borderBottomWidth = 1,
|
||||
borderBottomColor = new Color(1f, 1f, 1f, 0.12f)
|
||||
}
|
||||
};
|
||||
rootVisualElement.Add(topBar);
|
||||
|
||||
var main = new VisualElement
|
||||
{
|
||||
style =
|
||||
{
|
||||
flexGrow = 1f,
|
||||
flexDirection = FlexDirection.Row
|
||||
}
|
||||
};
|
||||
rootVisualElement.Add(main);
|
||||
|
||||
layerBar = new VisualElement
|
||||
{
|
||||
style =
|
||||
{
|
||||
width = 74,
|
||||
flexShrink = 0f,
|
||||
paddingTop = 6,
|
||||
paddingLeft = 6,
|
||||
paddingRight = 6,
|
||||
borderRightWidth = 1,
|
||||
borderRightColor = new Color(1f, 1f, 1f, 0.12f)
|
||||
}
|
||||
};
|
||||
main.Add(layerBar);
|
||||
|
||||
canvas = new WorldMapCanvas(this, state);
|
||||
canvas.SetLayout(layout);
|
||||
main.Add(canvas);
|
||||
|
||||
inspector = new WorldInspectorPanel(this, state);
|
||||
inspector.SetLayout(layout);
|
||||
main.Add(inspector);
|
||||
|
||||
infoLabel = new Label
|
||||
{
|
||||
style =
|
||||
{
|
||||
paddingLeft = 8,
|
||||
paddingTop = 4,
|
||||
paddingBottom = 4
|
||||
}
|
||||
};
|
||||
rootVisualElement.Add(infoLabel);
|
||||
|
||||
toolBar = new VisualElement
|
||||
{
|
||||
style =
|
||||
{
|
||||
flexDirection = FlexDirection.Row,
|
||||
alignItems = Align.Center,
|
||||
paddingLeft = 8,
|
||||
paddingRight = 8,
|
||||
paddingTop = 6,
|
||||
paddingBottom = 6,
|
||||
borderTopWidth = 1,
|
||||
borderTopColor = new Color(1f, 1f, 1f, 0.12f)
|
||||
}
|
||||
};
|
||||
rootVisualElement.Add(toolBar);
|
||||
|
||||
RebuildTopBar();
|
||||
RebuildLayerBar();
|
||||
RebuildToolBar();
|
||||
RebuildInfo();
|
||||
}
|
||||
|
||||
public void MutateLayout(string undoName, Action mutation)
|
||||
{
|
||||
if (layout is null || mutation is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var previousStageId = state.selectedStageId;
|
||||
var previousEndpointId = state.selectedEndpointId;
|
||||
var previousConnectionId = state.selectedConnectionId;
|
||||
Undo.RecordObject(layout, undoName);
|
||||
mutation();
|
||||
layout.EnsureDefaults();
|
||||
layout.PruneEmptyStagesAndDanglingConnections();
|
||||
ClearInvalidSelection();
|
||||
EditorUtility.SetDirty(layout);
|
||||
|
||||
if (previousStageId != state.selectedStageId ||
|
||||
previousEndpointId != state.selectedEndpointId ||
|
||||
previousConnectionId != state.selectedConnectionId)
|
||||
{
|
||||
SyncActiveLayerToSelection(true);
|
||||
}
|
||||
|
||||
canvas?.RequestRepaint();
|
||||
RebuildTopBar();
|
||||
RebuildLayerBar();
|
||||
RebuildToolBar();
|
||||
inspector?.Rebuild();
|
||||
RebuildInfo();
|
||||
Repaint();
|
||||
}
|
||||
|
||||
public WorldLayoutSO Layout => layout;
|
||||
|
||||
public void SetHoverTile(JWorldTile? tile)
|
||||
{
|
||||
state.hoverTile = tile;
|
||||
RebuildInfo();
|
||||
}
|
||||
|
||||
public void RequestRebuildInfo()
|
||||
{
|
||||
RebuildInfo();
|
||||
}
|
||||
|
||||
public void RequestSelectionRebuild()
|
||||
{
|
||||
SyncActiveLayerToSelection(true);
|
||||
canvas?.RequestRepaint();
|
||||
RebuildLayerBar();
|
||||
inspector?.Rebuild();
|
||||
RebuildInfo();
|
||||
Repaint();
|
||||
}
|
||||
|
||||
public void BeginStagePlacement(WorldStageKind stageKind)
|
||||
{
|
||||
if (state.pendingStagePlacementKind is null)
|
||||
{
|
||||
state.toolBeforeStagePlacement = state.activeTool;
|
||||
}
|
||||
|
||||
state.pendingStagePlacementKind = stageKind;
|
||||
state.pendingAnchorEndpointId = null;
|
||||
canvas?.RequestRepaint();
|
||||
RebuildTopBar();
|
||||
RebuildToolBar();
|
||||
RebuildInfo();
|
||||
Repaint();
|
||||
}
|
||||
|
||||
public void CancelStagePlacement()
|
||||
{
|
||||
if (state.pendingStagePlacementKind is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
state.pendingStagePlacementKind = null;
|
||||
state.activeTool = state.toolBeforeStagePlacement;
|
||||
canvas?.RequestRepaint();
|
||||
RebuildTopBar();
|
||||
RebuildToolBar();
|
||||
RebuildInfo();
|
||||
Repaint();
|
||||
}
|
||||
|
||||
public void SelectStage(string stageId)
|
||||
{
|
||||
state.selectedStageId = stageId;
|
||||
state.selectedEndpointId = null;
|
||||
state.selectedConnectionId = null;
|
||||
RequestSelectionRebuild();
|
||||
}
|
||||
|
||||
public void SelectEndpoint(string endpointId)
|
||||
{
|
||||
var endpoint = layout?.FindEndpoint(endpointId);
|
||||
if (endpoint is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
state.selectedStageId = endpoint.stageId;
|
||||
state.selectedEndpointId = endpoint.id;
|
||||
state.selectedConnectionId = null;
|
||||
RequestSelectionRebuild();
|
||||
}
|
||||
|
||||
public void SelectConnection(string connectionId)
|
||||
{
|
||||
var connection = FindConnection(connectionId);
|
||||
if (connection is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var endpointA = layout.FindEndpoint(connection.endpointAId);
|
||||
var endpointB = layout.FindEndpoint(connection.endpointBId);
|
||||
var endpoint = PickConnectionEndpointForCurrentLayer(endpointA, endpointB);
|
||||
state.selectedStageId = endpoint?.stageId;
|
||||
state.selectedEndpointId = null;
|
||||
state.selectedConnectionId = connection.id;
|
||||
RequestSelectionRebuild();
|
||||
}
|
||||
|
||||
private void RebuildTopBar()
|
||||
{
|
||||
if (topBar is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
topBar.Clear();
|
||||
|
||||
var layoutField = new ObjectField("World Layout")
|
||||
{
|
||||
objectType = typeof(WorldLayoutSO),
|
||||
value = layout,
|
||||
style =
|
||||
{
|
||||
minWidth = 240
|
||||
}
|
||||
};
|
||||
layoutField.RegisterValueChangedCallback(evt => SetLayout(evt.newValue as WorldLayoutSO));
|
||||
topBar.Add(layoutField);
|
||||
|
||||
topBar.Add(new Button(CreateNewLayoutAsset)
|
||||
{
|
||||
text = "New",
|
||||
style = { marginLeft = 6 }
|
||||
});
|
||||
|
||||
if (layout is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
layout.EnsureDefaults();
|
||||
|
||||
var graphField = new ObjectField("J Graph")
|
||||
{
|
||||
objectType = typeof(JGraphSO),
|
||||
value = graph,
|
||||
style =
|
||||
{
|
||||
marginLeft = 8,
|
||||
minWidth = 200
|
||||
}
|
||||
};
|
||||
graphField.RegisterValueChangedCallback(evt =>
|
||||
{
|
||||
graph = evt.newValue as JGraphSO;
|
||||
RebuildTopBar();
|
||||
});
|
||||
topBar.Add(graphField);
|
||||
|
||||
topBar.Add(new Button(CreateNewGraphAsset)
|
||||
{
|
||||
text = "+ JGraphSO",
|
||||
style = { marginLeft = 4 }
|
||||
});
|
||||
|
||||
topBar.Add(new Button(ValidateLayout)
|
||||
{
|
||||
text = "Validate",
|
||||
style = { marginLeft = 8 }
|
||||
});
|
||||
|
||||
var commit = new Button(CommitJourney)
|
||||
{
|
||||
text = "Commit Journey",
|
||||
style = { marginLeft = 4 }
|
||||
};
|
||||
commit.SetEnabled(graph is not null);
|
||||
topBar.Add(commit);
|
||||
|
||||
topBar.Add(new Button(SaveLayout)
|
||||
{
|
||||
text = "Save",
|
||||
style = { marginLeft = 8 }
|
||||
});
|
||||
}
|
||||
|
||||
private void RebuildLayerBar()
|
||||
{
|
||||
if (layerBar is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
layerBar.Clear();
|
||||
|
||||
if (layout is null)
|
||||
{
|
||||
layerBar.Add(new Label("Layers"));
|
||||
return;
|
||||
}
|
||||
|
||||
layout.EnsureDefaults();
|
||||
state.activeLayer = layout.ClampLayer(state.activeLayer);
|
||||
|
||||
var title = new Label("Layers")
|
||||
{
|
||||
style =
|
||||
{
|
||||
unityFontStyleAndWeight = FontStyle.Bold,
|
||||
marginBottom = 4
|
||||
}
|
||||
};
|
||||
layerBar.Add(title);
|
||||
|
||||
var topControls = new VisualElement
|
||||
{
|
||||
style =
|
||||
{
|
||||
flexDirection = FlexDirection.Row,
|
||||
marginBottom = 6
|
||||
}
|
||||
};
|
||||
var addTopLayer = new Button(delegate
|
||||
{
|
||||
MutateLayout("Add upper world layer", delegate
|
||||
{
|
||||
layout.maxWorldLayer += 1;
|
||||
state.activeLayer = layout.maxWorldLayer;
|
||||
});
|
||||
})
|
||||
{
|
||||
text = "+",
|
||||
style =
|
||||
{
|
||||
flexGrow = 1f,
|
||||
marginRight = 2,
|
||||
height = 24
|
||||
}
|
||||
};
|
||||
topControls.Add(addTopLayer);
|
||||
|
||||
var removeTopLayer = new Button(delegate
|
||||
{
|
||||
MutateLayout("Remove upper world layer", delegate
|
||||
{
|
||||
if (layout.maxWorldLayer > layout.minWorldLayer && !LayerHasStages(layout.maxWorldLayer))
|
||||
{
|
||||
layout.maxWorldLayer -= 1;
|
||||
state.activeLayer = layout.ClampLayer(state.activeLayer);
|
||||
}
|
||||
});
|
||||
})
|
||||
{
|
||||
text = "-",
|
||||
style =
|
||||
{
|
||||
flexGrow = 1f,
|
||||
marginLeft = 2,
|
||||
height = 24
|
||||
}
|
||||
};
|
||||
removeTopLayer.SetEnabled(layout.maxWorldLayer > layout.minWorldLayer && !LayerHasStages(layout.maxWorldLayer));
|
||||
topControls.Add(removeTopLayer);
|
||||
layerBar.Add(topControls);
|
||||
|
||||
for (var layer = layout.maxWorldLayer; layer >= layout.minWorldLayer; layer--)
|
||||
{
|
||||
var capturedLayer = layer;
|
||||
var button = new Button(delegate
|
||||
{
|
||||
state.activeLayer = capturedLayer;
|
||||
canvas?.RequestRepaint();
|
||||
RebuildLayerBar();
|
||||
inspector?.Rebuild();
|
||||
RebuildInfo();
|
||||
})
|
||||
{
|
||||
text = FormatLayer(capturedLayer),
|
||||
style =
|
||||
{
|
||||
marginBottom = 3,
|
||||
height = 26
|
||||
}
|
||||
};
|
||||
|
||||
if (capturedLayer == state.activeLayer)
|
||||
{
|
||||
button.style.backgroundColor = new Color(1f, 0.86f, 0.32f, 0.45f);
|
||||
button.style.color = Color.white;
|
||||
button.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
}
|
||||
|
||||
layerBar.Add(button);
|
||||
}
|
||||
|
||||
var bottomControls = new VisualElement
|
||||
{
|
||||
style =
|
||||
{
|
||||
flexDirection = FlexDirection.Row,
|
||||
marginTop = 6
|
||||
}
|
||||
};
|
||||
var addBottomLayer = new Button(delegate
|
||||
{
|
||||
MutateLayout("Add lower world layer", delegate
|
||||
{
|
||||
layout.minWorldLayer -= 1;
|
||||
state.activeLayer = layout.minWorldLayer;
|
||||
});
|
||||
})
|
||||
{
|
||||
text = "+",
|
||||
style =
|
||||
{
|
||||
flexGrow = 1f,
|
||||
marginRight = 2,
|
||||
height = 24
|
||||
}
|
||||
};
|
||||
bottomControls.Add(addBottomLayer);
|
||||
|
||||
var removeBottomLayer = new Button(delegate
|
||||
{
|
||||
MutateLayout("Remove lower world layer", delegate
|
||||
{
|
||||
if (layout.minWorldLayer < layout.maxWorldLayer && !LayerHasStages(layout.minWorldLayer))
|
||||
{
|
||||
layout.minWorldLayer += 1;
|
||||
state.activeLayer = layout.ClampLayer(state.activeLayer);
|
||||
}
|
||||
});
|
||||
})
|
||||
{
|
||||
text = "-",
|
||||
style =
|
||||
{
|
||||
flexGrow = 1f,
|
||||
marginLeft = 2,
|
||||
height = 24
|
||||
}
|
||||
};
|
||||
removeBottomLayer.SetEnabled(layout.minWorldLayer < layout.maxWorldLayer && !LayerHasStages(layout.minWorldLayer));
|
||||
bottomControls.Add(removeBottomLayer);
|
||||
layerBar.Add(bottomControls);
|
||||
}
|
||||
|
||||
private bool LayerHasStages(int layer)
|
||||
{
|
||||
if (layout is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var stage in layout.stages)
|
||||
{
|
||||
if (stage != null && stage.worldLayer == layer)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void RebuildToolBar()
|
||||
{
|
||||
if (toolBar is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
toolBar.Clear();
|
||||
toolBar.Add(new Label("Units")
|
||||
{
|
||||
style =
|
||||
{
|
||||
unityFontStyleAndWeight = FontStyle.Bold,
|
||||
marginRight = 8
|
||||
}
|
||||
});
|
||||
|
||||
AddUnitButton(WorldStageKind.Stage, "+ Stage", "Placing Stage");
|
||||
AddUnitButton(WorldStageKind.SavePoint, "+ Save Point", "Placing Save");
|
||||
|
||||
var separator = new VisualElement
|
||||
{
|
||||
style =
|
||||
{
|
||||
width = 1,
|
||||
height = 24,
|
||||
marginLeft = 8,
|
||||
marginRight = 8,
|
||||
backgroundColor = new Color(1f, 1f, 1f, 0.18f)
|
||||
}
|
||||
};
|
||||
toolBar.Add(separator);
|
||||
|
||||
toolBar.Add(new Label("Tools")
|
||||
{
|
||||
style =
|
||||
{
|
||||
unityFontStyleAndWeight = FontStyle.Bold,
|
||||
marginRight = 8
|
||||
}
|
||||
});
|
||||
|
||||
AddToolButton(WorldEditorTool.Select, "Select");
|
||||
AddToolButton(WorldEditorTool.PaintStage, "Paint");
|
||||
AddToolButton(WorldEditorTool.EraseStage, "Erase");
|
||||
AddToolButton(WorldEditorTool.Socket, "Socket");
|
||||
AddToolButton(WorldEditorTool.Anchor, "Anchor");
|
||||
AddToolButton(WorldEditorTool.Lift, "Lift");
|
||||
}
|
||||
|
||||
private void AddUnitButton(WorldStageKind stageKind, string label, string placingLabel)
|
||||
{
|
||||
var button = new Button(delegate { BeginStagePlacement(stageKind); })
|
||||
{
|
||||
text = state.pendingStagePlacementKind == stageKind ? placingLabel : label,
|
||||
style =
|
||||
{
|
||||
marginRight = 4,
|
||||
minWidth = stageKind == WorldStageKind.SavePoint ? 110 : 82,
|
||||
height = 28
|
||||
}
|
||||
};
|
||||
|
||||
if (state.pendingStagePlacementKind == stageKind)
|
||||
{
|
||||
button.style.backgroundColor = new Color(1f, 0.1f, 0.95f, 0.35f);
|
||||
button.style.color = Color.white;
|
||||
button.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
}
|
||||
|
||||
toolBar.Add(button);
|
||||
}
|
||||
|
||||
private void AddToolButton(WorldEditorTool tool, string label)
|
||||
{
|
||||
var button = new Button(delegate
|
||||
{
|
||||
state.activeTool = tool;
|
||||
canvas?.RequestRepaint();
|
||||
RebuildToolBar();
|
||||
inspector?.Rebuild();
|
||||
RebuildInfo();
|
||||
})
|
||||
{
|
||||
text = label,
|
||||
style =
|
||||
{
|
||||
marginRight = 4,
|
||||
minWidth = 76,
|
||||
height = 28
|
||||
}
|
||||
};
|
||||
|
||||
if (state.activeTool == tool)
|
||||
{
|
||||
button.style.backgroundColor = new Color(1f, 0.86f, 0.32f, 0.45f);
|
||||
button.style.color = Color.white;
|
||||
button.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
}
|
||||
|
||||
toolBar.Add(button);
|
||||
}
|
||||
|
||||
private static string FormatLayer(int layer)
|
||||
{
|
||||
if (layer > 0)
|
||||
{
|
||||
return "+" + layer;
|
||||
}
|
||||
|
||||
return layer.ToString();
|
||||
}
|
||||
|
||||
private void RebuildInfo()
|
||||
{
|
||||
if (infoLabel is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (layout is null)
|
||||
{
|
||||
infoLabel.text = "Select or create a WorldLayoutSO.";
|
||||
return;
|
||||
}
|
||||
|
||||
var selected = layout.FindStage(state.selectedStageId);
|
||||
var selectedEndpoint = layout.FindEndpoint(state.selectedEndpointId);
|
||||
var selectedConnection = FindConnection(state.selectedConnectionId);
|
||||
var hoverText = state.hoverTile.HasValue
|
||||
? " | Tile: (" + state.hoverTile.Value.x + ", " + state.hoverTile.Value.y + ")"
|
||||
: " | Tile: -";
|
||||
var anchorText = string.IsNullOrEmpty(state.pendingAnchorEndpointId)
|
||||
? string.Empty
|
||||
: " | Anchor link armed";
|
||||
var placementText = state.pendingStagePlacementKind.HasValue
|
||||
? " | Placing " + state.pendingStagePlacementKind.Value + " (click to deploy, Esc to cancel)"
|
||||
: string.Empty;
|
||||
var selectionText = "No selection.";
|
||||
if (selectedConnection is not null)
|
||||
{
|
||||
selectionText = "Selected connection: " + selectedConnection.id;
|
||||
}
|
||||
else if (selectedEndpoint is not null)
|
||||
{
|
||||
selectionText = "Selected " + selectedEndpoint.kind + ": " + selectedEndpoint.id;
|
||||
}
|
||||
else if (selected is not null)
|
||||
{
|
||||
selectionText = "Selected: " + selected.displayName + " (" + selected.id + ")";
|
||||
}
|
||||
|
||||
infoLabel.text = selectionText + hoverText + anchorText + placementText;
|
||||
}
|
||||
|
||||
private void SetLayout(WorldLayoutSO newLayout)
|
||||
{
|
||||
layout = newLayout;
|
||||
layout?.EnsureDefaults();
|
||||
if (layout is not null)
|
||||
{
|
||||
state.activeLayer = layout.ClampLayer(state.activeLayer);
|
||||
}
|
||||
|
||||
if (layout?.FindStage(state.selectedStageId) is null)
|
||||
{
|
||||
state.selectedStageId = null;
|
||||
}
|
||||
|
||||
if (layout?.FindEndpoint(state.selectedEndpointId) is null)
|
||||
{
|
||||
state.selectedEndpointId = null;
|
||||
}
|
||||
|
||||
if (FindConnection(state.selectedConnectionId) is null)
|
||||
{
|
||||
state.selectedConnectionId = null;
|
||||
}
|
||||
|
||||
canvas?.SetLayout(layout);
|
||||
inspector?.SetLayout(layout);
|
||||
RebuildTopBar();
|
||||
RebuildLayerBar();
|
||||
inspector?.Rebuild();
|
||||
RebuildInfo();
|
||||
}
|
||||
|
||||
private void ClearInvalidSelection()
|
||||
{
|
||||
if (layout is null)
|
||||
{
|
||||
state.selectedStageId = null;
|
||||
state.selectedEndpointId = null;
|
||||
state.selectedConnectionId = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (layout.FindStage(state.selectedStageId) is null)
|
||||
{
|
||||
state.selectedStageId = null;
|
||||
}
|
||||
|
||||
if (layout.FindEndpoint(state.selectedEndpointId) is null)
|
||||
{
|
||||
state.selectedEndpointId = null;
|
||||
}
|
||||
|
||||
if (FindConnection(state.selectedConnectionId) is null)
|
||||
{
|
||||
state.selectedConnectionId = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void SyncActiveLayerToSelection(bool frameWhenLayerChanges)
|
||||
{
|
||||
if (layout is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
layout.EnsureDefaults();
|
||||
var previousLayer = state.activeLayer;
|
||||
|
||||
var selectedEndpoint = layout.FindEndpoint(state.selectedEndpointId);
|
||||
if (selectedEndpoint is not null)
|
||||
{
|
||||
var endpointStage = layout.FindStage(selectedEndpoint.stageId);
|
||||
if (endpointStage is not null)
|
||||
{
|
||||
state.activeLayer = layout.ClampLayer(endpointStage.worldLayer);
|
||||
FrameSelectionIfLayerChanged(previousLayer, frameWhenLayerChanges);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var selectedConnection = FindConnection(state.selectedConnectionId);
|
||||
if (selectedConnection is not null)
|
||||
{
|
||||
var endpointA = layout.FindEndpoint(selectedConnection.endpointAId);
|
||||
var endpointB = layout.FindEndpoint(selectedConnection.endpointBId);
|
||||
var endpoint = PickConnectionEndpointForSelectedStage(endpointA, endpointB) ??
|
||||
PickConnectionEndpointForCurrentLayer(endpointA, endpointB);
|
||||
var endpointStage = endpoint is null ? null : layout.FindStage(endpoint.stageId);
|
||||
if (endpointStage is not null)
|
||||
{
|
||||
state.activeLayer = layout.ClampLayer(endpointStage.worldLayer);
|
||||
FrameSelectionIfLayerChanged(previousLayer, frameWhenLayerChanges);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var selectedStage = layout.FindStage(state.selectedStageId);
|
||||
if (selectedStage is not null)
|
||||
{
|
||||
state.activeLayer = layout.ClampLayer(selectedStage.worldLayer);
|
||||
FrameSelectionIfLayerChanged(previousLayer, frameWhenLayerChanges);
|
||||
}
|
||||
}
|
||||
|
||||
private void FrameSelectionIfLayerChanged(int previousLayer, bool frameWhenLayerChanges)
|
||||
{
|
||||
if (frameWhenLayerChanges && previousLayer != state.activeLayer)
|
||||
{
|
||||
canvas?.FrameSelection();
|
||||
}
|
||||
}
|
||||
|
||||
private WorldEndpointAuthoring PickConnectionEndpointForSelectedStage(
|
||||
WorldEndpointAuthoring endpointA,
|
||||
WorldEndpointAuthoring endpointB)
|
||||
{
|
||||
if (endpointA is not null && endpointA.stageId == state.selectedStageId)
|
||||
{
|
||||
return endpointA;
|
||||
}
|
||||
|
||||
if (endpointB is not null && endpointB.stageId == state.selectedStageId)
|
||||
{
|
||||
return endpointB;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private WorldEndpointAuthoring PickConnectionEndpointForCurrentLayer(
|
||||
WorldEndpointAuthoring endpointA,
|
||||
WorldEndpointAuthoring endpointB)
|
||||
{
|
||||
var stageA = endpointA is null ? null : layout.FindStage(endpointA.stageId);
|
||||
if (stageA is not null && stageA.worldLayer == state.activeLayer)
|
||||
{
|
||||
return endpointA;
|
||||
}
|
||||
|
||||
var stageB = endpointB is null ? null : layout.FindStage(endpointB.stageId);
|
||||
if (stageB is not null && stageB.worldLayer == state.activeLayer)
|
||||
{
|
||||
return endpointB;
|
||||
}
|
||||
|
||||
return endpointA ?? endpointB;
|
||||
}
|
||||
|
||||
private void CreateNewLayoutAsset()
|
||||
{
|
||||
var path = EditorUtility.SaveFilePanelInProject(
|
||||
"Create WorldLayoutSO",
|
||||
"WorldLayout",
|
||||
"asset",
|
||||
"Choose where to create the new WorldLayoutSO asset.");
|
||||
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var asset = CreateInstance<WorldLayoutSO>();
|
||||
asset.EnsureDefaults();
|
||||
AssetDatabase.CreateAsset(asset, path);
|
||||
AssetDatabase.SaveAssets();
|
||||
SetLayout(asset);
|
||||
}
|
||||
|
||||
private void CreateNewGraphAsset()
|
||||
{
|
||||
var path = EditorUtility.SaveFilePanelInProject(
|
||||
"Create JGraphSO",
|
||||
"JGraph",
|
||||
"asset",
|
||||
"Choose where to create the published Journey graph asset.");
|
||||
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var asset = CreateInstance<JGraphSO>();
|
||||
AssetDatabase.CreateAsset(asset, path);
|
||||
AssetDatabase.SaveAssets();
|
||||
graph = asset;
|
||||
RebuildTopBar();
|
||||
}
|
||||
|
||||
private void CreateStage()
|
||||
{
|
||||
BeginStagePlacement(WorldStageKind.Stage);
|
||||
}
|
||||
|
||||
private void CreateSavePoint()
|
||||
{
|
||||
BeginStagePlacement(WorldStageKind.SavePoint);
|
||||
}
|
||||
|
||||
private WorldConnectionAuthoring FindConnection(string connectionId)
|
||||
{
|
||||
if (layout is null || string.IsNullOrEmpty(connectionId))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
layout.EnsureDefaults();
|
||||
foreach (var connection in layout.connections)
|
||||
{
|
||||
if (connection != null && connection.id == connectionId)
|
||||
{
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void SaveLayout()
|
||||
{
|
||||
if (layout is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EditorUtility.SetDirty(layout);
|
||||
AssetDatabase.SaveAssets();
|
||||
Debug.Log("Saved WorldLayoutSO: " + AssetDatabase.GetAssetPath(layout));
|
||||
}
|
||||
|
||||
private void ValidateLayout()
|
||||
{
|
||||
MutateLayout("Repair world layout before validation", delegate
|
||||
{
|
||||
layout.PruneEmptyStagesAndDanglingConnections();
|
||||
});
|
||||
ShowValidationMessages(WorldLayoutValidator.Validate(layout));
|
||||
}
|
||||
|
||||
private void CommitJourney()
|
||||
{
|
||||
var messages = JourneyCommitter.Commit(layout, graph);
|
||||
ShowValidationMessages(messages);
|
||||
if (!WorldLayoutValidator.HasErrors(messages))
|
||||
{
|
||||
Debug.Log("Committed Journey graph: " + AssetDatabase.GetAssetPath(graph));
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowValidationMessages(List<WorldValidationMessage> messages)
|
||||
{
|
||||
if (messages is null || messages.Count == 0)
|
||||
{
|
||||
Debug.Log("World Editor validation passed.");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var message in messages)
|
||||
{
|
||||
if (message is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
LogValidationMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
private static void LogValidationMessage(WorldValidationMessage message)
|
||||
{
|
||||
var text = "World Editor " + message.severity + ": " + message.message +
|
||||
(string.IsNullOrEmpty(message.objectId) ? string.Empty : " [" + message.objectId + "]");
|
||||
|
||||
if (message.severity == WorldValidationSeverity.Error)
|
||||
{
|
||||
Debug.LogError(text);
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.LogWarning(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a24a25a37da44f078a55114d872d2f66
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
308
Assets/Scripts/Editor/GON/WorldEditor/WorldInspectorPanel.cs
Normal file
308
Assets/Scripts/Editor/GON/WorldEditor/WorldInspectorPanel.cs
Normal file
@ -0,0 +1,308 @@
|
||||
using System.Collections.Generic;
|
||||
using Editor.GON.StageEditor;
|
||||
using Intrepid.Gameplay.Journey;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Editor.GON.WorldEditor
|
||||
{
|
||||
public sealed class WorldInspectorPanel : VisualElement
|
||||
{
|
||||
private readonly WorldEditorWindow owner;
|
||||
private readonly WorldEditorState state;
|
||||
private WorldLayoutSO worldLayout;
|
||||
|
||||
public WorldInspectorPanel(WorldEditorWindow owner, WorldEditorState state)
|
||||
{
|
||||
this.owner = owner;
|
||||
this.state = state;
|
||||
|
||||
style.width = 300;
|
||||
style.minWidth = 260;
|
||||
style.maxWidth = 380;
|
||||
style.paddingLeft = 8;
|
||||
style.paddingRight = 8;
|
||||
style.paddingTop = 8;
|
||||
style.paddingBottom = 8;
|
||||
style.borderLeftWidth = 1;
|
||||
style.borderLeftColor = new Color(1f, 1f, 1f, 0.12f);
|
||||
style.flexShrink = 0;
|
||||
}
|
||||
|
||||
public void SetLayout(WorldLayoutSO newLayout)
|
||||
{
|
||||
worldLayout = newLayout;
|
||||
Rebuild();
|
||||
}
|
||||
|
||||
public void Rebuild()
|
||||
{
|
||||
Clear();
|
||||
|
||||
Add(new Label("Inspector")
|
||||
{
|
||||
style =
|
||||
{
|
||||
unityFontStyleAndWeight = FontStyle.Bold,
|
||||
marginBottom = 8
|
||||
}
|
||||
});
|
||||
|
||||
if (worldLayout is null)
|
||||
{
|
||||
Add(new HelpBox("Select or create a WorldLayoutSO asset.", HelpBoxMessageType.Info));
|
||||
return;
|
||||
}
|
||||
|
||||
worldLayout.EnsureDefaults();
|
||||
|
||||
var selectedConnection = FindConnection(state.selectedConnectionId);
|
||||
if (selectedConnection is not null)
|
||||
{
|
||||
BuildConnectionInspector(selectedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
var selectedEndpoint = worldLayout.FindEndpoint(state.selectedEndpointId);
|
||||
if (selectedEndpoint is not null)
|
||||
{
|
||||
BuildEndpointInspector(selectedEndpoint);
|
||||
return;
|
||||
}
|
||||
|
||||
var selectedStage = worldLayout.FindStage(state.selectedStageId);
|
||||
if (selectedStage is not null)
|
||||
{
|
||||
BuildStageInspector(selectedStage);
|
||||
return;
|
||||
}
|
||||
|
||||
Add(new HelpBox("No world item selected.", HelpBoxMessageType.Info));
|
||||
}
|
||||
|
||||
private void BuildStageInspector(WorldStageAuthoring stage)
|
||||
{
|
||||
AddSection("Stage");
|
||||
AddReadOnlyLine("Id", stage.id);
|
||||
AddReadOnlyLine("Kind", stage.stageKind.ToString());
|
||||
AddReadOnlyLine("Layer", FormatLayer(stage.worldLayer));
|
||||
AddReadOnlyLine("Tiles", stage.occupiedTiles.Count.ToString());
|
||||
AddReadOnlyLine("Endpoints", CountStageEndpoints(stage.id).ToString());
|
||||
|
||||
var kind = new EnumField("Kind", stage.stageKind);
|
||||
kind.RegisterValueChangedCallback(evt => owner.MutateLayout("Change world stage kind", delegate
|
||||
{
|
||||
stage.stageKind = (WorldStageKind)evt.newValue;
|
||||
worldLayout.EnforceSavePointRules(stage);
|
||||
}));
|
||||
Add(kind);
|
||||
|
||||
var name = new TextField("Name")
|
||||
{
|
||||
value = stage.displayName
|
||||
};
|
||||
name.RegisterValueChangedCallback(evt => owner.MutateLayout("Rename world stage", delegate
|
||||
{
|
||||
stage.displayName = string.IsNullOrWhiteSpace(evt.newValue) ? "Stage" : evt.newValue;
|
||||
}));
|
||||
Add(name);
|
||||
|
||||
var color = new ColorField("Color")
|
||||
{
|
||||
value = stage.color
|
||||
};
|
||||
color.RegisterValueChangedCallback(evt => owner.MutateLayout("Change world stage color", delegate
|
||||
{
|
||||
stage.color = evt.newValue;
|
||||
}));
|
||||
Add(color);
|
||||
|
||||
var definition = new ObjectField("Stage Definition")
|
||||
{
|
||||
objectType = typeof(StageDefinition),
|
||||
value = stage.stageDefinition
|
||||
};
|
||||
definition.RegisterValueChangedCallback(evt => owner.MutateLayout("Assign stage definition", delegate
|
||||
{
|
||||
stage.stageDefinition = evt.newValue as StageDefinition;
|
||||
}));
|
||||
Add(definition);
|
||||
}
|
||||
|
||||
private void BuildEndpointInspector(WorldEndpointAuthoring endpoint)
|
||||
{
|
||||
var stage = worldLayout.FindStage(endpoint.stageId);
|
||||
|
||||
AddSection(endpoint.kind.ToString());
|
||||
AddReadOnlyLine("Id", endpoint.id);
|
||||
AddReadOnlyLine("Stage", stage is null ? endpoint.stageId : stage.displayName);
|
||||
AddReadOnlyLine("Layer", stage is null ? "-" : FormatLayer(stage.worldLayer));
|
||||
AddReadOnlyLine("Tile", "(" + endpoint.worldTile.x + ", " + endpoint.worldTile.y + ")");
|
||||
|
||||
if (endpoint.kind == JEndpointKind.Socket)
|
||||
{
|
||||
AddReadOnlyLine("Face", endpoint.socketFace.ToString());
|
||||
}
|
||||
|
||||
var required = new Toggle("Required")
|
||||
{
|
||||
value = endpoint.required
|
||||
};
|
||||
required.RegisterValueChangedCallback(evt => owner.MutateLayout("Toggle endpoint required", delegate
|
||||
{
|
||||
endpoint.required = evt.newValue;
|
||||
}));
|
||||
Add(required);
|
||||
|
||||
var connections = FindConnectionsForEndpoint(endpoint.id);
|
||||
AddReadOnlyLine("Connections", connections.Count.ToString());
|
||||
foreach (var connection in connections)
|
||||
{
|
||||
AddConnectionButton(connection);
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildConnectionInspector(WorldConnectionAuthoring connection)
|
||||
{
|
||||
AddSection("JConnection");
|
||||
AddReadOnlyLine("Id", connection.id);
|
||||
|
||||
var endpointA = worldLayout.FindEndpoint(connection.endpointAId);
|
||||
var endpointB = worldLayout.FindEndpoint(connection.endpointBId);
|
||||
AddEndpointButton("Endpoint A", endpointA, connection.endpointAId);
|
||||
AddEndpointButton("Endpoint B", endpointB, connection.endpointBId);
|
||||
|
||||
var directionality = new EnumField("Direction", connection.directionality);
|
||||
directionality.RegisterValueChangedCallback(evt => owner.MutateLayout("Change connection direction", delegate
|
||||
{
|
||||
connection.directionality = (JConnectionDirectionality)evt.newValue;
|
||||
}));
|
||||
Add(directionality);
|
||||
}
|
||||
|
||||
private void AddConnectionButton(WorldConnectionAuthoring connection)
|
||||
{
|
||||
var button = new Button(delegate
|
||||
{
|
||||
owner.SelectConnection(connection.id);
|
||||
})
|
||||
{
|
||||
text = "Connection: " + connection.id,
|
||||
style =
|
||||
{
|
||||
marginTop = 4,
|
||||
unityTextAlign = TextAnchor.MiddleLeft
|
||||
}
|
||||
};
|
||||
Add(button);
|
||||
}
|
||||
|
||||
private void AddEndpointButton(string label, WorldEndpointAuthoring endpoint, string fallbackId)
|
||||
{
|
||||
var text = endpoint is null
|
||||
? fallbackId + " (missing)"
|
||||
: endpoint.kind + " " + endpoint.id;
|
||||
var button = new Button(delegate
|
||||
{
|
||||
if (endpoint is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
owner.SelectEndpoint(endpoint.id);
|
||||
})
|
||||
{
|
||||
text = label + ": " + text,
|
||||
style =
|
||||
{
|
||||
marginTop = 4,
|
||||
unityTextAlign = TextAnchor.MiddleLeft
|
||||
}
|
||||
};
|
||||
button.SetEnabled(endpoint is not null);
|
||||
Add(button);
|
||||
}
|
||||
|
||||
private List<WorldConnectionAuthoring> FindConnectionsForEndpoint(string endpointId)
|
||||
{
|
||||
var result = new List<WorldConnectionAuthoring>();
|
||||
foreach (var connection in worldLayout.connections)
|
||||
{
|
||||
if (connection == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (connection.endpointAId == endpointId || connection.endpointBId == endpointId)
|
||||
{
|
||||
result.Add(connection);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private WorldConnectionAuthoring FindConnection(string connectionId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(connectionId))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach (var connection in worldLayout.connections)
|
||||
{
|
||||
if (connection != null && connection.id == connectionId)
|
||||
{
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private int CountStageEndpoints(string stageId)
|
||||
{
|
||||
var count = 0;
|
||||
foreach (var endpoint in worldLayout.endpoints)
|
||||
{
|
||||
if (endpoint != null && endpoint.stageId == stageId)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
private void AddSection(string text)
|
||||
{
|
||||
Add(new Label(text)
|
||||
{
|
||||
style =
|
||||
{
|
||||
unityFontStyleAndWeight = FontStyle.Bold,
|
||||
marginTop = 4,
|
||||
marginBottom = 6
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void AddReadOnlyLine(string label, string value)
|
||||
{
|
||||
Add(new Label(label + ": " + value)
|
||||
{
|
||||
style =
|
||||
{
|
||||
marginBottom = 3,
|
||||
opacity = 0.85f
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static string FormatLayer(int layer)
|
||||
{
|
||||
return layer > 0 ? "+" + layer : layer.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2cf93c2a33314ae690dec73cb9b210e9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
418
Assets/Scripts/Editor/GON/WorldEditor/WorldLayoutSO.cs
Normal file
418
Assets/Scripts/Editor/GON/WorldEditor/WorldLayoutSO.cs
Normal file
@ -0,0 +1,418 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Editor.GON.StageEditor;
|
||||
using Intrepid.Gameplay.Journey;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Editor.GON.WorldEditor
|
||||
{
|
||||
public enum WorldStageKind
|
||||
{
|
||||
Stage = 0,
|
||||
SavePoint = 1
|
||||
}
|
||||
|
||||
[CreateAssetMenu(menuName = "GON/Editor/World Layout", fileName = "WorldLayout")]
|
||||
public sealed class WorldLayoutSO : ScriptableObject
|
||||
{
|
||||
public string id;
|
||||
public float worldTileSize = 24f;
|
||||
public float worldLayerHeight = 24f;
|
||||
public const string SavePointTag = "SavePoint";
|
||||
public int minWorldLayer = -2;
|
||||
public int maxWorldLayer = 2;
|
||||
public List<WorldStageAuthoring> stages = new();
|
||||
public List<WorldEndpointAuthoring> endpoints = new();
|
||||
public List<WorldConnectionAuthoring> connections = new();
|
||||
|
||||
public void EnsureDefaults()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(id))
|
||||
{
|
||||
id = Guid.NewGuid().ToString("N");
|
||||
}
|
||||
|
||||
if (worldTileSize <= 0f)
|
||||
{
|
||||
worldTileSize = 24f;
|
||||
}
|
||||
|
||||
if (worldLayerHeight <= 0f)
|
||||
{
|
||||
worldLayerHeight = 24f;
|
||||
}
|
||||
|
||||
if (minWorldLayer > maxWorldLayer)
|
||||
{
|
||||
(minWorldLayer, maxWorldLayer) = (maxWorldLayer, minWorldLayer);
|
||||
}
|
||||
|
||||
stages ??= new List<WorldStageAuthoring>();
|
||||
endpoints ??= new List<WorldEndpointAuthoring>();
|
||||
connections ??= new List<WorldConnectionAuthoring>();
|
||||
|
||||
foreach (var stage in stages)
|
||||
{
|
||||
stage?.EnsureDefaults();
|
||||
}
|
||||
}
|
||||
|
||||
public int ClampLayer(int layer)
|
||||
{
|
||||
EnsureDefaults();
|
||||
return Mathf.Clamp(layer, minWorldLayer, maxWorldLayer);
|
||||
}
|
||||
|
||||
public string CreateId(string prefix)
|
||||
{
|
||||
return prefix + "_" + Guid.NewGuid().ToString("N");
|
||||
}
|
||||
|
||||
public WorldStageAuthoring FindStage(string stageId)
|
||||
{
|
||||
EnsureDefaults();
|
||||
foreach (var stage in stages)
|
||||
{
|
||||
if (stage != null && stage.id == stageId)
|
||||
{
|
||||
return stage;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public WorldStageAuthoring FindStageAt(int worldLayer, JWorldTile tile)
|
||||
{
|
||||
EnsureDefaults();
|
||||
foreach (var stage in stages)
|
||||
{
|
||||
if (stage != null && stage.worldLayer == worldLayer && stage.ContainsTile(tile))
|
||||
{
|
||||
return stage;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public WorldEndpointAuthoring FindEndpoint(string endpointId)
|
||||
{
|
||||
EnsureDefaults();
|
||||
foreach (var endpoint in endpoints)
|
||||
{
|
||||
if (endpoint != null && endpoint.id == endpointId)
|
||||
{
|
||||
return endpoint;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool IsTileOccupiedByOther(string stageId, int worldLayer, JWorldTile tile)
|
||||
{
|
||||
var occupyingStage = FindStageAt(worldLayer, tile);
|
||||
return occupyingStage != null && occupyingStage.id != stageId;
|
||||
}
|
||||
|
||||
public WorldEndpointAuthoring FindEndpointAt(string stageId, JWorldTile tile, JEndpointKind kind)
|
||||
{
|
||||
EnsureDefaults();
|
||||
foreach (var endpoint in endpoints)
|
||||
{
|
||||
if (endpoint != null && endpoint.stageId == stageId && endpoint.kind == kind &&
|
||||
endpoint.worldTile.x == tile.x && endpoint.worldTile.y == tile.y)
|
||||
{
|
||||
return endpoint;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public WorldEndpointAuthoring FindSocketAt(string stageId, JWorldTile tile, JSocketFace face)
|
||||
{
|
||||
EnsureDefaults();
|
||||
foreach (var endpoint in endpoints)
|
||||
{
|
||||
if (endpoint != null &&
|
||||
endpoint.stageId == stageId &&
|
||||
endpoint.kind == JEndpointKind.Socket &&
|
||||
endpoint.socketFace == face &&
|
||||
endpoint.worldTile.x == tile.x &&
|
||||
endpoint.worldTile.y == tile.y)
|
||||
{
|
||||
return endpoint;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public WorldConnectionAuthoring FindConnectionBetween(string endpointAId, string endpointBId)
|
||||
{
|
||||
EnsureDefaults();
|
||||
foreach (var connection in connections)
|
||||
{
|
||||
if (connection == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((connection.endpointAId == endpointAId && connection.endpointBId == endpointBId) ||
|
||||
(connection.endpointAId == endpointBId && connection.endpointBId == endpointAId))
|
||||
{
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void RemoveEndpointAndConnections(string endpointId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(endpointId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureDefaults();
|
||||
for (var i = endpoints.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (endpoints[i] != null && endpoints[i].id == endpointId)
|
||||
{
|
||||
endpoints.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = connections.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var connection = connections[i];
|
||||
if (connection == null ||
|
||||
connection.endpointAId == endpointId ||
|
||||
connection.endpointBId == endpointId)
|
||||
{
|
||||
connections.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveStageAndOwnedData(string stageId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(stageId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureDefaults();
|
||||
var endpointIds = new List<string>();
|
||||
foreach (var endpoint in endpoints)
|
||||
{
|
||||
if (endpoint != null && endpoint.stageId == stageId)
|
||||
{
|
||||
endpointIds.Add(endpoint.id);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var endpointId in endpointIds)
|
||||
{
|
||||
RemoveEndpointAndConnections(endpointId);
|
||||
}
|
||||
|
||||
for (var i = stages.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (stages[i] != null && stages[i].id == stageId)
|
||||
{
|
||||
stages.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveEndpointsAtTile(string stageId, JWorldTile tile)
|
||||
{
|
||||
if (string.IsNullOrEmpty(stageId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureDefaults();
|
||||
var endpointIds = new List<string>();
|
||||
foreach (var endpoint in endpoints)
|
||||
{
|
||||
if (endpoint != null &&
|
||||
endpoint.stageId == stageId &&
|
||||
endpoint.worldTile.x == tile.x &&
|
||||
endpoint.worldTile.y == tile.y)
|
||||
{
|
||||
endpointIds.Add(endpoint.id);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var endpointId in endpointIds)
|
||||
{
|
||||
RemoveEndpointAndConnections(endpointId);
|
||||
}
|
||||
}
|
||||
|
||||
public bool PruneEmptyStagesAndDanglingConnections()
|
||||
{
|
||||
EnsureDefaults();
|
||||
var changed = false;
|
||||
for (var i = stages.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var stage = stages[i];
|
||||
stage?.EnsureDefaults();
|
||||
if (stage == null || stage.occupiedTiles.Count > 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
RemoveStageAndOwnedData(stage.id);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
for (var i = endpoints.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var endpoint = endpoints[i];
|
||||
var stage = endpoint == null ? null : FindStage(endpoint.stageId);
|
||||
if (endpoint == null || stage == null || !stage.ContainsTile(endpoint.worldTile))
|
||||
{
|
||||
if (endpoint != null)
|
||||
{
|
||||
RemoveEndpointAndConnections(endpoint.id);
|
||||
}
|
||||
else
|
||||
{
|
||||
endpoints.RemoveAt(i);
|
||||
}
|
||||
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = connections.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var connection = connections[i];
|
||||
if (connection == null ||
|
||||
FindEndpoint(connection.endpointAId) == null ||
|
||||
FindEndpoint(connection.endpointBId) == null)
|
||||
{
|
||||
connections.RemoveAt(i);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
public void EnforceSavePointRules(WorldStageAuthoring stage)
|
||||
{
|
||||
if (stage is null || stage.stageKind != WorldStageKind.SavePoint)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
stage.EnsureDefaults();
|
||||
if (stage.occupiedTiles.Count == 0)
|
||||
{
|
||||
stage.occupiedTiles.Add(new JWorldTile(0, 0));
|
||||
}
|
||||
|
||||
var keptTile = stage.occupiedTiles[0];
|
||||
stage.occupiedTiles.Clear();
|
||||
stage.occupiedTiles.Add(keptTile);
|
||||
|
||||
for (var i = endpoints.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var endpoint = endpoints[i];
|
||||
if (endpoint == null || endpoint.stageId != stage.id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var outsideSaveTile = endpoint.worldTile.x != keptTile.x || endpoint.worldTile.y != keptTile.y;
|
||||
if (outsideSaveTile || endpoint.kind is JEndpointKind.Anchor or JEndpointKind.Lift)
|
||||
{
|
||||
RemoveEndpointAndConnections(endpoint.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class WorldStageAuthoring
|
||||
{
|
||||
public string id;
|
||||
public string displayName;
|
||||
public WorldStageKind stageKind;
|
||||
public int worldLayer;
|
||||
public Color color = new(0.25f, 0.62f, 0.95f, 0.7f);
|
||||
public StageDefinition stageDefinition;
|
||||
public List<JWorldTile> occupiedTiles = new();
|
||||
|
||||
public void EnsureDefaults()
|
||||
{
|
||||
occupiedTiles ??= new List<JWorldTile>();
|
||||
if (string.IsNullOrWhiteSpace(displayName))
|
||||
{
|
||||
displayName = "Stage";
|
||||
}
|
||||
}
|
||||
|
||||
public bool ContainsTile(JWorldTile tile)
|
||||
{
|
||||
EnsureDefaults();
|
||||
foreach (var occupiedTile in occupiedTiles)
|
||||
{
|
||||
if (occupiedTile.x == tile.x && occupiedTile.y == tile.y)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void AddTile(JWorldTile tile)
|
||||
{
|
||||
EnsureDefaults();
|
||||
if (!ContainsTile(tile))
|
||||
{
|
||||
occupiedTiles.Add(tile);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveTile(JWorldTile tile)
|
||||
{
|
||||
EnsureDefaults();
|
||||
for (var i = occupiedTiles.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (occupiedTiles[i].x == tile.x && occupiedTiles[i].y == tile.y)
|
||||
{
|
||||
occupiedTiles.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class WorldEndpointAuthoring
|
||||
{
|
||||
public string id;
|
||||
public string stageId;
|
||||
public JWorldTile worldTile;
|
||||
public JEndpointKind kind;
|
||||
public bool required = true;
|
||||
public JSocketFace socketFace;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class WorldConnectionAuthoring
|
||||
{
|
||||
public string id;
|
||||
public string endpointAId;
|
||||
public string endpointBId;
|
||||
public JConnectionDirectionality directionality = JConnectionDirectionality.Bidirectional;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Editor/GON/WorldEditor/WorldLayoutSO.cs.meta
Normal file
11
Assets/Scripts/Editor/GON/WorldEditor/WorldLayoutSO.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8cbbff7dfcc24d2b9030f41f9f2ef718
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
306
Assets/Scripts/Editor/GON/WorldEditor/WorldLayoutValidator.cs
Normal file
306
Assets/Scripts/Editor/GON/WorldEditor/WorldLayoutValidator.cs
Normal file
@ -0,0 +1,306 @@
|
||||
using System.Collections.Generic;
|
||||
using Intrepid.Gameplay.Journey;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Editor.GON.WorldEditor
|
||||
{
|
||||
public static class WorldLayoutValidator
|
||||
{
|
||||
public static List<WorldValidationMessage> Validate(WorldLayoutSO layout)
|
||||
{
|
||||
var messages = new List<WorldValidationMessage>();
|
||||
if (layout is null)
|
||||
{
|
||||
messages.Add(new WorldValidationMessage(WorldValidationSeverity.Error, "No WorldLayoutSO selected."));
|
||||
return messages;
|
||||
}
|
||||
|
||||
layout.EnsureDefaults();
|
||||
ValidateStages(layout, messages);
|
||||
ValidateEndpoints(layout, messages);
|
||||
ValidateConnections(layout, messages);
|
||||
return messages;
|
||||
}
|
||||
|
||||
public static bool HasErrors(List<WorldValidationMessage> messages)
|
||||
{
|
||||
if (messages is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var message in messages)
|
||||
{
|
||||
if (message != null && message.severity == WorldValidationSeverity.Error)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void ValidateStages(WorldLayoutSO layout, List<WorldValidationMessage> messages)
|
||||
{
|
||||
var occupied = new Dictionary<string, string>();
|
||||
foreach (var stage in layout.stages)
|
||||
{
|
||||
if (stage is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
stage.EnsureDefaults();
|
||||
var endpointCount = 0;
|
||||
foreach (var endpoint in layout.endpoints)
|
||||
{
|
||||
if (endpoint != null && endpoint.stageId == stage.id)
|
||||
{
|
||||
endpointCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (endpointCount == 0)
|
||||
{
|
||||
messages.Add(new WorldValidationMessage(WorldValidationSeverity.Warning,
|
||||
"Stage has no Journey endpoints.", stage.id));
|
||||
}
|
||||
|
||||
if (stage.stageKind == WorldStageKind.SavePoint && stage.occupiedTiles.Count != 1)
|
||||
{
|
||||
messages.Add(new WorldValidationMessage(WorldValidationSeverity.Error,
|
||||
"Save Point stages must occupy exactly one WorldTile.", stage.id));
|
||||
}
|
||||
|
||||
foreach (var tile in stage.occupiedTiles)
|
||||
{
|
||||
var key = TileKey(stage.worldLayer, tile);
|
||||
if (occupied.TryGetValue(key, out var otherStageId) && otherStageId != stage.id)
|
||||
{
|
||||
messages.Add(new WorldValidationMessage(WorldValidationSeverity.Error,
|
||||
"WorldTile is occupied by more than one Stage in the same WorldLayer.", stage.id));
|
||||
}
|
||||
else
|
||||
{
|
||||
occupied[key] = stage.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ValidateEndpoints(WorldLayoutSO layout, List<WorldValidationMessage> messages)
|
||||
{
|
||||
var nonSocketByTile = new Dictionary<string, JEndpointKind>();
|
||||
var socketByFace = new HashSet<string>();
|
||||
|
||||
foreach (var endpoint in layout.endpoints)
|
||||
{
|
||||
if (endpoint is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var stage = layout.FindStage(endpoint.stageId);
|
||||
if (stage is null)
|
||||
{
|
||||
messages.Add(new WorldValidationMessage(WorldValidationSeverity.Error,
|
||||
"JEndpoint references a missing Stage.", endpoint.id));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!stage.ContainsTile(endpoint.worldTile))
|
||||
{
|
||||
messages.Add(new WorldValidationMessage(WorldValidationSeverity.Error,
|
||||
"JEndpoint is placed on a WorldTile not occupied by its Stage.", endpoint.id));
|
||||
}
|
||||
|
||||
if (stage.stageKind == WorldStageKind.SavePoint &&
|
||||
endpoint.kind is JEndpointKind.Anchor or JEndpointKind.Lift)
|
||||
{
|
||||
messages.Add(new WorldValidationMessage(WorldValidationSeverity.Error,
|
||||
"Save Point stages cannot contain JEndpointAnchor or JEndpointLift.", endpoint.id));
|
||||
}
|
||||
|
||||
if (endpoint.kind == JEndpointKind.Socket)
|
||||
{
|
||||
var socketKey = endpoint.stageId + ":" + endpoint.worldTile.x + ":" + endpoint.worldTile.y + ":" +
|
||||
endpoint.socketFace;
|
||||
if (!socketByFace.Add(socketKey))
|
||||
{
|
||||
messages.Add(new WorldValidationMessage(WorldValidationSeverity.Error,
|
||||
"More than one JEndpointSocket exists on the same tile face.", endpoint.id));
|
||||
}
|
||||
|
||||
var adjacent = Adjacent(endpoint.worldTile, endpoint.socketFace);
|
||||
if (stage.ContainsTile(adjacent))
|
||||
{
|
||||
messages.Add(new WorldValidationMessage(WorldValidationSeverity.Error,
|
||||
"JEndpointSocket is placed on an internal Stage face.", endpoint.id));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var key = TileKey(stage.worldLayer, endpoint.worldTile);
|
||||
if (nonSocketByTile.TryGetValue(key, out var existingKind) && existingKind != endpoint.kind)
|
||||
{
|
||||
messages.Add(new WorldValidationMessage(WorldValidationSeverity.Error,
|
||||
"JEndpointAnchor and JEndpointLift cannot coexist on the same WorldTile.", endpoint.id));
|
||||
}
|
||||
else
|
||||
{
|
||||
nonSocketByTile[key] = endpoint.kind;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ValidateConnections(WorldLayoutSO layout, List<WorldValidationMessage> messages)
|
||||
{
|
||||
var endpointConnectionCounts = new Dictionary<string, int>();
|
||||
foreach (var connection in layout.connections)
|
||||
{
|
||||
if (connection is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var endpointA = layout.FindEndpoint(connection.endpointAId);
|
||||
var endpointB = layout.FindEndpoint(connection.endpointBId);
|
||||
|
||||
if (endpointA is null || endpointB is null)
|
||||
{
|
||||
messages.Add(new WorldValidationMessage(WorldValidationSeverity.Error,
|
||||
"JConnection references a missing endpoint.", connection.id));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (endpointA.id == endpointB.id)
|
||||
{
|
||||
messages.Add(new WorldValidationMessage(WorldValidationSeverity.Error,
|
||||
"JConnection links an endpoint to itself.", connection.id));
|
||||
}
|
||||
|
||||
if (endpointA.kind != endpointB.kind)
|
||||
{
|
||||
messages.Add(new WorldValidationMessage(WorldValidationSeverity.Error,
|
||||
"JConnection links incompatible endpoint types.", connection.id));
|
||||
}
|
||||
|
||||
Increment(endpointConnectionCounts, endpointA.id);
|
||||
Increment(endpointConnectionCounts, endpointB.id);
|
||||
|
||||
ValidateConnectionGeometry(layout, connection, endpointA, endpointB, messages);
|
||||
}
|
||||
|
||||
foreach (var endpoint in layout.endpoints)
|
||||
{
|
||||
if (endpoint is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
endpointConnectionCounts.TryGetValue(endpoint.id, out var count);
|
||||
switch (endpoint.kind)
|
||||
{
|
||||
case JEndpointKind.Socket when count > 1:
|
||||
messages.Add(new WorldValidationMessage(WorldValidationSeverity.Error,
|
||||
"JEndpointSocket has more than one JConnection.", endpoint.id));
|
||||
break;
|
||||
case JEndpointKind.Lift when count > 2:
|
||||
messages.Add(new WorldValidationMessage(WorldValidationSeverity.Error,
|
||||
"JEndpointLift has more than two JConnections.", endpoint.id));
|
||||
break;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
messages.Add(new WorldValidationMessage(endpoint.required
|
||||
? WorldValidationSeverity.Error
|
||||
: WorldValidationSeverity.Warning,
|
||||
endpoint.required
|
||||
? "Required JEndpoint has no JConnection."
|
||||
: "Optional JEndpoint has no JConnection.",
|
||||
endpoint.id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ValidateConnectionGeometry(
|
||||
WorldLayoutSO layout,
|
||||
WorldConnectionAuthoring connection,
|
||||
WorldEndpointAuthoring endpointA,
|
||||
WorldEndpointAuthoring endpointB,
|
||||
List<WorldValidationMessage> messages)
|
||||
{
|
||||
if (endpointA.kind == JEndpointKind.Socket && endpointB.kind == JEndpointKind.Socket)
|
||||
{
|
||||
if (!AreOpposite(endpointA.socketFace, endpointB.socketFace) ||
|
||||
!IsAdjacentForFaces(endpointA.worldTile, endpointA.socketFace, endpointB.worldTile))
|
||||
{
|
||||
messages.Add(new WorldValidationMessage(WorldValidationSeverity.Error,
|
||||
"JEndpointSocket connections must use opposite faces on adjacent WorldTiles.", connection.id));
|
||||
}
|
||||
}
|
||||
|
||||
if (endpointA.kind == JEndpointKind.Lift && endpointB.kind == JEndpointKind.Lift)
|
||||
{
|
||||
var stageA = layout.FindStage(endpointA.stageId);
|
||||
var stageB = layout.FindStage(endpointB.stageId);
|
||||
if (endpointA.worldTile.x != endpointB.worldTile.x || endpointA.worldTile.y != endpointB.worldTile.y)
|
||||
{
|
||||
messages.Add(new WorldValidationMessage(WorldValidationSeverity.Error,
|
||||
"JEndpointLift connections must be aligned on the same 2D WorldTile coordinate.",
|
||||
connection.id));
|
||||
}
|
||||
|
||||
if (stageA != null && stageB != null &&
|
||||
Mathf.Abs(stageA.worldLayer - stageB.worldLayer) != 1)
|
||||
{
|
||||
messages.Add(new WorldValidationMessage(WorldValidationSeverity.Error,
|
||||
"JEndpointLift connections must connect adjacent WorldLayers.", connection.id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void Increment(Dictionary<string, int> counts, string key)
|
||||
{
|
||||
if (string.IsNullOrEmpty(key))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
counts.TryGetValue(key, out var count);
|
||||
counts[key] = count + 1;
|
||||
}
|
||||
|
||||
private static string TileKey(int layer, JWorldTile tile)
|
||||
{
|
||||
return layer + ":" + tile.x + ":" + tile.y;
|
||||
}
|
||||
|
||||
private static JWorldTile Adjacent(JWorldTile tile, JSocketFace face)
|
||||
{
|
||||
return face switch
|
||||
{
|
||||
JSocketFace.North => new JWorldTile(tile.x, tile.y - 1),
|
||||
JSocketFace.South => new JWorldTile(tile.x, tile.y + 1),
|
||||
JSocketFace.East => new JWorldTile(tile.x + 1, tile.y),
|
||||
_ => new JWorldTile(tile.x - 1, tile.y)
|
||||
};
|
||||
}
|
||||
|
||||
private static bool AreOpposite(JSocketFace a, JSocketFace b)
|
||||
{
|
||||
return (a == JSocketFace.North && b == JSocketFace.South) ||
|
||||
(a == JSocketFace.South && b == JSocketFace.North) ||
|
||||
(a == JSocketFace.East && b == JSocketFace.West) ||
|
||||
(a == JSocketFace.West && b == JSocketFace.East);
|
||||
}
|
||||
|
||||
private static bool IsAdjacentForFaces(JWorldTile a, JSocketFace faceA, JWorldTile b)
|
||||
{
|
||||
var expected = Adjacent(a, faceA);
|
||||
return expected.x == b.x && expected.y == b.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 86f52d9a97c44cb1b8593c99d411f5b1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1890
Assets/Scripts/Editor/GON/WorldEditor/WorldMapCanvas.cs
Normal file
1890
Assets/Scripts/Editor/GON/WorldEditor/WorldMapCanvas.cs
Normal file
File diff suppressed because it is too large
Load Diff
11
Assets/Scripts/Editor/GON/WorldEditor/WorldMapCanvas.cs.meta
Normal file
11
Assets/Scripts/Editor/GON/WorldEditor/WorldMapCanvas.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 817967f2b72043129f5018488de4c53d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
25
Assets/Scripts/Editor/GON/WorldEditor/WorldValidation.cs
Normal file
25
Assets/Scripts/Editor/GON/WorldEditor/WorldValidation.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System;
|
||||
|
||||
namespace Editor.GON.WorldEditor
|
||||
{
|
||||
public enum WorldValidationSeverity
|
||||
{
|
||||
Warning = 0,
|
||||
Error = 1
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class WorldValidationMessage
|
||||
{
|
||||
public WorldValidationSeverity severity;
|
||||
public string message;
|
||||
public string objectId;
|
||||
|
||||
public WorldValidationMessage(WorldValidationSeverity severity, string message, string objectId = null)
|
||||
{
|
||||
this.severity = severity;
|
||||
this.message = message;
|
||||
this.objectId = objectId;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e037255368a041d491478b61b7e0e75e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93fdd19587ea435285157d73a25958f0
|
||||
timeCreated: 1781500522
|
||||
3
Assets/Scripts/Intrepid/Gameplay/Journey.meta
Normal file
3
Assets/Scripts/Intrepid/Gameplay/Journey.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4d17ea30ca5144a099051de0e6b69242
|
||||
timeCreated: 1781870139
|
||||
33
Assets/Scripts/Intrepid/Gameplay/Journey/JConnection.cs
Normal file
33
Assets/Scripts/Intrepid/Gameplay/Journey/JConnection.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using System;
|
||||
|
||||
namespace Intrepid.Gameplay.Journey
|
||||
{
|
||||
[Serializable]
|
||||
public sealed class JConnection
|
||||
{
|
||||
public string id;
|
||||
public string endpointAId;
|
||||
public string endpointBId;
|
||||
public JConnectionDirectionality directionality = JConnectionDirectionality.Bidirectional;
|
||||
|
||||
public bool ContainsEndpoint(string endpointId)
|
||||
{
|
||||
return endpointAId == endpointId || endpointBId == endpointId;
|
||||
}
|
||||
|
||||
public string GetOtherEndpointId(string endpointId)
|
||||
{
|
||||
if (endpointAId == endpointId)
|
||||
{
|
||||
return endpointBId;
|
||||
}
|
||||
|
||||
if (endpointBId == endpointId)
|
||||
{
|
||||
return endpointAId;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Intrepid/Gameplay/Journey/JConnection.cs.meta
Normal file
11
Assets/Scripts/Intrepid/Gameplay/Journey/JConnection.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9c1fd63a9fe84c8fb09bb9c2e804ec8e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
21
Assets/Scripts/Intrepid/Gameplay/Journey/JEndpoint.cs
Normal file
21
Assets/Scripts/Intrepid/Gameplay/Journey/JEndpoint.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System;
|
||||
|
||||
namespace Intrepid.Gameplay.Journey
|
||||
{
|
||||
[Serializable]
|
||||
public sealed class JEndpoint
|
||||
{
|
||||
public string id;
|
||||
public string stageId;
|
||||
public JWorldTile worldTile;
|
||||
public JEndpointKind kind;
|
||||
public bool required;
|
||||
|
||||
// Used when kind is Socket. Ignored by Anchor and Lift endpoints.
|
||||
public JSocketFace socketFace;
|
||||
|
||||
public bool IsSocket => kind == JEndpointKind.Socket;
|
||||
public bool IsAnchor => kind == JEndpointKind.Anchor;
|
||||
public bool IsLift => kind == JEndpointKind.Lift;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Intrepid/Gameplay/Journey/JEndpoint.cs.meta
Normal file
11
Assets/Scripts/Intrepid/Gameplay/Journey/JEndpoint.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 71c2f06702924f18b413f79bb35f9af3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
102
Assets/Scripts/Intrepid/Gameplay/Journey/JGraphSO.cs
Normal file
102
Assets/Scripts/Intrepid/Gameplay/Journey/JGraphSO.cs
Normal file
@ -0,0 +1,102 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Intrepid.Gameplay.Journey
|
||||
{
|
||||
[CreateAssetMenu(menuName = "GON/Journey/J Graph", fileName = "JGraph")]
|
||||
public sealed class JGraphSO : ScriptableObject
|
||||
{
|
||||
public string sourceWorldLayoutId;
|
||||
public string publishedAt;
|
||||
public int schemaVersion = 1;
|
||||
public string contentHash;
|
||||
|
||||
public List<JStage> stages = new();
|
||||
public List<JEndpoint> endpoints = new();
|
||||
public List<JConnection> connections = new();
|
||||
|
||||
public void EnsureDefaults()
|
||||
{
|
||||
stages ??= new List<JStage>();
|
||||
endpoints ??= new List<JEndpoint>();
|
||||
connections ??= new List<JConnection>();
|
||||
|
||||
foreach (var stage in stages)
|
||||
{
|
||||
stage?.EnsureDefaults();
|
||||
}
|
||||
}
|
||||
|
||||
public JStage FindStage(string stageId)
|
||||
{
|
||||
EnsureDefaults();
|
||||
foreach (var stage in stages)
|
||||
{
|
||||
if (stage != null && stage.id == stageId)
|
||||
{
|
||||
return stage;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public JEndpoint FindEndpoint(string endpointId)
|
||||
{
|
||||
EnsureDefaults();
|
||||
foreach (var endpoint in endpoints)
|
||||
{
|
||||
if (endpoint != null && endpoint.id == endpointId)
|
||||
{
|
||||
return endpoint;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public JConnection FindConnection(string connectionId)
|
||||
{
|
||||
EnsureDefaults();
|
||||
foreach (var connection in connections)
|
||||
{
|
||||
if (connection != null && connection.id == connectionId)
|
||||
{
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<JEndpoint> GetEndpointsForStage(string stageId)
|
||||
{
|
||||
EnsureDefaults();
|
||||
var result = new List<JEndpoint>();
|
||||
foreach (var endpoint in endpoints)
|
||||
{
|
||||
if (endpoint != null && endpoint.stageId == stageId)
|
||||
{
|
||||
result.Add(endpoint);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<JConnection> GetConnectionsForEndpoint(string endpointId)
|
||||
{
|
||||
EnsureDefaults();
|
||||
var result = new List<JConnection>();
|
||||
foreach (var connection in connections)
|
||||
{
|
||||
if (connection != null && connection.ContainsEndpoint(endpointId))
|
||||
{
|
||||
result.Add(connection);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Intrepid/Gameplay/Journey/JGraphSO.cs.meta
Normal file
11
Assets/Scripts/Intrepid/Gameplay/Journey/JGraphSO.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fcb661d795ed4088af4ae73e4253f98b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
21
Assets/Scripts/Intrepid/Gameplay/Journey/JStage.cs
Normal file
21
Assets/Scripts/Intrepid/Gameplay/Journey/JStage.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Intrepid.Gameplay.Journey
|
||||
{
|
||||
[Serializable]
|
||||
public sealed class JStage
|
||||
{
|
||||
public string id;
|
||||
public string displayName;
|
||||
public int worldLayer;
|
||||
public List<JWorldTile> occupiedTiles = new();
|
||||
public List<string> tags = new();
|
||||
|
||||
public void EnsureDefaults()
|
||||
{
|
||||
occupiedTiles ??= new List<JWorldTile>();
|
||||
tags ??= new List<string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Intrepid/Gameplay/Journey/JStage.cs.meta
Normal file
11
Assets/Scripts/Intrepid/Gameplay/Journey/JStage.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5dbe6985a3384e0190ac342eb49eb4d9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
39
Assets/Scripts/Intrepid/Gameplay/Journey/JourneyTypes.cs
Normal file
39
Assets/Scripts/Intrepid/Gameplay/Journey/JourneyTypes.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using System;
|
||||
|
||||
namespace Intrepid.Gameplay.Journey
|
||||
{
|
||||
public enum JEndpointKind
|
||||
{
|
||||
Socket = 0,
|
||||
Anchor = 1,
|
||||
Lift = 2
|
||||
}
|
||||
|
||||
public enum JSocketFace
|
||||
{
|
||||
North = 0,
|
||||
South = 1,
|
||||
East = 2,
|
||||
West = 3
|
||||
}
|
||||
|
||||
public enum JConnectionDirectionality
|
||||
{
|
||||
Bidirectional = 0,
|
||||
AToB = 1,
|
||||
BToA = 2
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct JWorldTile
|
||||
{
|
||||
public int x;
|
||||
public int y;
|
||||
|
||||
public JWorldTile(int x, int y)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6fd7e60621d443e3a2f02fbb9ffcc801
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
2
discussion/index.ndjson
Normal file
2
discussion/index.ndjson
Normal file
@ -0,0 +1,2 @@
|
||||
{"type":"meta","next_id":{"DSC":2,"AGD":2,"DEC":2,"PLN":5,"LSN":2,"CLSN":1}}
|
||||
{"type":"discussion","id":"DSC-0001","status":"done","ticket":"world-editor-journey-spec","title":"World Editor / Journey Spec","created_at":"2026-06-19","updated_at":"2026-06-20","tags":["world-editor","journey","stage-contract","architecture"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0001","file":"discussion/lessons/DSC-0001-world-editor-journey-spec/LSN-0001-editor-authoring-runtime-publication.md","status":"done","created_at":"2026-06-20","updated_at":"2026-06-20"}]}
|
||||
@ -0,0 +1,52 @@
|
||||
---
|
||||
id: LSN-0001
|
||||
ticket: world-editor-journey-spec
|
||||
title: Separate editor authoring data from runtime Journey publication
|
||||
created: 2026-06-20
|
||||
tags:
|
||||
- world-editor
|
||||
- journey
|
||||
- unity
|
||||
- scriptableobjects
|
||||
---
|
||||
|
||||
## Context
|
||||
|
||||
The Gardens of Nil World Editor needs to organize the macro-world while the Stage Editor owns internal stage content. The first Journey implementation had to support editor iteration without letting unfinished authoring data leak into gameplay playtests.
|
||||
|
||||
The resulting model uses two ScriptableObject layers:
|
||||
|
||||
- `WorldLayoutSO` is editor-only authoring data for stages, footprints, endpoints, and connections.
|
||||
- `JGraphSO` is the published runtime Journey graph consumed by gameplay code.
|
||||
|
||||
## Key Decisions
|
||||
|
||||
### World Editor / Journey V1
|
||||
|
||||
**What:** Keep world authoring data under editor code and publish a separate runtime-safe Journey graph through an explicit commit action.
|
||||
|
||||
**Why:** Designers need to edit incomplete worlds without changing the runtime contract used by playtests. Gameplay code should depend on stable Journey data and must not reference editor-only types.
|
||||
|
||||
**Trade-offs:** The model requires a publication step and validation rules between authoring and runtime data. In exchange, it avoids coupling runtime traversal to mutable editor state and keeps Stage bake ownership separate from world topology authoring.
|
||||
|
||||
## Patterns and Algorithms
|
||||
|
||||
- Treat editor assets as work-in-progress sources of truth, not runtime APIs.
|
||||
- Publish runtime data through a deliberate commit action after validation.
|
||||
- Keep generated runtime records plain and queryable: `JStage`, `JEndpoint`, `JConnection`, and `JGraphSO`.
|
||||
- Use stable string ids for cross-editor contracts because Unity object references are not enough to bridge World Editor, Stage Editor, and runtime data safely.
|
||||
- Model physical transition space as stages, not as connections. `JConnection` remains logical and never owns space.
|
||||
|
||||
## Pitfalls
|
||||
|
||||
- If runtime code reads editor-only data directly, playtests can accidentally depend on incomplete authoring changes.
|
||||
- If connections own physical space, the boundary between World Editor and Stage Editor becomes ambiguous.
|
||||
- If validation does not prune stale authoring records, deleted or moved stages can leave invisible data that still affects Journey publication.
|
||||
- If StageDefinition becomes the runtime Journey contract, the Stage Editor and runtime traversal become coupled too early.
|
||||
|
||||
## Takeaways
|
||||
|
||||
- Use `WorldLayoutSO` for authoring and `JGraphSO` for runtime Journey.
|
||||
- Keep commit/publish explicit and validation-driven.
|
||||
- Keep Journey runtime code outside `Assets/Scripts/Editor`.
|
||||
- Preserve Stage Editor ownership of scene geometry and bake output.
|
||||
229
specs/world-editor-journey-v1.md
Normal file
229
specs/world-editor-journey-v1.md
Normal file
@ -0,0 +1,229 @@
|
||||
# World Editor / Journey V1 Specification
|
||||
|
||||
Source decision: `discussion/workflow/decisions/DEC-0001-world-editor-journey-v1.md`
|
||||
|
||||
## Purpose
|
||||
|
||||
The World Editor defines the macro-world contract for Gardens of Nil. It does not edit internal Stage content. Journey is the runtime-readable logical graph published from the World Editor.
|
||||
|
||||
This specification defines the V1 authoring and runtime boundary.
|
||||
|
||||
## Ownership Boundary
|
||||
|
||||
The World Editor SHALL own:
|
||||
|
||||
- macro WorldLayers;
|
||||
- WorldTile occupancy;
|
||||
- logical Stage placement;
|
||||
- Journey endpoints;
|
||||
- Journey connections;
|
||||
- commit-time validation;
|
||||
- publication of logical Journey data.
|
||||
|
||||
The Stage Editor SHALL own:
|
||||
|
||||
- internal Stage geometry;
|
||||
- floors inside a Stage;
|
||||
- Stage props;
|
||||
- Stage objects;
|
||||
- Stage scene generation;
|
||||
- Stage bake.
|
||||
|
||||
The World Editor commit MUST NOT create Stage scenes, Stage geometry, internal Stage objects, or baked Stage content.
|
||||
|
||||
## Authoring Asset
|
||||
|
||||
`WorldLayoutSO` is the editor-only authoring ScriptableObject for the World Editor.
|
||||
|
||||
`WorldLayoutSO` MUST contain:
|
||||
|
||||
- a stable layout id;
|
||||
- `worldTileSize`, defaulting to `24m`;
|
||||
- `worldLayerHeight`, defaulting to `24m`;
|
||||
- authoring Stage records;
|
||||
- occupied WorldTiles per Stage;
|
||||
- authoring endpoint records;
|
||||
- authoring connection records;
|
||||
- editor metadata.
|
||||
|
||||
`worldTileSize` and `worldLayerHeight` MUST be configurable. V1 defaults are `24m`.
|
||||
|
||||
`WorldLayoutSO` MAY reference editor-only Stage authoring data, including `StageDefinition`, but runtime code MUST NOT consume `WorldLayoutSO`.
|
||||
|
||||
## Runtime Asset
|
||||
|
||||
`JGraphSO` is the runtime Journey ScriptableObject.
|
||||
|
||||
Journey elements MUST use the `J` prefix. Journey ScriptableObjects MUST also use the `SO` suffix.
|
||||
|
||||
`JGraphSO` MUST contain:
|
||||
|
||||
- `sourceWorldLayoutId`;
|
||||
- `publishedAt`;
|
||||
- `schemaVersion`;
|
||||
- optional `contentHash`;
|
||||
- `JStage` records;
|
||||
- `JEndpoint` records;
|
||||
- `JConnection` records.
|
||||
|
||||
Runtime Journey code MUST consume `JGraphSO`. Runtime Journey code MUST NOT depend on `WorldLayoutSO`, `StageDefinition`, or any type under `Assets/Scripts/Editor`.
|
||||
|
||||
## World Model
|
||||
|
||||
The World Editor is 2D per `WorldLayer`.
|
||||
|
||||
A Stage:
|
||||
|
||||
- belongs to exactly one `WorldLayer`;
|
||||
- occupies a set of WorldTiles;
|
||||
- MUST NOT overlap another Stage on the same WorldLayer tile.
|
||||
|
||||
A WorldTile can be occupied by at most one Stage within a WorldLayer.
|
||||
|
||||
All physical space MUST belong to a Stage. `JConnection` MUST NOT own physical space. If a corridor, transition room, long lift, loading mask, or similar physical traversal space is needed, it MUST be represented as a Stage.
|
||||
|
||||
## JStage
|
||||
|
||||
`JStage` is the runtime logical representation of a Stage inside `JGraphSO`.
|
||||
|
||||
`JStage` MUST have a stable GUID/string id. Tags MAY be used for classification and lookup, but tags MUST NOT replace stable identity.
|
||||
|
||||
`JStage` is not Stage scene generation data and is not Stage bake data.
|
||||
|
||||
## Endpoints
|
||||
|
||||
Initial endpoint types are:
|
||||
|
||||
- `JEndpointSocket`;
|
||||
- `JEndpointAnchor`;
|
||||
- `JEndpointLift`.
|
||||
|
||||
Every endpoint MUST have:
|
||||
|
||||
- a stable GUID/string id;
|
||||
- an owning `JStage` id;
|
||||
- a WorldTile coordinate;
|
||||
- an endpoint type;
|
||||
- a required/optional flag.
|
||||
|
||||
### JEndpointSocket
|
||||
|
||||
`JEndpointSocket` represents a physical side connection on a free tile face.
|
||||
|
||||
It MUST:
|
||||
|
||||
- exist only on a free face of a Stage WorldTile;
|
||||
- use one of `North`, `South`, `East`, or `West`;
|
||||
- accept at most one `JConnection`;
|
||||
- connect only to another `JEndpointSocket`.
|
||||
|
||||
Socket-to-socket physical connections MUST connect opposite faces on adjacent WorldTiles.
|
||||
|
||||
### JEndpointAnchor
|
||||
|
||||
`JEndpointAnchor` represents an abstract travel point such as a portal, hub, or fast-travel anchor.
|
||||
|
||||
It MAY have multiple `JConnections`. Runtime destination selection for multi-connection anchors is outside V1.
|
||||
|
||||
### JEndpointLift
|
||||
|
||||
`JEndpointLift` represents macro vertical travel between WorldLayers.
|
||||
|
||||
It MUST:
|
||||
|
||||
- accept exactly one `JConnection` in V1;
|
||||
- connect only to another `JEndpointLift`;
|
||||
- align on the same 2D WorldTile coordinate as its paired lift;
|
||||
- connect across different WorldLayers.
|
||||
|
||||
## Endpoint Coexistence
|
||||
|
||||
A WorldTile MAY contain sockets and one non-socket endpoint.
|
||||
|
||||
`JEndpointAnchor` and `JEndpointLift` MUST NOT coexist on the same WorldTile.
|
||||
|
||||
Sockets MAY coexist with anchors or lifts.
|
||||
|
||||
## Connections
|
||||
|
||||
`JConnection` is a logical edge between exactly two endpoints.
|
||||
|
||||
`JConnection` MUST:
|
||||
|
||||
- have a stable GUID/string id;
|
||||
- reference endpoint A by id;
|
||||
- reference endpoint B by id;
|
||||
- connect endpoints of compatible type;
|
||||
- not own physical space.
|
||||
|
||||
Endpoint compatibility in V1 is same-type only:
|
||||
|
||||
- socket to socket;
|
||||
- anchor to anchor;
|
||||
- lift to lift.
|
||||
|
||||
Directionality MAY be represented in V1. Concrete requirement modeling and loading hints are outside V1, but `JConnection` SHOULD remain extensible so those fields can be added later.
|
||||
|
||||
## Commit Flow
|
||||
|
||||
The World Editor SHALL publish Journey data through an explicit commit action.
|
||||
|
||||
The commit action MUST:
|
||||
|
||||
- validate `WorldLayoutSO`;
|
||||
- abort if commit-blocking errors exist;
|
||||
- allow publication when only warnings exist;
|
||||
- create or update `JGraphSO`;
|
||||
- write `JStage`, `JEndpoint`, and `JConnection` records;
|
||||
- write publication metadata.
|
||||
|
||||
The commit action MUST NOT:
|
||||
|
||||
- generate Stage scenes;
|
||||
- generate Stage geometry;
|
||||
- generate internal Stage objects;
|
||||
- run Stage bake;
|
||||
- write Stage Editor content.
|
||||
|
||||
## Validation
|
||||
|
||||
Commit-blocking errors include:
|
||||
|
||||
- same-layer WorldTile overlap between Stages;
|
||||
- connection referencing a missing endpoint;
|
||||
- connection linking an endpoint to itself;
|
||||
- incompatible endpoint types;
|
||||
- socket with more than one connection;
|
||||
- socket on an internal Stage face;
|
||||
- socket connected to a non-opposite or non-adjacent socket;
|
||||
- anchor and lift on the same WorldTile;
|
||||
- lift connected to a lift with a different 2D coordinate;
|
||||
- required endpoint without connection.
|
||||
|
||||
Warnings include:
|
||||
|
||||
- optional endpoint without connection;
|
||||
- Stage without endpoints;
|
||||
- authoring metadata missing from non-critical fields.
|
||||
|
||||
## Editor Technology
|
||||
|
||||
World Editor V1 SHALL use the same window technology as the existing Stage Editor:
|
||||
|
||||
- `EditorWindow`;
|
||||
- UI Toolkit via `UnityEngine.UIElements` and `UnityEditor.UIElements`;
|
||||
- custom canvas based on `VisualElement.generateVisualContent`.
|
||||
|
||||
Stage Editor integration remains manual in V1.
|
||||
|
||||
## V1 Non-Goals
|
||||
|
||||
V1 does not include:
|
||||
|
||||
- loading hints;
|
||||
- streaming policies;
|
||||
- concrete `JRequirement` structures;
|
||||
- runtime destination selection UI or logic for multi-connection anchors;
|
||||
- deep Stage Editor marker sync;
|
||||
- automatic Stage Editor opening from the World Editor;
|
||||
- unified World/Stage Editor shell.
|
||||
Loading…
x
Reference in New Issue
Block a user