Merge branch 'update-netcode-1.2'
This commit is contained in:
Коммит
26d5c778be
|
@ -1,55 +0,0 @@
|
|||
**/Library/
|
||||
**/UserSettings/
|
||||
**/Temp/
|
||||
**/obj/
|
||||
|
||||
**/.vscode/
|
||||
**/.vs
|
||||
|
||||
**/Assets/Plugins/*
|
||||
**/Assets/Plugins.meta
|
||||
|
||||
*.user
|
||||
*.idea
|
||||
*.csproj
|
||||
*.csproj.user
|
||||
*.sln
|
||||
*.suo
|
||||
*.userprefs
|
||||
*.app
|
||||
*.VC.*
|
||||
.DS_Store
|
||||
*.swp
|
||||
*.DotSettings
|
||||
*.gen.csproj.meta
|
||||
|
||||
obj.meta
|
||||
.vs/
|
||||
build/*
|
||||
TwoStickShooter/Pure/Library/AnnotationManager
|
||||
*.pyc
|
||||
|
||||
#generated by performance framework
|
||||
*/PerformanceTestRunInfo.json
|
||||
Performance/Assets/StreamingAssets.meta
|
||||
Performance/Assets/StreamingAssets
|
||||
|
||||
StreamingAssets.meta
|
||||
PerformanceTestRunInfo.json
|
||||
PerformanceTestRunInfo.json.meta
|
||||
|
||||
**/InitTestScene*
|
||||
**/Logs
|
||||
**/Assets/StreamingAssets
|
||||
**/Assets/EntityCache
|
||||
**/Assets/TypeDependencyCache
|
||||
**/Assets/SceneDependencyCache/*
|
||||
**/Assets/SceneDependencyCache.meta
|
||||
*~master*
|
||||
*~HEAD*
|
||||
|
||||
artifacts
|
||||
|
||||
.Editor
|
||||
.UnityLauncher.Editor
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"tags": [],
|
||||
"launchArguments": null,
|
||||
"opened": 1685539680224
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
{
|
||||
"Show": true,
|
||||
"Dependencies": [
|
||||
"GlobalObjectId_V1-1-687ff696e4df441e5931eb81db4d1db0-93214019566545601-0",
|
||||
"GlobalObjectId_V1-1-efd815fb310344e61bf5fa7dc0f06555-93214019566545601-0"
|
||||
],
|
||||
"Components": [
|
||||
{
|
||||
"$type": "Unity.Build.Classic.ClassicBuildProfile, Unity.Build.Classic",
|
||||
"$version": 1,
|
||||
"Platform": "android",
|
||||
"Configuration": 2
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Build.Common.PlayerScriptingDefines, Unity.Build",
|
||||
"Defines": [
|
||||
"ENABLE_HYBRID_RENDERER_V2",
|
||||
"FRONTEND_PLAYER_BUILD"
|
||||
]
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Build.Classic.ClassicScriptingSettings, Unity.Build.Classic",
|
||||
"ScriptingBackend": 1,
|
||||
"Il2CppCompilerConfiguration": 1,
|
||||
"UseIncrementalGC": false
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 47d3411d85eb04758a5dd2c7d57da3ed
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 627ef77bce55554428c21a56f59002bd, type: 3}
|
|
@ -1,29 +0,0 @@
|
|||
{
|
||||
"Show": true,
|
||||
"Dependencies": [],
|
||||
"Components": [
|
||||
{
|
||||
"$type": "Unity.Build.Common.GeneralSettings, Unity.Build",
|
||||
"ProductName": "Asteroids",
|
||||
"CompanyName": "Unity Technologies",
|
||||
"Version": "0.1"
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Build.Common.SceneList, Unity.Build",
|
||||
"$version": 1,
|
||||
"BuildCurrentScene": false,
|
||||
"SceneInfos": [
|
||||
{
|
||||
"Scene": "GlobalObjectId_V1-1-e1d9a388defac7049a631b0047b4278e-102900000-0",
|
||||
"AutoLoad": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Build.Classic.ClassicScriptingSettings, Unity.Build.Classic",
|
||||
"ScriptingBackend": 0,
|
||||
"Il2CppCompilerConfiguration": 1,
|
||||
"UseIncrementalGC": false
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 74cc8eb4a6f6148b8b85e86a7ac739f2
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 627ef77bce55554428c21a56f59002bd, type: 3}
|
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"Show": true,
|
||||
"Dependencies": [
|
||||
"GlobalObjectId_V1-1-450f20c3e50de4631a862cc7b7da1ae6-93214019566545601-0",
|
||||
"GlobalObjectId_V1-1-74cc8eb4a6f6148b8b85e86a7ac739f2-93214019566545601-0"
|
||||
],
|
||||
"Components": [
|
||||
{
|
||||
"$type": "Unity.Build.Classic.ClassicBuildProfile, Unity.Build.Classic",
|
||||
"$version": 1,
|
||||
"Platform": "linux",
|
||||
"Configuration": 2
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: aec82c4761a8e40beb219c8f2483abd1
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 627ef77bce55554428c21a56f59002bd, type: 3}
|
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"Show": true,
|
||||
"Dependencies": [
|
||||
"GlobalObjectId_V1-1-69018010a3ed1485a922ec6aeaa79daf-93214019566545601-0",
|
||||
"GlobalObjectId_V1-1-74cc8eb4a6f6148b8b85e86a7ac739f2-93214019566545601-0"
|
||||
],
|
||||
"Components": [
|
||||
{
|
||||
"$type": "Unity.Build.Classic.ClassicBuildProfile, Unity.Build.Classic",
|
||||
"$version": 1,
|
||||
"Platform": "linux",
|
||||
"Configuration": 2
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 17866e5cc4b0345a691647ebe95d40f0
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 627ef77bce55554428c21a56f59002bd, type: 3}
|
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"Show": true,
|
||||
"Dependencies": [
|
||||
"GlobalObjectId_V1-1-450f20c3e50de4631a862cc7b7da1ae6-93214019566545601-0",
|
||||
"GlobalObjectId_V1-1-74cc8eb4a6f6148b8b85e86a7ac739f2-93214019566545601-0"
|
||||
],
|
||||
"Components": [
|
||||
{
|
||||
"$type": "Unity.Build.Classic.ClassicBuildProfile, Unity.Build.Classic",
|
||||
"$version": 1,
|
||||
"Platform": "macos",
|
||||
"Configuration": 2
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5d0038210168e4e7f90593725442bb39
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 627ef77bce55554428c21a56f59002bd, type: 3}
|
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"Show": true,
|
||||
"Dependencies": [
|
||||
"GlobalObjectId_V1-1-69018010a3ed1485a922ec6aeaa79daf-93214019566545601-0",
|
||||
"GlobalObjectId_V1-1-74cc8eb4a6f6148b8b85e86a7ac739f2-93214019566545601-0"
|
||||
],
|
||||
"Components": [
|
||||
{
|
||||
"$type": "Unity.Build.Classic.ClassicBuildProfile, Unity.Build.Classic",
|
||||
"$version": 1,
|
||||
"Platform": "macos",
|
||||
"Configuration": 2
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d00c07af8c31e43838690cbe652e53ca
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 627ef77bce55554428c21a56f59002bd, type: 3}
|
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"Show": true,
|
||||
"Dependencies": [
|
||||
"GlobalObjectId_V1-1-450f20c3e50de4631a862cc7b7da1ae6-93214019566545601-0",
|
||||
"GlobalObjectId_V1-1-74cc8eb4a6f6148b8b85e86a7ac739f2-93214019566545601-0"
|
||||
],
|
||||
"Components": [
|
||||
{
|
||||
"$type": "Unity.Build.Classic.ClassicBuildProfile, Unity.Build.Classic",
|
||||
"$version": 1,
|
||||
"Platform": "win",
|
||||
"Configuration": 2
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 28c100126ec9540fd9f4dfe16d0a1de0
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 627ef77bce55554428c21a56f59002bd, type: 3}
|
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"Show": true,
|
||||
"Dependencies": [
|
||||
"GlobalObjectId_V1-1-69018010a3ed1485a922ec6aeaa79daf-93214019566545601-0",
|
||||
"GlobalObjectId_V1-1-74cc8eb4a6f6148b8b85e86a7ac739f2-93214019566545601-0"
|
||||
],
|
||||
"Components": [
|
||||
{
|
||||
"$type": "Unity.Build.Classic.ClassicBuildProfile, Unity.Build.Classic",
|
||||
"$version": 1,
|
||||
"Platform": "win",
|
||||
"Configuration": 2
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5475da7dea6224981b641ce465030f6f
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 627ef77bce55554428c21a56f59002bd, type: 3}
|
|
@ -1,95 +0,0 @@
|
|||
{
|
||||
"Show": true,
|
||||
"Dependencies": [],
|
||||
"Components": [
|
||||
{
|
||||
"$type": "Unity.Build.Common.GeneralSettings, Unity.Build",
|
||||
"ProductName": "NetcodeSamples",
|
||||
"CompanyName": "Unity Technologies",
|
||||
"Version": "0.1"
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Build.Common.SceneList, Unity.Build",
|
||||
"$version": 1,
|
||||
"BuildCurrentScene": false,
|
||||
"SceneInfos": [
|
||||
{
|
||||
"Scene": "GlobalObjectId_V1-1-78517606c5abc4802a5a988a3f3fc2bf-102900000-0",
|
||||
"AutoLoad": true
|
||||
},
|
||||
{
|
||||
"Scene": "GlobalObjectId_V1-1-06ff0d515097f4e60973d2ca8d13eb39-102900000-0",
|
||||
"AutoLoad": false
|
||||
},
|
||||
{
|
||||
"Scene": "GlobalObjectId_V1-1-e1d9a388defac7049a631b0047b4278e-102900000-0",
|
||||
"AutoLoad": false
|
||||
},
|
||||
{
|
||||
"Scene": "GlobalObjectId_V1-1-46d38099d1fc14425a0f07eff0d05a93-102900000-0",
|
||||
"AutoLoad": false
|
||||
},
|
||||
{
|
||||
"Scene": "GlobalObjectId_V1-1-87e39eaa89fb14d36836ac169c4259e0-102900000-0",
|
||||
"AutoLoad": false
|
||||
},
|
||||
{
|
||||
"Scene": "GlobalObjectId_V1-1-d82373bbdea1f8744be2e30aed760957-102900000-0",
|
||||
"AutoLoad": false
|
||||
},
|
||||
{
|
||||
"Scene": "GlobalObjectId_V1-1-998e01b18de7849b7ae73384062aa9d5-102900000-0",
|
||||
"AutoLoad": false
|
||||
},
|
||||
{
|
||||
"Scene": "GlobalObjectId_V1-1-4cbe01b86844d4e719a3ad9d806e43ba-102900000-0",
|
||||
"AutoLoad": false
|
||||
},
|
||||
{
|
||||
"Scene": "GlobalObjectId_V1-1-001253cdb73684a52b79be89e69df75b-102900000-0",
|
||||
"AutoLoad": false
|
||||
},
|
||||
{
|
||||
"Scene": "GlobalObjectId_V1-1-5ad911e91463347e9885555d2d19e289-102900000-0",
|
||||
"AutoLoad": false
|
||||
},
|
||||
{
|
||||
"Scene": "GlobalObjectId_V1-1-ebf120ae2dfed4ea9bb75f83b7ecdd1e-102900000-0",
|
||||
"AutoLoad": false
|
||||
},
|
||||
{
|
||||
"Scene": "GlobalObjectId_V1-1-2418473ae6e6248b5803823efb4de8f5-102900000-0",
|
||||
"AutoLoad": false
|
||||
},
|
||||
{
|
||||
"Scene": "GlobalObjectId_V1-1-ba6070794104a46da93b6b86088e3c01-102900000-0",
|
||||
"AutoLoad": false
|
||||
},
|
||||
{
|
||||
"Scene": "GlobalObjectId_V1-1-9becba3d8791e41dc88d2151be0640f7-102900000-0",
|
||||
"AutoLoad": false
|
||||
},
|
||||
{
|
||||
"Scene": "GlobalObjectId_V1-1-d775a53e92655c74f8ceb41730800e49-102900000-0",
|
||||
"AutoLoad": false
|
||||
},
|
||||
{
|
||||
"Scene": "GlobalObjectId_V1-1-bef98bc3729e842e5b2f2cc28f19931d-102900000-0",
|
||||
"AutoLoad": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Build.Classic.ClassicScriptingSettings, Unity.Build.Classic",
|
||||
"ScriptingBackend": 0,
|
||||
"Il2CppCompilerConfiguration": 1,
|
||||
"UseIncrementalGC": false
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Build.Common.PlayerScriptingDefines, Unity.Build",
|
||||
"Defines": [
|
||||
"FRONTEND_PLAYER_BUILD"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: efd815fb310344e61bf5fa7dc0f06555
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 627ef77bce55554428c21a56f59002bd, type: 3}
|
|
@ -1,24 +0,0 @@
|
|||
{
|
||||
"Show": true,
|
||||
"Dependencies": [],
|
||||
"Components": [
|
||||
{
|
||||
"$type": "NetCodeConversionSettings, Unity.NetCode.Authoring.Hybrid",
|
||||
"Target": 2
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Build.Common.PlayerScriptingDefines, Unity.Build",
|
||||
"Defines": [
|
||||
"UNITY_CLIENT",
|
||||
"ENABLE_HYBRID_RENDERER_V2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Entities.Conversion.ConversionSystemFilterSettings, Unity.Entities.Hybrid",
|
||||
"ExcludedConversionSystemAssemblies": [
|
||||
"GlobalObjectId_V1-1-b7d127909f4a04725b3edab4d8700bed-5897886265953266890-0",
|
||||
"GlobalObjectId_V1-1-78161aee92fd144059f0fc99d4018d7b-5897886265953266890-0"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 450f20c3e50de4631a862cc7b7da1ae6
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 627ef77bce55554428c21a56f59002bd, type: 3}
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"Show": true,
|
||||
"Dependencies": [],
|
||||
"Components": [
|
||||
{
|
||||
"$type": "Unity.Build.Common.PlayerScriptingDefines, Unity.Build",
|
||||
"Defines": [
|
||||
"ENABLE_HYBRID_RENDERER_V2"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 687ff696e4df441e5931eb81db4d1db0
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 627ef77bce55554428c21a56f59002bd, type: 3}
|
|
@ -1,60 +0,0 @@
|
|||
{
|
||||
"Show": true,
|
||||
"Dependencies": [],
|
||||
"Components": [
|
||||
{
|
||||
"$type": "Unity.Build.DotsRuntime.IL2CPPSettings, Unity.Build.DotsRuntime",
|
||||
"ScriptDebugging": 0,
|
||||
"WaitForDebugger": false
|
||||
},
|
||||
{
|
||||
"$type": "NetCodeConversionSettings, Unity.NetCode.Authoring.Hybrid",
|
||||
"Target": 1
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Build.DotsRuntime.DotsRuntimeRootAssembly, Unity.Build.DotsRuntime",
|
||||
"BeeTargetOverride": null,
|
||||
"RootAssembly": "GlobalObjectId_V1-1-89eead9c79a674e97a92f7769eaedc59-5897886265953266890-0"
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Entities.Conversion.ConversionSystemFilterSettings, Unity.Entities.Hybrid",
|
||||
"ExcludedConversionSystemAssemblies": [
|
||||
"GlobalObjectId_V1-1-7a450cf7ca9694b5a8bfa3fd83ec635a-5897886265953266890-0",
|
||||
"GlobalObjectId_V1-1-c52403dffb9bc4f33a799f71eca4ab9a-5897886265953266890-0",
|
||||
"GlobalObjectId_V1-1-8281b45ed5ac44d5b9f06391156a3007-5897886265953266890-0",
|
||||
"GlobalObjectId_V1-1-308a44c6d7c754f2bb0e69df7e894c78-5897886265953266890-0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Build.Common.GeneralSettings, Unity.Build",
|
||||
"ProductName": "AsteroidsServer-DotsRuntime",
|
||||
"CompanyName": "Unity",
|
||||
"Version": "1.0.0"
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Build.Common.SceneList, Unity.Build",
|
||||
"$version": 1,
|
||||
"BuildCurrentScene": false,
|
||||
"SceneInfos": [
|
||||
{
|
||||
"Scene": "GlobalObjectId_V1-1-e1d9a388defac7049a631b0047b4278e-102900000-0",
|
||||
"AutoLoad": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Entities.Runtime.Build.DotsRuntimeScriptingSettings, Unity.Entities.Runtime.Build",
|
||||
"EnableSafetyChecks": 0,
|
||||
"EnableProfiler": 0,
|
||||
"ScriptingDefines": [
|
||||
"UNITY_SERVER",
|
||||
"UNITY_DOTSRUNTIME"
|
||||
],
|
||||
"EnableMultithreading": true
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Entities.Runtime.Build.DotsRuntimeBurstSettings, Unity.Entities.Runtime.Build",
|
||||
"EnableBurst": true
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9b3a397188c16436d8802a1edfb882cc
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 627ef77bce55554428c21a56f59002bd, type: 3}
|
|
@ -1,31 +0,0 @@
|
|||
{
|
||||
"Show": true,
|
||||
"Dependencies": [
|
||||
"GlobalObjectId_V1-1-9b3a397188c16436d8802a1edfb882cc-93214019566545601-0"
|
||||
],
|
||||
"Components": [
|
||||
{
|
||||
"$type": "Unity.Build.DotsRuntime.DotsRuntimeBuildProfile, Unity.Build.DotsRuntime",
|
||||
"Target": "linux-ns21",
|
||||
"Configuration": 2,
|
||||
"UseNewPipeline": false,
|
||||
"PipelineConstructor": null
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Build.Common.GeneralSettings, Unity.Build",
|
||||
"ProductName": "AsteroidsServer-DotsRuntime-Linux",
|
||||
"CompanyName": "Unity",
|
||||
"Version": "1.0.0"
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Entities.Runtime.Build.DotsRuntimeScriptingSettings, Unity.Entities.Runtime.Build",
|
||||
"EnableSafetyChecks": 0,
|
||||
"EnableProfiler": 0,
|
||||
"ScriptingDefines": [
|
||||
"UNITY_SERVER",
|
||||
"UNITY_DOTSRUNTIME"
|
||||
],
|
||||
"EnableMultithreading": true
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 17ae86afc85e04d8d8b0e2003757b527
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 627ef77bce55554428c21a56f59002bd, type: 3}
|
|
@ -1,40 +0,0 @@
|
|||
{
|
||||
"Show": true,
|
||||
"Dependencies": [
|
||||
"GlobalObjectId_V1-1-9b3a397188c16436d8802a1edfb882cc-93214019566545601-0"
|
||||
],
|
||||
"Components": [
|
||||
{
|
||||
"$type": "Unity.Build.DotsRuntime.DotsRuntimeBuildProfile, Unity.Build.DotsRuntime",
|
||||
"Target": "macos-ns21",
|
||||
"Configuration": 2,
|
||||
"UseNewPipeline": false,
|
||||
"PipelineConstructor": null
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Build.Common.GeneralSettings, Unity.Build",
|
||||
"ProductName": "AsteroidsServer-DotsRuntime-MacOS",
|
||||
"CompanyName": "Unity",
|
||||
"Version": "1.0.0"
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Entities.Runtime.Build.DotsRuntimeBurstSettings, Unity.Entities.Runtime.Build",
|
||||
"EnableBurst": true
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Build.DotsRuntime.IL2CPPSettings, Unity.Build.DotsRuntime",
|
||||
"ScriptDebugging": 0,
|
||||
"WaitForDebugger": false
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Entities.Runtime.Build.DotsRuntimeScriptingSettings, Unity.Entities.Runtime.Build",
|
||||
"EnableSafetyChecks": 0,
|
||||
"EnableProfiler": 0,
|
||||
"ScriptingDefines": [
|
||||
"UNITY_SERVER",
|
||||
"UNITY_DOTSRUNTIME"
|
||||
],
|
||||
"EnableMultithreading": true
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: df8e7252145fd4e96846b97d32d75a48
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 627ef77bce55554428c21a56f59002bd, type: 3}
|
|
@ -1,31 +0,0 @@
|
|||
{
|
||||
"Show": true,
|
||||
"Dependencies": [
|
||||
"GlobalObjectId_V1-1-9b3a397188c16436d8802a1edfb882cc-93214019566545601-0"
|
||||
],
|
||||
"Components": [
|
||||
{
|
||||
"$type": "Unity.Build.DotsRuntime.DotsRuntimeBuildProfile, Unity.Build.DotsRuntime",
|
||||
"Target": "windows-ns21",
|
||||
"Configuration": 2,
|
||||
"UseNewPipeline": false,
|
||||
"PipelineConstructor": null
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Build.Common.GeneralSettings, Unity.Build",
|
||||
"ProductName": "AsteroidsServer-DotsRuntime-Win",
|
||||
"CompanyName": "Unity",
|
||||
"Version": "1.0.0"
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Entities.Runtime.Build.DotsRuntimeScriptingSettings, Unity.Entities.Runtime.Build",
|
||||
"EnableSafetyChecks": 0,
|
||||
"EnableProfiler": 0,
|
||||
"ScriptingDefines": [
|
||||
"UNITY_SERVER",
|
||||
"UNITY_DOTSRUNTIME"
|
||||
],
|
||||
"EnableMultithreading": true
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6b1f192ecffdb4fd6bae6124373e844b
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 627ef77bce55554428c21a56f59002bd, type: 3}
|
|
@ -1,22 +0,0 @@
|
|||
{
|
||||
"Show": true,
|
||||
"Dependencies": [
|
||||
"GlobalObjectId_V1-1-687ff696e4df441e5931eb81db4d1db0-93214019566545601-0",
|
||||
"GlobalObjectId_V1-1-efd815fb310344e61bf5fa7dc0f06555-93214019566545601-0"
|
||||
],
|
||||
"Components": [
|
||||
{
|
||||
"$type": "Unity.Build.Classic.ClassicBuildProfile, Unity.Build.Classic",
|
||||
"$version": 1,
|
||||
"Platform": "macos",
|
||||
"Configuration": 2
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Build.Common.PlayerScriptingDefines, Unity.Build",
|
||||
"Defines": [
|
||||
"ENABLE_HYBRID_RENDERER_V2",
|
||||
"FRONTEND_PLAYER_BUILD"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bce786920f20443b899dc5caad373df4
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 627ef77bce55554428c21a56f59002bd, type: 3}
|
|
@ -1,28 +0,0 @@
|
|||
{
|
||||
"Show": true,
|
||||
"Dependencies": [],
|
||||
"Components": [
|
||||
{
|
||||
"$type": "NetCodeConversionSettings, Unity.NetCode.Authoring.Hybrid",
|
||||
"Target": 1
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Build.Classic.EnableHeadlessMode, Unity.Build.Classic"
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Build.Common.PlayerScriptingDefines, Unity.Build",
|
||||
"Defines": [
|
||||
"UNITY_SERVER"
|
||||
]
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Entities.Conversion.ConversionSystemFilterSettings, Unity.Entities.Hybrid",
|
||||
"ExcludedConversionSystemAssemblies": [
|
||||
"GlobalObjectId_V1-1-7a450cf7ca9694b5a8bfa3fd83ec635a-5897886265953266890-0",
|
||||
"GlobalObjectId_V1-1-c52403dffb9bc4f33a799f71eca4ab9a-5897886265953266890-0",
|
||||
"GlobalObjectId_V1-1-8281b45ed5ac44d5b9f06391156a3007-5897886265953266890-0",
|
||||
"GlobalObjectId_V1-1-308a44c6d7c754f2bb0e69df7e894c78-5897886265953266890-0"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 69018010a3ed1485a922ec6aeaa79daf
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 627ef77bce55554428c21a56f59002bd, type: 3}
|
|
@ -1,22 +0,0 @@
|
|||
{
|
||||
"Show": true,
|
||||
"Dependencies": [
|
||||
"GlobalObjectId_V1-1-687ff696e4df441e5931eb81db4d1db0-93214019566545601-0",
|
||||
"GlobalObjectId_V1-1-efd815fb310344e61bf5fa7dc0f06555-93214019566545601-0"
|
||||
],
|
||||
"Components": [
|
||||
{
|
||||
"$type": "Unity.Build.Classic.ClassicBuildProfile, Unity.Build.Classic",
|
||||
"$version": 1,
|
||||
"Platform": "win",
|
||||
"Configuration": 2
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Build.Common.PlayerScriptingDefines, Unity.Build",
|
||||
"Defines": [
|
||||
"ENABLE_HYBRID_RENDERER_V2",
|
||||
"FRONTEND_PLAYER_BUILD"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 07d34a3775a0a9348b6cf58a8b6daf54
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 627ef77bce55554428c21a56f59002bd, type: 3}
|
|
@ -1,33 +0,0 @@
|
|||
{
|
||||
"Show": true,
|
||||
"Dependencies": [
|
||||
"GlobalObjectId_V1-1-687ff696e4df441e5931eb81db4d1db0-93214019566545601-0",
|
||||
"GlobalObjectId_V1-1-efd815fb310344e61bf5fa7dc0f06555-93214019566545601-0"
|
||||
],
|
||||
"Components": [
|
||||
{
|
||||
"$type": "Unity.Build.Classic.ClassicScriptingSettings, Unity.Build.Classic",
|
||||
"ScriptingBackend": 1,
|
||||
"Il2CppCompilerConfiguration": 1,
|
||||
"UseIncrementalGC": false
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Build.Classic.ClassicBuildProfile, Unity.Build.Classic",
|
||||
"$version": 1,
|
||||
"Platform": "ios",
|
||||
"Configuration": 2
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Build.Classic.ClassicCodeStrippingOptions, Unity.Build.Classic",
|
||||
"StripEngineCode": false,
|
||||
"ManagedStrippingLevel": 1
|
||||
},
|
||||
{
|
||||
"$type": "Unity.Build.Common.PlayerScriptingDefines, Unity.Build",
|
||||
"Defines": [
|
||||
"ENABLE_HYBRID_RENDERER_V2",
|
||||
"FRONTEND_PLAYER_BUILD"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bc4e25bd6a15f40c69fd55121e903c05
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 627ef77bce55554428c21a56f59002bd, type: 3}
|
|
@ -0,0 +1,17 @@
|
|||
# global config file must have the is_global=true present in the first line.
|
||||
is_global=true
|
||||
|
||||
# enabe/disable the Netcode source generator files output in the temp folder. 0 disable, empty or 1 enable.
|
||||
unity.netcode.sourcegenerator.write_files_to_disk=0
|
||||
|
||||
# enable/disable Netcode source generator logs output to the Temp/NetCodeGenerated/sourcegenerato.log file. 0 disable, empty or 1 enable.
|
||||
unity.netcode.sourcegenerator.write_logs_to_disk=0
|
||||
|
||||
# the default Netcode source generator logging level is error.
|
||||
unity.netcode.sourcegenerator.logging_level=error
|
||||
|
||||
# Netcode source generator will emit profile timings. 0 disable, empty or 1 enable.
|
||||
unity.netcode.sourcegenerator.emit_timing=0
|
||||
|
||||
# Netcode source generator will wait attaching the debugger before processing the specified assembly (or all if the value is empty). Keep commented to avoid the debugger to attach
|
||||
#unity.netcode.sourcegenerator.attach_debugger=ASSEMBLY_NAME_OR_EMPTY
|
|
@ -1,6 +1,6 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 89eead9c79a674e97a92f7769eaedc59
|
||||
AssemblyDefinitionImporter:
|
||||
guid: 438ceb2db4b2d4bb89ca202571b8606d
|
||||
RoslynAnalyzerConfigImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
|
@ -1,28 +0,0 @@
|
|||
# Netcode for Entities samples
|
||||
|
||||
- [Netcode for Entities Manual](https://docs.unity3d.com/Packages/com.unity.netcode@latest)
|
||||
- [Netcode forums](https://forum.unity.com/forums/dots-netcode.425/)
|
||||
|
||||
### Asteroids
|
||||
|
||||
A small game featuring the Netcode for Entities Package features.
|
||||
|
||||
### NetCube
|
||||
|
||||
A small sample featuring the Netcode for Entities Package basic features, this is the sample used in the __Getting Started__ guide in the manual.
|
||||
|
||||
### PredictionSwitching
|
||||
|
||||
A sample using predicted physics based on Unity Physics. The sample is predicting all objects close the the player but not objects far away. The color of the spheres will change to indicate if they are predicted or interpolated.
|
||||
|
||||
### PlayerList
|
||||
|
||||
A sample which shows how to maintain a list of connected players by using the RPC feature.
|
||||
|
||||
### HelloNetcode
|
||||
|
||||
This is a suite of samples which aim to be small, simple and show features in isolation. Later samples then re-use earlier ones so it's simpler to see exactly what's being shown and similar routines (like connecting, going in game etc) don't need to be repeated. This way samples can also build on top of each other and become more complex. They are split into Basic, Intermediate and Advanced areas depending on level of complexity and how commonly the things shown are needed in a normal project.
|
||||
|
||||
## Building
|
||||
|
||||
Building is done via the **Build Settings** window as with normal Unity builds. Make sure you have the appropriate player type set int he _Entities->Build_ tab in the **Player Settings**. To build the whole sample scene list (with frontend) as a client/server build select the **ClientAndServer** as the *Netcode client target*. To make a client only build select **Client**. For a server only build switch to the **Dedicated Server** platform target. This will automatically use the **Server** configuration.
|
|
@ -0,0 +1,15 @@
|
|||
using UnityEngine;
|
||||
using Unity.Entities;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class ScoreTrackerAuthoring : MonoBehaviour
|
||||
{
|
||||
class Baker : Baker<ScoreTrackerAuthoring>
|
||||
{
|
||||
public override void Bake(ScoreTrackerAuthoring authoring)
|
||||
{
|
||||
var entity = GetEntity(TransformUsageFlags.ManualOverride); // So it's not included in the relevancy radius check, as we default Score to always be relevant by default.
|
||||
AddComponent(entity, new AsteroidScore());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bbd786c2e47c4d9d916c41b6d613bedf
|
||||
timeCreated: 1704924341
|
|
@ -0,0 +1,17 @@
|
|||
using Unity.Entities;
|
||||
using Unity.NetCode;
|
||||
using UnityEngine;
|
||||
|
||||
[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)]
|
||||
public partial class SetAlwaysRelevantSystem : SystemBase
|
||||
{
|
||||
protected override void OnCreate()
|
||||
{
|
||||
var relevancy = SystemAPI.GetSingletonRW<GhostRelevancy>();
|
||||
// This is set OnCreate but can be updated at runtime as well
|
||||
// You could also add an AlwaysRelevant component to mark entities at authoring time too
|
||||
relevancy.ValueRW.DefaultRelevancyQuery = GetEntityQuery(typeof(AsteroidScore));
|
||||
}
|
||||
|
||||
protected override void OnUpdate() { }
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b95edb1f46594018ad5b79019be30c23
|
||||
timeCreated: 1704923615
|
|
@ -84,12 +84,15 @@ namespace Asteroids.Client
|
|||
{
|
||||
if (SystemAPI.TryGetSingleton<CommandTarget>(out var commandTarget))
|
||||
{
|
||||
if (commandTarget.targetEntity == Entity.Null ||
|
||||
!EntityManager.HasComponent<ShipCommandData>(commandTarget.targetEntity))
|
||||
if (commandTarget.targetEntity == Entity.Null)
|
||||
{
|
||||
// No ghosts are spawned, so create a placeholder struct to store the commands in
|
||||
var ent = EntityManager.CreateEntity();
|
||||
EntityManager.AddBuffer<ShipCommandData>(ent);
|
||||
// No ghosts are spawned, so we need to create a placeholder input component to store commands in.
|
||||
// If the thin client timed out, and reconnected, we need to ensure this is not already created.
|
||||
if (!SystemAPI.TryGetSingletonEntity<ShipCommandData>(out var ent))
|
||||
{
|
||||
ent = EntityManager.CreateEntity();
|
||||
EntityManager.AddBuffer<ShipCommandData>(ent);
|
||||
}
|
||||
SystemAPI.SetSingleton(new CommandTarget{targetEntity = ent});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c8a873b0609d413da434c85e89747b60
|
||||
timeCreated: 1704928110
|
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
using Unity.Entities;
|
||||
using Unity.NetCode;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Samples.Asteroids.Client.UI
|
||||
{
|
||||
public class ScoreUI : MonoBehaviour
|
||||
{
|
||||
Text m_ScoreTextToUpdate;
|
||||
EntityQuery m_ScoreQuery;
|
||||
|
||||
void Start()
|
||||
{
|
||||
m_ScoreTextToUpdate = GetComponent<Text>();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (ClientServerBootstrap.ClientWorld == null)
|
||||
return;
|
||||
if (m_ScoreQuery == default)
|
||||
m_ScoreQuery = ClientServerBootstrap.ClientWorld.EntityManager.CreateEntityQuery(typeof(AsteroidScore));
|
||||
if (m_ScoreQuery.IsEmpty)
|
||||
return;
|
||||
var score = m_ScoreQuery.GetSingleton<AsteroidScore>().Value;
|
||||
m_ScoreTextToUpdate.text = "Score: " + score;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c9782b8d61f5475d8650cebbde4b409f
|
||||
timeCreated: 1704928119
|
|
@ -1,34 +0,0 @@
|
|||
{
|
||||
"name": "Asteroids",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"Asteroids.Server",
|
||||
"Bootstrap",
|
||||
"Unity.Burst",
|
||||
"Unity.Entities",
|
||||
"Unity.Mathematics",
|
||||
"Unity.NetCode",
|
||||
"Unity.Networking.Transport",
|
||||
"Unity.Platforms.RunLoop",
|
||||
"Unity.Platforms.Common",
|
||||
"Unity.Scenes",
|
||||
"Unity.Runtime.UnityInstance",
|
||||
"Unity.Runtime.EntryPoint",
|
||||
"Unity.Tiny.IO",
|
||||
"Configuration",
|
||||
"SamplesCommon.Mixed",
|
||||
"Unity.Logging",
|
||||
"Unity.Collections"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [
|
||||
"UNITY_DOTS_ENTRYPOINT"
|
||||
],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
#if UNITY_DOTSRUNTIME
|
||||
using Unity.Platforms;
|
||||
using Unity.Runtime;
|
||||
using Unity.Runtime.EntryPoint;
|
||||
using Unity.Logging;
|
||||
|
||||
namespace DOTSRuntime.Server
|
||||
{
|
||||
public class ServerMain
|
||||
{
|
||||
public static void Main()
|
||||
{
|
||||
Program.Initialize();
|
||||
var unity = UnityInstance.Initialize();
|
||||
|
||||
TempMemoryScope.EnterScope();
|
||||
Unity.Logging.DefaultSettings.Initialize();
|
||||
Log.Info("Logging initialized...");
|
||||
TempMemoryScope.ExitScope();
|
||||
|
||||
unity.OnTick = (double timestampInSeconds) =>
|
||||
{
|
||||
UnityInstance.UpdatePreFrame();
|
||||
Unity.Logging.DefaultSettings.UpdateFunction();
|
||||
var shouldContinue = unity.Update(timestampInSeconds);
|
||||
UnityInstance.UpdatePostFrame(shouldContinue);
|
||||
|
||||
return shouldContinue;
|
||||
};
|
||||
PlatformEvents.OnQuit += (sender, evt) =>
|
||||
{
|
||||
Log.Info("Application is shutting down...");
|
||||
unity.Deinitialize();
|
||||
Unity.Logging.Internal.LoggerManager.FlushAll();
|
||||
Program.Shutdown();
|
||||
};
|
||||
RunLoop.EnterMainLoop(unity.OnTick);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -1,4 +1,3 @@
|
|||
using AOT;
|
||||
using Unity.Burst;
|
||||
using Unity.Burst.Intrinsics;
|
||||
using Unity.Collections;
|
||||
|
@ -23,7 +22,7 @@ public struct RpcLevelLoaded : IComponentData, IRpcCommandSerializer<RpcLevelLoa
|
|||
}
|
||||
|
||||
[BurstCompile(DisableDirectCall = true)]
|
||||
[MonoPInvokeCallback(typeof(RpcExecutor.ExecuteDelegate))]
|
||||
[AOT.MonoPInvokeCallback(typeof(RpcExecutor.ExecuteDelegate))]
|
||||
private static void InvokeExecute(ref RpcExecutor.Parameters parameters)
|
||||
{
|
||||
var rpcData = default(RpcLevelLoaded);
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
using Unity.Entities;
|
||||
using Unity.NetCode;
|
||||
using UnityEngine;
|
||||
|
||||
public struct AsteroidScore : IComponentData
|
||||
{
|
||||
[GhostField] public int Value;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7662c530971f45df8fd9ec535d44d9a1
|
||||
timeCreated: 1704924454
|
|
@ -40,6 +40,9 @@ public struct LevelComponent : IComponentData
|
|||
[UnityEngine.SerializeField] private byte _enableGhostImportanceScaling;
|
||||
public bool enableGhostImportanceScaling => _enableGhostImportanceScaling != 0;
|
||||
|
||||
[UnityEngine.SerializeField] private byte _useBatchScalingFunction;
|
||||
public bool useBatchScalingFunction => _useBatchScalingFunction != 0;
|
||||
|
||||
public static LevelComponent Default = new LevelComponent
|
||||
{
|
||||
levelWidth = 2048,
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &1525771447942938581
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 3563239003391643041}
|
||||
- component: {fileID: 2744348672411674421}
|
||||
- component: {fileID: 8151184371318657797}
|
||||
- component: {fileID: 4477279557710362359}
|
||||
m_Layer: 0
|
||||
m_Name: ScoreTracker
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &3563239003391643041
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1525771447942938581}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 405.97098, y: 156.42908, 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 &2744348672411674421
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1525771447942938581}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: bbd786c2e47c4d9d916c41b6d613bedf, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!114 &8151184371318657797
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1525771447942938581}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: c16549610bfe4458aa9389201d072bb6, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!114 &4477279557710362359
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1525771447942938581}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 7c79d771cedb4794bf100ce60df5f764, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
DefaultGhostMode: 1
|
||||
SupportedGhostModes: 2
|
||||
OptimizationMode: 0
|
||||
Importance: 1
|
||||
prefabId:
|
||||
HasOwner: 0
|
||||
SupportAutoCommandTarget: 1
|
||||
TrackInterpolationDelay: 0
|
||||
GhostGroup: 0
|
||||
UsePreSerialization: 1
|
|
@ -1,6 +1,6 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ba70763071fb74d6ea02dd2c0dd614b6
|
||||
TextScriptImporter:
|
||||
guid: f997563c14c5b441a8f27a57be296294
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
|
@ -27,12 +27,12 @@ namespace Asteroids.Server
|
|||
float m_AsteroidRadius;
|
||||
float m_ShipRadius;
|
||||
|
||||
private NativeReference<Random> randomReference;
|
||||
ComponentLookup<PlayerStateComponentData> playerStateFromEntity;
|
||||
ComponentLookup<CommandTarget> commandTargetFromEntity;
|
||||
ComponentLookup<NetworkId> networkIdFromEntity;
|
||||
ComponentLookup<LocalTransform> localTransformLookup;
|
||||
|
||||
[BurstCompile]
|
||||
public void OnCreate(ref SystemState state)
|
||||
{
|
||||
var builder = new EntityQueryBuilder(Allocator.Temp).WithAll<LocalTransform, ShipStateComponentData>();
|
||||
|
@ -63,12 +63,24 @@ namespace Asteroids.Server
|
|||
state.RequireForUpdate(m_LevelQuery);
|
||||
state.RequireForUpdate<AsteroidsSpawner>();
|
||||
|
||||
// Ensure every random is seeded uniquely (not Burst compatible)...
|
||||
// AND that the random feedbacks into itself, ensuring better quality randomness for Asteroid spawns.
|
||||
var fileTimeUtc = System.DateTime.UtcNow.ToFileTimeUtc();
|
||||
randomReference = new NativeReference<Random>(Random.CreateFromIndex((uint) fileTimeUtc), Allocator.Persistent);
|
||||
|
||||
playerStateFromEntity = state.GetComponentLookup<PlayerStateComponentData>();
|
||||
commandTargetFromEntity = state.GetComponentLookup<CommandTarget>();
|
||||
networkIdFromEntity = state.GetComponentLookup<NetworkId>();
|
||||
localTransformLookup = state.GetComponentLookup<LocalTransform>(true);
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public void OnDestroy(ref SystemState state)
|
||||
{
|
||||
randomReference.Dispose();
|
||||
// Others are disposed automatically.
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public void OnUpdate(ref SystemState state)
|
||||
{
|
||||
|
@ -132,7 +144,6 @@ namespace Asteroids.Server
|
|||
state.Dependency = JobHandle.CombineDependencies(state.Dependency, combinedDependencies);
|
||||
|
||||
var tick = SystemAPI.GetSingleton<NetworkTime>().ServerTick;
|
||||
var random = new Random(tick.SerializedData);
|
||||
|
||||
SystemAPI.TryGetSingleton<ClientServerTickRate>(out var tickRate);
|
||||
tickRate.ResolveDefaults();
|
||||
|
@ -165,7 +176,7 @@ namespace Asteroids.Server
|
|||
dynamicAsteroidEntities = dynamicAsteroidEntities,
|
||||
staticAsteroidEntities = staticAsteroidEntities,
|
||||
level = level,
|
||||
random = random,
|
||||
random = randomReference,
|
||||
tick = tick,
|
||||
shipPrefab = m_ShipPrefab,
|
||||
fixedDeltaTime = fixedDeltaTime,
|
||||
|
@ -183,7 +194,7 @@ namespace Asteroids.Server
|
|||
shipTransformsList = shipTransformsList,
|
||||
localTransformLookup = localTransformLookup,
|
||||
level = level,
|
||||
random = random,
|
||||
random = randomReference,
|
||||
tick = tick,
|
||||
asteroidPrefab = m_AsteroidPrefab,
|
||||
asteroidLevelPadding = asteroidLevelPadding,
|
||||
|
@ -207,6 +218,7 @@ namespace Asteroids.Server
|
|||
}
|
||||
|
||||
[BurstCompile]
|
||||
[WithAll(typeof(PlayerSpawnRequest))]
|
||||
internal partial struct SpawnPlayerShips : IJobEntity
|
||||
{
|
||||
public EntityCommandBuffer ecb;
|
||||
|
@ -221,7 +233,7 @@ namespace Asteroids.Server
|
|||
[ReadOnly] public NativeList<Entity> staticAsteroidEntities;
|
||||
[ReadOnly] public NativeList<LevelComponent> level;
|
||||
|
||||
public Random random;
|
||||
public NativeReference<Random> random;
|
||||
public NetworkTick tick;
|
||||
public Entity shipPrefab;
|
||||
public float fixedDeltaTime;
|
||||
|
@ -229,7 +241,7 @@ namespace Asteroids.Server
|
|||
public float minShipAsteroidSpawnDistance;
|
||||
public float minShipToShipSpawnDistance;
|
||||
|
||||
void Execute(Entity entity, in PlayerSpawnRequest request, in ReceiveRpcCommandRequest requestSource)
|
||||
void Execute(Entity entity, in ReceiveRpcCommandRequest requestSource)
|
||||
{
|
||||
// Destroy the spawn request:
|
||||
ecb.DestroyEntity(entity);
|
||||
|
@ -243,7 +255,9 @@ namespace Asteroids.Server
|
|||
|
||||
// Try find a random spawn position for the Ship that isn't near another player.
|
||||
// Don't allow failure though, just take a "bad" position instead.
|
||||
TryFindSpawnPos(ref random, shipTransforms.AsArray(), level[0], shipLevelPadding, minShipToShipSpawnDistance, out var validShipPos);
|
||||
var rand = random.Value;
|
||||
TryFindSpawnPos(ref rand, shipTransforms.AsArray(), level[0], shipLevelPadding, minShipToShipSpawnDistance, out var validShipPos);
|
||||
random.Value = rand;
|
||||
|
||||
// Instantiate ship:
|
||||
var shipEntity = ecb.Instantiate(shipPrefab);
|
||||
|
@ -293,7 +307,7 @@ namespace Asteroids.Server
|
|||
[ReadOnly] public ComponentLookup<LocalTransform> localTransformLookup;
|
||||
[ReadOnly] public NativeList<LevelComponent> level;
|
||||
|
||||
public Random random;
|
||||
public NativeReference<Random> random;
|
||||
public NetworkTick tick;
|
||||
public Entity asteroidPrefab;
|
||||
public float asteroidLevelPadding;
|
||||
|
@ -305,15 +319,16 @@ namespace Asteroids.Server
|
|||
public void Execute()
|
||||
{
|
||||
var currentNumAsteroids = staticAsteroidEntities.Length + dynamicAsteroidEntities.Length;
|
||||
var rand = random.Value;
|
||||
for (int i = currentNumAsteroids; i < numAsteroids; ++i)
|
||||
{
|
||||
// Spawn asteroid at random pos, assuming we can find a valid one that isn't under a ship.
|
||||
// Don't treat this as an error (because it may happen occasionally by chance, or if the map is packed with ships).
|
||||
// Instead, just stop attempting to spawn any more this frame.
|
||||
if (!TryFindSpawnPos(ref random, shipTransformsList.AsArray(), level[0], asteroidLevelPadding, minShipAsteroidSpawnDistance, out var validAsteroidPos))
|
||||
return;
|
||||
if (!TryFindSpawnPos(ref rand, shipTransformsList.AsArray(), level[0], asteroidLevelPadding, minShipAsteroidSpawnDistance, out var validAsteroidPos))
|
||||
break;
|
||||
|
||||
var angle = random.NextFloat(-0.0f, 359.0f);
|
||||
var angle = rand.NextFloat(-0.0f, 359.0f);
|
||||
//@ronald. this is necessary since the meshes are not backing the correct scaling factor
|
||||
var originalScale = localTransformLookup[asteroidPrefab].Scale;
|
||||
var trans = LocalTransform.FromPositionRotationScale(
|
||||
|
@ -335,6 +350,8 @@ namespace Asteroids.Server
|
|||
else
|
||||
ecb.SetComponent(e, vel);
|
||||
}
|
||||
|
||||
random.Value = rand;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,8 +3,10 @@ using Unity.Burst;
|
|||
using Unity.Burst.Intrinsics;
|
||||
using Unity.Entities;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Mathematics;
|
||||
using Unity.Jobs;
|
||||
using Unity.Jobs.LowLevel.Unsafe;
|
||||
using Unity.Transforms;
|
||||
using Unity.NetCode;
|
||||
|
||||
|
@ -80,6 +82,8 @@ namespace Asteroids.Server
|
|||
|
||||
commandTarget = state.GetComponentLookup<CommandTarget>();
|
||||
linkedEntityGroupFromEntity = state.GetBufferLookup<LinkedEntityGroup>();
|
||||
|
||||
state.RequireForUpdate<AsteroidScore>();
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
|
@ -102,6 +106,8 @@ namespace Asteroids.Server
|
|||
[ReadOnly] public EntityTypeHandle entityType;
|
||||
|
||||
[ReadOnly] public NativeList<LevelComponent> level;
|
||||
[NativeSetThreadIndex] public int ThreadIndex;
|
||||
[NativeDisableParallelForRestriction] public NativeArray<int> asteroidDestructCounter;
|
||||
public NetworkTick tick;
|
||||
public float fixedDeltaTime;
|
||||
public void Execute(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask)
|
||||
|
@ -163,6 +169,7 @@ namespace Asteroids.Server
|
|||
if (Intersect(firstRadius, secondRadius, firstPos, secondPos))
|
||||
{
|
||||
commandBuffer.DestroyEntity(unfilteredChunkIndex, asteroidEntity);
|
||||
asteroidDestructCounter[ThreadIndex]++;
|
||||
|
||||
if(level[0].bulletsDestroyedOnContact)
|
||||
commandBuffer.DestroyEntity(unfilteredChunkIndex, bulletEntities[bullet]);
|
||||
|
@ -335,6 +342,26 @@ namespace Asteroids.Server
|
|||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
internal struct GatherAsteroidDestructCounter : IJob
|
||||
{
|
||||
[ReadOnly] public NativeArray<int> asteroidDestructCounter;
|
||||
public EntityCommandBuffer commandBuffer;
|
||||
[ReadOnly] public int currentScore;
|
||||
[ReadOnly] public Entity scoreSingleton;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
int total = currentScore;
|
||||
for (int i = 1; i < asteroidDestructCounter.Length; ++i)
|
||||
{
|
||||
total += asteroidDestructCounter[i];
|
||||
}
|
||||
|
||||
commandBuffer.SetComponent(scoreSingleton, new AsteroidScore { Value = total });
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public void OnUpdate(ref SystemState state)
|
||||
{
|
||||
|
@ -361,6 +388,11 @@ namespace Asteroids.Server
|
|||
|
||||
commandTarget.Update(ref state);
|
||||
linkedEntityGroupFromEntity.Update(ref state);
|
||||
|
||||
int chunkCount = asteroidQuery.CalculateChunkCountWithoutFiltering();
|
||||
int maxThreadCount = JobsUtility.ThreadIndexCount;
|
||||
|
||||
var asteroidDestroyCounter = CollectionHelper.CreateNativeArray<int>(maxThreadCount, Allocator.TempJob);
|
||||
|
||||
var asteroidJob = new DestroyAsteroidJob
|
||||
{
|
||||
|
@ -369,6 +401,7 @@ namespace Asteroids.Server
|
|||
bulletAgeType = bulletAgeType,
|
||||
|
||||
transformType = transformType,
|
||||
asteroidDestructCounter = asteroidDestroyCounter,
|
||||
|
||||
staticAsteroidType = staticAsteroidType,
|
||||
sphereType = sphereType,
|
||||
|
@ -407,14 +440,26 @@ namespace Asteroids.Server
|
|||
var h1 = asteroidJob.ScheduleParallel(asteroidQuery, asteroidDep);
|
||||
var h2 = shipJob.ScheduleParallel(shipQuery, shipDep);
|
||||
|
||||
var handle = JobHandle.CombineDependencies(h1, h2);
|
||||
|
||||
var cleanupShipJob = new ClearShipPointerJob
|
||||
{
|
||||
playerClearQueue = playerClearQueue,
|
||||
commandTarget = commandTarget,
|
||||
linkedEntityGroupFromEntity = linkedEntityGroupFromEntity
|
||||
};
|
||||
|
||||
var asteroidScore = SystemAPI.GetSingleton<AsteroidScore>();
|
||||
|
||||
var updateScore = new GatherAsteroidDestructCounter
|
||||
{
|
||||
commandBuffer = SystemAPI.GetSingleton<EndSimulationEntityCommandBufferSystem.Singleton>().CreateCommandBuffer(state.WorldUnmanaged),
|
||||
asteroidDestructCounter = asteroidDestroyCounter,
|
||||
currentScore = asteroidScore.Value,
|
||||
scoreSingleton = SystemAPI.GetSingletonEntity<AsteroidScore>()
|
||||
};
|
||||
var scoreHandle = updateScore.Schedule(dependsOn: h1);
|
||||
var cleanupHandle = asteroidDestroyCounter.Dispose(scoreHandle);
|
||||
|
||||
var handle = JobHandle.CombineDependencies(h1, h2, cleanupHandle);
|
||||
state.Dependency = JobHandle.CombineDependencies(cleanupShipJob.Schedule(h2), handle);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ namespace Asteroids.Server
|
|||
{
|
||||
private EntityQuery m_LevelGroup;
|
||||
private PortableFunctionPointer<GhostImportance.ScaleImportanceDelegate> m_ScaleFunctionPointer;
|
||||
private PortableFunctionPointer<GhostImportance.BatchScaleImportanceDelegate> m_BatchScaleFunction;
|
||||
|
||||
public void OnCreate(ref SystemState state)
|
||||
{
|
||||
|
@ -26,6 +27,7 @@ namespace Asteroids.Server
|
|||
|
||||
state.RequireForUpdate<ServerSettings>();
|
||||
m_ScaleFunctionPointer = GhostDistanceImportance.ScaleFunctionPointer;
|
||||
m_BatchScaleFunction = GhostDistanceImportance.BatchScaleFunctionPointer;
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
|
@ -56,6 +58,7 @@ namespace Asteroids.Server
|
|||
});
|
||||
state.EntityManager.AddComponentData(gridSingleton, new GhostImportance
|
||||
{
|
||||
BatchScaleImportanceFunction = settings.levelData.useBatchScalingFunction ? m_BatchScaleFunction: default,
|
||||
ScaleImportanceFunction = m_ScaleFunctionPointer,
|
||||
GhostConnectionComponentType = ComponentType.ReadOnly<GhostConnectionPosition>(),
|
||||
GhostImportanceDataType = ComponentType.ReadOnly<GhostDistanceData>(),
|
||||
|
|
|
@ -20,7 +20,6 @@ GameObject:
|
|||
- component: {fileID: -6897639722122874107}
|
||||
- component: {fileID: -5231493766772932575}
|
||||
- component: {fileID: 5941306285269308673}
|
||||
- component: {fileID: -4792171066699290668}
|
||||
- component: {fileID: -4874576295782791584}
|
||||
- component: {fileID: 4277607168032350576}
|
||||
m_Layer: 0
|
||||
|
@ -247,19 +246,6 @@ MeshFilter:
|
|||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 700954011552825696}
|
||||
m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
|
||||
--- !u!114 &-4792171066699290668
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 700954011552825696}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 54b6467bcd530cd4d809fae70ea0ca9d, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
color: {r: 0, g: 0, b: 0, a: 0}
|
||||
--- !u!114 &-4874576295782791584
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 40ce81ce095fd4c4eaef9cb266786fb4
|
||||
guid: ac23f599aae3a47c7893493141f25d33
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
|
@ -0,0 +1,86 @@
|
|||
using Unity.Entities;
|
||||
using Unity.NetCode;
|
||||
|
||||
namespace Samples.CustomChunkSerializer
|
||||
{
|
||||
[GhostEnabledBit]
|
||||
[GhostComponent(SendDataForChildEntity = true)]
|
||||
public struct IntCompo1 : IComponentData, IEnableableComponent
|
||||
{
|
||||
[GhostField] public int Value;
|
||||
}
|
||||
|
||||
[GhostEnabledBit]
|
||||
[GhostComponent(SendDataForChildEntity = true)]
|
||||
public struct IntCompo2 : IComponentData, IEnableableComponent
|
||||
{
|
||||
[GhostField] public int Value;
|
||||
}
|
||||
|
||||
[GhostEnabledBit]
|
||||
[GhostComponent(SendDataForChildEntity = true)]
|
||||
public struct IntCompo3 : IComponentData, IEnableableComponent
|
||||
{
|
||||
[GhostField] public int Value;
|
||||
}
|
||||
|
||||
[GhostEnabledBit]
|
||||
[GhostComponent(SendDataForChildEntity = true)]
|
||||
public struct FloatCompo1 : IComponentData, IEnableableComponent
|
||||
{
|
||||
[GhostField(Quantization = 1000)] public float Value;
|
||||
}
|
||||
|
||||
[GhostEnabledBit]
|
||||
[GhostComponent(SendDataForChildEntity = true)]
|
||||
public struct FloatCompo2 : IComponentData, IEnableableComponent
|
||||
{
|
||||
[GhostField(Quantization = 1000)] public float Value;
|
||||
}
|
||||
|
||||
[GhostEnabledBit]
|
||||
[GhostComponent(SendDataForChildEntity = true)]
|
||||
public struct FloatCompo3 : IComponentData, IEnableableComponent
|
||||
{
|
||||
[GhostField(Quantization = 1000)] public float Value;
|
||||
}
|
||||
|
||||
[GhostComponent(SendDataForChildEntity = true)]
|
||||
public struct Buf1 : IBufferElementData
|
||||
{
|
||||
[GhostField] public int Value;
|
||||
}
|
||||
|
||||
[GhostComponent(SendDataForChildEntity = true)]
|
||||
public struct Buf2 : IBufferElementData
|
||||
{
|
||||
[GhostField] public float Value;
|
||||
}
|
||||
|
||||
[GhostComponent(SendDataForChildEntity = true)]
|
||||
public struct Buf3 : IBufferElementData
|
||||
{
|
||||
[GhostField] public int Value1;
|
||||
[GhostField] public int Value2;
|
||||
[GhostField] public float Value3;
|
||||
[GhostField] public float Value4;
|
||||
}
|
||||
|
||||
[GhostComponent(SendTypeOptimization = GhostSendType.OnlyInterpolatedClients)]
|
||||
public struct InterpolatedOnlyComp : IComponentData
|
||||
{
|
||||
[GhostField] public int Value1;
|
||||
[GhostField] public int Value2;
|
||||
[GhostField] public int Value3;
|
||||
[GhostField] public int Value4;
|
||||
}
|
||||
|
||||
[GhostComponent(OwnerSendType = SendToOwnerType.SendToNonOwner)]
|
||||
public struct OwnerOnlyComp : IComponentData
|
||||
{
|
||||
[GhostField] public int Value1;
|
||||
[GhostField] public int Value2;
|
||||
[GhostField] public int Value3;
|
||||
[GhostField] public int Value4;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b7730bbe03dd347f688216bd8ec25b05
|
||||
guid: 741840051872d4ba6824aa3e7f449ccc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
|
@ -0,0 +1,367 @@
|
|||
using System;
|
||||
using AOT;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Entities;
|
||||
using Unity.NetCode;
|
||||
using Unity.NetCode.LowLevel.Unsafe;
|
||||
using Unity.Transforms;
|
||||
using UnityEngine.Assertions;
|
||||
|
||||
namespace Samples.CustomChunkSerializer
|
||||
{
|
||||
[BurstCompile]
|
||||
public struct ChunkSerializer
|
||||
{
|
||||
//About the snapshot buffer memory layout
|
||||
//The snapshot buffer contains entries in this format
|
||||
// [tick][ent1 data][ent2 data] ... [entN data]
|
||||
// the data has the following layout:
|
||||
// uint Tick
|
||||
// 4 bytes aligned change mask bits
|
||||
// (optional)
|
||||
// 4 bytes aligned enable bits state
|
||||
// padding (to 16 bytes)
|
||||
// component1 (aligned to 16 byte boundary)
|
||||
// component2 (aligned to 16 byte boundary)
|
||||
// ..
|
||||
// componentN (aligned to 16 byte boundary)
|
||||
|
||||
//About the bitsize memory layout.
|
||||
//The bitStartAndSize contains the start uint and bit len of the ghost data.
|
||||
//Has the following layout
|
||||
// [Component1 ][Component2
|
||||
// |ent1 start|ent1 len|..|entN start|entN len||ent1 start|ent1 len|..|entN start|entN len|
|
||||
//
|
||||
// The stride is NumComponent * (endIndex - startIndex), where endIndex and startIndex are the first and last
|
||||
// relevant entity index in the chunk.
|
||||
|
||||
public static PortableFunctionPointer<GhostPrefabCustomSerializer.CollectComponentDelegate> CollectComponentFunc =
|
||||
new PortableFunctionPointer<GhostPrefabCustomSerializer.CollectComponentDelegate>(CollectComponents);
|
||||
|
||||
public static PortableFunctionPointer<GhostPrefabCustomSerializer.ChunkSerializerDelegate> SerializerFunc =
|
||||
new PortableFunctionPointer<GhostPrefabCustomSerializer.ChunkSerializerDelegate>(SerializeChunk);
|
||||
|
||||
public static PortableFunctionPointer<GhostPrefabCustomSerializer.ChunkPreserializeDelegate> PreSerializerFunc =
|
||||
new PortableFunctionPointer<GhostPrefabCustomSerializer.ChunkPreserializeDelegate>(PreSerializeChunk);
|
||||
|
||||
//Custom method to register the component types in a specific order, so that the chunk serializer can be written
|
||||
//way more easily.
|
||||
[BurstCompile(DisableDirectCall = true)]
|
||||
[MonoPInvokeCallback(typeof(GhostPrefabCustomSerializer.CollectComponentDelegate))]
|
||||
public static void CollectComponents(IntPtr componentTypesPtr, IntPtr componentCountPtr)
|
||||
{
|
||||
ref var componentTypes = ref GhostComponentSerializer.TypeCast<NativeList<ComponentType>>(componentTypesPtr);
|
||||
ref var componentCount = ref GhostComponentSerializer.TypeCast<NativeArray<int>>(componentCountPtr);
|
||||
//Root
|
||||
componentTypes.Add(ComponentType.ReadWrite<GhostOwner>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<LocalTransform>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<IntCompo1>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<IntCompo2>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<IntCompo3>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<FloatCompo1>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<FloatCompo2>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<FloatCompo3>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<InterpolatedOnlyComp>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<OwnerOnlyComp>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<Buf1>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<Buf2>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<Buf3>());
|
||||
componentCount[0] = 13;
|
||||
//Child 1
|
||||
componentTypes.Add(ComponentType.ReadWrite<IntCompo1>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<FloatCompo1>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<Buf1>());
|
||||
componentCount[1] = 3;
|
||||
//Child 2
|
||||
componentTypes.Add(ComponentType.ReadWrite<IntCompo2>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<FloatCompo2>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<Buf2>());
|
||||
componentCount[2] = 3;
|
||||
}
|
||||
|
||||
[BurstCompile(DisableDirectCall = true)]
|
||||
[MonoPInvokeCallback(typeof(GhostPrefabCustomSerializer.CollectComponentDelegate))]
|
||||
private static unsafe void PreSerializeChunk(in ArchetypeChunk chunk, in GhostCollectionPrefabSerializer typeData,
|
||||
in DynamicBuffer<GhostCollectionComponentIndex> componentIndices,
|
||||
ref GhostPrefabCustomSerializer.Context context)
|
||||
{
|
||||
var indices = (GhostCollectionComponentIndex*)componentIndices.GetUnsafeReadOnlyPtr() + typeData.FirstComponent;
|
||||
CopyComponentsToSnapshot(chunk, ref context, typeData, indices);
|
||||
}
|
||||
|
||||
const int BaselinesPerEntity = 4;
|
||||
//Assumptions made:
|
||||
// - components are never removed (so we not check for presence)
|
||||
[BurstCompile(DisableDirectCall = true)]
|
||||
[MonoPInvokeCallback(typeof(GhostPrefabCustomSerializer.ChunkSerializerDelegate))]
|
||||
private static unsafe void SerializeChunk(ref ArchetypeChunk chunk,
|
||||
in GhostCollectionPrefabSerializer typeData,
|
||||
in DynamicBuffer<GhostCollectionComponentIndex> componentIndices,
|
||||
ref GhostPrefabCustomSerializer.Context context,
|
||||
ref DataStreamWriter tempWriter,
|
||||
in StreamCompressionModel compressionModel, ref int lastSerializedEntity)
|
||||
{
|
||||
var baselinesPerEntity = (IntPtr*)context.baselinePerEntityPtr;
|
||||
var sameBaselinePerEntity = (int*)context.sameBaselinePerEntityPtr;
|
||||
int* entityBitAndSize = (int*)context.entityStartBit;
|
||||
var entityCount = context.endIndex - context.startIndex;
|
||||
int* componentBitsSize = entityBitAndSize + 2*entityCount;
|
||||
int compBitSizeStride = 2*entityCount;
|
||||
var indices = (GhostCollectionComponentIndex*)componentIndices.GetUnsafeReadOnlyPtr() + typeData.FirstComponent;
|
||||
if(context.hasPreserializedData == 0)
|
||||
CopyComponentsToSnapshot(chunk, ref context, typeData, indices);
|
||||
|
||||
int* dynamicDataSizePerEntity = (int*)context.dynamicDataSizePerEntityPtr;
|
||||
for (int ent = context.startIndex; ent < context.endIndex; ++ent)
|
||||
{
|
||||
var old = tempWriter;
|
||||
var entOffset = ent - context.startIndex;
|
||||
//Avoid serializing irrelevant entities
|
||||
var sameBaselineCount = sameBaselinePerEntity[entOffset];
|
||||
if (sameBaselineCount < 0)
|
||||
{
|
||||
// This is an irrelevant ghost, do not send . There is no need to reset the
|
||||
//bits size and start bit, because the same check is also done outside.
|
||||
continue;
|
||||
}
|
||||
|
||||
//The writer contains data in a different format in the case of the chunk serializer:
|
||||
//we are serializing on per "entity" directly here.
|
||||
//This give the advantage of being able to early exit without need to serialise other entities if
|
||||
//they don't fit (or at least early exiting after the first one that fails)
|
||||
//Ideally, (this is a second phase), we can now write directly in the real data stream. Right now
|
||||
//this is not possible because we are adding the size of buffers and ghosts data (delta compressed) before
|
||||
//the ghost stream.
|
||||
var snapshotData = context.snapshotDataPtr + entOffset*context.snapshotStride;
|
||||
var changeMaskData = snapshotData + sizeof(int);
|
||||
var currentWrittenBits = tempWriter.LengthInBits;
|
||||
var baseline0Ptr = baselinesPerEntity[BaselinesPerEntity*entOffset];
|
||||
var baseline1Ptr = baselinesPerEntity[BaselinesPerEntity*entOffset + 1];
|
||||
var baseline2Ptr = baselinesPerEntity[BaselinesPerEntity*entOffset + 2];
|
||||
//This can an IntPtrZero if there are no buffers of the baseline does not exist
|
||||
var dynamicDataBaselinePtr = baselinesPerEntity[BaselinesPerEntity*entOffset + 3];
|
||||
//This requires to overwrite the snapshot data with all zeros or keep the current predicted baseline (optimal)
|
||||
var ghostSendType = GhostSendType.AllClients;
|
||||
var sendToOwner = SendToOwnerType.All;
|
||||
//the comp bit size already point to the entityBitSize[1] for the first component entry.
|
||||
var compBitSize = componentBitsSize + 2*entOffset + 1;
|
||||
if (typeData.PredictionOwnerOffset != 0)
|
||||
{
|
||||
var isOwner = (context.networkId == *(int*)((byte*)snapshotData + typeData.PredictionOwnerOffset));
|
||||
if (typeData.PartialSendToOwner != 0)
|
||||
sendToOwner = isOwner ? SendToOwnerType.SendToOwner : SendToOwnerType.SendToNonOwner;
|
||||
if (typeData.PartialComponents != 0 && typeData.OwnerPredicted != 0)
|
||||
ghostSendType = isOwner ? GhostSendType.OnlyPredictedClients : GhostSendType.OnlyInterpolatedClients;
|
||||
}
|
||||
if (baseline2Ptr != IntPtr.Zero)
|
||||
{
|
||||
SerializeWithThreeBaselines(snapshotData, context.snapshotOffset, sendToOwner, ghostSendType,
|
||||
indices, ref tempWriter, compressionModel, baseline0Ptr, baseline1Ptr, baseline2Ptr,
|
||||
changeMaskData, context.snapshotDynamicDataPtr, dynamicDataBaselinePtr,
|
||||
ref dynamicDataSizePerEntity[entOffset], compBitSize, compBitSizeStride);
|
||||
}
|
||||
//Single baseline
|
||||
else if (baseline0Ptr != IntPtr.Zero)
|
||||
{
|
||||
SerializeWithSingleBaseline(snapshotData, context.snapshotOffset, sendToOwner, ghostSendType,
|
||||
indices, ref tempWriter, compressionModel, baseline0Ptr,
|
||||
changeMaskData, context.snapshotDynamicDataPtr, dynamicDataBaselinePtr,
|
||||
ref dynamicDataSizePerEntity[entOffset], compBitSize, compBitSizeStride);
|
||||
}
|
||||
//No baseline, we are passing a pointer to a baseline that contains all zero.
|
||||
//The advantage of this is that can be extended, to allow using "initial-value"
|
||||
//optimization, to send the delta in respect the prefab initial data.
|
||||
else
|
||||
{
|
||||
SerializeWithSingleBaseline(snapshotData, context.snapshotOffset, sendToOwner, ghostSendType,
|
||||
indices, ref tempWriter, compressionModel, context.zeroBaseline,
|
||||
changeMaskData, context.snapshotDynamicDataPtr, IntPtr.Zero,
|
||||
ref dynamicDataSizePerEntity[entOffset], compBitSize, compBitSizeStride);
|
||||
}
|
||||
//Count the number of bits for each ghosts.
|
||||
entityBitAndSize[2*entOffset] = currentWrittenBits / 32;
|
||||
entityBitAndSize[2*entOffset+1] = tempWriter.LengthInBits - currentWrittenBits;
|
||||
var missing = 32 - tempWriter.LengthInBits & 31;
|
||||
if (missing < 32)
|
||||
tempWriter.WriteRawBits(0, missing);
|
||||
if (tempWriter.HasFailedWrites)
|
||||
{
|
||||
//If we were able to store at least one entity there is not need to mark the stream
|
||||
//as failed.
|
||||
//Rollback it here and let the outer loop to serialize the full entities.
|
||||
if (entOffset > 0)
|
||||
{
|
||||
tempWriter = old;
|
||||
lastSerializedEntity = ent - 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe void CopyComponentsToSnapshot(ArchetypeChunk chunk,
|
||||
ref GhostPrefabCustomSerializer.Context context,
|
||||
in GhostCollectionPrefabSerializer typeData,
|
||||
GhostCollectionComponentIndex* indices)
|
||||
{
|
||||
var ghostChunkComponentTypesPtr = (DynamicComponentTypeHandle*)context.ghostChunkComponentTypes;
|
||||
|
||||
var maskOffset = 0;
|
||||
var snapshotOffset = context.snapshotOffset;
|
||||
var dynamicSnapshotOffset = context.dynamicDataOffset;
|
||||
var changeMaskUints = GhostComponentSerializer.ChangeMaskArraySizeInUInts(typeData.ChangeMaskBits);
|
||||
var snapshotPtr = context.snapshotDataPtr;
|
||||
var enableBits = (byte*)(snapshotPtr + sizeof(int) + 4*changeMaskUints);
|
||||
|
||||
//ROOT COMPONENTS
|
||||
//GENERATE ONLY THIS
|
||||
new Unity.NetCode.Generated.GhostOwnerGhostComponentSerializer().CopyComponentToSnapshot(chunk, ref context,
|
||||
ghostChunkComponentTypesPtr, indices[0], snapshotPtr, ref snapshotOffset);
|
||||
new Unity.NetCode.Generated.TransformDefaultVariantGhostComponentSerializer().CopyComponentToSnapshot(chunk, ref context,
|
||||
ghostChunkComponentTypesPtr,indices[1], snapshotPtr, ref snapshotOffset);
|
||||
CustomGhostSerializerHelpers.CopyEnableBits(chunk, context.startIndex, context.endIndex, context.snapshotStride,
|
||||
ref ghostChunkComponentTypesPtr[indices[2].ComponentIndex], enableBits, ref maskOffset);
|
||||
new CustomSerializer.Generated.IntCompo1GhostComponentSerializer().CopyComponentToSnapshot(chunk, ref context,
|
||||
ghostChunkComponentTypesPtr, indices[2], snapshotPtr, ref snapshotOffset);
|
||||
CustomGhostSerializerHelpers.CopyEnableBits(chunk, context.startIndex, context.endIndex, context.snapshotStride,
|
||||
ref ghostChunkComponentTypesPtr[indices[3].ComponentIndex], enableBits, ref maskOffset);
|
||||
new CustomSerializer.Generated.IntCompo2GhostComponentSerializer().CopyComponentToSnapshot(chunk, ref context,
|
||||
ghostChunkComponentTypesPtr, indices[3], snapshotPtr, ref snapshotOffset);
|
||||
CustomGhostSerializerHelpers.CopyEnableBits(chunk, context.startIndex, context.endIndex, context.snapshotStride,
|
||||
ref ghostChunkComponentTypesPtr[indices[4].ComponentIndex], enableBits, ref maskOffset);
|
||||
new CustomSerializer.Generated.IntCompo3GhostComponentSerializer().CopyComponentToSnapshot(chunk, ref context,
|
||||
ghostChunkComponentTypesPtr,indices[4], snapshotPtr, ref snapshotOffset);
|
||||
CustomGhostSerializerHelpers.CopyEnableBits(chunk, context.startIndex, context.endIndex, context.snapshotStride,
|
||||
ref ghostChunkComponentTypesPtr[indices[5].ComponentIndex], enableBits, ref maskOffset);
|
||||
new CustomSerializer.Generated.FloatCompo1GhostComponentSerializer().CopyComponentToSnapshot(chunk, ref context,
|
||||
ghostChunkComponentTypesPtr,indices[5], snapshotPtr, ref snapshotOffset);
|
||||
CustomGhostSerializerHelpers.CopyEnableBits(chunk, context.startIndex, context.endIndex, context.snapshotStride,
|
||||
ref ghostChunkComponentTypesPtr[indices[6].ComponentIndex], enableBits, ref maskOffset);
|
||||
new CustomSerializer.Generated.FloatCompo2GhostComponentSerializer().CopyComponentToSnapshot(chunk, ref context,
|
||||
ghostChunkComponentTypesPtr,indices[6], snapshotPtr, ref snapshotOffset);
|
||||
CustomGhostSerializerHelpers.CopyEnableBits(chunk, context.startIndex, context.endIndex, context.snapshotStride,
|
||||
ref ghostChunkComponentTypesPtr[indices[7].ComponentIndex], enableBits, ref maskOffset);
|
||||
new CustomSerializer.Generated.FloatCompo3GhostComponentSerializer().CopyComponentToSnapshot(chunk, ref context,
|
||||
ghostChunkComponentTypesPtr,indices[7], snapshotPtr, ref snapshotOffset);
|
||||
new CustomSerializer.Generated.InterpolatedOnlyCompGhostComponentSerializer().CopyComponentToSnapshot(chunk, ref context,
|
||||
ghostChunkComponentTypesPtr,indices[8], snapshotPtr, ref snapshotOffset);
|
||||
new CustomSerializer.Generated.OwnerOnlyCompGhostComponentSerializer().CopyComponentToSnapshot(chunk, ref context,
|
||||
ghostChunkComponentTypesPtr,indices[9], snapshotPtr, ref snapshotOffset);
|
||||
new CustomSerializer.Generated.Buf1GhostComponentSerializer().CopyBufferToSnapshot(chunk, ref context,
|
||||
ghostChunkComponentTypesPtr,indices[10], snapshotPtr, ref snapshotOffset, ref dynamicSnapshotOffset);
|
||||
new CustomSerializer.Generated.Buf2GhostComponentSerializer().CopyBufferToSnapshot(chunk, ref context,
|
||||
ghostChunkComponentTypesPtr,indices[11], snapshotPtr, ref snapshotOffset, ref dynamicSnapshotOffset);
|
||||
new CustomSerializer.Generated.Buf3GhostComponentSerializer().CopyBufferToSnapshot(chunk, ref context,
|
||||
ghostChunkComponentTypesPtr,indices[12], snapshotPtr, ref snapshotOffset, ref dynamicSnapshotOffset);
|
||||
|
||||
//CHILD COMPONENTS
|
||||
var linkedGroup = chunk.GetBufferAccessor(ref context.linkedEntityGroupTypeHandle);
|
||||
for (int ent = context.startIndex; ent < context.endIndex; ++ent)
|
||||
{
|
||||
var childEnableMaskOffset = maskOffset;
|
||||
var childSnapshotOffset = snapshotOffset;
|
||||
|
||||
//GENERATE ONLY THIS
|
||||
var childEnt = linkedGroup[ent][1].Value;
|
||||
var childEntityStorageInfo = context.childEntityLookup[childEnt];
|
||||
CustomGhostSerializerHelpers.CopyEnableBits(childEntityStorageInfo.Chunk, childEntityStorageInfo.IndexInChunk, childEntityStorageInfo.IndexInChunk+1, context.snapshotStride,
|
||||
ref ghostChunkComponentTypesPtr[indices[13].ComponentIndex], enableBits, ref childEnableMaskOffset);
|
||||
new CustomSerializer.Generated.IntCompo1GhostComponentSerializer().CopyChildComponentToSnapshot(childEntityStorageInfo.Chunk, childEntityStorageInfo.IndexInChunk, ref context,
|
||||
ghostChunkComponentTypesPtr,indices[13], snapshotPtr, ref childSnapshotOffset);
|
||||
CustomGhostSerializerHelpers.CopyEnableBits(childEntityStorageInfo.Chunk, childEntityStorageInfo.IndexInChunk, childEntityStorageInfo.IndexInChunk+1, context.snapshotStride,
|
||||
ref ghostChunkComponentTypesPtr[indices[14].ComponentIndex], enableBits, ref childEnableMaskOffset);
|
||||
new CustomSerializer.Generated.FloatCompo1GhostComponentSerializer().CopyChildComponentToSnapshot(childEntityStorageInfo.Chunk, childEntityStorageInfo.IndexInChunk, ref context,
|
||||
ghostChunkComponentTypesPtr,indices[14], snapshotPtr, ref childSnapshotOffset);
|
||||
new CustomSerializer.Generated.Buf1GhostComponentSerializer().CopyChildBufferToSnapshot(childEntityStorageInfo.Chunk, childEntityStorageInfo.IndexInChunk, ref context,
|
||||
ghostChunkComponentTypesPtr,indices[15], snapshotPtr, ref childSnapshotOffset, ref dynamicSnapshotOffset);
|
||||
|
||||
childEnt = linkedGroup[ent][2].Value;
|
||||
childEntityStorageInfo = context.childEntityLookup[childEnt];
|
||||
CustomGhostSerializerHelpers.CopyEnableBits(childEntityStorageInfo.Chunk, childEntityStorageInfo.IndexInChunk, childEntityStorageInfo.IndexInChunk+1, context.snapshotStride,
|
||||
ref ghostChunkComponentTypesPtr[indices[16].ComponentIndex], enableBits, ref childEnableMaskOffset);
|
||||
new CustomSerializer.Generated.IntCompo2GhostComponentSerializer().CopyChildComponentToSnapshot(childEntityStorageInfo.Chunk, childEntityStorageInfo.IndexInChunk, ref context,
|
||||
ghostChunkComponentTypesPtr,indices[16], snapshotPtr, ref childSnapshotOffset);
|
||||
CustomGhostSerializerHelpers.CopyEnableBits(childEntityStorageInfo.Chunk, childEntityStorageInfo.IndexInChunk, childEntityStorageInfo.IndexInChunk+1, context.snapshotStride,
|
||||
ref ghostChunkComponentTypesPtr[indices[17].ComponentIndex], enableBits, ref childEnableMaskOffset);
|
||||
new CustomSerializer.Generated.FloatCompo2GhostComponentSerializer().CopyChildComponentToSnapshot(childEntityStorageInfo.Chunk, childEntityStorageInfo.IndexInChunk, ref context,
|
||||
ghostChunkComponentTypesPtr,indices[17], snapshotPtr, ref childSnapshotOffset);
|
||||
new CustomSerializer.Generated.Buf2GhostComponentSerializer().CopyChildBufferToSnapshot(childEntityStorageInfo.Chunk, childEntityStorageInfo.IndexInChunk, ref context,
|
||||
ghostChunkComponentTypesPtr,indices[18], snapshotPtr, ref childSnapshotOffset, ref dynamicSnapshotOffset);
|
||||
|
||||
Assert.IsTrue(childEnableMaskOffset <= typeData.EnableableBits);
|
||||
|
||||
snapshotPtr += context.snapshotStride;
|
||||
enableBits += context.snapshotStride;
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe void SerializeWithSingleBaseline(IntPtr snapshotData, int snapshotOffset,
|
||||
SendToOwnerType sendToOwnerMask, GhostSendType sendTypeMask,
|
||||
GhostCollectionComponentIndex* indices,
|
||||
ref DataStreamWriter writer, in StreamCompressionModel compressionModel, IntPtr baseline0Ptr,
|
||||
IntPtr changeMaskData,
|
||||
IntPtr dynamicSnapshotData, IntPtr baselineDynamicData, ref int dynamicDataSizePerEntity,
|
||||
int* compBitSize, int compBitSizeStride)
|
||||
{
|
||||
var changeMaskOffset = 0;
|
||||
//GENERATE ONLY THIS
|
||||
compBitSize[0*compBitSizeStride] = default(Unity.NetCode.Generated.GhostOwnerGhostComponentSerializer).SerializeComponentSingleBaseline(snapshotData,baseline0Ptr,changeMaskData,ref changeMaskOffset, ref snapshotOffset, ref writer, compressionModel);
|
||||
compBitSize[1*compBitSizeStride] = default(Unity.NetCode.Generated.TransformDefaultVariantGhostComponentSerializer).SerializeComponentSingleBaseline(snapshotData,baseline0Ptr,changeMaskData,ref changeMaskOffset, ref snapshotOffset, ref writer, compressionModel);
|
||||
compBitSize[2*compBitSizeStride] = default(CustomSerializer.Generated.IntCompo1GhostComponentSerializer).SerializeComponentSingleBaseline(snapshotData,baseline0Ptr,changeMaskData,ref changeMaskOffset, ref snapshotOffset, ref writer, compressionModel);
|
||||
compBitSize[3*compBitSizeStride] = default(CustomSerializer.Generated.IntCompo2GhostComponentSerializer).SerializeComponentSingleBaseline(snapshotData,baseline0Ptr,changeMaskData,ref changeMaskOffset, ref snapshotOffset, ref writer, compressionModel);
|
||||
compBitSize[4*compBitSizeStride] = default(CustomSerializer.Generated.IntCompo3GhostComponentSerializer).SerializeComponentSingleBaseline(snapshotData,baseline0Ptr,changeMaskData,ref changeMaskOffset, ref snapshotOffset, ref writer, compressionModel);
|
||||
compBitSize[5*compBitSizeStride] = default(CustomSerializer.Generated.FloatCompo1GhostComponentSerializer).SerializeComponentSingleBaseline(snapshotData,baseline0Ptr,changeMaskData,ref changeMaskOffset, ref snapshotOffset, ref writer, compressionModel);
|
||||
compBitSize[6*compBitSizeStride] = default(CustomSerializer.Generated.FloatCompo2GhostComponentSerializer).SerializeComponentSingleBaseline(snapshotData,baseline0Ptr,changeMaskData,ref changeMaskOffset, ref snapshotOffset, ref writer, compressionModel);
|
||||
compBitSize[7*compBitSizeStride] = default(CustomSerializer.Generated.FloatCompo3GhostComponentSerializer).SerializeComponentSingleBaseline(snapshotData,baseline0Ptr,changeMaskData,ref changeMaskOffset, ref snapshotOffset, ref writer, compressionModel);
|
||||
compBitSize[8*compBitSizeStride] = default(CustomSerializer.Generated.InterpolatedOnlyCompGhostComponentSerializer).SerializeComponentSingleBaseline(snapshotData,baseline0Ptr,changeMaskData,ref changeMaskOffset, ref snapshotOffset, ref writer, compressionModel, (int)(indices[8].SendMask & sendTypeMask) | (int)(indices[8].SendToOwner & sendToOwnerMask));
|
||||
compBitSize[9*compBitSizeStride] = default(CustomSerializer.Generated.OwnerOnlyCompGhostComponentSerializer).SerializeComponentSingleBaseline(snapshotData,baseline0Ptr,changeMaskData,ref changeMaskOffset, ref snapshotOffset, ref writer, compressionModel, (int)(indices[9].SendMask & sendTypeMask) | (int)(indices[9].SendToOwner & sendToOwnerMask));
|
||||
compBitSize[10*compBitSizeStride] = default(CustomSerializer.Generated.Buf1GhostComponentSerializer).SerializeBuffer(snapshotData,baseline0Ptr, dynamicSnapshotData, baselineDynamicData, changeMaskData, ref changeMaskOffset, ref snapshotOffset, ref dynamicDataSizePerEntity, ref writer, compressionModel);
|
||||
compBitSize[11*compBitSizeStride] = default(CustomSerializer.Generated.Buf2GhostComponentSerializer).SerializeBuffer(snapshotData,baseline0Ptr, dynamicSnapshotData, baselineDynamicData, changeMaskData, ref changeMaskOffset, ref snapshotOffset, ref dynamicDataSizePerEntity, ref writer, compressionModel);
|
||||
compBitSize[12*compBitSizeStride] = default(CustomSerializer.Generated.Buf3GhostComponentSerializer).SerializeBuffer(snapshotData,baseline0Ptr, dynamicSnapshotData, baselineDynamicData, changeMaskData, ref changeMaskOffset, ref snapshotOffset, ref dynamicDataSizePerEntity, ref writer, compressionModel);
|
||||
compBitSize[13*compBitSizeStride] = default(CustomSerializer.Generated.IntCompo1GhostComponentSerializer).SerializeComponentSingleBaseline(snapshotData,baseline0Ptr,changeMaskData,ref changeMaskOffset, ref snapshotOffset, ref writer, compressionModel);
|
||||
compBitSize[14*compBitSizeStride] = default(CustomSerializer.Generated.FloatCompo1GhostComponentSerializer).SerializeComponentSingleBaseline(snapshotData,baseline0Ptr,changeMaskData,ref changeMaskOffset, ref snapshotOffset, ref writer, compressionModel);
|
||||
compBitSize[15*compBitSizeStride] = default(CustomSerializer.Generated.Buf1GhostComponentSerializer).SerializeBuffer(snapshotData,baseline0Ptr, dynamicSnapshotData, baselineDynamicData, changeMaskData, ref changeMaskOffset, ref snapshotOffset, ref dynamicDataSizePerEntity, ref writer, compressionModel);
|
||||
compBitSize[16*compBitSizeStride] = default(CustomSerializer.Generated.IntCompo2GhostComponentSerializer).SerializeComponentSingleBaseline(snapshotData,baseline0Ptr,changeMaskData,ref changeMaskOffset, ref snapshotOffset, ref writer, compressionModel);
|
||||
compBitSize[17*compBitSizeStride] = default(CustomSerializer.Generated.FloatCompo2GhostComponentSerializer).SerializeComponentSingleBaseline(snapshotData,baseline0Ptr,changeMaskData,ref changeMaskOffset, ref snapshotOffset, ref writer, compressionModel);
|
||||
compBitSize[18*compBitSizeStride] = default(CustomSerializer.Generated.Buf2GhostComponentSerializer).SerializeBuffer(snapshotData,baseline0Ptr, dynamicSnapshotData, baselineDynamicData, changeMaskData,ref changeMaskOffset, ref snapshotOffset, ref dynamicDataSizePerEntity, ref writer, compressionModel);
|
||||
}
|
||||
|
||||
private static unsafe void SerializeWithThreeBaselines(IntPtr snapshotData, int snapshotOffset,
|
||||
SendToOwnerType sendToOwnerMask, GhostSendType sendTypeMask,
|
||||
GhostCollectionComponentIndex* indices,
|
||||
ref DataStreamWriter writer, in StreamCompressionModel compressionModel,
|
||||
IntPtr baseline0Ptr, IntPtr baseline1Ptr, IntPtr baseline2Ptr, IntPtr changeMaskData,
|
||||
IntPtr dynamicSnapshotData, IntPtr baselineDynamicData, ref int dynamicDataSizePerEntity,
|
||||
int* compBitSize, int compBitSizeStride)
|
||||
{
|
||||
var predictor = new GhostDeltaPredictor(
|
||||
new NetworkTick { SerializedData = GhostComponentSerializer.TypeCast<uint>(snapshotData) },
|
||||
new NetworkTick { SerializedData = GhostComponentSerializer.TypeCast<uint>(baseline0Ptr) },
|
||||
new NetworkTick { SerializedData = GhostComponentSerializer.TypeCast<uint>(baseline1Ptr) },
|
||||
new NetworkTick { SerializedData = GhostComponentSerializer.TypeCast<uint>(baseline2Ptr) });
|
||||
var changeMaskOffset = 0;
|
||||
|
||||
//GENERATE ONLY THIS
|
||||
compBitSize[0*compBitSizeStride] = default(Unity.NetCode.Generated.GhostOwnerGhostComponentSerializer).SerializeComponentThreeBaseline(snapshotData,baseline0Ptr,baseline1Ptr, baseline2Ptr, changeMaskData, ref changeMaskOffset, ref snapshotOffset, ref predictor, ref writer, compressionModel);
|
||||
compBitSize[1*compBitSizeStride] = default(Unity.NetCode.Generated.TransformDefaultVariantGhostComponentSerializer).SerializeComponentThreeBaseline(snapshotData,baseline0Ptr,baseline1Ptr, baseline2Ptr, changeMaskData, ref changeMaskOffset, ref snapshotOffset, ref predictor, ref writer, compressionModel);
|
||||
compBitSize[2*compBitSizeStride] = default(CustomSerializer.Generated.IntCompo1GhostComponentSerializer).SerializeComponentThreeBaseline(snapshotData,baseline0Ptr,baseline1Ptr, baseline2Ptr, changeMaskData, ref changeMaskOffset, ref snapshotOffset, ref predictor, ref writer, compressionModel);
|
||||
compBitSize[3*compBitSizeStride] = default(CustomSerializer.Generated.IntCompo2GhostComponentSerializer).SerializeComponentThreeBaseline(snapshotData,baseline0Ptr,baseline1Ptr, baseline2Ptr, changeMaskData, ref changeMaskOffset, ref snapshotOffset, ref predictor, ref writer, compressionModel);
|
||||
compBitSize[4*compBitSizeStride] = default(CustomSerializer.Generated.IntCompo3GhostComponentSerializer).SerializeComponentThreeBaseline(snapshotData,baseline0Ptr,baseline1Ptr, baseline2Ptr, changeMaskData, ref changeMaskOffset, ref snapshotOffset, ref predictor, ref writer, compressionModel);
|
||||
compBitSize[5*compBitSizeStride] = default(CustomSerializer.Generated.FloatCompo1GhostComponentSerializer).SerializeComponentThreeBaseline(snapshotData,baseline0Ptr,baseline1Ptr, baseline2Ptr, changeMaskData,ref changeMaskOffset, ref snapshotOffset, ref predictor, ref writer, compressionModel);
|
||||
compBitSize[6*compBitSizeStride] = default(CustomSerializer.Generated.FloatCompo2GhostComponentSerializer).SerializeComponentThreeBaseline(snapshotData,baseline0Ptr,baseline1Ptr, baseline2Ptr, changeMaskData, ref changeMaskOffset, ref snapshotOffset, ref predictor, ref writer, compressionModel);
|
||||
compBitSize[7*compBitSizeStride] = default(CustomSerializer.Generated.FloatCompo3GhostComponentSerializer).SerializeComponentThreeBaseline(snapshotData,baseline0Ptr,baseline1Ptr, baseline2Ptr, changeMaskData, ref changeMaskOffset, ref snapshotOffset, ref predictor, ref writer, compressionModel);
|
||||
compBitSize[8*compBitSizeStride] = default(CustomSerializer.Generated.InterpolatedOnlyCompGhostComponentSerializer).SerializeComponentThreeBaseline(snapshotData,baseline0Ptr,baseline1Ptr, baseline2Ptr, changeMaskData, ref changeMaskOffset, ref snapshotOffset, ref predictor, ref writer, compressionModel, (int)(indices[8].SendMask & sendTypeMask) | (int)(indices[8].SendToOwner & sendToOwnerMask));
|
||||
compBitSize[9*compBitSizeStride] = default(CustomSerializer.Generated.OwnerOnlyCompGhostComponentSerializer).SerializeComponentThreeBaseline(snapshotData,baseline0Ptr,baseline1Ptr, baseline2Ptr, changeMaskData, ref changeMaskOffset, ref snapshotOffset, ref predictor, ref writer, compressionModel, (int)(indices[9].SendMask & sendTypeMask) | (int)(indices[9].SendToOwner & sendToOwnerMask));
|
||||
compBitSize[10*compBitSizeStride] = default(CustomSerializer.Generated.Buf1GhostComponentSerializer).SerializeBuffer(snapshotData,baseline0Ptr, dynamicSnapshotData, baselineDynamicData, changeMaskData,ref changeMaskOffset, ref snapshotOffset, ref dynamicDataSizePerEntity, ref writer, compressionModel);
|
||||
compBitSize[11*compBitSizeStride] = default(CustomSerializer.Generated.Buf2GhostComponentSerializer).SerializeBuffer(snapshotData,baseline0Ptr, dynamicSnapshotData, baselineDynamicData, changeMaskData,ref changeMaskOffset, ref snapshotOffset, ref dynamicDataSizePerEntity, ref writer, compressionModel);
|
||||
compBitSize[12*compBitSizeStride] = default(CustomSerializer.Generated.Buf3GhostComponentSerializer).SerializeBuffer(snapshotData,baseline0Ptr, dynamicSnapshotData, baselineDynamicData, changeMaskData,ref changeMaskOffset, ref snapshotOffset, ref dynamicDataSizePerEntity, ref writer, compressionModel);
|
||||
compBitSize[13*compBitSizeStride] = default(CustomSerializer.Generated.IntCompo1GhostComponentSerializer).SerializeComponentThreeBaseline(snapshotData,baseline0Ptr,baseline1Ptr, baseline2Ptr, changeMaskData,ref changeMaskOffset, ref snapshotOffset, ref predictor, ref writer, compressionModel);
|
||||
compBitSize[14*compBitSizeStride] = default(CustomSerializer.Generated.FloatCompo1GhostComponentSerializer).SerializeComponentThreeBaseline(snapshotData,baseline0Ptr,baseline1Ptr, baseline2Ptr, changeMaskData,ref changeMaskOffset, ref snapshotOffset, ref predictor, ref writer, compressionModel);
|
||||
compBitSize[15*compBitSizeStride] = default(CustomSerializer.Generated.Buf1GhostComponentSerializer).SerializeBuffer(snapshotData,baseline0Ptr, dynamicSnapshotData, baselineDynamicData, changeMaskData,ref changeMaskOffset, ref snapshotOffset, ref dynamicDataSizePerEntity,ref writer, compressionModel);
|
||||
compBitSize[16*compBitSizeStride] = default(CustomSerializer.Generated.IntCompo2GhostComponentSerializer).SerializeComponentThreeBaseline(snapshotData,baseline0Ptr,baseline1Ptr, baseline2Ptr, changeMaskData,ref changeMaskOffset, ref snapshotOffset, ref predictor, ref writer, compressionModel);
|
||||
compBitSize[17*compBitSizeStride] = default(CustomSerializer.Generated.FloatCompo2GhostComponentSerializer).SerializeComponentThreeBaseline(snapshotData,baseline0Ptr,baseline1Ptr, baseline2Ptr, changeMaskData,ref changeMaskOffset, ref snapshotOffset, ref predictor, ref writer, compressionModel);
|
||||
compBitSize[18*compBitSizeStride] = default(CustomSerializer.Generated.Buf2GhostComponentSerializer).SerializeBuffer(snapshotData,baseline0Ptr, dynamicSnapshotData, baselineDynamicData, changeMaskData,ref changeMaskOffset, ref snapshotOffset, ref dynamicDataSizePerEntity, ref writer, compressionModel);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dd27dcb4859d4bed9b64765463602e5d
|
||||
timeCreated: 1695464432
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"name": "CustomSerializer",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:953adc2a6b8b4e3c8df5b728bcd546e9",
|
||||
"GUID:734d92eba21c94caba915361bd5ac177",
|
||||
"GUID:d8b63aba1907145bea998dd612889d6b",
|
||||
"GUID:e0cd26848372d4e5c891c569017e11f1",
|
||||
"GUID:2665a8d13d1b3f18800f46e256720795",
|
||||
"GUID:f2d49d9fa7e7eb3418e39723a7d3b92f",
|
||||
"GUID:8819f35a0fc84499b990e90a4ca1911f",
|
||||
"GUID:a5baed0c9693541a5bd947d336ec7659"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": true,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 54ee788d33434308ae727b0388cbe753
|
||||
timeCreated: 1695581462
|
|
@ -0,0 +1,165 @@
|
|||
# Creating a custom chunk serialization method
|
||||
|
||||
This sample shows how implement and register a custom serialization method, to serialize ghost chunks of a given archetype.
|
||||
|
||||
## Why using custom serialization function
|
||||
|
||||
Only one reason: **Peformance**! When using the a custom serialization function designed for a specific archetype,
|
||||
you can make (or relax) certain assumptions: I.e.
|
||||
* No checks for removed components.
|
||||
* Optimise the loops that gather and copy data.
|
||||
* Generally write things in a way that gives both the compiler, and burst in primis, more opportunities for
|
||||
auto-vectorization.
|
||||
|
||||
In general, it also gives a CPU performance gain in cases where the ghost has a lots of small components, reducing function pointer call overhead (and more importantly single call setup overhead).
|
||||
|
||||
### Current limitation of the custom serializer API
|
||||
This is an advanced feature of the Netcode package (we can say it is "in-preview"), available for now only when using the PrefabCreation API (i.e. manually created ghost entities types).
|
||||
|
||||
# USING THE API
|
||||
## Registering custom serializers
|
||||
In order to use custom chunk serialization function; **said function must be registered to the GhostCollection system, before the
|
||||
prefabs are collected and processed.** A good place to put the registration, is in the system where you create the prefabs.
|
||||
|
||||
To register your custom serialization function, you need to retrieve the `GhostCollectionCustomSerializer` singleton,
|
||||
and add an entry for a given archetype. A ghost archetype is identified by its GhostType hash.
|
||||
|
||||
```csharp
|
||||
GhostPrefabCreation.ConvertToGhostPrefab(EntityManager, prefab, prefabConfig);
|
||||
var hash = (Unity.Entities.Hash128)EntityManager.GetComponentData<GhostType>(prefab);
|
||||
var customSerializers = SystemAPI.GetSingletonRW<GhostCollectionCustomSerializers>();
|
||||
customSerializers.ValueRW.Serializers.Add(hash, new GhostPrefabCustomSerializer
|
||||
{
|
||||
SerializeChunk = CustomChunkSerializer.SerializerFunc,
|
||||
PreSerializeChunk = CustomChunkSerializer.PreSerializerFunc
|
||||
});
|
||||
```
|
||||
|
||||
Both `SerializeChunk` and `PreSerializeChunk` functions are optional, meaning that you can have either one of them, or both.
|
||||
|
||||
## Register a custom component list provider for the archetype
|
||||
In order to be able to serialize a component, it is necessary to access and retrieve the component data from the chunk.
|
||||
This is achieved by accessing the list of serialized components registered for this archetype, and retrieve from them a list of type handles (the `DynamicTypeHandle`) for each component type.
|
||||
|
||||
Each the prefab processed by the `GhostCollectionSystem` has:
|
||||
- one entry in the `GhostCollectionPrefabSerializer` list, that contains a bunch of metadata information to serialize the type.
|
||||
- each serialized component will create an entry in the `GhostCollectionComponentIndex` (for root and child entities in order) that contains (among other things):
|
||||
- which serializer to use (the SerializerIndex field)
|
||||
- an index in the `DynamicTypeList` (ComponentIndex) that let you retrieve the `DynamicComponentTypeHandle`.
|
||||
|
||||
```csharp
|
||||
var typeData = ghostCollectionPrefabSerializer[ghostType];
|
||||
var componentIndex = typeData.FirstComponent;
|
||||
var index = componentIndices[componentIndex];
|
||||
var dynamicTypeHandle = dynamicTypeList[index.ComponentIndex];
|
||||
```
|
||||
|
||||
When writing a custom serialization method, it can be tricky to find the index of a specific component type
|
||||
in the `componentIndices` list, for the current ghost archetype. That because a components position in the list depends upon:
|
||||
- its stable-type-hash
|
||||
- the serializer hash associated with that specific component for that archetype.
|
||||
|
||||
Therefore, we support passing a `CollectComponents` function pointer to the GhostPrefabCreation.ConvertToGhostPrefab` (a field of the config argument),
|
||||
such that you know exactly the index into the `componentIndices` list for a specific component type.
|
||||
|
||||
For example:
|
||||
|
||||
```csharp
|
||||
public static void CollectComponents(IntPtr componentTypesPtr, IntPtr componentCountPtr)
|
||||
{
|
||||
ref var componentTypes = ref GhostComponentSerializer.TypeCast<NativeList<ComponentType>>(componentTypesPtr);
|
||||
ref var componentCount = ref GhostComponentSerializer.TypeCast<NativeArray<int>>(componentCountPtr);
|
||||
//Root
|
||||
componentTypes.Add(ComponentType.ReadWrite<GhostOwner>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<LocalTransform>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<IntCompo1>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<IntCompo2>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<IntCompo3>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<FloatCompo1>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<FloatCompo2>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<FloatCompo3>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<InterpolatedOnlyComp>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<OwnerOnlyComp>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<Buf1>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<Buf2>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<Buf3>());
|
||||
componentCount[0] = 13;
|
||||
//Child 1
|
||||
componentTypes.Add(ComponentType.ReadWrite<IntCompo1>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<FloatCompo1>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<Buf1>());
|
||||
componentCount[1] = 3;
|
||||
//Child 2
|
||||
componentTypes.Add(ComponentType.ReadWrite<IntCompo2>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<FloatCompo2>());
|
||||
componentTypes.Add(ComponentType.ReadWrite<Buf2>());
|
||||
componentCount[2] = 3;
|
||||
}
|
||||
```
|
||||
|
||||
You can find this function in the `CustomChunkSerializer.cs` file.
|
||||
|
||||
When the function is present, the components list for that archetype use the order specified by that method, giving you the possibility
|
||||
to access the component types information consistently, and also allowing you to define the component serialization order.
|
||||
|
||||
## Implementing custom chunk serializer
|
||||
|
||||
We provide a bunch of utility methods that can be used to serialize the enable bits, buffers and components inside the
|
||||
`CustomGhostSerializerHelpers` class.
|
||||
The `CustomChunkSerializer.cs` can be considered a sort of template that you can reuse to write or generate your serializer almost
|
||||
automatically (by just invoking the provider helper functions).
|
||||
|
||||
To make the code as re-usable as possible (and reducing mistakes), you must re-use the generated component serializer struct
|
||||
(i.e `MyAssembly.Generated.MyComponentGhostComponentSerializer`) and:
|
||||
- invoke on an instance of that serializer one of the `CopyToSnapshot<T>` methods.
|
||||
- invoke on an instance of that serializer one of the `SerializeWithSingleBaseline` or `SerializeWithThreeBaseline` or `SerializeBuffer`.
|
||||
|
||||
Unfortunately, given that the `MyAssembly.Generated.MyComponentGhostComponentSerializer` serializer is auto-generated, most IDE's will not help auto-complete the method name, nor will they recognize the classes existence. But the code will compile correctly.
|
||||
|
||||
The serialization is divided in two steps:
|
||||
|
||||
### STEP 1 - COPY TO SNAPSHOT
|
||||
You just need to implement the `CustomChunkSerializer.CopyComponentsToSnapshot` method, by copying the enable bits (if necessary), and copying the component data. For example:
|
||||
|
||||
```csharp
|
||||
|
||||
new Unity.NetCode.Generated.GhostOwnerGhostComponentSerializer().CopyComponentToSnapshot(chunk, ref context,
|
||||
ghostChunkComponentTypesPtr, indices[0], snapshotPtr, ref snapshotOffset);
|
||||
new Unity.NetCode.Generated.TransformDefaultVariantGhostComponentSerializer().CopyComponentToSnapshot(chunk, ref context,
|
||||
ghostChunkComponentTypesPtr,indices[1], snapshotPtr, ref snapshotOffset);
|
||||
CustomGhostSerializerHelpers.CopyEnableBits(chunk, context.startIndex, context.endIndex, context.snapshotStride,
|
||||
ref ghostChunkComponentTypesPtr[indices[2].ComponentIndex], enableBits, ref maskOffset);
|
||||
```
|
||||
|
||||
Similarly, for child entity components, we have similar methods that just scaffold some implementation details and boilerplate template code.
|
||||
|
||||
### STEP 2 - SERIALIZE TO THE DATASTREAM
|
||||
After the data has been copied into the snapshot buffer, we can serialize the snapshot (entity by entity), into the data stream. Based on the acknowledge baselines, we should serialize by either:
|
||||
- A single or default baseline
|
||||
- three baselines.
|
||||
|
||||
The `CustomChunkSerializer` class has two methods that need to be implemented:
|
||||
- `SerializeWithSingleBaseline`
|
||||
- `SerializeWithThreeBaseline`
|
||||
|
||||
All code-generated serializers provide three static methods can be used for writing the snapshot data into the stream:
|
||||
- `SerializeSingleBaseline`: serialize the data using only one baseline (either acked or the default one).
|
||||
- `SerializeThreeBaseline`: serialize the data using the last three baselines (all acked) and by predicting the value to reduce the delta.
|
||||
- `SerializeBuffer`: serialize a buffer to the stream using one single baseline (either the default or the acked one).
|
||||
|
||||
See the `CustomChunkSerializer.cs` for an example how to use them. But as a short example:
|
||||
|
||||
```csharp
|
||||
|
||||
//With a single baseline
|
||||
compBitSize[0*compBitSizeStride] = default(Unity.NetCode.Generated.GhostOwnerGhostComponentSerializer).SerializeComponentThreeBaseline(snapshotData,baseline0Ptr,
|
||||
baseline1Ptr, baseline2Ptr, changeMaskData, ref changeMaskOffset, ref snapshotOffset, ref predictor, ref writer, compressionModel);
|
||||
|
||||
//With three baseline
|
||||
compBitSize[0*compBitSizeStride] = default(Unity.NetCode.Generated.GhostOwnerGhostComponentSerializer).SerializeComponentThreeBaseline(snapshotData,baseline0Ptr,
|
||||
baseline1Ptr, baseline2Ptr, changeMaskData, ref changeMaskOffset, ref snapshotOffset, ref predictor, ref writer, compressionModel);
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 704a06de9d09493f8f217485272238a4
|
||||
timeCreated: 1698317036
|
|
@ -0,0 +1,233 @@
|
|||
using Unity.Collections;
|
||||
using Unity.Entities;
|
||||
using Unity.Mathematics;
|
||||
using Unity.NetCode;
|
||||
using Unity.Transforms;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
namespace Samples.CustomChunkSerializer
|
||||
{
|
||||
[UpdateInGroup(typeof(InitializationSystemGroup))]
|
||||
public partial class CustomSerializerSample : SystemBase
|
||||
{
|
||||
protected override void OnCreate()
|
||||
{
|
||||
RequireForUpdate<GhostCollection>();
|
||||
RequireForUpdate<TestCustomSerializer>();
|
||||
}
|
||||
|
||||
public static Entity CreateEntityArchetype(EntityManager entityManager, bool initValues)
|
||||
{
|
||||
var entity = entityManager.CreateEntity();
|
||||
var child0 = entityManager.CreateEntity(typeof(GhostChildEntity));
|
||||
var child1 = entityManager.CreateEntity(typeof(GhostChildEntity));
|
||||
var linkedEntityGroups = entityManager.AddBuffer<LinkedEntityGroup>(entity);
|
||||
linkedEntityGroups.Add(entity);
|
||||
linkedEntityGroups.Add(child0);
|
||||
linkedEntityGroups.Add(child1);
|
||||
entityManager.AddComponent(entity, ComponentType.ReadWrite<GhostOwner>());
|
||||
entityManager.AddComponent(entity, ComponentType.ReadWrite<LocalTransform>());
|
||||
entityManager.AddComponent(entity, ComponentType.ReadWrite<IntCompo1>());
|
||||
entityManager.AddComponent(entity, ComponentType.ReadWrite<IntCompo2>());
|
||||
entityManager.AddComponent(entity, ComponentType.ReadWrite<IntCompo3>());
|
||||
entityManager.AddComponent(entity, ComponentType.ReadWrite<FloatCompo1>());
|
||||
entityManager.AddComponent(entity, ComponentType.ReadWrite<FloatCompo2>());
|
||||
entityManager.AddComponent(entity, ComponentType.ReadWrite<FloatCompo3>());
|
||||
entityManager.AddComponent(entity, ComponentType.ReadWrite<InterpolatedOnlyComp>());
|
||||
entityManager.AddComponent(entity, ComponentType.ReadWrite<OwnerOnlyComp>());
|
||||
entityManager.AddComponent(entity, ComponentType.ReadWrite<Buf1>());
|
||||
entityManager.AddComponent(entity, ComponentType.ReadWrite<Buf2>());
|
||||
entityManager.AddComponent(entity, ComponentType.ReadWrite<Buf3>());
|
||||
entityManager.AddComponent(child0, ComponentType.ReadWrite<IntCompo1>());
|
||||
entityManager.AddComponent(child0, ComponentType.ReadWrite<FloatCompo1>());
|
||||
entityManager.AddComponent(child0, ComponentType.ReadWrite<Buf1>());
|
||||
entityManager.AddComponent(child1, ComponentType.ReadWrite<IntCompo2>());
|
||||
entityManager.AddComponent(child1, ComponentType.ReadWrite<FloatCompo2>());
|
||||
entityManager.AddComponent(child1, ComponentType.ReadWrite<Buf2>());
|
||||
|
||||
if (initValues)
|
||||
{
|
||||
entityManager.SetComponentData(entity, new IntCompo1 { Value = 100 });
|
||||
entityManager.SetComponentData(entity, new IntCompo2 { Value = 200 });
|
||||
entityManager.SetComponentData(entity, new IntCompo3 { Value = 300 });
|
||||
|
||||
entityManager.SetComponentData(entity, new FloatCompo1 { Value = 10f });
|
||||
entityManager.SetComponentData(entity, new FloatCompo2 { Value = 20f });
|
||||
entityManager.SetComponentData(entity, new FloatCompo3 { Value = 30f });
|
||||
entityManager.SetComponentData(entity, new InterpolatedOnlyComp{Value1 = 10, Value2 = 20, Value3 = 30, Value4 = 40});
|
||||
entityManager.SetComponentData(entity, new OwnerOnlyComp{Value1 = 10, Value2 = 20, Value3 = 30, Value4 = 40});
|
||||
entityManager.SetComponentData(entity, LocalTransform.FromPosition(new float3(1f, 2f, 3f)));
|
||||
|
||||
var buf1 = entityManager.GetBuffer<Buf1>(entity);
|
||||
buf1.ResizeUninitialized(5);
|
||||
for (int i = 0; i < buf1.Length; ++i)
|
||||
buf1.ElementAt(i).Value = 10;
|
||||
var buf2 = entityManager.GetBuffer<Buf2>(entity);
|
||||
buf2.ResizeUninitialized(5);
|
||||
for (int i = 0; i < buf2.Length; ++i)
|
||||
buf2.ElementAt(i).Value = 20;
|
||||
var buf3 = entityManager.GetBuffer<Buf3>(entity);
|
||||
buf3.ResizeUninitialized(5);
|
||||
for (int i = 0; i < buf3.Length; ++i)
|
||||
{
|
||||
buf3.ElementAt(i).Value1 = 10;
|
||||
buf3.ElementAt(i).Value2 = 20;
|
||||
buf3.ElementAt(i).Value3 = 30f;
|
||||
buf3.ElementAt(i).Value4 = 40f;
|
||||
}
|
||||
|
||||
entityManager.SetComponentData(child0, new IntCompo1 { Value = 100 });
|
||||
entityManager.SetComponentData(child0, new FloatCompo1 { Value = 100f });
|
||||
buf1 = entityManager.GetBuffer<Buf1>(child0);
|
||||
buf1.ResizeUninitialized(5);
|
||||
for (int i = 0; i < buf1.Length; ++i)
|
||||
buf1.ElementAt(i).Value = 10;
|
||||
|
||||
entityManager.SetComponentData(child1, new IntCompo2 { Value = 200 });
|
||||
entityManager.SetComponentData(child1, new FloatCompo2 { Value = 200f });
|
||||
buf2 = entityManager.GetBuffer<Buf2>(child1);
|
||||
buf2.ResizeUninitialized(5);
|
||||
for (int i = 0; i < buf1.Length; ++i)
|
||||
buf2.ElementAt(i).Value = 20;
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
//First frame: create all the ghost prefabs. This is going to create
|
||||
Entity prefab = CreateEntityArchetype(EntityManager, World.IsServer());
|
||||
var comp = SystemAPI.GetSingleton<TestCustomSerializer>();
|
||||
var prefabConfig = new GhostPrefabCreation.Config
|
||||
{
|
||||
Name = "SimpleGhost",
|
||||
Importance = 1,
|
||||
SupportedGhostModes = GhostModeMask.All,
|
||||
DefaultGhostMode = GhostMode.OwnerPredicted,
|
||||
OptimizationMode = GhostOptimizationMode.Dynamic,
|
||||
UsePreSerialization = comp.usePreserialization,
|
||||
CollectComponentFunc = ChunkSerializer.CollectComponentFunc
|
||||
};
|
||||
EntityManager.SetName(prefab, prefabConfig.Name);
|
||||
GhostPrefabCreation.ConvertToGhostPrefab(EntityManager, prefab, prefabConfig);
|
||||
var hash = (Unity.Entities.Hash128)EntityManager.GetComponentData<GhostType>(prefab);
|
||||
var customSerializer = SystemAPI.GetSingletonRW<GhostCollectionCustomSerializers>();
|
||||
customSerializer.ValueRW.Serializers.Add(hash, new GhostPrefabCustomSerializer
|
||||
{
|
||||
SerializeChunk = ChunkSerializer.SerializerFunc,
|
||||
PreSerializeChunk = ChunkSerializer.PreSerializerFunc
|
||||
});
|
||||
if (World.IsServer())
|
||||
{
|
||||
SystemAPI.GetSingletonRW<GhostSendSystemData>().ValueRW.UseCustomSerializer = comp.useCustomSerializer ? 1 : 0;
|
||||
var entities = EntityManager.Instantiate(prefab, comp.numInstances, Allocator.Temp);
|
||||
for (int i = 0; i < entities.Length; ++i)
|
||||
{
|
||||
EntityManager.SetComponentData(entities[i], new GhostOwner{NetworkId = 1});
|
||||
}
|
||||
}
|
||||
Enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
[RequireMatchingQueriesForUpdate]
|
||||
public partial class AutoGoInGame : SystemBase
|
||||
{
|
||||
protected override void OnCreate()
|
||||
{
|
||||
RequireForUpdate<GhostCollection>();
|
||||
RequireForUpdate<TestCustomSerializer>();
|
||||
}
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
var buffer = new EntityCommandBuffer(Allocator.Temp);
|
||||
foreach (var (con,ent) in SystemAPI.Query<RefRO<NetworkId>>().WithNone<NetworkStreamInGame>().WithEntityAccess())
|
||||
{
|
||||
buffer.AddComponent(ent, new NetworkStreamInGame());
|
||||
}
|
||||
buffer.Playback(EntityManager);
|
||||
}
|
||||
}
|
||||
|
||||
[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)]
|
||||
[UpdateInGroup(typeof(GhostSimulationSystemGroup))]
|
||||
[CreateAfter(typeof(GhostSendSystem))]
|
||||
public partial class RandomizeSystem : SystemBase
|
||||
{
|
||||
protected override void OnCreate()
|
||||
{
|
||||
RequireForUpdate<TestCustomSerializer>();
|
||||
}
|
||||
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
//change all the components is a bad case scenario, because that may not let the serialization
|
||||
//code to perform all the calculation (many call, zero size to write), lots of write etc
|
||||
//it is possible to maximize the amount of work by forcing the ghost send system to always send
|
||||
//up to x chunks to have some more reliable "results"
|
||||
var testCustomSerializer = SystemAPI.GetSingleton<TestCustomSerializer>();
|
||||
var ghostsQuery = GetEntityQuery(typeof(GhostInstance));
|
||||
var ghostsChunks = ghostsQuery.ToArchetypeChunkArray(Allocator.Temp);
|
||||
var entityTypeHandle = GetEntityTypeHandle();
|
||||
foreach(var c in ghostsChunks)
|
||||
{
|
||||
if (UnityEngine.Random.value > testCustomSerializer.percentChunkChange)
|
||||
continue;
|
||||
var entities = c.GetNativeArray(entityTypeHandle);
|
||||
for (var ent = 0; ent < entities.Length; ++ent)
|
||||
{
|
||||
if (UnityEngine.Random.value > testCustomSerializer.percentEntityChanges)
|
||||
continue;
|
||||
|
||||
var entity = entities[ent];
|
||||
var lg = EntityManager.GetBuffer<LinkedEntityGroup>(entity);
|
||||
|
||||
World.EntityManager.SetComponentData(entity, new IntCompo1{Value = Random.Range(-10, 20)});
|
||||
World.EntityManager.SetComponentData(entity, new IntCompo2{Value = Random.Range(-10, 20)});
|
||||
World.EntityManager.SetComponentData(entity, new IntCompo3{Value = Random.Range(-10, 20)});
|
||||
World.EntityManager.SetComponentData(entity, new FloatCompo1{Value = Random.Range(-10f, 20f)});
|
||||
World.EntityManager.SetComponentData(entity, new FloatCompo2{Value = Random.Range(-10f, 20f)});
|
||||
World.EntityManager.SetComponentData(entity, new FloatCompo3{Value = Random.Range(-10f, 20f)});
|
||||
{
|
||||
var b1 = EntityManager.GetBuffer<Buf1>(lg[0].Value);
|
||||
for (int el = 0; el < 5; ++el)
|
||||
b1.ElementAt(el).Value = Random.Range(-10, 20);
|
||||
}
|
||||
{
|
||||
var b1 = EntityManager.GetBuffer<Buf2>(lg[0].Value);
|
||||
for (int el = 0; el < 5; ++el)
|
||||
b1.ElementAt(el).Value = Random.Range(-10, 20);
|
||||
}
|
||||
{
|
||||
var b1 = EntityManager.GetBuffer<Buf3>(lg[0].Value);
|
||||
for (int el = 0; el < 5; ++el)
|
||||
{
|
||||
b1.ElementAt(el).Value1 = Random.Range(-10, 20);
|
||||
b1.ElementAt(el).Value2 = Random.Range(-10, 20);
|
||||
b1.ElementAt(el).Value3 = Random.Range(-10, 20);
|
||||
b1.ElementAt(el).Value4 = Random.Range(-10, 20);
|
||||
}
|
||||
|
||||
}
|
||||
var child0 = lg[1].Value;
|
||||
World.EntityManager.SetComponentData(child0, new IntCompo1{Value = Random.Range(-10, 20)});
|
||||
World.EntityManager.SetComponentData(child0, new FloatCompo1{Value = Random.Range(-10f, 20f)});
|
||||
{
|
||||
var b1 = EntityManager.GetBuffer<Buf1>(lg[1].Value);
|
||||
for (int el = 0; el < 5; ++el)
|
||||
b1.ElementAt(el).Value = Random.Range(-10, 20);
|
||||
}
|
||||
var child1 = lg[2].Value;
|
||||
World.EntityManager.SetComponentData(child1, new IntCompo2{Value = Random.Range(-10, 20)});
|
||||
World.EntityManager.SetComponentData(child1, new FloatCompo2{Value = Random.Range(-10f, 20f)});
|
||||
{
|
||||
var b1 = EntityManager.GetBuffer<Buf2>(lg[2].Value);
|
||||
for (int el = 0; el < 5; ++el)
|
||||
b1.ElementAt(el).Value = Random.Range(-10, 20);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7e1a5fbe08244f31abfa48fd361d61c8
|
||||
timeCreated: 1695636910
|
|
@ -0,0 +1,35 @@
|
|||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
|
||||
public struct TestCustomSerializer : IComponentData
|
||||
{
|
||||
public int numInstances;
|
||||
public float percentChunkChange;
|
||||
public float percentEntityChanges;
|
||||
public bool useCustomSerializer;
|
||||
public bool usePreserialization;
|
||||
}
|
||||
|
||||
public class TestCustomSerializerAuthoring : MonoBehaviour
|
||||
{
|
||||
public int numInstances;
|
||||
public int percentChunkChange;
|
||||
public int percentEntityChanges;
|
||||
public bool useCustomSerializer;
|
||||
public bool usePreserialization;
|
||||
|
||||
private class Baker : Unity.Entities.Baker<TestCustomSerializerAuthoring>
|
||||
{
|
||||
public override void Bake(TestCustomSerializerAuthoring customSerializerAuthoring)
|
||||
{
|
||||
AddComponent(GetEntity(TransformUsageFlags.None), new TestCustomSerializer
|
||||
{
|
||||
numInstances = customSerializerAuthoring.numInstances,
|
||||
percentChunkChange = customSerializerAuthoring.percentChunkChange*0.01f,
|
||||
percentEntityChanges = customSerializerAuthoring.percentEntityChanges*0.01f,
|
||||
useCustomSerializer = customSerializerAuthoring.useCustomSerializer,
|
||||
usePreserialization = customSerializerAuthoring.usePreserialization,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8a0aa95684d6490989bfb89e13358141
|
||||
timeCreated: 1695846542
|
|
@ -25,6 +25,11 @@ namespace Samples.HelloNetcode
|
|||
// The initialize method is what entities calls to create the default worlds
|
||||
public override bool Initialize(string defaultWorldName)
|
||||
{
|
||||
// If the user added an OverrideDefaultNetcodeBootstrap MonoBehaviour to their active scene,
|
||||
// or disabled Bootstrapping project-wide, we should respect that here.
|
||||
if (!DetermineIfBootstrappingEnabled())
|
||||
return false;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// If we are in the editor, we check if the loaded scene is "Frontend",
|
||||
// if we are in a player we assume it is in the frontend if FRONTEND_PLAYER_BUILD
|
||||
|
@ -41,7 +46,7 @@ namespace Samples.HelloNetcode
|
|||
{
|
||||
// This will enable auto connect. We only enable auto connect if we are not going through frontend.
|
||||
// The frontend will parse and validate the address before connecting manually.
|
||||
// Using this auto connect feature will deal with the client only connect address from Multiplayer PlayMode Tools
|
||||
// Using this auto connect feature will deal with the client only connect address from PlayMode Tools
|
||||
AutoConnectPort = 7979;
|
||||
|
||||
// Use "-port 8000" when running a build from commandline to specify the port to use
|
||||
|
@ -51,7 +56,7 @@ namespace Samples.HelloNetcode
|
|||
AutoConnectPort = UInt16.Parse(commandPort);
|
||||
|
||||
|
||||
// Create the default client and server worlds, depending on build type in a player or the Multiplayer PlayMode Tools in the editor
|
||||
// Create the default client and server worlds, depending on build type in a player or the PlayMode Tools in the editor
|
||||
CreateDefaultClientServerWorlds();
|
||||
}
|
||||
else
|
||||
|
|
|
@ -40,20 +40,17 @@ namespace Samples.HelloNetcode
|
|||
|
||||
public void Start()
|
||||
{
|
||||
foreach (var world in World.All)
|
||||
if (ClientServerBootstrap.ClientWorld != null)
|
||||
{
|
||||
if (world.IsClient() && !world.IsThinClient())
|
||||
{
|
||||
var sys = world.GetOrCreateSystemManaged<FrontendHUDSystem>();
|
||||
sys.UIBehaviour = this;
|
||||
var simGroup = world.GetExistingSystemManaged<SimulationSystemGroup>();
|
||||
simGroup.AddSystemToUpdateList(sys);
|
||||
}
|
||||
var sys = ClientServerBootstrap.ClientWorld.GetOrCreateSystemManaged<FrontendHUDSystem>();
|
||||
sys.UIBehaviour = this;
|
||||
var simGroup = ClientServerBootstrap.ClientWorld.GetExistingSystemManaged<SimulationSystemGroup>();
|
||||
simGroup.AddSystemToUpdateList(sys);
|
||||
}
|
||||
|
||||
// We must always have an event system (DOTS-7177), but some scenes will already have one,
|
||||
// so we only enable ours if we can't find someone else's.
|
||||
if (FindObjectOfType<UnityEngine.EventSystems.EventSystem>(false) == null)
|
||||
if (Object.FindFirstObjectByType<UnityEngine.EventSystems.EventSystem>() == null)
|
||||
m_EventSystem.gameObject.SetActive(true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
|
@ -9,22 +11,40 @@ namespace Samples.HelloNetcode
|
|||
void Start()
|
||||
{
|
||||
#if UNITY_SERVER
|
||||
string sceneName = "Asteroids";
|
||||
string defaultSceneName = "Asteroids";
|
||||
#else
|
||||
string sceneName = "Frontend";
|
||||
string defaultSceneName = "Frontend";
|
||||
#endif
|
||||
|
||||
// Commandline always overrides defaults if it exists
|
||||
string commandScene = CommandLineUtils.GetCommandLineValueFromKey("scene");
|
||||
if (!string.IsNullOrEmpty(commandScene))
|
||||
if (string.IsNullOrWhiteSpace(commandScene))
|
||||
{
|
||||
var scene = SceneManager.GetSceneByName(commandScene);
|
||||
|
||||
if (!scene.IsValid())
|
||||
Debug.LogWarning($"Scene '{commandScene}' not found, using default '{sceneName}' instead");
|
||||
SceneManager.LoadScene(defaultSceneName);
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < SceneManager.sceneCountInBuildSettings; ++i)
|
||||
{
|
||||
var scenePath = SceneUtility.GetScenePathByBuildIndex(i);
|
||||
var scene = Path.GetFileNameWithoutExtension(scenePath);
|
||||
if (commandScene == scene)
|
||||
{
|
||||
|
||||
SceneManager.LoadScene(sceneName);
|
||||
SceneManager.LoadScene(commandScene);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Debug.LogError($"${commandScene} not found. Scenes present in the build\n: {string.Join(',', GetAllScenesInBuild())}");
|
||||
Application.Quit(-1);
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetAllScenesInBuild()
|
||||
{
|
||||
|
||||
for (int i = 0; i < SceneManager.sceneCountInBuildSettings; ++i)
|
||||
{
|
||||
var scenePath = SceneUtility.GetScenePathByBuildIndex(i);
|
||||
yield return Path.GetFileNameWithoutExtension(scenePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,9 +25,7 @@ namespace Samples.HelloNetcode
|
|||
NetworkEndpoint m_Endpoint;
|
||||
NetworkConnection m_ClientConnection;
|
||||
public RelayServerData RelayClientData;
|
||||
#if !UNITY_SERVER
|
||||
public RelayFrontend UIBehaviour;
|
||||
#endif
|
||||
|
||||
[Flags]
|
||||
enum ClientStatus
|
||||
|
|
|
@ -25,9 +25,7 @@ namespace Samples.HelloNetcode
|
|||
[UpdateInGroup(typeof(SimulationSystemGroup))]
|
||||
public partial class HostServer : SystemBase
|
||||
{
|
||||
#if !UNITY_SERVER
|
||||
public RelayFrontend UIBehaviour;
|
||||
#endif
|
||||
const int RelayMaxConnections = 5;
|
||||
public string JoinCode;
|
||||
|
||||
|
@ -48,7 +46,6 @@ namespace Samples.HelloNetcode
|
|||
SigningIn,
|
||||
FailedToHost,
|
||||
Ready,
|
||||
GettingRegions,
|
||||
Allocating,
|
||||
GettingJoinCode,
|
||||
GetRelayData,
|
||||
|
@ -99,15 +96,7 @@ namespace Samples.HelloNetcode
|
|||
#if !UNITY_SERVER
|
||||
UIBehaviour.HostConnectionStatus = "Logging in anonymously";
|
||||
#endif
|
||||
m_HostStatus = WaitForSignIn(m_SignInTask, out m_RegionsTask);
|
||||
return;
|
||||
}
|
||||
case HostStatus.GettingRegions:
|
||||
{
|
||||
#if !UNITY_SERVER
|
||||
UIBehaviour.HostConnectionStatus = "Waiting for regions";
|
||||
#endif
|
||||
m_HostStatus = WaitForRegions(m_RegionsTask, out m_AllocationTask);
|
||||
m_HostStatus = WaitForSignIn(m_SignInTask, out m_AllocationTask);
|
||||
return;
|
||||
}
|
||||
case HostStatus.Allocating:
|
||||
|
@ -140,11 +129,11 @@ namespace Samples.HelloNetcode
|
|||
}
|
||||
}
|
||||
|
||||
static HostStatus WaitForSignIn(Task signInTask, out Task<List<Region>> regionTask)
|
||||
static HostStatus WaitForSignIn(Task signInTask, out Task<Allocation> allocationTask)
|
||||
{
|
||||
allocationTask = default;
|
||||
if (!signInTask.IsCompleted)
|
||||
{
|
||||
regionTask = default;
|
||||
return HostStatus.SigningIn;
|
||||
}
|
||||
|
||||
|
@ -152,13 +141,13 @@ namespace Samples.HelloNetcode
|
|||
{
|
||||
Debug.LogError("Signing in failed");
|
||||
Debug.LogException(signInTask.Exception);
|
||||
regionTask = default;
|
||||
return HostStatus.FailedToHost;
|
||||
}
|
||||
|
||||
// Request list of valid regions
|
||||
regionTask = RelayService.Instance.ListRegionsAsync();
|
||||
return HostStatus.GettingRegions;
|
||||
// Request an allocation to the Relay service
|
||||
// with a maximum of 5 peer connections, for a maximum of 6 players.
|
||||
allocationTask = RelayService.Instance.CreateAllocationAsync(RelayMaxConnections);
|
||||
return HostStatus.Allocating;
|
||||
}
|
||||
|
||||
static HostStatus WaitForInitialization(Task initializeTask, out Task nextTask)
|
||||
|
@ -249,32 +238,6 @@ namespace Samples.HelloNetcode
|
|||
return HostStatus.GettingJoinCode;
|
||||
}
|
||||
|
||||
static HostStatus WaitForRegions(Task<List<Region>> collectRegionTask, out Task<Allocation> allocationTask)
|
||||
{
|
||||
if (!collectRegionTask.IsCompleted)
|
||||
{
|
||||
allocationTask = null;
|
||||
return HostStatus.GettingRegions;
|
||||
}
|
||||
|
||||
if (collectRegionTask.IsFaulted)
|
||||
{
|
||||
Debug.LogError("List regions request failed");
|
||||
Debug.LogException(collectRegionTask.Exception);
|
||||
allocationTask = null;
|
||||
return HostStatus.FailedToHost;
|
||||
}
|
||||
|
||||
var regionList = collectRegionTask.Result;
|
||||
// pick a region from the list
|
||||
var targetRegion = regionList[0].Id;
|
||||
|
||||
// Request an allocation to the Relay service
|
||||
// with a maximum of 5 peer connections, for a maximum of 6 players.
|
||||
allocationTask = RelayService.Instance.CreateAllocationAsync(RelayMaxConnections, targetRegion);
|
||||
return HostStatus.Allocating;
|
||||
}
|
||||
|
||||
// connectionType also supports udp, but this is not recommended
|
||||
static RelayServerData HostRelayData(Allocation allocation, string connectionType = "dtls")
|
||||
{
|
||||
|
|
|
@ -31,12 +31,16 @@ namespace Samples.HelloNetcode
|
|||
{
|
||||
var settings = DefaultDriverBuilder.GetNetworkSettings();
|
||||
settings.WithRelayParameters(ref m_RelayClientData);
|
||||
DefaultDriverBuilder.RegisterClientUdpDriver(world, ref driverStore, netDebug, settings);
|
||||
DefaultDriverBuilder.RegisterClientDriver(world, ref driverStore, netDebug, settings);
|
||||
}
|
||||
|
||||
public void CreateServerDriver(World world, ref NetworkDriverStore driverStore, NetDebug netDebug)
|
||||
{
|
||||
#if !UNITY_WEBGL || UNITY_EDITOR
|
||||
DefaultDriverBuilder.RegisterServerDriver(world, ref driverStore, netDebug, ref m_RelayServerData);
|
||||
#else
|
||||
throw new System.NotSupportedException("It is not allowed to create a server NetworkDriver for WebGL build.");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#if !UNITY_SERVER
|
||||
using Unity.Entities;
|
||||
using Unity.NetCode;
|
||||
using Unity.Networking.Transport;
|
||||
using Unity.Networking.Transport.Relay;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
|
@ -18,7 +18,12 @@ namespace Samples.HelloNetcode
|
|||
/// A bootstrap world is constructed to run the jobs for setting up host and client configuration for relay server.
|
||||
/// Once this is done the game can be launched and the configuration can be retrieved from the constructed world.
|
||||
/// </summary>
|
||||
public class RelayFrontend : Frontend
|
||||
public class RelayFrontend :
|
||||
#if UNITY_SERVER
|
||||
MonoBehaviour
|
||||
#else
|
||||
Frontend
|
||||
#endif
|
||||
{
|
||||
public string HostConnectionStatus
|
||||
{
|
||||
|
@ -49,6 +54,7 @@ namespace Samples.HelloNetcode
|
|||
JoinLocalGame,
|
||||
}
|
||||
|
||||
#if !UNITY_SERVER
|
||||
public void OnRelayEnable(Toggle value)
|
||||
{
|
||||
TogglePersistentState(!value.isOn);
|
||||
|
@ -251,6 +257,6 @@ namespace Samples.HelloNetcode
|
|||
// For a locally hosted server, the client would need to connect to NetworkEndpoint.AnyIpv4, and the relayClientData.Endpoint in all other cases.
|
||||
client.EntityManager.SetComponentData(networkStreamEntity, new NetworkStreamRequestConnect { Endpoint = relayClientData.Endpoint });
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -28,9 +28,9 @@ RectTransform:
|
|||
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: 7958460717334784095}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
|
@ -67,10 +67,10 @@ MonoBehaviour:
|
|||
m_Calls: []
|
||||
m_FontData:
|
||||
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_FontSize: 14
|
||||
m_FontSize: 28
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 0
|
||||
m_MinSize: 10
|
||||
m_MinSize: 0
|
||||
m_MaxSize: 40
|
||||
m_Alignment: 4
|
||||
m_AlignByGeometry: 0
|
||||
|
@ -108,15 +108,15 @@ RectTransform:
|
|||
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:
|
||||
- {fileID: 7958460717230692451}
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: -364.76, y: 166}
|
||||
m_SizeDelta: {x: 100, y: 30}
|
||||
m_SizeDelta: {x: 300, y: 90}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &7958460717334784088
|
||||
CanvasRenderer:
|
||||
|
|
|
@ -25,3 +25,5 @@ To set up a disconnect timeout on the driver a custom/manual driver needs to be
|
|||
Try it with one thin client added in the playermode tools to see what messages are passed around when it is disconnected. Try making a standalone build with this sample (can be picked from frontend sample list) and then terminate the standalone process when testing to see the timeout event.
|
||||
|
||||
The UI is not set up to do anything fancy but just demonstrate connection events on disconnections.
|
||||
|
||||
Please take note of the descriptions beneath the buttons labeled `ServerWorld`, `ClientWorld`, and `ThinClientWorld`. These descriptions indicate the specific world in which the given connection is stored (the name of the connection is the number which we can disconnect). For instance, if we are testing this sample in the editor with a single ThinClient, you will observe this connection appearing twice: once in the `ThinClientWorld` and once in the `ServerWorld`. This duplication occurs because both of these worlds store the same connection. In another scenario, if the server is operational in the editor and we connect to it from a different build, you will notice that there is a connection in the editor for the `ServerWorld` and in the build for the `ClientWorld`.
|
||||
|
|
|
@ -38,7 +38,7 @@ RenderSettings:
|
|||
m_ReflectionIntensity: 1
|
||||
m_CustomReflection: {fileID: 0}
|
||||
m_Sun: {fileID: 0}
|
||||
m_IndirectSpecularColor: {r: 0.44657874, g: 0.49641275, b: 0.5748172, a: 1}
|
||||
m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1}
|
||||
m_UseRadianceAmbientProbe: 0
|
||||
--- !u!157 &3
|
||||
LightmapSettings:
|
||||
|
@ -104,7 +104,7 @@ NavMeshSettings:
|
|||
serializedVersion: 2
|
||||
m_ObjectHideFlags: 0
|
||||
m_BuildSettings:
|
||||
serializedVersion: 2
|
||||
serializedVersion: 3
|
||||
agentTypeID: 0
|
||||
agentRadius: 0.5
|
||||
agentHeight: 2
|
||||
|
@ -117,7 +117,7 @@ NavMeshSettings:
|
|||
cellSize: 0.16666667
|
||||
manualTileSize: 0
|
||||
tileSize: 256
|
||||
accuratePlacement: 0
|
||||
buildHeightMesh: 0
|
||||
maxJobWorkers: 0
|
||||
preserveTilesOutsideBounds: 0
|
||||
debug:
|
||||
|
@ -163,12 +163,13 @@ Transform:
|
|||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 225538412}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 417.63858, y: 192.56496, z: -5.0249343}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 5
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &420232002
|
||||
GameObject:
|
||||
|
@ -182,6 +183,7 @@ GameObject:
|
|||
- component: {fileID: 420232005}
|
||||
- component: {fileID: 420232004}
|
||||
- component: {fileID: 420232003}
|
||||
- component: {fileID: 420232007}
|
||||
m_Layer: 5
|
||||
m_Name: Canvas
|
||||
m_TagString: Untagged
|
||||
|
@ -218,11 +220,11 @@ MonoBehaviour:
|
|||
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_UiScaleMode: 0
|
||||
m_UiScaleMode: 1
|
||||
m_ReferencePixelsPerUnit: 100
|
||||
m_ScaleFactor: 1
|
||||
m_ReferenceResolution: {x: 800, y: 600}
|
||||
m_ScreenMatchMode: 0
|
||||
m_ReferenceResolution: {x: 1920, y: 1080}
|
||||
m_ScreenMatchMode: 1
|
||||
m_MatchWidthOrHeight: 0
|
||||
m_PhysicalUnit: 3
|
||||
m_FallbackScreenDPI: 96
|
||||
|
@ -246,7 +248,9 @@ Canvas:
|
|||
m_OverrideSorting: 0
|
||||
m_OverridePixelPerfect: 0
|
||||
m_SortingBucketNormalizedSize: 0
|
||||
m_VertexColorAlwaysGammaSpace: 0
|
||||
m_AdditionalShaderChannelsFlag: 0
|
||||
m_UpdateRectTransformForStandalone: 0
|
||||
m_SortingLayerID: 0
|
||||
m_SortingOrder: 0
|
||||
m_TargetDisplay: 0
|
||||
|
@ -260,15 +264,39 @@ RectTransform:
|
|||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 0, y: 0, z: 0}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 4
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0, y: 0}
|
||||
--- !u!114 &420232007
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 420232002}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 8a8695521f0d02e499659fee002a26c2, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Padding:
|
||||
m_Left: 0
|
||||
m_Right: 0
|
||||
m_Top: 0
|
||||
m_Bottom: 0
|
||||
m_ChildAlignment: 0
|
||||
m_StartCorner: 0
|
||||
m_StartAxis: 0
|
||||
m_CellSize: {x: 250, y: 150}
|
||||
m_Spacing: {x: 15, y: 15}
|
||||
m_Constraint: 0
|
||||
m_ConstraintCount: 2
|
||||
--- !u!1 &848706481
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -299,6 +327,7 @@ MonoBehaviour:
|
|||
m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_SendPointerHoverToParent: 1
|
||||
m_HorizontalAxis: Horizontal
|
||||
m_VerticalAxis: Vertical
|
||||
m_SubmitButton: Submit
|
||||
|
@ -328,12 +357,13 @@ Transform:
|
|||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 848706481}
|
||||
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_RootOrder: 2
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &1025617519
|
||||
GameObject:
|
||||
|
@ -345,6 +375,7 @@ GameObject:
|
|||
m_Component:
|
||||
- component: {fileID: 1025617521}
|
||||
- component: {fileID: 1025617520}
|
||||
- component: {fileID: 1025617522}
|
||||
m_Layer: 0
|
||||
m_Name: Directional Light
|
||||
m_TagString: Untagged
|
||||
|
@ -421,13 +452,37 @@ Transform:
|
|||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1025617519}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
|
||||
m_LocalPosition: {x: 0, y: 3, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 1
|
||||
m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
|
||||
--- !u!114 &1025617522
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1025617519}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Version: 3
|
||||
m_UsePipelineSettings: 1
|
||||
m_AdditionalLightsShadowResolutionTier: 2
|
||||
m_LightLayerMask: 1
|
||||
m_RenderingLayers: 1
|
||||
m_CustomShadowLayers: 0
|
||||
m_ShadowLayerMask: 1
|
||||
m_ShadowRenderingLayers: 1
|
||||
m_LightCookieSize: {x: 1, y: 1}
|
||||
m_LightCookieOffset: {x: 0, y: 0}
|
||||
m_SoftShadowQuality: 0
|
||||
--- !u!1 &1739351329
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -468,9 +523,17 @@ Camera:
|
|||
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_FocalLength: 50
|
||||
m_NormalizedViewPortRect:
|
||||
serializedVersion: 2
|
||||
x: 0
|
||||
|
@ -504,12 +567,13 @@ Transform:
|
|||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1739351329}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 1, z: -10}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &2020952715
|
||||
GameObject:
|
||||
|
@ -556,10 +620,21 @@ Transform:
|
|||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2020952715}
|
||||
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_RootOrder: 3
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1660057539 &9223372036854775807
|
||||
SceneRoots:
|
||||
m_ObjectHideFlags: 0
|
||||
m_Roots:
|
||||
- {fileID: 1739351332}
|
||||
- {fileID: 1025617521}
|
||||
- {fileID: 848706484}
|
||||
- {fileID: 2020952717}
|
||||
- {fileID: 420232006}
|
||||
- {fileID: 225538414}
|
||||
|
|
|
@ -11,7 +11,7 @@ using UnityEngine.UI;
|
|||
namespace Samples.HelloNetcode
|
||||
{
|
||||
[UpdateInGroup(typeof(HelloNetcodeSystemGroup))]
|
||||
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation | WorldSystemFilterFlags.ServerSimulation)]
|
||||
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation | WorldSystemFilterFlags.ServerSimulation | WorldSystemFilterFlags.ThinClientSimulation)]
|
||||
public partial class ConnectionMonitorSystem : SystemBase
|
||||
{
|
||||
private BeginSimulationEntityCommandBufferSystem m_CommandBufferSystem;
|
||||
|
@ -35,7 +35,7 @@ namespace Samples.HelloNetcode
|
|||
protected override void OnUpdate()
|
||||
{
|
||||
if (m_ConnectionUI == null)
|
||||
m_ConnectionUI = GameObject.FindObjectOfType<ConnectionUI>();
|
||||
m_ConnectionUI = GameObject.FindFirstObjectByType<ConnectionUI>();
|
||||
|
||||
var buffer = m_CommandBufferSystem.CreateCommandBuffer();
|
||||
Entities.WithName("AddConnectionStateToNewConnections").WithNone<ConnectionState>().ForEach((Entity entity,
|
||||
|
@ -45,6 +45,7 @@ namespace Samples.HelloNetcode
|
|||
}).Run();
|
||||
|
||||
FixedString32Bytes worldName = World.Name;
|
||||
var unmanagedWorld = World.Unmanaged;
|
||||
// Buttons are laid out in columns according to worlds, Server,ClientWorld0,ClientWorld1 and so on
|
||||
int worldIndex = 0;
|
||||
if (int.TryParse(World.Name[World.Name.Length - 1].ToString(), out worldIndex))
|
||||
|
@ -55,12 +56,15 @@ namespace Samples.HelloNetcode
|
|||
UnityEngine.Debug.Log($"[{worldName}] New connection ID:{id.Value}");
|
||||
|
||||
// Not thread safe, so all UI logic is kept on main thread
|
||||
ConnectionMonitorUIData.Connections.Data.Enqueue(new Connection(){Id = id.Value, WorldIndex = worldIndex, WorldName = worldName});
|
||||
ConnectionMonitorUIData.Connections.Data.Enqueue(new Connection(){Id = id.Value, WorldIndex = worldIndex, World = unmanagedWorld});
|
||||
}).Run();
|
||||
|
||||
Entities.WithName("HandleDisconnect").WithNone<NetworkStreamConnection>().ForEach((Entity entity, in ConnectionState state) =>
|
||||
{
|
||||
UnityEngine.Debug.Log($"[{worldName}] Connection disconnected ID:{state.NetworkId} Reason:{DisconnectReasonEnumToString.Convert((int)state.DisconnectReason)}");
|
||||
UnityEngine.Debug.Log($"[{worldName}] Connection disconnected ID:{state.NetworkId} Reason:{state.DisconnectReason.ToFixedString()}");
|
||||
|
||||
// Not thread safe, so all UI logic is kept on main thread
|
||||
ConnectionMonitorUIData.Connections.Data.Enqueue(new Connection(){Id = state.NetworkId, WorldIndex = worldIndex, World = unmanagedWorld, ConnectionDeleted = true});
|
||||
buffer.RemoveComponent<ConnectionState>(entity);
|
||||
}).Run();
|
||||
|
||||
|
@ -86,6 +90,15 @@ namespace Samples.HelloNetcode
|
|||
return settings;
|
||||
}
|
||||
|
||||
private void CreateDriver(out NetworkDriver driver, NetworkSettings settings)
|
||||
{
|
||||
#if !UNITY_WEBGL
|
||||
driver = NetworkDriver.Create(new UDPNetworkInterface(), settings);
|
||||
#else
|
||||
driver = NetworkDriver.Create(new WebSocketNetworkInterface(), settings);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void CreateClientDriver(World world, ref NetworkDriverStore driverStore, NetDebug netDebug)
|
||||
{
|
||||
var driverInstance = new NetworkDriverStore.NetworkDriverInstance();
|
||||
|
@ -95,17 +108,17 @@ namespace Samples.HelloNetcode
|
|||
if (NetworkSimulatorSettings.Enabled)
|
||||
{
|
||||
NetworkSimulatorSettings.SetSimulatorSettings(ref settings);
|
||||
driverInstance.driver = NetworkDriver.Create(new UDPNetworkInterface(), settings);
|
||||
CreateDriver(out driverInstance.driver, settings);
|
||||
DefaultDriverBuilder.CreateClientSimulatorPipelines(ref driverInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
driverInstance.driver = NetworkDriver.Create(new UDPNetworkInterface(), settings);
|
||||
CreateDriver(out driverInstance.driver, settings);
|
||||
DefaultDriverBuilder.CreateClientPipelines(ref driverInstance);
|
||||
}
|
||||
#else
|
||||
var settings = CreateNetworkSettings();
|
||||
driverInstance.driver = NetworkDriver.Create(new UDPNetworkInterface(), settings);
|
||||
CreateDriver(out driverInstance.driver, settings);
|
||||
DefaultDriverBuilder.CreateClientPipelines(ref driverInstance);
|
||||
#endif
|
||||
driverStore.RegisterDriver(TransportType.Socket, driverInstance);
|
||||
|
@ -113,11 +126,15 @@ namespace Samples.HelloNetcode
|
|||
|
||||
public void CreateServerDriver(World world, ref NetworkDriverStore driverStore, NetDebug netDebug)
|
||||
{
|
||||
#if UNITY_EDITOR || !UNITY_WEBGL
|
||||
var settings = CreateNetworkSettings();
|
||||
var driverInstance = new NetworkDriverStore.NetworkDriverInstance();
|
||||
driverInstance.driver = NetworkDriver.Create(new UDPNetworkInterface(), settings);
|
||||
CreateDriver(out driverInstance.driver, settings);
|
||||
DefaultDriverBuilder.CreateServerPipelines(ref driverInstance);
|
||||
driverStore.RegisterDriver(TransportType.Socket, driverInstance);
|
||||
#else
|
||||
throw new System.NotSupportedException("It is not allowed to create a server NetworkDriver for WebGL build.");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,7 +166,8 @@ namespace Samples.HelloNetcode
|
|||
{
|
||||
public int Id;
|
||||
public int WorldIndex;
|
||||
public FixedString32Bytes WorldName;
|
||||
public WorldUnmanaged World;
|
||||
public bool ConnectionDeleted;
|
||||
}
|
||||
|
||||
public abstract class ConnectionMonitorUIData
|
||||
|
|
|
@ -28,9 +28,9 @@ RectTransform:
|
|||
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_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
|
@ -67,10 +67,10 @@ MonoBehaviour:
|
|||
m_Calls: []
|
||||
m_FontData:
|
||||
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_FontSize: 14
|
||||
m_FontSize: 23
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 0
|
||||
m_MinSize: 10
|
||||
m_MinSize: 2
|
||||
m_MaxSize: 40
|
||||
m_Alignment: 1
|
||||
m_AlignByGeometry: 0
|
||||
|
|
|
@ -21,40 +21,46 @@ namespace Samples.HelloNetcode
|
|||
return;
|
||||
while (ConnectionMonitorUIData.Connections.Data.TryDequeue(out var con))
|
||||
{
|
||||
var buttonGo = UnityEngine.GameObject.Instantiate(m_Button, m_Canvas.transform, false);
|
||||
buttonGo.GetComponent<RectTransform>().anchoredPosition3D +=
|
||||
new Vector3(con.WorldIndex * m_VerticalSpace, (con.Id - 1) * m_HorizontalSpace, 0);
|
||||
buttonGo.name = $"{con.WorldIndex} {con.Id}";
|
||||
buttonGo.GetComponentInChildren<Text>().text = $"Disconnect {con.Id}";
|
||||
buttonGo.onClick.AddListener(() => Disconnect(con));
|
||||
if (con.ConnectionDeleted)
|
||||
{
|
||||
GameObject buttonToDelete = GameObject.Find(con.Id.ToString());
|
||||
if (buttonToDelete != null)
|
||||
{
|
||||
Destroy(buttonToDelete);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var parent = new GameObject(con.Id.ToString());
|
||||
parent.AddComponent<VerticalLayoutGroup>();
|
||||
parent.transform.SetParent(m_Canvas.transform);
|
||||
var buttonGo = Instantiate(m_Button, parent.transform, false);
|
||||
buttonGo.GetComponent<RectTransform>().anchoredPosition3D += new Vector3(con.WorldIndex * m_VerticalSpace, (con.Id - 1) * m_HorizontalSpace, 0);
|
||||
buttonGo.name = $"{con.WorldIndex} {con.Id}";
|
||||
buttonGo.GetComponentInChildren<Text>().text = $"Disconnect {con.Id}";
|
||||
buttonGo.onClick.AddListener(() => Disconnect(con));
|
||||
|
||||
var textGo = UnityEngine.GameObject.Instantiate(m_Text, m_Canvas.transform, false);
|
||||
textGo.GetComponent<RectTransform>().anchoredPosition3D +=
|
||||
new Vector3(con.WorldIndex * m_VerticalSpace, 0, 0);
|
||||
textGo.name = $"{con.WorldIndex} {con.Id}";
|
||||
textGo.text = con.WorldName.Value;
|
||||
var textGo = Instantiate(m_Text, parent.transform, false);
|
||||
textGo.GetComponent<RectTransform>().anchoredPosition3D += new Vector3(con.WorldIndex * m_VerticalSpace, 0, 0);
|
||||
textGo.name = $"{con.WorldIndex} {con.Id}";
|
||||
textGo.text = con.World.Name.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Disconnect(Connection con)
|
||||
{
|
||||
UnityEngine.Debug.Log($"[{con.WorldName}] Disconnecting {con.Id}");
|
||||
foreach (var world in World.All)
|
||||
{
|
||||
if (world.Name == con.WorldName)
|
||||
{
|
||||
var connection = world.EntityManager.CreateEntityQuery(ComponentType.ReadOnly<NetworkId>(),
|
||||
ComponentType.ReadOnly<NetworkStreamConnection>());
|
||||
var connectionIds = connection.ToComponentDataArray<NetworkId>(Allocator.Temp);
|
||||
var connectionEntities = connection.ToEntityArray(Allocator.Temp);
|
||||
for (int i = 0; i < connectionIds.Length; ++i)
|
||||
{
|
||||
if (connectionIds[i].Value == con.Id)
|
||||
world.EntityManager.AddComponent<NetworkStreamRequestDisconnect>(connectionEntities[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Debug.Log($"[{con.World.Name.Value}] Disconnecting {con.Id}");
|
||||
|
||||
var connection = con.World.EntityManager.CreateEntityQuery(ComponentType.ReadOnly<NetworkId>(),
|
||||
ComponentType.ReadOnly<NetworkStreamConnection>());
|
||||
var connectionIds = connection.ToComponentDataArray<NetworkId>(Allocator.Temp);
|
||||
var connectionEntities = connection.ToEntityArray(Allocator.Temp);
|
||||
for (int i = 0; i < connectionIds.Length; ++i)
|
||||
{
|
||||
if (connectionIds[i].Value == con.Id)
|
||||
con.World.EntityManager.AddComponent<NetworkStreamRequestDisconnect>(connectionEntities[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,26 +17,16 @@ namespace Samples.HelloNetcode
|
|||
public ScrollRect m_ScrollRect;
|
||||
public GameObject m_ChatWindowPrefab;
|
||||
|
||||
List<World> m_ClientWorlds = new List<World>();
|
||||
private int m_CurrentUserSlot = 0;
|
||||
private int m_UserSlotHorizontalSpace = -13;
|
||||
private int m_OwnUser = -1;
|
||||
|
||||
void Start()
|
||||
{
|
||||
foreach (var world in World.All)
|
||||
{
|
||||
if (world.IsClient() && !world.IsThinClient())
|
||||
m_ClientWorlds.Add(world);
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (m_OwnUser == -1)
|
||||
if (m_OwnUser == -1 && ClientServerBootstrap.ClientWorld != null)
|
||||
{
|
||||
// Non-thin client will always be first in the list
|
||||
var connectionQuery = m_ClientWorlds[0].EntityManager
|
||||
var connectionQuery = ClientServerBootstrap.ClientWorld.EntityManager
|
||||
.CreateEntityQuery(ComponentType.ReadOnly<NetworkId>());
|
||||
var connectionIds = connectionQuery.ToComponentDataArray<NetworkId>(Allocator.Temp);
|
||||
if (connectionIds.Length > 0)
|
||||
|
@ -76,8 +66,7 @@ namespace Samples.HelloNetcode
|
|||
|
||||
public void SendChatMessage()
|
||||
{
|
||||
if (m_ClientWorlds.Count > 0)
|
||||
SendRPC(m_ClientWorlds[0], m_InputText.text);
|
||||
SendRPC(ClientServerBootstrap.ClientWorld, m_InputText.text);
|
||||
// Clear the input text as the message has been sent, and place the UI focus back on it
|
||||
// so it's ready to accept the next message
|
||||
m_InputText.text = "";
|
||||
|
|
|
@ -17,6 +17,7 @@ GameObject:
|
|||
- component: {fileID: -8791223551774281384}
|
||||
- component: {fileID: 933197558220950793}
|
||||
- component: {fileID: 7756198234017677449}
|
||||
- component: {fileID: -7326952838053417493}
|
||||
m_Layer: 0
|
||||
m_Name: Player
|
||||
m_TagString: Untagged
|
||||
|
@ -184,3 +185,15 @@ MonoBehaviour:
|
|||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
ComponentOverrides: []
|
||||
--- !u!114 &-7326952838053417493
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5094733018780473589}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 6f0825796d5f408c90844cba5ba8fdcc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: PrespawnBarrel
|
||||
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords: []
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap:
|
||||
RenderType: Opaque
|
||||
disabledShaderPasses: []
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BaseMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _BumpMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailAlbedoMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailMask:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailNormalMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _EmissionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OcclusionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ParallaxMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _SpecGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_Lightmaps:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_LightmapsInd:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_ShadowMasks:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _AlphaClip: 0
|
||||
- _AlphaToMask: 0
|
||||
- _Blend: 0
|
||||
- _BlendModePreserveSpecular: 1
|
||||
- _BumpScale: 1
|
||||
- _ClearCoatMask: 0
|
||||
- _ClearCoatSmoothness: 0
|
||||
- _Cull: 2
|
||||
- _Cutoff: 0.5
|
||||
- _DetailAlbedoMapScale: 1
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _DstBlendAlpha: 0
|
||||
- _EnvironmentReflections: 1
|
||||
- _GlossMapScale: 0
|
||||
- _Glossiness: 0
|
||||
- _GlossyReflections: 0
|
||||
- _Metallic: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.005
|
||||
- _QueueOffset: 0
|
||||
- _ReceiveShadows: 1
|
||||
- _Smoothness: 0.5
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 1
|
||||
- _SrcBlendAlpha: 1
|
||||
- _Surface: 0
|
||||
- _WorkflowMode: 1
|
||||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _BaseColor: {r: 0.8113208, g: 0.8113208, b: 0.8113208, a: 1}
|
||||
- _Color: {r: 0.8113208, g: 0.8113208, b: 0.8113208, a: 1}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _SpecColor: {r: 0.2, g: 0.2, b: 0.2, a: 1}
|
||||
m_BuildTextureStacks: []
|
||||
--- !u!114 &8866395362223680394
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
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: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
version: 7
|
|
@ -1,8 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 83ca9d2de1b6dbc4db6df8360559b009
|
||||
guid: ecd6118a9f570c84aba37745783b8564
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 0
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -65,7 +65,7 @@ MeshRenderer:
|
|||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2}
|
||||
- {fileID: 2100000, guid: ecd6118a9f570c84aba37745783b8564, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: PrespawnBarrelChild
|
||||
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords: []
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap:
|
||||
RenderType: Opaque
|
||||
disabledShaderPasses: []
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BaseMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _BumpMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailAlbedoMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailMask:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailNormalMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _EmissionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OcclusionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ParallaxMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _SpecGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_Lightmaps:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_LightmapsInd:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_ShadowMasks:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _AlphaClip: 0
|
||||
- _AlphaToMask: 0
|
||||
- _Blend: 0
|
||||
- _BlendModePreserveSpecular: 1
|
||||
- _BumpScale: 1
|
||||
- _ClearCoatMask: 0
|
||||
- _ClearCoatSmoothness: 0
|
||||
- _Cull: 2
|
||||
- _Cutoff: 0.5
|
||||
- _DetailAlbedoMapScale: 1
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _DstBlendAlpha: 0
|
||||
- _EnvironmentReflections: 1
|
||||
- _GlossMapScale: 0
|
||||
- _Glossiness: 0
|
||||
- _GlossyReflections: 0
|
||||
- _Metallic: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.005
|
||||
- _QueueOffset: 0
|
||||
- _ReceiveShadows: 1
|
||||
- _Smoothness: 0.5
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 1
|
||||
- _SrcBlendAlpha: 1
|
||||
- _Surface: 0
|
||||
- _WorkflowMode: 1
|
||||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _BaseColor: {r: 0.26415092, g: 0.26415092, b: 0.26415092, a: 1}
|
||||
- _Color: {r: 0.26415092, g: 0.26415092, b: 0.26415092, a: 1}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _SpecColor: {r: 0.2, g: 0.2, b: 0.2, a: 1}
|
||||
m_BuildTextureStacks: []
|
||||
--- !u!114 &8866395362223680394
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
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: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
version: 7
|
|
@ -1,8 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9d4a6471a69208a499b9f55b8dedb016
|
||||
guid: a97404c336661364aa910059eb7f0d6c
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 0
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -30,6 +30,7 @@ Transform:
|
|||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: -0.42018604, y: -0.22284698, z: 0.57614875}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
|
@ -53,6 +54,7 @@ MeshRenderer:
|
|||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
|
@ -61,7 +63,7 @@ MeshRenderer:
|
|||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2}
|
||||
- {fileID: 2100000, guid: a97404c336661364aa910059eb7f0d6c, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
|
@ -91,8 +93,17 @@ CapsuleCollider:
|
|||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2142660659608484602}
|
||||
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: 1
|
||||
serializedVersion: 2
|
||||
m_Radius: 0.5000001
|
||||
m_Height: 2
|
||||
m_Direction: 1
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: PrespawnBarrelWithNestedChild
|
||||
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords: []
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap:
|
||||
RenderType: Opaque
|
||||
disabledShaderPasses: []
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BaseMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _BumpMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailAlbedoMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailMask:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailNormalMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _EmissionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OcclusionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ParallaxMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _SpecGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_Lightmaps:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_LightmapsInd:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_ShadowMasks:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _AlphaClip: 0
|
||||
- _AlphaToMask: 0
|
||||
- _Blend: 0
|
||||
- _BlendModePreserveSpecular: 1
|
||||
- _BumpScale: 1
|
||||
- _ClearCoatMask: 0
|
||||
- _ClearCoatSmoothness: 0
|
||||
- _Cull: 2
|
||||
- _Cutoff: 0.5
|
||||
- _DetailAlbedoMapScale: 1
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _DstBlendAlpha: 0
|
||||
- _EnvironmentReflections: 1
|
||||
- _GlossMapScale: 0
|
||||
- _Glossiness: 0
|
||||
- _GlossyReflections: 0
|
||||
- _Metallic: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.005
|
||||
- _QueueOffset: 0
|
||||
- _ReceiveShadows: 1
|
||||
- _Smoothness: 0.5
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 1
|
||||
- _SrcBlendAlpha: 1
|
||||
- _Surface: 0
|
||||
- _WorkflowMode: 1
|
||||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _BaseColor: {r: 0.09433961, g: 0.09433961, b: 0.09433961, a: 1}
|
||||
- _Color: {r: 0.09433961, g: 0.09433961, b: 0.09433961, a: 1}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _SpecColor: {r: 0.2, g: 0.2, b: 0.2, a: 1}
|
||||
m_BuildTextureStacks: []
|
||||
--- !u!114 &8866395362223680394
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
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: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
version: 7
|
|
@ -1,8 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 27ec74688746f5747923ac7d239c23a4
|
||||
guid: 73fb4638e69fcaf4fb164fefbecf8f22
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 0
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -67,7 +67,7 @@ MeshRenderer:
|
|||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2}
|
||||
- {fileID: 2100000, guid: 73fb4638e69fcaf4fb164fefbecf8f22, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче