Netcode Bootstrap
This commit is contained in:
+22
@@ -0,0 +1,22 @@
|
||||
#if RUKHANKA_WITH_NETCODE
|
||||
|
||||
using Unity.NetCode;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka.Samples
|
||||
{
|
||||
|
||||
[UnityEngine.Scripting.Preserve]
|
||||
public class GameBootstrap : ClientServerBootstrap
|
||||
{
|
||||
public override bool Initialize(string defaultWorldName)
|
||||
{
|
||||
AutoConnectPort = 7979; // Enabled auto connect
|
||||
return base.Initialize(defaultWorldName); // Use the regular bootstrap
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bdfdae841942d834bb042df3854712d0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scenes/13. Netcode Demo/Scripts/Game.cs
|
||||
uploadId: 897522
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
#if RUKHANKA_WITH_NETCODE
|
||||
|
||||
using Unity.Collections;
|
||||
using Unity.Entities;
|
||||
using Unity.NetCode;
|
||||
using Unity.Burst;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Rukhanka.Samples
|
||||
{
|
||||
|
||||
public struct GoInGameRequest : IRpcCommand {}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[BurstCompile]
|
||||
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation | WorldSystemFilterFlags.ThinClientSimulation)]
|
||||
public partial struct GoInGameClientSystem : ISystem
|
||||
{
|
||||
[BurstCompile]
|
||||
public void OnCreate(ref SystemState state)
|
||||
{
|
||||
var builder = new EntityQueryBuilder(Allocator.Temp)
|
||||
.WithAll<NetworkId>()
|
||||
.WithNone<NetworkStreamInGame>();
|
||||
state.RequireForUpdate(state.GetEntityQuery(builder));
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public void OnUpdate(ref SystemState state)
|
||||
{
|
||||
var commandBuffer = new EntityCommandBuffer(Allocator.Temp);
|
||||
foreach (var (id, entity) in SystemAPI.Query<RefRO<NetworkId>>().WithEntityAccess().WithNone<NetworkStreamInGame>())
|
||||
{
|
||||
commandBuffer.AddComponent<NetworkStreamInGame>(entity);
|
||||
var req = commandBuffer.CreateEntity();
|
||||
commandBuffer.AddComponent<GoInGameRequest>(req);
|
||||
commandBuffer.AddComponent(req, new SendRpcCommandRequest { TargetConnection = entity });
|
||||
}
|
||||
commandBuffer.Playback(state.EntityManager);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[BurstCompile]
|
||||
[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)]
|
||||
public partial struct GoInGameServerSystem : ISystem
|
||||
{
|
||||
private ComponentLookup<NetworkId> networkIdFromEntity;
|
||||
|
||||
[BurstCompile]
|
||||
public void OnCreate(ref SystemState state)
|
||||
{
|
||||
var builder = new EntityQueryBuilder(Allocator.Temp)
|
||||
.WithAll<GoInGameRequest>()
|
||||
.WithAll<ReceiveRpcCommandRequest>();
|
||||
state.RequireForUpdate(state.GetEntityQuery(builder));
|
||||
networkIdFromEntity = state.GetComponentLookup<NetworkId>(true);
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public void OnUpdate(ref SystemState state)
|
||||
{
|
||||
var worldName = state.WorldUnmanaged.Name;
|
||||
var commandBuffer = new EntityCommandBuffer(Allocator.Temp);
|
||||
networkIdFromEntity.Update(ref state);
|
||||
|
||||
foreach (var (reqSrc, reqEntity) in SystemAPI.Query<RefRO<ReceiveRpcCommandRequest>>().WithAll<GoInGameRequest>().WithEntityAccess())
|
||||
{
|
||||
commandBuffer.AddComponent<NetworkStreamInGame>(reqSrc.ValueRO.SourceConnection);
|
||||
var networkId = networkIdFromEntity[reqSrc.ValueRO.SourceConnection];
|
||||
|
||||
Debug.Log($"'{worldName}' setting connection '{networkId.Value}' to in game");
|
||||
|
||||
commandBuffer.DestroyEntity(reqEntity);
|
||||
}
|
||||
|
||||
commandBuffer.Playback(state.EntityManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4576be8e57f3a0943ac7190f541f192a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scenes/13. Netcode Demo/Scripts/GoInGame.cs
|
||||
uploadId: 897522
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
#if RUKHANKA_WITH_NETCODE
|
||||
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Entities;
|
||||
using Unity.Mathematics;
|
||||
using Unity.NetCode;
|
||||
using Unity.Transforms;
|
||||
using static Unity.Entities.SystemAPI;
|
||||
using Random = Unity.Mathematics.Random;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka.Samples
|
||||
{
|
||||
|
||||
public struct ServerSpawnPrefabCommand: IRpcCommand
|
||||
{
|
||||
public int spawnCount;
|
||||
public float3 spawnerPos;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[BurstCompile]
|
||||
[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)]
|
||||
public partial struct ServerSpawnerSystem: ISystem
|
||||
{
|
||||
uint updateCounter;
|
||||
BufferLookup<AnimatorControllerParameterComponent> paramBufLookup;
|
||||
ComponentLookup<NetworkId> networkIdLookup;
|
||||
|
||||
EntityQuery prefabSpawners;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[BurstCompile]
|
||||
public void OnCreate(ref SystemState ss)
|
||||
{
|
||||
paramBufLookup = ss.GetBufferLookup<AnimatorControllerParameterComponent>();
|
||||
networkIdLookup = ss.GetComponentLookup<NetworkId>();
|
||||
|
||||
var eqb0 = new EntityQueryBuilder(Allocator.Temp)
|
||||
.WithAll<SpawnPrefabComponent, NetworkedPrefab>();
|
||||
prefabSpawners = ss.GetEntityQuery(eqb0);
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public void OnUpdate(ref SystemState ss)
|
||||
{
|
||||
var ecbs = GetSingleton<EndSimulationEntityCommandBufferSystem.Singleton>();
|
||||
var ecb = ecbs.CreateCommandBuffer(ss.WorldUnmanaged);
|
||||
FastAnimatorParameter animSpeed = new FastAnimatorParameter("Crowd_AnimationSpeed");
|
||||
|
||||
paramBufLookup.Update(ref ss);
|
||||
networkIdLookup.Update(ref ss);
|
||||
|
||||
var spawners = prefabSpawners.ToComponentDataArray<SpawnPrefabComponent>(Allocator.Temp);
|
||||
|
||||
foreach (var (c0, c1, e) in Query<RefRO<ServerSpawnPrefabCommand>, RefRO<ReceiveRpcCommandRequest>>().WithEntityAccess())
|
||||
{
|
||||
var spc = c0.ValueRO;
|
||||
var rpc = c1.ValueRO;
|
||||
var random = Random.CreateFromIndex(updateCounter++);
|
||||
|
||||
for (var i = 0; i < spc.spawnCount; ++i)
|
||||
{
|
||||
var spawner = spawners[(int)(random.NextUInt() % spawners.Length)];
|
||||
var entity = ss.EntityManager.Instantiate(spawner.prefabToSpawn);
|
||||
|
||||
var randomPos = random.NextFloat2() * 2 - 1;
|
||||
var position = new float3(randomPos.x, 0, randomPos.y) * spawner.spawnRadius;
|
||||
var rot = quaternion.RotateY(random.NextFloat() * math.PI * 2);
|
||||
var transform = ss.EntityManager.GetComponentData<LocalTransform>(entity);
|
||||
|
||||
transform.Position += position + spc.spawnerPos;
|
||||
transform.Rotation = rot;
|
||||
ecb.SetComponent(entity, transform);
|
||||
|
||||
var netId = networkIdLookup[rpc.SourceConnection];
|
||||
var go = new GhostOwner() { NetworkId = netId.Value };
|
||||
ecb.AddComponent(entity, go);
|
||||
ecb.AppendToBuffer(rpc.SourceConnection, new LinkedEntityGroup { Value = entity });
|
||||
|
||||
if (HasComponent<AnimatorControllerParameterIndexTableComponent>(entity))
|
||||
{
|
||||
var acpit = GetComponent<AnimatorControllerParameterIndexTableComponent>(entity);
|
||||
paramBufLookup.TryGetBuffer(entity, out var acpc);
|
||||
var randomSpeedVal = (random.NextFloat() * 2 - 1) * 0.5f + 1;
|
||||
animSpeed.SetRuntimeParameterData(acpit.value, acpc, new ParameterValue() { floatValue = randomSpeedVal } );
|
||||
}
|
||||
}
|
||||
ecb.DestroyEntity(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8dc2f39e57608d24bb029603c441358e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scenes/13. Netcode Demo/Scripts/ServerSpawner.cs
|
||||
uploadId: 897522
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
using TMPro;
|
||||
using Unity.Collections;
|
||||
using Unity.Entities;
|
||||
using Unity.Mathematics;
|
||||
#if RUKHANKA_WITH_NETCODE
|
||||
using Unity.NetCode;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka.Samples
|
||||
{
|
||||
class UIController_NetcodeDemo: MonoBehaviour
|
||||
{
|
||||
public TextMeshProUGUI spawnCountLabel;
|
||||
public TextMeshProUGUI localObjectsCountLabel;
|
||||
public TextMeshProUGUI predictedGhostCountLabel;
|
||||
public TextMeshProUGUI interpolatedGhostCountLabel;
|
||||
public TextMeshProUGUI descriptionLabel;
|
||||
public Slider spawnCountSlider;
|
||||
public Button spawnNetworkedBtn;
|
||||
public Button spawnLocalBtn;
|
||||
|
||||
EntityQuery spawnerQuery, connectionQuery, localObjectsQuery, predictedGhostObjectsQuery, interpolatedGhostObjectsQuery;
|
||||
EntityManager em;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Start()
|
||||
{
|
||||
#if !RUKHANKA_WITH_NETCODE
|
||||
descriptionLabel.text += $"\n\n<color=red>This sample is intended to work with 'Netcode for Entites' package and RUKHANKA_WITH_NETCODE script symbol defined! </color>";
|
||||
#endif
|
||||
|
||||
spawnNetworkedBtn.onClick.AddListener(SpawnNetworkedPrefabs);
|
||||
spawnLocalBtn.onClick.AddListener(SpawnLocalPrefabs);
|
||||
|
||||
var worlds = World.All;
|
||||
foreach (var w in worlds)
|
||||
{
|
||||
if (RukhankaSystemsBootstrap.IsClientOrLocalSimulationWorld(w))
|
||||
{
|
||||
em = w.EntityManager;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var ecb0 = new EntityQueryBuilder(Allocator.Temp)
|
||||
.WithAll<SpawnPrefabComponent>()
|
||||
.WithNone<NetworkedPrefab>();
|
||||
spawnerQuery = em.CreateEntityQuery(ecb0);
|
||||
|
||||
var ecb1 = new EntityQueryBuilder(Allocator.Temp)
|
||||
#if RUKHANKA_WITH_NETCODE
|
||||
.WithAll<NetworkId>()
|
||||
#endif
|
||||
;
|
||||
connectionQuery = em.CreateEntityQuery(ecb1);
|
||||
|
||||
var ecb2 = new EntityQueryBuilder(Allocator.Temp)
|
||||
.WithAll<AnimatorControllerLayerComponent>()
|
||||
#if RUKHANKA_WITH_NETCODE
|
||||
.WithNone<GhostInstance>()
|
||||
#endif
|
||||
;
|
||||
localObjectsQuery = em.CreateEntityQuery(ecb2);
|
||||
|
||||
var ecb3 = new EntityQueryBuilder(Allocator.Temp)
|
||||
.WithAll<AnimatorControllerLayerComponent>()
|
||||
#if RUKHANKA_WITH_NETCODE
|
||||
.WithAll<PredictedGhost>()
|
||||
#endif
|
||||
;
|
||||
predictedGhostObjectsQuery = em.CreateEntityQuery(ecb3);
|
||||
|
||||
var ecb4 = new EntityQueryBuilder(Allocator.Temp)
|
||||
.WithAll<AnimatorControllerLayerComponent>()
|
||||
#if RUKHANKA_WITH_NETCODE
|
||||
.WithNone<PredictedGhost>()
|
||||
.WithAll<GhostInstance>()
|
||||
#endif
|
||||
;
|
||||
interpolatedGhostObjectsQuery = em.CreateEntityQuery(ecb4);
|
||||
|
||||
#if !RUKHANKA_WITH_NETCODE
|
||||
predictedGhostCountLabel.enabled = false;
|
||||
interpolatedGhostCountLabel.enabled = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SpawnLocalPrefabs()
|
||||
{
|
||||
var spawners = spawnerQuery.ToEntityArray(Allocator.Temp);
|
||||
|
||||
var alreadySpawned = 0;
|
||||
var spawnCount = (int)math.max(1, spawnCountSlider.value / spawners.Length);
|
||||
for (var i = 0; i < spawners.Length && alreadySpawned < spawnCountSlider.value; ++i)
|
||||
{
|
||||
var scc = new SpawnCommandComponent()
|
||||
{
|
||||
spawnCount = i == spawners.Length - 1 ? (int)spawnCountSlider.value - alreadySpawned : spawnCount
|
||||
};
|
||||
alreadySpawned += scc.spawnCount;
|
||||
|
||||
em.AddComponentData(spawners[i], scc);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SpawnNetworkedPrefabs()
|
||||
{
|
||||
#if RUKHANKA_WITH_NETCODE
|
||||
var connection = connectionQuery.ToEntityArray(Allocator.Temp);
|
||||
|
||||
if (!connection.IsCreated || connection.Length == 0)
|
||||
{
|
||||
Debug.LogError($"Cannot send spawn command! No server connection!");
|
||||
return;
|
||||
}
|
||||
|
||||
var scc = new ServerSpawnPrefabCommand()
|
||||
{
|
||||
spawnerPos = float3.zero,
|
||||
spawnCount = (int)spawnCountSlider.value
|
||||
};
|
||||
|
||||
var e = em.CreateEntity();
|
||||
em.AddComponentData(e, scc);
|
||||
var rpc = new SendRpcCommandRequest() { TargetConnection = connection[0]};
|
||||
em.AddComponentData(e, rpc);
|
||||
#endif
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Update()
|
||||
{
|
||||
spawnCountLabel.text = $"{spawnCountSlider.value}";
|
||||
var localObjectsCount = localObjectsQuery.CalculateEntityCount();
|
||||
localObjectsCountLabel.text = $"Local objects count: {localObjectsCount}";
|
||||
#if RUKHANKA_WITH_NETCODE
|
||||
var predictedGhostCount = predictedGhostObjectsQuery.CalculateEntityCount();
|
||||
predictedGhostCountLabel.text = $"Predicted ghosts count: {predictedGhostCount}";
|
||||
var interpolatedGhostsCount = interpolatedGhostObjectsQuery.CalculateEntityCount();
|
||||
interpolatedGhostCountLabel.text = $"Interpolated ghosts count: {interpolatedGhostsCount}";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6124b89967d417b4ba756adbf28d1bf4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scenes/13. Netcode Demo/Scripts/UIController_NetcodeDemo.cs
|
||||
uploadId: 897522
|
||||
Reference in New Issue
Block a user