/// <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); GameObject pickupable = Game.GameWorld.Instance.SpawnPickupable(msg.prefabId, position, rotation); RegisterPickupable(msg.id, pickupable); }
/// <summary> /// Constructor. /// </summary> /// <param name="netManager">Network manager owning this network world.</param> public NetWorld(NetManager netManager) { this.netManager = netManager; // Register all network vehicles. RegisterVehicle("JONNEZ ES(Clone)"); RegisterVehicle("HAYOSIKO(1500kg, 250)"); RegisterVehicle("SATSUMA(557kg, 248)"); RegisterVehicle("RCO_RUSCKO12(270)"); RegisterVehicle("KEKMET(350-400psi)"); RegisterVehicle("FLATBED"); RegisterVehicle("FERNDALE(1630kg)"); Game.GameCallbacks.onWorldUnload += () => { OnGameWorldUnload(); }; Game.GameCallbacks.onWorldLoad += () => { OnGameWorldLoad(); }; Game.GameCallbacks.onPlayMakerObjectCreate += (GameObject instance, GameObject pickupable) => { if (!Game.GamePickupableDatabase.IsPickupable(instance)) { return; } var metaData = pickupable.GetComponent <Game.Components.PickupableMetaDataComponent>(); Client.Assert(metaData != null, "Tried to spawn pickupable that has no meta data assigned."); ushort freeId = FindFreePickpableId(); Client.Assert(freeId != NetPickupable.INVALID_ID, "Out of pickupables pool"); RegisterPickupable(freeId, instance); Messages.PickupableSpawnMessage msg = new Messages.PickupableSpawnMessage(); msg.id = freeId; 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); }; netManager.BindMessageHandler((Steamworks.CSteamID sender, Messages.PickupableSpawnMessage msg) => { SpawnPickupable(msg); }); netManager.BindMessageHandler((Steamworks.CSteamID sender, Messages.PickupableDestroyMessage msg) => { Client.Assert(netPickupables.ContainsKey(msg.id), "Invalid pickupable id in destroy message."); NetPickupable pickupable = netPickupables[msg.id]; GameObject.Destroy(pickupable.gameObject); netPickupables.Remove(msg.id); }); }
/// <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; } }
/// <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 (netPickupables.ContainsKey(msg.id)) { NetPickupable netPickupable = netPickupables[msg.id]; GameObject gameObject = netPickupable.gameObject; Game.GamePickupableDatabase.PrefabDesc desc = Game.GamePickupableDatabase.Instance.GetPickupablePrefab(msg.prefabId); if (gameObject != null) { var metaData = gameObject.GetComponent <Game.Components.PickupableMetaDataComponent>(); if (msg.prefabId == metaData.prefabId) { gameObject.SetActive(msg.active); gameObject.transform.position = position; gameObject.transform.rotation = rotation; if (msg.HasData) { HandlePickupablesSpawnData(gameObject, desc.type, msg.Data); } return; } } DestroyPickupableLocal(msg.id); } GameObject pickupable = Game.GameWorld.Instance.SpawnPickupable(msg.prefabId, position, rotation); if (msg.HasData) { Game.GamePickupableDatabase.PrefabDesc desc = Game.GamePickupableDatabase.Instance.GetPickupablePrefab(msg.prefabId); HandlePickupablesSpawnData(pickupable, desc.type, msg.Data); } RegisterPickupable(msg.id, pickupable); }
/// <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); }
/// <summary> /// Constructor. /// </summary> /// <param name="netManager">Network manager owning this network world.</param> public NetWorld(NetManager netManager) { this.netManager = netManager; // Register all network vehicles. RegisterVehicle("JONNEZ ES(Clone)"); RegisterVehicle("HAYOSIKO(1500kg, 250)"); RegisterVehicle("SATSUMA(557kg, 248)"); RegisterVehicle("RCO_RUSCKO12(270)"); RegisterVehicle("KEKMET(350-400psi)"); RegisterVehicle("FLATBED"); RegisterVehicle("FERNDALE(1630kg)"); RegisterVehicle("GIFU(750/450psi)"); Game.GameCallbacks.onWorldUnload += () => { OnGameWorldUnload(); }; Game.GameCallbacks.onWorldLoad += () => { OnGameWorldLoad(); }; Game.GameCallbacks.onPlayMakerObjectCreate += (GameObject instance, GameObject pickupable) => { if (!Game.GamePickupableDatabase.IsPickupable(instance)) { return; } var metaData = pickupable.GetComponent <Game.Components.PickupableMetaDataComponent>(); Client.Assert(metaData != null, "Tried to spawn pickupable that has no meta data assigned."); ushort freeId = FindFreePickpableId(); Client.Assert(freeId != NetPickupable.INVALID_ID, "Out of pickupables pool"); RegisterPickupable(freeId, instance); Messages.PickupableSpawnMessage msg = new Messages.PickupableSpawnMessage(); msg.id = freeId; msg.prefabId = metaData.prefabId; msg.transform.position = Utils.GameVec3ToNet(instance.transform.position); msg.transform.rotation = Utils.GameQuatToNet(instance.transform.rotation); msg.active = instance.activeSelf; netManager.BroadcastMessage(msg, Steamworks.EP2PSend.k_EP2PSendReliable); }; Game.GameCallbacks.onPlayMakerObjectActivate += (GameObject instance, bool activate) => { if (activate == instance.activeSelf) { return; } if (!Game.GamePickupableDatabase.IsPickupable(instance)) { return; } NetPickupable pickupable = GetPickupableByGameObject(instance); if (pickupable == null) { return; } if (activate) { var metaData = pickupable.gameObject.GetComponent <Game.Components.PickupableMetaDataComponent>(); Messages.PickupableSpawnMessage msg = new Messages.PickupableSpawnMessage(); msg.id = pickupable.NetId; 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.NetId; msg.activate = false; netManager.BroadcastMessage(msg, Steamworks.EP2PSend.k_EP2PSendReliable); } }; Game.GameCallbacks.onPlayMakerObjectDestroy += (GameObject instance) => { if (!Game.GamePickupableDatabase.IsPickupable(instance)) { return; } NetPickupable pickupable = GetPickupableByGameObject(instance); if (pickupable == null) { return; } HandlePickupableDestroy(instance); }; Game.GameCallbacks.onPlayMakerSetPosition += (GameObject gameObject, Vector3 position, Space space) => { if (!Game.GamePickupableDatabase.IsPickupable(gameObject)) { return; } NetPickupable pickupable = GetPickupableByGameObject(gameObject); if (pickupable == null) { return; } if (space == Space.Self) { position += gameObject.transform.position; } Messages.PickupableSetPositionMessage msg = new Messages.PickupableSetPositionMessage(); msg.id = pickupable.NetId; msg.position = Utils.GameVec3ToNet(position); netManager.BroadcastMessage(msg, Steamworks.EP2PSend.k_EP2PSendReliable); }; RegisterNetworkMessagesHandlers(netManager.MessageHandler); }
/// <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); }
/// <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"); }
/// <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); }
/// <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); }
/// <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; }