The following logic will instantiate a character once, twice or thrice when connecting thin clients.
I really don’t understand this behavior.
How can I make the Instantiate only once?
Memo:
Charater 1" in the image is me(not ThinClient, this is Client).
Charater 2" and after is ThinClient.
For some reason, Character3 and Character4 are sometimes two and sometimes three.
Thanks in advance.
“com.unity.entities”: “1.2.3”,
“com.unity.entities.graphics”: “1.2.3”,
“com.unity.netcode”: “1.2.3”,
“com.unity.physics”: “1.2.3”,
using Unity.Burst;
using Unity.Entities;
using Unity.NetCode;
using Unity.Mathematics;
using Unity.Transforms;
using Unity.Collections;
[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)]
[UpdateInGroup(typeof(InitializationSystemGroup))]
[BurstCompile]
public partial struct GoInGameServerSystem : ISystem
{
[BurstCompile]
void OnCreate(ref SystemState state)
{
var builder = new EntityQueryBuilder(Allocator.Temp);
builder.WithAll<ReceiveRpcCommandRequest, ClientJoinRequest>();
state.RequireForUpdate(state.GetEntityQuery(builder));
}
[BurstCompile]
void OnUpdate(ref SystemState state)
{
if (SystemAPI.HasSingleton<PrefabsData>())
{
EntityCommandBuffer ecb = SystemAPI.GetSingletonRW<EndSimulationEntityCommandBufferSystem.Singleton>().ValueRW.CreateCommandBuffer(state.WorldUnmanaged);
// Get our PrefabsData singleton, which contains the prefabs we'll spawn
PrefabsData prefabsData = SystemAPI.GetSingleton<PrefabsData>();
// When a client wants to join, spawn and setup a character for them
foreach (var (receiveRPC, joinRequest, entity) in SystemAPI.Query<ReceiveRpcCommandRequest, ClientJoinRequest>().WithEntityAccess())
{
UnityEngine.Debug.Log("Processing ClientJoinRequest...");
// Spawn character, player, and camera ghost prefabs
Entity characterEntity = ecb.Instantiate(prefabsData.CharacterPrefab);
UnityEngine.Debug.Log("Instantiate Character");
// Add spawned prefabs to the connection entity's linked entities, so they get destroyed along with it
ecb.AppendToBuffer(receiveRPC.SourceConnection, new LinkedEntityGroup { Value = characterEntity });
// Setup the owners of the ghost prefabs (which are all owner-predicted)
// The owner is the client connection that sent the join request
int clientConnectionId = SystemAPI.GetComponent<NetworkId>(receiveRPC.SourceConnection).Value;
ecb.SetComponent(characterEntity, new GhostOwner { NetworkId = clientConnectionId });
// entityName
var entityName = "Character: " + clientConnectionId;
ecb.SetName(characterEntity, entityName);
// Place character at a random point around world origin
ecb.SetComponent(characterEntity, LocalTransform.FromPosition(new float3(0, 1, 0)));
// Allow this client to stream in game
ecb.AddComponent<NetworkStreamInGame>(receiveRPC.SourceConnection);
// Destroy the RPC since we've processed it
ecb.DestroyEntity(entity);
UnityEngine.Debug.Log("ClientJoinRequest processed and entity destroyed");
}
}
}
}
using Unity.Burst;
using Unity.Entities;
using Unity.NetCode;
using Unity.Collections;
public struct ClientJoinRequest : IRpcCommand { }
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation | WorldSystemFilterFlags.ThinClientSimulation)]
[UpdateInGroup(typeof(InitializationSystemGroup))]
[BurstCompile]
public partial struct GoInGameClientSystem : ISystem
{
[BurstCompile]
private void OnCreate(ref SystemState state)
{
var builder = new EntityQueryBuilder(Allocator.Temp);
builder.WithAll<NetworkId>().WithNone<NetworkStreamInGame>();
state.RequireForUpdate(state.GetEntityQuery(builder));
}
[BurstCompile]
void OnUpdate(ref SystemState state)
{
EntityCommandBuffer ecb = SystemAPI.GetSingletonRW<EndSimulationEntityCommandBufferSystem.Singleton>().ValueRW.CreateCommandBuffer(state.WorldUnmanaged);
// Send a join request to the server if we haven't done so yet
foreach (var (netId, entity) in SystemAPI.Query<NetworkId>().WithNone<NetworkStreamInGame>().WithEntityAccess())
{
// Mark our connection as ready to go in game
ecb.AddComponent(entity, new NetworkStreamInGame());
// Send an RPC that asks the server if we can join
Entity joinRPC = ecb.CreateEntity();
ecb.AddComponent(joinRPC, new ClientJoinRequest());
ecb.AddComponent(joinRPC, new SendRpcCommandRequest { TargetConnection = entity });
}
}
}