public void Update() { while (SteamNetworking.IsP2PPacketAvailable(0)) { P2Packet?packet = SteamNetworking.ReadP2PPacket(0); if (packet.HasValue) { P2PMessage msg = new P2PMessage(packet.Value.Data); MessageType type = (MessageType)msg.ReadByte(); switch (type) { case MessageType.Join: { if (msg.ReadByte() != JobSimulatorMultiplayer.PROTOCOL_VERSION) { // Somebody tried to join with an incompatible verison P2PMessage m2 = new P2PMessage(); m2.WriteByte((byte)MessageType.JoinRejected); SteamNetworking.SendP2PPacket(packet.Value.SteamId, m2.GetBytes(), -1, 0, P2PSend.Reliable); SteamNetworking.CloseP2PSessionWithUser(packet.Value.SteamId); } else { MelonModLogger.Log("Player joined with SteamID: " + packet.Value.SteamId); players.Add(packet.Value.SteamId); MelonModLogger.Log("Player count: " + players.Count); byte newPlayerId = smallIdCounter; smallPlayerIds.Add(packet.Value.SteamId, newPlayerId); largePlayerIds.Add(newPlayerId, packet.Value.SteamId); smallIdCounter++; string name = msg.ReadUnicodeString(); MelonModLogger.Log("Name: " + name); foreach (var smallId in playerNames.Keys) { ClientJoinMessage cjm = new ClientJoinMessage { playerId = smallId, name = playerNames[smallId], steamId = largePlayerIds[smallId] }; SteamNetworking.SendP2PPacket(packet.Value.SteamId, cjm.MakeMsg().GetBytes(), -1, 0, P2PSend.Reliable); } ClientJoinMessage cjm2 = new ClientJoinMessage { playerId = 0, name = SteamClient.Name, steamId = SteamClient.SteamId }; SteamNetworking.SendP2PPacket(packet.Value.SteamId, cjm2.MakeMsg().GetBytes(), -1, 0, P2PSend.Reliable); playerNames.Add(newPlayerId, name); ClientJoinMessage cjm3 = new ClientJoinMessage { playerId = newPlayerId, name = name, steamId = packet.Value.SteamId }; ServerSendToAllExcept(cjm3, P2PSend.Reliable, packet.Value.SteamId); playerObjects.Add(newPlayerId, new PlayerRep(name, packet.Value.SteamId)); RichPresence.SetActivity( new Activity() { State = "Hosting a server", Assets = { LargeImage = "jobsim" }, Secrets = new ActivitySecrets() { Join = SteamClient.SteamId.ToString() }, Party = new ActivityParty() { Id = partyId, Size = new PartySize() { CurrentSize = players.Count + 1, MaxSize = JobSimulatorMultiplayer.MAX_PLAYERS } } }); SceneTransitionMessage stm = new SceneTransitionMessage() { sceneName = SceneManager.GetActiveScene().name }; SendToId(stm, P2PSend.Reliable, packet.Value.SteamId); SetPartyIdMessage spid = new SetPartyIdMessage() { partyId = partyId }; SendToId(spid, P2PSend.Reliable, packet.Value.SteamId); } break; } case MessageType.Disconnect: { MelonModLogger.Log("Player left with SteamID: " + packet.Value.SteamId); byte smallId = smallPlayerIds[packet.Value.SteamId]; P2PMessage disconnectMsg = new P2PMessage(); disconnectMsg.WriteByte((byte)MessageType.Disconnect); disconnectMsg.WriteByte(smallId); foreach (SteamId p in players) { SteamNetworking.SendP2PPacket(p, disconnectMsg.GetBytes(), -1, 0, P2PSend.Reliable); } playerObjects[smallId].Destroy(); playerObjects.Remove(smallId); players.RemoveAll((ulong val) => val == packet.Value.SteamId); smallPlayerIds.Remove(packet.Value.SteamId); break; } case MessageType.PlayerPosition: { if (smallPlayerIds.ContainsKey(packet.Value.SteamId)) { byte playerId = smallPlayerIds[packet.Value.SteamId]; PlayerRep pr = GetPlayerRep(playerId); PlayerPositionMessage ppm = new PlayerPositionMessage(msg); pr.head.transform.position = ppm.headPos; pr.handL.transform.position = ppm.lHandPos; pr.handR.transform.position = ppm.rHandPos; pr.head.transform.rotation = ppm.headRot; pr.handL.transform.rotation = ppm.lHandRot; pr.handR.transform.rotation = ppm.rHandRot; /*MelonModLogger.Log($@"--------------------- * SteamID: {pr.steamId.ToString()} * LeftHand: {ppm.lHandPos.ToString()} * RightHand: {ppm.rHandPos.ToString()} * Head: {ppm.headPos.ToString()} * ---------------------");*/ OtherPlayerPositionMessage relayOPPM = new OtherPlayerPositionMessage { headPos = ppm.headPos, lHandPos = ppm.lHandPos, rHandPos = ppm.rHandPos, headRot = ppm.headRot, lHandRot = ppm.lHandRot, rHandRot = ppm.rHandRot, playerId = ppm.playerId }; ServerSendToAllExcept(relayOPPM, P2PSend.Unreliable, packet.Value.SteamId); } break; } case MessageType.ObjectSync: { ObjectSyncMessage osm = new ObjectSyncMessage(msg); for (int i = 0; i < osm.objectsToSync.Count; i++) { GameObject obj = ObjectIDManager.GetObject(osm.objectsToSync.Keys.ToList()[i]).gameObject; if (!obj) { MelonModLogger.LogError($"Couldn't find object with ID {obj.name}"); } else { obj.transform.position = osm.objectsToSync.Values.ToList()[i].Item1; obj.transform.rotation = osm.objectsToSync.Values.ToList()[i].Item2; } MelonModLogger.Log($"got sync message with id: {obj.name}"); } break; } default: MelonModLogger.Log("Unknown message type: " + type.ToString()); break; } } } /* * foreach (var pair in ObjectIDManager.objects) * { * ServerSyncedObject sso = pair.Value; * if (sso.NeedsSync()) * { * // Sync it * pair.Value.lastSyncedPos = pair.Value.transform.position; * pair.Value.lastSyncedRotation = pair.Value.transform.rotation; * * ObjectSyncMessage osm = new ObjectSyncMessage * { * ID = sso.IDHolder.ID, * position = pair.Value.transform.position, * rotation = pair.Value.transform.rotation * }; * * //ServerSendToAll(osm, P2PSend.Unreliable); * } * } */ SendSync(); if (GlobalStorage.Instance.MasterHMDAndInputController != null) { OtherPlayerPositionMessage ppm = new OtherPlayerPositionMessage { headPos = GlobalStorage.Instance.MasterHMDAndInputController.camTransform.position, lHandPos = GlobalStorage.Instance.MasterHMDAndInputController.LeftHand.cfjTransform.position, rHandPos = GlobalStorage.Instance.MasterHMDAndInputController.RightHand.cfjTransform.position, headRot = GlobalStorage.Instance.MasterHMDAndInputController.camTransform.rotation, lHandRot = GlobalStorage.Instance.MasterHMDAndInputController.LeftHand.cfjTransform.rotation, rHandRot = GlobalStorage.Instance.MasterHMDAndInputController.RightHand.cfjTransform.rotation, }; ServerSendToAll(ppm, P2PSend.Unreliable); } }
private void TransportLayer_OnMessageReceived(ITransportConnection connection, P2PMessage msg) { MessageType type = (MessageType)msg.ReadByte(); switch (type) { case MessageType.GunFire: { GunFireMessage gfm = new GunFireMessage(msg); byte LocalplayerId = smallPlayerIds[connection.ConnectedTo]; if (playerObjects.ContainsKey(LocalplayerId)) { PlayerRep pr = playerObjects[LocalplayerId]; AmmoVariables ammoVariables = new AmmoVariables() { AttackDamage = gfm.ammoDamage, AttackType = AttackType.Piercing, cartridgeType = Cart.Cal_9mm, ExitVelocity = gfm.exitVelocity, ProjectileMass = gfm.projectileMass, Tracer = false }; if ((StressLevelZero.Handedness)gfm.handedness == StressLevelZero.Handedness.RIGHT) { pr.rightGunScript.firePointTransform.position = gfm.firepointPos; pr.rightGunScript.firePointTransform.rotation = gfm.firepointRotation; pr.rightGunScript.muzzleVelocity = gfm.muzzleVelocity; pr.rightBulletObject.ammoVariables = ammoVariables; pr.leftGunScript.PullCartridge(); pr.rightGunScript.Fire(); } if ((StressLevelZero.Handedness)gfm.handedness == StressLevelZero.Handedness.LEFT) { pr.leftGunScript.firePointTransform.position = gfm.firepointPos; pr.leftGunScript.firePointTransform.rotation = gfm.firepointRotation; pr.leftGunScript.muzzleVelocity = gfm.muzzleVelocity; pr.leftBulletObject.ammoVariables = ammoVariables; pr.leftGunScript.PullCartridge(); pr.leftGunScript.Fire(); } GunFireMessageOther gfmo = new GunFireMessageOther() { playerId = LocalplayerId, handedness = gfm.handedness, firepointPos = gfm.firepointPos, firepointRotation = gfm.firepointRotation, ammoDamage = gfm.ammoDamage, projectileMass = gfm.projectileMass, exitVelocity = gfm.exitVelocity, muzzleVelocity = gfm.muzzleVelocity }; pr.faceAnimator.faceState = Source.Representations.FaceAnimator.FaceState.Angry; pr.faceAnimator.faceTime = 5; ServerSendToAllExcept(gfmo, MessageSendType.Reliable, connection.ConnectedTo); } break; } case MessageType.Join: { if (msg.ReadByte() != MultiplayerMod.PROTOCOL_VERSION) { // Somebody tried to join with an incompatible verison P2PMessage m2 = new P2PMessage(); m2.WriteByte((byte)MessageType.JoinRejected); connection.SendMessage(m2, MessageSendType.Reliable); connection.Disconnect(); } else { MelonLogger.Log("Player joined with ID: " + connection.ConnectedTo); if (players.Contains(connection.ConnectedTo)) { players.Remove(connection.ConnectedTo); } players.Add(connection.ConnectedTo); MelonLogger.Log("Player count: " + players.Count); byte newPlayerId = smallIdCounter; if (smallPlayerIds.ContainsKey(newPlayerId)) { smallPlayerIds.Remove(newPlayerId); } smallPlayerIds.Add(connection.ConnectedTo, newPlayerId); if (largePlayerIds.ContainsKey(newPlayerId)) { largePlayerIds.Remove(newPlayerId); } largePlayerIds.Add(newPlayerId, connection.ConnectedTo); smallIdCounter++; playerConnections.Add(connection.ConnectedTo, connection); string name = msg.ReadUnicodeString(); MelonLogger.Log("Name: " + name); foreach (var smallId in playerNames.Keys) { ClientJoinMessage cjm = new ClientJoinMessage { playerId = smallId, name = playerNames[smallId], steamId = largePlayerIds[smallId] }; connection.SendMessage(cjm.MakeMsg(), MessageSendType.Reliable); } ClientJoinMessage cjm2 = new ClientJoinMessage { playerId = 0, name = SteamClient.Name, steamId = SteamClient.SteamId }; connection.SendMessage(cjm2.MakeMsg(), MessageSendType.Reliable); if (playerNames.ContainsKey(newPlayerId)) { playerNames.Remove(newPlayerId); } playerNames.Add(newPlayerId, name); ClientJoinMessage cjm3 = new ClientJoinMessage { playerId = newPlayerId, name = name, steamId = connection.ConnectedTo }; ServerSendToAllExcept(cjm3, MessageSendType.Reliable, connection.ConnectedTo); if (playerObjects.ContainsKey(newPlayerId)) { playerObjects.Remove(newPlayerId); } playerObjects.Add(newPlayerId, new PlayerRep(name, connection.ConnectedTo)); RichPresence.SetActivity( new Activity() { Details = "Hosting a server", Secrets = new ActivitySecrets() { Join = SteamClient.SteamId.ToString() }, Party = new ActivityParty() { Id = partyId, Size = new PartySize() { CurrentSize = players.Count + 1, MaxSize = MultiplayerMod.MAX_PLAYERS } } }); SceneTransitionMessage stm = new SceneTransitionMessage() { sceneName = BoneworksSceneManager.GetCurrentSceneName() }; connection.SendMessage(stm.MakeMsg(), MessageSendType.Reliable); SetPartyIdMessage spid = new SetPartyIdMessage() { partyId = partyId }; connection.SendMessage(spid.MakeMsg(), MessageSendType.Reliable); SetLocalSmallIdMessage slsi = new SetLocalSmallIdMessage() { smallId = newPlayerId }; connection.SendMessage(slsi.MakeMsg(), MessageSendType.Reliable); foreach (var so in syncObjs) { var iam = new IDAllocationMessage { allocatedId = so.ID, namePath = BWUtil.GetFullNamePath(so.gameObject), initialOwner = so.owner }; connection.SendMessage(iam.MakeMsg(), MessageSendType.Reliable); } ui.SetPlayerCount(players.Count, MultiplayerUIState.Server); foreach (PlayerRep pr in playerObjects.Values) { pr.faceAnimator.faceState = Source.Representations.FaceAnimator.FaceState.Happy; pr.faceAnimator.faceTime = 15; } } break; } case MessageType.Disconnect: { MelonLogger.Log("Player left with ID: " + connection.ConnectedTo); byte smallId = smallPlayerIds[connection.ConnectedTo]; playerObjects[smallId].Delete(); playerObjects.Remove(smallId); players.RemoveAll((ulong val) => val == connection.ConnectedTo); smallPlayerIds.Remove(connection.ConnectedTo); P2PMessage disconnectMsg = new P2PMessage(); disconnectMsg.WriteByte((byte)MessageType.Disconnect); disconnectMsg.WriteByte(smallId); foreach (SteamId p in players) { playerConnections[p].SendMessage(disconnectMsg, MessageSendType.Reliable); } foreach (PlayerRep pr in playerObjects.Values) { pr.faceAnimator.faceState = Source.Representations.FaceAnimator.FaceState.Sad; pr.faceAnimator.faceTime = 6; } break; } case MessageType.FullRig: { FullRigTransformMessage frtm = new FullRigTransformMessage(msg); byte playerId = smallPlayerIds[connection.ConnectedTo]; if (playerObjects.ContainsKey(playerId)) { PlayerRep pr = playerObjects[playerId]; if (pr.rigTransforms.main != null) { //ApplyTransformMessage(pr, frtm); pr.ApplyTransformMessage(frtm); OtherFullRigTransformMessage ofrtm = new OtherFullRigTransformMessage { playerId = playerId, posMain = frtm.posMain, posRoot = frtm.posRoot, posLHip = frtm.posLHip, posRHip = frtm.posRHip, posLKnee = frtm.posLKnee, posRKnee = frtm.posRKnee, posLAnkle = frtm.posLAnkle, posRAnkle = frtm.posRAnkle, posSpine1 = frtm.posSpine1, posSpine2 = frtm.posSpine2, posSpineTop = frtm.posSpineTop, posLClavicle = frtm.posLClavicle, posRClavicle = frtm.posRClavicle, posNeck = frtm.posNeck, posLShoulder = frtm.posLShoulder, posRShoulder = frtm.posRShoulder, posLElbow = frtm.posLElbow, posRElbow = frtm.posRElbow, posLWrist = frtm.posLWrist, posRWrist = frtm.posRWrist, rotMain = frtm.rotMain, rotRoot = frtm.rotRoot, rotLHip = frtm.rotLHip, rotRHip = frtm.rotRHip, rotLKnee = frtm.rotLKnee, rotRKnee = frtm.rotRKnee, rotLAnkle = frtm.rotLAnkle, rotRAnkle = frtm.rotRAnkle, rotSpine1 = frtm.rotSpine1, rotSpine2 = frtm.rotSpine2, rotSpineTop = frtm.rotSpineTop, rotLClavicle = frtm.rotLClavicle, rotRClavicle = frtm.rotRClavicle, rotNeck = frtm.rotNeck, rotLShoulder = frtm.rotLShoulder, rotRShoulder = frtm.rotRShoulder, rotLElbow = frtm.rotLElbow, rotRElbow = frtm.rotRElbow, rotLWrist = frtm.rotLWrist, rotRWrist = frtm.rotRWrist }; ServerSendToAllExcept(ofrtm, MessageSendType.Unreliable, connection.ConnectedTo); } } break; } case MessageType.IdRequest: { var idrqm = new IDRequestMessage(msg); MelonLogger.Log("ID request: " + idrqm.namePath); var obj = BWUtil.GetObjectFromFullPath(idrqm.namePath); SetupSyncFor(obj, idrqm.initialOwner); break; } case MessageType.ChangeObjectOwnership: { var coom = new ChangeObjectOwnershipMessage(msg); if (coom.ownerId != smallPlayerIds[connection.ConnectedTo] && coom.ownerId != 0) { MelonLogger.LogError("Invalid object ownership change??"); } if (!ObjectIDManager.objects.ContainsKey(coom.objectId)) { MelonLogger.LogError($"Got ownership change for invalid object ID {coom.objectId}"); } MelonLogger.Log($"Object {coom.objectId} is now owned by {coom.ownerId}"); var obj = ObjectIDManager.GetObject(coom.objectId); var so = obj.GetComponent <SyncedObject>(); so.owner = coom.ownerId; if (so.owner != 0) { coom.linVelocity = so.rb.velocity; coom.angVelocity = so.rb.angularVelocity; so.rb.isKinematic = true; } else if (so.owner == 0) { so.rb.isKinematic = false; so.rb.velocity = coom.linVelocity; so.rb.angularVelocity = coom.angVelocity; } ServerSendToAll(coom, MessageSendType.Reliable); break; } case MessageType.ObjectSync: { ObjectSyncMessage osm = new ObjectSyncMessage(msg); GameObject obj = ObjectIDManager.GetObject(osm.id); var so = obj.GetComponent <SyncedObject>(); if (!obj) { MelonLogger.LogError($"Couldn't find object with ID {osm.id}"); } else { if (so.owner != smallPlayerIds[connection.ConnectedTo]) { MelonLogger.LogError("Got object sync from client that doesn't own the object"); } else { obj.transform.position = osm.position; obj.transform.rotation = osm.rotation; ServerSendToAllExcept(osm, MessageSendType.Reliable, connection.ConnectedTo); } } break; } default: MelonLogger.Log("Unknown message type: " + type.ToString()); break; } }
private void TransportLayer_OnMessageReceived(ITransportConnection connection, P2PMessage msg) { MessageType type = (MessageType)msg.ReadByte(); switch (type) { case MessageType.Join: { if (msg.ReadByte() != MultiplayerMod.PROTOCOL_VERSION) { // Somebody tried to join with an incompatible verison P2PMessage m2 = new P2PMessage(); m2.WriteByte((byte)MessageType.JoinRejected); connection.SendMessage(m2, MessageSendType.Reliable); connection.Disconnect(); } else { MelonModLogger.Log("Player joined with ID: " + connection.ConnectedTo); players.Add(connection.ConnectedTo); MelonModLogger.Log("Player count: " + players.Count); byte newPlayerId = smallIdCounter; smallPlayerIds.Add(connection.ConnectedTo, newPlayerId); largePlayerIds.Add(newPlayerId, connection.ConnectedTo); smallIdCounter++; playerConnections.Add(connection.ConnectedTo, connection); string name = msg.ReadUnicodeString(); MelonModLogger.Log("Name: " + name); foreach (var smallId in playerNames.Keys) { ClientJoinMessage cjm = new ClientJoinMessage { playerId = smallId, name = playerNames[smallId], steamId = largePlayerIds[smallId] }; connection.SendMessage(cjm.MakeMsg(), MessageSendType.Reliable); } ClientJoinMessage cjm2 = new ClientJoinMessage { playerId = 0, name = SteamClient.Name, steamId = SteamClient.SteamId }; connection.SendMessage(cjm2.MakeMsg(), MessageSendType.Reliable); playerNames.Add(newPlayerId, name); ClientJoinMessage cjm3 = new ClientJoinMessage { playerId = newPlayerId, name = name, steamId = connection.ConnectedTo }; ServerSendToAllExcept(cjm3, MessageSendType.Reliable, connection.ConnectedTo); playerObjects.Add(newPlayerId, new PlayerRep(name, connection.ConnectedTo)); RichPresence.SetActivity( new Activity() { Details = "Hosting a server", Secrets = new ActivitySecrets() { Join = SteamClient.SteamId.ToString() }, Party = new ActivityParty() { Id = partyId, Size = new PartySize() { CurrentSize = players.Count + 1, MaxSize = MultiplayerMod.MAX_PLAYERS } } }); SceneTransitionMessage stm = new SceneTransitionMessage() { sceneName = BoneworksSceneManager.GetCurrentSceneName() }; connection.SendMessage(stm.MakeMsg(), MessageSendType.Reliable); SetPartyIdMessage spid = new SetPartyIdMessage() { partyId = partyId }; connection.SendMessage(spid.MakeMsg(), MessageSendType.Reliable); ui.SetPlayerCount(players.Count, MultiplayerUIState.Server); } break; } case MessageType.Disconnect: { MelonModLogger.Log("Player left with ID: " + connection.ConnectedTo); byte smallId = smallPlayerIds[connection.ConnectedTo]; playerObjects[smallId].Destroy(); playerObjects.Remove(smallId); players.RemoveAll((ulong val) => val == connection.ConnectedTo); smallPlayerIds.Remove(connection.ConnectedTo); P2PMessage disconnectMsg = new P2PMessage(); disconnectMsg.WriteByte((byte)MessageType.Disconnect); disconnectMsg.WriteByte(smallId); foreach (SteamId p in players) { playerConnections[p].SendMessage(disconnectMsg, MessageSendType.Reliable); } break; } //case MessageType.PlayerPosition: // { // if (smallPlayerIds.ContainsKey(packet.Value.SteamId)) // { // byte playerId = smallPlayerIds[packet.Value.SteamId]; // PlayerRep pr = GetPlayerRep(playerId); // PlayerPositionMessage ppm = new PlayerPositionMessage(msg); // pr.head.transform.position = ppm.headPos; // pr.handL.transform.position = ppm.lHandPos; // pr.handR.transform.position = ppm.rHandPos; // pr.ford.transform.position = ppm.pelvisPos - new Vector3(0.0f, 0.3f, 0.0f); // pr.pelvis.transform.position = ppm.pelvisPos; // pr.footL.transform.position = ppm.lFootPos; // pr.footR.transform.position = ppm.rFootPos; // //pr.ford.transform.rotation = ppm.pelvisRot; // pr.head.transform.rotation = ppm.headRot; // pr.handL.transform.rotation = ppm.lHandRot; // pr.handR.transform.rotation = ppm.rHandRot; // pr.pelvis.transform.rotation = ppm.pelvisRot; // pr.footL.transform.rotation = ppm.lFootRot; // pr.footR.transform.rotation = ppm.rFootRot; // // Send to all other players // OtherPlayerPositionMessage relayOPPM = new OtherPlayerPositionMessage // { // headPos = ppm.headPos, // lHandPos = ppm.lHandPos, // rHandPos = ppm.rHandPos, // pelvisPos = ppm.pelvisPos, // lFootPos = ppm.lFootPos, // rFootPos = ppm.rFootPos, // headRot = ppm.headRot, // lHandRot = ppm.lHandRot, // rHandRot = ppm.rHandRot, // pelvisRot = ppm.pelvisRot, // lFootRot = ppm.lFootRot, // rFootRot = ppm.rFootRot, // playerId = smallPlayerIds[packet.Value.SteamId] // }; // ServerSendToAllExcept(relayOPPM, P2PSend.Unreliable, packet.Value.SteamId); // } // break; // } case MessageType.FullRig: { FullRigTransformMessage frtm = new FullRigTransformMessage(msg); byte playerId = smallPlayerIds[connection.ConnectedTo]; if (playerObjects.ContainsKey(playerId)) { PlayerRep pr = playerObjects[playerId]; if (pr.rigTransforms.main != null) { //ApplyTransformMessage(pr, frtm); pr.ApplyTransformMessage(frtm); OtherFullRigTransformMessage ofrtm = new OtherFullRigTransformMessage { playerId = playerId, posMain = frtm.posMain, posRoot = frtm.posRoot, posLHip = frtm.posLHip, posRHip = frtm.posRHip, posLKnee = frtm.posLKnee, posRKnee = frtm.posRKnee, posLAnkle = frtm.posLAnkle, posRAnkle = frtm.posRAnkle, posSpine1 = frtm.posSpine1, posSpine2 = frtm.posSpine2, posSpineTop = frtm.posSpineTop, posLClavicle = frtm.posLClavicle, posRClavicle = frtm.posRClavicle, posNeck = frtm.posNeck, posLShoulder = frtm.posLShoulder, posRShoulder = frtm.posRShoulder, posLElbow = frtm.posLElbow, posRElbow = frtm.posRElbow, posLWrist = frtm.posLWrist, posRWrist = frtm.posRWrist, rotMain = frtm.rotMain, rotRoot = frtm.rotRoot, rotLHip = frtm.rotLHip, rotRHip = frtm.rotRHip, rotLKnee = frtm.rotLKnee, rotRKnee = frtm.rotRKnee, rotLAnkle = frtm.rotLAnkle, rotRAnkle = frtm.rotRAnkle, rotSpine1 = frtm.rotSpine1, rotSpine2 = frtm.rotSpine2, rotSpineTop = frtm.rotSpineTop, rotLClavicle = frtm.rotLClavicle, rotRClavicle = frtm.rotRClavicle, rotNeck = frtm.rotNeck, rotLShoulder = frtm.rotLShoulder, rotRShoulder = frtm.rotRShoulder, rotLElbow = frtm.rotLElbow, rotRElbow = frtm.rotRElbow, rotLWrist = frtm.rotLWrist, rotRWrist = frtm.rotRWrist }; ServerSendToAllExcept(ofrtm, MessageSendType.Unreliable, connection.ConnectedTo); } } break; } case MessageType.HandGunChange: { HandGunChangeMessage hgcm = new HandGunChangeMessage(msg, false) { playerId = smallPlayerIds[connection.ConnectedTo], isForOtherPlayer = false }; MelonModLogger.Log("Got HGC: " + hgcm.type.ToString() + ", destroy: " + hgcm.destroy.ToString()); if (hgcm.destroy) { Destroy(playerObjects[smallPlayerIds[connection.ConnectedTo]].currentGun); } else { MelonModLogger.Log("Spawning " + hgcm.type.ToString()); PlayerRep pr = playerObjects[smallPlayerIds[connection.ConnectedTo]]; pr.currentGun = BWUtil.SpawnGun(hgcm.type); if (pr.currentGun == null) { MelonModLogger.LogError("Failed to spawn gun"); } pr.currentGun.transform.parent = pr.gunParent.transform; pr.currentGun.transform.localPosition = Vector3.zero; pr.currentGun.transform.localRotation = Quaternion.identity; //Quaternion.AngleAxis(90.0f, new Vector3(0.0f, 1.0f, 0.0f)) * Quaternion.AngleAxis(90.0f, new Vector3(1.0f, 0.0f, 0.0f)); pr.currentGun.GetComponentInChildren <Rigidbody>().isKinematic = true; } hgcm.isForOtherPlayer = true; ServerSendToAllExcept(hgcm, MessageSendType.Reliable, connection.ConnectedTo); break; } default: MelonModLogger.Log("Unknown message type: " + type.ToString()); break; } }