Also, if I do a build and try to start it when a client server setup is running in editor, then the just opened build crashes the editor.
How can I get rid of these errors and how can I test that the netcode works by making a build and connecting it to a server?
I’m on NetCode version 0.5 and latest Unity.
Clearly the Getting started has been working at some point as seen in this video.
When did the error start occurring, when you added the cube? Try following the “get started” and hitting “play” after you make the client/server connection and see if the error still appears.
So change [UpdateInGroup(typeof(ClientSimulationSystemGroup))] to [UpdateInGroup(typeof(GhostInputSystemGroup))] in SampleCubeInput and I think it might fix it.
@adammpolak Thanks for the good help.I don’t know why it still doesn’t work. Here is the code, but hard to say what is the issue since I tried removing code from both of the classes and the issues still persists
namespace Game.Netcode
{
[UpdateInGroup(typeof(GhostInputSystemGroup))]
public class SamplePlayerInput : ComponentSystem
{
protected override void OnCreate()
{
RequireSingletonForUpdate<NetworkIdComponent>();
}
protected override void OnUpdate()
{
var localInput = GetSingleton<CommandTargetComponent>().targetEntity;
if (localInput == Entity.Null)
{
var localPlayerId = GetSingleton<NetworkIdComponent>().Value;
Entities.WithAll<MovePlayerComponent>().WithNone<PlayerInput>().ForEach((Entity ent, ref GhostOwnerComponent ghostOwner) =>
{
if (ghostOwner.NetworkId == localPlayerId)
{
PostUpdateCommands.AddBuffer<PlayerInput>(ent);
PostUpdateCommands.SetComponent(GetSingletonEntity<CommandTargetComponent>(), new CommandTargetComponent {targetEntity = ent});
}
});
return;
}
var input = default(PlayerInput);
input.Tick = World.GetExistingSystem<ClientSimulationSystemGroup>().ServerTick;
if (Input.GetKey("a"))
input.horizontal -= 1;
if (Input.GetKey("d"))
input.horizontal += 1;
if (Input.GetKey("s"))
input.vertical -= 1;
if (Input.GetKey("w"))
input.vertical += 1;
var inputBuffer = EntityManager.GetBuffer<PlayerInput>(localInput);
inputBuffer.AddCommandData(input);
}
}
}
namespace Game.NetCode
{
[UpdateInGroup(typeof(GhostPredictionSystemGroup))]
public class MoveCubeSystem : ComponentSystem
{
protected override void OnCreate()
{
RequireSingletonForUpdate<NetworkIdComponent>();
}
protected override void OnUpdate()
{
var group = World.GetExistingSystem<GhostPredictionSystemGroup>();
var tick = group.PredictingTick;
var deltaTime = Time.DeltaTime;
Entities.ForEach((DynamicBuffer<PlayerInput> inputBuffer, ref Translation trans, ref MovePlayerComponent mp, ref PredictedGhostComponent prediction) =>
{
if (!GhostPredictionSystemGroup.ShouldPredict(tick, prediction))
{
return;
}
PlayerInput input;
inputBuffer.GetDataAtTick(tick, out input);
if (input.horizontal > 0)
{
trans.Value.x += deltaTime;
}
if (input.horizontal < 0)
{
trans.Value.x -= deltaTime;
}
if (input.vertical > 0)
{
trans.Value.z += deltaTime;
}
if (input.vertical < 0)
{
trans.Value.z -= deltaTime;
}
});
}
}
}
ok there is something weird. There is 2 entities with player component. On client side 1 entity is updating and on server side both entities that has that component are not updating. I don’t think this should be happening
@adammpolak I also add the code for adding these comonents.
GoInGameClientSystem
// When client has a connection with network id, go in game and tell server to also go in game
using Unity.Entities;
using Unity.NetCode;
using UnityEngine;
namespace Game.NetCode.Client
{
[UpdateInGroup(typeof(ClientSimulationSystemGroup))]
[DisableAutoCreation]
[AlwaysUpdateSystem]
public class GoInGameClientSystem : ComponentSystem
{
private bool multiPlayerGameStarted = false;
public bool MultiPlayerGameStarted
{
get { return multiPlayerGameStarted; }
set { multiPlayerGameStarted = value; }
}
protected override void OnCreate()
{
}
protected override void OnUpdate()
{
Entities.WithNone<NetworkStreamInGame>().ForEach((Entity ent, ref NetworkIdComponent id) =>
{
PostUpdateCommands.AddComponent<NetworkStreamInGame>(ent);
var req = PostUpdateCommands.CreateEntity();
PostUpdateCommands.AddComponent<GoInGameCommandRequest>(req);
PostUpdateCommands.AddComponent(req, new SendRpcCommandRequestComponent {TargetConnection = ent});
});
}
}
}
Go in game server system.
// When server receives go in game request, go in game and delete request
using System;
using Unity.Entities;
using Unity.NetCode;
using UnityEngine;
namespace Game.NetCode.Server
{
[UpdateInGroup(typeof(ServerSimulationSystemGroup))]
public class GoInGameServerSystem : ComponentSystem
{
private bool multiPlayerGameStarted = false;
public bool MultiPlayerGameStarted
{
get { return multiPlayerGameStarted; }
set { multiPlayerGameStarted = value; }
}
protected override void OnUpdate()
{
HandleIncomingGoInGameRequests();
}
private void HandleIncomingGoInGameRequests()
{
Entities.WithNone<SendRpcCommandRequestComponent>().ForEach(
(Entity reqEnt, ref GoInGameCommandRequest req, ref ReceiveRpcCommandRequestComponent reqSrc) =>
{
PostUpdateCommands.AddComponent<NetworkStreamInGame>(reqSrc.SourceConnection);
UnityEngine.Debug.Log(String.Format("Server setting connection {0} to in game",
EntityManager.GetComponentData<NetworkIdComponent>(reqSrc.SourceConnection).Value));
var ghostCollection = Entity.Null;
ghostCollection = GetSingletonEntity<GhostPrefabCollectionComponent>();
var prefab = Entity.Null;
var prefabs = EntityManager.GetBuffer<GhostPrefabBuffer>(ghostCollection);
for (int ghostId = 0; ghostId < prefabs.Length; ++ghostId)
{
if (EntityManager.HasComponent<MovePlayerComponent>(prefabs[ghostId].Value))
{
prefab = prefabs[ghostId].Value;
}
}
var player = EntityManager.Instantiate(prefab);
EntityManager.SetComponentData(player,
new GhostOwnerComponent
{
NetworkId = EntityManager.GetComponentData<NetworkIdComponent>(reqSrc.SourceConnection)
.Value
});
PostUpdateCommands.AddBuffer<PlayerInput>(player);
PostUpdateCommands.SetComponent(reqSrc.SourceConnection,
new CommandTargetComponent {targetEntity = player});
PostUpdateCommands.DestroyEntity(reqEnt);
});
}
}
}
I have added this to a button so the mp game can be started on request. Here is code for it from game manager class.
public void StartMultiPlayer()
{
foreach (var world in World.All)
{
if (world.Name== "ServerWorld")
{
App.View.ViewElements.StatsWindowText.text += "found server world" + "\n";
ServerWorld = world;
}
if (world.Name== "ClientWorld0")
{
App.View.ViewElements.StatsWindowText.text += "found client world" + "\n";
ClientWorld = world;
}
}
serverStart = World.DefaultGameObjectInjectionWorld.GetExistingSystem<GameInitConnection>();
serverStart.MultiPlayerGameStarted = true;
serverStart.Update();
server = ServerWorld.GetExistingSystem<GoInGameServerSystem>();
server.MultiPlayerGameStarted = true;
server.Update();
client = ClientWorld.GetOrCreateSystem<GoInGameClientSystem>();
client.MultiPlayerGameStarted = true;
client.Update();
GetComponent<LoadNetCodeSystemAndSubScene>().NetWorkScene.gameObject.GetComponent<SubScene>().enabled = true;
var playerCount = ServerWorld.GetOrCreateSystem<NetworkGameInformationRelay>().GetPlayerCount();
App.View.ViewElements.StatsWindowText.text += "Player count: " + playerCount + "\n";
}
Also I tried using it like in the getting started manual. Without button and the same issue still persists.
@adammpolak Maybe this is related to the subscene based loading. That is required. Its not documented, but when I did the getting started I got message to put the ghost collection inside subscene.
edit. I mean maybe separating the ghost collection group in to a subscene somehow breaks the connection between client and server system stream components(send and receive).
I made empty project and redid the getting started and its now working. Thanks for all the help.
I’ll try to move the other project content to the new. Weird there is no real difference other than the other has vr device added to the project.
@adammpolak Thanks for the tips!
I actually found out that source for the prediction errors is open-vr. Since the game I’m developing is a virtual reality game, I unfortunately cannot use the netcode. I submitted a bug report about this. http://fogbugz.unity3d.com/default.asp?1296576_3jh7gb2umqtmcagc
Anyways thanks for all the help for everyone involved!