Added Dedicated Server Functionality

dev-hazim
Hazim Bin Ijaz 2 days ago
parent 1dd1430423
commit e77b7d9489

@ -20,6 +20,6 @@ MonoBehaviour:
abilityCooldownTime: 3 abilityCooldownTime: 3
prefab: {fileID: 9694722736535169, guid: 9b94ed8895919e84aa669628b0761eaf, type: 3} prefab: {fileID: 9694722736535169, guid: 9b94ed8895919e84aa669628b0761eaf, type: 3}
wallLength: 8 wallLength: 8
wallWidth: 0.5 wallWidth: 0.01
wallHeight: 2 wallHeight: 2
scaleUpDuration: 1 scaleUpDuration: 1

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

@ -0,0 +1,15 @@
%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: 5cccef3cfcbccdb4aa4b407a003237b7, type: 3}
m_Name: NetworkGameState
m_EditorClassIdentifier:
Value: {fileID: 0}

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

@ -11,7 +11,6 @@ GameObject:
- component: {fileID: 1756252046645169901} - component: {fileID: 1756252046645169901}
- component: {fileID: 7200474853122004856} - component: {fileID: 7200474853122004856}
- component: {fileID: 5290524345172392442} - component: {fileID: 5290524345172392442}
- component: {fileID: 550742182908126467}
- component: {fileID: 8921202503349013827} - component: {fileID: 8921202503349013827}
- component: {fileID: 5807442085122568602} - component: {fileID: 5807442085122568602}
- component: {fileID: -7009867759405921325} - component: {fileID: -7009867759405921325}
@ -33,7 +32,7 @@ Transform:
serializedVersion: 2 serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 8, y: 1, z: 0.5} m_LocalScale: {x: 8, y: 1, z: 0.01}
m_ConstrainProportionsScale: 0 m_ConstrainProportionsScale: 0
m_Children: [] m_Children: []
m_Father: {fileID: 0} m_Father: {fileID: 0}
@ -88,27 +87,6 @@ MeshRenderer:
m_SortingLayer: 0 m_SortingLayer: 0
m_SortingOrder: 0 m_SortingOrder: 0
m_AdditionalVertexStreams: {fileID: 0} m_AdditionalVertexStreams: {fileID: 0}
--- !u!65 &550742182908126467
BoxCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 9694722736535169}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 0
m_ProvidesContacts: 0
m_Enabled: 0
serializedVersion: 3
m_Size: {x: 1, y: 1, z: 1}
m_Center: {x: 0, y: 0, z: 0}
--- !u!208 &8921202503349013827 --- !u!208 &8921202503349013827
NavMeshObstacle: NavMeshObstacle:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -119,7 +97,7 @@ NavMeshObstacle:
m_Enabled: 1 m_Enabled: 1
serializedVersion: 3 serializedVersion: 3
m_Shape: 1 m_Shape: 1
m_Extents: {x: 0.5, y: 0.5, z: 0.5} m_Extents: {x: 0.5, y: 0.5, z: 0.005}
m_MoveThreshold: 0.01 m_MoveThreshold: 0.01
m_Carve: 1 m_Carve: 1
m_CarveOnlyStationary: 0 m_CarveOnlyStationary: 0
@ -137,7 +115,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3} m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
GlobalObjectIdHash: 3892629208 GlobalObjectIdHash: 1554870052
InScenePlacedSourceGlobalObjectIdHash: 0 InScenePlacedSourceGlobalObjectIdHash: 0
AlwaysReplicateAsRoot: 0 AlwaysReplicateAsRoot: 0
SynchronizeTransform: 1 SynchronizeTransform: 1

@ -0,0 +1,99 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &3487892320786813612
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 4251412275105530415}
- component: {fileID: 8671395340743330634}
- component: {fileID: 3758027155353090712}
- component: {fileID: 4390463078158709668}
- component: {fileID: 6970145845986941762}
m_Layer: 0
m_Name: NetworkGameState
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &4251412275105530415
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3487892320786813612}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -0.2769791, y: 1.2954404, z: 0.23972915}
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 &8671395340743330634
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3487892320786813612}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
m_Name:
m_EditorClassIdentifier:
GlobalObjectIdHash: 1396645719
InScenePlacedSourceGlobalObjectIdHash: 0
AlwaysReplicateAsRoot: 0
SynchronizeTransform: 1
ActiveSceneSynchronization: 0
SceneMigrationSynchronization: 1
SpawnWithObservers: 1
DontDestroyWithOwner: 0
AutoObjectParentSync: 1
--- !u!114 &3758027155353090712
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3487892320786813612}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 9fb009f05b6b84d35af38930cac98d9a, type: 3}
m_Name:
m_EditorClassIdentifier:
m_GameStateTransformVariable: {fileID: 11400000, guid: f90b09725fdc466489abf3df1697fccc, type: 2}
m_NetworkWinState: {fileID: 4390463078158709668}
--- !u!114 &4390463078158709668
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3487892320786813612}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 69eb1bedacf698e4bada2f8d55dabdd8, type: 3}
m_Name:
m_EditorClassIdentifier:
winState:
m_InternalValue: 0
--- !u!114 &6970145845986941762
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3487892320786813612}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: b280145480d7594419baed09a111184b, type: 3}
m_Name:
m_EditorClassIdentifier:
m_TransformVariable: {fileID: 11400000, guid: f90b09725fdc466489abf3df1697fccc, type: 2}

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 2200a7c8099eb8b4a8a43beb96097cef
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,50 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &483784040165852385
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8317007143651163113}
- component: {fileID: 1988754947503560336}
m_Layer: 0
m_Name: DSLobbyManagementState
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &8317007143651163113
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 483784040165852385}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 27.0119, y: -29.155869, z: 13.674866}
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 &1988754947503560336
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 483784040165852385}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a35fe42cd86928c4d9dd52f2136ba795, type: 3}
m_Name:
m_EditorClassIdentifier:
parentReference:
TypeName: Unity.BossRoom.ApplicationLifecycle.ApplicationController
autoRun: 1
autoInjectGameObjects: []

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 85008d44a844548c083b38cda8083ef7
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,187 @@
%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: 9
m_Fog: 0
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
m_FogMode: 3
m_FogDensity: 0.01
m_LinearFogStart: 0
m_LinearFogEnd: 300
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
m_AmbientIntensity: 1
m_AmbientMode: 0
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
m_HaloStrength: 0.5
m_FlareStrength: 1
m_FlareFadeSpeed: 3
m_HaloTexture: {fileID: 0}
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
m_DefaultReflectionMode: 0
m_DefaultReflectionResolution: 128
m_ReflectionBounces: 1
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0}
m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
m_ObjectHideFlags: 0
serializedVersion: 12
m_GIWorkflowMode: 1
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_FinalGather: 0
m_FinalGatherFiltering: 1
m_FinalGatherRayCount: 256
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: 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!1001 &8885455575253120869
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 483784040165852385, guid: 85008d44a844548c083b38cda8083ef7, type: 3}
propertyPath: m_Name
value: DSLobbyManagementState
objectReference: {fileID: 0}
- target: {fileID: 8317007143651163113, guid: 85008d44a844548c083b38cda8083ef7, type: 3}
propertyPath: m_LocalPosition.x
value: 27.0119
objectReference: {fileID: 0}
- target: {fileID: 8317007143651163113, guid: 85008d44a844548c083b38cda8083ef7, type: 3}
propertyPath: m_LocalPosition.y
value: -29.155869
objectReference: {fileID: 0}
- target: {fileID: 8317007143651163113, guid: 85008d44a844548c083b38cda8083ef7, type: 3}
propertyPath: m_LocalPosition.z
value: 13.674866
objectReference: {fileID: 0}
- target: {fileID: 8317007143651163113, guid: 85008d44a844548c083b38cda8083ef7, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 8317007143651163113, guid: 85008d44a844548c083b38cda8083ef7, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8317007143651163113, guid: 85008d44a844548c083b38cda8083ef7, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8317007143651163113, guid: 85008d44a844548c083b38cda8083ef7, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8317007143651163113, guid: 85008d44a844548c083b38cda8083ef7, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8317007143651163113, guid: 85008d44a844548c083b38cda8083ef7, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8317007143651163113, guid: 85008d44a844548c083b38cda8083ef7, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 85008d44a844548c083b38cda8083ef7, type: 3}
--- !u!1660057539 &9223372036854775807
SceneRoots:
m_ObjectHideFlags: 0
m_Roots:
- {fileID: 8885455575253120869}

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

@ -38,7 +38,7 @@ RenderSettings:
m_ReflectionIntensity: 1 m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0} m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0} m_Sun: {fileID: 0}
m_IndirectSpecularColor: {r: 0.12731749, g: 0.13414757, b: 0.1210787, a: 1} m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
m_UseRadianceAmbientProbe: 0 m_UseRadianceAmbientProbe: 0
--- !u!157 &3 --- !u!157 &3
LightmapSettings: LightmapSettings:
@ -1348,6 +1348,10 @@ PrefabInstance:
serializedVersion: 3 serializedVersion: 3
m_TransformParent: {fileID: 0} m_TransformParent: {fileID: 0}
m_Modifications: m_Modifications:
- target: {fileID: 1984353324962460586, guid: c16e5c84955e2124b819f83a4e5078db, type: 3}
propertyPath: m_GameState
value:
objectReference: {fileID: 8671395340743330634, guid: 2200a7c8099eb8b4a8a43beb96097cef, type: 3}
- target: {fileID: 1984353324962460586, guid: c16e5c84955e2124b819f83a4e5078db, type: 3} - target: {fileID: 1984353324962460586, guid: c16e5c84955e2124b819f83a4e5078db, type: 3}
propertyPath: m_NetworkManager propertyPath: m_NetworkManager
value: value:
@ -1516,6 +1520,71 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 593a2fe42fa9d37498c96f9a383b6521, type: 3} m_Script: {fileID: 11500000, guid: 593a2fe42fa9d37498c96f9a383b6521, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
--- !u!1001 &6826832879089252232
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 3487892320786813612, guid: 2200a7c8099eb8b4a8a43beb96097cef, type: 3}
propertyPath: m_Name
value: NetworkGameState
objectReference: {fileID: 0}
- target: {fileID: 4251412275105530415, guid: 2200a7c8099eb8b4a8a43beb96097cef, type: 3}
propertyPath: m_LocalPosition.x
value: -0.2769791
objectReference: {fileID: 0}
- target: {fileID: 4251412275105530415, guid: 2200a7c8099eb8b4a8a43beb96097cef, type: 3}
propertyPath: m_LocalPosition.y
value: 1.2954404
objectReference: {fileID: 0}
- target: {fileID: 4251412275105530415, guid: 2200a7c8099eb8b4a8a43beb96097cef, type: 3}
propertyPath: m_LocalPosition.z
value: 0.23972915
objectReference: {fileID: 0}
- target: {fileID: 4251412275105530415, guid: 2200a7c8099eb8b4a8a43beb96097cef, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4251412275105530415, guid: 2200a7c8099eb8b4a8a43beb96097cef, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4251412275105530415, guid: 2200a7c8099eb8b4a8a43beb96097cef, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4251412275105530415, guid: 2200a7c8099eb8b4a8a43beb96097cef, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4251412275105530415, guid: 2200a7c8099eb8b4a8a43beb96097cef, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4251412275105530415, guid: 2200a7c8099eb8b4a8a43beb96097cef, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4251412275105530415, guid: 2200a7c8099eb8b4a8a43beb96097cef, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8671395340743330634, guid: 2200a7c8099eb8b4a8a43beb96097cef, type: 3}
propertyPath: GlobalObjectIdHash
value: 2423675111
objectReference: {fileID: 0}
- target: {fileID: 8671395340743330634, guid: 2200a7c8099eb8b4a8a43beb96097cef, type: 3}
propertyPath: InScenePlacedSourceGlobalObjectIdHash
value: 1399236880
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 2200a7c8099eb8b4a8a43beb96097cef, type: 3}
--- !u!1001 &7200250264107179103 --- !u!1001 &7200250264107179103
PrefabInstance: PrefabInstance:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -1721,3 +1790,4 @@ SceneRoots:
- {fileID: 2133349239} - {fileID: 2133349239}
- {fileID: 1965079830} - {fileID: 1965079830}
- {fileID: 1232034916} - {fileID: 1232034916}
- {fileID: 6826832879089252232}

@ -9,6 +9,7 @@ using Unity.BossRoom.UnityServices;
using Unity.BossRoom.UnityServices.Auth; using Unity.BossRoom.UnityServices.Auth;
using Unity.BossRoom.UnityServices.Lobbies; using Unity.BossRoom.UnityServices.Lobbies;
using Unity.BossRoom.Utils; using Unity.BossRoom.Utils;
using Unity.Multiplayer.Samples;
using Unity.Netcode; using Unity.Netcode;
using UnityEngine; using UnityEngine;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
@ -61,6 +62,8 @@ namespace Unity.BossRoom.ApplicationLifecycle
//they are networked so that the clients can subscribe to those messages that are published by the server //they are networked so that the clients can subscribe to those messages that are published by the server
builder.RegisterComponent(new NetworkedMessageChannel<LifeStateChangedEventMessage>()).AsImplementedInterfaces(); builder.RegisterComponent(new NetworkedMessageChannel<LifeStateChangedEventMessage>()).AsImplementedInterfaces();
builder.RegisterComponent(new NetworkedMessageChannel<ConnectionEventMessage>()).AsImplementedInterfaces(); builder.RegisterComponent(new NetworkedMessageChannel<ConnectionEventMessage>()).AsImplementedInterfaces();
Debug.Log("Registered NetworkedMessageChannel<ConnectionEventMessage>.");
#if UNITY_EDITOR || DEVELOPMENT_BUILD #if UNITY_EDITOR || DEVELOPMENT_BUILD
builder.RegisterComponent(new NetworkedMessageChannel<CheatUsedMessage>()).AsImplementedInterfaces(); builder.RegisterComponent(new NetworkedMessageChannel<CheatUsedMessage>()).AsImplementedInterfaces();
#endif #endif
@ -93,8 +96,16 @@ namespace Unity.BossRoom.ApplicationLifecycle
DontDestroyOnLoad(gameObject); DontDestroyOnLoad(gameObject);
DontDestroyOnLoad(m_UpdateRunner.gameObject); DontDestroyOnLoad(m_UpdateRunner.gameObject);
Application.targetFrameRate = 120; Application.targetFrameRate = 120;
if (DedicatedServerUtilities.IsServerBuildTarget)
{
// skip main menu and start IP server directly
SceneManager.LoadScene("DedicatedServerLobbyManagement");
}
else
{
SceneManager.LoadScene("MainMenu"); SceneManager.LoadScene("MainMenu");
} }
}
protected override void OnDestroy() protected override void OnDestroy()
{ {

@ -1,6 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Unity.BossRoom.Utils; using Unity.BossRoom.Utils;
using Unity.Collections;
using Unity.Multiplayer.Samples.BossRoom;
using Unity.Netcode; using Unity.Netcode;
using UnityEngine; using UnityEngine;
using UUnity.BossRoom.ConnectionManagement; using UUnity.BossRoom.ConnectionManagement;
@ -69,6 +71,10 @@ namespace Unity.BossRoom.ConnectionManagement
[Inject] [Inject]
IObjectResolver m_Resolver; IObjectResolver m_Resolver;
[SerializeField]
NetworkObject m_GameState;
public NetworkObject GameState => m_GameState;
public int MaxConnectedPlayers = 8; public int MaxConnectedPlayers = 8;
internal readonly OfflineState m_Offline = new OfflineState(); internal readonly OfflineState m_Offline = new OfflineState();
@ -77,6 +83,9 @@ namespace Unity.BossRoom.ConnectionManagement
internal readonly ClientReconnectingState m_ClientReconnecting = new ClientReconnectingState(); internal readonly ClientReconnectingState m_ClientReconnecting = new ClientReconnectingState();
internal readonly StartingHostState m_StartingHost = new StartingHostState(); internal readonly StartingHostState m_StartingHost = new StartingHostState();
internal readonly HostingState m_Hosting = new HostingState(); internal readonly HostingState m_Hosting = new HostingState();
internal readonly ServerStartingState m_ServerStarting = new ServerStartingState();
internal readonly ServerListeningState m_ServerListening = new ServerListeningState();
internal readonly DisconnectingWithReasonState m_DisconnectingWithReason = new DisconnectingWithReasonState();
void Awake() void Awake()
{ {
@ -85,7 +94,7 @@ namespace Unity.BossRoom.ConnectionManagement
void Start() void Start()
{ {
List<ConnectionState> states = new() { m_Offline, m_ClientConnecting, m_ClientConnected, m_ClientReconnecting, m_StartingHost, m_Hosting }; List<ConnectionState> states = new() { m_Offline, m_ClientConnecting, m_ClientConnected, m_ClientReconnecting, m_StartingHost, m_Hosting, m_ServerStarting, m_ServerListening, m_DisconnectingWithReason };
foreach (var connectionState in states) foreach (var connectionState in states)
{ {
m_Resolver.Inject(connectionState); m_Resolver.Inject(connectionState);
@ -172,10 +181,45 @@ namespace Unity.BossRoom.ConnectionManagement
{ {
m_CurrentState.StartHostIP(playerName, ipaddress, port); m_CurrentState.StartHostIP(playerName, ipaddress, port);
} }
public void StartServerIP(string ipaddress, int port)
{
m_CurrentState.StartServerIP(ipaddress, port);
}
public void RequestShutdown() public void RequestShutdown()
{ {
m_CurrentState.OnUserRequestedShutdown(); m_CurrentState.OnUserRequestedShutdown();
} }
internal void ReceiveServertoClientSuccessPayload_CustomMessage(ulong clientID, FastBufferReader reader)
{
reader.ReadValueSafe(out ServerType isHost);
IsConnectedToHost = isHost;
}
public ServerType IsConnectedToHost { get; set; }
internal static void SendServertoClientSuccessPayload(ulong clientID, ServerType isHost)
{
var writer = new FastBufferWriter(sizeof(bool), Allocator.Temp);
writer.WriteValueSafe(isHost);
NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage(nameof(ReceiveServertoClientSuccessPayload_CustomMessage), clientID, writer);
}
public enum ServerType : byte
{
Undefined = 0,
DedicatedServer,
ClientHostedServer
}
public static void SendServerToClientSetDisconnectReason(ulong clientID, ConnectStatus status)
{
var writer = new FastBufferWriter(sizeof(ConnectStatus), Allocator.Temp);
writer.WriteValueSafe(status);
NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage(nameof(ReceiveServerToClientSetDisconnectReason_CustomMessage), clientID, writer);
}
void ReceiveServerToClientSetDisconnectReason_CustomMessage(ulong clientID, FastBufferReader reader)
{
reader.ReadValueSafe(out ConnectStatus status);
m_CurrentState.OnDisconnectReasonReceived(status);
}
} }
} }

@ -23,6 +23,12 @@ namespace Unity.BossRoom.ConnectionManagement
public override void Exit() { } public override void Exit() { }
public override void OnDisconnectReasonReceived(ConnectStatus disconnectReason)
{
m_ConnectStatusPublisher.Publish(disconnectReason);
m_ConnectionManager.ChangeState(m_ConnectionManager.m_DisconnectingWithReason);
}
public override void OnClientDisconnect(ulong _) public override void OnClientDisconnect(ulong _)
{ {
var disconnectReason = m_ConnectionManager.NetworkManager.DisconnectReason; var disconnectReason = m_ConnectionManager.NetworkManager.DisconnectReason;

@ -54,6 +54,11 @@ namespace Unity.BossRoom.ConnectionManagement
m_ConnectionManager.ChangeState(m_ConnectionManager.m_Offline); m_ConnectionManager.ChangeState(m_ConnectionManager.m_Offline);
} }
public override void OnDisconnectReasonReceived(ConnectStatus disconnectReason)
{
m_ConnectStatusPublisher.Publish(disconnectReason);
m_ConnectionManager.ChangeState(m_ConnectionManager.m_DisconnectingWithReason);
}
internal async Task ConnectClientAsync() internal async Task ConnectClientAsync()
{ {

@ -45,6 +45,19 @@ namespace Unity.BossRoom.ConnectionManagement
m_ConnectionManager.ChangeState(m_ConnectionManager.m_ClientConnected); m_ConnectionManager.ChangeState(m_ConnectionManager.m_ClientConnected);
} }
public override void OnDisconnectReasonReceived(ConnectStatus disconnectReason)
{
m_ConnectStatusPublisher.Publish(disconnectReason);
switch (disconnectReason)
{
case ConnectStatus.UserRequestedDisconnect:
case ConnectStatus.HostEndedSession:
case ConnectStatus.ServerFull:
m_ConnectionManager.ChangeState(m_ConnectionManager.m_DisconnectingWithReason);
break;
}
}
public override void OnClientDisconnect(ulong _) public override void OnClientDisconnect(ulong _)
{ {
var disconnectReason = m_ConnectionManager.NetworkManager.DisconnectReason; var disconnectReason = m_ConnectionManager.NetworkManager.DisconnectReason;

@ -28,6 +28,8 @@ namespace Unity.BossRoom.ConnectionManagement
public virtual void StartClientIP(string playerName, string ipaddress, int port) { } public virtual void StartClientIP(string playerName, string ipaddress, int port) { }
public virtual void StartServerIP(string ipaddress, int port) { }
public virtual void StartClientLobby(string playerName) { } public virtual void StartClientLobby(string playerName) { }
public virtual void StartHostIP(string playerName, string ipaddress, int port) { } public virtual void StartHostIP(string playerName, string ipaddress, int port) { }
@ -41,5 +43,7 @@ namespace Unity.BossRoom.ConnectionManagement
public virtual void OnTransportFailure() { } public virtual void OnTransportFailure() { }
public virtual void OnServerStopped() { } public virtual void OnServerStopped() { }
public virtual void OnDisconnectReasonReceived(ConnectStatus disconnectReason) { }
} }
} }

@ -0,0 +1,24 @@
namespace Unity.BossRoom.ConnectionManagement
{
/// <summary>
/// Connection state corresponding to a client who received a message from the server with a disconnect reason.
/// Since our disconnect process runs in multiple steps host side, this state is the first step client side. This
/// state simply waits for the actual disconnect, then transitions to the offline state.
/// </summary>
class DisconnectingWithReasonState : ConnectionState
{
public override void Enter() { }
public override void Exit() { }
public override void OnClientDisconnect(ulong _)
{
m_ConnectionManager.ChangeState(m_ConnectionManager.m_Offline);
}
public override void OnUserRequestedShutdown()
{
m_ConnectionManager.ChangeState(m_ConnectionManager.m_Offline);
}
}
}

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8cdbdfce07de4da48006d8e16b95da48
timeCreated: 1654886224

@ -3,6 +3,8 @@ using Unity.BossRoom.ConnectionManagement;
using Unity.BossRoom.UnityServices.Lobbies; using Unity.BossRoom.UnityServices.Lobbies;
using Unity.BossRoom.Utils; using Unity.BossRoom.Utils;
using Unity.Multiplayer.Samples.Utilities; using Unity.Multiplayer.Samples.Utilities;
using Unity.Netcode;
using Unity.Netcode.Transports.UTP;
using UnityEngine; using UnityEngine;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
using VContainer; using VContainer;
@ -61,5 +63,61 @@ namespace UUnity.BossRoom.ConnectionManagement
var connectionMethod = new ConnectionMethodRelay(m_LobbyServiceFacade, m_LocalLobby, m_ConnectionManager, m_ProfileManager, playerName); var connectionMethod = new ConnectionMethodRelay(m_LobbyServiceFacade, m_LocalLobby, m_ConnectionManager, m_ProfileManager, playerName);
m_ConnectionManager.ChangeState(m_ConnectionManager.m_StartingHost.Configure(connectionMethod)); m_ConnectionManager.ChangeState(m_ConnectionManager.m_StartingHost.Configure(connectionMethod));
} }
public override void StartServerIP(string ip, int port)
{
// Log input parameters to ensure they are correct
Debug.Log($"StartServerIP called with IP: {ip}, Port: {port}");
// Check if NetworkManager.Singleton is null
if (NetworkManager.Singleton == null)
{
Debug.Log("NetworkManager.Singleton is null. Ensure a NetworkManager exists in the scene.");
return;
}
// Check if NetworkConfig or NetworkTransport is null
if (NetworkManager.Singleton.NetworkConfig == null)
{
Debug.Log("NetworkManager.Singleton.NetworkConfig is null. Ensure NetworkConfig is properly configured.");
return;
}
if (NetworkManager.Singleton.NetworkConfig.NetworkTransport == null)
{
Debug.Log("NetworkManager.Singleton.NetworkConfig.NetworkTransport is null. Ensure NetworkTransport is properly configured.");
return;
}
// Attempt to cast the transport to UnityTransport
var utp = NetworkManager.Singleton.NetworkConfig.NetworkTransport as UnityTransport;
if (utp == null)
{
Debug.Log("Failed to cast NetworkTransport to UnityTransport. Ensure UnityTransport is set up as the transport.");
return;
}
// Log before setting connection data
Debug.Log($"Setting UnityTransport connection data with IP: {ip}, Port: {port}");
utp.SetConnectionData(ip, (ushort)port);
// Check if ConnectionManager or m_ServerStarting is null
if (m_ConnectionManager == null)
{
Debug.Log("m_ConnectionManager is null. Ensure it is properly assigned.");
return;
}
if (m_ConnectionManager.m_ServerStarting == null)
{
Debug.Log("m_ServerStarting is null. Ensure all states are properly initialized in ConnectionManager.");
return;
}
// Log state change
Debug.Log("Changing state to m_ServerStarting.");
m_ConnectionManager.ChangeState(m_ConnectionManager.m_ServerStarting);
}
} }
} }

@ -0,0 +1,171 @@
using System;
using System.Collections;
using Unity.BossRoom.Infrastructure;
using Unity.BossRoom.UnityServices.Lobbies;
using Unity.Multiplayer.Samples.BossRoom;
using Unity.Netcode;
using UnityEngine;
using VContainer;
namespace Unity.BossRoom.ConnectionManagement
{
class ServerListeningState : ConnectionState
{
[Inject]
protected LobbyServiceFacade m_LobbyServiceFacade;
[Inject]
protected IPublisher<ConnectionEventMessage> m_ConnectionEventPublisher;
// used in ApprovalCheck. This is intended as a bit of light protection against DOS attacks that rely on sending silly big buffers of garbage.
const int k_MaxConnectPayload = 1024;
public override void Enter()
{
var gameState = UnityEngine.Object.Instantiate(m_ConnectionManager.GameState);
gameState.Spawn();
// TODO Phil is refactoring the above, leaving this here for now
}
public override void Exit()
{
SessionManager<SessionPlayerData>.Instance.OnServerEnded();
}
public override void OnClientConnected(ulong clientId)
{
m_ConnectionEventPublisher.Publish(new ConnectionEventMessage() { ConnectStatus = ConnectStatus.Success, PlayerName = SessionManager<SessionPlayerData>.Instance.GetPlayerData(clientId)?.PlayerName });
}
public override void OnClientDisconnect(ulong clientId)
{
var playerId = SessionManager<SessionPlayerData>.Instance.GetPlayerId(clientId);
if (playerId != null)
{
if (m_LobbyServiceFacade.CurrentUnityLobby != null)
{
m_LobbyServiceFacade.RemovePlayerFromLobbyAsync(playerId);
}
var sessionData = SessionManager<SessionPlayerData>.Instance.GetPlayerData(playerId);
if (sessionData.HasValue)
{
m_ConnectionEventPublisher.Publish(new ConnectionEventMessage() { ConnectStatus = ConnectStatus.GenericDisconnect, PlayerName = sessionData.Value.PlayerName });
}
SessionManager<SessionPlayerData>.Instance.DisconnectClient(clientId);
}
}
/// <summary>
/// This logic plugs into the "ConnectionApprovalResponse" exposed by Netcode.NetworkManager. It is run every time a client connects to us.
/// The complementary logic that runs when the client starts its connection can be found in ClientConnectingState.
/// </summary>
/// <remarks>
/// Multiple things can be done here, some asynchronously. For example, it could authenticate your user against an auth service like UGS' auth service. It can
/// also send custom messages to connecting users before they receive their connection result (this is useful to set status messages client side
/// when connection is refused, for example).
/// </remarks>
/// <param name="request"> The initial request contains, among other things, binary data passed into StartClient. In our case, this is the client's GUID,
/// which is a unique identifier for their install of the game that persists across app restarts.
/// <param name="response"> Our response to the approval process. In case of connection refusal with custom return message, we delay using the Pending field.
public override void ApprovalCheck(NetworkManager.ConnectionApprovalRequest request, NetworkManager.ConnectionApprovalResponse response)
{
Debug.Log($"ApprovalCheck called for clientId: {request.ClientNetworkId}");
var connectionData = request.Payload;
var clientId = request.ClientNetworkId;
// Check if the connection data size exceeds the maximum payload size
if (connectionData.Length > k_MaxConnectPayload)
{
Debug.LogWarning($"Connection data from clientId: {clientId} exceeds the maximum allowed size of {k_MaxConnectPayload}. Denying connection.");
response.Approved = false;
return;
}
// Decode and parse the connection payload
var payload = System.Text.Encoding.UTF8.GetString(connectionData);
Debug.Log($"Received connection payload from clientId: {clientId}: {payload}");
ConnectionPayload connectionPayload;
try
{
connectionPayload = JsonUtility.FromJson<ConnectionPayload>(payload);
}
catch (Exception ex)
{
Debug.LogError($"Failed to deserialize connection payload from clientId: {clientId}. Error: {ex.Message}");
response.Approved = false;
return;
}
// Determine the connection status
var gameReturnStatus = GetConnectStatus(connectionPayload);
Debug.Log($"Connect status for clientId: {clientId}: {gameReturnStatus}");
if (gameReturnStatus == ConnectStatus.Success)
{
Debug.Log($"Connection approved for clientId: {clientId}. Setting up session data.");
SessionManager<SessionPlayerData>.Instance.SetupConnectingPlayerSessionData(clientId, connectionPayload.playerId,
new SessionPlayerData(clientId, connectionPayload.playerName, new NetworkGuid(), 0, true));
response.Approved = true;
response.CreatePlayerObject = true;
response.Position = Vector3.zero;
response.Rotation = Quaternion.identity;
Debug.Log($"Sending success payload to clientId: {clientId}");
ConnectionManager.SendServertoClientSuccessPayload(clientId, NetworkManager.Singleton.IsHost ? ConnectionManager.ServerType.ClientHostedServer : ConnectionManager.ServerType.DedicatedServer);
return;
}
// Log denial reason and handle feedback
Debug.LogWarning($"Connection denied for clientId: {clientId}. Reason: {gameReturnStatus}");
IEnumerator WaitToDenyApproval()
{
Debug.Log($"Sending denial reason to clientId: {clientId}");
response.Pending = true; // Delay the approval response
response.Approved = false;
ConnectionManager.SendServerToClientSetDisconnectReason(clientId, gameReturnStatus);
yield return null; // Wait for one frame
response.Pending = false; // Finish the approval process
Debug.Log($"Denied connection finalized for clientId: {clientId}");
}
// Start coroutine to handle denial
ConnectionManager.SendServerToClientSetDisconnectReason(clientId, gameReturnStatus);
Debug.Log($"Starting denial process for clientId: {clientId}");
m_ConnectionManager.StartCoroutine(WaitToDenyApproval());
if (m_LobbyServiceFacade.CurrentUnityLobby != null)
{
Debug.Log($"Removing clientId: {clientId} from lobby.");
m_LobbyServiceFacade.RemovePlayerFromLobbyAsync(connectionPayload.playerId);
}
}
ConnectStatus GetConnectStatus(ConnectionPayload connectionPayload)
{
if (m_ConnectionManager.NetworkManager.ConnectedClientsIds.Count >= m_ConnectionManager.MaxConnectedPlayers)
{
return ConnectStatus.ServerFull;
}
if (connectionPayload.isDebug != Debug.isDebugBuild)
{
return ConnectStatus.IncompatibleBuildType;
}
return SessionManager<SessionPlayerData>.Instance.IsDuplicateConnection(connectionPayload.playerId) ?
ConnectStatus.LoggedInAgain : ConnectStatus.Success;
}
// TODO handle server shutdown by itself (clean shutdown) and tells clients to disconnect? connection draining? MTT-4069
}
}

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 70a54926786e4e92a304a22c43bacb25
timeCreated: 1657574627

@ -0,0 +1,25 @@
using Unity.Multiplayer.Samples;
using Unity.Netcode;
using UnityEngine;
namespace Unity.BossRoom.ConnectionManagement
{
class ServerStartingState : ConnectionState
{
public override void Enter()
{
var success = NetworkManager.Singleton.StartServer();
if (!success)
{
Debug.Log("StartServer returned false and failed starting. Killing process.");
Application.Quit(1);
return;
}
m_ConnectionManager.ChangeState(m_ConnectionManager.m_ServerListening);
}
public override void Exit() { }
}
}

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3340424e374042ab977d9f1dfced6811
timeCreated: 1657574995

@ -0,0 +1,63 @@
using System;
using System.Collections;
using System.Collections.Generic;
using BossRoom.Scripts.Shared.Utilities;
using Unity.BossRoom.ConnectionManagement;
using Unity.BossRoom.Gameplay.GameState;
using Unity.Multiplayer.Samples.Utilities;
using UnityEngine;
using VContainer;
namespace Unity.Multiplayer.Samples.BossRoom.Server
{
public class DSLobbyManagementState : GameStateBehaviour
{
[Inject]
ConnectionManager m_ConnectionManager;
public override GameState ActiveState => GameState.DedicatedServerLobbyManagement;
protected override void Start()
{
base.Start();
// TODO create DGS lobby here, register to matchmaking, etc. This state bypasses the main menu setup users would normally do get in a game
// and does its own game setup MTT-4035
var address = "0.0.0.0"; // Change this for fancier infrastructure hosting setup where you can listen on different IP addresses. Right now listening on all.
var port = 9998;
// Some quick command line processing.
Dictionary<string, string> args = new();
foreach (var oneArg in Environment.GetCommandLineArgs())
{
var keyValue = oneArg.Split('=');
args.Add(keyValue[0], keyValue.Length > 1 ? keyValue[1] : null);
}
var portArg = "-port";
if (args.ContainsKey(portArg) && !int.TryParse(args[portArg], out port))
{
DedicatedServerUtilities.Log("failed to parse -port arg: " + args[portArg]);
}
var ipArg = "-ip";
if (args.TryGetValue(ipArg, out var arg))
{
address = arg;
DedicatedServerUtilities.Log("Got IP: " + args[portArg]);
}
IEnumerator StartServerCoroutine()
{
DedicatedServerUtilities.Log($"Starting Headless Server, listening on address {address}:{port}");
m_ConnectionManager.StartServerIP(address, port); // This will switch to the char select scene once the server started callback has been called
yield return new WaitForServerStarted(); // Less performant than just the callback, but way more readable than a callback hell.
// TODO change scene to char select here and do other init. why is it handled by connection manager right now?
SceneLoaderWrapper.Instance.AddOnSceneEventCallback();
SceneLoaderWrapper.Instance.LoadScene("CharSelect", useNetworkSceneManager: true);
}
StartCoroutine(StartServerCoroutine());
}
}
}

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a35fe42cd86928c4d9dd52f2136ba795
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -7,6 +7,7 @@ namespace Unity.BossRoom.Gameplay.GameState
public enum GameState public enum GameState
{ {
MainMenu, MainMenu,
DedicatedServerLobbyManagement,
CharSelect, CharSelect,
BossRoom, BossRoom,
PostGame PostGame

@ -0,0 +1,34 @@
using System;
using Unity.Netcode;
using UnityEngine;
namespace Unity.Multiplayer.Samples.BossRoom
{
public class NetworkGameState : NetworkBehaviour
{
[SerializeField]
TransformVariable m_GameStateTransformVariable;
[SerializeField]
NetworkWinState m_NetworkWinState;
public NetworkWinState NetworkWinState => m_NetworkWinState;
void Awake()
{
DontDestroyOnLoad(this);
}
public override void OnNetworkSpawn()
{
gameObject.name = "NetworkGameState";
m_GameStateTransformVariable.Value = transform;
}
public override void OnNetworkDespawn()
{
m_GameStateTransformVariable.Value = null;
}
}
}

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9fb009f05b6b84d35af38930cac98d9a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,21 @@
using System;
using Unity.Netcode;
using UnityEngine;
namespace Unity.Multiplayer.Samples.BossRoom
{
public enum WinState
{
Invalid,
Win,
Loss
}
/// <summary>
/// MonoBehaviour containing only one NetworkVariableBool to represent the game session's win state.
/// </summary>
public class NetworkWinState : NetworkBehaviour
{
public NetworkVariable<WinState> winState = new NetworkVariable<WinState>(WinState.Invalid);
}
}

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 69eb1bedacf698e4bada2f8d55dabdd8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -3,6 +3,7 @@ using System.Collections;
using Unity.BossRoom.ConnectionManagement; using Unity.BossRoom.ConnectionManagement;
using Unity.BossRoom.Gameplay.GameplayObjects; using Unity.BossRoom.Gameplay.GameplayObjects;
using Unity.BossRoom.Infrastructure; using Unity.BossRoom.Infrastructure;
using Unity.Multiplayer.Samples;
using Unity.Multiplayer.Samples.BossRoom; using Unity.Multiplayer.Samples.BossRoom;
using Unity.Multiplayer.Samples.Utilities; using Unity.Multiplayer.Samples.Utilities;
using Unity.Netcode; using Unity.Netcode;
@ -48,6 +49,31 @@ namespace Unity.BossRoom.Gameplay.GameState
} }
} }
// void OnClientChangedSeat(ulong clientId, int newSeatIdx, bool lockedIn)
// {
// int idx = FindLobbyPlayerIdx(clientId);
// if (idx == -1)
// {
// throw new Exception($"OnClientChangedSeat: client ID {clientId} is not a lobby player and cannot change seats! Shouldn't be here!");
// }
//
// if (networkCharSelection.IsLobbyClosed.Value)
// {
// // The user tried to change their class after everything was locked in... too late! Discard this choice
// return;
// }
//
// // Allow multiple players to select the same character without restrictions
// networkCharSelection.LobbyPlayers[idx] = new NetworkCharSelection.LobbyPlayerState(clientId,
// networkCharSelection.LobbyPlayers[idx].PlayerName,
// networkCharSelection.LobbyPlayers[idx].PlayerNumber,
// lockedIn ? NetworkCharSelection.SeatState.LockedIn : NetworkCharSelection.SeatState.Active,
// newSeatIdx,
// Time.time);
// Debug.Log("CloseLobbyIfReady");
// CloseLobbyIfReady();
// }
void OnClientChangedSeat(ulong clientId, int newSeatIdx, bool lockedIn) void OnClientChangedSeat(ulong clientId, int newSeatIdx, bool lockedIn)
{ {
int idx = FindLobbyPlayerIdx(clientId); int idx = FindLobbyPlayerIdx(clientId);
@ -62,14 +88,56 @@ namespace Unity.BossRoom.Gameplay.GameState
return; return;
} }
// Allow multiple players to select the same character without restrictions if (newSeatIdx == -1)
{
// we can't lock in with no seat
lockedIn = false;
}
else
{
// see if someone has already locked-in that seat! If so, too late... discard this choice
foreach (NetworkCharSelection.LobbyPlayerState playerInfo in networkCharSelection.LobbyPlayers)
{
if (playerInfo.ClientId != clientId && playerInfo.SeatIdx == newSeatIdx && playerInfo.SeatState == NetworkCharSelection.SeatState.LockedIn)
{
// somebody already locked this choice in. Stop!
// Instead of granting lock request, change this player to Inactive state.
networkCharSelection.LobbyPlayers[idx] = new NetworkCharSelection.LobbyPlayerState(clientId,
networkCharSelection.LobbyPlayers[idx].PlayerName,
networkCharSelection.LobbyPlayers[idx].PlayerNumber,
NetworkCharSelection.SeatState.Inactive);
// then early out
return;
}
}
}
networkCharSelection.LobbyPlayers[idx] = new NetworkCharSelection.LobbyPlayerState(clientId, networkCharSelection.LobbyPlayers[idx] = new NetworkCharSelection.LobbyPlayerState(clientId,
networkCharSelection.LobbyPlayers[idx].PlayerName, networkCharSelection.LobbyPlayers[idx].PlayerName,
networkCharSelection.LobbyPlayers[idx].PlayerNumber, networkCharSelection.LobbyPlayers[idx].PlayerNumber,
lockedIn ? NetworkCharSelection.SeatState.LockedIn : NetworkCharSelection.SeatState.Active, lockedIn ? NetworkCharSelection.SeatState.LockedIn : NetworkCharSelection.SeatState.Active,
newSeatIdx, newSeatIdx,
Time.time); Time.time);
Debug.Log("CloseLobbyIfReady");
if (lockedIn)
{
// to help the clients visually keep track of who's in what seat, we'll "kick out" any other players
// who were also in that seat. (Those players didn't click "Ready!" fast enough, somebody else took their seat!)
for (int i = 0; i < networkCharSelection.LobbyPlayers.Count; ++i)
{
if (networkCharSelection.LobbyPlayers[i].SeatIdx == newSeatIdx && i != idx)
{
// change this player to Inactive state.
networkCharSelection.LobbyPlayers[i] = new NetworkCharSelection.LobbyPlayerState(
networkCharSelection.LobbyPlayers[i].ClientId,
networkCharSelection.LobbyPlayers[i].PlayerName,
networkCharSelection.LobbyPlayers[i].PlayerNumber,
NetworkCharSelection.SeatState.Inactive);
}
}
}
CloseLobbyIfReady(); CloseLobbyIfReady();
} }
@ -93,14 +161,50 @@ namespace Unity.BossRoom.Gameplay.GameState
} }
void CloseLobbyIfReady() void CloseLobbyIfReady()
{ {
startButtonScipt.InteractableTruer(false); // If dedicated server, leave char select open if there's no one left
if (DedicatedServerUtilities.IsServerBuildTarget && networkCharSelection.LobbyPlayers.Count == 0)
{
return;
}
foreach (NetworkCharSelection.LobbyPlayerState playerInfo in networkCharSelection.LobbyPlayers) foreach (NetworkCharSelection.LobbyPlayerState playerInfo in networkCharSelection.LobbyPlayers)
{ {
if (playerInfo.SeatState != NetworkCharSelection.SeatState.LockedIn) if (playerInfo.SeatState != NetworkCharSelection.SeatState.LockedIn)
return; // at least one player isn't locked in yet! return; // nope, at least one player isn't locked in yet!
}
// everybody's ready at the same time! Lock it down!
networkCharSelection.IsLobbyClosed.Value = true;
// remember our choices so the next scene can use the info
SaveLobbyResults();
// Delay a few seconds to give the UI time to react, then switch scenes
IEnumerator WaitToEndLobby()
{
yield return new WaitForSeconds(3);
SceneLoaderWrapper.Instance.LoadScene("BossRoom", useNetworkSceneManager: true);
} }
startButtonScipt.InteractableTruer(true); m_WaitToEndLobbyCoroutine = StartCoroutine(WaitToEndLobby());
} }
// void CloseLobbyIfReady()
// {
// // If dedicated server, leave char select open if there's no one left
// if (DedicatedServerUtilities.IsServerBuildTarget && networkCharSelection.LobbyPlayers.Count == 0)
// {
// return;
// }
//
// startButtonScipt.InteractableTruer(false);
// foreach (NetworkCharSelection.LobbyPlayerState playerInfo in networkCharSelection.LobbyPlayers)
// {
// if (playerInfo.SeatState != NetworkCharSelection.SeatState.LockedIn)
// return; // at least one player isn't locked in yet!
// }
// startButtonScipt.InteractableTruer(true);
// }
public StartButtonScipt startButtonScipt; public StartButtonScipt startButtonScipt;
void CancelCloseLobby() void CancelCloseLobby()
{ {

@ -0,0 +1,23 @@
using UnityEngine;
namespace Unity.Multiplayer.Samples.BossRoom
{
/// <summary>
/// Class which registers a transform to an associated TransformVariable ScriptableObject.
/// </summary>
public class TransformRegister : MonoBehaviour
{
[SerializeField]
TransformVariable m_TransformVariable;
void OnEnable()
{
m_TransformVariable.Value = transform;
}
void OnDisable()
{
m_TransformVariable.Value = null;
}
}
}

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b280145480d7594419baed09a111184b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,14 @@
using UnityEngine;
namespace Unity.Multiplayer.Samples.BossRoom
{
/// <summary>
/// A ScriptableObject which contains a reference to a Transform component. This can be used to remove dependencies
/// between scene objects.
/// </summary>
[CreateAssetMenu]
public class TransformVariable : ScriptableObject
{
public Transform Value;
}
}

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5cccef3cfcbccdb4aa4b407a003237b7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

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

@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine;
using UnityEngine.SceneManagement;
using Debug = UnityEngine.Debug;
namespace Unity.Multiplayer.Samples
{
public static class DedicatedServerUtilities
{
public static bool IsServerBuildTarget
{
get
{
#if UNITY_SERVER
return true;
#else
return false;
#endif
}
}
/// <summary>
/// Some notes on logging and dedicated servers:
///
/// With dedicated server, you don't have a view into your game like you'd have with other types of platforms. You'll rely a lot on logging to get
/// insights into what's happening on your servers, even more with your live fleets of thousands of servers.
/// Unity's default logging isn't usable for dedicated server use cases. The following requirements are missing:
/// - Structured logging: with 1000+ server fleets, you don't want to look at log files individually. You'll need log ingestion/analysis tools to be able
/// to parse all that data (think tools like elasticsearch for example). Making your logs structured so they are machine friendly (for example
/// having each log entry be a json object) makes this easier to integrate with those tools and easier to analyze.
/// - Log levels: most of the time, you won't want to receive info or debug logs, only warnings and errors (so you don't spam your analysis tools and so they don't
/// cost your a fortune). However, you'll also want to enable info and debug logs for specific servers when debugging them. Having a logger that
/// manages this for you is better than wrapping your logs yourself and managing this yourself.
/// - Log file rotation: Dedicated servers can run for days and days, while games on user devices will run for a few play sessions before being closed. This means your
/// log file will grow and grow. Rotation is an automated way to swap log files each x hours or days. This allows deleting and easier managing
/// of older log files.
/// - Performance: logging can be a performance costly operation, which contributes to your CPU perf costs, which in turn are translated to hosting monetary costs.
/// Having a logging library that's optimized for these scenarios is essential (burstable, threaded, etc).
/// This also includes not having to print full stack traces (not needed for most devops operations, but could be enabled for debugging)
///
/// A few solutions exists for this. ZLogger https://github.com/Cysharp/ZLogger and serilog https://www.nuget.org/packages/serilog/ for example.
/// Unity also has an experimental package com.unity.logging that answers the above needs as well. Once this is out of experimental, this will be
/// integrated in boss room. TODO for this first pass at DGS, we're using the default logger. TODO replace me - MTT-4038
/// </summary>
/// <param name="message"></param>
public static void Log(string message)
{
// IMPORTANT FOR LOGGING READ ABOVE. The following isn't recommended for production use with dedicated game servers.
Debug.Log($"[{DateTime.UtcNow}] {Time.realtimeSinceStartup} {Time.time} pid[{Process.GetCurrentProcess().Id}] - {message}");
}
/// <summary>
/// Quick tool to get insights in your current scene, to be able to debug client and server hierarchies.
/// </summary>
public static void PrintSceneHierarchy()
{
List<GameObject> rootObjects = new List<GameObject>();
Scene scene = SceneManager.GetActiveScene();
scene.GetRootGameObjects(rootObjects);
string toPrint = "\n";
foreach (var rootObject in rootObjects)
{
toPrint += $"{GetInfoForObject(rootObject)}\n";
PrintChildObjectsRecursive(rootObject, depth: 0, ref toPrint);
}
Log(toPrint);
}
private static void PrintChildObjectsRecursive(GameObject parentObject, int depth, ref string toPrint)
{
if (parentObject.transform.childCount == 0)
{
return;
}
string tabs = new string(' ', ++depth * 4);
foreach (Transform child in parentObject.transform)
{
toPrint += $"{tabs}{GetInfoForObject(child.gameObject)}\n";
PrintChildObjectsRecursive(child.gameObject, depth, ref toPrint); // asdf
}
}
private static string GetInfoForObject(GameObject obj)
{
List<Component> allComponents = new();
obj.GetComponents(allComponents);
var nullCount = allComponents.FindAll(component => component == null).Count;
return $"{obj.name}\tnb null {nullCount}/{allComponents.Count}";
}
}
}

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 035a4d94ff413464f85c30a5cc56cf91
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,23 @@
using Unity.Netcode;
using UnityEngine;
namespace BossRoom.Scripts.Shared.Utilities
{
public class WaitForServerStarted : CustomYieldInstruction
{
bool m_IsDone;
public override bool keepWaiting => m_IsDone;
public WaitForServerStarted()
{
void SetDone()
{
NetworkManager.Singleton.OnServerStarted -= SetDone;
m_IsDone = true;
}
NetworkManager.Singleton.OnServerStarted += SetDone;
}
}
}

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8a86c80ed82a60747a073c9940723d4d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -127,6 +127,18 @@ namespace Unity.Multiplayer.Samples.Utilities
} }
} }
/// <summary>
/// Initializes the callback on scene events. This needs to be called right after initializing NetworkManager
/// (after StartHost, StartClient or StartServer)
/// </summary>
public void AddOnSceneEventCallback()
{
if (IsNetworkSceneManagementEnabled)
{
NetworkManager.SceneManager.OnSceneEvent += OnSceneEvent;
}
}
void OnSceneEvent(SceneEvent sceneEvent) void OnSceneEvent(SceneEvent sceneEvent)
{ {
switch (sceneEvent.SceneEventType) switch (sceneEvent.SceneEventType)

@ -0,0 +1,17 @@
{
"MonoBehaviour": {
"Version": 4,
"EnableBurstCompilation": true,
"EnableOptimisations": true,
"EnableSafetyChecks": false,
"EnableDebugInAllBuilds": false,
"DebugDataKind": 1,
"EnableArmv9SecurityFeatures": false,
"CpuMinTargetX32": 0,
"CpuMaxTargetX32": 0,
"CpuMinTargetX64": 0,
"CpuMaxTargetX64": 0,
"CpuTargetsX64": 72,
"OptimizeFor": 0
}
}

@ -11,6 +11,9 @@ EditorBuildSettings:
- enabled: 1 - enabled: 1
path: Assets/Scenes/MainMenu.unity path: Assets/Scenes/MainMenu.unity
guid: e676e10fba50b4172a2b5146af0b3c12 guid: e676e10fba50b4172a2b5146af0b3c12
- enabled: 1
path: Assets/Scenes/DedicatedServerLobbyManagement.unity
guid: c415c55354f6743faa63ac4c8b181a65
- enabled: 1 - enabled: 1
path: Assets/Scenes/CharSelect.unity path: Assets/Scenes/CharSelect.unity
guid: 69ca9af1235ffe340a45770dd5771f03 guid: 69ca9af1235ffe340a45770dd5771f03

Loading…
Cancel
Save