Example #1
0
 /// <summary>
 /// Adds new object to the ObjectIDs Dictionary.
 /// </summary>
 /// <param name="osc">Object to add.</param>
 /// <param name="objectID">Object ID to assign to object.</param>
 /// <returns>ObjectID of object.</returns>
 public int AddNewObject(ObjectSyncComponent osc, int objectID)
 {
     // Assign ObjectID automatically.
     if (objectID == AUTOMATIC_ID)
     {
         if (steamID.m_SteamID == 0)
         {
             steamID = Steamworks.SteamUser.GetSteamID();
         }
         Logger.Debug($"Added new ObjectID at: {ObjectIDs.Count + 1}");
         ObjectIDs.GetOrAdd(ObjectIDs.Count + 1, osc);
         return(ObjectIDs.Count);
     }
     // Assign object a specific ObjectID.
     else
     {
         Logger.Debug($"Force adding new ObjectID at: {objectID}");
         if (ObjectIDs.ContainsKey(objectID))
         {
             ObjectIDs[objectID] = osc;
         }
         else
         {
             ObjectIDs.GetOrAdd(objectID, osc);
         }
         return(objectID);
     }
 }
Example #2
0
        /// <summary>
        /// Constructor.
        /// </summary>
        public VehicleDoor(GameObject go, ObjectSyncComponent syncComponent)
        {
            gameObject = go;
            osc        = syncComponent;

            // Rear door of van and vehicle trunks.
            if (go.name == "RearDoor" || go.name == "Bootlid")
            {
                doorType = DoorTypes.RearDoor;
                // Van, Old car.
                if (go.transform.FindChild("doorear"))
                {
                    gameObject = go.transform.FindChild("doorear").gameObject;
                }
                // Ferndale.
                else
                {
                    gameObject = go.transform.FindChild("Bootlid").gameObject;
                }
            }
            // Driver and passenger doors.
            else if (go.name == "doorl" || go.name == "doorr" || go.name == "door(leftx)" || go.name == "door(right)")
            {
                doorType = DoorTypes.DriverDoor;
            }

            hinge        = gameObject.GetComponent <HingeJoint>();
            lastRotation = hinge.angle;
            rigidbody    = gameObject.GetComponent <Rigidbody>();

            HookEvents();
        }
Example #3
0
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="go"></param>
        public AIVehicle(GameObject go, ObjectSyncComponent osc)
        {
            gameObject       = go;
            syncComponent    = osc;
            parentGameObject = go.transform.parent.gameObject;

            // Set vehicle type, used to apply vehicle-specific event hooks.
            string goName = gameObject.transform.parent.gameObject.name;

            if (goName == "AMIS2" || goName == "KYLAJANI")
            {
                type = VehicleTypes.Amis;
            }
            else if (goName == "BUS")
            {
                type = VehicleTypes.Bus;
            }
            else if (goName == "FITTAN" && parentGameObject.transform.FindChild("Navigation") != null)
            {
                type = VehicleTypes.Fitan;
            }
            else if (parentGameObject.transform.FindChild("NavigationCW") != null || parentGameObject.transform.FindChild("NavigationCCW") != null)
            {
                type = VehicleTypes.TrafficDirectional;
            }
            else
            {
                type = VehicleTypes.Traffic;
            }

            rigidbody = parentGameObject.GetComponent <Rigidbody>();

            dynamics = parentGameObject.GetComponent <CarDynamics>();

            throttleFsm = Utils.GetPlaymakerScriptByName(parentGameObject, "Throttle");

            if (type == VehicleTypes.TrafficDirectional)
            {
                if (parentGameObject.transform.FindChild("NavigationCW") != null)
                {
                    navigationFsm = Utils.GetPlaymakerScriptByName(parentGameObject.transform.FindChild("NavigationCW").gameObject, "Navigation");
                    isClockwise   = 1;
                }
                else
                {
                    navigationFsm = Utils.GetPlaymakerScriptByName(parentGameObject.transform.FindChild("NavigationCCW").gameObject, "Navigation");
                    isClockwise   = 0;
                }
                directionFsm = Utils.GetPlaymakerScriptByName(parentGameObject, "Direction");
            }
            else
            {
                navigationFsm = Utils.GetPlaymakerScriptByName(parentGameObject.transform.FindChild("Navigation").gameObject, "Navigation");
            }

            EventHooks();
        }
Example #4
0
        /// <summary>
        /// Handle pickup of the object.
        /// </summary>
        private void PickupObject()
        {
            pickedUpGameObject = pickupFsm.Fsm.GetFsmGameObject("PickedObject").Value;
            ObjectSyncComponent osc = pickedUpGameObject.GetComponent <ObjectSyncComponent>();

            osc.TakeSyncControl();
            osc.SendConstantSync(true);

            Logger.Log("Picked up object: " + pickedUpGameObject);
        }
Example #5
0
 /// <summary>
 /// Write vehicle switch changes into vehicle switch message.
 /// </summary>
 /// <param name="state">The engine state to write.</param>
 public void WriteVehicleSwitchMessage(ObjectSyncComponent vehicle, PlayerVehicle.SwitchIDs switchID, bool newValue, float newValueFloat)
 {
     Network.Messages.VehicleSwitchMessage msg = new Network.Messages.VehicleSwitchMessage();
     msg.objectID    = vehicle.ObjectID;
     msg.switchID    = (int)switchID;
     msg.switchValue = newValue;
     if (newValueFloat != -1)
     {
         msg.SwitchValueFloat = newValueFloat;
     }
     NetManager.Instance.BroadcastMessage(msg, Steamworks.EP2PSend.k_EP2PSendReliable);
 }
Example #6
0
        /// <summary>
        /// Constructor.
        /// </summary>
        public Weather(GameObject go, ObjectSyncComponent syncComponent)
        {
            gameObject = go;
            osc        = syncComponent;
            weatherFSM = gameObject.GetComponent <PlayMakerFSM>();

            if (Network.NetManager.Instance.IsHost)
            {
                osc.TakeSyncControl();
            }

            HookEvents();
        }
Example #7
0
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="go"></param>
        public PlayerVehicle(GameObject go, ObjectSyncComponent osc)
        {
            gameObject       = go;
            syncComponent    = osc;
            ParentGameObject = go.transform.parent.parent.gameObject;

            rigidbody  = ParentGameObject.GetComponent <Rigidbody>();
            dynamics   = ParentGameObject.GetComponent <CarDynamics>();
            driveTrain = ParentGameObject.GetComponent <Drivetrain>();

            axisCarController = ParentGameObject.GetComponent <AxisCarController>();
            mpCarController   = ParentGameObject.AddComponent <MPCarController>();

            FindFSMs();
        }
Example #8
0
        /// <summary>
        /// Handle destroy of pickupable game object.
        /// </summary>
        /// <param name="pickupable">The destroyed pickupable.</param>
        public void HandlePickupableDestroy(GameObject pickupable)
        {
            ObjectSyncComponent osc = GetPickupableByGameObject(pickupable);

            if (osc != null)
            {
                Messages.PickupableDestroyMessage msg = new Messages.PickupableDestroyMessage();
                msg.id = osc.ObjectID;
                netManager.BroadcastMessage(msg, Steamworks.EP2PSend.k_EP2PSendReliable);

                Logger.Debug($"Handle pickupable destroy {pickupable.name}, Object ID: {osc.ObjectID}");
            }
            else
            {
                Logger.Debug($"Unhandled pickupable has been destroyed {pickupable.name}");
                Logger.Debug(Environment.StackTrace);
            }
        }
Example #9
0
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="go"></param>
        public PlayerVehicle(GameObject go, ObjectSyncComponent osc)
        {
            gameObject       = go;
            syncComponent    = osc;
            ParentGameObject = go.transform.parent.parent.gameObject;

            if (ParentGameObject.name.StartsWith("JONNEZ"))
            {
                isBike        = true;
                steeringPivot = ParentGameObject.transform.FindChild("LOD/Suspension/Steering/SteeringPivot").gameObject;
            }

            rigidbody  = ParentGameObject.GetComponent <Rigidbody>();
            dynamics   = ParentGameObject.GetComponent <CarDynamics>();
            driveTrain = ParentGameObject.GetComponent <Drivetrain>();

            axisCarController = ParentGameObject.GetComponent <AxisCarController>();
            mpCarController   = ParentGameObject.AddComponent <MPCarController>();

            AddVehicleDoorSync();
            FindFSMs();
        }
Example #10
0
		/// <summary>
		/// Collect given objects.
		/// </summary>
		/// <param name="gameObject">The game object to collect.</param>
		public void CollectGameObject(GameObject gameObject) {
			if (gameObject.name == "SUN" && worldTimeFsm == null) {
				// Yep it's called "Color" :>
				worldTimeFsm = Utils.GetPlaymakerScriptByName(gameObject, "Color");
				if (worldTimeFsm == null) {
					return;
				}

				// Register refresh world time event.
				if (!worldTimeFsm.Fsm.HasEvent(REFRESH_WORLD_TIME_EVENT)) {
					FsmEvent mpRefreshWorldTimeEvent = worldTimeFsm.Fsm.GetEvent(REFRESH_WORLD_TIME_EVENT);
					PlayMakerUtils.AddNewGlobalTransition(worldTimeFsm, mpRefreshWorldTimeEvent, "State 1");
				}

				// Make sure world time is up-to-date with cache.
				WorldTime = worldTimeCached;
			}
			else if (Utils.IsGameObjectHierarchyMatching(gameObject, "mailbox_bottom_player/Name")) {
				SetupMailbox(gameObject);
			}
			else if (gameObject.name == "TRAFFIC") {
				new TrafficManager(gameObject);
			}
			else if (gameObject.name == "STORE") {
				new Shop(gameObject);
			}
			else if (gameObject.name == "BOAT") {
				ObjectSyncComponent osc = gameObject.transform.FindChild("GFX").FindChild("Colliders").FindChild("Collider").gameObject.AddComponent<ObjectSyncComponent>();
				osc.Setup(ObjectSyncManager.ObjectTypes.Boat, ObjectSyncManager.AUTOMATIC_ID);
			}
			else if (gameObject.name == "GarageDoors") {
				ObjectSyncComponent oscLeft = gameObject.transform.FindChild("DoorLeft").FindChild("Coll").gameObject.AddComponent<ObjectSyncComponent>();
				oscLeft.Setup(ObjectSyncManager.ObjectTypes.GarageDoor, ObjectSyncManager.AUTOMATIC_ID);
				ObjectSyncComponent oscRight = gameObject.transform.FindChild("DoorRight").FindChild("Coll").gameObject.AddComponent<ObjectSyncComponent>();
				oscRight.Setup(ObjectSyncManager.ObjectTypes.GarageDoor, ObjectSyncManager.AUTOMATIC_ID);
			}
		}
Example #11
0
        /// <summary>
        /// Handle set owner messages on the host.
        /// </summary>
        public static void SetOwnerHandler(Network.Messages.ObjectSyncMessage msg, ObjectSyncComponent osc, Steamworks.CSteamID sender)
        {
            NetPlayer player = NetManager.Instance.GetPlayer(sender);

            // No one owns the object, accept ownership request.
            if (osc.Owner == null || osc.Owner == player)
            {
                osc.Owner = player;
                osc.OwnerSetToRemote(NetManager.Instance.GetPlayer(sender));
                SendSyncResponse(player, msg.objectID, true);

                // Send updated ownership info to other clients.
                Network.Messages.ObjectSyncMessage msgBroadcast = new Network.Messages.ObjectSyncMessage();
                msgBroadcast.objectID      = msg.objectID;
                msgBroadcast.OwnerPlayerID = NetManager.Instance.GetPlayerIDBySteamID(sender);
                msgBroadcast.SyncType      = (int)SyncTypes.SetOwner;
                NetManager.Instance.BroadcastMessage(msgBroadcast, Steamworks.EP2PSend.k_EP2PSendReliable);
            }
            // Someone else owns the object, deny ownership request.
            else
            {
                SendSyncResponse(player, msg.objectID, false);
            }
        }
Example #12
0
        /// <summary>
        /// Collect given objects.
        /// </summary>
        /// <param name="gameObject">The game object to collect.</param>
        public void CollectGameObject(GameObject gameObject)
        {
            if (gameObject.name == "SUN" && worldTimeFsm == null)
            {
                // Yep it's called "Color" :>
                worldTimeFsm = Utils.GetPlaymakerScriptByName(gameObject, "Color");
                if (worldTimeFsm == null)
                {
                    return;
                }

                // Register refresh world time event.
                if (!worldTimeFsm.Fsm.HasEvent(REFRESH_WORLD_TIME_EVENT))
                {
                    FsmEvent mpRefreshWorldTimeEvent = worldTimeFsm.Fsm.GetEvent(REFRESH_WORLD_TIME_EVENT);
                    PlayMakerUtils.AddNewGlobalTransition(worldTimeFsm, mpRefreshWorldTimeEvent, "State 1");
                }

                // Make sure world time is up-to-date with cache.
                WorldTime = worldTimeCached;
            }
            else if (Utils.IsGameObjectHierarchyMatching(gameObject, "mailbox_bottom_player/Name"))
            {
                SetupMailbox(gameObject);
            }
            else if (gameObject.name == "TRAFFIC")
            {
                trafficManager.Setup(gameObject);
            }
            else if (gameObject.name == "STORE")
            {
                shopManager.Setup(gameObject);
            }
            else if (gameObject.name == "BOAT")
            {
                ObjectSyncComponent osc = gameObject.transform.FindChild("GFX/Colliders/Collider").gameObject.AddComponent <ObjectSyncComponent>();
                osc.Setup(ObjectSyncManager.ObjectTypes.Boat, ObjectSyncManager.AUTOMATIC_ID);
            }

            // Garage doors.
            else if (gameObject.name == "GarageDoors")
            {
                ObjectSyncComponent oscLeft = gameObject.transform.FindChild("DoorLeft/Coll").gameObject.AddComponent <ObjectSyncComponent>();
                oscLeft.Setup(ObjectSyncManager.ObjectTypes.GarageDoor, ObjectSyncManager.AUTOMATIC_ID);
                ObjectSyncComponent oscRight = gameObject.transform.FindChild("DoorRight/Coll").gameObject.AddComponent <ObjectSyncComponent>();
                oscRight.Setup(ObjectSyncManager.ObjectTypes.GarageDoor, ObjectSyncManager.AUTOMATIC_ID);
            }
            // Old car shed doors.
            else if (gameObject.name == "Doors" && gameObject.transform.parent.name == "Shed")
            {
                PlayMakerFSM doorLeft = gameObject.transform.FindChild("DoorLeft/Mesh").gameObject.GetComponent <PlayMakerFSM>();
                EventHook.AddWithSync(doorLeft, "Open door");
                EventHook.AddWithSync(doorLeft, "Close door");
                PlayMakerFSM doorRight = gameObject.transform.FindChild("DoorRight/Mesh").gameObject.GetComponent <PlayMakerFSM>();
                EventHook.AddWithSync(doorRight, "Open door");
                EventHook.AddWithSync(doorRight, "Close door");
            }

            // Weather system.
            else if (gameObject.name == "Clouds" && gameObject.transform.parent.name == "CloudSystem")
            {
                ObjectSyncComponent osc = gameObject.AddComponent <ObjectSyncComponent>();
                osc.Setup(ObjectSyncManager.ObjectTypes.Weather, ObjectSyncManager.AUTOMATIC_ID);
            }

            // Sewage well jobs.
            else if (gameObject.name.StartsWith("HouseShit"))
            {
                ObjectSyncComponent osc = gameObject.AddComponent <ObjectSyncComponent>();
                osc.Setup(ObjectSyncManager.ObjectTypes.SewageWell, ObjectSyncManager.AUTOMATIC_ID);
            }

            // Phone.
            else if (gameObject.name == "Ring")
            {
                phoneManager.Setup(gameObject);
            }
            // Map.
            else if (gameObject.name == "MAP" && gameObject.transform.FindChild("Darts"))
            {
                mapManager.Setup(gameObject);
            }
        }
Example #13
0
        /// <summary>
        /// Spawn pickupable from network message.
        /// </summary>
        /// <param name="msg">The message containing info about pickupable to
        /// spawn.</param>
        public void SpawnPickupable(Messages.PickupableSpawnMessage msg)
        {
            Vector3    position = Utils.NetVec3ToGame(msg.transform.position);
            Quaternion rotation = Utils.NetQuatToGame(msg.transform.rotation);

            if (ObjectSyncManager.Instance.ObjectIDs.ContainsKey(msg.id))
            {
                ObjectSyncComponent osc = ObjectSyncManager.Instance.ObjectIDs[msg.id];
                // Ignore spawn requests for items that are already spawned.
                if (osc.ObjectID == msg.id)
                {
                    return;
                }
                GameObject gameObject = osc.gameObject;
                GamePickupableDatabase.PrefabDesc desc =
                    GamePickupableDatabase.Instance.GetPickupablePrefab(msg.prefabId);
                if (gameObject != null)
                {
                    var metaData = gameObject.GetComponent <PickupableMetaDataComponent>();
                    // Incorrect prefab found.
                    if (msg.prefabId != metaData.prefabId)
                    {
                        bool resolved = false;
                        foreach (var go in ObjectSyncManager.Instance.ObjectIDs)
                        {
                            if (go.Value.gameObject.GetComponent <PickupableMetaDataComponent>()
                                .prefabId == msg.prefabId)
                            {
                                gameObject = go.Value.gameObject;
                                Logger.Log("Prefab mismatch was resolved.");
                                resolved = true;
                                break;
                            }
                        }
                        if (!resolved)
                        {
                            Client.Assert(true, "Prefab ID mismatch couldn't be resolved!");
                        }
                    }
                    gameObject.SetActive(msg.active);
                    gameObject.transform.position = position;
                    gameObject.transform.rotation = rotation;

                    if (gameObject.GetComponent <ObjectSyncComponent>() != null)
                    {
                        GameObject.Destroy(gameObject.GetComponent <ObjectSyncComponent>());
                    }
                    gameObject.AddComponent <ObjectSyncComponent>().Setup(
                        ObjectSyncManager.ObjectTypes.Pickupable, msg.id);
                    return;
                }

                DestroyPickupableLocal(msg.id);
            }

            GameObject pickupable = GameWorld.Instance.SpawnPickupable(
                msg.prefabId, position, rotation, msg.id);

            RegisterPickupable(pickupable, true);
            if (pickupable.GetComponent <ObjectSyncComponent>() != null)
            {
                GameObject.Destroy(pickupable.GetComponent <ObjectSyncComponent>());
            }
            pickupable.AddComponent <ObjectSyncComponent>().Setup(
                ObjectSyncManager.ObjectTypes.Pickupable, msg.id);
        }
Example #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

            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");
        }
Example #15
0
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="netManager">Network manager owning this network world.</param>
        public NetWorld(NetManager netManager)
        {
            this.netManager = netManager;
            Instance        = this;

            GameCallbacks.onWorldUnload += () => { OnGameWorldUnload(); };

            GameCallbacks.onWorldLoad += () => { OnGameWorldLoad(); };

            GameCallbacks.onPlayMakerObjectCreate += (GameObject instance,
                                                      GameObject prefab) => {
                if (!Game.GamePickupableDatabase.IsPickupable(instance))
                {
                    return;
                }

                var metaData =
                    prefab.GetComponent <Game.Components.PickupableMetaDataComponent>();
                Client.Assert(metaData != null,
                              "Tried to spawn pickupable that has no meta data assigned.");
                RegisterPickupable(instance);

                Messages.PickupableSpawnMessage msg = new Messages.PickupableSpawnMessage();
                msg.prefabId           = metaData.prefabId;
                msg.transform.position = Utils.GameVec3ToNet(instance.transform.position);
                msg.transform.rotation = Utils.GameQuatToNet(instance.transform.rotation);
                msg.active             = instance.activeSelf;

                // Check for multiple sync components from prefab
                ObjectSyncComponent oscOld = prefab.GetComponent <ObjectSyncComponent>();
                if (instance.GetComponents <ObjectSyncComponent>().Length > 1)
                {
                    foreach (ObjectSyncComponent osc in instance
                             .GetComponents <ObjectSyncComponent>())
                    {
                        if (osc.ObjectID == oscOld.ObjectID)
                        {
                            GameObject.Destroy(osc);
                        }
                        else
                        {
                            msg.id = osc.ObjectID;
                        }
                    }
                }
                else
                {
                    msg.id = instance.GetComponent <ObjectSyncComponent>().ObjectID;
                }

                // Determine if object should be spawned on remote client.
                // (Helps to avoid duplicate objects spawning)
                bool sendToRemote = false;
                if (NetManager.Instance.IsHost)
                {
                    Logger.Debug("Sending new object data to client!");
                    sendToRemote = true;
                }
                else
                {
                    if (instance.name.StartsWith("BottleBeerFly"))
                    {
                        sendToRemote = true;
                    }
                }

                if (sendToRemote)
                {
                    netManager.BroadcastMessage(msg, Steamworks.EP2PSend.k_EP2PSendReliable);
                    Logger.Debug("Sending new object data to client!");
                }
            };

            GameCallbacks.onPlayMakerObjectActivate += (GameObject instance,
                                                        bool activate) => {
                if (playerIsLoading)
                {
                    return;
                }

                if (activate == instance.activeSelf)
                {
                    return;
                }

                if (!GamePickupableDatabase.IsPickupable(instance))
                {
                    return;
                }

                ObjectSyncComponent pickupable = GetPickupableByGameObject(instance);
                if (pickupable == null)
                {
                    return;
                }

                if (activate)
                {
                    var metaData =
                        pickupable.gameObject.GetComponent <PickupableMetaDataComponent>();

                    Messages.PickupableSpawnMessage msg =
                        new Messages.PickupableSpawnMessage();
                    msg.id                 = pickupable.ObjectID;
                    msg.prefabId           = metaData.prefabId;
                    msg.transform.position = Utils.GameVec3ToNet(instance.transform.position);
                    msg.transform.rotation = Utils.GameQuatToNet(instance.transform.rotation);
                    netManager.BroadcastMessage(msg, Steamworks.EP2PSend.k_EP2PSendReliable);
                }
                else
                {
                    Messages.PickupableActivateMessage msg =
                        new Messages.PickupableActivateMessage();
                    msg.id       = pickupable.ObjectID;
                    msg.activate = false;
                    netManager.BroadcastMessage(msg, Steamworks.EP2PSend.k_EP2PSendReliable);
                }
            };

            GameCallbacks.onPlayMakerObjectDestroy += (GameObject instance) => {
                if (!Game.GamePickupableDatabase.IsPickupable(instance))
                {
                    return;
                }

                ObjectSyncComponent pickupable = GetPickupableByGameObject(instance);
                if (pickupable == null)
                {
                    Logger.Debug(
                        $"Pickupable {instance.name} has been destroyed however it is not registered, skipping removal.");
                    return;
                }

                HandlePickupableDestroy(instance);
            };

            GameCallbacks.onPlayMakerSetPosition +=
                (GameObject gameObject, Vector3 position, Space space) => {
                if (!Game.GamePickupableDatabase.IsPickupable(gameObject))
                {
                    return;
                }

                ObjectSyncComponent pickupable = GetPickupableByGameObject(gameObject);
                if (pickupable == null)
                {
                    return;
                }

                if (space == Space.Self)
                {
                    position += gameObject.transform.position;
                }

                Messages.PickupableSetPositionMessage msg =
                    new Messages.PickupableSetPositionMessage();
                msg.id       = pickupable.ObjectID;
                msg.position = Utils.GameVec3ToNet(position);
                netManager.BroadcastMessage(msg, Steamworks.EP2PSend.k_EP2PSendReliable);
            };

            RegisterNetworkMessagesHandlers(netManager.MessageHandler);
        }
Example #16
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);
                    }
                }
            });
        }
Example #17
0
        /// <summary>
        /// Handles sync taken by force messages on the host.
        /// </summary>
        public static void SyncTakenByForceHandler(Network.Messages.ObjectSyncMessage msg, ObjectSyncComponent osc, Steamworks.CSteamID sender)
        {
            if (osc.Owner == NetManager.Instance.GetLocalPlayer())
            {
                osc.SyncTakenByForce();
                osc.SyncEnabled = false;
            }
            osc.Owner = NetManager.Instance.GetPlayer(sender);

            if (osc.Owner == NetManager.Instance.GetLocalPlayer())
            {
                osc.SyncEnabled = true;
            }

            // Send updated ownership info to other clients.
            Network.Messages.ObjectSyncMessage msgBroadcast = new Network.Messages.ObjectSyncMessage();
            msgBroadcast.objectID      = msg.objectID;
            msgBroadcast.OwnerPlayerID = NetManager.Instance.GetPlayerIDBySteamID(sender);
            msgBroadcast.SyncType      = (int)SyncTypes.ForceSetOwner;
            NetManager.Instance.BroadcastMessage(msgBroadcast, Steamworks.EP2PSend.k_EP2PSendReliable);
        }
Example #18
0
        /// <summary>
        /// Handles remove owner messages on the host.
        /// </summary>
        public static void RemoveOwnerHandler(Network.Messages.ObjectSyncMessage msg, ObjectSyncComponent osc, Steamworks.CSteamID sender)
        {
            osc.Owner = null;
            osc.OwnerRemoved();

            // Send updated ownership info to other clients.
            Network.Messages.ObjectSyncMessage msgBroadcast = new Network.Messages.ObjectSyncMessage();
            msgBroadcast.objectID      = msg.objectID;
            msgBroadcast.OwnerPlayerID = NetManager.Instance.GetPlayerIDBySteamID(sender);
            msgBroadcast.SyncType      = (int)SyncTypes.RemoveOwner;
            NetManager.Instance.BroadcastMessage(msgBroadcast, Steamworks.EP2PSend.k_EP2PSendReliable);
        }
Example #19
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;
        }
Example #20
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);
                }
            });
        }
Example #21
0
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="netManager">Network manager owning this network world.</param>
        public NetWorld(NetManager netManager)
        {
            this.netManager = netManager;
            Instance        = this;

            GameCallbacks.onWorldUnload += () => {
                OnGameWorldUnload();
            };

            GameCallbacks.onWorldLoad += () => {
                OnGameWorldLoad();
            };

            GameCallbacks.onPlayMakerObjectCreate += (GameObject instance, GameObject prefab) => {
                if (!GamePickupableDatabase.IsPickupable(instance))
                {
                    return;
                }

                var metaData = prefab.GetComponent <PickupableMetaDataComponent>();
                Client.Assert(metaData != null, "Tried to spawn pickupable that has no meta data assigned.");

                Messages.PickupableSpawnMessage msg = new Messages.PickupableSpawnMessage();
                msg.prefabId           = metaData.prefabId;
                msg.transform.position = Utils.GameVec3ToNet(instance.transform.position);
                msg.transform.rotation = Utils.GameQuatToNet(instance.transform.rotation);
                msg.active             = instance.activeSelf;

                // Setup sync component on object.
                Client.Assert(instance.GetComponent <ObjectSyncComponent>(), $"Object created but no ObjectSyncComponent could be found! Object name: {instance.name}");
                ObjectSyncComponent osc = instance.GetComponent <ObjectSyncComponent>();
                msg.id = osc.Setup(osc.ObjectType, ObjectSyncManager.AUTOMATIC_ID);

                // Determine if object should be spawned on remote client.
                // (Helps to avoid duplicate objects spawning)
                bool sendToRemote = false;
                if (NetManager.Instance.IsHost)
                {
                    Logger.Debug("Sending new object data to client!");
                    sendToRemote = true;
                }
                else
                {
                    // This is a hack to workout beer bottles not spawning on the remote client due to items only spawning on the host.
                    // This will be replaced in the future.
                    if (instance.name.StartsWith("BottleBeerFly"))
                    {
                        sendToRemote = true;
                    }
                }

                if (sendToRemote)
                {
                    netManager.BroadcastMessage(msg, Steamworks.EP2PSend.k_EP2PSendReliable);
                    Logger.Debug("Sending new object data to client!");
                }
            };

            GameCallbacks.onPlayMakerObjectActivate += (GameObject instance, bool activate) => {
                if (playerIsLoading)
                {
                    return;
                }

                if (activate == instance.activeSelf)
                {
                    return;
                }

                if (!GamePickupableDatabase.IsPickupable(instance))
                {
                    return;
                }

                ObjectSyncComponent pickupable = GetPickupableByGameObject(instance);
                if (pickupable == null)
                {
                    return;
                }

                if (activate)
                {
                    var metaData = pickupable.gameObject.GetComponent <PickupableMetaDataComponent>();

                    Messages.PickupableSpawnMessage msg = new Messages.PickupableSpawnMessage();
                    msg.id                 = pickupable.ObjectID;
                    msg.prefabId           = metaData.prefabId;
                    msg.transform.position = Utils.GameVec3ToNet(instance.transform.position);
                    msg.transform.rotation = Utils.GameQuatToNet(instance.transform.rotation);
                    netManager.BroadcastMessage(msg, Steamworks.EP2PSend.k_EP2PSendReliable);
                }
                else
                {
                    Messages.PickupableActivateMessage msg = new Messages.PickupableActivateMessage();
                    msg.id       = pickupable.ObjectID;
                    msg.activate = false;
                    netManager.BroadcastMessage(msg, Steamworks.EP2PSend.k_EP2PSendReliable);
                }
            };

            GameCallbacks.onPlayMakerObjectDestroy += (GameObject instance) => {
                if (!GamePickupableDatabase.IsPickupable(instance))
                {
                    return;
                }

                ObjectSyncComponent pickupable = GetPickupableByGameObject(instance);
                if (pickupable == null)
                {
                    Logger.Debug($"Pickupable {instance.name} has been destroyed however it is not registered, skipping removal.");
                    return;
                }

                HandlePickupableDestroy(instance);
            };

            GameCallbacks.onPlayMakerSetPosition += (GameObject gameObject, Vector3 position, Space space) => {
                if (!GamePickupableDatabase.IsPickupable(gameObject))
                {
                    return;
                }

                ObjectSyncComponent pickupable = GetPickupableByGameObject(gameObject);
                if (pickupable == null)
                {
                    return;
                }


                if (space == Space.Self)
                {
                    position += gameObject.transform.position;
                }

                Messages.PickupableSetPositionMessage msg = new Messages.PickupableSetPositionMessage();
                msg.id       = pickupable.ObjectID;
                msg.position = Utils.GameVec3ToNet(position);
                netManager.BroadcastMessage(msg, Steamworks.EP2PSend.k_EP2PSendReliable);
            };

            RegisterNetworkMessagesHandlers(netManager.MessageHandler);
        }