IMPORTANT
The problem described here does not happen if I change my code as follows:
// var connectionEntity = networkStream.GetSingletonEntity<NetworkStreamConnection>();
var connectionEntity = networkStream.EntityManager.CreateEntityQuery(typeof(NetworkStreamConnection)).ToEntityArray(Allocator.Temp)[0];
This may suggest that there is actually a bug / restriction in specifically calling another system’s GetSingleton method.
END IMPORTANT
I am interested in creating two worlds for a multiplayer client: ApplicationWorld and ConnectedWorld. I would like the ApplicationWorld to store data that is persistent across the entire lifespan of the application whereas the ConnectedWorld only stores data that is necessary for the NetCode framework to sync this ConnectedWorld’s state to some remote server. Players may use the game as a browser to create and join different games hosted on different servers. As such, I thought the cleanest way to allow this was to simply store the entire world of the currently-connected client such that when the player leaves that game I can simply throw away the entire world ( and with it all its associated state which is no longer needed ).
I built exactly this system and was humming along until I tried to query data from the ConnectedWorld from a System associated with the ApplicationWorld. I have inserted code showing what I am doing to be clear although hopefully the details of it don’t distract from my more general goal of inspecting the data in 1 world to make decisions about changing the data in another world.
[RunAsClientMenuSystem]
[UpdateInWorld(UpdateInWorld.TargetWorld.Default)]
public class ClientMenuSystem : SystemBase {
World ClientWorld;
protected override void OnUpdate() {
var clientMenuStateEntity = GetSingletonEntity<ClientMenuState>();
var state = GetComponent<ClientMenuState>(clientMenuStateEntity);
if (connectingToServer) {
var networkStream = ClientWorld.GetExistingSystem<NetworkStreamReceiveSystem>();
var connectionEntity = networkStream.GetSingletonEntity<NetworkStreamConnection>();
if (ClientWorld.EntityManager.HasComponent<NetworkIdComponent>(connectionEntity)) {
var joinGameRequest = ClientWorld.EntityManager.CreateEntity();
var rpcCommandRequest = new SendRpcCommandRequestComponent {
TargetConnection = connectionEntity
};
ClientWorld.EntityManager.AddComponent<RpcJoinGame>(joinGameRequest);
ClientWorld.EntityManager.AddComponentData(joinGameRequest, rpcCommandRequest);
}
}
This code is partial to highlight the key details of what I am trying to do. Unity violently objects to the line var connectionEntity = networkStream.GetSingletonEntity<NetworkStreamConnection>() and produces the following cryptic error:
I am guessing that this is fundamentally about the fact that the two worlds maintain completely-separate dependency graphs for their updates and thus it is fundamentally unsafe to query the data from another world ( nevermind change it ).
Now, my question is: What should I do to elegantly organize my code if I CANNOT use multiple worlds w/ coordination?
I would like to easily be able to join and leave network games ( meaning connect to them and disconnect from them ) and I would like to easily blow away the state associated with those games. I don’t see a remotely elegant way to do this without simply deleting the un-needed world when it is no longer relevant.
Any help/insight/admonishment would be very helpful here and greatly appreciated.
Steve
