Adding new Races, Main Menu -> Lobby flow, and what's needed to set up multiplayer testing.
This commit is contained in:
parent
60fa58b07f
commit
fdada6f132
29 changed files with 2581 additions and 176 deletions
8
Assets/_Project/Art/Sprites.meta
Normal file
8
Assets/_Project/Art/Sprites.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2d10906489190644baf28d93e5197c42
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
3
Assets/_Project/Art/Sprites/BloodAngels.jpg
Normal file
3
Assets/_Project/Art/Sprites/BloodAngels.jpg
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:4fa63ce77f2808fb9a275dcfea9747c91e2c6e521589b1af1bf85d29ef7752ae
|
||||||
|
size 7854
|
||||||
117
Assets/_Project/Art/Sprites/BloodAngels.jpg.meta
Normal file
117
Assets/_Project/Art/Sprites/BloodAngels.jpg.meta
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: dbc19961a66b0b6478efea006e0a0fee
|
||||||
|
TextureImporter:
|
||||||
|
internalIDToNameTable: []
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 13
|
||||||
|
mipmaps:
|
||||||
|
mipMapMode: 0
|
||||||
|
enableMipMap: 0
|
||||||
|
sRGBTexture: 1
|
||||||
|
linearTexture: 0
|
||||||
|
fadeOut: 0
|
||||||
|
borderMipMap: 0
|
||||||
|
mipMapsPreserveCoverage: 0
|
||||||
|
alphaTestReferenceValue: 0.5
|
||||||
|
mipMapFadeDistanceStart: 1
|
||||||
|
mipMapFadeDistanceEnd: 3
|
||||||
|
bumpmap:
|
||||||
|
convertToNormalMap: 0
|
||||||
|
externalNormalMap: 0
|
||||||
|
heightScale: 0.25
|
||||||
|
normalMapFilter: 0
|
||||||
|
flipGreenChannel: 0
|
||||||
|
isReadable: 0
|
||||||
|
streamingMipmaps: 0
|
||||||
|
streamingMipmapsPriority: 0
|
||||||
|
vTOnly: 0
|
||||||
|
ignoreMipmapLimit: 0
|
||||||
|
grayScaleToAlpha: 0
|
||||||
|
generateCubemap: 6
|
||||||
|
cubemapConvolution: 0
|
||||||
|
seamlessCubemap: 0
|
||||||
|
textureFormat: 1
|
||||||
|
maxTextureSize: 2048
|
||||||
|
textureSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
filterMode: 1
|
||||||
|
aniso: 1
|
||||||
|
mipBias: 0
|
||||||
|
wrapU: 1
|
||||||
|
wrapV: 1
|
||||||
|
wrapW: 0
|
||||||
|
nPOTScale: 0
|
||||||
|
lightmap: 0
|
||||||
|
compressionQuality: 50
|
||||||
|
spriteMode: 1
|
||||||
|
spriteExtrude: 1
|
||||||
|
spriteMeshType: 1
|
||||||
|
alignment: 0
|
||||||
|
spritePivot: {x: 0.5, y: 0.5}
|
||||||
|
spritePixelsToUnits: 100
|
||||||
|
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
spriteGenerateFallbackPhysicsShape: 1
|
||||||
|
alphaUsage: 1
|
||||||
|
alphaIsTransparency: 1
|
||||||
|
spriteTessellationDetail: -1
|
||||||
|
textureType: 8
|
||||||
|
textureShape: 1
|
||||||
|
singleChannelComponent: 0
|
||||||
|
flipbookRows: 1
|
||||||
|
flipbookColumns: 1
|
||||||
|
maxTextureSizeSet: 0
|
||||||
|
compressionQualitySet: 0
|
||||||
|
textureFormatSet: 0
|
||||||
|
ignorePngGamma: 0
|
||||||
|
applyGammaDecoding: 0
|
||||||
|
swizzle: 50462976
|
||||||
|
cookieLightType: 0
|
||||||
|
platformSettings:
|
||||||
|
- serializedVersion: 4
|
||||||
|
buildTarget: DefaultTexturePlatform
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
- serializedVersion: 4
|
||||||
|
buildTarget: Standalone
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
spriteSheet:
|
||||||
|
serializedVersion: 2
|
||||||
|
sprites: []
|
||||||
|
outline: []
|
||||||
|
customData:
|
||||||
|
physicsShape: []
|
||||||
|
bones: []
|
||||||
|
spriteID: 5e97eb03825dee720800000000000000
|
||||||
|
internalID: 0
|
||||||
|
vertices: []
|
||||||
|
indices:
|
||||||
|
edges: []
|
||||||
|
weights: []
|
||||||
|
secondaryTextures: []
|
||||||
|
spriteCustomMetadata:
|
||||||
|
entries: []
|
||||||
|
nameFileIdTable: {}
|
||||||
|
mipmapLimitGroupName:
|
||||||
|
pSDRemoveMatte: 0
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
3
Assets/_Project/Art/Sprites/Ultramarines.jpg
Normal file
3
Assets/_Project/Art/Sprites/Ultramarines.jpg
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:9033f5e4e490ee5a82e550aae4f690eefc49463a804ecc91e2874a28e8f988d1
|
||||||
|
size 5726
|
||||||
117
Assets/_Project/Art/Sprites/Ultramarines.jpg.meta
Normal file
117
Assets/_Project/Art/Sprites/Ultramarines.jpg.meta
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f19f71b7dd6671841abd34ce8b359351
|
||||||
|
TextureImporter:
|
||||||
|
internalIDToNameTable: []
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 13
|
||||||
|
mipmaps:
|
||||||
|
mipMapMode: 0
|
||||||
|
enableMipMap: 0
|
||||||
|
sRGBTexture: 1
|
||||||
|
linearTexture: 0
|
||||||
|
fadeOut: 0
|
||||||
|
borderMipMap: 0
|
||||||
|
mipMapsPreserveCoverage: 0
|
||||||
|
alphaTestReferenceValue: 0.5
|
||||||
|
mipMapFadeDistanceStart: 1
|
||||||
|
mipMapFadeDistanceEnd: 3
|
||||||
|
bumpmap:
|
||||||
|
convertToNormalMap: 0
|
||||||
|
externalNormalMap: 0
|
||||||
|
heightScale: 0.25
|
||||||
|
normalMapFilter: 0
|
||||||
|
flipGreenChannel: 0
|
||||||
|
isReadable: 0
|
||||||
|
streamingMipmaps: 0
|
||||||
|
streamingMipmapsPriority: 0
|
||||||
|
vTOnly: 0
|
||||||
|
ignoreMipmapLimit: 0
|
||||||
|
grayScaleToAlpha: 0
|
||||||
|
generateCubemap: 6
|
||||||
|
cubemapConvolution: 0
|
||||||
|
seamlessCubemap: 0
|
||||||
|
textureFormat: 1
|
||||||
|
maxTextureSize: 2048
|
||||||
|
textureSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
filterMode: 1
|
||||||
|
aniso: 1
|
||||||
|
mipBias: 0
|
||||||
|
wrapU: 1
|
||||||
|
wrapV: 1
|
||||||
|
wrapW: 0
|
||||||
|
nPOTScale: 0
|
||||||
|
lightmap: 0
|
||||||
|
compressionQuality: 50
|
||||||
|
spriteMode: 1
|
||||||
|
spriteExtrude: 1
|
||||||
|
spriteMeshType: 1
|
||||||
|
alignment: 0
|
||||||
|
spritePivot: {x: 0.5, y: 0.5}
|
||||||
|
spritePixelsToUnits: 100
|
||||||
|
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
spriteGenerateFallbackPhysicsShape: 1
|
||||||
|
alphaUsage: 1
|
||||||
|
alphaIsTransparency: 1
|
||||||
|
spriteTessellationDetail: -1
|
||||||
|
textureType: 8
|
||||||
|
textureShape: 1
|
||||||
|
singleChannelComponent: 0
|
||||||
|
flipbookRows: 1
|
||||||
|
flipbookColumns: 1
|
||||||
|
maxTextureSizeSet: 0
|
||||||
|
compressionQualitySet: 0
|
||||||
|
textureFormatSet: 0
|
||||||
|
ignorePngGamma: 0
|
||||||
|
applyGammaDecoding: 0
|
||||||
|
swizzle: 50462976
|
||||||
|
cookieLightType: 0
|
||||||
|
platformSettings:
|
||||||
|
- serializedVersion: 4
|
||||||
|
buildTarget: DefaultTexturePlatform
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
- serializedVersion: 4
|
||||||
|
buildTarget: Standalone
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
spriteSheet:
|
||||||
|
serializedVersion: 2
|
||||||
|
sprites: []
|
||||||
|
outline: []
|
||||||
|
customData:
|
||||||
|
physicsShape: []
|
||||||
|
bones: []
|
||||||
|
spriteID: 5e97eb03825dee720800000000000000
|
||||||
|
internalID: 0
|
||||||
|
vertices: []
|
||||||
|
indices:
|
||||||
|
edges: []
|
||||||
|
weights: []
|
||||||
|
secondaryTextures: []
|
||||||
|
spriteCustomMetadata:
|
||||||
|
entries: []
|
||||||
|
nameFileIdTable: {}
|
||||||
|
mipmapLimitGroupName:
|
||||||
|
pSDRemoveMatte: 0
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
8
Assets/_Project/Data/Races.meta
Normal file
8
Assets/_Project/Data/Races.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0d631899488b6db4a8d9af9a97a9b2d5
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
23
Assets/_Project/Data/Races/BloodAngels_Placeholder.asset
Normal file
23
Assets/_Project/Data/Races/BloodAngels_Placeholder.asset
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
%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: 98b7d5d116870f94da912007f6aa5cbb, type: 3}
|
||||||
|
m_Name: BloodAngels_Placeholder
|
||||||
|
m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.RaceDefinition
|
||||||
|
Id: 2
|
||||||
|
DisplayName: Blood Angels
|
||||||
|
Icon: {fileID: 21300000, guid: dbc19961a66b0b6478efea006e0a0fee, type: 3}
|
||||||
|
BuilderName: Mother Teresa
|
||||||
|
BuilderDescription: Evil beyond measure, a truly fucked up woman
|
||||||
|
LoreText: Crucified and brought back by God because her job wasn't finished. She's
|
||||||
|
here to bring death to to Xenos scum.
|
||||||
|
BuilderPrefab: {fileID: 116861493430507844, guid: 3398cc5831880954487717577f61b6d7, type: 3}
|
||||||
|
Towers: []
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4d91bbd27e96fb845af6bb1bf0a22fe4
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 11400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
23
Assets/_Project/Data/Races/Ultramarines_Placeholder.asset
Normal file
23
Assets/_Project/Data/Races/Ultramarines_Placeholder.asset
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
%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: 98b7d5d116870f94da912007f6aa5cbb, type: 3}
|
||||||
|
m_Name: Ultramarines_Placeholder
|
||||||
|
m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.RaceDefinition
|
||||||
|
Id: 1
|
||||||
|
DisplayName: Ultramarines
|
||||||
|
Icon: {fileID: 21300000, guid: f19f71b7dd6671841abd34ce8b359351, type: 3}
|
||||||
|
BuilderName: Master Chief
|
||||||
|
BuilderDescription: My man makes some bangin towers
|
||||||
|
LoreText: King of the protoss, he's here to kick bubblegum and chew ass, and he's
|
||||||
|
all out of ass.
|
||||||
|
BuilderPrefab: {fileID: 116861493430507844, guid: 3398cc5831880954487717577f61b6d7, type: 3}
|
||||||
|
Towers: []
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c8b11f545e3990049a5953a34459f58a
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 11400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -146,7 +146,7 @@ MonoBehaviour:
|
||||||
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
|
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject
|
m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject
|
||||||
GlobalObjectIdHash: 4180539217
|
GlobalObjectIdHash: 3501512193
|
||||||
InScenePlacedSourceGlobalObjectIdHash: 3702618695
|
InScenePlacedSourceGlobalObjectIdHash: 3702618695
|
||||||
DeferredDespawnTick: 0
|
DeferredDespawnTick: 0
|
||||||
Ownership: 1
|
Ownership: 1
|
||||||
|
|
@ -977,7 +977,6 @@ GameObject:
|
||||||
- component: {fileID: 4960685830559074027}
|
- component: {fileID: 4960685830559074027}
|
||||||
- component: {fileID: 4757296063414367819}
|
- component: {fileID: 4757296063414367819}
|
||||||
- component: {fileID: 336275605508886593}
|
- component: {fileID: 336275605508886593}
|
||||||
- component: {fileID: 4966682596699708025}
|
|
||||||
m_Layer: 0
|
m_Layer: 0
|
||||||
m_Name: SelectionRing
|
m_Name: SelectionRing
|
||||||
m_TagString: Untagged
|
m_TagString: Untagged
|
||||||
|
|
@ -1057,18 +1056,6 @@ MeshRenderer:
|
||||||
m_SortingOrder: 0
|
m_SortingOrder: 0
|
||||||
m_MaskInteraction: 0
|
m_MaskInteraction: 0
|
||||||
m_AdditionalVertexStreams: {fileID: 0}
|
m_AdditionalVertexStreams: {fileID: 0}
|
||||||
--- !u!114 &4966682596699708025
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 2652716240617921727}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 67895f626233fdc499dffbbfcc225530, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.SelectionRingVisual
|
|
||||||
--- !u!1 &2781170330021425455
|
--- !u!1 &2781170330021425455
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|
|
||||||
|
|
@ -1502,12 +1502,12 @@ MonoBehaviour:
|
||||||
edgePanEnabled: 1
|
edgePanEnabled: 1
|
||||||
minDollyDistance: 5
|
minDollyDistance: 5
|
||||||
maxDollyDistance: 50
|
maxDollyDistance: 50
|
||||||
startDollyDistance: 35
|
startDollyDistance: 25
|
||||||
zoomSpeed: 3
|
zoomSpeed: 3
|
||||||
cursorAnchoredZoom: 1
|
cursorAnchoredZoom: 1
|
||||||
minPitchDegrees: 30
|
minPitchDegrees: 30
|
||||||
maxPitchDegrees: 75
|
maxPitchDegrees: 75
|
||||||
startPitchDegrees: 60
|
startPitchDegrees: 50
|
||||||
pitchSpeed: 4
|
pitchSpeed: 4
|
||||||
--- !u!4 &1239994224
|
--- !u!4 &1239994224
|
||||||
Transform:
|
Transform:
|
||||||
|
|
@ -1950,112 +1950,6 @@ MonoBehaviour:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
m_Bits: 64
|
m_Bits: 64
|
||||||
raycastMaxDistance: 500
|
raycastMaxDistance: 500
|
||||||
--- !u!1 &1682341399
|
|
||||||
GameObject:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
serializedVersion: 6
|
|
||||||
m_Component:
|
|
||||||
- component: {fileID: 1682341402}
|
|
||||||
- component: {fileID: 1682341401}
|
|
||||||
- component: {fileID: 1682341400}
|
|
||||||
m_Layer: 0
|
|
||||||
m_Name: NetworkManager
|
|
||||||
m_TagString: Untagged
|
|
||||||
m_Icon: {fileID: 0}
|
|
||||||
m_NavMeshLayer: 0
|
|
||||||
m_StaticEditorFlags: 0
|
|
||||||
m_IsActive: 1
|
|
||||||
--- !u!114 &1682341400
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 1682341399}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 6960e84d07fb87f47956e7a81d71c4e6, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.Transports.UTP.UnityTransport
|
|
||||||
m_ProtocolType: 0
|
|
||||||
m_UseWebSockets: 0
|
|
||||||
m_UseEncryption: 0
|
|
||||||
m_MaxPacketQueueSize: 128
|
|
||||||
m_MaxPayloadSize: 6144
|
|
||||||
m_HeartbeatTimeoutMS: 500
|
|
||||||
m_ConnectTimeoutMS: 1000
|
|
||||||
m_MaxConnectAttempts: 60
|
|
||||||
m_DisconnectTimeoutMS: 30000
|
|
||||||
ConnectionData:
|
|
||||||
Address: 127.0.0.1
|
|
||||||
Port: 7777
|
|
||||||
WebSocketPath: /
|
|
||||||
ServerListenAddress: 127.0.0.1
|
|
||||||
ClientBindPort: 0
|
|
||||||
DebugSimulator:
|
|
||||||
PacketDelayMS: 0
|
|
||||||
PacketJitterMS: 0
|
|
||||||
PacketDropRate: 0
|
|
||||||
--- !u!114 &1682341401
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 1682341399}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 593a2fe42fa9d37498c96f9a383b6521, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkManager
|
|
||||||
NetworkManagerExpanded: 0
|
|
||||||
NetworkConfig:
|
|
||||||
ProtocolVersion: 0
|
|
||||||
NetworkTransport: {fileID: 1682341400}
|
|
||||||
PlayerPrefab: {fileID: 3493329038866903420, guid: 9a9c23b8584ab444aa5066a48579a9ec, type: 3}
|
|
||||||
Prefabs:
|
|
||||||
NetworkPrefabsLists:
|
|
||||||
- {fileID: 11400000, guid: 481ab1d7456efd044bc3e349aacd92ae, type: 2}
|
|
||||||
TickRate: 30
|
|
||||||
ClientConnectionBufferTimeout: 10
|
|
||||||
ConnectionApproval: 0
|
|
||||||
ConnectionData:
|
|
||||||
EnableTimeResync: 0
|
|
||||||
TimeResyncInterval: 30
|
|
||||||
EnsureNetworkVariableLengthSafety: 0
|
|
||||||
EnableSceneManagement: 1
|
|
||||||
ForceSamePrefabs: 1
|
|
||||||
RecycleNetworkIds: 1
|
|
||||||
NetworkIdRecycleDelay: 120
|
|
||||||
RpcHashSize: 0
|
|
||||||
LoadSceneTimeOut: 120
|
|
||||||
SpawnTimeout: 10
|
|
||||||
EnableNetworkLogs: 1
|
|
||||||
NetworkTopology: 0
|
|
||||||
UseCMBService: 0
|
|
||||||
AutoSpawnPlayerPrefabClientSide: 1
|
|
||||||
NetworkProfilingMetrics: 1
|
|
||||||
OldPrefabList: []
|
|
||||||
RunInBackground: 1
|
|
||||||
LogLevel: 1
|
|
||||||
--- !u!4 &1682341402
|
|
||||||
Transform:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 1682341399}
|
|
||||||
serializedVersion: 2
|
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
|
||||||
m_ConstrainProportionsScale: 0
|
|
||||||
m_Children: []
|
|
||||||
m_Father: {fileID: 0}
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
|
||||||
--- !u!1 &1731269685
|
--- !u!1 &1731269685
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|
@ -2598,7 +2492,6 @@ SceneRoots:
|
||||||
m_Roots:
|
m_Roots:
|
||||||
- {fileID: 410087041}
|
- {fileID: 410087041}
|
||||||
- {fileID: 832575519}
|
- {fileID: 832575519}
|
||||||
- {fileID: 1682341402}
|
|
||||||
- {fileID: 441239881}
|
- {fileID: 441239881}
|
||||||
- {fileID: 167151709}
|
- {fileID: 167151709}
|
||||||
- {fileID: 1507514109}
|
- {fileID: 1507514109}
|
||||||
|
|
|
||||||
546
Assets/_Project/Scenes/UI/Lobby.unity
Normal file
546
Assets/_Project/Scenes/UI/Lobby.unity
Normal file
|
|
@ -0,0 +1,546 @@
|
||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!29 &1
|
||||||
|
OcclusionCullingSettings:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 2
|
||||||
|
m_OcclusionBakeSettings:
|
||||||
|
smallestOccluder: 5
|
||||||
|
smallestHole: 0.25
|
||||||
|
backfaceThreshold: 100
|
||||||
|
m_SceneGUID: 00000000000000000000000000000000
|
||||||
|
m_OcclusionCullingData: {fileID: 0}
|
||||||
|
--- !u!104 &2
|
||||||
|
RenderSettings:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 10
|
||||||
|
m_Fog: 0
|
||||||
|
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
|
||||||
|
m_FogMode: 3
|
||||||
|
m_FogDensity: 0.01
|
||||||
|
m_LinearFogStart: 0
|
||||||
|
m_LinearFogEnd: 300
|
||||||
|
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
|
||||||
|
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
|
||||||
|
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
|
||||||
|
m_AmbientIntensity: 1
|
||||||
|
m_AmbientMode: 0
|
||||||
|
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
|
||||||
|
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_HaloStrength: 0.5
|
||||||
|
m_FlareStrength: 1
|
||||||
|
m_FlareFadeSpeed: 3
|
||||||
|
m_HaloTexture: {fileID: 0}
|
||||||
|
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
|
||||||
|
m_DefaultReflectionMode: 0
|
||||||
|
m_DefaultReflectionResolution: 128
|
||||||
|
m_ReflectionBounces: 1
|
||||||
|
m_ReflectionIntensity: 1
|
||||||
|
m_CustomReflection: {fileID: 0}
|
||||||
|
m_Sun: {fileID: 0}
|
||||||
|
m_UseRadianceAmbientProbe: 0
|
||||||
|
--- !u!157 &3
|
||||||
|
LightmapSettings:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 13
|
||||||
|
m_BakeOnSceneLoad: 0
|
||||||
|
m_GISettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_BounceScale: 1
|
||||||
|
m_IndirectOutputScale: 1
|
||||||
|
m_AlbedoBoost: 1
|
||||||
|
m_EnvironmentLightingMode: 0
|
||||||
|
m_EnableBakedLightmaps: 1
|
||||||
|
m_EnableRealtimeLightmaps: 0
|
||||||
|
m_LightmapEditorSettings:
|
||||||
|
serializedVersion: 12
|
||||||
|
m_Resolution: 2
|
||||||
|
m_BakeResolution: 40
|
||||||
|
m_AtlasSize: 1024
|
||||||
|
m_AO: 0
|
||||||
|
m_AOMaxDistance: 1
|
||||||
|
m_CompAOExponent: 1
|
||||||
|
m_CompAOExponentDirect: 0
|
||||||
|
m_ExtractAmbientOcclusion: 0
|
||||||
|
m_Padding: 2
|
||||||
|
m_LightmapParameters: {fileID: 0}
|
||||||
|
m_LightmapsBakeMode: 1
|
||||||
|
m_TextureCompression: 1
|
||||||
|
m_ReflectionCompression: 2
|
||||||
|
m_MixedBakeMode: 2
|
||||||
|
m_BakeBackend: 1
|
||||||
|
m_PVRSampling: 1
|
||||||
|
m_PVRDirectSampleCount: 32
|
||||||
|
m_PVRSampleCount: 512
|
||||||
|
m_PVRBounces: 2
|
||||||
|
m_PVREnvironmentSampleCount: 256
|
||||||
|
m_PVREnvironmentReferencePointCount: 2048
|
||||||
|
m_PVRFilteringMode: 1
|
||||||
|
m_PVRDenoiserTypeDirect: 1
|
||||||
|
m_PVRDenoiserTypeIndirect: 1
|
||||||
|
m_PVRDenoiserTypeAO: 1
|
||||||
|
m_PVRFilterTypeDirect: 0
|
||||||
|
m_PVRFilterTypeIndirect: 0
|
||||||
|
m_PVRFilterTypeAO: 0
|
||||||
|
m_PVREnvironmentMIS: 1
|
||||||
|
m_PVRCulling: 1
|
||||||
|
m_PVRFilteringGaussRadiusDirect: 1
|
||||||
|
m_PVRFilteringGaussRadiusIndirect: 5
|
||||||
|
m_PVRFilteringGaussRadiusAO: 2
|
||||||
|
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
|
||||||
|
m_PVRFilteringAtrousPositionSigmaIndirect: 2
|
||||||
|
m_PVRFilteringAtrousPositionSigmaAO: 1
|
||||||
|
m_ExportTrainingData: 0
|
||||||
|
m_TrainingDataDestination: TrainingData
|
||||||
|
m_LightProbeSampleCountMultiplier: 4
|
||||||
|
m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_LightingSettings: {fileID: 0}
|
||||||
|
--- !u!196 &4
|
||||||
|
NavMeshSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_BuildSettings:
|
||||||
|
serializedVersion: 3
|
||||||
|
agentTypeID: 0
|
||||||
|
agentRadius: 0.5
|
||||||
|
agentHeight: 2
|
||||||
|
agentSlope: 45
|
||||||
|
agentClimb: 0.4
|
||||||
|
ledgeDropHeight: 0
|
||||||
|
maxJumpAcrossDistance: 0
|
||||||
|
minRegionArea: 2
|
||||||
|
manualCellSize: 0
|
||||||
|
cellSize: 0.16666667
|
||||||
|
manualTileSize: 0
|
||||||
|
tileSize: 256
|
||||||
|
buildHeightMesh: 0
|
||||||
|
maxJobWorkers: 0
|
||||||
|
preserveTilesOutsideBounds: 0
|
||||||
|
debug:
|
||||||
|
m_Flags: 0
|
||||||
|
m_NavMeshData: {fileID: 0}
|
||||||
|
--- !u!1 &178257552
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 178257555}
|
||||||
|
- component: {fileID: 178257554}
|
||||||
|
- component: {fileID: 178257553}
|
||||||
|
- component: {fileID: 178257556}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: LobbyUI
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!114 &178257553
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 178257552}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 8c40427d598ba944c82f3790429c5532, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: Assembly-CSharp::TD.UI.LobbyController
|
||||||
|
raceOverlay: {fileID: 178257556}
|
||||||
|
--- !u!114 &178257554
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 178257552}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: UnityEngine.dll::UnityEngine.UIElements.UIDocument
|
||||||
|
m_PanelSettings: {fileID: 11400000, guid: 6aa0af71585acea4db4995c3931dc946, type: 2}
|
||||||
|
m_ParentUI: {fileID: 0}
|
||||||
|
sourceAsset: {fileID: 0}
|
||||||
|
m_SortingOrder: 0
|
||||||
|
m_Position: 0
|
||||||
|
m_WorldSpaceSizeMode: 1
|
||||||
|
m_WorldSpaceWidth: 1920
|
||||||
|
m_WorldSpaceHeight: 1080
|
||||||
|
m_PivotReferenceSize: 0
|
||||||
|
m_Pivot: 0
|
||||||
|
m_WorldSpaceCollider: {fileID: 0}
|
||||||
|
--- !u!4 &178257555
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 178257552}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!114 &178257556
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 178257552}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 9ab3ad11b37d4c54d9f310f5356d31ac, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: Assembly-CSharp::TD.UI.RaceSelectionOverlay
|
||||||
|
--- !u!1 &203844586
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 203844589}
|
||||||
|
- component: {fileID: 203844588}
|
||||||
|
- component: {fileID: 203844587}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Directional Light
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!114 &203844587
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 203844586}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_UsePipelineSettings: 1
|
||||||
|
m_AdditionalLightsShadowResolutionTier: 2
|
||||||
|
m_CustomShadowLayers: 0
|
||||||
|
m_LightCookieSize: {x: 1, y: 1}
|
||||||
|
m_LightCookieOffset: {x: 0, y: 0}
|
||||||
|
m_SoftShadowQuality: 0
|
||||||
|
m_RenderingLayersMask:
|
||||||
|
serializedVersion: 0
|
||||||
|
m_Bits: 1
|
||||||
|
m_ShadowRenderingLayersMask:
|
||||||
|
serializedVersion: 0
|
||||||
|
m_Bits: 1
|
||||||
|
m_Version: 4
|
||||||
|
m_LightLayerMask: 1
|
||||||
|
m_ShadowLayerMask: 1
|
||||||
|
m_RenderingLayers: 1
|
||||||
|
m_ShadowRenderingLayers: 1
|
||||||
|
--- !u!108 &203844588
|
||||||
|
Light:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 203844586}
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 13
|
||||||
|
m_Type: 1
|
||||||
|
m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
|
||||||
|
m_Intensity: 1
|
||||||
|
m_Range: 10
|
||||||
|
m_SpotAngle: 30
|
||||||
|
m_InnerSpotAngle: 21.80208
|
||||||
|
m_CookieSize2D: {x: 10, y: 10}
|
||||||
|
m_Shadows:
|
||||||
|
m_Type: 2
|
||||||
|
m_Resolution: -1
|
||||||
|
m_CustomResolution: -1
|
||||||
|
m_Strength: 1
|
||||||
|
m_Bias: 0.05
|
||||||
|
m_NormalBias: 0.4
|
||||||
|
m_NearPlane: 0.2
|
||||||
|
m_CullingMatrixOverride:
|
||||||
|
e00: 1
|
||||||
|
e01: 0
|
||||||
|
e02: 0
|
||||||
|
e03: 0
|
||||||
|
e10: 0
|
||||||
|
e11: 1
|
||||||
|
e12: 0
|
||||||
|
e13: 0
|
||||||
|
e20: 0
|
||||||
|
e21: 0
|
||||||
|
e22: 1
|
||||||
|
e23: 0
|
||||||
|
e30: 0
|
||||||
|
e31: 0
|
||||||
|
e32: 0
|
||||||
|
e33: 1
|
||||||
|
m_UseCullingMatrixOverride: 0
|
||||||
|
m_Cookie: {fileID: 0}
|
||||||
|
m_DrawHalo: 0
|
||||||
|
m_Flare: {fileID: 0}
|
||||||
|
m_RenderMode: 0
|
||||||
|
m_CullingMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
m_RenderingLayerMask: 1
|
||||||
|
m_Lightmapping: 4
|
||||||
|
m_LightShadowCasterMode: 0
|
||||||
|
m_AreaSize: {x: 1, y: 1}
|
||||||
|
m_BounceIntensity: 1
|
||||||
|
m_ColorTemperature: 6570
|
||||||
|
m_UseColorTemperature: 0
|
||||||
|
m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_UseBoundingSphereOverride: 0
|
||||||
|
m_UseViewFrustumForShadowCasterCull: 1
|
||||||
|
m_ForceVisible: 0
|
||||||
|
m_ShapeRadius: 0
|
||||||
|
m_ShadowAngle: 0
|
||||||
|
m_LightUnit: 1
|
||||||
|
m_LuxAtDistance: 1
|
||||||
|
m_EnableSpotReflector: 1
|
||||||
|
--- !u!4 &203844589
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 203844586}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
|
||||||
|
--- !u!1 &961739749
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 961739753}
|
||||||
|
- component: {fileID: 961739752}
|
||||||
|
- component: {fileID: 961739751}
|
||||||
|
- component: {fileID: 961739750}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Main Camera
|
||||||
|
m_TagString: MainCamera
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!114 &961739750
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 961739749}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_RenderShadows: 1
|
||||||
|
m_RequiresDepthTextureOption: 2
|
||||||
|
m_RequiresOpaqueTextureOption: 2
|
||||||
|
m_CameraType: 0
|
||||||
|
m_Cameras: []
|
||||||
|
m_RendererIndex: -1
|
||||||
|
m_VolumeLayerMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 1
|
||||||
|
m_VolumeTrigger: {fileID: 0}
|
||||||
|
m_VolumeFrameworkUpdateModeOption: 2
|
||||||
|
m_RenderPostProcessing: 0
|
||||||
|
m_Antialiasing: 0
|
||||||
|
m_AntialiasingQuality: 2
|
||||||
|
m_StopNaN: 0
|
||||||
|
m_Dithering: 0
|
||||||
|
m_ClearDepth: 1
|
||||||
|
m_AllowXRRendering: 1
|
||||||
|
m_AllowHDROutput: 1
|
||||||
|
m_UseScreenCoordOverride: 0
|
||||||
|
m_ScreenSizeOverride: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_RequiresDepthTexture: 0
|
||||||
|
m_RequiresColorTexture: 0
|
||||||
|
m_TaaSettings:
|
||||||
|
m_Quality: 3
|
||||||
|
m_FrameInfluence: 0.1
|
||||||
|
m_JitterScale: 1
|
||||||
|
m_MipBias: 0
|
||||||
|
m_VarianceClampScale: 0.9
|
||||||
|
m_ContrastAdaptiveSharpening: 0
|
||||||
|
m_Version: 2
|
||||||
|
--- !u!81 &961739751
|
||||||
|
AudioListener:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 961739749}
|
||||||
|
m_Enabled: 1
|
||||||
|
--- !u!20 &961739752
|
||||||
|
Camera:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 961739749}
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 2
|
||||||
|
m_ClearFlags: 1
|
||||||
|
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
|
||||||
|
m_projectionMatrixMode: 1
|
||||||
|
m_GateFitMode: 2
|
||||||
|
m_FOVAxisMode: 0
|
||||||
|
m_Iso: 200
|
||||||
|
m_ShutterSpeed: 0.005
|
||||||
|
m_Aperture: 16
|
||||||
|
m_FocusDistance: 10
|
||||||
|
m_FocalLength: 50
|
||||||
|
m_BladeCount: 5
|
||||||
|
m_Curvature: {x: 2, y: 11}
|
||||||
|
m_BarrelClipping: 0.25
|
||||||
|
m_Anamorphism: 0
|
||||||
|
m_SensorSize: {x: 36, y: 24}
|
||||||
|
m_LensShift: {x: 0, y: 0}
|
||||||
|
m_NormalizedViewPortRect:
|
||||||
|
serializedVersion: 2
|
||||||
|
x: 0
|
||||||
|
y: 0
|
||||||
|
width: 1
|
||||||
|
height: 1
|
||||||
|
near clip plane: 0.3
|
||||||
|
far clip plane: 1000
|
||||||
|
field of view: 60
|
||||||
|
orthographic: 0
|
||||||
|
orthographic size: 5
|
||||||
|
m_Depth: -1
|
||||||
|
m_CullingMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
m_RenderingPath: -1
|
||||||
|
m_TargetTexture: {fileID: 0}
|
||||||
|
m_TargetDisplay: 0
|
||||||
|
m_TargetEye: 3
|
||||||
|
m_HDR: 1
|
||||||
|
m_AllowMSAA: 1
|
||||||
|
m_AllowDynamicResolution: 0
|
||||||
|
m_ForceIntoRT: 0
|
||||||
|
m_OcclusionCulling: 1
|
||||||
|
m_StereoConvergence: 10
|
||||||
|
m_StereoSeparation: 0.022
|
||||||
|
--- !u!4 &961739753
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 961739749}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!1 &2030215725
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 2030215727}
|
||||||
|
- component: {fileID: 2030215726}
|
||||||
|
- component: {fileID: 2030215728}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: LobbyService
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!114 &2030215726
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 2030215725}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject
|
||||||
|
GlobalObjectIdHash: 1514133910
|
||||||
|
InScenePlacedSourceGlobalObjectIdHash: 0
|
||||||
|
DeferredDespawnTick: 0
|
||||||
|
Ownership: 1
|
||||||
|
AlwaysReplicateAsRoot: 0
|
||||||
|
SynchronizeTransform: 1
|
||||||
|
ActiveSceneSynchronization: 0
|
||||||
|
SceneMigrationSynchronization: 1
|
||||||
|
SpawnWithObservers: 1
|
||||||
|
DontDestroyWithOwner: 0
|
||||||
|
AutoObjectParentSync: 1
|
||||||
|
SyncOwnerTransformWhenParented: 1
|
||||||
|
AllowOwnerToParent: 0
|
||||||
|
--- !u!4 &2030215727
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 2030215725}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!114 &2030215728
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 2030215725}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 46ab03868ea4bd541bd6be3446c2bd3d, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.LobbyService
|
||||||
|
ShowTopMostFoldoutHeaderGroup: 1
|
||||||
|
--- !u!1660057539 &9223372036854775807
|
||||||
|
SceneRoots:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_Roots:
|
||||||
|
- {fileID: 961739753}
|
||||||
|
- {fileID: 203844589}
|
||||||
|
- {fileID: 2030215727}
|
||||||
|
- {fileID: 178257555}
|
||||||
7
Assets/_Project/Scenes/UI/Lobby.unity.meta
Normal file
7
Assets/_Project/Scenes/UI/Lobby.unity.meta
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3a3639dca674a8049a570cb848bb69d2
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
662
Assets/_Project/Scenes/UI/MainMenu.unity
Normal file
662
Assets/_Project/Scenes/UI/MainMenu.unity
Normal file
|
|
@ -0,0 +1,662 @@
|
||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!29 &1
|
||||||
|
OcclusionCullingSettings:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 2
|
||||||
|
m_OcclusionBakeSettings:
|
||||||
|
smallestOccluder: 5
|
||||||
|
smallestHole: 0.25
|
||||||
|
backfaceThreshold: 100
|
||||||
|
m_SceneGUID: 00000000000000000000000000000000
|
||||||
|
m_OcclusionCullingData: {fileID: 0}
|
||||||
|
--- !u!104 &2
|
||||||
|
RenderSettings:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 10
|
||||||
|
m_Fog: 0
|
||||||
|
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
|
||||||
|
m_FogMode: 3
|
||||||
|
m_FogDensity: 0.01
|
||||||
|
m_LinearFogStart: 0
|
||||||
|
m_LinearFogEnd: 300
|
||||||
|
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
|
||||||
|
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
|
||||||
|
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
|
||||||
|
m_AmbientIntensity: 1
|
||||||
|
m_AmbientMode: 0
|
||||||
|
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
|
||||||
|
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_HaloStrength: 0.5
|
||||||
|
m_FlareStrength: 1
|
||||||
|
m_FlareFadeSpeed: 3
|
||||||
|
m_HaloTexture: {fileID: 0}
|
||||||
|
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
|
||||||
|
m_DefaultReflectionMode: 0
|
||||||
|
m_DefaultReflectionResolution: 128
|
||||||
|
m_ReflectionBounces: 1
|
||||||
|
m_ReflectionIntensity: 1
|
||||||
|
m_CustomReflection: {fileID: 0}
|
||||||
|
m_Sun: {fileID: 0}
|
||||||
|
m_UseRadianceAmbientProbe: 0
|
||||||
|
--- !u!157 &3
|
||||||
|
LightmapSettings:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 13
|
||||||
|
m_BakeOnSceneLoad: 0
|
||||||
|
m_GISettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_BounceScale: 1
|
||||||
|
m_IndirectOutputScale: 1
|
||||||
|
m_AlbedoBoost: 1
|
||||||
|
m_EnvironmentLightingMode: 0
|
||||||
|
m_EnableBakedLightmaps: 1
|
||||||
|
m_EnableRealtimeLightmaps: 0
|
||||||
|
m_LightmapEditorSettings:
|
||||||
|
serializedVersion: 12
|
||||||
|
m_Resolution: 2
|
||||||
|
m_BakeResolution: 40
|
||||||
|
m_AtlasSize: 1024
|
||||||
|
m_AO: 0
|
||||||
|
m_AOMaxDistance: 1
|
||||||
|
m_CompAOExponent: 1
|
||||||
|
m_CompAOExponentDirect: 0
|
||||||
|
m_ExtractAmbientOcclusion: 0
|
||||||
|
m_Padding: 2
|
||||||
|
m_LightmapParameters: {fileID: 0}
|
||||||
|
m_LightmapsBakeMode: 1
|
||||||
|
m_TextureCompression: 1
|
||||||
|
m_ReflectionCompression: 2
|
||||||
|
m_MixedBakeMode: 2
|
||||||
|
m_BakeBackend: 1
|
||||||
|
m_PVRSampling: 1
|
||||||
|
m_PVRDirectSampleCount: 32
|
||||||
|
m_PVRSampleCount: 512
|
||||||
|
m_PVRBounces: 2
|
||||||
|
m_PVREnvironmentSampleCount: 256
|
||||||
|
m_PVREnvironmentReferencePointCount: 2048
|
||||||
|
m_PVRFilteringMode: 1
|
||||||
|
m_PVRDenoiserTypeDirect: 1
|
||||||
|
m_PVRDenoiserTypeIndirect: 1
|
||||||
|
m_PVRDenoiserTypeAO: 1
|
||||||
|
m_PVRFilterTypeDirect: 0
|
||||||
|
m_PVRFilterTypeIndirect: 0
|
||||||
|
m_PVRFilterTypeAO: 0
|
||||||
|
m_PVREnvironmentMIS: 1
|
||||||
|
m_PVRCulling: 1
|
||||||
|
m_PVRFilteringGaussRadiusDirect: 1
|
||||||
|
m_PVRFilteringGaussRadiusIndirect: 5
|
||||||
|
m_PVRFilteringGaussRadiusAO: 2
|
||||||
|
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
|
||||||
|
m_PVRFilteringAtrousPositionSigmaIndirect: 2
|
||||||
|
m_PVRFilteringAtrousPositionSigmaAO: 1
|
||||||
|
m_ExportTrainingData: 0
|
||||||
|
m_TrainingDataDestination: TrainingData
|
||||||
|
m_LightProbeSampleCountMultiplier: 4
|
||||||
|
m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_LightingSettings: {fileID: 0}
|
||||||
|
--- !u!196 &4
|
||||||
|
NavMeshSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_BuildSettings:
|
||||||
|
serializedVersion: 3
|
||||||
|
agentTypeID: 0
|
||||||
|
agentRadius: 0.5
|
||||||
|
agentHeight: 2
|
||||||
|
agentSlope: 45
|
||||||
|
agentClimb: 0.4
|
||||||
|
ledgeDropHeight: 0
|
||||||
|
maxJumpAcrossDistance: 0
|
||||||
|
minRegionArea: 2
|
||||||
|
manualCellSize: 0
|
||||||
|
cellSize: 0.16666667
|
||||||
|
manualTileSize: 0
|
||||||
|
tileSize: 256
|
||||||
|
buildHeightMesh: 0
|
||||||
|
maxJobWorkers: 0
|
||||||
|
preserveTilesOutsideBounds: 0
|
||||||
|
debug:
|
||||||
|
m_Flags: 0
|
||||||
|
m_NavMeshData: {fileID: 0}
|
||||||
|
--- !u!1 &203844586
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 203844589}
|
||||||
|
- component: {fileID: 203844588}
|
||||||
|
- component: {fileID: 203844587}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Directional Light
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!114 &203844587
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 203844586}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_UsePipelineSettings: 1
|
||||||
|
m_AdditionalLightsShadowResolutionTier: 2
|
||||||
|
m_CustomShadowLayers: 0
|
||||||
|
m_LightCookieSize: {x: 1, y: 1}
|
||||||
|
m_LightCookieOffset: {x: 0, y: 0}
|
||||||
|
m_SoftShadowQuality: 0
|
||||||
|
m_RenderingLayersMask:
|
||||||
|
serializedVersion: 0
|
||||||
|
m_Bits: 1
|
||||||
|
m_ShadowRenderingLayersMask:
|
||||||
|
serializedVersion: 0
|
||||||
|
m_Bits: 1
|
||||||
|
m_Version: 4
|
||||||
|
m_LightLayerMask: 1
|
||||||
|
m_ShadowLayerMask: 1
|
||||||
|
m_RenderingLayers: 1
|
||||||
|
m_ShadowRenderingLayers: 1
|
||||||
|
--- !u!108 &203844588
|
||||||
|
Light:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 203844586}
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 13
|
||||||
|
m_Type: 1
|
||||||
|
m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
|
||||||
|
m_Intensity: 1
|
||||||
|
m_Range: 10
|
||||||
|
m_SpotAngle: 30
|
||||||
|
m_InnerSpotAngle: 21.80208
|
||||||
|
m_CookieSize2D: {x: 10, y: 10}
|
||||||
|
m_Shadows:
|
||||||
|
m_Type: 2
|
||||||
|
m_Resolution: -1
|
||||||
|
m_CustomResolution: -1
|
||||||
|
m_Strength: 1
|
||||||
|
m_Bias: 0.05
|
||||||
|
m_NormalBias: 0.4
|
||||||
|
m_NearPlane: 0.2
|
||||||
|
m_CullingMatrixOverride:
|
||||||
|
e00: 1
|
||||||
|
e01: 0
|
||||||
|
e02: 0
|
||||||
|
e03: 0
|
||||||
|
e10: 0
|
||||||
|
e11: 1
|
||||||
|
e12: 0
|
||||||
|
e13: 0
|
||||||
|
e20: 0
|
||||||
|
e21: 0
|
||||||
|
e22: 1
|
||||||
|
e23: 0
|
||||||
|
e30: 0
|
||||||
|
e31: 0
|
||||||
|
e32: 0
|
||||||
|
e33: 1
|
||||||
|
m_UseCullingMatrixOverride: 0
|
||||||
|
m_Cookie: {fileID: 0}
|
||||||
|
m_DrawHalo: 0
|
||||||
|
m_Flare: {fileID: 0}
|
||||||
|
m_RenderMode: 0
|
||||||
|
m_CullingMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
m_RenderingLayerMask: 1
|
||||||
|
m_Lightmapping: 4
|
||||||
|
m_LightShadowCasterMode: 0
|
||||||
|
m_AreaSize: {x: 1, y: 1}
|
||||||
|
m_BounceIntensity: 1
|
||||||
|
m_ColorTemperature: 6570
|
||||||
|
m_UseColorTemperature: 0
|
||||||
|
m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_UseBoundingSphereOverride: 0
|
||||||
|
m_UseViewFrustumForShadowCasterCull: 1
|
||||||
|
m_ForceVisible: 0
|
||||||
|
m_ShapeRadius: 0
|
||||||
|
m_ShadowAngle: 0
|
||||||
|
m_LightUnit: 1
|
||||||
|
m_LuxAtDistance: 1
|
||||||
|
m_EnableSpotReflector: 1
|
||||||
|
--- !u!4 &203844589
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 203844586}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
|
||||||
|
--- !u!1 &514623720
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 514623722}
|
||||||
|
- component: {fileID: 514623721}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: RaceRegistry
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!114 &514623721
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 514623720}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 50ccfdaa301b6a7439b4edfc750550aa, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.RaceRegistry
|
||||||
|
definitions:
|
||||||
|
- {fileID: 11400000, guid: c8b11f545e3990049a5953a34459f58a, type: 2}
|
||||||
|
- {fileID: 11400000, guid: 4d91bbd27e96fb845af6bb1bf0a22fe4, type: 2}
|
||||||
|
--- !u!4 &514623722
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 514623720}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!1 &626141751
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 626141754}
|
||||||
|
- component: {fileID: 626141753}
|
||||||
|
- component: {fileID: 626141752}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: MainMenuUI
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!114 &626141752
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 626141751}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 01199add5a12f4a4bb9a94d1e44fbb4d, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: Assembly-CSharp::TD.UI.MainMenuController
|
||||||
|
defaultPort: 7777
|
||||||
|
defaultJoinAddress: 127.0.0.1
|
||||||
|
--- !u!114 &626141753
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 626141751}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: UnityEngine.dll::UnityEngine.UIElements.UIDocument
|
||||||
|
m_PanelSettings: {fileID: 11400000, guid: 6aa0af71585acea4db4995c3931dc946, type: 2}
|
||||||
|
m_ParentUI: {fileID: 0}
|
||||||
|
sourceAsset: {fileID: 0}
|
||||||
|
m_SortingOrder: 0
|
||||||
|
m_Position: 0
|
||||||
|
m_WorldSpaceSizeMode: 1
|
||||||
|
m_WorldSpaceWidth: 1920
|
||||||
|
m_WorldSpaceHeight: 1080
|
||||||
|
m_PivotReferenceSize: 0
|
||||||
|
m_Pivot: 0
|
||||||
|
m_WorldSpaceCollider: {fileID: 0}
|
||||||
|
--- !u!4 &626141754
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 626141751}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!1 &769692006
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 769692009}
|
||||||
|
- component: {fileID: 769692008}
|
||||||
|
- component: {fileID: 769692007}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: NetworkManager
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!114 &769692007
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 769692006}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 6960e84d07fb87f47956e7a81d71c4e6, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.Transports.UTP.UnityTransport
|
||||||
|
m_ProtocolType: 0
|
||||||
|
m_UseWebSockets: 0
|
||||||
|
m_UseEncryption: 0
|
||||||
|
m_MaxPacketQueueSize: 128
|
||||||
|
m_MaxPayloadSize: 6144
|
||||||
|
m_HeartbeatTimeoutMS: 500
|
||||||
|
m_ConnectTimeoutMS: 1000
|
||||||
|
m_MaxConnectAttempts: 60
|
||||||
|
m_DisconnectTimeoutMS: 30000
|
||||||
|
ConnectionData:
|
||||||
|
Address: 127.0.0.1
|
||||||
|
Port: 7777
|
||||||
|
WebSocketPath: /
|
||||||
|
ServerListenAddress: 127.0.0.1
|
||||||
|
ClientBindPort: 0
|
||||||
|
DebugSimulator:
|
||||||
|
PacketDelayMS: 0
|
||||||
|
PacketJitterMS: 0
|
||||||
|
PacketDropRate: 0
|
||||||
|
--- !u!114 &769692008
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 769692006}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 593a2fe42fa9d37498c96f9a383b6521, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkManager
|
||||||
|
NetworkManagerExpanded: 0
|
||||||
|
NetworkConfig:
|
||||||
|
ProtocolVersion: 0
|
||||||
|
NetworkTransport: {fileID: 769692007}
|
||||||
|
PlayerPrefab: {fileID: 3493329038866903420, guid: 9a9c23b8584ab444aa5066a48579a9ec, type: 3}
|
||||||
|
Prefabs:
|
||||||
|
NetworkPrefabsLists:
|
||||||
|
- {fileID: 11400000, guid: 481ab1d7456efd044bc3e349aacd92ae, type: 2}
|
||||||
|
TickRate: 30
|
||||||
|
ClientConnectionBufferTimeout: 10
|
||||||
|
ConnectionApproval: 0
|
||||||
|
ConnectionData:
|
||||||
|
EnableTimeResync: 0
|
||||||
|
TimeResyncInterval: 30
|
||||||
|
EnsureNetworkVariableLengthSafety: 0
|
||||||
|
EnableSceneManagement: 1
|
||||||
|
ForceSamePrefabs: 1
|
||||||
|
RecycleNetworkIds: 1
|
||||||
|
NetworkIdRecycleDelay: 120
|
||||||
|
RpcHashSize: 0
|
||||||
|
LoadSceneTimeOut: 120
|
||||||
|
SpawnTimeout: 10
|
||||||
|
EnableNetworkLogs: 1
|
||||||
|
NetworkTopology: 0
|
||||||
|
UseCMBService: 0
|
||||||
|
AutoSpawnPlayerPrefabClientSide: 1
|
||||||
|
NetworkProfilingMetrics: 1
|
||||||
|
OldPrefabList: []
|
||||||
|
RunInBackground: 1
|
||||||
|
LogLevel: 1
|
||||||
|
--- !u!4 &769692009
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 769692006}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!1 &961739749
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 961739753}
|
||||||
|
- component: {fileID: 961739752}
|
||||||
|
- component: {fileID: 961739751}
|
||||||
|
- component: {fileID: 961739750}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Main Camera
|
||||||
|
m_TagString: MainCamera
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!114 &961739750
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 961739749}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_RenderShadows: 1
|
||||||
|
m_RequiresDepthTextureOption: 2
|
||||||
|
m_RequiresOpaqueTextureOption: 2
|
||||||
|
m_CameraType: 0
|
||||||
|
m_Cameras: []
|
||||||
|
m_RendererIndex: -1
|
||||||
|
m_VolumeLayerMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 1
|
||||||
|
m_VolumeTrigger: {fileID: 0}
|
||||||
|
m_VolumeFrameworkUpdateModeOption: 2
|
||||||
|
m_RenderPostProcessing: 0
|
||||||
|
m_Antialiasing: 0
|
||||||
|
m_AntialiasingQuality: 2
|
||||||
|
m_StopNaN: 0
|
||||||
|
m_Dithering: 0
|
||||||
|
m_ClearDepth: 1
|
||||||
|
m_AllowXRRendering: 1
|
||||||
|
m_AllowHDROutput: 1
|
||||||
|
m_UseScreenCoordOverride: 0
|
||||||
|
m_ScreenSizeOverride: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_RequiresDepthTexture: 0
|
||||||
|
m_RequiresColorTexture: 0
|
||||||
|
m_TaaSettings:
|
||||||
|
m_Quality: 3
|
||||||
|
m_FrameInfluence: 0.1
|
||||||
|
m_JitterScale: 1
|
||||||
|
m_MipBias: 0
|
||||||
|
m_VarianceClampScale: 0.9
|
||||||
|
m_ContrastAdaptiveSharpening: 0
|
||||||
|
m_Version: 2
|
||||||
|
--- !u!81 &961739751
|
||||||
|
AudioListener:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 961739749}
|
||||||
|
m_Enabled: 1
|
||||||
|
--- !u!20 &961739752
|
||||||
|
Camera:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 961739749}
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 2
|
||||||
|
m_ClearFlags: 1
|
||||||
|
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
|
||||||
|
m_projectionMatrixMode: 1
|
||||||
|
m_GateFitMode: 2
|
||||||
|
m_FOVAxisMode: 0
|
||||||
|
m_Iso: 200
|
||||||
|
m_ShutterSpeed: 0.005
|
||||||
|
m_Aperture: 16
|
||||||
|
m_FocusDistance: 10
|
||||||
|
m_FocalLength: 50
|
||||||
|
m_BladeCount: 5
|
||||||
|
m_Curvature: {x: 2, y: 11}
|
||||||
|
m_BarrelClipping: 0.25
|
||||||
|
m_Anamorphism: 0
|
||||||
|
m_SensorSize: {x: 36, y: 24}
|
||||||
|
m_LensShift: {x: 0, y: 0}
|
||||||
|
m_NormalizedViewPortRect:
|
||||||
|
serializedVersion: 2
|
||||||
|
x: 0
|
||||||
|
y: 0
|
||||||
|
width: 1
|
||||||
|
height: 1
|
||||||
|
near clip plane: 0.3
|
||||||
|
far clip plane: 1000
|
||||||
|
field of view: 60
|
||||||
|
orthographic: 0
|
||||||
|
orthographic size: 5
|
||||||
|
m_Depth: -1
|
||||||
|
m_CullingMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
m_RenderingPath: -1
|
||||||
|
m_TargetTexture: {fileID: 0}
|
||||||
|
m_TargetDisplay: 0
|
||||||
|
m_TargetEye: 3
|
||||||
|
m_HDR: 1
|
||||||
|
m_AllowMSAA: 1
|
||||||
|
m_AllowDynamicResolution: 0
|
||||||
|
m_ForceIntoRT: 0
|
||||||
|
m_OcclusionCulling: 1
|
||||||
|
m_StereoConvergence: 10
|
||||||
|
m_StereoSeparation: 0.022
|
||||||
|
--- !u!4 &961739753
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 961739749}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!1 &1648104262
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 1648104264}
|
||||||
|
- component: {fileID: 1648104263}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: SessionFlow
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!114 &1648104263
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1648104262}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 474003b8e462dcc479e313f3d4f1cf12, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: Assembly-CSharp::TD.Net.SessionFlow
|
||||||
|
--- !u!4 &1648104264
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1648104262}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!1660057539 &9223372036854775807
|
||||||
|
SceneRoots:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_Roots:
|
||||||
|
- {fileID: 961739753}
|
||||||
|
- {fileID: 203844589}
|
||||||
|
- {fileID: 769692009}
|
||||||
|
- {fileID: 1648104264}
|
||||||
|
- {fileID: 626141754}
|
||||||
|
- {fileID: 514623722}
|
||||||
7
Assets/_Project/Scenes/UI/MainMenu.unity.meta
Normal file
7
Assets/_Project/Scenes/UI/MainMenu.unity.meta
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1f4cb4a6391f5e94285960890282b70e
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -73,14 +73,24 @@ namespace TD.Core
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Identifies the race a player has chosen in the race-pick phase.
|
/// Stable identifier per race. Values 1-16 reserve slots for the planned
|
||||||
/// Backed by byte. Specific race values are defined in Phase 1.8.
|
/// 16-race grid in the lobby; only races with a corresponding
|
||||||
|
/// <c>RaceDefinition</c> asset registered with <c>RaceRegistry</c> are
|
||||||
|
/// playable. Unregistered slots render as "Coming Soon" in the selection UI.
|
||||||
|
///
|
||||||
|
/// Names are intentionally generic so display names / lore can be authored
|
||||||
|
/// on the asset without renaming the enum — renaming would change byte
|
||||||
|
/// values and break save data once persistence lands.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum RaceId : byte
|
public enum RaceId : byte
|
||||||
{
|
{
|
||||||
/// <summary>No race selected yet (lobby / pre-pick).</summary>
|
/// <summary>No race selected yet (lobby / pre-pick).</summary>
|
||||||
None = 0,
|
None = 0,
|
||||||
// Race entries added in Phase 1.8.
|
|
||||||
|
Race1 = 1, Race2 = 2, Race3 = 3, Race4 = 4,
|
||||||
|
Race5 = 5, Race6 = 6, Race7 = 7, Race8 = 8,
|
||||||
|
Race9 = 9, Race10 = 10, Race11 = 11, Race12 = 12,
|
||||||
|
Race13 = 13, Race14 = 14, Race15 = 15, Race16 = 16,
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum PlayerSlot : byte
|
public enum PlayerSlot : byte
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,18 @@
|
||||||
// Assets/_Project/Scripts/Gameplay/PlayerBuilderSpawner.cs
|
// Assets/_Project/Scripts/Gameplay/PlayerBuilderSpawner.cs
|
||||||
|
using System.Collections.Generic;
|
||||||
using Unity.Netcode;
|
using Unity.Netcode;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityEngine.SceneManagement;
|
||||||
using TD.Core;
|
using TD.Core;
|
||||||
using TD.Levels;
|
using TD.Levels;
|
||||||
|
using TD.Net;
|
||||||
|
|
||||||
namespace TD.Gameplay
|
namespace TD.Gameplay
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lives on the Player Prefab. On the server, when the player NetworkObject spawns,
|
/// Lives on the Player Prefab. On the server, spawns and re-spawns a separate
|
||||||
/// instantiates and spawns a separate <see cref="Builder"/> NetworkObject owned by that
|
/// <see cref="Builder"/> NetworkObject owned by this player each time the Match
|
||||||
/// player. The builder is positioned at the centroid of the player's zone before spawn.
|
/// scene loads. The builder is positioned at the centroid of the player's zone.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// <para><b>Why a separate NetworkObject?</b> Multi-builder races (Path E) become "spawn
|
/// <para><b>Why a separate NetworkObject?</b> Multi-builder races (Path E) become "spawn
|
||||||
|
|
@ -20,31 +23,79 @@ namespace TD.Gameplay
|
||||||
/// no-ops; they just receive the resulting Builder NetworkObject like any other
|
/// no-ops; they just receive the resulting Builder NetworkObject like any other
|
||||||
/// replicated spawn.</para>
|
/// replicated spawn.</para>
|
||||||
///
|
///
|
||||||
/// <para><b>Lifetime.</b> The spawned builder is destroyed when the player NetworkObject
|
/// <para><b>Lifetime & scene flow.</b> The player NetworkObject persists across
|
||||||
/// despawns (e.g., disconnect). NGO does this automatically because we set
|
/// scenes (MainMenu → Lobby → Match → Lobby …) because it's the
|
||||||
/// <c>destroyWithScene</c> and store no other references — the builder's despawn cleans
|
/// <c>NetworkManager.PlayerPrefab</c>. The Builder is spawned with
|
||||||
/// up the static registry in <see cref="Builder.OnNetworkDespawn"/>.</para>
|
/// <c>destroyWithScene: true</c> so it's torn down on every scene unload — we
|
||||||
|
/// only want a builder in the Match scene. <see cref="HandleSceneLoadCompleted"/>
|
||||||
|
/// re-spawns when entering Match; <see cref="OnNetworkDespawn"/> handles
|
||||||
|
/// disconnect cleanup.</para>
|
||||||
|
///
|
||||||
|
/// <para><b>Race-driven builder prefab.</b> If a <see cref="RaceRegistry"/> exists
|
||||||
|
/// in the Match scene AND the player's selected <see cref="RaceDefinition"/> has
|
||||||
|
/// a <c>BuilderPrefab</c> assigned, that prefab is used. Otherwise this falls back
|
||||||
|
/// to the inspector-assigned <see cref="builderPrefab"/> (the universal default).
|
||||||
|
/// Phase 1.8 races just need to fill in their <c>BuilderPrefab</c> field; no code
|
||||||
|
/// change required.</para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public class PlayerBuilderSpawner : NetworkBehaviour
|
public class PlayerBuilderSpawner : NetworkBehaviour
|
||||||
{
|
{
|
||||||
[Tooltip("Builder prefab to instantiate. Must be registered with the NetworkManager " +
|
[Tooltip("Default Builder prefab. Used when the player's race has no BuilderPrefab " +
|
||||||
"as a network prefab.")]
|
"assigned (or when no RaceRegistry is present in the scene). Must be " +
|
||||||
|
"registered with the NetworkManager as a network prefab.")]
|
||||||
[SerializeField] private GameObject builderPrefab;
|
[SerializeField] private GameObject builderPrefab;
|
||||||
|
|
||||||
// Cached reference so we can despawn the builder if needed (e.g., player disconnects).
|
// Cached reference so we can despawn the builder if needed (e.g., player disconnects).
|
||||||
private NetworkObject spawnedBuilder;
|
private NetworkObject spawnedBuilder;
|
||||||
|
|
||||||
|
// Track our scene-load subscription state so we can clean up correctly.
|
||||||
|
private bool sceneSubscribed;
|
||||||
|
|
||||||
public override void OnNetworkSpawn()
|
public override void OnNetworkSpawn()
|
||||||
{
|
{
|
||||||
if (!IsServer) return;
|
if (!IsServer) return;
|
||||||
|
|
||||||
if (builderPrefab == null)
|
if (builderPrefab == null)
|
||||||
{
|
{
|
||||||
Debug.LogError("[PlayerBuilderSpawner] No Builder prefab assigned. " +
|
Debug.LogError("[PlayerBuilderSpawner] No default Builder prefab assigned. " +
|
||||||
"Cannot spawn builder for client " + OwnerClientId + ".");
|
"Cannot spawn builder for client " + OwnerClientId + ".");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Subscribe to NGO's scene-load completion so we re-spawn the builder
|
||||||
|
// every time the Match scene comes up (initial match start, Retry, etc.).
|
||||||
|
if (NetworkManager != null && NetworkManager.SceneManager != null)
|
||||||
|
{
|
||||||
|
NetworkManager.SceneManager.OnLoadEventCompleted += HandleSceneLoadCompleted;
|
||||||
|
sceneSubscribed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Edge case: the player connected while a match is already in progress.
|
||||||
|
// The Match scene is already loaded, so OnLoadEventCompleted won't fire
|
||||||
|
// again until the next transition. Spawn now.
|
||||||
|
if (SceneManager.GetActiveScene().name == SceneNames.Match)
|
||||||
|
TrySpawnBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
// NGO fires this on the server once a scene load is acknowledged complete
|
||||||
|
// by every connected client (or timed out). We only act when the Match
|
||||||
|
// scene loads; Lobby / MainMenu loads are no-ops here.
|
||||||
|
private void HandleSceneLoadCompleted(string sceneName,
|
||||||
|
LoadSceneMode loadSceneMode,
|
||||||
|
List<ulong> clientsCompleted,
|
||||||
|
List<ulong> clientsTimedOut)
|
||||||
|
{
|
||||||
|
if (!IsServer) return;
|
||||||
|
if (sceneName != SceneNames.Match) return;
|
||||||
|
TrySpawnBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spawns the builder if it doesn't already exist. Defers to a SlotReady
|
||||||
|
// event if PlayerMatchState hasn't finished assigning the slot yet.
|
||||||
|
private void TrySpawnBuilder()
|
||||||
|
{
|
||||||
|
if (spawnedBuilder != null && spawnedBuilder.IsSpawned) return;
|
||||||
|
|
||||||
var pms = GetComponent<PlayerMatchState>();
|
var pms = GetComponent<PlayerMatchState>();
|
||||||
if (pms == null)
|
if (pms == null)
|
||||||
{
|
{
|
||||||
|
|
@ -53,8 +104,6 @@ namespace TD.Gameplay
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PlayerMatchState.OnNetworkSpawn may have already fired (component order: it first)
|
|
||||||
// or may fire after us (component order: we first). Handle both cases.
|
|
||||||
if (pms.Slot != PlayerSlot.None)
|
if (pms.Slot != PlayerSlot.None)
|
||||||
SpawnBuilderForOwner(pms.Slot);
|
SpawnBuilderForOwner(pms.Slot);
|
||||||
else
|
else
|
||||||
|
|
@ -65,11 +114,21 @@ namespace TD.Gameplay
|
||||||
{
|
{
|
||||||
var pms = GetComponent<PlayerMatchState>();
|
var pms = GetComponent<PlayerMatchState>();
|
||||||
if (pms != null) pms.SlotReady -= OnOwnerSlotReady;
|
if (pms != null) pms.SlotReady -= OnOwnerSlotReady;
|
||||||
SpawnBuilderForOwner(slot);
|
|
||||||
|
// Only spawn if we're in the Match scene. SlotReady can fire in MainMenu
|
||||||
|
// (during initial connection) — we don't want a builder there.
|
||||||
|
if (SceneManager.GetActiveScene().name == SceneNames.Match)
|
||||||
|
SpawnBuilderForOwner(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnNetworkDespawn()
|
public override void OnNetworkDespawn()
|
||||||
{
|
{
|
||||||
|
if (sceneSubscribed && NetworkManager != null && NetworkManager.SceneManager != null)
|
||||||
|
{
|
||||||
|
NetworkManager.SceneManager.OnLoadEventCompleted -= HandleSceneLoadCompleted;
|
||||||
|
sceneSubscribed = false;
|
||||||
|
}
|
||||||
|
|
||||||
// When the player despawns (disconnect), also despawn their builder if it still exists.
|
// When the player despawns (disconnect), also despawn their builder if it still exists.
|
||||||
if (IsServer && spawnedBuilder != null && spawnedBuilder.IsSpawned)
|
if (IsServer && spawnedBuilder != null && spawnedBuilder.IsSpawned)
|
||||||
{
|
{
|
||||||
|
|
@ -84,7 +143,19 @@ namespace TD.Gameplay
|
||||||
// Falls back to origin if loader/zone data isn't available.
|
// Falls back to origin if loader/zone data isn't available.
|
||||||
Vector3 spawnPos = ComputeZoneCentroid(slot);
|
Vector3 spawnPos = ComputeZoneCentroid(slot);
|
||||||
|
|
||||||
var go = Instantiate(builderPrefab, spawnPos, Quaternion.identity);
|
// Pick the prefab: race-specific takes priority, default falls back.
|
||||||
|
// Falling back is what lets all races share the default builder
|
||||||
|
// during Phase 1.7 — each RaceDefinition just needs the same default
|
||||||
|
// assigned, and the spawner picks it up automatically.
|
||||||
|
GameObject prefab = ResolveBuilderPrefab();
|
||||||
|
if (prefab == null)
|
||||||
|
{
|
||||||
|
Debug.LogError("[PlayerBuilderSpawner] No builder prefab available. " +
|
||||||
|
"Set the default in the inspector or assign one to the player's race.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var go = Instantiate(prefab, spawnPos, Quaternion.identity);
|
||||||
var netObj = go.GetComponent<NetworkObject>();
|
var netObj = go.GetComponent<NetworkObject>();
|
||||||
if (netObj == null)
|
if (netObj == null)
|
||||||
{
|
{
|
||||||
|
|
@ -114,6 +185,22 @@ namespace TD.Gameplay
|
||||||
|
|
||||||
// ----- Helpers ----------------------------------------------------
|
// ----- Helpers ----------------------------------------------------
|
||||||
|
|
||||||
|
// Picks the builder prefab to spawn for this player. Race-specific takes
|
||||||
|
// priority when (a) RaceRegistry is in the scene, (b) the player picked
|
||||||
|
// a race, and (c) that race's RaceDefinition has a BuilderPrefab assigned.
|
||||||
|
// Otherwise falls back to the inspector-assigned default.
|
||||||
|
private GameObject ResolveBuilderPrefab()
|
||||||
|
{
|
||||||
|
var pms = GetComponent<PlayerMatchState>();
|
||||||
|
if (pms != null && pms.RaceSelection != RaceId.None && RaceRegistry.Instance != null)
|
||||||
|
{
|
||||||
|
var raceDef = RaceRegistry.Instance.Get(pms.RaceSelection);
|
||||||
|
if (raceDef != null && raceDef.BuilderPrefab != null)
|
||||||
|
return raceDef.BuilderPrefab;
|
||||||
|
}
|
||||||
|
return builderPrefab;
|
||||||
|
}
|
||||||
|
|
||||||
private static Vector3 ComputeZoneCentroid(PlayerSlot slot)
|
private static Vector3 ComputeZoneCentroid(PlayerSlot slot)
|
||||||
{
|
{
|
||||||
var loader = LevelLoader.Instance;
|
var loader = LevelLoader.Instance;
|
||||||
|
|
|
||||||
75
Assets/_Project/Scripts/Gameplay/RaceDefinition.cs
Normal file
75
Assets/_Project/Scripts/Gameplay/RaceDefinition.cs
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
// Assets/_Project/Scripts/Gameplay/RaceDefinition.cs
|
||||||
|
using UnityEngine;
|
||||||
|
using TD.Core;
|
||||||
|
using TD.Towers;
|
||||||
|
|
||||||
|
namespace TD.Gameplay
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// One asset per playable race. Holds the race's identity (the
|
||||||
|
/// <see cref="RaceId"/> binding for networked selection), the visual + lore
|
||||||
|
/// content shown in the lobby's race-selection UI, and stub fields for the
|
||||||
|
/// Phase 1.8 gameplay payload (race-specific builder + tower roster).
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para><b>Creating a new race.</b> Right-click in the project window →
|
||||||
|
/// <c>Create → TD → Race Definition</c>. Fill in the inspector:
|
||||||
|
/// <list type="bullet">
|
||||||
|
/// <item><b>Id</b> — pick an unused <see cref="RaceId"/> value (Race1..Race16).</item>
|
||||||
|
/// <item><b>Display Name</b> — what shows in the grid + detail header.</item>
|
||||||
|
/// <item><b>Icon</b> — square sprite, ~256x256, drawn in the grid + detail.</item>
|
||||||
|
/// <item><b>Builder Name / Description</b> — text in the detail panel.</item>
|
||||||
|
/// <item><b>Lore Text</b> — longer description in the detail panel.</item>
|
||||||
|
/// <item><b>Builder Prefab / Towers</b> — <i>stubs</i>, wired in Phase 1.8.</item>
|
||||||
|
/// </list>
|
||||||
|
/// Then drag the asset into the <c>RaceRegistry</c>'s <c>Definitions</c>
|
||||||
|
/// array on the scene's <c>RaceRegistry</c> GameObject.</para>
|
||||||
|
///
|
||||||
|
/// <para><b>Why <see cref="Id"/> is serialized rather than inferred from the
|
||||||
|
/// asset name.</b> Race selection is networked via a
|
||||||
|
/// <see cref="UnityEngine.SerializeField"/>-backed enum on
|
||||||
|
/// <c>PlayerMatchState</c>. The enum byte value is the wire identity; the
|
||||||
|
/// asset is just the local lookup. Keeping the binding explicit on the
|
||||||
|
/// asset prevents accidental drift if assets get renamed.</para>
|
||||||
|
/// </remarks>
|
||||||
|
[CreateAssetMenu(fileName = "RaceDefinition", menuName = "TD/Race Definition", order = 5)]
|
||||||
|
public class RaceDefinition : ScriptableObject
|
||||||
|
{
|
||||||
|
[Header("Identity")]
|
||||||
|
[Tooltip("Enum value used by PlayerMatchState.RaceSelection on the network. " +
|
||||||
|
"Pick an unused RaceId (Race1..Race16). Each asset must use a unique value.")]
|
||||||
|
public RaceId Id = RaceId.None;
|
||||||
|
|
||||||
|
[Tooltip("Race name shown in the lobby grid and detail panel header.")]
|
||||||
|
public string DisplayName;
|
||||||
|
|
||||||
|
[Tooltip("Square icon shown in the grid cell and as the larger image in the detail panel. " +
|
||||||
|
"~256x256 PNG works well; the UI scales to fit.")]
|
||||||
|
public Sprite Icon;
|
||||||
|
|
||||||
|
[Header("Builder")]
|
||||||
|
[Tooltip("Builder name shown in the detail panel (the builder is the in-match avatar " +
|
||||||
|
"that gates tower placement by proximity).")]
|
||||||
|
public string BuilderName;
|
||||||
|
|
||||||
|
[Tooltip("Short description of the builder shown beneath the name in the detail panel.")]
|
||||||
|
[TextArea(2, 4)]
|
||||||
|
public string BuilderDescription;
|
||||||
|
|
||||||
|
[Header("Lore")]
|
||||||
|
[Tooltip("Race lore / background shown in the detail panel. Lorem ipsum is fine " +
|
||||||
|
"for placeholder races; replace when actual writing is ready.")]
|
||||||
|
[TextArea(5, 15)]
|
||||||
|
public string LoreText;
|
||||||
|
|
||||||
|
[Header("Gameplay payload (Phase 1.8 — not wired yet)")]
|
||||||
|
[Tooltip("STUB (Phase 1.8): race-specific builder prefab. Currently every race spawns " +
|
||||||
|
"the default builder. When Phase 1.8 lands, PlayerBuilderSpawner will pick " +
|
||||||
|
"the prefab based on the player's RaceSelection.")]
|
||||||
|
public GameObject BuilderPrefab;
|
||||||
|
|
||||||
|
[Tooltip("STUB (Phase 1.8): tower roster available to this race. TowerRegistry will " +
|
||||||
|
"filter to this list when the active player belongs to this race.")]
|
||||||
|
public TowerDefinition[] Towers;
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Assets/_Project/Scripts/Gameplay/RaceDefinition.cs.meta
Normal file
2
Assets/_Project/Scripts/Gameplay/RaceDefinition.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 98b7d5d116870f94da912007f6aa5cbb
|
||||||
152
Assets/_Project/Scripts/Gameplay/RaceRegistry.cs
Normal file
152
Assets/_Project/Scripts/Gameplay/RaceRegistry.cs
Normal file
|
|
@ -0,0 +1,152 @@
|
||||||
|
// Assets/_Project/Scripts/Gameplay/RaceRegistry.cs
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using TD.Core;
|
||||||
|
|
||||||
|
namespace TD.Gameplay
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Persistent (DontDestroyOnLoad) singleton that holds every
|
||||||
|
/// <see cref="RaceDefinition"/> available in the current build and lets
|
||||||
|
/// any code look one up by <see cref="RaceId"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para><b>Inspector setup.</b> Place ONE <c>RaceRegistry</c> GameObject in
|
||||||
|
/// the <b>MainMenu scene</b> only. Drag every <c>RaceDefinition</c> asset
|
||||||
|
/// into the <c>Definitions</c> array. The registry marks itself
|
||||||
|
/// <c>DontDestroyOnLoad</c> on Awake, so it survives the scene transitions
|
||||||
|
/// MainMenu → Lobby → Match → back to Lobby and is available to all of
|
||||||
|
/// them through <see cref="Instance"/>.</para>
|
||||||
|
///
|
||||||
|
/// <para><b>Why not also in Lobby/Match scenes?</b> Maintaining the
|
||||||
|
/// <c>Definitions</c> array in multiple places is a designer trap — update
|
||||||
|
/// one, forget the other, runtime mismatch. Single source of truth in
|
||||||
|
/// MainMenu eliminates that class of bug. Duplicate instances in other
|
||||||
|
/// scenes are detected in <see cref="Awake"/> and self-destruct, so an
|
||||||
|
/// accidental copy doesn't break anything but does log a warning.</para>
|
||||||
|
///
|
||||||
|
/// <para><b>Editor-only standalone testing.</b> If you open the Lobby or
|
||||||
|
/// Match scene directly from the editor (without going through MainMenu
|
||||||
|
/// first), no RaceRegistry will exist and race-dependent code falls back
|
||||||
|
/// gracefully (<see cref="Get"/> returns null; UI shows "Coming Soon" or
|
||||||
|
/// the default builder is used). For standalone-scene testing, you can
|
||||||
|
/// temporarily add a registry to whatever scene you're testing — but don't
|
||||||
|
/// commit it as part of normal play flow.</para>
|
||||||
|
///
|
||||||
|
/// <para><b>Slot model.</b> The lobby grid shows 16 slots (one per
|
||||||
|
/// <see cref="RaceId"/> value 1-16) regardless of how many are filled.
|
||||||
|
/// <see cref="Get"/> returns null for unregistered slots, which the UI
|
||||||
|
/// renders as a "Coming Soon" placeholder.</para>
|
||||||
|
///
|
||||||
|
/// <para><b>Plain MonoBehaviour.</b> Not a NetworkBehaviour — the registry
|
||||||
|
/// is identical on every peer (same ScriptableObject assets), so nothing
|
||||||
|
/// to sync. Network state tracks only the chosen <see cref="RaceId"/> on
|
||||||
|
/// <c>PlayerMatchState</c>; the rest is local lookup.</para>
|
||||||
|
/// </remarks>
|
||||||
|
public class RaceRegistry : MonoBehaviour
|
||||||
|
{
|
||||||
|
// ----- Singleton -------------------------------------------------
|
||||||
|
|
||||||
|
public static RaceRegistry Instance { get; private set; }
|
||||||
|
|
||||||
|
// ----- Inspector --------------------------------------------------
|
||||||
|
|
||||||
|
[Tooltip("All RaceDefinition assets available in this build. Drag each asset " +
|
||||||
|
"into the array. Duplicate Ids are rejected with a warning; null entries " +
|
||||||
|
"are skipped.")]
|
||||||
|
[SerializeField] private RaceDefinition[] definitions;
|
||||||
|
|
||||||
|
// ----- Internal lookup -------------------------------------------
|
||||||
|
|
||||||
|
private readonly Dictionary<RaceId, RaceDefinition> byId
|
||||||
|
= new Dictionary<RaceId, RaceDefinition>();
|
||||||
|
|
||||||
|
// ----- Lifecycle --------------------------------------------------
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
// Persistent-singleton pattern: the FIRST instance to wake up wins
|
||||||
|
// and survives scene loads. Subsequent instances (e.g. a stale
|
||||||
|
// copy left over in the Lobby or Match scene) are self-destroyed,
|
||||||
|
// not just ignored — we want the scene to "self-heal" if someone
|
||||||
|
// accidentally drops a second copy in.
|
||||||
|
if (Instance != null && Instance != this)
|
||||||
|
{
|
||||||
|
Debug.LogWarning(
|
||||||
|
$"[RaceRegistry] Persistent instance already exists. " +
|
||||||
|
$"Destroying duplicate in scene '{gameObject.scene.name}'. " +
|
||||||
|
$"Keep RaceRegistry in the MainMenu scene only.");
|
||||||
|
Destroy(gameObject);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Instance = this;
|
||||||
|
DontDestroyOnLoad(gameObject);
|
||||||
|
BuildLookup();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDestroy()
|
||||||
|
{
|
||||||
|
if (Instance == this) Instance = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- Public API -------------------------------------------------
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the <see cref="RaceDefinition"/> for the given id, or null
|
||||||
|
/// if no asset is registered for that id (e.g. "Coming Soon" slots).
|
||||||
|
/// </summary>
|
||||||
|
public RaceDefinition Get(RaceId id)
|
||||||
|
{
|
||||||
|
byId.TryGetValue(id, out var def);
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Iterates the canonical 16 lobby slots (Race1..Race16). For each
|
||||||
|
/// slot returns either the registered <see cref="RaceDefinition"/> or
|
||||||
|
/// null. UI consumers use this to render a stable 16-cell grid where
|
||||||
|
/// unfilled slots show a placeholder.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<(RaceId id, RaceDefinition def)> AllSlots()
|
||||||
|
{
|
||||||
|
for (int i = (int)RaceId.Race1; i <= (int)RaceId.Race16; i++)
|
||||||
|
{
|
||||||
|
var id = (RaceId)i;
|
||||||
|
yield return (id, Get(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- Private ----------------------------------------------------
|
||||||
|
|
||||||
|
private void BuildLookup()
|
||||||
|
{
|
||||||
|
byId.Clear();
|
||||||
|
if (definitions == null || definitions.Length == 0)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("[RaceRegistry] No RaceDefinition assets assigned. " +
|
||||||
|
"Drag assets into the Definitions array.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var def in definitions)
|
||||||
|
{
|
||||||
|
if (def == null) continue;
|
||||||
|
if (def.Id == RaceId.None)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"[RaceRegistry] '{def.name}' has Id=None — set it to " +
|
||||||
|
"an unused Race1..Race16 value.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (byId.ContainsKey(def.Id))
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"[RaceRegistry] Duplicate Id '{def.Id}' detected on " +
|
||||||
|
$"'{def.name}'. Earlier registration kept; rename one.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
byId[def.Id] = def;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Log($"[RaceRegistry] Registered {byId.Count} race(s).");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Assets/_Project/Scripts/Gameplay/RaceRegistry.cs.meta
Normal file
2
Assets/_Project/Scripts/Gameplay/RaceRegistry.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 50ccfdaa301b6a7439b4edfc750550aa
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
// Assets/_Project/Scripts/UI/LobbyController.cs
|
// Assets/_Project/Scripts/UI/LobbyController.cs
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using Unity.Netcode;
|
using Unity.Netcode;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UIElements;
|
using UnityEngine.UIElements;
|
||||||
|
|
@ -45,6 +46,22 @@ namespace TD.UI
|
||||||
private Button leaveButton;
|
private Button leaveButton;
|
||||||
private Label statusLabel;
|
private Label statusLabel;
|
||||||
|
|
||||||
|
// ----- Race selection overlay ------------------------------------
|
||||||
|
|
||||||
|
[Tooltip("Sibling RaceSelectionOverlay component that owns the race-pick UI. " +
|
||||||
|
"Auto-located on the same GameObject if not assigned.")]
|
||||||
|
[SerializeField] private RaceSelectionOverlay raceOverlay;
|
||||||
|
|
||||||
|
// Snapshot of player-list state from the last rebuild. RefreshPlayerList
|
||||||
|
// skips rebuilding when this matches the current frame's signature —
|
||||||
|
// critical because rebuilding every frame destroys the per-row buttons
|
||||||
|
// mid-click, and UI Toolkit's Clickable manipulator needs the same
|
||||||
|
// element instance to receive PointerDown AND PointerUp for the action
|
||||||
|
// to fire. Pre-fix, clicks on Select Race / Ready / Unready were silently
|
||||||
|
// lost because the button was destroyed between press and release.
|
||||||
|
private string lastPlayerListSignature = string.Empty;
|
||||||
|
private readonly StringBuilder signatureBuffer = new StringBuilder();
|
||||||
|
|
||||||
// ----- Lifecycle --------------------------------------------------
|
// ----- Lifecycle --------------------------------------------------
|
||||||
|
|
||||||
private void Start()
|
private void Start()
|
||||||
|
|
@ -59,6 +76,13 @@ namespace TD.UI
|
||||||
}
|
}
|
||||||
|
|
||||||
BuildUI(root);
|
BuildUI(root);
|
||||||
|
|
||||||
|
// Initialize the race overlay with our root so it can install its
|
||||||
|
// UI elements on top of the lobby. Hidden by default.
|
||||||
|
if (raceOverlay == null) raceOverlay = GetComponent<RaceSelectionOverlay>();
|
||||||
|
if (raceOverlay != null) raceOverlay.Initialize(root);
|
||||||
|
else Debug.LogWarning("[LobbyController] No RaceSelectionOverlay component found — " +
|
||||||
|
"race-picker button will be disabled. Add one to this GameObject.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Update()
|
private void Update()
|
||||||
|
|
@ -131,16 +155,23 @@ namespace TD.UI
|
||||||
|
|
||||||
private void RefreshPlayerList()
|
private void RefreshPlayerList()
|
||||||
{
|
{
|
||||||
|
// Sort by slot for stable ordering. AllPlayers is keyed by clientId
|
||||||
|
// which may not be slot-ordered.
|
||||||
|
var players = PlayerMatchState.AllPlayers.OrderBy(p => (int)p.Slot).ToList();
|
||||||
|
|
||||||
|
// Skip rebuild when the player-relevant state hasn't changed.
|
||||||
|
// Without this guard the per-row buttons are destroyed every frame,
|
||||||
|
// which loses clicks (see lastPlayerListSignature comment above).
|
||||||
|
string signature = ComputePlayerListSignature(players);
|
||||||
|
if (signature == lastPlayerListSignature) return;
|
||||||
|
lastPlayerListSignature = signature;
|
||||||
|
|
||||||
playerListContainer.Clear();
|
playerListContainer.Clear();
|
||||||
|
|
||||||
ulong localId = NetworkManager.Singleton != null
|
ulong localId = NetworkManager.Singleton != null
|
||||||
? NetworkManager.Singleton.LocalClientId
|
? NetworkManager.Singleton.LocalClientId
|
||||||
: ulong.MaxValue;
|
: ulong.MaxValue;
|
||||||
|
|
||||||
// Sort by slot for stable ordering. AllPlayers is keyed by clientId
|
|
||||||
// which may not be slot-ordered.
|
|
||||||
var players = PlayerMatchState.AllPlayers.OrderBy(p => (int)p.Slot).ToList();
|
|
||||||
|
|
||||||
foreach (var pms in players)
|
foreach (var pms in players)
|
||||||
{
|
{
|
||||||
bool isLocal = pms.OwnerClientId == localId;
|
bool isLocal = pms.OwnerClientId == localId;
|
||||||
|
|
@ -151,6 +182,26 @@ namespace TD.UI
|
||||||
playerListContainer.Add(new Label("(no players connected)") { style = { color = Color.gray } });
|
playerListContainer.Add(new Label("(no players connected)") { style = { color = Color.gray } });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compact signature of every field the player rows depend on. When this
|
||||||
|
// changes we rebuild; when it's identical we leave the existing rows
|
||||||
|
// (and their button event handlers) intact for click handling.
|
||||||
|
private string ComputePlayerListSignature(System.Collections.Generic.List<PlayerMatchState> players)
|
||||||
|
{
|
||||||
|
signatureBuffer.Clear();
|
||||||
|
foreach (var pms in players)
|
||||||
|
{
|
||||||
|
signatureBuffer.Append(pms.OwnerClientId);
|
||||||
|
signatureBuffer.Append(':');
|
||||||
|
signatureBuffer.Append((int)pms.Slot);
|
||||||
|
signatureBuffer.Append(':');
|
||||||
|
signatureBuffer.Append((int)pms.RaceSelection);
|
||||||
|
signatureBuffer.Append(':');
|
||||||
|
signatureBuffer.Append(pms.IsReady ? '1' : '0');
|
||||||
|
signatureBuffer.Append(';');
|
||||||
|
}
|
||||||
|
return signatureBuffer.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
private VisualElement BuildPlayerRow(PlayerMatchState pms, bool isLocal)
|
private VisualElement BuildPlayerRow(PlayerMatchState pms, bool isLocal)
|
||||||
{
|
{
|
||||||
var row = new VisualElement();
|
var row = new VisualElement();
|
||||||
|
|
@ -200,23 +251,17 @@ namespace TD.UI
|
||||||
// Local-only controls.
|
// Local-only controls.
|
||||||
if (isLocal)
|
if (isLocal)
|
||||||
{
|
{
|
||||||
// PLACEHOLDER race picker — the RaceId enum only has None right
|
// Race selection — opens the overlay that lets the player browse
|
||||||
// now (Phase 1.8 will fill it). For now the single button submits
|
// the 4x4 race grid and pick one. The overlay handles submission
|
||||||
// RaceId.None, which keeps the ready-up gate effectively a no-op
|
// (PlayerMatchState.SubmitRaceRpc) directly, so we just open it.
|
||||||
// (the server requires RaceSelection != None to allow ready). To
|
var pickRaceBtn = new Button(OpenRaceOverlay)
|
||||||
// exercise the flow end-to-end before races exist, comment out
|
|
||||||
// the gate in PlayerMatchState.SubmitReadyRpc.
|
|
||||||
//
|
|
||||||
// TODO (Phase 1.8): replace with a dropdown of RaceDefinition
|
|
||||||
// assets discovered at runtime, each option calling
|
|
||||||
// pms.SubmitRaceRpc(definition.Id).
|
|
||||||
var pickRaceBtn = new Button(() => pms.SubmitRaceRpc(RaceId.None))
|
|
||||||
{
|
{
|
||||||
text = "Pick Race (stub)"
|
text = "Select Race"
|
||||||
};
|
};
|
||||||
pickRaceBtn.style.minWidth = 130;
|
pickRaceBtn.style.minWidth = 130;
|
||||||
pickRaceBtn.style.height = 28;
|
pickRaceBtn.style.height = 28;
|
||||||
pickRaceBtn.style.marginLeft = 12;
|
pickRaceBtn.style.marginLeft = 12;
|
||||||
|
pickRaceBtn.SetEnabled(raceOverlay != null);
|
||||||
row.Add(pickRaceBtn);
|
row.Add(pickRaceBtn);
|
||||||
|
|
||||||
var readyBtn = new Button(() => pms.SubmitReadyRpc(!pms.IsReady))
|
var readyBtn = new Button(() => pms.SubmitReadyRpc(!pms.IsReady))
|
||||||
|
|
@ -247,6 +292,16 @@ namespace TD.UI
|
||||||
|
|
||||||
// ----- Button handlers --------------------------------------------
|
// ----- Button handlers --------------------------------------------
|
||||||
|
|
||||||
|
private void OpenRaceOverlay()
|
||||||
|
{
|
||||||
|
if (raceOverlay == null)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("[LobbyController] Race overlay not assigned.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
raceOverlay.Show();
|
||||||
|
}
|
||||||
|
|
||||||
private void OnStartMatchClicked()
|
private void OnStartMatchClicked()
|
||||||
{
|
{
|
||||||
var svc = LobbyService.Instance;
|
var svc = LobbyService.Instance;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
// Assets/_Project/Scripts/UI/MainMenuController.cs
|
// Assets/_Project/Scripts/UI/MainMenuController.cs
|
||||||
|
using System.Collections;
|
||||||
using Unity.Netcode;
|
using Unity.Netcode;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UIElements;
|
using UnityEngine.UIElements;
|
||||||
|
using TD.Core;
|
||||||
|
using TD.Gameplay;
|
||||||
using TD.Net;
|
using TD.Net;
|
||||||
|
|
||||||
namespace TD.UI
|
namespace TD.UI
|
||||||
|
|
@ -44,6 +47,7 @@ namespace TD.UI
|
||||||
private Button hostButton;
|
private Button hostButton;
|
||||||
private Button joinButton;
|
private Button joinButton;
|
||||||
private Button quitButton;
|
private Button quitButton;
|
||||||
|
private Button quickStartButton;
|
||||||
private VisualElement joinPanel;
|
private VisualElement joinPanel;
|
||||||
private TextField joinAddressField;
|
private TextField joinAddressField;
|
||||||
private TextField joinPortField;
|
private TextField joinPortField;
|
||||||
|
|
@ -96,12 +100,14 @@ namespace TD.UI
|
||||||
buttonColumn.style.alignItems = Align.Center;
|
buttonColumn.style.alignItems = Align.Center;
|
||||||
root.Add(buttonColumn);
|
root.Add(buttonColumn);
|
||||||
|
|
||||||
hostButton = MakeMenuButton("Host Game", OnHostClicked);
|
hostButton = MakeMenuButton("Host Game", OnHostClicked);
|
||||||
joinButton = MakeMenuButton("Join Game", OnJoinClicked);
|
joinButton = MakeMenuButton("Join Game", OnJoinClicked);
|
||||||
quitButton = MakeMenuButton("Quit", OnQuitClicked);
|
quitButton = MakeMenuButton("Quit", OnQuitClicked);
|
||||||
|
quickStartButton = MakeMenuButton("Quick Start", OnQuickStartClicked);
|
||||||
buttonColumn.Add(hostButton);
|
buttonColumn.Add(hostButton);
|
||||||
buttonColumn.Add(joinButton);
|
buttonColumn.Add(joinButton);
|
||||||
buttonColumn.Add(quitButton);
|
buttonColumn.Add(quitButton);
|
||||||
|
buttonColumn.Add(quickStartButton);
|
||||||
|
|
||||||
// Join sub-panel — hidden until Join is clicked. Holds the IP+port
|
// Join sub-panel — hidden until Join is clicked. Holds the IP+port
|
||||||
// fields and the Connect / Cancel buttons.
|
// fields and the Connect / Cancel buttons.
|
||||||
|
|
@ -120,14 +126,14 @@ namespace TD.UI
|
||||||
joinAddressField = new TextField("Host address");
|
joinAddressField = new TextField("Host address");
|
||||||
joinAddressField.value = defaultJoinAddress;
|
joinAddressField.value = defaultJoinAddress;
|
||||||
joinAddressField.style.width = 280;
|
joinAddressField.style.width = 280;
|
||||||
joinAddressField.style.color = Color.white;
|
StyleJoinFieldText(joinAddressField);
|
||||||
joinPanel.Add(joinAddressField);
|
joinPanel.Add(joinAddressField);
|
||||||
|
|
||||||
joinPortField = new TextField("Port");
|
joinPortField = new TextField("Port");
|
||||||
joinPortField.value = defaultPort.ToString();
|
joinPortField.value = defaultPort.ToString();
|
||||||
joinPortField.style.width = 280;
|
joinPortField.style.width = 280;
|
||||||
joinPortField.style.marginTop = 8;
|
joinPortField.style.marginTop = 8;
|
||||||
joinPortField.style.color = Color.white;
|
StyleJoinFieldText(joinPortField);
|
||||||
joinPanel.Add(joinPortField);
|
joinPanel.Add(joinPortField);
|
||||||
|
|
||||||
var joinButtons = new VisualElement();
|
var joinButtons = new VisualElement();
|
||||||
|
|
@ -154,6 +160,19 @@ namespace TD.UI
|
||||||
root.Add(statusLabel);
|
root.Add(statusLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TextField's visible text color lives on the inner "unity-text-input"
|
||||||
|
// element, not on the TextField root. Setting it on the root alone
|
||||||
|
// leaves the inner element's inherited white color in place — which is
|
||||||
|
// invisible against the default white input background. Same gotcha as
|
||||||
|
// the chat input's dark-styling path in HUDController.
|
||||||
|
private static void StyleJoinFieldText(TextField field)
|
||||||
|
{
|
||||||
|
field.style.color = Color.black;
|
||||||
|
var inner = field.Q("unity-text-input");
|
||||||
|
if (inner != null)
|
||||||
|
inner.style.color = Color.black;
|
||||||
|
}
|
||||||
|
|
||||||
private static Button MakeMenuButton(string text, System.Action onClick)
|
private static Button MakeMenuButton(string text, System.Action onClick)
|
||||||
{
|
{
|
||||||
var btn = new Button(() => onClick?.Invoke()) { text = text };
|
var btn = new Button(() => onClick?.Invoke()) { text = text };
|
||||||
|
|
@ -229,5 +248,53 @@ namespace TD.UI
|
||||||
Application.Quit();
|
Application.Quit();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dev / testing shortcut: skips the lobby entirely. Hosts a single-player
|
||||||
|
// session, auto-selects Race1 for the local player, and loads the Match
|
||||||
|
// scene directly. Useful for iterating on gameplay without clicking
|
||||||
|
// through Host → Lobby → Pick Race → Ready → Start every time.
|
||||||
|
//
|
||||||
|
// To remove for a shipping build: delete the button-creation lines in
|
||||||
|
// BuildUI plus this method and its coroutine. No other consumers.
|
||||||
|
private void OnQuickStartClicked()
|
||||||
|
{
|
||||||
|
statusLabel.text = "Quick starting…";
|
||||||
|
StartCoroutine(QuickStartCoroutine());
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerator QuickStartCoroutine()
|
||||||
|
{
|
||||||
|
if (!NetworkBootstrap.StartHost(defaultPort))
|
||||||
|
{
|
||||||
|
statusLabel.text = "Failed to start host. Check the console.";
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the local player's PlayerMatchState to spawn. Empirically
|
||||||
|
// this happens synchronously inside StartHost, but waiting one frame
|
||||||
|
// is cheap insurance against future NGO changes to spawn timing.
|
||||||
|
// Cap the wait at 60 frames so a real failure doesn't silently hang.
|
||||||
|
int safetyFrames = 0;
|
||||||
|
while (PlayerMatchState.Local == null && safetyFrames++ < 60)
|
||||||
|
yield return null;
|
||||||
|
|
||||||
|
var pms = PlayerMatchState.Local;
|
||||||
|
if (pms == null)
|
||||||
|
{
|
||||||
|
Debug.LogError("[MainMenuController] Quick Start: PlayerMatchState.Local " +
|
||||||
|
"didn't appear within 60 frames after StartHost. Aborting.");
|
||||||
|
statusLabel.text = "Quick Start failed: player did not spawn.";
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server-only setters — host is server + client, so these are valid
|
||||||
|
// directly. Skipping the RPC round-trip avoids any frame-of-latency
|
||||||
|
// before LoadSceneAsHost reads RaceSelection on the way into Match.
|
||||||
|
pms.SetRaceSelection(RaceId.Race1);
|
||||||
|
pms.SetReady(true);
|
||||||
|
|
||||||
|
// Skip Lobby — drop straight into the Match scene.
|
||||||
|
NetworkBootstrap.LoadSceneAsHost(SceneNames.Match);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
510
Assets/_Project/Scripts/UI/RaceSelectionOverlay.cs
Normal file
510
Assets/_Project/Scripts/UI/RaceSelectionOverlay.cs
Normal file
|
|
@ -0,0 +1,510 @@
|
||||||
|
// Assets/_Project/Scripts/UI/RaceSelectionOverlay.cs
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Unity.Netcode;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.InputSystem;
|
||||||
|
using UnityEngine.UIElements;
|
||||||
|
using TD.Core;
|
||||||
|
using TD.Gameplay;
|
||||||
|
|
||||||
|
namespace TD.UI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Lobby-scene overlay that lets the local player pick their race.
|
||||||
|
/// Shows a 4x4 grid of race icons + a detail panel that pops up to the
|
||||||
|
/// right when an icon is clicked. Reads other players' picks from
|
||||||
|
/// <see cref="PlayerMatchState.AllPlayers"/> each frame to grey out
|
||||||
|
/// races that have already been taken.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para><b>Wiring.</b> Attach this component to the same GameObject as
|
||||||
|
/// <c>LobbyController</c>. The controller calls <see cref="Initialize"/>
|
||||||
|
/// once with its root <see cref="VisualElement"/>, and <see cref="Show"/>
|
||||||
|
/// when the "Select Race" button is clicked.</para>
|
||||||
|
///
|
||||||
|
/// <para><b>Why same UIDocument.</b> The overlay's elements are inserted as
|
||||||
|
/// absolute-positioned children of the lobby root — that way one UIDocument
|
||||||
|
/// + one PanelSettings serves both the lobby and the overlay, and z-order is
|
||||||
|
/// natural (overlay last → on top).</para>
|
||||||
|
///
|
||||||
|
/// <para><b>Visual states per grid cell.</b>
|
||||||
|
/// <list type="bullet">
|
||||||
|
/// <item><b>Free</b> — race not picked by anyone. Icon in color, clickable.</item>
|
||||||
|
/// <item><b>Taken by another player</b> — greyed out, clickable for viewing
|
||||||
|
/// the detail panel but confirm button is disabled. Player slot
|
||||||
|
/// number overlaid in color so others know who claimed it.</item>
|
||||||
|
/// <item><b>Taken by local player</b> — bordered highlight, clickable.
|
||||||
|
/// Confirm button enabled (no-op if already selected, but lets the
|
||||||
|
/// player re-confirm). Local slot number overlaid.</item>
|
||||||
|
/// <item><b>Unregistered slot</b> — placeholder "Coming Soon", not
|
||||||
|
/// clickable. No RaceDefinition asset exists for this RaceId yet.</item>
|
||||||
|
/// </list></para>
|
||||||
|
/// </remarks>
|
||||||
|
public class RaceSelectionOverlay : MonoBehaviour
|
||||||
|
{
|
||||||
|
// ----- UI state ---------------------------------------------------
|
||||||
|
|
||||||
|
private VisualElement overlayRoot;
|
||||||
|
private VisualElement gridContainer;
|
||||||
|
private VisualElement detailPanel;
|
||||||
|
private Label detailHeader;
|
||||||
|
private VisualElement detailIcon;
|
||||||
|
private Label detailBuilderName;
|
||||||
|
private Label detailBuilderDesc;
|
||||||
|
private Label detailLore;
|
||||||
|
private Button detailConfirmButton;
|
||||||
|
private Label detailUnavailableNote;
|
||||||
|
|
||||||
|
// Currently-viewed race in the detail panel. RaceId.None means no
|
||||||
|
// detail is open and the panel shows a hint instead.
|
||||||
|
private RaceId viewedRace = RaceId.None;
|
||||||
|
|
||||||
|
// Re-built each Update from PlayerMatchState data. Maps each taken
|
||||||
|
// RaceId to the slot of the player that picked it.
|
||||||
|
private readonly Dictionary<RaceId, PlayerSlot> picksByRace = new Dictionary<RaceId, PlayerSlot>();
|
||||||
|
|
||||||
|
// Snapshot of pick-state from the last grid rebuild. RefreshGrid skips
|
||||||
|
// rebuilding when this matches the current frame — same click-eating
|
||||||
|
// problem as the lobby's player list. Cleared on Show() so the grid
|
||||||
|
// always rebuilds when the overlay reopens.
|
||||||
|
private string lastGridSignature = string.Empty;
|
||||||
|
private readonly StringBuilder signatureBuffer = new StringBuilder();
|
||||||
|
|
||||||
|
// ----- Public API -------------------------------------------------
|
||||||
|
|
||||||
|
public bool IsVisible =>
|
||||||
|
overlayRoot != null && overlayRoot.style.display.value == DisplayStyle.Flex;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called by LobbyController once to attach the overlay's UI to the
|
||||||
|
/// lobby's UIDocument root. Builds the elements (hidden) and is then
|
||||||
|
/// reused across Show / Hide cycles.
|
||||||
|
/// </summary>
|
||||||
|
public void Initialize(VisualElement lobbyRoot)
|
||||||
|
{
|
||||||
|
if (lobbyRoot == null)
|
||||||
|
{
|
||||||
|
Debug.LogError("[RaceSelectionOverlay] Initialize received null lobby root.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BuildUI(lobbyRoot);
|
||||||
|
Hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reveals the overlay, refreshes the grid against current picks, and
|
||||||
|
/// auto-opens the detail panel for the local player's currently-picked
|
||||||
|
/// race (if any) so they can change it directly.
|
||||||
|
/// </summary>
|
||||||
|
public void Show()
|
||||||
|
{
|
||||||
|
if (overlayRoot == null) return;
|
||||||
|
overlayRoot.style.display = DisplayStyle.Flex;
|
||||||
|
|
||||||
|
// If the local player already has a race, seed the detail panel with
|
||||||
|
// it. Otherwise leave the panel showing the placeholder hint.
|
||||||
|
var local = PlayerMatchState.Local;
|
||||||
|
viewedRace = (local != null) ? local.RaceSelection : RaceId.None;
|
||||||
|
|
||||||
|
// Force a fresh grid build on each open so visuals reflect any
|
||||||
|
// picks that happened while the overlay was closed.
|
||||||
|
lastGridSignature = string.Empty;
|
||||||
|
RefreshGrid();
|
||||||
|
RefreshDetail();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Hide()
|
||||||
|
{
|
||||||
|
if (overlayRoot == null) return;
|
||||||
|
overlayRoot.style.display = DisplayStyle.None;
|
||||||
|
viewedRace = RaceId.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- Lifecycle --------------------------------------------------
|
||||||
|
|
||||||
|
private void Update()
|
||||||
|
{
|
||||||
|
if (!IsVisible) return;
|
||||||
|
|
||||||
|
// Esc closes the overlay. Read directly via Input System — we want
|
||||||
|
// this even when nothing is focused.
|
||||||
|
var kb = Keyboard.current;
|
||||||
|
if (kb != null && kb.escapeKey.wasPressedThisFrame)
|
||||||
|
{
|
||||||
|
Hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh against current picks every frame — cheap (max 16 cells,
|
||||||
|
// max 9 players) and means other-player changes show up immediately.
|
||||||
|
RefreshGrid();
|
||||||
|
RefreshDetail();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- UI construction --------------------------------------------
|
||||||
|
|
||||||
|
private void BuildUI(VisualElement lobbyRoot)
|
||||||
|
{
|
||||||
|
// Root overlay — fills the screen with a dark backdrop.
|
||||||
|
overlayRoot = new VisualElement();
|
||||||
|
overlayRoot.pickingMode = PickingMode.Position;
|
||||||
|
overlayRoot.style.position = Position.Absolute;
|
||||||
|
overlayRoot.style.left = 0;
|
||||||
|
overlayRoot.style.right = 0;
|
||||||
|
overlayRoot.style.top = 0;
|
||||||
|
overlayRoot.style.bottom = 0;
|
||||||
|
overlayRoot.style.backgroundColor = new Color(0f, 0f, 0f, 0.85f);
|
||||||
|
overlayRoot.style.alignItems = Align.Center;
|
||||||
|
overlayRoot.style.justifyContent = Justify.Center;
|
||||||
|
lobbyRoot.Add(overlayRoot);
|
||||||
|
|
||||||
|
// Title + close button in a top bar.
|
||||||
|
var topBar = new VisualElement();
|
||||||
|
topBar.style.position = Position.Absolute;
|
||||||
|
topBar.style.top = 20;
|
||||||
|
topBar.style.left = 40;
|
||||||
|
topBar.style.right = 40;
|
||||||
|
topBar.style.flexDirection = FlexDirection.Row;
|
||||||
|
topBar.style.justifyContent = Justify.SpaceBetween;
|
||||||
|
topBar.style.alignItems = Align.Center;
|
||||||
|
overlayRoot.Add(topBar);
|
||||||
|
|
||||||
|
var title = new Label("Select Race");
|
||||||
|
title.style.fontSize = 32;
|
||||||
|
title.style.color = Color.white;
|
||||||
|
title.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||||
|
topBar.Add(title);
|
||||||
|
|
||||||
|
var closeBtn = new Button(Hide) { text = "X" };
|
||||||
|
closeBtn.style.width = 44;
|
||||||
|
closeBtn.style.height = 44;
|
||||||
|
closeBtn.style.fontSize = 20;
|
||||||
|
topBar.Add(closeBtn);
|
||||||
|
|
||||||
|
// Main content row: grid on the left, detail panel on the right.
|
||||||
|
var content = new VisualElement();
|
||||||
|
content.style.flexDirection = FlexDirection.Row;
|
||||||
|
content.style.alignItems = Align.Stretch;
|
||||||
|
content.style.marginTop = 40;
|
||||||
|
overlayRoot.Add(content);
|
||||||
|
|
||||||
|
// Grid container — 4x4 of cells. Uses wrap to flow rows.
|
||||||
|
gridContainer = new VisualElement();
|
||||||
|
gridContainer.style.flexDirection = FlexDirection.Row;
|
||||||
|
gridContainer.style.flexWrap = Wrap.Wrap;
|
||||||
|
gridContainer.style.width = 560; // 4 cells * (120 + 8 margin) = 512 + slack
|
||||||
|
gridContainer.style.marginRight = 32;
|
||||||
|
content.Add(gridContainer);
|
||||||
|
|
||||||
|
// Detail panel — built once, populated in RefreshDetail.
|
||||||
|
detailPanel = new VisualElement();
|
||||||
|
detailPanel.style.width = 380;
|
||||||
|
detailPanel.style.minHeight = 520;
|
||||||
|
detailPanel.style.paddingTop = 20;
|
||||||
|
detailPanel.style.paddingBottom = 20;
|
||||||
|
detailPanel.style.paddingLeft = 20;
|
||||||
|
detailPanel.style.paddingRight = 20;
|
||||||
|
detailPanel.style.backgroundColor = new Color(0.10f, 0.10f, 0.14f, 0.95f);
|
||||||
|
detailPanel.style.borderTopWidth = detailPanel.style.borderBottomWidth =
|
||||||
|
detailPanel.style.borderLeftWidth = detailPanel.style.borderRightWidth = 2;
|
||||||
|
var detailBorder = new Color(0.4f, 0.4f, 0.5f);
|
||||||
|
detailPanel.style.borderTopColor = detailPanel.style.borderBottomColor =
|
||||||
|
detailPanel.style.borderLeftColor = detailPanel.style.borderRightColor = detailBorder;
|
||||||
|
detailPanel.style.flexDirection = FlexDirection.Column;
|
||||||
|
content.Add(detailPanel);
|
||||||
|
|
||||||
|
detailHeader = new Label("Pick a race");
|
||||||
|
detailHeader.style.fontSize = 22;
|
||||||
|
detailHeader.style.color = Color.white;
|
||||||
|
detailHeader.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||||
|
detailHeader.style.marginBottom = 12;
|
||||||
|
detailPanel.Add(detailHeader);
|
||||||
|
|
||||||
|
detailIcon = new VisualElement();
|
||||||
|
detailIcon.style.width = 200;
|
||||||
|
detailIcon.style.height = 200;
|
||||||
|
detailIcon.style.alignSelf = Align.Center;
|
||||||
|
detailIcon.style.backgroundColor = new Color(0.18f, 0.18f, 0.22f);
|
||||||
|
detailIcon.style.marginBottom = 12;
|
||||||
|
detailPanel.Add(detailIcon);
|
||||||
|
|
||||||
|
detailBuilderName = new Label();
|
||||||
|
detailBuilderName.style.fontSize = 16;
|
||||||
|
detailBuilderName.style.color = new Color(0.95f, 0.85f, 0.5f);
|
||||||
|
detailBuilderName.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||||
|
detailPanel.Add(detailBuilderName);
|
||||||
|
|
||||||
|
detailBuilderDesc = new Label();
|
||||||
|
detailBuilderDesc.style.fontSize = 13;
|
||||||
|
detailBuilderDesc.style.color = new Color(0.85f, 0.85f, 0.85f);
|
||||||
|
detailBuilderDesc.style.marginBottom = 10;
|
||||||
|
detailBuilderDesc.style.whiteSpace = WhiteSpace.Normal;
|
||||||
|
detailPanel.Add(detailBuilderDesc);
|
||||||
|
|
||||||
|
detailLore = new Label();
|
||||||
|
detailLore.style.fontSize = 12;
|
||||||
|
detailLore.style.color = new Color(0.75f, 0.75f, 0.75f);
|
||||||
|
detailLore.style.marginBottom = 16;
|
||||||
|
detailLore.style.whiteSpace = WhiteSpace.Normal;
|
||||||
|
detailLore.style.flexGrow = 1;
|
||||||
|
detailPanel.Add(detailLore);
|
||||||
|
|
||||||
|
// Notice shown when the viewed race is taken by another player.
|
||||||
|
detailUnavailableNote = new Label();
|
||||||
|
detailUnavailableNote.style.color = new Color(1f, 0.5f, 0.3f);
|
||||||
|
detailUnavailableNote.style.fontSize = 12;
|
||||||
|
detailUnavailableNote.style.marginBottom = 8;
|
||||||
|
detailUnavailableNote.style.whiteSpace = WhiteSpace.Normal;
|
||||||
|
detailPanel.Add(detailUnavailableNote);
|
||||||
|
|
||||||
|
detailConfirmButton = new Button(OnConfirmClicked) { text = "Confirm Selection" };
|
||||||
|
detailConfirmButton.style.height = 40;
|
||||||
|
detailConfirmButton.style.fontSize = 16;
|
||||||
|
detailPanel.Add(detailConfirmButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- Per-frame refresh ------------------------------------------
|
||||||
|
|
||||||
|
// Walks every PlayerMatchState and records which RaceId each non-None
|
||||||
|
// pick belongs to. Used by both the grid (grey out taken) and the
|
||||||
|
// detail panel (gate the confirm button).
|
||||||
|
private void RebuildPickIndex()
|
||||||
|
{
|
||||||
|
picksByRace.Clear();
|
||||||
|
foreach (var pms in PlayerMatchState.AllPlayers)
|
||||||
|
{
|
||||||
|
if (pms.RaceSelection == RaceId.None) continue;
|
||||||
|
picksByRace[pms.RaceSelection] = pms.Slot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshGrid()
|
||||||
|
{
|
||||||
|
if (gridContainer == null) return;
|
||||||
|
if (RaceRegistry.Instance == null) return;
|
||||||
|
|
||||||
|
RebuildPickIndex();
|
||||||
|
|
||||||
|
// Skip rebuild when nothing changed — keeps the cell event handlers
|
||||||
|
// alive across frames so clicks aren't eaten mid-press.
|
||||||
|
PlayerSlot localSlot = PlayerMatchState.Local != null
|
||||||
|
? PlayerMatchState.Local.Slot
|
||||||
|
: PlayerSlot.None;
|
||||||
|
string signature = ComputeGridSignature(localSlot);
|
||||||
|
if (signature == lastGridSignature) return;
|
||||||
|
lastGridSignature = signature;
|
||||||
|
|
||||||
|
gridContainer.Clear();
|
||||||
|
foreach (var (id, def) in RaceRegistry.Instance.AllSlots())
|
||||||
|
{
|
||||||
|
gridContainer.Add(BuildCell(id, def, localSlot));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compact signature of every input the grid cells depend on: the
|
||||||
|
// current pick map (RaceId → PlayerSlot) plus the local player's slot
|
||||||
|
// (which affects "is this mine" highlighting on each cell).
|
||||||
|
private string ComputeGridSignature(PlayerSlot localSlot)
|
||||||
|
{
|
||||||
|
signatureBuffer.Clear();
|
||||||
|
signatureBuffer.Append((int)localSlot);
|
||||||
|
signatureBuffer.Append('|');
|
||||||
|
foreach (var kvp in picksByRace.OrderBy(p => (int)p.Key))
|
||||||
|
{
|
||||||
|
signatureBuffer.Append((int)kvp.Key);
|
||||||
|
signatureBuffer.Append(':');
|
||||||
|
signatureBuffer.Append((int)kvp.Value);
|
||||||
|
signatureBuffer.Append(';');
|
||||||
|
}
|
||||||
|
return signatureBuffer.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private VisualElement BuildCell(RaceId id, RaceDefinition def, PlayerSlot localSlot)
|
||||||
|
{
|
||||||
|
// Outer cell with fixed size for consistent grid layout.
|
||||||
|
var cell = new VisualElement();
|
||||||
|
cell.style.width = 120;
|
||||||
|
cell.style.height = 120;
|
||||||
|
cell.style.marginTop = cell.style.marginBottom =
|
||||||
|
cell.style.marginLeft = cell.style.marginRight = 4;
|
||||||
|
cell.style.borderTopWidth = cell.style.borderBottomWidth =
|
||||||
|
cell.style.borderLeftWidth = cell.style.borderRightWidth = 2;
|
||||||
|
|
||||||
|
bool isLocked = (def == null);
|
||||||
|
bool isPicked = picksByRace.TryGetValue(id, out var picker);
|
||||||
|
bool isMine = isPicked && picker == localSlot;
|
||||||
|
bool isTakenByOther = isPicked && !isMine;
|
||||||
|
|
||||||
|
// Border color signals state at a glance.
|
||||||
|
Color borderColor = isMine
|
||||||
|
? new Color(0.3f, 0.85f, 0.3f) // green for "mine"
|
||||||
|
: isTakenByOther
|
||||||
|
? new Color(0.6f, 0.2f, 0.2f) // red-ish for taken
|
||||||
|
: isLocked
|
||||||
|
? new Color(0.3f, 0.3f, 0.3f) // dim for placeholder
|
||||||
|
: new Color(0.5f, 0.5f, 0.6f); // neutral for free
|
||||||
|
cell.style.borderTopColor = cell.style.borderBottomColor =
|
||||||
|
cell.style.borderLeftColor = cell.style.borderRightColor = borderColor;
|
||||||
|
cell.style.backgroundColor = new Color(0.10f, 0.10f, 0.14f);
|
||||||
|
|
||||||
|
// Icon area (or placeholder text for locked slots).
|
||||||
|
var iconHolder = new VisualElement();
|
||||||
|
iconHolder.pickingMode = PickingMode.Ignore;
|
||||||
|
iconHolder.style.flexGrow = 1;
|
||||||
|
iconHolder.style.alignItems = Align.Center;
|
||||||
|
iconHolder.style.justifyContent = Justify.Center;
|
||||||
|
iconHolder.style.unityBackgroundImageTintColor = isTakenByOther
|
||||||
|
? new Color(0.4f, 0.4f, 0.4f) // greyed out
|
||||||
|
: Color.white;
|
||||||
|
if (def != null && def.Icon != null)
|
||||||
|
iconHolder.style.backgroundImage = new StyleBackground(def.Icon);
|
||||||
|
else if (isLocked)
|
||||||
|
{
|
||||||
|
var placeholder = new Label("?");
|
||||||
|
placeholder.style.fontSize = 36;
|
||||||
|
placeholder.style.color = new Color(0.4f, 0.4f, 0.4f);
|
||||||
|
iconHolder.Add(placeholder);
|
||||||
|
}
|
||||||
|
cell.Add(iconHolder);
|
||||||
|
|
||||||
|
// Race name strip at the bottom — visible even when icon is missing.
|
||||||
|
var nameLabel = new Label(def != null ? def.DisplayName : "Coming Soon");
|
||||||
|
nameLabel.pickingMode = PickingMode.Ignore;
|
||||||
|
nameLabel.style.unityTextAlign = TextAnchor.MiddleCenter;
|
||||||
|
nameLabel.style.fontSize = 11;
|
||||||
|
nameLabel.style.color = isLocked ? new Color(0.45f, 0.45f, 0.45f) : Color.white;
|
||||||
|
nameLabel.style.paddingTop = 2;
|
||||||
|
nameLabel.style.paddingBottom = 2;
|
||||||
|
nameLabel.style.backgroundColor = new Color(0f, 0f, 0f, 0.55f);
|
||||||
|
cell.Add(nameLabel);
|
||||||
|
|
||||||
|
// Picker badge — top-right corner, only when taken. Shows the slot
|
||||||
|
// number of whoever picked it.
|
||||||
|
if (isPicked)
|
||||||
|
{
|
||||||
|
var badge = new Label($"P{(int)picker}");
|
||||||
|
badge.pickingMode = PickingMode.Ignore;
|
||||||
|
badge.style.position = Position.Absolute;
|
||||||
|
badge.style.top = 4;
|
||||||
|
badge.style.right = 4;
|
||||||
|
badge.style.fontSize = 16;
|
||||||
|
badge.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||||
|
badge.style.color = isMine
|
||||||
|
? new Color(0.3f, 0.85f, 0.3f)
|
||||||
|
: new Color(1f, 0.7f, 0.2f);
|
||||||
|
badge.style.paddingLeft = 4;
|
||||||
|
badge.style.paddingRight = 4;
|
||||||
|
badge.style.backgroundColor = new Color(0f, 0f, 0f, 0.7f);
|
||||||
|
cell.Add(badge);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Click handler — only enabled for non-locked cells. Locked cells
|
||||||
|
// still get the visual treatment but no click response.
|
||||||
|
if (!isLocked)
|
||||||
|
{
|
||||||
|
cell.RegisterCallback<ClickEvent>(_ => OnCellClicked(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- Detail panel -----------------------------------------------
|
||||||
|
|
||||||
|
private void OnCellClicked(RaceId id)
|
||||||
|
{
|
||||||
|
viewedRace = id;
|
||||||
|
RefreshDetail();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshDetail()
|
||||||
|
{
|
||||||
|
if (detailPanel == null) return;
|
||||||
|
var registry = RaceRegistry.Instance;
|
||||||
|
if (registry == null) return;
|
||||||
|
|
||||||
|
var def = registry.Get(viewedRace);
|
||||||
|
|
||||||
|
if (def == null)
|
||||||
|
{
|
||||||
|
// Empty / locked / no selection — show placeholder hint.
|
||||||
|
detailHeader.text = "Pick a race";
|
||||||
|
detailBuilderName.text = string.Empty;
|
||||||
|
detailBuilderDesc.text = string.Empty;
|
||||||
|
detailLore.text = "Click a race icon to see details.";
|
||||||
|
detailIcon.style.backgroundImage = null;
|
||||||
|
detailUnavailableNote.text = string.Empty;
|
||||||
|
detailConfirmButton.SetEnabled(false);
|
||||||
|
detailConfirmButton.text = "Confirm Selection";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
detailHeader.text = def.DisplayName;
|
||||||
|
detailBuilderName.text = string.IsNullOrEmpty(def.BuilderName)
|
||||||
|
? "Builder: (unnamed)"
|
||||||
|
: $"Builder: {def.BuilderName}";
|
||||||
|
detailBuilderDesc.text = def.BuilderDescription ?? string.Empty;
|
||||||
|
detailLore.text = def.LoreText ?? string.Empty;
|
||||||
|
detailIcon.style.backgroundImage = def.Icon != null
|
||||||
|
? new StyleBackground(def.Icon)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
// Is this race available to the local player?
|
||||||
|
bool isPicked = picksByRace.TryGetValue(viewedRace, out var picker);
|
||||||
|
PlayerSlot localSlot = PlayerMatchState.Local != null
|
||||||
|
? PlayerMatchState.Local.Slot
|
||||||
|
: PlayerSlot.None;
|
||||||
|
bool takenByOther = isPicked && picker != localSlot;
|
||||||
|
bool takenByMe = isPicked && picker == localSlot;
|
||||||
|
|
||||||
|
if (takenByOther)
|
||||||
|
{
|
||||||
|
detailUnavailableNote.text = $"Already selected by P{(int)picker}.";
|
||||||
|
detailConfirmButton.SetEnabled(false);
|
||||||
|
detailConfirmButton.text = "Unavailable";
|
||||||
|
}
|
||||||
|
else if (takenByMe)
|
||||||
|
{
|
||||||
|
detailUnavailableNote.text = "Your current selection.";
|
||||||
|
detailConfirmButton.SetEnabled(true);
|
||||||
|
detailConfirmButton.text = "Confirm Selection";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
detailUnavailableNote.text = string.Empty;
|
||||||
|
detailConfirmButton.SetEnabled(true);
|
||||||
|
detailConfirmButton.text = "Confirm Selection";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnConfirmClicked()
|
||||||
|
{
|
||||||
|
var local = PlayerMatchState.Local;
|
||||||
|
if (local == null)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("[RaceSelectionOverlay] No local PlayerMatchState — cannot submit race.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (viewedRace == RaceId.None) return;
|
||||||
|
|
||||||
|
// Re-check exclusivity right before submitting — between detail open
|
||||||
|
// and confirm click, another player may have grabbed it.
|
||||||
|
if (picksByRace.TryGetValue(viewedRace, out var picker) && picker != local.Slot)
|
||||||
|
{
|
||||||
|
Debug.Log($"[RaceSelectionOverlay] Race already taken by P{(int)picker}. " +
|
||||||
|
"Refreshing detail.");
|
||||||
|
RefreshDetail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
local.SubmitRaceRpc(viewedRace);
|
||||||
|
|
||||||
|
// Per the spec: confirming clears the detail panel but keeps the
|
||||||
|
// overlay open. The grid will update to show the new picked state
|
||||||
|
// on the next Update tick.
|
||||||
|
viewedRace = RaceId.None;
|
||||||
|
RefreshDetail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Assets/_Project/Scripts/UI/RaceSelectionOverlay.cs.meta
Normal file
2
Assets/_Project/Scripts/UI/RaceSelectionOverlay.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9ab3ad11b37d4c54d9f310f5356d31ac
|
||||||
|
|
@ -5,6 +5,12 @@ EditorBuildSettings:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
m_Scenes:
|
m_Scenes:
|
||||||
|
- enabled: 1
|
||||||
|
path: Assets/_Project/Scenes/UI/MainMenu.unity
|
||||||
|
guid: 1f4cb4a6391f5e94285960890282b70e
|
||||||
|
- enabled: 1
|
||||||
|
path: Assets/_Project/Scenes/UI/Lobby.unity
|
||||||
|
guid: 3a3639dca674a8049a570cb848bb69d2
|
||||||
- enabled: 1
|
- enabled: 1
|
||||||
path: Assets/_Project/Scenes/Levels/Main.unity
|
path: Assets/_Project/Scenes/Levels/Main.unity
|
||||||
guid: 99c9720ab356a0642a771bea13969a05
|
guid: 99c9720ab356a0642a771bea13969a05
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
--- !u!114 &1
|
--- !u!114 &1
|
||||||
MonoBehaviour:
|
MonoBehaviour:
|
||||||
m_ObjectHideFlags: 53
|
m_ObjectHideFlags: 61
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
m_PrefabInstance: {fileID: 0}
|
m_PrefabInstance: {fileID: 0}
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
|
|
||||||
|
|
@ -75,20 +75,24 @@ The most architecturally significant pending system. This blocks the Phase 2 tow
|
||||||
- 4-connected, no diagonals (matches existing maze validation)
|
- 4-connected, no diagonals (matches existing maze validation)
|
||||||
- Re-pathing on tower placement/removal events. Fire on: `TowerInstance` spawn/despawn, construction-start, construction-finish, shelved-tower despawn.
|
- Re-pathing on tower placement/removal events. Fire on: `TowerInstance` spawn/despawn, construction-start, construction-finish, shelved-tower despawn.
|
||||||
|
|
||||||
### 1.7 Lobby & Connection (CURRENT)
|
### 1.7 Lobby & Connection (COMPLETE — 2026-05-17)
|
||||||
|
|
||||||
Replaces the current bare "Start Host" button with a proper main menu → lobby → match flow.
|
Replaced the bare "Start Host" button with a proper main menu → lobby → match flow.
|
||||||
Lobby is its own scene; players gather, pick races, ready up, and the host starts the match.
|
Lobby is its own scene; players gather, pick races, ready up, and the host starts the match.
|
||||||
|
|
||||||
**v1 scope (Direct IP, Option A host-leaves-closes-lobby):**
|
**v1 shipped (Direct IP, Option A host-leaves-closes-lobby):**
|
||||||
|
|
||||||
- `MainMenu` scene — Host / Join (with IP+port field) / Quit
|
- `MainMenu` scene — Host / Join (with IP+port field) / Quit / **Quick Start** (dev shortcut)
|
||||||
- `Lobby` scene — player list, per-player race picker, ready toggle, host-only Start button, Leave button
|
- `Lobby` scene — player list, per-player **Select Race** button opening the race-selection overlay, ready toggle, host-only Start button, Leave button
|
||||||
- `LobbyService` `NetworkBehaviour` scene singleton — Start Match RPC, Return to Lobby RPC
|
- `LobbyService` `NetworkBehaviour` scene singleton — Start Match RPC, Return to Lobby RPC
|
||||||
- `NetworkBootstrap` static — wraps `UnityTransport` host/join/disconnect. Designed for the Steam swap-out below: same call sites, different transport.
|
- `NetworkBootstrap` static — wraps `UnityTransport` host/join/disconnect. Designed for the Steam swap-out below: same call sites, different transport.
|
||||||
- `PlayerMatchState` extended with `IsReady` NetworkVariable and `SetReadyRpc` / `SetRaceRpc` for client → server submissions
|
- `SessionFlow` DontDestroyOnLoad singleton — routes disconnected peers back to MainMenu on host loss
|
||||||
|
- `PlayerMatchState` extended with `IsReady` NetworkVariable and `SubmitRaceRpc` / `SubmitReadyRpc` for client → server submissions
|
||||||
|
- `PlayerBuilderSpawner` refactored to spawn on `NetworkSceneManager.OnLoadEventCompleted` for the Match scene, not on initial player spawn. Pulls race-specific `BuilderPrefab` from `RaceRegistry` when available, falls back to the inspector default. Re-spawns cleanly across Match → Lobby → Match cycles.
|
||||||
- Match-end overlay extended: **Retry** (back to lobby) AND **Return to Main Menu** (this player only)
|
- Match-end overlay extended: **Retry** (back to lobby) AND **Return to Main Menu** (this player only)
|
||||||
- Host leaves → server raises a "lobby closed" RPC; all clients shutdown + return to main menu. Same applies if the host clicks "Return to Main Menu" after a match — session ends for everyone, each player returns independently to their own main menu.
|
- Host leaves → all clients return to main menu via `SessionFlow.OnClientDisconnectCallback` (Option A). Same applies if the host clicks "Return to Main Menu" after a match.
|
||||||
|
- **Race data + selection UI** delivered as part of 1.7 (originally scoped for 1.8): `RaceId` enum expanded to 16 slots, `RaceDefinition` ScriptableObject (Id, DisplayName, Icon, BuilderName, BuilderDescription, LoreText, BuilderPrefab, Towers stub), `RaceRegistry` (DontDestroyOnLoad singleton in MainMenu — single source of truth across all scenes), `RaceSelectionOverlay` (4×4 grid + detail panel, taken-race greying with picker badge, Esc/X close, server-side exclusivity enforced via `SubmitRaceRpc`).
|
||||||
|
- **Quick Start dev button** in MainMenu — bypasses lobby: hosts → waits for `PlayerMatchState.Local` → sets Race1 + ready → loads Match scene directly. Coroutine in `MainMenuController.QuickStartCoroutine`.
|
||||||
|
|
||||||
### 1.7-Future Steam Lobby Migration (Option C — DEFERRED)
|
### 1.7-Future Steam Lobby Migration (Option C — DEFERRED)
|
||||||
|
|
||||||
|
|
@ -119,16 +123,29 @@ Decision deferred per existing context document; Builder code is already terrain
|
||||||
|
|
||||||
Options previously discussed: Unity Terrain, mesh-based (Blender), ProBuilder, per-tile heights via volumes.
|
Options previously discussed: Unity Terrain, mesh-based (Blender), ProBuilder, per-tile heights via volumes.
|
||||||
|
|
||||||
### 1.8 Race system (Path E)
|
### 1.8 Race system (Path E) — PARTIALLY COMPLETE
|
||||||
|
|
||||||
The largest content-shaped piece of Phase 1. Required before Phase 2 because the prototype tower (Space Marine) is conceptually a unit of the Adeptus Astartes race, and the data model needs to reflect that.
|
Data model and lobby selection UI shipped as part of 1.7 (2026-05-17). Remaining work is gameplay-side integration of the race payload during a match.
|
||||||
|
|
||||||
- `RaceDefinition` `ScriptableObject` — race content bundle (tower roster, race-specific units, builder variants, starting bonuses)
|
**Already done (delivered with 1.7):**
|
||||||
- Race-pick UI (in-match overlay) — grid of race cards, timer-based auto-lock. First concrete `MatchState` consumer.
|
|
||||||
- Multi-builder race support — revisit `PlayerBuilderSpawner` to spawn N builders
|
- `RaceDefinition` ScriptableObject with Identity / Builder / Lore / Gameplay-payload sections
|
||||||
- `TowerRegistry` filtering by active match's race rosters
|
- `RaceRegistry` DontDestroyOnLoad singleton (placed in MainMenu, persists into Lobby + Match)
|
||||||
- Auto-discovery of `RaceDefinition` assets (mirror the `Resources.LoadAll` pattern from `TowerRegistry`)
|
- `RaceId` enum (None + Race1..Race16) — 16-slot grid reserved
|
||||||
|
- Lobby race-selection overlay (4×4 grid + detail panel + exclusivity enforcement)
|
||||||
|
- `PlayerMatchState.RaceSelection` NetworkVariable + `SubmitRaceRpc`
|
||||||
|
- `PlayerBuilderSpawner` reads race-specific `BuilderPrefab` when available
|
||||||
|
- Two placeholder RaceDefinition assets configured with the default builder (proves the data path works without race-specific content)
|
||||||
|
|
||||||
|
**Still pending:**
|
||||||
|
|
||||||
|
- Replace lobby race-pick with in-match race-pick overlay (timer-based auto-lock, `MatchState.RacePickTimer`) — OR retain lobby pick and remove the in-match flow concept. **Open decision** (see 1.10 reconciliation question).
|
||||||
|
- Multi-builder race support — revisit `PlayerBuilderSpawner` to spawn N builders for races that need them
|
||||||
|
- `TowerRegistry` filtering by active match's race rosters (currently shows all registered towers regardless of race)
|
||||||
|
- Auto-discovery of `RaceDefinition` assets (today's flow: drag each asset into `RaceRegistry.Definitions` manually)
|
||||||
- Replace `TowerPlacementManager.towerDefinitions[]` inspector array with race-driven discovery
|
- Replace `TowerPlacementManager.towerDefinitions[]` inspector array with race-driven discovery
|
||||||
|
- Race-specific builder prefabs (currently every race uses the same default builder)
|
||||||
|
- Real race content (display names, lore, icons, distinct builder visuals) — placeholder races exist but are interchangeable
|
||||||
|
|
||||||
### 1.9 Camera polish
|
### 1.9 Camera polish
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue