Beispiel #1
0
        /// <summary>
        /// Write player state into the network message.
        /// </summary>
        /// <param name="msg">Message to write to.</param>
        public void WriteSpawnState(Messages.FullWorldSyncMessage msg)
        {
            msg.spawnPosition = Utils.GameVec3ToNet(GetPosition());
            msg.spawnRotation = Utils.GameQuatToNet(GetRotation());

            msg.pickedUpObject = NetPickupable.INVALID_ID;
        }
Beispiel #2
0
        /// <summary>
        /// Handle full world sync message.
        /// </summary>
        /// <param name="msg">The message to handle.</param>

        public void HandleFullWorldSync(Messages.FullWorldSyncMessage msg)
        {
            // Doors.

            foreach (Messages.DoorsInitMessage door in msg.doors)
            {
                Vector3 position            = Utils.NetVec3ToGame(door.position);
                Game.Objects.GameDoor doors = Game.GameDoorsManager.Instance.FindGameDoors(position);
                Client.Assert(doors != null, $"Unable to find doors at: {position}.");
                if (doors.IsOpen != door.open)
                {
                    doors.Open(door.open);
                }
            }

            // Vehicles.

            foreach (Messages.VehicleInitMessage vehicleMsg in msg.vehicles)
            {
                Vector3    pos = Utils.NetVec3ToGame(vehicleMsg.transform.position);
                Quaternion rot = Utils.NetQuatToGame(vehicleMsg.transform.rotation);

                NetVehicle vehicle = GetVehicle(vehicleMsg.id);
                Client.Assert(vehicle != null, $"Received info about non existing vehicle {vehicleMsg.id} in full world sync. (pos: {pos}, rot: {rot})");

                vehicle.Teleport(pos, rot);
            }

            // Pickupables

            foreach (Messages.PickupableSpawnMessage pickupableMsg in msg.pickupables)
            {
                SpawnPickupable(pickupableMsg);
            }
        }
Beispiel #3
0
        /// <summary>
        /// Write player state into the network message.
        /// </summary>
        /// <param name="msg">Message to write to.</param>
        public void WriteSpawnState(Messages.FullWorldSyncMessage msg)
        {
            msg.spawnPosition = Utils.GameVec3ToNet(GetPosition());
            msg.spawnRotation = Utils.GameQuatToNet(GetRotation());

            if (state == State.OnFoot)
            {
                msg.occupiedVehicleId = NetVehicle.INVALID_ID;
            }
            else
            {
                msg.occupiedVehicleId = currentVehicle.NetId;
                msg.passenger         = state == State.Passenger;
            }

            msg.pickedUpObject = NetPickupable.INVALID_ID;

            GamePlayer player = GameWorld.Instance.Player;

            if (player != null)
            {
                // It is possible the local player is not spawned yet. If so we do not
                // care about those values as those can be only set when player is actually spawned.

                var pickedUpObject = player.PickedUpObject;
                if (pickedUpObject != null)
                {
                    msg.pickedUpObject = netWorld.GetPickupableNetId(pickedUpObject);
                }
            }
        }
Beispiel #4
0
        /// <summary>
        /// Write full world synchronization message.
        /// </summary>
        /// <param name="msg">The message to write to.</param>
        public void WriteFullWorldSync(Messages.FullWorldSyncMessage msg)
        {
            // Write doors

            List <Game.Objects.GameDoor> doors = Game.GameDoorsManager.Instance.doors;
            int doorsCount = doors.Count;

            msg.doors = new Messages.DoorsInitMessage[doorsCount];

            for (int i = 0; i < doorsCount; ++i)
            {
                var doorMsg = new Messages.DoorsInitMessage();
                Game.Objects.GameDoor door = doors[i];
                doorMsg.position = Utils.GameVec3ToNet(door.Position);
                doorMsg.open     = door.IsOpen;
                msg.doors[i]     = doorMsg;
            }

            // Write vehicles.

            int vehiclesCount = vehicles.Count;

            msg.vehicles = new Messages.VehicleInitMessage[vehiclesCount];

            for (int i = 0; i < vehiclesCount; ++i)
            {
                var        vehicleMsg = new Messages.VehicleInitMessage();
                NetVehicle vehicle    = vehicles[i];
                vehicleMsg.id = vehicle.NetId;
                vehicleMsg.transform.position = Utils.GameVec3ToNet(vehicle.GetPosition());
                vehicleMsg.transform.rotation = Utils.GameQuatToNet(vehicle.GetRotation());
                msg.vehicles[i] = vehicleMsg;
            }

            // Write pickupables.

            msg.pickupables = new Messages.PickupableSpawnMessage[netPickupables.Count];
            int idx = 0;

            foreach (var kv in netPickupables)
            {
                NetPickupable pickupable    = kv.Value;
                var           pickupableMsg = new Messages.PickupableSpawnMessage();
                pickupableMsg.id = pickupable.NetId;
                // Logger.Log($"Serializing pickupable: {pickupableMsg.id}. {pickupable.gameObject}");
                var metaData = pickupable.gameObject.GetComponent <Game.Components.PickupableMetaDataComponent>();
                pickupableMsg.prefabId = metaData.prefabId;
                Transform transform = pickupable.gameObject.transform;
                pickupableMsg.transform.position = Utils.GameVec3ToNet(transform.position);
                pickupableMsg.transform.rotation = Utils.GameQuatToNet(transform.rotation);
                msg.pickupables[idx++]           = pickupableMsg;
            }
        }
Beispiel #5
0
        /// <summary>
        /// Handle full world sync message.
        /// </summary>
        /// <param name="msg">The message to handle.</param>

        public void HandleFullWorldSync(Messages.FullWorldSyncMessage msg)
        {
            // Read time

            Game.GameWorld gameWorld = Game.GameWorld.Instance;
            gameWorld.WorldTime = msg.dayTime;
            gameWorld.WorldDay  = msg.day;

            // Read mailbox name

            gameWorld.PlayerLastName = msg.mailboxName;

            // Doors.

            foreach (Messages.DoorsInitMessage door in msg.doors)
            {
                Vector3 position            = Utils.NetVec3ToGame(door.position);
                Game.Objects.GameDoor doors = Game.GameDoorsManager.Instance.FindGameDoors(position);
                Client.Assert(doors != null, $"Unable to find doors at: {position}.");
                if (doors.IsOpen != door.open)
                {
                    doors.Open(door.open);
                }
            }

            // Lights.

            foreach (Messages.LightSwitchMessage light in msg.lights)
            {
                Vector3 position = Utils.NetVec3ToGame(light.pos);
                Game.Objects.LightSwitch lights = Game.LightSwitchManager.Instance.FindLightSwitch(position);
                Client.Assert(lights != null, $"Unable to find light switch at: {position}.");
                if (lights.SwitchStatus != light.toggle)
                {
                    lights.TurnOn(light.toggle);
                }
            }

            // Weather.

            Game.GameWeatherManager.Instance.SetWeather(msg.currentWeather);

            // Vehicles.

            foreach (Messages.VehicleInitMessage vehicleMsg in msg.vehicles)
            {
                Vector3    pos = Utils.NetVec3ToGame(vehicleMsg.transform.position);
                Quaternion rot = Utils.NetQuatToGame(vehicleMsg.transform.rotation);

                NetVehicle vehicle = GetVehicle(vehicleMsg.id);
                Client.Assert(vehicle != null, $"Received info about non existing vehicle {vehicleMsg.id} in full world sync. (pos: {pos}, rot: {rot})");

                vehicle.Teleport(pos, rot);
            }

            // Pickupables

            List <ushort> pickupablesIds = new List <ushort>();

            foreach (var kv in netPickupables)
            {
                pickupablesIds.Add(kv.Key);
            }

            foreach (Messages.PickupableSpawnMessage pickupableMsg in msg.pickupables)
            {
                SpawnPickupable(pickupableMsg);
                pickupablesIds.Remove(pickupableMsg.id);
            }

            // Remove spawned (and active) pickupables that we did not get info about.

            foreach (ushort id in pickupablesIds)
            {
                GameObject gameObject = netPickupables[id].gameObject;
                if (gameObject && !gameObject.activeSelf)
                {
                    continue;
                }

                DestroyPickupableLocal(id);
            }
        }
Beispiel #6
0
        /// <summary>
        /// Write full world synchronization message.
        /// </summary>
        /// <param name="msg">The message to write to.</param>
        public void WriteFullWorldSync(Messages.FullWorldSyncMessage msg)
        {
            // Write time

            Game.GameWorld gameWorld = Game.GameWorld.Instance;
            msg.dayTime = gameWorld.WorldTime;
            msg.day     = gameWorld.WorldDay;

            // Write mailbox name

            msg.mailboxName = gameWorld.PlayerLastName;

            // Write doors

            List <Game.Objects.GameDoor> doors = Game.GameDoorsManager.Instance.doors;
            int doorsCount = doors.Count;

            msg.doors = new Messages.DoorsInitMessage[doorsCount];

            for (int i = 0; i < doorsCount; ++i)
            {
                var doorMsg = new Messages.DoorsInitMessage();
                Game.Objects.GameDoor door = doors[i];
                doorMsg.position = Utils.GameVec3ToNet(door.Position);
                doorMsg.open     = door.IsOpen;
                msg.doors[i]     = doorMsg;
            }

            // Write light switches.

            List <Game.Objects.LightSwitch> lights = Game.LightSwitchManager.Instance.lightSwitches;
            int lightCount = lights.Count;

            msg.lights = new Messages.LightSwitchMessage[lightCount];

            for (int i = 0; i < lightCount; i++)
            {
                var lightMsg = new Messages.LightSwitchMessage();
                Game.Objects.LightSwitch light = lights[i];
                lightMsg.pos    = Utils.GameVec3ToNet(light.Position);
                lightMsg.toggle = light.SwitchStatus;
                msg.lights[i]   = lightMsg;
            }

            // Write weather

            Game.GameWeatherManager.Instance.WriteWeather(msg.currentWeather);

            // Write vehicles.

            int vehiclesCount = vehicles.Count;

            msg.vehicles = new Messages.VehicleInitMessage[vehiclesCount];

            for (int i = 0; i < vehiclesCount; ++i)
            {
                var        vehicleMsg = new Messages.VehicleInitMessage();
                NetVehicle vehicle    = vehicles[i];
                vehicleMsg.id = vehicle.NetId;
                vehicleMsg.transform.position = Utils.GameVec3ToNet(vehicle.GetPosition());
                vehicleMsg.transform.rotation = Utils.GameQuatToNet(vehicle.GetRotation());
                msg.vehicles[i] = vehicleMsg;
            }

            // Write pickupables.

            var pickupableMessages = new List <Messages.PickupableSpawnMessage>();

            foreach (var kv in netPickupables)
            {
                NetPickupable pickupable = kv.Value;
                if (pickupable.gameObject == null)
                {
                    Logger.Log($"Null ptr of the pickupable game object {pickupable.NetId}");
                    continue;
                }
                var pickupableMsg = new Messages.PickupableSpawnMessage();
                pickupableMsg.id = pickupable.NetId;
                var metaData = pickupable.gameObject.GetComponent <Game.Components.PickupableMetaDataComponent>();
                pickupableMsg.prefabId = metaData.prefabId;
                Transform transform = pickupable.gameObject.transform;
                pickupableMsg.transform.position = Utils.GameVec3ToNet(transform.position);
                pickupableMsg.transform.rotation = Utils.GameQuatToNet(transform.rotation);
                pickupableMsg.active             = pickupable.gameObject.activeSelf;
                List <float> data = new List <float>();

                //Beercases
                if (metaData.PrefabDescriptor.type == Game.GamePickupableDatabase.PrefabType.BeerCase && pickupable.gameObject.name != "beer case")
                {
                    Game.Objects.BeerCase beer = Game.BeerCaseManager.Instance.FindBeerCase(pickupable.gameObject);
                    data.Add(Game.BeerCaseManager.Instance.FullCaseBottles - beer.UsedBottles);
                }

                if (data.Count != 0)
                {
                    pickupableMsg.Data = data.ToArray();
                }
                pickupableMessages.Add(pickupableMsg);
            }

            msg.pickupables = pickupableMessages.ToArray();

            netManager.GetLocalPlayer().WriteSpawnState(msg);
        }
Beispiel #7
0
        /// <summary>
        /// Register world related network message handlers.
        /// </summary>
        /// <param name="netMessageHandler">The network message handler to register messages to.</param>
        void RegisterNetworkMessagesHandlers(NetMessageHandler netMessageHandler)
        {
            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.PickupableSetPositionMessage msg) => {
                Client.Assert(netPickupables.ContainsKey(msg.id), $"Tried to move pickupable that is not spawned {msg.id}.");
                GameObject gameObject         = netPickupables[msg.id].gameObject;
                gameObject.transform.position = Utils.NetVec3ToGame(msg.position);
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.PickupableActivateMessage msg) => {
                GameObject gameObject = null;
                if (netPickupables.ContainsKey(msg.id))
                {
                    gameObject = netPickupables[msg.id].gameObject;
                }

                if (msg.activate)
                {
                    Client.Assert(gameObject != null, "Tried to activate pickupable but its not spawned!");
                    gameObject.SetActive(true);
                }
                else
                {
                    if (gameObject != null)
                    {
                        gameObject.SetActive(false);
                    }
                }
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.PickupableSpawnMessage msg) => {
                SpawnPickupable(msg);
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.PickupableDestroyMessage msg) => {
                if (!netPickupables.ContainsKey(msg.id))
                {
                    return;
                }

                NetPickupable pickupable = netPickupables[msg.id];
                GameObject.Destroy(pickupable.gameObject);
                netPickupables.Remove(msg.id);
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.WorldPeriodicalUpdateMessage msg) => {
                // Game reports 'next hour' - we want to have transition so correct it.
                Game.GameWorld.Instance.WorldTime = (float)msg.sunClock - 2.0f;
                Game.GameWorld.Instance.WorldDay  = (int)msg.worldDay;
                Game.GameWeatherManager.Instance.SetWeather(msg.currentWeather);
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.RemoveBottleMessage msg) => {
                GameObject beerGO          = GetPickupableGameObject(msg.netId);
                Game.Objects.BeerCase beer = Game.BeerCaseManager.Instance.FindBeerCase(beerGO);
                if (beer == null)
                {
                    Logger.Log($"Player tried to drink beer, however, the beercase cannot be found.");
                    return;
                }
                beer.RemoveBottles(1);
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.PlayerSyncMessage msg) => {
                NetPlayer player = netManager.GetPlayer(sender);
                if (player == null)
                {
                    Logger.Log($"Received synchronization packet from {sender} but there is not player registered using this id.");
                    return;
                }

                player.HandleSynchronize(msg);
            });


            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.OpenDoorsMessage msg) => {
                NetPlayer player = netManager.GetPlayer(sender);
                if (player == null)
                {
                    Logger.Log($"Received OpenDoorsMessage however there is no matching player {sender}! (open: {msg.open}");
                    return;
                }

                Game.Objects.GameDoor doors = Game.GameDoorsManager.Instance.FindGameDoors(Utils.NetVec3ToGame(msg.position));
                if (doors == null)
                {
                    Logger.Log($"Player tried to open door, however, the door could not be found!");
                    return;
                }
                doors.Open(msg.open);
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.FullWorldSyncMessage msg) => {
                NetPlayer player = netManager.GetPlayer(sender);

                // This one should never happen - if happens there is something done miserably wrong.
                Client.Assert(player != null, $"There is no player matching given steam id {sender}.");

                // Handle full world state synchronization.

                HandleFullWorldSync(msg);

                // Spawn host character.

                player.Spawn();

                // Set player state.

                player.Teleport(Utils.NetVec3ToGame(msg.spawnPosition), Utils.NetQuatToGame(msg.spawnRotation));

                if (msg.occupiedVehicleId != NetVehicle.INVALID_ID)
                {
                    var vehicle = GetVehicle(msg.occupiedVehicleId);
                    Client.Assert(vehicle != null, $"Player {player.GetName()} ({player.SteamId}) you tried to join reported that he drives car that does not exists in your game. Vehicle id: {msg.occupiedVehicleId}, passenger: {msg.passenger}");
                    player.EnterVehicle(vehicle, msg.passenger);
                }

                if (msg.pickedUpObject != NetPickupable.INVALID_ID)
                {
                    player.PickupObject(msg.pickedUpObject);
                }

                // World is loaded! Notify network manager about that.

                netManager.OnNetworkWorldLoaded();
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.AskForWorldStateMessage msg) => {
                var msgF = new Messages.FullWorldSyncMessage();
                WriteFullWorldSync(msgF);
                netManager.BroadcastMessage(msgF, Steamworks.EP2PSend.k_EP2PSendReliable);
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.VehicleEnterMessage msg) => {
                NetPlayer player = netManager.GetPlayer(sender);
                if (player == null)
                {
                    Logger.Error($"Steam user of id {sender} send message however there is no active player matching this id.");
                    return;
                }

                NetVehicle vehicle = GetVehicle(msg.vehicleId);
                if (vehicle == null)
                {
                    Logger.Error("Player " + player.SteamId + " tried to enter vehicle " + msg.vehicleId + " but there is no vehicle with such id.");
                    return;
                }

                player.EnterVehicle(vehicle, msg.passenger);
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.VehicleLeaveMessage msg) => {
                NetPlayer player = netManager.GetPlayer(sender);
                if (player == null)
                {
                    Logger.Error($"Steam user of id {sender} send message however there is no active player matching this id.");
                    return;
                }
                player.LeaveVehicle();
            });


            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.VehicleSyncMessage msg) => {
                NetPlayer player = netManager.GetPlayer(sender);
                if (player == null)
                {
                    Logger.Error($"Steam user of id {sender} send message however there is no active player matching this id.");
                    return;
                }
                player.HandleVehicleSync(msg);
            });


            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.PickupObjectMessage msg) => {
                NetPlayer player = netManager.GetPlayer(sender);
                if (player == null)
                {
                    Logger.Error($"Steam user of id {sender} send message however there is no active player matching this id.");
                    return;
                }
                player.PickupObject(msg.netId);
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.ReleaseObjectMessage msg) => {
                NetPlayer player = netManager.GetPlayer(sender);
                if (player == null)
                {
                    Logger.Error($"Steam user of id {sender} send message however there is no active player matching this id.");
                    return;
                }
                player.ReleaseObject(msg.drop);
            });



            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.LightSwitchMessage msg) => {
                Game.Objects.LightSwitch light = Game.LightSwitchManager.Instance.FindLightSwitch(Utils.NetVec3ToGame(msg.pos));
                light.TurnOn(msg.toggle);
            });
        }
Beispiel #8
0
        /// <summary>
        /// Handle full world sync message.
        /// </summary>
        /// <param name="msg">The message to handle.</param>

        public void HandleFullWorldSync(Messages.FullWorldSyncMessage msg)
        {
            Logger.Debug("Handling full world synchronization message.");
            var watch = System.Diagnostics.Stopwatch.StartNew();

            // Read time

            Game.GameWorld gameWorld = Game.GameWorld.Instance;
            gameWorld.WorldTime = msg.dayTime;
            gameWorld.WorldDay  = msg.day;

            // Read mailbox name

            gameWorld.PlayerLastName = msg.mailboxName;

            // Doors.

            foreach (Messages.DoorsInitMessage door in msg.doors)
            {
                Vector3 position            = Utils.NetVec3ToGame(door.position);
                Game.Objects.GameDoor doors =
                    Game.GameDoorsManager.Instance.FindGameDoors(position);
                Client.Assert(doors != null, $"Unable to find doors at: {position}.");
                if (doors.IsOpen != door.open)
                {
                    doors.Open(door.open);
                }
            }

            // Lights.

            foreach (Messages.LightSwitchMessage light in msg.lights)
            {
                Vector3 position = Utils.NetVec3ToGame(light.pos);
                Game.Objects.LightSwitch lights =
                    Game.LightSwitchManager.Instance.FindLightSwitch(position);
                Client.Assert(
                    lights != null, $"Unable to find light switch at: {position}.");
                if (lights.SwitchStatus != light.toggle)
                {
                    lights.TurnOn(light.toggle);
                }
            }

            // Weather.

            GameWeatherManager.Instance.SetWeather(msg.currentWeather);

            // Pickupables

            foreach (Messages.PickupableSpawnMessage pickupableMsg in msg.pickupables)
            {
                SpawnPickupable(pickupableMsg);
            }

            // Remove spawned (and active) pickupables that we did not get info about.

            foreach (var kv in GamePickupableDatabase.Instance.Pickupables)
            {
                if (kv.Value.GetComponent <ObjectSyncComponent>() == null)
                {
                    GameObject.Destroy(kv.Value);
                }
            }

            GamePickupableDatabase.Instance.Pickupables.Clear();
            playerIsLoading = false;

            watch.Stop();
            Logger.Debug("Full world synchronization message has been handled. Took " +
                         watch.ElapsedMilliseconds + "ms");
        }
Beispiel #9
0
        /// <summary>
        /// Write full world synchronization message.
        /// </summary>
        /// <param name="msg">The message to write to.</param>
        public void WriteFullWorldSync(Messages.FullWorldSyncMessage msg)
        {
            Logger.Debug("Writing full world synchronization message.");
            var watch = System.Diagnostics.Stopwatch.StartNew();

            // 'Player is loading' is only applicable for remote client.
            playerIsLoading = false;

            // Write time

            Game.GameWorld gameWorld = Game.GameWorld.Instance;
            msg.dayTime = gameWorld.WorldTime;
            msg.day     = gameWorld.WorldDay;

            // Write mailbox name

            msg.mailboxName = gameWorld.PlayerLastName;

            // Write doors

            List <GameDoor> doors      = GameDoorsManager.Instance.doors;
            int             doorsCount = doors.Count;

            msg.doors = new Messages.DoorsInitMessage[doorsCount];

            Logger.Debug($"Writing state of {doorsCount} doors.");
            for (int i = 0; i < doorsCount; ++i)
            {
                var      doorMsg = new Messages.DoorsInitMessage();
                GameDoor door    = doors[i];
                doorMsg.position = Utils.GameVec3ToNet(door.Position);
                doorMsg.open     = door.IsOpen;
                msg.doors[i]     = doorMsg;
            }

            // Write light switches.

            List <LightSwitch> lights = Game.LightSwitchManager.Instance.lightSwitches;
            int lightCount            = lights.Count;

            msg.lights = new Messages.LightSwitchMessage[lightCount];

            Logger.Debug($"Writing light switches state of {lightCount}");
            for (int i = 0; i < lightCount; i++)
            {
                var         lightMsg = new Messages.LightSwitchMessage();
                LightSwitch light    = lights[i];
                lightMsg.pos    = Utils.GameVec3ToNet(light.Position);
                lightMsg.toggle = light.SwitchStatus;
                msg.lights[i]   = lightMsg;
            }

            // Write weather

            GameWeatherManager.Instance.WriteWeather(msg.currentWeather);

            // Write objects. (Pickupables, Player vehicles, AI vehicles)

            var pickupableMessages = new List <Messages.PickupableSpawnMessage>();

            Logger.Debug(
                $"Writing state of {ObjectSyncManager.Instance.ObjectIDs.Count} objects");
            foreach (var kv in ObjectSyncManager.Instance.ObjectIDs)
            {
                ObjectSyncComponent osc = kv.Value;
                if (osc == null)
                {
                    continue;
                }
                if (osc.ObjectType != ObjectSyncManager.ObjectTypes.Pickupable)
                {
                    continue;
                }
                bool wasActive = true;
                if (!osc.gameObject.activeSelf)
                {
                    wasActive = false;
                    osc.gameObject.SetActive(true);
                }
                Logger.Log($"Writing object: {osc.gameObject.name}");

                var pickupableMsg = new Messages.PickupableSpawnMessage();

                var metaData = osc.gameObject.GetComponent <PickupableMetaDataComponent>();
                Client.Assert(metaData != null && metaData.PrefabDescriptor != null,
                              $"Object with broken meta data -- {osc.gameObject.name}.");

                pickupableMsg.prefabId = metaData.prefabId;

                Transform transform = osc.gameObject.transform;
                pickupableMsg.transform.position = Utils.GameVec3ToNet(transform.position);
                pickupableMsg.transform.rotation = Utils.GameQuatToNet(transform.rotation);

                pickupableMsg.active = osc.gameObject.activeSelf;

                // ObjectID
                pickupableMsg.id =
                    osc.gameObject.GetComponent <ObjectSyncComponent>().ObjectID;

                List <float> data = new List <float>();

                if (data.Count != 0)
                {
                    pickupableMsg.Data = data.ToArray();
                }
                if (!wasActive)
                {
                    osc.gameObject.SetActive(false);
                }
                pickupableMessages.Add(pickupableMsg);
            }

            msg.pickupables = pickupableMessages.ToArray();

            netManager.GetLocalPlayer().WriteSpawnState(msg);

            watch.Stop();
            Logger.Debug(
                "World state has been written. Took " + watch.ElapsedMilliseconds + "ms");
        }
Beispiel #10
0
        /// <summary>
        /// Register world related network message handlers.
        /// </summary>
        /// <param name="netMessageHandler">The network message handler to register
        /// messages to.</param>
        void RegisterNetworkMessagesHandlers(NetMessageHandler netMessageHandler)
        {
            netMessageHandler.BindMessageHandler(
                (Steamworks.CSteamID sender,
                 Messages.PickupableSetPositionMessage msg) => {
                Client.Assert(ObjectSyncManager.Instance.ObjectIDs.ContainsKey(msg.id),
                              $"Tried to move pickupable that is not spawned {msg.id}.");
                GameObject gameObject =
                    ObjectSyncManager.Instance.ObjectIDs[msg.id].gameObject;
                gameObject.transform.position = Utils.NetVec3ToGame(msg.position);
            });

            netMessageHandler.BindMessageHandler(
                (Steamworks.CSteamID sender, Messages.PickupableActivateMessage msg) => {
                GameObject gameObject = null;
                if (ObjectSyncManager.Instance.ObjectIDs.ContainsKey(msg.id))
                {
                    gameObject = ObjectSyncManager.Instance.ObjectIDs[msg.id].gameObject;
                }
                Client.Assert(gameObject != null,
                              "Tried to activate pickupable but its not spawned!");

                if (msg.activate)
                {
                    gameObject.SetActive(true);
                }
                else
                {
                    if (gameObject != null)
                    {
                        gameObject.SetActive(false);
                    }
                }
            });

            netMessageHandler.BindMessageHandler(
                (Steamworks.CSteamID sender, Messages.PickupableSpawnMessage msg) => {
                SpawnPickupable(msg);
            });

            netMessageHandler.BindMessageHandler(
                (Steamworks.CSteamID sender, Messages.PickupableDestroyMessage msg) => {
                if (!ObjectSyncManager.Instance.ObjectIDs.ContainsKey(msg.id))
                {
                    return;
                }

                GameObject go;
                try {
                    go = ObjectSyncManager.Instance.ObjectIDs[msg.id].gameObject;
                } catch {
                    Logger.Error(
                        "Failed to remove object: OSC found but can't get GameObject.");
                    return;
                }

                GameObject.Destroy(
                    ObjectSyncManager.Instance.ObjectIDs[msg.id].gameObject);
            });

            netMessageHandler.BindMessageHandler(
                (Steamworks.CSteamID sender,
                 Messages.WorldPeriodicalUpdateMessage msg) => {
                // Game reports 'next hour' - we want to have transition so correct it.
                GameWorld.Instance.WorldTime = (float)msg.sunClock - 2.0f;
                GameWorld.Instance.WorldDay  = (int)msg.worldDay;
                GameWeatherManager.Instance.SetWeather(msg.currentWeather);
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender,
                                                  Messages.PlayerSyncMessage msg) => {
                NetPlayer player = netManager.GetPlayer(sender);
                if (player == null)
                {
                    Logger.Log(
                        $"Received synchronization packet from {sender} but there is not player registered using this id.");
                    return;
                }

                player.HandleSynchronize(msg);
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender,
                                                  Messages.AnimSyncMessage msg) => {
                NetPlayer player = netManager.GetPlayer(sender);
                if (player == null)
                {
                    Logger.Log(
                        $"Received animation synchronization packet from {sender} but there is not player registered using this id.");
                    return;
                }

                player.HandleAnimSynchronize(msg);
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender,
                                                  Messages.OpenDoorsMessage msg) => {
                NetPlayer player = netManager.GetPlayer(sender);
                if (player == null)
                {
                    Logger.Log(
                        $"Received OpenDoorsMessage however there is no matching player {sender}! (open: {msg.open}");
                    return;
                }

                GameDoor doors = GameDoorsManager.Instance.FindGameDoors(
                    Utils.NetVec3ToGame(msg.position));
                if (doors == null)
                {
                    Logger.Log(
                        $"Player tried to open door, however, the door could not be found!");
                    return;
                }
                doors.Open(msg.open);
            });

            netMessageHandler.BindMessageHandler(
                (Steamworks.CSteamID sender, Messages.FullWorldSyncMessage msg) => {
                NetPlayer player = netManager.GetPlayer(sender);

                // This one should never happen - if happens there is something done
                // miserably wrong.
                Client.Assert(player != null,
                              $"There is no player matching given steam id {sender}.");

                // Handle full world state synchronization.

                HandleFullWorldSync(msg);

                // Spawn host character.

                player.Spawn();

                // Set player state.

                player.Teleport(Utils.NetVec3ToGame(msg.spawnPosition),
                                Utils.NetQuatToGame(msg.spawnRotation));

                if (msg.pickedUpObject != NetPickupable.INVALID_ID)
                {
                    player.PickupObject(msg.pickedUpObject);
                }

                // World is loaded! Notify network manager about that.

                netManager.OnNetworkWorldLoaded();
            });

            netMessageHandler.BindMessageHandler(
                (Steamworks.CSteamID sender, Messages.AskForWorldStateMessage msg) => {
                var msgF = new Messages.FullWorldSyncMessage();
                WriteFullWorldSync(msgF);
                netManager.BroadcastMessage(
                    msgF, Steamworks.EP2PSend.k_EP2PSendReliable);
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender,
                                                  Messages.VehicleEnterMessage msg) => {
                NetPlayer player = netManager.GetPlayer(sender);
                if (player == null)
                {
                    Logger.Error(
                        $"Steam user of id {sender} send message however there is no active player matching this id.");
                    return;
                }

                ObjectSyncComponent vehicle =
                    ObjectSyncManager.Instance.ObjectIDs[msg.objectID];
                if (vehicle == null)
                {
                    Logger.Error("Player " + player.SteamId +
                                 " tried to enter vehicle with Object ID " + msg.objectID +
                                 " but there is no vehicle with such id.");
                    return;
                }

                player.EnterVehicle(vehicle, msg.passenger);
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender,
                                                  Messages.VehicleLeaveMessage msg) => {
                NetPlayer player = netManager.GetPlayer(sender);
                if (player == null)
                {
                    Logger.Error(
                        $"Steam user of id {sender} send message however there is no active player matching this id.");
                    return;
                }
                player.LeaveVehicle();
            });

            netMessageHandler.BindMessageHandler(
                (Steamworks.CSteamID sender, Messages.VehicleStateMessage msg) => {
                float startTime = -1;

                ObjectSyncComponent vehicle =
                    ObjectSyncManager.Instance.ObjectIDs[msg.objectID];
                if (vehicle == null)
                {
                    Logger.Log("Remote player tried to set state of vehicle " +
                               msg.objectID + " but there is no vehicle with such id.");
                    return;
                }

                if (msg.HasStartTime)
                {
                    startTime = msg.StartTime;
                }

                PlayerVehicle subType = vehicle.GetObjectSubtype() as PlayerVehicle;
                subType.SetEngineState((PlayerVehicle.EngineStates)msg.state,
                                       (PlayerVehicle.DashboardStates)msg.dashstate, startTime);
            });

            netMessageHandler.BindMessageHandler(
                (Steamworks.CSteamID sender, Messages.VehicleSwitchMessage msg) => {
                float newValueFloat = -1;

                PlayerVehicle vehicle =
                    ObjectSyncManager.Instance.ObjectIDs[msg.objectID].GetObjectSubtype()
                    as PlayerVehicle;
                if (vehicle == null)
                {
                    Logger.Log("Remote player tried to change a switch in vehicle " +
                               msg.objectID + " but there is no vehicle with such id.");
                    return;
                }

                if (msg.HasSwitchValueFloat)
                {
                    newValueFloat = msg.SwitchValueFloat;
                }

                vehicle.SetVehicleSwitch((PlayerVehicle.SwitchIDs)msg.switchID,
                                         msg.switchValue, newValueFloat);
            });

            netMessageHandler.BindMessageHandler(
                (Steamworks.CSteamID sender, Messages.LightSwitchMessage msg) => {
                LightSwitch light = Game.LightSwitchManager.Instance.FindLightSwitch(
                    Utils.NetVec3ToGame(msg.pos));
                light.TurnOn(msg.toggle);
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender,
                                                  Messages.ObjectSyncMessage msg) => {
                ObjectSyncComponent osc;
                ObjectSyncManager.SyncTypes type = (ObjectSyncManager.SyncTypes)msg.SyncType;
                try {
                    osc = ObjectSyncManager.Instance.ObjectIDs[msg.objectID];
                } catch {
                    Logger.Log(
                        $"Specified object is not yet added to the ObjectID's Dictionary! (Object ID: {msg.objectID})");
                    return;
                }
                if (osc != null)
                {
                    // Set owner.
                    if (type == ObjectSyncManager.SyncTypes.SetOwner)
                    {
                        if (osc.Owner == ObjectSyncManager.NO_OWNER ||
                            osc.Owner == sender.m_SteamID)
                        {
                            osc.OwnerSetToRemote(sender.m_SteamID);
                            netManager.GetLocalPlayer().SendObjectSyncResponse(osc.ObjectID, true);
                        }
                        else
                        {
                            Logger.Debug(
                                $"Set owner request rejected for object: {osc.transform.name} (Owner: {osc.Owner} Sender: {sender.m_SteamID})");
                        }
                    }
                    // Remove owner.
                    else if (type == ObjectSyncManager.SyncTypes.RemoveOwner)
                    {
                        if (osc.Owner == sender.m_SteamID)
                        {
                            osc.OwnerRemoved();
                        }
                    }
                    // Force set owner.
                    else if (type == ObjectSyncManager.SyncTypes.ForceSetOwner)
                    {
                        osc.Owner = sender.m_SteamID;
                        netManager.GetLocalPlayer().SendObjectSyncResponse(osc.ObjectID, true);
                        osc.SyncTakenByForce();
                        osc.SyncEnabled = false;
                    }

                    // Set object's position and variables
                    if (osc.Owner == sender.m_SteamID ||
                        type == ObjectSyncManager.SyncTypes.PeriodicSync)
                    {
                        if (msg.HasSyncedVariables == true)
                        {
                            osc.HandleSyncedVariables(msg.SyncedVariables);
                        }
                        osc.SetPositionAndRotation(Utils.NetVec3ToGame(msg.position),
                                                   Utils.NetQuatToGame(msg.rotation));
                    }
                }
            });

            netMessageHandler.BindMessageHandler(
                (Steamworks.CSteamID sender, Messages.ObjectSyncResponseMessage msg) => {
                ObjectSyncComponent osc =
                    ObjectSyncManager.Instance.ObjectIDs[msg.objectID];
                if (msg.accepted)
                {
                    osc.SyncEnabled = true;
                    osc.Owner       = Steamworks.SteamUser.GetSteamID().m_SteamID;
                }
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender,
                                                  Messages.ObjectSyncRequestMessage
                                                  msg) => {
                try {
                    ObjectSyncComponent osc =
                        ObjectSyncManager.Instance.ObjectIDs[msg.objectID];
                    osc.SendObjectSync(ObjectSyncManager.SyncTypes.GenericSync, true, true);
                } catch {
                    Logger.Error(
                        $"Remote client tried to request object sync of an unknown object, Object ID: {msg.objectID}");
                }
            });

            netMessageHandler.BindMessageHandler(
                (Steamworks.CSteamID sender, Messages.EventHookSyncMessage msg) => {
                if (msg.request)
                {
                    EventHook.SendSync(msg.fsmID);
                }
                else
                {
                    if (msg.HasFsmEventName)
                    {
                        EventHook.HandleEventSync(
                            msg.fsmID, msg.fsmEventID, msg.FsmEventName);
                    }
                    else
                    {
                        EventHook.HandleEventSync(msg.fsmID, msg.fsmEventID);
                    }
                }
            });
        }
Beispiel #11
0
        public NetManager()
        {
            this.netManagerCreationTime = DateTime.UtcNow;
            netWorld = new NetWorld(this);

            // Setup local player.
            players[0] = new NetLocalPlayer(this, netWorld, Steamworks.SteamUser.GetSteamID());

            p2pSessionRequestCallback = Steamworks.Callback <Steamworks.P2PSessionRequest_t> .Create((Steamworks.P2PSessionRequest_t result) => {
                if (!Steamworks.SteamNetworking.AcceptP2PSessionWithUser(result.m_steamIDRemote))
                {
                    Logger.Log("Accepted p2p session with " + result.m_steamIDRemote.ToString());
                }
            });

            gameLobbyJoinRequestedCallback = Steamworks.Callback <Steamworks.GameLobbyJoinRequested_t> .Create(OnGameLobbyJoinRequested);

            lobbyCreatedCallResult = new Steamworks.CallResult <Steamworks.LobbyCreated_t>((Steamworks.LobbyCreated_t result, bool ioFailure) => {
                if (result.m_eResult != Steamworks.EResult.k_EResultOK)
                {
                    Logger.Log("Oh my f*****g god i failed to create a lobby for you. Please forgive me. (result: " + result.m_eResult + ")");

                    MPGUI.Instance.ShowMessageBox("Failed to create lobby due to steam error.\n" + result.m_eResult, () => {
                        MPController.Instance.LoadLevel("MainMenu");
                    });
                    return;
                }

                Logger.Log("Hey you! I have lobby id for you! " + result.m_ulSteamIDLobby);

                mode           = Mode.Host;
                state          = State.Playing;
                currentLobbyId = new Steamworks.CSteamID(result.m_ulSteamIDLobby);

                netWorld.RegisterPickupables();
            });

            lobbyEnterCallResult = new Steamworks.CallResult <Steamworks.LobbyEnter_t>((Steamworks.LobbyEnter_t result, bool ioFailure) => {
                if (result.m_EChatRoomEnterResponse != (uint)Steamworks.EChatRoomEnterResponse.k_EChatRoomEnterResponseSuccess)
                {
                    Logger.Log("Oh my f*****g god i failed to join the lobby for you. Please forgive me. (reponse: " + result.m_EChatRoomEnterResponse + ")");

                    players[1] = null;
                    return;
                }

                Logger.Log("Oh hello! " + result.m_ulSteamIDLobby);

                mode           = Mode.Player;
                state          = State.LoadingGameWorld;
                currentLobbyId = new Steamworks.CSteamID(result.m_ulSteamIDLobby);

                SendHandshake();
            });

            // TODO: Move message handlers to some class.

            BindMessageHandler((Steamworks.CSteamID sender, Messages.HandshakeMessage msg) => {
                remoteClock = msg.clock;
                HandleHandshake(sender, msg);
            });

            BindMessageHandler((Steamworks.CSteamID sender, Messages.PlayerSyncMessage msg) => {
                if (players[1] == null)
                {
                    Logger.Log("Received synchronization packet but no remote player is currently connected.");
                    return;
                }

                players[1].HandleSynchronize(msg);
            });

            BindMessageHandler((Steamworks.CSteamID sender, Messages.HeartbeatMessage msg) => {
                var message         = new Messages.HeartbeatResponseMessage();
                message.clientClock = msg.clientClock;
                message.clock       = GetNetworkClock();
                BroadcastMessage(message, Steamworks.EP2PSend.k_EP2PSendReliable);
            });

            BindMessageHandler((Steamworks.CSteamID sender, Messages.HeartbeatResponseMessage msg) => {
                ping = (uint)(GetNetworkClock() - msg.clientClock);

                // TODO: Some smart lag compensation.
                remoteClock = msg.clock;

                timeSinceLastHeartbeat = 0.0f;
            });

            BindMessageHandler((Steamworks.CSteamID sender, Messages.DisconnectMessage msg) => {
                HandleDisconnect(false);
            });

            BindMessageHandler((Steamworks.CSteamID sender, Messages.OpenDoorsMessage msg) => {
                NetPlayer player = players[1];
                // 1.5 is a length of the ray used to check interaction with doors in game scripts.
                Vector3 interactionPosition = player.GetPosition() + player.GetRotation() * Vector3.forward * 1.5f;
                Game.Objects.GameDoor doors = Game.GameDoorsManager.Instance.FindGameDoors(interactionPosition);
                if (doors == null)
                {
                    Logger.Log($"Player tried to open doors however he is not close to any: {interactionPosition}.");
                    return;
                }
                doors.Open(msg.open);
            });

            BindMessageHandler((Steamworks.CSteamID sender, Messages.FullWorldSyncMessage msg) => {
                netWorld.HandleFullWorldSync(msg);

                // Now spawn player.

                if (players[1] != null)
                {
                    players[1].Spawn();
                }

                // World loaded we are playing!

                state = State.Playing;
            });

            BindMessageHandler((Steamworks.CSteamID sender, Messages.AskForWorldStateMessage msg) => {
                var msgF = new Messages.FullWorldSyncMessage();
                netWorld.WriteFullWorldSync(msgF);
                BroadcastMessage(msgF, Steamworks.EP2PSend.k_EP2PSendReliable);
            });

            BindMessageHandler((Steamworks.CSteamID sender, Messages.VehicleEnterMessage msg) => {
                NetPlayer player = players[1];
                if (player == null)
                {
                    return;
                }

                NetVehicle vehicle = netWorld.GetVehicle(msg.vehicleId);
                if (vehicle == null)
                {
                    Logger.Log("Player " + player.SteamId + " tried to enter vehicle " + msg.vehicleId + " but there is no vehicle with such id.");
                    return;
                }

                player.EnterVehicle(vehicle, msg.passenger);
            });

            BindMessageHandler((Steamworks.CSteamID sender, Messages.VehicleLeaveMessage msg) => {
                NetPlayer player = players[1];
                if (player == null)
                {
                    return;
                }
                player.LeaveVehicle();
            });


            BindMessageHandler((Steamworks.CSteamID sender, Messages.VehicleSyncMessage msg) => {
                NetPlayer player = players[1];
                if (player == null)
                {
                    return;
                }

                player.HandleVehicleSync(msg);
            });


            BindMessageHandler((Steamworks.CSteamID sender, Messages.PickupObjectMessage msg) => {
                NetPlayer player = players[1];
                if (player == null)
                {
                    return;
                }
                player.PickupObject(msg.netId);
            });

            BindMessageHandler((Steamworks.CSteamID sender, Messages.ReleaseObjectMessage msg) => {
                NetPlayer player = players[1];
                if (player == null)
                {
                    return;
                }
                player.ReleaseObject(msg.drop);
            });
        }
Beispiel #12
0
        /// <summary>
        /// Handle full world sync message.
        /// </summary>
        /// <param name="msg">The message to handle.</param>

        public void HandleFullWorldSync(Messages.FullWorldSyncMessage msg)
        {
            Logger.Debug("Handling full world synchronization message.");
            var watch = System.Diagnostics.Stopwatch.StartNew();

            // Read time

            Game.GameWorld gameWorld = GameWorld.Instance;
            gameWorld.WorldTime = msg.dayTime;
            gameWorld.WorldDay  = msg.day;

            // Read mailbox name

            gameWorld.PlayerLastName = msg.mailboxName;

            // Doors.

            foreach (Messages.DoorsInitMessage door in msg.doors)
            {
                Vector3  position = Utils.NetVec3ToGame(door.position);
                GameDoor doors    = GameDoorsManager.Instance.FindGameDoors(position);
                Client.Assert(doors != null, $"Unable to find doors at: {position}.");
                if (doors.IsOpen != door.open)
                {
                    doors.Open(door.open);
                }
            }

            // Lights.

            foreach (Messages.LightSwitchMessage light in msg.lights)
            {
                Vector3     position = Utils.NetVec3ToGame(light.pos);
                LightSwitch lights   = LightSwitchManager.Instance.FindLightSwitch(position);
                Client.Assert(lights != null, $"Unable to find light switch at: {position}.");
                if (lights.SwitchStatus != light.toggle)
                {
                    lights.TurnOn(light.toggle);
                }
            }

            // Pickupables

            foreach (Messages.PickupableSpawnMessage pickupableMsg in msg.pickupables)
            {
                SpawnPickupable(pickupableMsg);
            }

            // Remove spawned (and active) pickupables that we did not get info about.

            foreach (var kv in GamePickupableDatabase.Instance.Pickupables)
            {
                if (kv.Value.GetComponent <ObjectSyncComponent>() == null)
                {
                    GameObject.Destroy(kv.Value);
                }
            }

            // Connected players.

            int i = 0;

            foreach (int newPlayerID in msg.connectedPlayers.playerIDs)
            {
                Steamworks.CSteamID localSteamID     = Steamworks.SteamUser.GetSteamID();
                Steamworks.CSteamID newPlayerSteamID = new Steamworks.CSteamID(msg.connectedPlayers.steamIDs[i]);
                // If player is not host or local player, setup new player.
                if (newPlayerSteamID != netManager.GetHostPlayer().SteamId&& newPlayerSteamID != localSteamID)
                {
                    netManager.players.Add(newPlayerID, new NetPlayer(netManager, this, newPlayerSteamID));
                    netManager.players[newPlayerID].Spawn();
                    Logger.Debug("Setup new player at ID: " + newPlayerID);
                }
                i++;
            }

            // Object owners.

            foreach (Messages.ObjectOwnerSync syncMsg in msg.objectOwners)
            {
                if (syncMsg.ownerPlayerID != -1)
                {
                    ObjectSyncManager.Instance.ObjectIDs[syncMsg.objectID].Owner = netManager.GetPlayerByPlayerID(syncMsg.ownerPlayerID);
                }
            }

            GamePickupableDatabase.Instance.Pickupables.Clear();
            playerIsLoading = false;

            watch.Stop();
            Logger.Debug("Full world synchronization message has been handled. Took " + watch.ElapsedMilliseconds + "ms");
        }
Beispiel #13
0
        /// <summary>
        /// Register world related network message handlers.
        /// </summary>
        /// <param name="netMessageHandler">The network message handler to register messages to.</param>
        void RegisterNetworkMessagesHandlers(NetMessageHandler netMessageHandler)
        {
            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.PickupableSetPositionMessage msg) => {
                Client.Assert(ObjectSyncManager.GetObjectByID(msg.id), $"Tried to move pickupable that is not spawned {msg.id}.");
                GameObject gameObject         = ObjectSyncManager.GetObjectByID(msg.id);
                gameObject.transform.position = Utils.NetVec3ToGame(msg.position);
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.PickupableActivateMessage msg) => {
                GameObject gameObject = null;
                if (ObjectSyncManager.GetObjectByID(msg.id))
                {
                    gameObject = ObjectSyncManager.GetObjectByID(msg.id);
                }
                Client.Assert(gameObject != null, "Tried to activate a pickupable but it's not spawned! Does any connected client or you have other mods beside MSC:MP installed? Try uninstalling them!");

                if (msg.activate)
                {
                    gameObject.SetActive(true);
                }
                else
                {
                    if (gameObject != null)
                    {
                        gameObject.SetActive(false);
                    }
                }
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.PickupableSpawnMessage msg) => {
                SpawnPickupable(msg);
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.PickupableDestroyMessage msg) => {
                if (!ObjectSyncManager.GetSyncComponentByID(msg.id))
                {
                    return;
                }

                ObjectSyncComponent osc = ObjectSyncManager.GetSyncComponentByID(msg.id);

                GameObject.Destroy(ObjectSyncManager.GetObjectByID(msg.id));
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.WorldPeriodicalUpdateMessage msg) => {
                // Game reports 'next hour' - we want to have transition so correct it.
                GameWorld.Instance.WorldTime = (float)msg.sunClock - 2.0f;
                GameWorld.Instance.WorldDay  = (int)msg.worldDay;
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.PlayerSyncMessage msg) => {
                NetPlayer player = netManager.GetPlayer(sender);
                if (player == null)
                {
                    Logger.Error($"Received synchronization packet from {sender} but there is not player registered using this id.");
                    return;
                }

                player.HandleSynchronize(msg);
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.AnimSyncMessage msg) => {
                NetPlayer player = netManager.GetPlayer(sender);
                if (player == null)
                {
                    Logger.Error($"Received animation synchronization packet from {sender} but there is not player registered using this id.");
                    return;
                }

                player.HandleAnimSynchronize(msg);
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.OpenDoorsMessage msg) => {
                NetPlayer player = netManager.GetPlayer(sender);
                if (player == null)
                {
                    Logger.Error($"Received OpenDoorsMessage however there is no matching player {sender}! (open: {msg.open}");
                    return;
                }

                GameDoor doors = GameDoorsManager.Instance.FindGameDoors(Utils.NetVec3ToGame(msg.position));
                if (doors == null)
                {
                    Logger.Error($"Player tried to open door, however, the door could not be found!");
                    return;
                }
                doors.Open(msg.open);
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.FullWorldSyncMessage msg) => {
                NetPlayer player = netManager.GetPlayer(sender);

                // This one should never happen - if happens there is something done miserably wrong.
                Client.Assert(player != null, $"There is no player matching given steam id {sender}.");

                // Handle full world state synchronization.

                HandleFullWorldSync(msg);

                // Spawn host character.

                player.Spawn();

                // Set player state.

                player.Teleport(Utils.NetVec3ToGame(msg.spawnPosition), Utils.NetQuatToGame(msg.spawnRotation));

                if (msg.pickedUpObject != NetPickupable.INVALID_ID)
                {
                    player.PickupObject(msg.pickedUpObject);
                }

                // World is loaded! Notify network manager about that.

                netManager.OnNetworkWorldLoaded();
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.AskForWorldStateMessage msg) => {
                var msgF = new Messages.FullWorldSyncMessage();
                WriteFullWorldSync(msgF);
                netManager.SendMessage(netManager.GetPlayer(sender), msgF, Steamworks.EP2PSend.k_EP2PSendReliable);
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.VehicleEnterMessage msg) => {
                NetPlayer player = netManager.GetPlayer(sender);
                if (player == null)
                {
                    Logger.Error($"Steam user of id {sender} send message however there is no active player matching this id.");
                    return;
                }

                ObjectSyncComponent vehicle = ObjectSyncManager.Instance.ObjectIDs[msg.objectID];
                if (vehicle == null)
                {
                    Logger.Error("Player " + player.SteamId + " tried to enter vehicle with Object ID " + msg.objectID + " but there is no vehicle with such id.");
                    return;
                }

                player.EnterVehicle(vehicle, msg.passenger);
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.VehicleLeaveMessage msg) => {
                NetPlayer player = netManager.GetPlayer(sender);
                if (player == null)
                {
                    Logger.Error($"Steam user of id {sender} send message however there is no active player matching this id.");
                    return;
                }
                player.LeaveVehicle();
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.VehicleSwitchMessage msg) => {
                float newValueFloat = -1;

                PlayerVehicle vehicle = ObjectSyncManager.Instance.ObjectIDs[msg.objectID].GetObjectSubtype() as PlayerVehicle;
                if (vehicle == null)
                {
                    Logger.Debug("Remote player tried to change a switch in vehicle " + msg.objectID + " but there is no vehicle with such id.");
                    return;
                }

                if (msg.HasSwitchValueFloat)
                {
                    newValueFloat = msg.SwitchValueFloat;
                }

                vehicle.SetVehicleSwitch((PlayerVehicle.SwitchIDs)msg.switchID, msg.switchValue, newValueFloat);
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.LightSwitchMessage msg) => {
                LightSwitch light = LightSwitchManager.Instance.FindLightSwitch(Utils.NetVec3ToGame(msg.pos));
                light.TurnOn(msg.toggle);
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.ObjectSyncMessage msg) => {
                ObjectSyncComponent osc;
                ObjectSyncManager.SyncTypes type = (ObjectSyncManager.SyncTypes)msg.SyncType;
                if (ObjectSyncManager.GetObjectByID(msg.objectID))
                {
                    osc = ObjectSyncManager.GetSyncComponentByID(msg.objectID);
                }
                else
                {
                    Logger.Error($"Specified object is not yet added to the ObjectID's Dictionary! (Object ID: {msg.objectID})");
                    return;
                }

                // This *should* never happen, but apparently it's possible.
                Client.Assert(osc != null, $"Object Sync Component wasn't found for object with ID {msg.objectID}, however, the object had a dictionary entry!");

                // Host controls who owns an object.
                if (NetManager.Instance.IsHost)
                {
                    // Set owner on host.
                    if (type == ObjectSyncManager.SyncTypes.SetOwner)
                    {
                        ObjectSyncManager.SetOwnerHandler(msg, osc, sender);
                    }
                    // Remove owner on host.
                    if (type == ObjectSyncManager.SyncTypes.RemoveOwner)
                    {
                        if (osc.Owner == netManager.GetLocalPlayer())
                        {
                            ObjectSyncManager.RemoveOwnerHandler(msg, osc, sender);
                        }
                    }
                    // Sync taken by force on host.
                    if (type == ObjectSyncManager.SyncTypes.ForceSetOwner)
                    {
                        ObjectSyncManager.SyncTakenByForceHandler(msg, osc, sender);
                    }
                }

                // Set ownership info on clients.
                else
                {
                    NetPlayer player = netManager.GetPlayerByPlayerID(msg.OwnerPlayerID);
                    // Check if player exists.
                    if (player == null)
                    {
                        return;
                    }
                    // Set owner.
                    if (type == ObjectSyncManager.SyncTypes.SetOwner)
                    {
                        if (osc.Owner != netManager.GetLocalPlayer())
                        {
                            osc.OwnerSetToRemote(player);
                        }
                        osc.Owner = player;
                    }
                    // Remove owner.
                    else if (type == ObjectSyncManager.SyncTypes.RemoveOwner)
                    {
                        if (osc.Owner != netManager.GetLocalPlayer())
                        {
                            osc.OwnerRemoved();
                        }
                        osc.Owner = null;
                    }
                    // Force set owner.
                    else if (type == ObjectSyncManager.SyncTypes.ForceSetOwner)
                    {
                        if (osc.Owner != netManager.GetLocalPlayer())
                        {
                            osc.SyncTakenByForce();
                            osc.SyncEnabled = false;
                        }
                        osc.Owner = player;
                        if (osc.Owner == netManager.GetLocalPlayer())
                        {
                            osc.SyncEnabled = true;
                        }
                    }
                }

                // Set object's position and variables.
                if ((osc.Owner == netManager.GetPlayer(sender)) || type == ObjectSyncManager.SyncTypes.PeriodicSync)
                {
                    // Send synced variables, or variables only sync in some cases.
                    if (msg.HasSyncedVariables)
                    {
                        osc.HandleSyncedVariables(msg.SyncedVariables);
                    }

                    // Full sync.
                    if (msg.HasPosition && msg.HasRotation)
                    {
                        osc.SetPositionAndRotation(Utils.NetVec3ToGame(msg.Position), Utils.NetQuatToGame(msg.Rotation));
                    }
                    // Position only sync.
                    else if (msg.HasPosition)
                    {
                        Quaternion zero = new Quaternion(0, 0, 0, 0);
                        osc.SetPositionAndRotation(Utils.NetVec3ToGame(msg.Position), zero);
                    }
                    // Rotation only sync.
                    else if (msg.HasRotation)
                    {
                        osc.SetPositionAndRotation(Vector3.zero, Utils.NetQuatToGame(msg.Rotation));
                    }
                }
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.ObjectSyncResponseMessage msg) => {
                ObjectSyncComponent osc = ObjectSyncManager.GetSyncComponentByID(msg.objectID);
                if (msg.accepted)
                {
                    osc.SyncEnabled = true;
                    osc.Owner       = NetManager.Instance.GetLocalPlayer();
                }
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.ObjectSyncRequestMessage msg) => {
                Client.Assert(ObjectSyncManager.GetObjectByID(msg.objectID), $"Remote client tried to request object sync of an unknown object, remote ObjectID was: {msg.objectID}");

                ObjectSyncComponent osc = ObjectSyncManager.GetSyncComponentByID(msg.objectID);
                osc.SendObjectSync(ObjectSyncManager.SyncTypes.GenericSync, true, true);
            });

            netMessageHandler.BindMessageHandler((Steamworks.CSteamID sender, Messages.EventHookSyncMessage msg) => {
                if (msg.request)
                {
                    EventHook.SendSync(msg.fsmID);
                    return;
                }

                if (msg.HasFsmEventName)
                {
                    EventHook.HandleEventSync(msg.fsmID, msg.fsmEventID, msg.FsmEventName);
                }
                else
                {
                    EventHook.HandleEventSync(msg.fsmID, msg.fsmEventID);
                }
            });
        }
Beispiel #14
0
        /// <summary>
        /// Write full world synchronization message.
        /// </summary>
        /// <param name="msg">The message to write to.</param>
        public void WriteFullWorldSync(Messages.FullWorldSyncMessage msg)
        {
            Logger.Debug("Writing full world synchronization message.");
            var watch = System.Diagnostics.Stopwatch.StartNew();

            // 'Player is loading' is only applicable for remote client.
            playerIsLoading = false;

            // Write time

            GameWorld gameWorld = GameWorld.Instance;

            msg.dayTime = gameWorld.WorldTime;
            msg.day     = gameWorld.WorldDay;

            // Write mailbox name

            msg.mailboxName = gameWorld.PlayerLastName;

            // Write doors

            List <GameDoor> doors      = GameDoorsManager.Instance.doors;
            int             doorsCount = doors.Count;

            msg.doors = new Messages.DoorsInitMessage[doorsCount];

            Logger.Debug($"Writing state of {doorsCount} doors.");
            for (int i = 0; i < doorsCount; ++i)
            {
                var      doorMsg = new Messages.DoorsInitMessage();
                GameDoor door    = doors[i];
                doorMsg.position = Utils.GameVec3ToNet(door.Position);
                doorMsg.open     = door.IsOpen;
                msg.doors[i]     = doorMsg;
            }

            // Write light switches.

            List <LightSwitch> lights = Game.LightSwitchManager.Instance.lightSwitches;
            int lightCount            = lights.Count;

            msg.lights = new Messages.LightSwitchMessage[lightCount];

            Logger.Debug($"Writing light switches state of {lightCount}");
            for (int i = 0; i < lightCount; i++)
            {
                var         lightMsg = new Messages.LightSwitchMessage();
                LightSwitch light    = lights[i];
                lightMsg.pos    = Utils.GameVec3ToNet(light.Position);
                lightMsg.toggle = light.SwitchStatus;
                msg.lights[i]   = lightMsg;
            }

            // Write connected players.

            msg.connectedPlayers = new Messages.ConnectedPlayersMessage();
            int[]   playerIDs = new int[netManager.players.Count];
            ulong[] steamIDs  = new ulong[netManager.players.Count];
            int     index2    = 0;

            foreach (var connectedPlayer in netManager.players)
            {
                playerIDs[index2] = connectedPlayer.Key;
                steamIDs[index2]  = connectedPlayer.Value.SteamId.m_SteamID;
                index2++;
            }
            msg.connectedPlayers.playerIDs = playerIDs;
            msg.connectedPlayers.steamIDs  = steamIDs;

            // Write objects. (Pickupables, Player vehicles, AI vehicles)

            var pickupableMessages = new List <Messages.PickupableSpawnMessage>();

            Logger.Debug($"Writing state of {ObjectSyncManager.Instance.ObjectIDs.Count} objects");
            foreach (var kv in ObjectSyncManager.Instance.ObjectIDs)
            {
                ObjectSyncComponent osc = kv.Value;
                if (osc == null)
                {
                    continue;
                }
                if (osc.ObjectType != ObjectSyncManager.ObjectTypes.Pickupable)
                {
                    continue;
                }
                bool wasActive = true;
                if (!osc.gameObject.activeSelf)
                {
                    wasActive = false;
                    osc.gameObject.SetActive(true);
                }
                if (NetWorld.DisplayObjectRegisteringDebug)
                {
                    Logger.Debug($"Writing object: {osc.gameObject.name}");
                }

                var pickupableMsg = new Messages.PickupableSpawnMessage();

                var metaData = osc.gameObject.GetComponent <PickupableMetaDataComponent>();
                Client.Assert(metaData != null && metaData.PrefabDescriptor != null, $"Object with broken meta data -- {osc.gameObject.name}.");

                pickupableMsg.prefabId = metaData.prefabId;

                Transform transform = osc.gameObject.transform;
                pickupableMsg.transform.position = Utils.GameVec3ToNet(transform.position);
                pickupableMsg.transform.rotation = Utils.GameQuatToNet(transform.rotation);

                pickupableMsg.active = osc.gameObject.activeSelf;

                // ObjectID
                pickupableMsg.id = osc.gameObject.GetComponent <ObjectSyncComponent>().ObjectID;

                List <float> data = new List <float>();

                if (data.Count != 0)
                {
                    pickupableMsg.Data = data.ToArray();
                }
                if (!wasActive)
                {
                    osc.gameObject.SetActive(false);
                }
                pickupableMessages.Add(pickupableMsg);
            }

            // Object owners.

            int objectsCount = ObjectSyncManager.Instance.ObjectIDs.Count;

            msg.objectOwners = new Messages.ObjectOwnerSync[objectsCount];

            Dictionary <NetPlayer, int> playersReversed = new Dictionary <NetPlayer, int>();

            foreach (var player in netManager.players)
            {
                playersReversed.Add(player.Value, player.Key);
            }

            Logger.Debug($"Writing owners of {objectsCount} objects!");
            int index = 0;

            foreach (var objectId in ObjectSyncManager.Instance.ObjectIDs)
            {
                var objectMsg = new Messages.ObjectOwnerSync();
                objectMsg.objectID = objectId.Key;
                if (objectId.Value.Owner != null)
                {
                    objectMsg.ownerPlayerID = playersReversed[objectId.Value.Owner];
                }
                else
                {
                    objectMsg.ownerPlayerID = -1;
                }
                msg.objectOwners[index] = objectMsg;
                index++;
            }

            msg.pickupables = pickupableMessages.ToArray();

            netManager.GetLocalPlayer().WriteSpawnState(msg);

            watch.Stop();
            Logger.Debug("World state has been written. Took " + watch.ElapsedMilliseconds + "ms");

            // Write player keys.

            int[] keys =
            {
                HutongGames.PlayMaker.FsmVariables.GlobalVariables.GetFsmInt("PlayerKeyGifu").Value,
                HutongGames.PlayMaker.FsmVariables.GlobalVariables.GetFsmInt("PlayerKeyHayosiko").Value,
                HutongGames.PlayMaker.FsmVariables.GlobalVariables.GetFsmInt("PlayerKeyFerndale").Value,
                HutongGames.PlayMaker.FsmVariables.GlobalVariables.GetFsmInt("PlayerKeyHome").Value,
                HutongGames.PlayMaker.FsmVariables.GlobalVariables.GetFsmInt("PlayerKeyRuscko").Value,
                HutongGames.PlayMaker.FsmVariables.GlobalVariables.GetFsmInt("PlayerKeySatsuma").Value
            };
            msg.playerKeys = keys;

            // Write uncle states.

            msg.uncleStage = UncleManager.Instance.UncleStage;
            msg.uncleTime  = UncleManager.Instance.UncleTime;
            msg.uncleHome  = UncleManager.Instance.UncleHome;
        }