void VerifyGhostValues(NetCodeTestWorld testWorld)
        {
            var serverEntity = testWorld.TryGetSingletonEntity <GhostValueSerializer>(testWorld.ServerWorld);
            var clientEntity = testWorld.TryGetSingletonEntity <GhostValueSerializer>(testWorld.ClientWorlds[0]);

            Assert.AreNotEqual(Entity.Null, serverEntity);
            Assert.AreNotEqual(Entity.Null, clientEntity);

            var serverValues = testWorld.ServerWorld.EntityManager.GetComponentData <GhostValueSerializer>(serverEntity);
            var clientValues = testWorld.ClientWorlds[0].EntityManager.GetComponentData <GhostValueSerializer>(clientEntity);

            Assert.AreEqual(serverValues.BoolValue, clientValues.BoolValue);
            Assert.AreEqual(serverValues.IntValue, clientValues.IntValue);
            Assert.AreEqual(serverValues.FloatValue, clientValues.FloatValue);
            Assert.AreEqual(serverValues.UnquantizedFloatValue, clientValues.UnquantizedFloatValue);

            Assert.AreEqual(serverValues.Float2Value, clientValues.Float2Value);
            Assert.AreEqual(serverValues.UnquantizedFloat2Value, clientValues.UnquantizedFloat2Value);
            Assert.AreEqual(serverValues.Float3Value, clientValues.Float3Value);
            Assert.AreEqual(serverValues.UnquantizedFloat3Value, clientValues.UnquantizedFloat3Value);
            Assert.AreEqual(serverValues.Float4Value, clientValues.Float4Value);
            Assert.AreEqual(serverValues.UnquantizedFloat4Value, clientValues.UnquantizedFloat4Value);
            Assert.Less(math.distance(serverValues.QuaternionValue.value, clientValues.QuaternionValue.value), 0.001f);
            Assert.AreEqual(serverValues.UnquantizedQuaternionValue, clientValues.UnquantizedQuaternionValue);

            Assert.AreEqual(serverValues.StringValue32, clientValues.StringValue32);
            Assert.AreEqual(serverValues.StringValue64, clientValues.StringValue64);
            Assert.AreEqual(serverValues.StringValue128, clientValues.StringValue128);
            Assert.AreEqual(serverValues.StringValue512, clientValues.StringValue512);
            Assert.AreEqual(serverValues.StringValue4096, clientValues.StringValue4096);

            Assert.AreEqual(serverEntity, serverValues.EntityValue);
            Assert.AreEqual(clientEntity, clientValues.EntityValue);
        }
Ejemplo n.º 2
0
        public void CanRecoverFromDeletingGhostOnClient()
        {
            using (var testWorld = new NetCodeTestWorld())
            {
                DeleteGhostOnClientSystem.s_DeleteCount = 1;
                testWorld.Bootstrap(true, typeof(DeleteGhostOnClientSystem));

                var ghostGameObject = new GameObject();
                ghostGameObject.AddComponent <TestNetCodeAuthoring>().Converter = new InvalidUsageConverter();

                Assert.IsTrue(testWorld.CreateGhostCollection(ghostGameObject));

                testWorld.CreateWorlds(true, 1);

                testWorld.SpawnOnServer(ghostGameObject);

                var serverEnt = testWorld.TryGetSingletonEntity <GhostOwnerComponent>(testWorld.ServerWorld);
                testWorld.ServerWorld.EntityManager.SetComponentData(serverEnt, new GhostOwnerComponent {
                    NetworkId = 42
                });

                float frameTime = 1.0f / 60.0f;
                // Connect and make sure the connection could be established
                Assert.IsTrue(testWorld.Connect(frameTime, 4));

                // Go in-game
                testWorld.GoInGame();

                LogAssert.Expect(LogType.Error, new Regex("Found a ghost in the ghost map which does not have an entity connected to it. This can happen if you delete ghost entities on the client."));
                LogAssert.Expect(LogType.Error, new Regex("Ghost ID \\d+ has already been added to the spawned ghost map"));
                // Let the game run for a bit so the ghosts are spawned on the client
                for (int i = 0; i < 64; ++i)
                {
                    testWorld.Tick(frameTime);
                }

                // Validate that the ghost was deleted on the cliet
                Assert.AreEqual(0, DeleteGhostOnClientSystem.s_DeleteCount);

                // Check that the client world has the right thing and value
                var clientEnt = testWorld.TryGetSingletonEntity <GhostOwnerComponent>(testWorld.ClientWorlds[0]);
                Assert.AreNotEqual(Entity.Null, clientEnt);
                Assert.AreEqual(42, testWorld.ClientWorlds[0].EntityManager.GetComponentData <GhostOwnerComponent>(clientEnt).NetworkId);

                // Delete on server
                testWorld.ServerWorld.EntityManager.DestroyEntity(serverEnt);
                for (int i = 0; i < 4; ++i)
                {
                    testWorld.Tick(frameTime);
                }
                clientEnt = testWorld.TryGetSingletonEntity <GhostOwnerComponent>(testWorld.ClientWorlds[0]);
                Assert.AreEqual(Entity.Null, clientEnt);
            }
        }
        public void EntityMarkedAsChildIsSentAsPartOfGroup()
        {
            using (var testWorld = new NetCodeTestWorld())
            {
                testWorld.Bootstrap(true);

                var ghostGameObject = new GameObject();
                ghostGameObject.name = "ParentGhost";
                ghostGameObject.AddComponent <TestNetCodeAuthoring>().Converter = new GhostGroupGhostConverter();
                var childGhostGameObject = new GameObject();
                childGhostGameObject.name = "ChildGhost";
                childGhostGameObject.AddComponent <TestNetCodeAuthoring>().Converter = new GhostGroupGhostConverter();

                Assert.IsTrue(testWorld.CreateGhostCollection(ghostGameObject, childGhostGameObject));

                testWorld.CreateWorlds(true, 1);

                testWorld.SpawnOnServer(ghostGameObject);
                testWorld.SpawnOnServer(childGhostGameObject);

                var serverEnt      = testWorld.TryGetSingletonEntity <GhostGroupRoot>(testWorld.ServerWorld);
                var serverChildEnt = testWorld.TryGetSingletonEntity <GhostChildEntityComponent>(testWorld.ServerWorld);
                testWorld.ServerWorld.EntityManager.SetComponentData(serverEnt, new GhostOwnerComponent {
                    NetworkId = 42
                });
                testWorld.ServerWorld.EntityManager.SetComponentData(serverChildEnt, new GhostOwnerComponent {
                    NetworkId = 43
                });
                testWorld.ServerWorld.EntityManager.GetBuffer <GhostGroup>(serverEnt).Add(new GhostGroup {
                    Value = serverChildEnt
                });

                float frameTime = 1.0f / 60.0f;
                // Connect and make sure the connection could be established
                Assert.IsTrue(testWorld.Connect(frameTime, 4));

                // Go in-game
                testWorld.GoInGame();

                // Let the game run for a bit so the ghosts are spawned on the client
                for (int i = 0; i < 64; ++i)
                {
                    testWorld.Tick(frameTime);
                }

                // Check that the client world has the right thing and value
                var clientEnt      = testWorld.TryGetSingletonEntity <GhostGroupRoot>(testWorld.ClientWorlds[0]);
                var clientChildEnt = testWorld.TryGetSingletonEntity <GhostChildEntityComponent>(testWorld.ClientWorlds[0]);
                Assert.AreEqual(42, testWorld.ClientWorlds[0].EntityManager.GetComponentData <GhostOwnerComponent>(clientEnt).NetworkId);
                Assert.AreNotEqual(Entity.Null, clientChildEnt);
                Assert.AreEqual(43, testWorld.ClientWorlds[0].EntityManager.GetComponentData <GhostOwnerComponent>(clientChildEnt).NetworkId);
            }
        }
        public void ChildEntityDataIsReplicated()
        {
            using (var testWorld = new NetCodeTestWorld())
            {
                testWorld.Bootstrap(true);

                var ghostGameObject = new GameObject();
                ghostGameObject.AddComponent <TestNetCodeAuthoring>().Converter = new MultiEntityGhostConverter();
                var childGhost = new GameObject();
                childGhost.transform.parent = ghostGameObject.transform;
                childGhost.AddComponent <TestNetCodeAuthoring>().Converter = new MultiEntityGhostConverter();

                Assert.IsTrue(testWorld.CreateGhostCollection(ghostGameObject));

                testWorld.CreateWorlds(true, 1);

                testWorld.SpawnOnServer(ghostGameObject);

                var serverEnt = testWorld.TryGetSingletonEntity <TopLevelGhostEntity>(testWorld.ServerWorld);
                Assert.IsTrue(testWorld.ServerWorld.EntityManager.HasComponent <LinkedEntityGroup>(serverEnt));
                var serverEntityGroup = testWorld.ServerWorld.EntityManager.GetBuffer <LinkedEntityGroup>(serverEnt);
                Assert.AreEqual(2, serverEntityGroup.Length);
                testWorld.ServerWorld.EntityManager.SetComponentData(serverEntityGroup[0].Value, new GhostOwnerComponent {
                    NetworkId = 42
                });
                testWorld.ServerWorld.EntityManager.SetComponentData(serverEntityGroup[1].Value, new GhostOwnerComponent {
                    NetworkId = 42
                });

                float frameTime = 1.0f / 60.0f;
                // Connect and make sure the connection could be established
                Assert.IsTrue(testWorld.Connect(frameTime, 4));

                // Go in-game
                testWorld.GoInGame();

                // Let the game run for a bit so the ghosts are spawned on the client
                for (int i = 0; i < 64; ++i)
                {
                    testWorld.Tick(frameTime);
                }

                // Check that the client world has the right thing and value
                var clientEnt = testWorld.TryGetSingletonEntity <TopLevelGhostEntity>(testWorld.ClientWorlds[0]);
                Assert.IsTrue(testWorld.ClientWorlds[0].EntityManager.HasComponent <LinkedEntityGroup>(clientEnt));
                var clientEntityGroup = testWorld.ClientWorlds[0].EntityManager.GetBuffer <LinkedEntityGroup>(clientEnt);
                Assert.AreEqual(2, clientEntityGroup.Length);
                Assert.AreEqual(42, testWorld.ClientWorlds[0].EntityManager.GetComponentData <GhostOwnerComponent>(clientEntityGroup[0].Value).NetworkId);
                Assert.AreEqual(42, testWorld.ClientWorlds[0].EntityManager.GetComponentData <GhostOwnerComponent>(clientEntityGroup[1].Value).NetworkId);
            }
        }
        public void GhostCollectionGenerateSameHashOnClientAndServer()
        {
            using (var testWorld = new NetCodeTestWorld())
            {
                var ghost1 = new GameObject();
                ghost1.AddComponent <TestNetCodeAuthoring>().Converter           = new TestConverter();
                ghost1.AddComponent <GhostAuthoringComponent>().DefaultGhostMode = GhostAuthoringComponent.GhostMode.Predicted;
                var ghost2 = new GameObject();
                ghost2.AddComponent <TestNetCodeAuthoring>().Converter           = new TestConverter();
                ghost2.AddComponent <GhostAuthoringComponent>().DefaultGhostMode = GhostAuthoringComponent.GhostMode.Interpolated;

                testWorld.Bootstrap(true);
                testWorld.CreateGhostCollection(ghost1, ghost2);

                testWorld.CreateWorlds(true, 1);
                float frameTime = 1.0f / 60.0f;
                var   serverCollectionSystem = testWorld.ServerWorld.GetExistingSystem <GhostCollectionSystem>();
                var   clientCollectionSystem = testWorld.ClientWorlds[0].GetExistingSystem <GhostCollectionSystem>();
                //First tick: compute on both client and server the ghost collection hash
                testWorld.Tick(frameTime);
                Assert.AreEqual(serverCollectionSystem.CalculateComponentCollectionHash(), clientCollectionSystem.CalculateComponentCollectionHash());

                // compare the list of loaded prefabs
                var serverCollectionSingleton = testWorld.TryGetSingletonEntity <GhostCollection>(testWorld.ServerWorld);
                var clientCollectionSingleton = testWorld.TryGetSingletonEntity <GhostCollection>(testWorld.ClientWorlds[0]);
                Assert.AreNotEqual(Entity.Null, serverCollectionSingleton);
                Assert.AreNotEqual(Entity.Null, clientCollectionSingleton);
                var serverCollection = testWorld.ServerWorld.EntityManager.GetBuffer <GhostCollectionPrefab>(serverCollectionSingleton);
                var clientCollection = testWorld.ClientWorlds[0].EntityManager.GetBuffer <GhostCollectionPrefab>(clientCollectionSingleton);
                Assert.AreEqual(serverCollection.Length, clientCollection.Length);
                for (int i = 0; i < serverCollection.Length; ++i)
                {
                    Assert.AreEqual(serverCollection[i].GhostType, clientCollection[i].GhostType);
                    Assert.AreEqual(serverCollection[i].Hash, clientCollection[i].Hash);
                }

                //Check that and server can connect (same component hash)
                Assert.IsTrue(testWorld.Connect(frameTime, 4));

                testWorld.GoInGame();
                for (int i = 0; i < 10; ++i)
                {
                    testWorld.Tick(frameTime);
                }

                Assert.IsTrue(testWorld.ClientWorlds[0].GetExistingSystem <NetworkStreamReceiveSystem>()
                              .HasSingleton <NetworkIdComponent>());
            }
        }
        public void EntityReferenceSetAtSpawnIsResolved()
        {
            using (var testWorld = new NetCodeTestWorld())
            {
                testWorld.Bootstrap(true);

                var ghostGameObject = new GameObject();
                ghostGameObject.AddComponent <TestNetCodeAuthoring>().Converter = new GhostValueSerializerConverter();
                var referencedGameObject = new GameObject();
                referencedGameObject.AddComponent <GhostOwnerComponentAuthoring>();

                Assert.IsTrue(testWorld.CreateGhostCollection(ghostGameObject, referencedGameObject));

                testWorld.CreateWorlds(true, 1);

                float frameTime = 1.0f / 60.0f;
                // Connect and make sure the connection could be established
                Assert.IsTrue(testWorld.Connect(frameTime, 4));

                // Go in-game
                testWorld.GoInGame();
                for (int i = 0; i < 4; ++i)
                {
                    testWorld.Tick(frameTime);
                }

                var serverRefEntity = testWorld.SpawnOnServer(referencedGameObject);
                var serverEnt       = testWorld.SpawnOnServer(ghostGameObject);
                testWorld.ServerWorld.EntityManager.SetComponentData(serverEnt, new GhostValueSerializer {
                    EntityValue = serverRefEntity
                });

                // Let the game run for a bit so the ghosts are spawned on the client
                for (int i = 0; i < 8; ++i)
                {
                    testWorld.Tick(frameTime);
                    var clientRefEntity = testWorld.TryGetSingletonEntity <GhostOwnerComponent>(testWorld.ClientWorlds[0]);
                    var clientEntity    = testWorld.TryGetSingletonEntity <GhostValueSerializer>(testWorld.ClientWorlds[0]);
                    if (clientEntity != Entity.Null)
                    {
                        // Make sure the reference always exist if the ghost exists
                        Assert.AreEqual(clientRefEntity, testWorld.ClientWorlds[0].EntityManager.GetComponentData <GhostValueSerializer>(clientEntity).EntityValue);
                    }
                }
                // Verify that we did get the referenced entity at some point
                Assert.AreNotEqual(Entity.Null, testWorld.TryGetSingletonEntity <GhostOwnerComponent>(testWorld.ClientWorlds[0]));
            }
        }
        public void StaticGhostsAreNotApplied()
        {
            using (var testWorld = new NetCodeTestWorld())
            {
                testWorld.Bootstrap(true);

                SetupBasicTest(testWorld);

                var clientEnt = testWorld.TryGetSingletonEntity <GhostOwnerComponent>(testWorld.ClientWorlds[0]);
                Assert.AreNotEqual(Entity.Null, clientEnt);

                var clientEntityManager = testWorld.ClientWorlds[0].EntityManager;

                // Write some data to a ghost field and verify that it was not touched by the ghost apply
                clientEntityManager.SetComponentData(clientEnt, new GhostOwnerComponent {
                    NetworkId = 42
                });

                // Run a bit longer
                for (int i = 0; i < 16; ++i)
                {
                    testWorld.Tick(frameTime);
                }

                Assert.AreEqual(42, clientEntityManager.GetComponentData <GhostOwnerComponent>(clientEnt).NetworkId);
            }
        }
        void SetGhostValues(NetCodeTestWorld testWorld, int baseValue)
        {
            var serverEntity = testWorld.TryGetSingletonEntity <GhostValueSerializer>(testWorld.ServerWorld);

            Assert.AreNotEqual(Entity.Null, serverEntity);
            testWorld.ServerWorld.EntityManager.SetComponentData(serverEntity, new GhostValueSerializer
            {
                BoolValue             = (baseValue & 1) != 0,
                IntValue              = baseValue,
                UIntValue             = (uint)baseValue + 1u,
                FloatValue            = baseValue + 2,
                UnquantizedFloatValue = baseValue + 3,

                Float2Value                = new float2(baseValue + 4, baseValue + 5),
                UnquantizedFloat2Value     = new float2(baseValue + 6, baseValue + 7),
                Float3Value                = new float3(baseValue + 8, baseValue + 9, baseValue + 10),
                UnquantizedFloat3Value     = new float3(baseValue + 11, baseValue + 12, baseValue + 13),
                Float4Value                = new float4(baseValue + 14, baseValue + 15, baseValue + 16, baseValue + 17),
                UnquantizedFloat4Value     = new float4(baseValue + 18, baseValue + 19, baseValue + 20, baseValue + 21),
                QuaternionValue            = math.normalize(new quaternion(baseValue + 22, baseValue + 23, baseValue + 24, baseValue + 25)),
                UnquantizedQuaternionValue = math.normalize(new quaternion(baseValue + 26, baseValue + 27, baseValue + 28, baseValue + 29)),

                StringValue32   = new FixedString32($"baseValue = {baseValue}"),
                StringValue64   = new FixedString64($"baseValue = {baseValue*2}"),
                StringValue128  = new FixedString128($"baseValue = {baseValue*3}"),
                StringValue512  = new FixedString512($"baseValue = {baseValue*4}"),
                StringValue4096 = new FixedString4096($"baseValue = {baseValue*5}"),

                EntityValue = serverEntity
            });
        }
Ejemplo n.º 9
0
        public void Rpc_UsingConnectionEntityOnClient_Works()
        {
            using (var testWorld = new NetCodeTestWorld())
            {
                testWorld.Bootstrap(true,
                                    typeof(ClientRcpSendSystem),
                                    typeof(ServerRpcReceiveSystem),
                                    typeof(NonSerializedRpcCommandRequestSystem));
                testWorld.CreateWorlds(true, 1);

                int SendCount = 10;
                ClientRcpSendSystem.SendCount        = SendCount;
                ServerRpcReceiveSystem.ReceivedCount = 0;

                float frameTime = 1.0f / 60.0f;
                // Connect and make sure the connection could be established
                Assert.IsTrue(testWorld.Connect(frameTime, 4));

                var remote = testWorld.TryGetSingletonEntity <NetworkStreamConnection>(testWorld.ClientWorlds[0]);
                testWorld.ClientWorlds[0].GetExistingSystem <ClientRcpSendSystem>().Remote = remote;

                for (int i = 0; i < 33; ++i)
                {
                    testWorld.Tick(16f / 1000f);
                }

                Assert.AreEqual(SendCount, ServerRpcReceiveSystem.ReceivedCount);
            }
        }
        public void StaticGhostsAreSentWhenModified()
        {
            using (var testWorld = new NetCodeTestWorld())
            {
                testWorld.Bootstrap(true, typeof(StaticOptimizationTestSystem));
                StaticOptimizationTestSystem.s_ModifyNetworkId = 1;

                SetupBasicTest(testWorld);

                var clientEnt = testWorld.TryGetSingletonEntity <GhostOwnerComponent>(testWorld.ClientWorlds[0]);
                Assert.AreNotEqual(Entity.Null, clientEnt);

                var clientEntityManager = testWorld.ClientWorlds[0].EntityManager;
                // Store the last tick we got for this
                var clientSnapshotBuffer = clientEntityManager.GetBuffer <SnapshotDataBuffer>(clientEnt);
                var clientSnapshot       = clientEntityManager.GetComponentData <SnapshotData>(clientEnt);
                var lastSnapshot         = clientSnapshot.GetLatestTick(clientSnapshotBuffer);

                // Run a bit longer
                for (int i = 0; i < 16; ++i)
                {
                    testWorld.Tick(frameTime);
                }

                // Verify taht we did not get any new snapshot
                clientSnapshotBuffer = clientEntityManager.GetBuffer <SnapshotDataBuffer>(clientEnt);
                clientSnapshot       = clientEntityManager.GetComponentData <SnapshotData>(clientEnt);
                Assert.AreEqual(lastSnapshot, clientSnapshot.GetLatestTick(clientSnapshotBuffer));

                // Run one tick with modification
                StaticOptimizationTestSystem.s_ModifyNetworkId = 0;
                testWorld.Tick(frameTime);
                StaticOptimizationTestSystem.s_ModifyNetworkId = 1;

                for (int i = 0; i < 16; ++i)
                {
                    testWorld.Tick(frameTime);
                }

                // Verify taht we did not get any new snapshot
                clientSnapshotBuffer = clientEntityManager.GetBuffer <SnapshotDataBuffer>(clientEnt);
                clientSnapshot       = clientEntityManager.GetComponentData <SnapshotData>(clientEnt);
                var newLastSnapshot = clientSnapshot.GetLatestTick(clientSnapshotBuffer);
                Assert.AreNotEqual(lastSnapshot, newLastSnapshot);

                for (int i = 0; i < 16; ++i)
                {
                    testWorld.Tick(frameTime);
                }

                // Verify that the snapshot stayed static at the new position
                clientSnapshotBuffer = clientEntityManager.GetBuffer <SnapshotDataBuffer>(clientEnt);
                clientSnapshot       = clientEntityManager.GetComponentData <SnapshotData>(clientEnt);
                Assert.AreEqual(newLastSnapshot, clientSnapshot.GetLatestTick(clientSnapshotBuffer));
            }
        }
        public void ExtrapolationProduceSmoothValues()
        {
            using (var testWorld = new NetCodeTestWorld())
            {
                testWorld.Bootstrap(true, typeof(MoveExtrapolated), typeof(CheckExtrapolate));

                var ghostGameObject = new GameObject();
                ghostGameObject.AddComponent <TestNetCodeAuthoring>().Converter = new GhostExtrapolationConverter();
                ghostGameObject.AddComponent <GhostAuthoringComponent>();
                Assert.IsTrue(testWorld.CreateGhostCollection(ghostGameObject));

                testWorld.CreateWorlds(true, 1);

                var tickRate = testWorld.ServerWorld.EntityManager.CreateEntity();
                // Set low net tick rate to make sure interpolation is used
                testWorld.ServerWorld.EntityManager.AddComponentData(tickRate, new ClientServerTickRate {
                    NetworkTickRate = 1
                });

                var clientTickRate = testWorld.ClientWorlds[0].EntityManager.CreateEntity();
                // Disable interpolation time to make sure extrapolation is used
                var tr = NetworkTimeSystem.DefaultClientTickRate;
                tr.InterpolationTimeNetTicks    = 0;
                tr.MaxExtrapolationTimeSimTicks = 120;
                testWorld.ClientWorlds[0].EntityManager.AddComponentData(clientTickRate, tr);

                testWorld.SpawnOnServer(ghostGameObject);

                float frameTime = 1.0f / 60.0f;
                // Connect and make sure the connection could be established
                Assert.IsTrue(testWorld.Connect(frameTime, 4));

                // Go in-game
                testWorld.GoInGame();

                // Let the simulation run for a bit since extrapolation requires two snapshots to be received before it does anything
                for (int i = 0; i < 256; ++i)
                {
                    testWorld.Tick(frameTime);
                }

                // Enable the checks
                var clientEnt = testWorld.TryGetSingletonEntity <TestExtrapolated>(testWorld.ClientWorlds[0]);
                Assert.AreNotEqual(Entity.Null, clientEnt);
                testWorld.ClientWorlds[0].EntityManager.AddComponentData(clientEnt, new ExtrapolateBackup {
                    Value = 0
                });

                // Let the game run for a bit more and verify that they are extrapolated
                for (int i = 0; i < 256; ++i)
                {
                    testWorld.Tick(frameTime);
                }
            }
        }
        public void MaxSmoothingDistanceIsUsed()
        {
            using (var testWorld = new NetCodeTestWorld())
            {
                testWorld.Bootstrap(true, typeof(MoveExtrapolated), typeof(CheckInterpolationDistance));

                var ghostGameObject = new GameObject();
                ghostGameObject.AddComponent <TestNetCodeAuthoring>().Converter = new GhostExtrapolationConverter();
                ghostGameObject.AddComponent <GhostAuthoringComponent>();
                Assert.IsTrue(testWorld.CreateGhostCollection(ghostGameObject));

                testWorld.CreateWorlds(true, 1);

                var tickRate = testWorld.ServerWorld.EntityManager.CreateEntity();
                // Set low net tick rate to make sure interpolation is used
                testWorld.ServerWorld.EntityManager.AddComponentData(tickRate, new ClientServerTickRate {
                    NetworkTickRate = 30
                });

                testWorld.SpawnOnServer(ghostGameObject);

                float frameTime = 1.0f / 60.0f;
                // Connect and make sure the connection could be established
                Assert.IsTrue(testWorld.Connect(frameTime, 4));

                // Go in-game
                testWorld.GoInGame();


                for (int i = 0; i < 8; ++i)
                {
                    testWorld.Tick(frameTime);
                }

                var clientEnt = testWorld.TryGetSingletonEntity <TestExtrapolated>(testWorld.ClientWorlds[0]);
                Assert.AreNotEqual(Entity.Null, clientEnt);

                Assert.Less(testWorld.ClientWorlds[0].EntityManager.GetComponentData <TestExtrapolated>(clientEnt).Value, 100);
                // Let the game run for a bit so the ghosts are spawned on the client
                for (int i = 0; i < 256; ++i)
                {
                    testWorld.Tick(frameTime);
                }

                Assert.Greater(testWorld.ClientWorlds[0].EntityManager.GetComponentData <TestExtrapolated>(clientEnt).Value, 200);
            }
        }
        public void StructWithLargeNumberOfFields()
        {
            using (var testWorld = new NetCodeTestWorld())
            {
                testWorld.Bootstrap(true);

                var ghostGameObject = new GameObject();
                ghostGameObject.AddComponent <TestNetCodeAuthoring>().Converter = new GhostGenBigStructConverter();

                Assert.IsTrue(testWorld.CreateGhostCollection(ghostGameObject));

                testWorld.CreateWorlds(true, 1);

                var serverEntity = testWorld.SpawnOnServer(ghostGameObject);
                //Use reflection.. just because if is faster
                var data = default(GhostGenBigStruct);
                unsafe
                {
                    var values = (int *)UnsafeUtility.AddressOf(ref data);
                    for (int i = 0; i < 100; ++i)
                    {
                        values[i] = i;
                    }
                }
                testWorld.ServerWorld.EntityManager.SetComponentData(serverEntity, data);

                float frameTime = 1.0f / 60.0f;
                // Connect and make sure the connection could be established
                Assert.IsTrue(testWorld.Connect(frameTime, 4));

                // Go in-game
                testWorld.GoInGame();

                // Let the game run for a bit so the ghosts are spawned on the client
                for (int i = 0; i < 16; ++i)
                {
                    testWorld.Tick(frameTime);
                }

                var clientEntity = testWorld.TryGetSingletonEntity <GhostGenBigStruct>(testWorld.ClientWorlds[0]);
                var clientData   = testWorld.ClientWorlds[0].EntityManager.GetComponentData <GhostGenBigStruct>(clientEntity);
                var serverData   = testWorld.ServerWorld.EntityManager.GetComponentData <GhostGenBigStruct>(serverEntity);
                Assert.AreEqual(serverData, clientData);
            }
        }
        public void EntityReferenceUnavailableGhostIsResolved()
        {
            using (var testWorld = new NetCodeTestWorld())
            {
                testWorld.Bootstrap(true);

                var ghostGameObject = new GameObject();
                ghostGameObject.AddComponent <TestNetCodeAuthoring>().Converter = new GhostValueSerializerConverter();
                var referencedGameObject = new GameObject();
                referencedGameObject.AddComponent <GhostOwnerComponentAuthoring>();

                Assert.IsTrue(testWorld.CreateGhostCollection(ghostGameObject, referencedGameObject));

                testWorld.CreateWorlds(true, 1);
                var ghostSendSystem = testWorld.ServerWorld.GetExistingSystem <GhostSendSystem>();

                float frameTime = 1.0f / 60.0f;
                // Connect and make sure the connection could be established
                Assert.IsTrue(testWorld.Connect(frameTime, 4));
                ghostSendSystem.GhostRelevancyMode = GhostRelevancyMode.SetIsRelevant;

                // Go in-game
                testWorld.GoInGame();
                for (int i = 0; i < 4; ++i)
                {
                    testWorld.Tick(frameTime);
                }

                var con = testWorld.TryGetSingletonEntity <NetworkIdComponent>(testWorld.ServerWorld);
                Assert.AreNotEqual(Entity.Null, con);
                var serverConnectionId = testWorld.ServerWorld.EntityManager.GetComponentData <NetworkIdComponent>(con).Value;

                var serverRefEntity = testWorld.SpawnOnServer(referencedGameObject);
                var serverEnt       = testWorld.SpawnOnServer(ghostGameObject);
                testWorld.ServerWorld.EntityManager.SetComponentData(serverEnt, new GhostValueSerializer {
                    EntityValue = serverRefEntity
                });

                testWorld.Tick(frameTime);

                var serverGhostId    = testWorld.ServerWorld.EntityManager.GetComponentData <GhostComponent>(serverEnt).ghostId;
                var serverRefGhostId = testWorld.ServerWorld.EntityManager.GetComponentData <GhostComponent>(serverRefEntity).ghostId;

                // only mark the entity with the ref as relevant so that arrived before the referenced entity exists
                ghostSendSystem.GhostRelevancySet.TryAdd(new RelevantGhostForConnection(serverConnectionId, serverGhostId), 1);

                // Let the game run for a bit so the ghosts are spawned on the client
                for (int i = 0; i < 8; ++i)
                {
                    testWorld.Tick(frameTime);
                    var clientRefEntity = testWorld.TryGetSingletonEntity <GhostOwnerComponent>(testWorld.ClientWorlds[0]);
                    var clientEntity    = testWorld.TryGetSingletonEntity <GhostValueSerializer>(testWorld.ClientWorlds[0]);
                    if (clientEntity != Entity.Null)
                    {
                        // Make sure the reference always exist if the ghost exists
                        Assert.AreEqual(clientRefEntity, testWorld.ClientWorlds[0].EntityManager.GetComponentData <GhostValueSerializer>(clientEntity).EntityValue);
                    }
                }
                // Verify that we did not the referenced entity since it is irrelevant
                Assert.AreEqual(Entity.Null, testWorld.TryGetSingletonEntity <GhostOwnerComponent>(testWorld.ClientWorlds[0]));

                ghostSendSystem.GhostRelevancySet.TryAdd(new RelevantGhostForConnection(serverConnectionId, serverRefGhostId), 1);
                for (int i = 0; i < 8; ++i)
                {
                    testWorld.Tick(frameTime);
                    var clientRefEntity = testWorld.TryGetSingletonEntity <GhostOwnerComponent>(testWorld.ClientWorlds[0]);
                    var clientEntity    = testWorld.TryGetSingletonEntity <GhostValueSerializer>(testWorld.ClientWorlds[0]);
                    if (clientEntity != Entity.Null)
                    {
                        // Make sure the reference always exist if the ghost exists
                        Assert.AreEqual(clientRefEntity, testWorld.ClientWorlds[0].EntityManager.GetComponentData <GhostValueSerializer>(clientEntity).EntityValue);
                    }
                }
                Assert.AreNotEqual(Entity.Null, testWorld.TryGetSingletonEntity <GhostOwnerComponent>(testWorld.ClientWorlds[0]));

                // Delete the referenced entity and make sure the ref is updated
                testWorld.ServerWorld.EntityManager.DestroyEntity(serverRefEntity);
                int mismatchFrames = 0;
                for (int i = 0; i < 8; ++i)
                {
                    testWorld.Tick(frameTime);
                    var clientRefEntity = testWorld.TryGetSingletonEntity <GhostOwnerComponent>(testWorld.ClientWorlds[0]);
                    var clientEntity    = testWorld.TryGetSingletonEntity <GhostValueSerializer>(testWorld.ClientWorlds[0]);
                    if (clientEntity != Entity.Null)
                    {
                        // The desapwn order might not be the same between client and server, if the server has despawned the entity there will be no reference,
                        // but the client despawns at the end of the frame it was destroyed so it might still exist for one frame
                        Assert.IsFalse(clientRefEntity == Entity.Null && testWorld.ClientWorlds[0].EntityManager.GetComponentData <GhostValueSerializer>(clientEntity).EntityValue != Entity.Null);
                        if (clientRefEntity != testWorld.ClientWorlds[0].EntityManager.GetComponentData <GhostValueSerializer>(clientEntity).EntityValue)
                        {
                            ++mismatchFrames;
                        }
                    }
                }
                Assert.LessOrEqual(mismatchFrames, 1);
                Assert.AreEqual(Entity.Null, testWorld.TryGetSingletonEntity <GhostOwnerComponent>(testWorld.ClientWorlds[0]));
            }
        }
Ejemplo n.º 15
0
        public void OverrideComponentSendType_ChildEntity()
        {
            using (var testWorld = new NetCodeTestWorld())
            {
                testWorld.Bootstrap(true);
                var names      = new[] { "All", "Interpolated", "Predicted", "None" };
                var sendTypes  = new[] { GhostSendType.All, GhostSendType.Interpolated, GhostSendType.Predicted, (GhostSendType)0 };
                var collection = CreatePrefabs(names);
                for (int i = 0; i < sendTypes.Length; ++i)
                {
                    var authoring = collection[i].GetComponent <GhostAuthoringComponent>();
                    authoring.ComponentOverrides = new List <GhostAuthoringComponent.ComponentOverride>
                    {
                        new GhostAuthoringComponent.ComponentOverride
                        {
                            fullTypeName           = typeof(GhostGen_IntStruct).FullName,
                            gameObject             = collection[i].transform.GetChild(0).gameObject,
                            PrefabType             = (int)GhostPrefabType.All,
                            OwnerPredictedSendType = (int)sendTypes[i],
                            SendToChild            = GhostAuthoringComponent.ComponentOverride.UseDefaultValue,
                            ComponentVariant       = 0
                        }
                    };
                }

                Assert.IsTrue(testWorld.CreateGhostCollection(collection));
                testWorld.CreateWorlds(true, 1);

                //Register serializers and setup all the system
                for (int i = 0; i < 16; ++i)
                {
                    testWorld.Tick(1.0f / 60.0f);
                }

                //In order to get the collection setup I need to enter in game
                testWorld.Connect(1.0f / 60f, 16);
                testWorld.GoInGame();

                for (int i = 0; i < collection.Length; ++i)
                {
                    testWorld.SpawnOnServer(collection[i]);
                }

                for (int i = 0; i < 16; ++i)
                {
                    testWorld.Tick(1.0f / 60.0f);
                }

                //Then check the expected results
                var collectionEntity         = testWorld.TryGetSingletonEntity <GhostCollection>(testWorld.ServerWorld);
                var ghostCollection          = testWorld.ServerWorld.EntityManager.GetBuffer <GhostCollectionComponentIndex>(collectionEntity);
                var ghostComponentCollection = testWorld.ServerWorld.EntityManager.GetBuffer <GhostCollectionComponentType>(collectionEntity);

                var type  = TypeManager.GetTypeIndex(typeof(GhostGen_IntStruct));
                var index = 0;
                while (index < ghostCollection.Length && ghostComponentCollection[ghostCollection[index].ComponentIndex].Type.TypeIndex != type)
                {
                    ++index;
                }
                var serializerIndex = ghostCollection[index].SerializerIndex;

                CheckCollection(testWorld.ServerWorld, serializerIndex, 1);
                CheckCollection(testWorld.ClientWorlds[0], serializerIndex, 1);
            }
        }
        public void SendToOwner_Clients_ReceiveTheCorrectData(GhostAuthoringComponent.GhostModeMask modeMask, GhostAuthoringComponent.GhostMode mode)
        {
            using (var testWorld = new NetCodeTestWorld())
            {
                testWorld.Bootstrap(true, typeof(InputSystem));

                var ghostGameObject = new GameObject();
                ghostGameObject.AddComponent <TestNetCodeAuthoring>().Converter = new TestComponentConverter();
                var ghostConfig = ghostGameObject.AddComponent <GhostAuthoringComponent>();
                ghostConfig.SupportedGhostModes = modeMask;
                ghostConfig.DefaultGhostMode    = mode;
                //Some context about where owner make sense:
                //interpolated ghost: does even make sense that a ghost has an owner? Yes, it does and it is usually the server.
                //                    Can be a player ??? Yes it can. In that case, the player can still control the ghost via command but it will not predict the
                //                    ghost movement. Only the server will compute the correct position. The client will always see a delayed and interpolated replica.
                //Predicted ghost: owner make absolutely sense.
                //OwnerPredicted: by definition
                Assert.IsTrue(testWorld.CreateGhostCollection(ghostGameObject));
                testWorld.CreateWorlds(true, 2);
                //Here I do a trick: I will wait until the CollectionSystem is run and the component collection built.
                //Then I will change the serializer flags a little to make them behave the way I want.
                //This is a temporary hack, can be remove whe override per prefab will be available.
                var queryServer  = testWorld.ServerWorld.EntityManager.CreateEntityQuery(ComponentType.ReadOnly <GhostCollection>());
                var queryClient0 = testWorld.ClientWorlds[0].EntityManager.CreateEntityQuery(ComponentType.ReadOnly <GhostCollection>());
                var queryClient1 = testWorld.ClientWorlds[1].EntityManager.CreateEntityQuery(ComponentType.ReadOnly <GhostCollection>());
                while (true)
                {
                    testWorld.Tick(1.0f / 60f);
                    if (queryServer.IsEmptyIgnoreFilter || queryClient0.IsEmptyIgnoreFilter || queryClient1.IsEmptyIgnoreFilter)
                    {
                        continue;
                    }
                    if (testWorld.ServerWorld.EntityManager.GetBuffer <GhostComponentSerializer.State>(queryServer.GetSingletonEntity()).Length == 0 ||
                        testWorld.ServerWorld.EntityManager.GetBuffer <GhostComponentSerializer.State>(queryServer.GetSingletonEntity()).Length == 0 ||
                        testWorld.ServerWorld.EntityManager.GetBuffer <GhostComponentSerializer.State>(queryServer.GetSingletonEntity()).Length == 0)
                    {
                        continue;
                    }
                    ChangeSendToOwnerOption(testWorld.ServerWorld);
                    ChangeSendToOwnerOption(testWorld.ClientWorlds[0]);
                    ChangeSendToOwnerOption(testWorld.ClientWorlds[1]);
                    break;
                }

                Assert.IsTrue(testWorld.Connect(1.0f / 60.0f, 64));
                testWorld.GoInGame();

                var net1   = testWorld.TryGetSingletonEntity <NetworkIdComponent>(testWorld.ClientWorlds[0]);
                var netId1 = testWorld.ClientWorlds[0].EntityManager.GetComponentData <NetworkIdComponent>(net1);

                var serverEnt = testWorld.SpawnOnServer(ghostGameObject);
                testWorld.ServerWorld.EntityManager.SetComponentData(serverEnt, new GhostGen_IntStruct {
                    IntValue = 10000
                });
                testWorld.ServerWorld.EntityManager.SetComponentData(serverEnt, new GhostTypeIndex {
                    Value = 20000
                });
                testWorld.ServerWorld.EntityManager.SetComponentData(serverEnt, new GhostPredictedOnly {
                    Value = 30000
                });
                testWorld.ServerWorld.EntityManager.SetComponentData(serverEnt, new GhostInterpolatedOnly {
                    Value = 40000
                });
                testWorld.ServerWorld.EntityManager.SetComponentData(serverEnt, new GhostOwnerComponent {
                    NetworkId = netId1.Value
                });
                var serverBuffer1 = testWorld.ServerWorld.EntityManager.GetBuffer <GhostGenBuffer_ByteBuffer>(serverEnt);
                serverBuffer1.Capacity = 10;
                for (int i = 0; i < 10; ++i)
                {
                    serverBuffer1.Add(new GhostGenBuffer_ByteBuffer {
                        Value = (byte)(10 + i)
                    });
                }
                var serverBuffer2 = testWorld.ServerWorld.EntityManager.GetBuffer <GhostGenTest_Buffer>(serverEnt);
                serverBuffer2.Capacity = 10;
                for (int i = 0; i < 10; ++i)
                {
                    serverBuffer2.Add(new GhostGenTest_Buffer());
                }

                for (int i = 0; i < 16; ++i)
                {
                    testWorld.Tick(1.0f / 60.0f);
                }

                serverBuffer1 = testWorld.ServerWorld.EntityManager.GetBuffer <GhostGenBuffer_ByteBuffer>(serverEnt);
                serverBuffer2 = testWorld.ServerWorld.EntityManager.GetBuffer <GhostGenTest_Buffer>(serverEnt);
                var serverComp1   = testWorld.ServerWorld.EntityManager.GetComponentData <GhostGen_IntStruct>(serverEnt);
                var serverComp2   = testWorld.ServerWorld.EntityManager.GetComponentData <GhostTypeIndex>(serverEnt);
                var predictedOnly = testWorld.ServerWorld.EntityManager.GetComponentData <GhostPredictedOnly>(serverEnt);
                var interpOnly    = testWorld.ServerWorld.EntityManager.GetComponentData <GhostInterpolatedOnly>(serverEnt);

                for (int i = 0; i < 2; ++i)
                {
                    var clientEnt            = testWorld.TryGetSingletonEntity <GhostOwnerComponent>(testWorld.ClientWorlds[i]);
                    var clientComp1_ToOwner  = testWorld.ClientWorlds[i].EntityManager.GetComponentData <GhostGen_IntStruct>(clientEnt);
                    var clientComp2_NonOwner = testWorld.ClientWorlds[i].EntityManager.GetComponentData <GhostTypeIndex>(clientEnt);
                    var clientPredOnly       = testWorld.ClientWorlds[i].EntityManager.GetComponentData <GhostPredictedOnly>(clientEnt);
                    var clientInterpOnly     = testWorld.ClientWorlds[i].EntityManager.GetComponentData <GhostInterpolatedOnly>(clientEnt);

                    var clientBuffer1 = testWorld.ClientWorlds[i].EntityManager.GetBuffer <GhostGenBuffer_ByteBuffer>(clientEnt);
                    var clientBuffer2 = testWorld.ClientWorlds[i].EntityManager.GetBuffer <GhostGenTest_Buffer>(clientEnt);

                    Assert.AreEqual(i == 0, serverComp1.IntValue == clientComp1_ToOwner.IntValue, $"Client {i}");
                    Assert.AreEqual(i == 1, serverComp2.Value == clientComp2_NonOwner.Value, $"Client {i}");

                    //The component are sent to all the clients and only the SendToOwner matter
                    if (mode == GhostAuthoringComponent.GhostMode.Predicted)
                    {
                        Assert.AreEqual(i == 0, predictedOnly.Value == clientPredOnly.Value, $"Client {i}");
                        Assert.AreEqual(false, interpOnly.Value == clientInterpOnly.Value, $"Client {i}");
                    }
                    else if (mode == GhostAuthoringComponent.GhostMode.Interpolated)
                    {
                        Assert.AreEqual(false, predictedOnly.Value == clientPredOnly.Value, $"Client {i}");
                        Assert.AreEqual(i == 1, interpOnly.Value == clientInterpOnly.Value, $"Client {i}");
                    }
                    else if (mode == GhostAuthoringComponent.GhostMode.OwnerPredicted)
                    {
                        Assert.AreEqual(i == 0, predictedOnly.Value == clientPredOnly.Value, $"Client {i}");
                        Assert.AreEqual(i == 1, interpOnly.Value == clientInterpOnly.Value, $"Client {i}");
                    }
                    Assert.AreEqual(true, 10 == clientBuffer1.Length);
                    Assert.AreEqual(i == 1, 10 == clientBuffer2.Length);
                    Assert.AreEqual(i == 0, 0 == clientBuffer2.Length);
                    for (int k = 0; k < clientBuffer1.Length; ++k)
                    {
                        Assert.AreEqual(serverBuffer1[k].Value, clientBuffer1[k].Value, $"Client {i}");
                    }
                    for (int k = 0; k < clientBuffer2.Length; ++k)
                    {
                        Assert.AreEqual(serverBuffer2[k].IntValue, clientBuffer2[k].IntValue, $"Client {i}");
                    }
                }
            }
        }
        void VerifyGhostValues(NetCodeTestWorld testWorld)
        {
            var serverEntity = testWorld.TryGetSingletonEntity <GhostGenTestTypeFlat>(testWorld.ServerWorld);
            var clientEntity = testWorld.TryGetSingletonEntity <GhostGenTestTypeFlat>(testWorld.ClientWorlds[0]);

            Assert.AreNotEqual(Entity.Null, serverEntity);
            Assert.AreNotEqual(Entity.Null, clientEntity);

            var serverValues = testWorld.ServerWorld.EntityManager.GetComponentData <GhostGenTestTypeFlat>(serverEntity);
            var clientValues = testWorld.ClientWorlds[0].EntityManager.GetComponentData <GhostGenTestTypeFlat>(clientEntity);

            Assert.AreEqual(serverValues.Int3, clientValues.Int3);
            Assert.AreEqual(serverValues.Composed_Int3, clientValues.Composed_Int3);

            Assert.AreEqual(serverValues.UInt3, clientValues.UInt3);
            Assert.AreEqual(serverValues.Composed_UInt3, clientValues.Composed_UInt3);

            Assert.AreEqual(serverValues.Partial_UInt3.x, clientValues.Partial_UInt3.x);
            Assert.AreEqual(serverValues.Partial_UInt3.y, clientValues.Partial_UInt3.y);
            Assert.AreEqual(0, clientValues.Partial_UInt3.z);
            Assert.AreEqual(serverValues.ComposedPartial_UInt3.x, clientValues.ComposedPartial_UInt3.x);
            Assert.AreEqual(serverValues.ComposedPartial_UInt3.y, clientValues.ComposedPartial_UInt3.y);
            Assert.AreEqual(0, clientValues.ComposedPartial_UInt3.z);

            Assert.AreEqual(serverValues.FloatX, clientValues.FloatX);
            Assert.AreEqual(serverValues.Composed_FloatX, clientValues.Composed_FloatX);

            Assert.AreEqual(serverValues.IntValue, clientValues.IntValue);
            Assert.AreEqual(serverValues.UIntValue, clientValues.UIntValue);
            Assert.AreEqual(serverValues.BoolValue, clientValues.BoolValue);

            Assert.AreEqual(serverValues.FloatValue, clientValues.FloatValue);
            Assert.AreEqual(serverValues.Interpolated_FloatValue, clientValues.Interpolated_FloatValue);
            Assert.AreEqual(serverValues.Unquantized_FloatValue, clientValues.Unquantized_FloatValue);
            Assert.AreEqual(serverValues.Unquantized_Interpolated_FloatValue, clientValues.Unquantized_Interpolated_FloatValue);

            Assert.AreEqual(serverValues.Float2Value, clientValues.Float2Value);
            Assert.AreEqual(serverValues.Interpolated_Float2Value, clientValues.Interpolated_Float2Value);
            Assert.AreEqual(serverValues.Unquantized_Float2Value, clientValues.Unquantized_Float2Value);
            Assert.AreEqual(serverValues.Interpolated_Unquantized_Float2Value, clientValues.Interpolated_Unquantized_Float2Value);

            Assert.AreEqual(serverValues.Float3Value, clientValues.Float3Value);
            Assert.AreEqual(serverValues.Interpolated_Float3Value, clientValues.Interpolated_Float3Value);
            Assert.AreEqual(serverValues.Unquantized_Float3Value, clientValues.Unquantized_Float3Value);
            Assert.AreEqual(serverValues.Interpolated_Unquantized_Float3Value, clientValues.Interpolated_Unquantized_Float3Value);

            Assert.AreEqual(serverValues.Float4Value, clientValues.Float4Value);
            Assert.AreEqual(serverValues.Interpolated_Float4Value, clientValues.Interpolated_Float4Value);
            Assert.AreEqual(serverValues.Unquantized_Float4Value, clientValues.Unquantized_Float4Value);
            Assert.AreEqual(serverValues.Interpolated_Unquantized_Float4Value, clientValues.Interpolated_Unquantized_Float4Value);

            Assert.Less(math.distance(serverValues.QuaternionValue.value, clientValues.QuaternionValue.value), 0.001f);
            Assert.Less(math.distance(serverValues.Interpolated_QuaternionValue.value, clientValues.Interpolated_QuaternionValue.value), 0.001f);
            Assert.AreEqual(serverValues.Unquantized_QuaternionValue, clientValues.Unquantized_QuaternionValue);
            Assert.AreEqual(serverValues.Interpolated_Unquantized_QuaternionValue, clientValues.Interpolated_Unquantized_QuaternionValue);

            Assert.AreEqual(serverValues.String32Value, clientValues.String32Value);
            Assert.AreEqual(serverValues.String64Value, clientValues.String64Value);
            Assert.AreEqual(serverValues.String128Value, clientValues.String128Value);
            Assert.AreEqual(serverValues.String512Value, clientValues.String512Value);
            Assert.AreEqual(serverValues.String4096Value, clientValues.String4096Value);

            Assert.AreEqual(serverEntity, serverValues.EntityValue);
            Assert.AreEqual(clientEntity, clientValues.EntityValue);
        }
        void SetGhostValues(NetCodeTestWorld testWorld, int baseValue)
        {
            var serverEntity = testWorld.TryGetSingletonEntity <GhostGenTestTypeFlat>(testWorld.ServerWorld);

            Assert.AreNotEqual(Entity.Null, serverEntity);
            int i = 0;

            testWorld.ServerWorld.EntityManager.SetComponentData(serverEntity, new GhostGenTestTypeFlat
            {
                Int3 = new int3()
                {
                    x = baseValue,
                    y = baseValue + ++i,
                    z = baseValue + ++i
                },
                Composed_Int3 = new int3()
                {
                    x = baseValue + ++i,
                    y = baseValue + ++i,
                    z = baseValue + ++i,
                },
                UInt3 = new uint3()
                {
                    x = (uint)baseValue + (uint)++i,
                    y = (uint)baseValue + (uint)++i,
                    z = (uint)baseValue + (uint)++i
                },
                Composed_UInt3 = new uint3()
                {
                    x = (uint)baseValue + (uint)++i,
                    y = (uint)baseValue + (uint)++i,
                    z = (uint)baseValue + (uint)++i
                },
                Partial_UInt3 = new partialUint3()
                {
                    x = (uint)baseValue + (uint)++i,
                    y = (uint)baseValue + (uint)++i,
                    z = (uint)baseValue + (uint)++i
                },
                ComposedPartial_UInt3 = new partialUint3()
                {
                    x = (uint)baseValue + (uint)++i,
                    y = (uint)baseValue + (uint)++i,
                    z = (uint)baseValue + (uint)++i
                },
                FloatX = new floatX()
                {
                    x = new float2(baseValue + (uint)++i, baseValue + (uint)++i),
                    y = new float3(baseValue + (uint)++i, baseValue + (uint)++i, baseValue + (uint)++i),
                    z = new float4(baseValue + (uint)++i, baseValue + (uint)++i, baseValue + (uint)++i, baseValue + (uint)++i),
                },
                Composed_FloatX = new floatX()
                {
                    x = new float2(baseValue + (uint)++i, baseValue + (uint)++i),
                    y = new float3(baseValue + (uint)++i, baseValue + (uint)++i, baseValue + (uint)++i),
                    z = new float4(baseValue + (uint)++i, baseValue + (uint)++i, baseValue + (uint)++i, baseValue + (uint)++i),
                },
                IntValue  = baseValue + ++i,
                UIntValue = (uint)baseValue + (uint)++i,
                BoolValue = (baseValue & ++ i) != 0,

                FloatValue = baseValue + ++i,
                Interpolated_FloatValue             = baseValue + ++i,
                Unquantized_FloatValue              = baseValue + ++i,
                Unquantized_Interpolated_FloatValue = baseValue + ++i,

                Float2Value = new float2(baseValue + ++i, baseValue + ++i),
                Interpolated_Float2Value             = new float2(baseValue + ++i, baseValue + ++i),
                Unquantized_Float2Value              = new float2(baseValue + ++i, baseValue + ++i),
                Interpolated_Unquantized_Float2Value = new float2(baseValue + ++i, baseValue + ++i),

                Float3Value = new float3(baseValue + ++i, baseValue + ++i, baseValue + ++i),
                Interpolated_Float3Value             = new float3(baseValue + ++i, baseValue + ++i, baseValue + ++i),
                Unquantized_Float3Value              = new float3(baseValue + ++i, baseValue + ++i, baseValue + ++i),
                Interpolated_Unquantized_Float3Value = new float3(baseValue + ++i, baseValue + ++i, baseValue + ++i),

                Float4Value = new float4(baseValue + ++i, baseValue + ++i, baseValue + ++i, baseValue + ++i),
                Interpolated_Float4Value             = new float4(baseValue + ++i, baseValue + ++i, baseValue + ++i, baseValue + ++i),
                Unquantized_Float4Value              = new float4(baseValue + ++i, baseValue + ++i, baseValue + ++i, baseValue + ++i),
                Interpolated_Unquantized_Float4Value = new float4(baseValue + ++i, baseValue + ++i, baseValue + ++i, baseValue + ++i),

                QuaternionValue = math.normalize(new quaternion(0.4f, 0.4f, 0.4f, 0.6f)),
                Interpolated_QuaternionValue             = math.normalize(new quaternion(0.5f, 0.5f, 0.5f, 0.5f)),
                Unquantized_QuaternionValue              = math.normalize(new quaternion(0.6f, 0.6f, 0.6f, 0.6f)),
                Interpolated_Unquantized_QuaternionValue = math.normalize(new quaternion(0.5f, 0.5f, 0.5f, 0.5f)),

                String32Value   = new FixedString32($"baseValue = {baseValue + ++i}"),
                String64Value   = new FixedString64($"baseValue = {baseValue + ++i}"),
                String128Value  = new FixedString128($"baseValue = {baseValue + ++i}"),
                String512Value  = new FixedString512($"baseValue = {baseValue + ++i}"),
                String4096Value = new FixedString4096($"baseValue = {baseValue + ++i}"),

                EntityValue = serverEntity,
            });
            Debug.Log($"i is {i}");
        }
        public void RelevancyChangesSendsStaticGhosts()
        {
            using (var testWorld = new NetCodeTestWorld())
            {
                testWorld.Bootstrap(true);

                // Spawn 16 ghosts
                SetupBasicTest(testWorld, 16);
                // Set the ghost id for one of them to 1 so it is modified
                var serverQuery = testWorld.ServerWorld.EntityManager.CreateEntityQuery(ComponentType.ReadOnly <GhostOwnerComponent>());
                int ghostId;
                using (var serverEntities = serverQuery.ToEntityArray(Allocator.TempJob))
                {
                    Assert.AreEqual(16, serverEntities.Length);
                    ghostId = testWorld.ServerWorld.EntityManager.GetComponentData <GhostComponent>(serverEntities[0]).ghostId;
                }
                var con = testWorld.TryGetSingletonEntity <NetworkIdComponent>(testWorld.ServerWorld);
                Assert.AreNotEqual(Entity.Null, con);
                var connectionId = testWorld.ServerWorld.EntityManager.GetComponentData <NetworkIdComponent>(con).Value;

                // Get the changes across to the client
                for (int i = 0; i < 16; ++i)
                {
                    testWorld.Tick(frameTime);
                }

                var clientEntityManager = testWorld.ClientWorlds[0].EntityManager;
                var clientQuery         = clientEntityManager.CreateEntityQuery(ComponentType.ReadOnly <GhostOwnerComponent>());
                var clientEntities      = clientQuery.ToComponentDataArray <GhostOwnerComponent>(Allocator.Temp);
                Assert.AreEqual(16, clientEntities.Length);


                // Make one of the ghosts irrelevant
                var ghostSendSystem = testWorld.ServerWorld.GetExistingSystem <GhostSendSystem>();
                ghostSendSystem.GhostRelevancyMode = GhostRelevancyMode.SetIsIrrelevant;
                var key = new RelevantGhostForConnection {
                    Connection = connectionId, Ghost = ghostId
                };
                ghostSendSystem.GhostRelevancySet.TryAdd(key, 1);

                // Get the changes across to the client
                for (int i = 0; i < 16; ++i)
                {
                    testWorld.Tick(frameTime);
                }

                clientEntities = clientQuery.ToComponentDataArray <GhostOwnerComponent>(Allocator.Temp);
                Assert.AreEqual(15, clientEntities.Length);

                // Allow it to spawn again
                ghostSendSystem.GhostRelevancySet.Remove(key);

                // Get the changes across to the client
                for (int i = 0; i < 16; ++i)
                {
                    testWorld.Tick(frameTime);
                }

                clientEntities = clientQuery.ToComponentDataArray <GhostOwnerComponent>(Allocator.Temp);
                Assert.AreEqual(16, clientEntities.Length);
            }
        }
Ejemplo n.º 20
0
        public void SerializationVariant_AreAppliedToBothRootAndChildEntities()
        {
            using (var testWorld = new NetCodeTestWorld())
            {
                testWorld.Bootstrap(true);
                var ghostGameObject = new GameObject("Root");
                var childGhost      = new GameObject("Child");
                childGhost.transform.parent = ghostGameObject.transform;
                var authoring = ghostGameObject.AddComponent <GhostAuthoringComponent>();
                authoring.DefaultGhostMode    = GhostAuthoringComponent.GhostMode.Interpolated;
                authoring.SupportedGhostModes = GhostAuthoringComponent.GhostModeMask.All;

                //Setup a variant for both root and child entity and check that the runtime serializer use this one to serialize data
                var attrType = typeof(TranslationVariantTest).GetCustomAttribute <GhostComponentVariationAttribute>();
                var hash     = GhostComponentVariationAttribute.ComputeVariantHash(typeof(TranslationVariantTest), attrType);
                authoring.ComponentOverrides = new List <GhostAuthoringComponent.ComponentOverride>
                {
                    new GhostAuthoringComponent.ComponentOverride
                    {
                        fullTypeName           = typeof(Transforms.Translation).FullName,
                        gameObject             = ghostGameObject,
                        PrefabType             = (int)GhostPrefabType.All,
                        OwnerPredictedSendType = (int)GhostSendType.All,
                        ComponentVariant       = hash
                    },
                    new GhostAuthoringComponent.ComponentOverride
                    {
                        fullTypeName           = typeof(Transforms.Translation).FullName,
                        gameObject             = childGhost,
                        PrefabType             = (int)GhostPrefabType.All,
                        OwnerPredictedSendType = (int)GhostSendType.All,
                        ComponentVariant       = hash
                    }
                };

                Assert.IsTrue(testWorld.CreateGhostCollection(ghostGameObject), "Cannot create ghost collection");
                testWorld.CreateWorlds(true, 1);

                //Register serializers and setup all the system
                for (int i = 0; i < 16; ++i)
                {
                    testWorld.Tick(1.0f / 60.0f);
                }

                //In order to get the collection setup I need to enter in game
                testWorld.Connect(1.0f / 60f, 16);
                testWorld.GoInGame();
                testWorld.SpawnOnServer(ghostGameObject);

                for (int i = 0; i < 16; ++i)
                {
                    testWorld.Tick(1.0f / 60.0f);
                }

                var typeIndex = TypeManager.GetTypeIndex <Transforms.Translation>();
                //Then check the expected results
                var collection = testWorld.TryGetSingletonEntity <GhostCollection>(testWorld.ServerWorld);
                var ghostSerializerCollection = testWorld.ServerWorld.EntityManager.GetBuffer <GhostComponentSerializer.State>(collection);
                //Check that the variant has been registered
                bool variantIsPresent = false;
                foreach (var t in ghostSerializerCollection)
                {
                    variantIsPresent |= t.VariantHash == hash;
                }
                Assert.IsTrue(variantIsPresent);

                var componentIndex        = testWorld.ServerWorld.EntityManager.GetBuffer <GhostCollectionComponentIndex>(collection);
                var ghostPrefabCollection = testWorld.ServerWorld.EntityManager.GetBuffer <GhostCollectionPrefabSerializer>(collection);
                //And verify that the component associated with the ghost for the transform point to this index
                for (int i = 0; i < ghostPrefabCollection[0].NumComponents; ++i)
                {
                    var idx = componentIndex[ghostPrefabCollection[0].FirstComponent + i];
                    if (ghostSerializerCollection[idx.SerializerIndex].ComponentType.TypeIndex == typeIndex)
                    {
                        Assert.IsTrue(ghostSerializerCollection[idx.SerializerIndex].VariantHash == hash);
                    }
                }
            }
        }
Ejemplo n.º 21
0
        public void OverrideComponentPrefabType_RootEntity()
        {
            using (var testWorld = new NetCodeTestWorld())
            {
                testWorld.Bootstrap(true);
                var names       = new[] { "ServerOnly", "ClientOnly", "PredictedOnly", "InterpolatedOnly" };
                var prefabTypes = new[] { GhostPrefabType.Server, GhostPrefabType.Client, GhostPrefabType.InterpolatedClient, GhostPrefabType.PredictedClient };
                var collection  = CreatePrefabs(names);
                //overrides the component prefab types in different prefabs
                for (int i = 0; i < prefabTypes.Length; ++i)
                {
                    var authoring = collection[i].GetComponent <GhostAuthoringComponent>();
                    authoring.ComponentOverrides = new List <GhostAuthoringComponent.ComponentOverride>
                    {
                        new GhostAuthoringComponent.ComponentOverride
                        {
                            fullTypeName           = typeof(GhostGen_IntStruct).FullName,
                            gameObject             = collection[i],
                            PrefabType             = (int)prefabTypes[i],
                            OwnerPredictedSendType = (int)GhostSendType.All,
                            ComponentVariant       = 0
                        }
                    };
                }

                Assert.IsTrue(testWorld.CreateGhostCollection(collection));
                testWorld.CreateWorlds(true, 1);

                //Register serializers and setup all the system
                for (int i = 0; i < 16; ++i)
                {
                    testWorld.Tick(1.0f / 60.0f);
                }

                //Then check the expected results
                var ghostCollection = testWorld.TryGetSingletonEntity <GhostPrefabCollectionComponent>(testWorld.ServerWorld);
                var prefabList      = testWorld.ServerWorld.EntityManager.GetBuffer <GhostPrefabBuffer>(ghostCollection).ToNativeArray(Allocator.Temp);
                Assert.AreEqual(4, prefabList.Length);
                for (int i = 0; i < prefabList.Length; ++i)
                {
                    if ((prefabTypes[i] & GhostPrefabType.Server) != 0)
                    {
                        Assert.IsTrue(testWorld.ServerWorld.EntityManager.HasComponent <GhostGen_IntStruct>(prefabList[i].Value));
                    }
                    else
                    {
                        Assert.IsFalse(testWorld.ServerWorld.EntityManager.HasComponent <GhostGen_IntStruct>(prefabList[i].Value));
                    }
                    var linkedGroupBuffer = testWorld.ServerWorld.EntityManager.GetBuffer <LinkedEntityGroup>(prefabList[i].Value);
                    Assert.IsTrue(testWorld.ServerWorld.EntityManager.HasComponent <GhostGen_IntStruct>(linkedGroupBuffer[1].Value));
                }

                ghostCollection = testWorld.TryGetSingletonEntity <GhostPrefabCollectionComponent>(testWorld.ClientWorlds[0]);
                prefabList      = testWorld.ClientWorlds[0].EntityManager.GetBuffer <GhostPrefabBuffer>(ghostCollection).ToNativeArray(Allocator.Temp);
                Assert.AreEqual(4, prefabList.Length);
                for (int i = 0; i < prefabList.Length; ++i)
                {
                    if ((prefabTypes[i] & GhostPrefabType.Client) != 0)
                    {
                        Assert.IsTrue(testWorld.ClientWorlds[0].EntityManager.HasComponent <GhostGen_IntStruct>(prefabList[i].Value));
                    }
                    else
                    {
                        Assert.IsFalse(testWorld.ClientWorlds[0].EntityManager.HasComponent <GhostGen_IntStruct>(prefabList[i].Value));
                    }
                    var linkedGroupBuffer = testWorld.ClientWorlds[0].EntityManager.GetBuffer <LinkedEntityGroup>(prefabList[i].Value);
                    Assert.IsTrue(testWorld.ClientWorlds[0].EntityManager.HasComponent <GhostGen_IntStruct>(linkedGroupBuffer[1].Value));
                }
            }
        }
        private void TestHelper(bool predicted, bool ownerPrediction)
        {
            using (var testWorld = new NetCodeTestWorld())
            {
                testWorld.Bootstrap(true);

                var ghostGameObject = new GameObject();
                ghostGameObject.AddComponent <TestNetCodeAuthoring>().Converter = new GhostPredictedOnlyConverter();
                var ghostConfig = ghostGameObject.AddComponent <GhostAuthoringComponent>();
                if (ownerPrediction)
                {
                    ghostConfig.DefaultGhostMode = GhostAuthoringComponent.GhostMode.OwnerPredicted;
                }
                else
                {
                    ghostConfig.SupportedGhostModes = predicted ? GhostAuthoringComponent.GhostModeMask.Predicted : GhostAuthoringComponent.GhostModeMask.Interpolated;
                }

                Assert.IsTrue(testWorld.CreateGhostCollection(ghostGameObject));

                testWorld.CreateWorlds(true, 1);

                testWorld.SpawnOnServer(ghostGameObject);
                var serverEnt = testWorld.TryGetSingletonEntity <GhostPredictedOnly>(testWorld.ServerWorld);
                Assert.AreNotEqual(Entity.Null, serverEnt);
                testWorld.ServerWorld.EntityManager.SetComponentData(serverEnt, new GhostPredictedOnly {
                    Value = 1
                });
                testWorld.ServerWorld.EntityManager.SetComponentData(serverEnt, new GhostInterpolatedOnly {
                    Value = 1
                });
                testWorld.ServerWorld.EntityManager.SetComponentData(serverEnt, new GhostOwnerComponent {
                    NetworkId = predicted ? 1 : 2
                });

                float frameTime = 1.0f / 60.0f;
                // Connect and make sure the connection could be established
                Assert.IsTrue(testWorld.Connect(frameTime, 4));

                // Check the clients network id
                var serverCon = testWorld.TryGetSingletonEntity <NetworkIdComponent>(testWorld.ServerWorld);
                Assert.AreNotEqual(Entity.Null, serverCon);
                Assert.AreEqual(1, testWorld.ServerWorld.EntityManager.GetComponentData <NetworkIdComponent>(serverCon).Value);

                // Go in-game
                testWorld.GoInGame();

                // Let the game run for a bit so the ghosts are spawned on the client
                for (int i = 0; i < 64; ++i)
                {
                    testWorld.Tick(frameTime);
                }

                // Check that the client world has the right thing and value
                var clientEnt = testWorld.TryGetSingletonEntity <GhostOwnerComponent>(testWorld.ClientWorlds[0]);
                Assert.AreNotEqual(Entity.Null, clientEnt);
                Assert.AreEqual(predicted, testWorld.ClientWorlds[0].EntityManager.HasComponent <PredictedGhostComponent>(clientEnt));
                Assert.AreEqual(predicted ? 0 : 1, testWorld.ClientWorlds[0].EntityManager.GetComponentData <GhostInterpolatedOnly>(clientEnt).Value);
                Assert.AreEqual(predicted ? 1 : 0, testWorld.ClientWorlds[0].EntityManager.GetComponentData <GhostPredictedOnly>(clientEnt).Value);
            }
        }
Ejemplo n.º 23
0
        public void ServerGhostCountOnlyIncludesRelevantSet()
        {
            using (var testWorld = new NetCodeTestWorld())
            {
                testWorld.Bootstrap(true);

                var ghostGameObject = new GameObject();
                ghostGameObject.AddComponent <TestNetCodeAuthoring>().Converter = new LateJoinCompletionConverter();

                Assert.IsTrue(testWorld.CreateGhostCollection(ghostGameObject));

                testWorld.CreateWorlds(true, 1);

                float frameTime = 1.0f / 60.0f;
                // Connect and make sure the connection could be established
                Assert.IsTrue(testWorld.Connect(frameTime, 4));

                for (int i = 0; i < 8; ++i)
                {
                    testWorld.SpawnOnServer(ghostGameObject);
                }

                // Go in-game
                testWorld.GoInGame();

                testWorld.Tick(frameTime);

                // Setup relevancy
                var ghostSendSystem = testWorld.ServerWorld.GetExistingSystem <GhostSendSystem>();
                ghostSendSystem.GhostRelevancyMode = GhostRelevancyMode.SetIsRelevant;
                var serverConnectionEnt = testWorld.TryGetSingletonEntity <NetworkIdComponent>(testWorld.ServerWorld);
                var serverConnectionId  = testWorld.ServerWorld.EntityManager.GetComponentData <NetworkIdComponent>(serverConnectionEnt).Value;
                var query  = testWorld.ServerWorld.EntityManager.CreateEntityQuery(ComponentType.ReadWrite <GhostComponent>());
                var ghosts = query.ToComponentDataArray <GhostComponent>(Allocator.Temp);
                Assert.AreEqual(ghosts.Length, 8);
                for (int i = 0; i < 6; ++i)
                {
                    ghostSendSystem.GhostRelevancySet.TryAdd(new RelevantGhostForConnection {
                        Ghost = ghosts[i].ghostId, Connection = serverConnectionId
                    }, 1);
                }

                // Let the game run for a bit so the ghosts are spawned on the client
                for (int i = 0; i < 4; ++i)
                {
                    testWorld.Tick(frameTime);
                }

                var ghostReceiveSystem = testWorld.ClientWorlds[0].GetExistingSystem <GhostReceiveSystem>();
                // Validate that the ghost was deleted on the cliet
                Assert.AreEqual(6, ghostReceiveSystem.GhostCountOnServer);
                Assert.AreEqual(6, ghostReceiveSystem.GhostCountOnClient);

                // Spawn a few more and verify taht the count is updated
                for (int i = 0; i < 8; ++i)
                {
                    testWorld.SpawnOnServer(ghostGameObject);
                }
                for (int i = 0; i < 4; ++i)
                {
                    testWorld.Tick(frameTime);
                }
                Assert.AreEqual(6, ghostReceiveSystem.GhostCountOnServer);
                Assert.AreEqual(6, ghostReceiveSystem.GhostCountOnClient);
            }
        }
Ejemplo n.º 24
0
        public void PartialPredictionTicksAreRolledBack()
        {
            using (var testWorld = new NetCodeTestWorld())
            {
                testWorld.Bootstrap(true, typeof(PredictionTestPredictionSystem));
                PredictionTestPredictionSystem.s_IsEnabled = true;

                var ghostGameObject = new GameObject();
                ghostGameObject.AddComponent <TestNetCodeAuthoring>().Converter = new PredictionTestConverter();
                var ghostConfig = ghostGameObject.AddComponent <GhostAuthoringComponent>();
                ghostConfig.DefaultGhostMode = GhostAuthoringComponent.GhostMode.Predicted;

                Assert.IsTrue(testWorld.CreateGhostCollection(ghostGameObject));

                testWorld.CreateWorlds(true, 1);

                var serverEnt = testWorld.SpawnOnServer(ghostGameObject);
                Assert.AreNotEqual(Entity.Null, serverEnt);

                // Connect and make sure the connection could be established
                Assert.IsTrue(testWorld.Connect(frameTime, 4));

                // Go in-game
                testWorld.GoInGame();

                // Let the game run for a bit so the ghosts are spawned on the client
                for (int i = 0; i < 16; ++i)
                {
                    testWorld.Tick(frameTime);
                }

                var clientEnt = testWorld.TryGetSingletonEntity <GhostOwnerComponent>(testWorld.ClientWorlds[0]);
                Assert.AreNotEqual(Entity.Null, clientEnt);

                var prevServer = testWorld.ServerWorld.EntityManager.GetComponentData <Translation>(serverEnt).Value;
                var prevClient = testWorld.ClientWorlds[0].EntityManager.GetComponentData <Translation>(clientEnt).Value;
                for (int i = 0; i < 64; ++i)
                {
                    testWorld.Tick(frameTime / 4);
                    var curServer = testWorld.ServerWorld.EntityManager.GetComponentData <Translation>(serverEnt).Value;
                    var curClient = testWorld.ClientWorlds[0].EntityManager.GetComponentData <Translation>(clientEnt).Value;
                    // Server does not do fractional ticks so it will not advance the position every frame
                    Assert.GreaterOrEqual(curServer.x, prevServer.x);
                    // Client does fractional ticks and position should be always increasing
                    Assert.Greater(curClient.x, prevClient.x);
                    prevServer = curServer;
                    prevClient = curClient;
                }

                // Stop updating, let it run for a while and check that they ended on the same value
                PredictionTestPredictionSystem.s_IsEnabled = false;
                for (int i = 0; i < 16; ++i)
                {
                    testWorld.Tick(frameTime);
                }

                prevServer = testWorld.ServerWorld.EntityManager.GetComponentData <Translation>(serverEnt).Value;
                prevClient = testWorld.ClientWorlds[0].EntityManager.GetComponentData <Translation>(clientEnt).Value;
                Assert.IsTrue(math.distance(prevServer, prevClient) < 0.01);
            }
        }