/// <summary> /// Constructor. /// </summary> /// <param name="netManager">The network manager owning this player.</param> /// <param name="netWorld">Network world owning this player.</param> /// <param name="steamId">The steam id of the player.</param> public NetLocalPlayer(NetManager netManager, NetWorld netWorld, Steamworks.CSteamID steamId) : base(netManager, netWorld, steamId) { GameDoorsManager.Instance.onDoorsOpen = () => { Messages.OpenDoorsMessage msg = new Messages.OpenDoorsMessage(); msg.open = true; netManager.BroadcastMessage(msg, Steamworks.EP2PSend.k_EP2PSendReliable); }; GameDoorsManager.Instance.onDoorsClose = () => { Messages.OpenDoorsMessage msg = new Messages.OpenDoorsMessage(); msg.open = false; netManager.BroadcastMessage(msg, Steamworks.EP2PSend.k_EP2PSendReliable); }; GameCallbacks.onObjectPickup = (GameObject gameObj) => { Messages.PickupObjectMessage msg = new Messages.PickupObjectMessage(); msg.netId = netWorld.GetPickupableNetId(gameObj); netManager.BroadcastMessage(msg, Steamworks.EP2PSend.k_EP2PSendReliable); }; GameCallbacks.onObjectRelease = (bool drop) => { Messages.ReleaseObjectMessage msg = new Messages.ReleaseObjectMessage(); msg.drop = drop; netManager.BroadcastMessage(msg, Steamworks.EP2PSend.k_EP2PSendReliable); }; }
public NetManager() { statistics = new NetStatistics(this); netManagerCreationTime = DateTime.UtcNow; netMessageHandler = new NetMessageHandler(this); netWorld = new NetWorld(this); p2pSessionRequestCallback = Steamworks.Callback <Steamworks.P2PSessionRequest_t> .Create( OnP2PSessionRequest); p2pConnectFailCallback = Steamworks.Callback <Steamworks.P2PSessionConnectFail_t> .Create( OnP2PConnectFail); gameLobbyJoinRequestedCallback = Steamworks.Callback <Steamworks.GameLobbyJoinRequested_t> .Create( OnGameLobbyJoinRequested); lobbyCreatedCallResult = new Steamworks.CallResult <Steamworks.LobbyCreated_t>(OnLobbyCreated); lobbyEnterCallResult = new Steamworks.CallResult <Steamworks.LobbyEnter_t>(OnLobbyEnter); Instance = this; RegisterProtocolMessagesHandlers(); }
/// <summary> /// Constructor. /// </summary> /// <param name="netManager">The network manager owning this player.</param> /// <param name="netWorld">Network world owning this player.</param> /// <param name="steamId">The steam id of the player.</param> public NetLocalPlayer( NetManager netManager, NetWorld netWorld, Steamworks.CSteamID steamId) : base(netManager, netWorld, steamId) { Instance = this; steamID = steamId; GameDoorsManager.Instance.onDoorsOpen = (GameObject door) => { Messages.OpenDoorsMessage msg = new Messages.OpenDoorsMessage(); msg.position = Utils.GameVec3ToNet(door.transform.position); msg.open = true; netManager.BroadcastMessage(msg, Steamworks.EP2PSend.k_EP2PSendReliable); }; GameDoorsManager.Instance.onDoorsClose = (GameObject door) => { Messages.OpenDoorsMessage msg = new Messages.OpenDoorsMessage(); msg.position = Utils.GameVec3ToNet(door.transform.position); msg.open = false; netManager.BroadcastMessage(msg, Steamworks.EP2PSend.k_EP2PSendReliable); }; LightSwitchManager.Instance.onLightSwitchUsed = (GameObject lswitch, bool turnedOn) => { Messages.LightSwitchMessage msg = new Messages.LightSwitchMessage(); msg.pos = Utils.GameVec3ToNet(lswitch.transform.position); msg.toggle = turnedOn; netManager.BroadcastMessage(msg, Steamworks.EP2PSend.k_EP2PSendReliable); }; if (animManager == null) { animManager = new PlayerAnimManager(); } }
public NetManager() { Instance = this; statistics = new NetStatistics(this); netManagerCreationTime = DateTime.UtcNow; netMessageHandler = new NetMessageHandler(this); netWorld = new NetWorld(this); // Hopefully this will fix people playing with different mod versions! string versionFull = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(); int buildNumber = Convert.ToInt32(versionFull.Substring(versionFull.LastIndexOf('.') + 1)); PROTOCOL_VERSION = buildNumber; Logger.Log("Build version is: " + PROTOCOL_VERSION); p2pSessionRequestCallback = Steamworks.Callback <Steamworks.P2PSessionRequest_t> .Create(OnP2PSessionRequest); p2pConnectFailCallback = Steamworks.Callback <Steamworks.P2PSessionConnectFail_t> .Create(OnP2PConnectFail); gameLobbyJoinRequestedCallback = Steamworks.Callback <Steamworks.GameLobbyJoinRequested_t> .Create(OnGameLobbyJoinRequested); lobbyCreatedCallResult = new Steamworks.CallResult <Steamworks.LobbyCreated_t>(OnLobbyCreated); lobbyEnterCallResult = new Steamworks.CallResult <Steamworks.LobbyEnter_t>(OnLobbyEnter); lobbyListResult = new Steamworks.CallResult <Steamworks.LobbyMatchList_t>(OnLobbyList); lobbyDataResult = new Steamworks.CallResult <Steamworks.LobbyDataUpdate_t>(OnGetLobbyInfo); RegisterProtocolMessagesHandlers(); RequestLobbies(); }
public NetManager() { this.netManagerCreationTime = DateTime.UtcNow; netMessageHandler = new NetMessageHandler(this); netWorld = new NetWorld(this); p2pSessionRequestCallback = Steamworks.Callback <Steamworks.P2PSessionRequest_t> .Create((Steamworks.P2PSessionRequest_t result) => { if (!Steamworks.SteamNetworking.AcceptP2PSessionWithUser(result.m_steamIDRemote)) { Logger.Log("Accepted p2p session with " + result.m_steamIDRemote.ToString()); } }); gameLobbyJoinRequestedCallback = Steamworks.Callback <Steamworks.GameLobbyJoinRequested_t> .Create(OnGameLobbyJoinRequested); lobbyCreatedCallResult = new Steamworks.CallResult <Steamworks.LobbyCreated_t>((Steamworks.LobbyCreated_t result, bool ioFailure) => { if (result.m_eResult != Steamworks.EResult.k_EResultOK) { Logger.Log("Oh my f*****g god i failed to create a lobby for you. Please forgive me. (result: " + result.m_eResult + ")"); MPGUI.Instance.ShowMessageBox("Failed to create lobby due to steam error.\n" + result.m_eResult, () => { MPController.Instance.LoadLevel("MainMenu"); }); return; } Logger.Log("Hey you! I have lobby id for you! " + result.m_ulSteamIDLobby); // Setup local player. players[0] = new NetLocalPlayer(this, netWorld, Steamworks.SteamUser.GetSteamID()); mode = Mode.Host; state = State.Playing; currentLobbyId = new Steamworks.CSteamID(result.m_ulSteamIDLobby); }); lobbyEnterCallResult = new Steamworks.CallResult <Steamworks.LobbyEnter_t>((Steamworks.LobbyEnter_t result, bool ioFailure) => { if (result.m_EChatRoomEnterResponse != (uint)Steamworks.EChatRoomEnterResponse.k_EChatRoomEnterResponseSuccess) { Logger.Log("Oh my f*****g god i failed to join the lobby for you. Please forgive me. (reponse: " + result.m_EChatRoomEnterResponse + ")"); players[1] = null; return; } // Setup local player. players[0] = new NetLocalPlayer(this, netWorld, Steamworks.SteamUser.GetSteamID()); Logger.Log("Oh hello! " + result.m_ulSteamIDLobby); mode = Mode.Player; state = State.LoadingGameWorld; currentLobbyId = new Steamworks.CSteamID(result.m_ulSteamIDLobby); ShowLoadingScreen(true); SendHandshake(); }); RegisterProtocolMessagesHandlers(); }
/// <summary> /// Constructor. /// </summary> /// <param name="netManager">Network manager managing connection to the /// player.</param> <param name="netWorld">Network world owning this /// player.</param> <param name="steamId">Player's steam id.</param> public NetPlayer( NetManager netManager, NetWorld netWorld, Steamworks.CSteamID steamId) { this.netManager = netManager; this.netWorld = netWorld; this.steamId = steamId; }
/// <summary> /// Constructor. /// </summary> /// <param name="netManager">The network manager owning this player.</param> /// <param name="netWorld">Network world owning this player.</param> /// <param name="steamId">The steam id of the player.</param> public NetLocalPlayer(NetManager netManager, NetWorld netWorld, Steamworks.CSteamID steamId) : base(netManager, netWorld, steamId) { GameDoorsManager.Instance.onDoorsOpen = (GameObject door) => { Messages.OpenDoorsMessage msg = new Messages.OpenDoorsMessage(); msg.position = Utils.GameVec3ToNet(door.transform.position); msg.open = true; netManager.BroadcastMessage(msg, Steamworks.EP2PSend.k_EP2PSendReliable); }; GameDoorsManager.Instance.onDoorsClose = (GameObject door) => { Messages.OpenDoorsMessage msg = new Messages.OpenDoorsMessage(); msg.position = Utils.GameVec3ToNet(door.transform.position); msg.open = false; netManager.BroadcastMessage(msg, Steamworks.EP2PSend.k_EP2PSendReliable); }; GameCallbacks.onObjectPickup = (GameObject gameObj) => { Messages.PickupObjectMessage msg = new Messages.PickupObjectMessage(); msg.netId = netWorld.GetPickupableNetId(gameObj); Client.Assert(msg.netId != NetPickupable.INVALID_ID, "Tried to pickup not network pickupable."); netManager.BroadcastMessage(msg, Steamworks.EP2PSend.k_EP2PSendReliable); }; GameCallbacks.onObjectRelease = (bool drop) => { Messages.ReleaseObjectMessage msg = new Messages.ReleaseObjectMessage(); msg.drop = drop; netManager.BroadcastMessage(msg, Steamworks.EP2PSend.k_EP2PSendReliable); }; BeerCaseManager.Instance.onBottleConsumed = (GameObject bcase) => { Messages.RemoveBottleMessage msg = new Messages.RemoveBottleMessage(); msg.netId = netWorld.GetPickupableNetId(bcase); Client.Assert(msg.netId != NetPickupable.INVALID_ID, "Tried to drink from not network beercase."); netManager.BroadcastMessage(msg, Steamworks.EP2PSend.k_EP2PSendReliable); }; LightSwitchManager.Instance.onLightSwitchUsed = (GameObject lswitch, bool turnedOn) => { Messages.LightSwitchMessage msg = new Messages.LightSwitchMessage(); msg.pos = Utils.GameVec3ToNet(lswitch.transform.position); msg.toggle = turnedOn; netManager.BroadcastMessage(msg, Steamworks.EP2PSend.k_EP2PSendReliable); }; if (animManager == null) { animManager = new PlayerAnimManager(); } }
/// <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); }
public NetManager() { this.netManagerCreationTime = DateTime.UtcNow; netWorld = new NetWorld(this); // Setup local player. players[0] = new NetLocalPlayer(this, netWorld, Steamworks.SteamUser.GetSteamID()); p2pSessionRequestCallback = Steamworks.Callback <Steamworks.P2PSessionRequest_t> .Create((Steamworks.P2PSessionRequest_t result) => { if (!Steamworks.SteamNetworking.AcceptP2PSessionWithUser(result.m_steamIDRemote)) { Logger.Log("Accepted p2p session with " + result.m_steamIDRemote.ToString()); } }); gameLobbyJoinRequestedCallback = Steamworks.Callback <Steamworks.GameLobbyJoinRequested_t> .Create(OnGameLobbyJoinRequested); lobbyCreatedCallResult = new Steamworks.CallResult <Steamworks.LobbyCreated_t>((Steamworks.LobbyCreated_t result, bool ioFailure) => { if (result.m_eResult != Steamworks.EResult.k_EResultOK) { Logger.Log("Oh my f*****g god i failed to create a lobby for you. Please forgive me. (result: " + result.m_eResult + ")"); MPGUI.Instance.ShowMessageBox("Failed to create lobby due to steam error.\n" + result.m_eResult, () => { MPController.Instance.LoadLevel("MainMenu"); }); return; } Logger.Log("Hey you! I have lobby id for you! " + result.m_ulSteamIDLobby); mode = Mode.Host; state = State.Playing; currentLobbyId = new Steamworks.CSteamID(result.m_ulSteamIDLobby); netWorld.RegisterPickupables(); }); lobbyEnterCallResult = new Steamworks.CallResult <Steamworks.LobbyEnter_t>((Steamworks.LobbyEnter_t result, bool ioFailure) => { if (result.m_EChatRoomEnterResponse != (uint)Steamworks.EChatRoomEnterResponse.k_EChatRoomEnterResponseSuccess) { Logger.Log("Oh my f*****g god i failed to join the lobby for you. Please forgive me. (reponse: " + result.m_EChatRoomEnterResponse + ")"); players[1] = null; return; } Logger.Log("Oh hello! " + result.m_ulSteamIDLobby); mode = Mode.Player; state = State.LoadingGameWorld; currentLobbyId = new Steamworks.CSteamID(result.m_ulSteamIDLobby); SendHandshake(); }); // TODO: Move message handlers to some class. BindMessageHandler((Steamworks.CSteamID sender, Messages.HandshakeMessage msg) => { remoteClock = msg.clock; HandleHandshake(sender, msg); }); BindMessageHandler((Steamworks.CSteamID sender, Messages.PlayerSyncMessage msg) => { if (players[1] == null) { Logger.Log("Received synchronization packet but no remote player is currently connected."); return; } players[1].HandleSynchronize(msg); }); BindMessageHandler((Steamworks.CSteamID sender, Messages.HeartbeatMessage msg) => { var message = new Messages.HeartbeatResponseMessage(); message.clientClock = msg.clientClock; message.clock = GetNetworkClock(); BroadcastMessage(message, Steamworks.EP2PSend.k_EP2PSendReliable); }); BindMessageHandler((Steamworks.CSteamID sender, Messages.HeartbeatResponseMessage msg) => { ping = (uint)(GetNetworkClock() - msg.clientClock); // TODO: Some smart lag compensation. remoteClock = msg.clock; timeSinceLastHeartbeat = 0.0f; }); BindMessageHandler((Steamworks.CSteamID sender, Messages.DisconnectMessage msg) => { HandleDisconnect(false); }); BindMessageHandler((Steamworks.CSteamID sender, Messages.OpenDoorsMessage msg) => { NetPlayer player = players[1]; // 1.5 is a length of the ray used to check interaction with doors in game scripts. Vector3 interactionPosition = player.GetPosition() + player.GetRotation() * Vector3.forward * 1.5f; Game.Objects.GameDoor doors = Game.GameDoorsManager.Instance.FindGameDoors(interactionPosition); if (doors == null) { Logger.Log($"Player tried to open doors however he is not close to any: {interactionPosition}."); return; } doors.Open(msg.open); }); BindMessageHandler((Steamworks.CSteamID sender, Messages.FullWorldSyncMessage msg) => { netWorld.HandleFullWorldSync(msg); // Now spawn player. if (players[1] != null) { players[1].Spawn(); } // World loaded we are playing! state = State.Playing; }); BindMessageHandler((Steamworks.CSteamID sender, Messages.AskForWorldStateMessage msg) => { var msgF = new Messages.FullWorldSyncMessage(); netWorld.WriteFullWorldSync(msgF); BroadcastMessage(msgF, Steamworks.EP2PSend.k_EP2PSendReliable); }); BindMessageHandler((Steamworks.CSteamID sender, Messages.VehicleEnterMessage msg) => { NetPlayer player = players[1]; if (player == null) { return; } NetVehicle vehicle = netWorld.GetVehicle(msg.vehicleId); if (vehicle == null) { Logger.Log("Player " + player.SteamId + " tried to enter vehicle " + msg.vehicleId + " but there is no vehicle with such id."); return; } player.EnterVehicle(vehicle, msg.passenger); }); BindMessageHandler((Steamworks.CSteamID sender, Messages.VehicleLeaveMessage msg) => { NetPlayer player = players[1]; if (player == null) { return; } player.LeaveVehicle(); }); BindMessageHandler((Steamworks.CSteamID sender, Messages.VehicleSyncMessage msg) => { NetPlayer player = players[1]; if (player == null) { return; } player.HandleVehicleSync(msg); }); BindMessageHandler((Steamworks.CSteamID sender, Messages.PickupObjectMessage msg) => { NetPlayer player = players[1]; if (player == null) { return; } player.PickupObject(msg.netId); }); BindMessageHandler((Steamworks.CSteamID sender, Messages.ReleaseObjectMessage msg) => { NetPlayer player = players[1]; if (player == null) { return; } player.ReleaseObject(msg.drop); }); }
/// <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); }