public override void Write(byte[] buffer, int offset, int count) { stream.Write(buffer, offset, count); // ETW Provider Dump Message and Reassembly string messageName = "RDPBCGR:TLSSent"; byte[] sentBytes = new byte[count]; Array.Copy(buffer, offset, sentBytes, 0, count); sentBuffer.AddRange(sentBytes); if (sentBufferIndex + lengthHigh < sentBuffer.Count && sentBufferIndex + lengthLow < sentBuffer.Count) { int length = (sentBuffer[sentBufferIndex + lengthHigh] << 8) + sentBuffer[sentBufferIndex + lengthLow]; while (sentBufferIndex + headerLength + length < sentBuffer.Count) { sentBufferIndex = sentBufferIndex + headerLength + length; length = (sentBuffer[sentBufferIndex + lengthHigh] << 8) + sentBuffer[sentBufferIndex + lengthLow]; } if (sentBufferIndex + headerLength + length == sentBuffer.Count) { ExtendedLogger.DumpMessage(messageName, RdpbcgrUtility.DumpLevel_LayerTLS, "TLS Sent Data", sentBuffer.ToArray()); sentBuffer.Clear(); sentBufferIndex = 0; } } }
public OBFUnityActionInternal(Type type, object instance) { MethodInfo[] addRemoveMethods = type.GetMethods().Where(a => a.GetParameters().Length > 0 && a.GetParameters()[0].ParameterType == typeof(UnityAction <T>)).ToArray(); if (addRemoveMethods.Length < 2) { ExtendedLogger.LogError("Failed to find required UnityActionInternal functions for type: " + type.Name + "!"); return; } if (addRemoveMethods[0].GetMethodBody().GetILAsByteArray().Length > addRemoveMethods[1].GetMethodBody().GetILAsByteArray().Length) { MethodAdd = addRemoveMethods[0]; MethodRemove = addRemoveMethods[1]; } else { MethodAdd = addRemoveMethods[1]; MethodRemove = addRemoveMethods[0]; } MethodExecute = type.GetMethods().First(a => a.GetParameters()[0].ParameterType == typeof(T)); ExtendedLogger.Log("Found Execute method in " + type.Name + " with name: " + MethodExecute.Name + "!"); ExtendedLogger.Log("Found Add method in " + type.Name + " with name: " + MethodAdd.Name + "!"); ExtendedLogger.Log("Found Remove method in " + type.Name + " with name: " + MethodRemove.Name + "!"); Instance = instance; }
public override int Read(byte[] buffer, int offset, int count) { int readcount = stream.Read(buffer, offset, count); // ETW Provider Dump Message and Reassembly string messageName = "RDPBCGR:TLSReceived"; byte[] readBytes = new byte[readcount]; Array.Copy(buffer, offset, readBytes, 0, readcount); receivedBuffer.AddRange(readBytes); if (receivedBufferIndex + lengthHigh < receivedBuffer.Count && receivedBufferIndex + lengthLow < receivedBuffer.Count) { int length = (receivedBuffer[receivedBufferIndex + lengthHigh] << 8) + receivedBuffer[receivedBufferIndex + lengthLow]; while (receivedBufferIndex + headerLength + length < receivedBuffer.Count) { receivedBufferIndex = receivedBufferIndex + headerLength + length; length = (receivedBuffer[receivedBufferIndex + lengthHigh] << 8) + receivedBuffer[receivedBufferIndex + lengthLow]; } if (receivedBufferIndex + headerLength + length == receivedBuffer.Count) { ExtendedLogger.DumpMessage(messageName, RdpbcgrUtility.DumpLevel_LayerTLS, "TLS Received Data", receivedBuffer.ToArray()); receivedBuffer.Clear(); receivedBufferIndex = 0; } } return(readcount); }
/// <summary> /// Receive Loop /// </summary> private void ReceiveLoop() { TimeSpan timeout; object remoteEndpoint; StackPacket receivedPacket; timeout = new TimeSpan(0, 0, 10); // 100 milliseconds. while (running) { // An infinite loop to receive packet from transport stack. try { receivedPacket = udpTransport.ExpectPacket(timeout, localEndPoint, out remoteEndpoint); if (serverSocketDic.ContainsKey(remoteEndpoint as IPEndPoint)) { serverSocketDic[remoteEndpoint as IPEndPoint].ReceivePacket(receivedPacket); } else // If the packet belong to no RDPEUDP socket, try to Accept as a new RDPEUDP socket. { StackPacketInfo packetinfo = new StackPacketInfo(localEndPoint, remoteEndpoint, receivedPacket); lock (this.unprocessedPacketBuffer) { unprocessedPacketBuffer.Add(packetinfo); } // ETW Provider Dump Message byte[] packetBytes = receivedPacket.ToBytes(); string messageName = "RDPEUDP:ReceivedPDU"; ExtendedLogger.DumpMessage(messageName, RdpeudpSocket.DumpLevel_LayerTLS, typeof(RdpeudpPacket).Name, packetBytes); } } catch (TimeoutException) { } Thread.Sleep(RdpeudpSocketConfig.ReceivingInterval); } }
void OnApplicationFocus(bool hasFocus) { if (!ModPrefs.GetBool("vrcextended", "fpsManagement")) { return; } if (!hasFocus) { Application.targetFrameRate = 5; ExtendedLogger.Log("Game out of focus, setting FPS to " + Application.targetFrameRate); } else { if (ModPrefs.GetBool("vrcextended", "unlimitedFPS")) { Application.targetFrameRate = 0; } else { Application.targetFrameRate = VRCExtended.FrameRate; } ExtendedLogger.Log("Game in focus, setting FPS to " + Application.targetFrameRate); } }
/// <summary> /// Sends a request to SUT /// </summary> /// <param name="SUTIPAddress">Indicats IP address of SUT</param> /// <returns>Indicates if the request is sent succesfully</returns> public bool SendRequest(string SUTIPAddress) { // Add code here to construct a requst message and then send it to SUT // Dump request message to ETW provider: Protocol-Test-Suite // Then the message data could be captured using an ETW capture tool. // It's useful when the message is encrypted. ExtendedLogger.DumpMessage("XXXX: Request", System.Text.Encoding.Default.GetBytes("Here is the binary of the request")); return(true); }
public VRCEUiText(string name, Vector2 position, string text, Transform parent = null) { // Get required information Transform orgControl = VRCEUi.InternalUserInfoScreen.UsernameText; if (orgControl == null) { ExtendedLogger.LogError("Could not find Username text!"); Success = false; return; } // Duplicate object GameObject goControl = GameObject.Instantiate(orgControl.gameObject); if (goControl == null) { ExtendedLogger.LogError("Could not duplicate Favorite button!"); Success = false; return; } // Set UI properties Control = goControl.transform; TextControl = Control.GetComponent <Text>().transform; // Remove components that may cause issues GameObject.DestroyImmediate(Control.GetComponent <RectTransform>()); // Set control properties Text = TextControl.GetComponent <Text>(); // Set required parts if (parent != null) { Control.SetParent(parent); } goControl.name = name; // Modify RectTransform Position = Control.GetComponent <RectTransform>(); RectTransform tmpRT = orgControl.GetComponent <RectTransform>(); Position.localScale = tmpRT.localScale; Position.anchoredPosition = tmpRT.anchoredPosition; Position.sizeDelta = tmpRT.sizeDelta; Position.localPosition = new Vector3(position.x, position.y, 0f); Position.localRotation = tmpRT.localRotation; // Change UI properties Text.text = text; // Finish Success = true; }
/// <summary> /// Send bytes via UDP transport /// </summary> /// <param name="data"></param> public void SendBytesByUDP(byte[] data) { StackPacket stackPacket = new RdpeudpBasePacket(data); packetSender(remoteEndPoint, stackPacket); // ETW Provider Dump Message string messageName = "RDPEUDP:SentPDU"; ExtendedLogger.DumpMessage(messageName, DumpLevel_LayerTLS, typeof(RdpeudpPacket).Name, data); }
/// <summary> /// Waits for a resonse from SUT /// </summary> /// <param name="status">Indicates the status in the response</param> /// <param name="timeout">Indicates the timeout in seconds when waiting for the response</param> /// <returns>Indicates if the response is received successfully</returns> public bool WaitForResponse(out int status, int timeout) { // Add code here to receive data from SUT, and parse the data to a message structure status = 0; // Dump response message to ETW provider: Protocol-Test-Suite // Then the message data could be captured using an ETW capture tool. // It's useful when the message is encrypted. ExtendedLogger.DumpMessage("XXXX: Response", System.Text.Encoding.Default.GetBytes("Here is the binary of the response")); return(true); }
/// <summary> /// Process Static virtual channel data /// </summary> /// <param name="data"></param> protected void ProcessSVCData(byte[] data) { if (this.Received != null) { Received(data); } // ETW Provider Dump message string messageName = "RDPBCGR:SVC Received Data"; ExtendedLogger.DumpMessage(messageName, RdpbcgrUtility.DumpLevel_Layer1, "RDPBCGR: Static Virtual Channel Received Data", data); }
void OnTriggerExit(Collider collider) { if (collider.tag != "handCollider") { return; } /*if (VRCEPlayer.Instance.Avatar == collider.gameObject) * return;*/ ExtendedLogger.Log("Exited collider!"); }
internal static void Setup() { _player_get_user = typeof(Player).GetMethod("get_user", BindingFlags.Public | BindingFlags.Instance); _player_get_Instance = typeof(Player).GetMethod("get_Instance", BindingFlags.Public | BindingFlags.Static); _vrcplayer_get_AvatarManager = typeof(VRCPlayer).GetMethod("get_AvatarManager", BindingFlags.Public | BindingFlags.Instance); #if DEBUG _vrcplayer_get_uSpeaker = typeof(VRCPlayer).GetMethod("get_uSpeaker", BindingFlags.Public | BindingFlags.Instance); _uspeaker_AudioSource = typeof(USpeaker).GetFields(BindingFlags.NonPublic | BindingFlags.Instance).First(a => a.FieldType == typeof(AudioSource)); ExtendedLogger.Log("Found user voice AudioSource: " + _uspeaker_AudioSource.Name); #endif }
private static void SetupUserInfo(PageUserInfo __instance) { SelectedAPI = __instance.user; ExtendedUser eUser = ExtendedServer.Users.FirstOrDefault(a => a.UniqueID == SelectedAPI.id); VRCExtended.ToggleUserInfoMore(false); VRCEUi.InternalUserInfoScreen.Moderator.gameObject.SetActive(false); if (APIUser.CurrentUser.id == __instance.user.id) { VRCExtended.UserInfoLastLogin.Text.text = ""; VRCExtended.UserInfoMore.Button.interactable = false; } else { APIUser.FetchUser(__instance.user.id, (APIUser user) => { if (string.IsNullOrEmpty(user.last_login)) { return; } DateTime dt = DateTime.Parse(user.last_login); if (ModPrefs.GetBool("vrcextended", "useDTFormat")) { VRCExtended.UserInfoLastLogin.Text.text = "Last login: "******"MM.dd.yyyy hh:mm tt"); } else { VRCExtended.UserInfoLastLogin.Text.text = "Last login: "******"dd.MM.yyyy hh:mm"); } }, (string error) => { ExtendedLogger.LogError(error); }); VRCExtended.UserInfoMore.Button.interactable = true; if (eUser != null) { VRCExtended.UserInfoColliderControl.Button.interactable = true; VRCExtended.UserInfoColliderControl.Text.text = (eUser.HasColliders ? "Disable colliders" : "Enable colliders"); } else { VRCExtended.UserInfoColliderControl.Button.interactable = false; VRCExtended.UserInfoColliderControl.Text.text = "Not in world!"; } } }
static async Task Main(string[] args) { ILogger logger = new ExtendedLogger(); CommandExecuter cmd = new CommandExecuter(logger); var parser = new Parser(config => config.CaseInsensitiveEnumValues = true); await parser.ParseArguments <SettingsListOptions, CreateSettingsOptions, ChangeSettingsOptions, WatchOptions>(args) .MapResult( async(SettingsListOptions options) => await cmd.ExecuteAsync(new SettingsListCommand(), options), async(CreateSettingsOptions options) => await cmd.ExecuteAsync(new CreateSettingsCommand(), options), async(ChangeSettingsOptions options) => await cmd.ExecuteAsync(new ChangeSettingsCommand(), options), async(WatchOptions options) => await cmd.ExecuteAsync(new WatchCommand(), options), // TODO: async (BuildOptions options) => await cmd.ExecuteAsync(new BuildCommand(), options), async errs => 1); }
/// <summary> /// Send bytes through this security channel /// </summary> /// <param name="data"></param> /// <param name="timeout"></param> public void Send(byte[] data) { if (!isAuthenticated) { throw new NotSupportedException("Cannot send bytes from SSL Stream before it is authenticated."); } if (data != null && data.Length > 0) { byte[] dataToSent = Encrypt(data); this.rdpeudpSocket.Send(dataToSent); // ETW Provider Dump Message string messageName = "RDPEMT:SentPDU"; ExtendedLogger.DumpMessage(messageName, RdpbcgrUtility.DumpLevel_Layer2, "RDPEMT Sent PDU", data); } }
/// <summary> /// Send bytes through this security channel /// </summary> /// <param name="data"></param> /// <param name="timeout"></param> public void Send(byte[] data) { if (data != null && data.Length > 0) { List <byte[]> toSentList = Encrypt(data); if (toSentList != null) { foreach (byte[] toSentData in toSentList) { rdpeudpSocket.Send(toSentData); } } // ETW Provider Dump Message string messageName = "RDPEMT:SentPDU"; ExtendedLogger.DumpMessage(messageName, RdpbcgrUtility.DumpLevel_Layer2, "RDPEMT Sent PDU", data); } }
/// <summary> /// Method used to process a received packet /// </summary> /// <param name="packet"></param> public void ReceivePacket(StackPacket packet) { // Transfer packet to RdpeudpPacket eudpPacket = new RdpeudpPacket(); byte[] packetBytes = packet.ToBytes(); if (!PduMarshaler.Unmarshal(packetBytes, eudpPacket, false)) { return; } // ETW Provider Dump Message string messageName = "RDPEUDP:ReceivedPDU"; ExtendedLogger.DumpMessage(messageName, DumpLevel_LayerTLS, eudpPacket.GetType().Name, packetBytes); ReceivePacket(eudpPacket); }
public static void Setup() { // Setup harmony instances HarmonyInstance iSetupUserInfo = HarmonyInstance.Create("vrcextended.pageuserinfo.setupuserinfo"); // Patch try { iSetupUserInfo.Patch(typeof(PageUserInfo).GetMethods(BindingFlags.Public | BindingFlags.Instance).First(a => a.Name == "SetupUserInfo" && a.GetParameters().Length > 1), null, new HarmonyMethod(typeof(Patch_PageUserInfo).GetMethod("SetupUserInfo", BindingFlags.NonPublic | BindingFlags.Static))); ExtendedLogger.Log("Patched PageUserInfo.SetupUserInfo"); } catch (Exception ex) { ExtendedLogger.LogError("Failed to patch PageUserInfo!", ex); return; } }
public static void Setup() { // Setup harmony instances HarmonyInstance iEnter = HarmonyInstance.Create("vrcextended.portalinternal.enter"); // Patch try { iEnter.Patch(typeof(PortalInternal).GetMethod("Enter", BindingFlags.Public | BindingFlags.Instance), new HarmonyMethod(typeof(Patch_PortalInternal).GetMethod("Enter", BindingFlags.Static | BindingFlags.NonPublic))); ExtendedLogger.Log("Patched PortalInternal.Enter"); } catch (Exception ex) { ExtendedLogger.LogError("Failed to patch PortalInternal: " + ex); return; } }
/// <summary> /// Send data from this channel /// </summary> /// <param name="data"></param> public void Send(byte[] data) { if (data == null || data.Length == 0) { return; } ChannelChunk[] chunks = SplitToChunks(data); foreach (ChannelChunk chunk in chunks) { Sender(ChannelId, chunk.channelPduHeader, chunk.chunkData); } // ETW Provider Dump message string messageName = "RDPBCGR:SVC Sent Data"; ExtendedLogger.DumpMessage(messageName, RdpbcgrUtility.DumpLevel_Layer1, "RDPBCGR: Static Virtual Channel Sent Data", data); }
public static Transform DuplicateButton(Transform button, string name, string text, Vector2 offset, Transform parent = null) { // Create new one GameObject goButton = GameObject.Instantiate(button.gameObject); if (goButton == null) { ExtendedLogger.LogError("Could not duplicate button!"); return(null); } // Get UI components Button objButton = goButton.GetComponentInChildren <Button>(); Text objText = goButton.GetComponentInChildren <Text>(); // Destroy broke components GameObject.DestroyImmediate(goButton.GetComponent <RectTransform>()); // Set required parts if (parent != null) { goButton.transform.SetParent(parent); } goButton.name = name; // Modify RectTransform RectTransform rtOriginal = button.GetComponent <RectTransform>(); RectTransform rtNew = goButton.GetComponent <RectTransform>(); rtNew.localScale = rtOriginal.localScale; rtNew.anchoredPosition = rtOriginal.anchoredPosition; rtNew.sizeDelta = rtOriginal.sizeDelta; rtNew.localPosition = rtOriginal.localPosition + new Vector3(offset.x, offset.y, 0f); rtNew.localRotation = rtOriginal.localRotation; // Change UI properties objText.text = text; objButton.onClick = new Button.ButtonClickedEvent(); // Finish return(goButton.transform); }
protected static void SubscribeLogger() { DumpMessageHandler = new KerberosUtility.DumpMessageEventHandler ( (string messageName, string messageDescription, KerberosUtility.DumpLevel dumpLevel, byte[] payload) => { if (Enum.IsDefined(typeof(DumpLevel), (int)dumpLevel)) { ExtendedLogger.DumpMessage(messageName, (DumpLevel)dumpLevel, messageDescription, payload); } } ); KerberosUtility.DumpMessage += DumpMessageHandler; }
/// <summary> /// Process bytes received from /// </summary> /// <param name="data"></param> public void ReceiveBytes(byte[] data) { if (data != null && data.Length > 0) { innerStream.AddReceivedData(data); if (isAuthenticated) { int actualLen = this.sslStream.Read(readBuffer, 0, readBuffer.Length); byte[] decryptedData = new byte[actualLen]; Array.Copy(readBuffer, 0, decryptedData, 0, actualLen); // ETW Provider Dump Message string messageName = "RDPEMT:ReceivedPDU"; ExtendedLogger.DumpMessage(messageName, RdpbcgrUtility.DumpLevel_Layer2, "RDPEMT Received PDU", decryptedData); if (Received != null) { Received(decryptedData); } } } }
/// <summary> /// Process bytes received from /// </summary> /// <param name="data"></param> public void ReceiveBytes(byte[] data) { if (data != null && data.Length > 0) { if (isAuthenticated) { byte[] decryptedData = Decrypt(data); // ETW Provider Dump Message string messageName = "RDPEMT:ReceivedPDU"; ExtendedLogger.DumpMessage(messageName, RdpbcgrUtility.DumpLevel_Layer2, "RDPEMT Received PDU", decryptedData); if (Received != null) { Received(decryptedData); } } else { this.AddReceivedData(data); } } }
public void SegmentAndCompressFrame(byte[] rawSvrData, byte compressFlag, uint segmentPartSize) { // Set descriptor type based on data length if (rawSvrData.Length <= segmentPartSize) { segHeader.descriptor = DescriptorTypes.SINGLE; segHeader.bulkData = new RDP8_BULK_ENCODED_DATA(); segHeader.bulkData.header = compressFlag; // RDP 8.0 compression here. if (compressFlag == ((byte)PACKET_COMPR_FLAG.PACKET_COMPR_TYPE_RDP8 | (byte)PACKET_COMPR_FLAG.PACKET_COMPRESSED)) { CompressFactory cpf = new CompressFactory(); byte[] compressedData = cpf.Compress(rawSvrData); segHeader.bulkData.data = compressedData; // ETW Provider Dump message string messageName = "DecompressedData"; ExtendedLogger.DumpMessage(messageName, RdpbcgrUtility.DumpLevel_Layer3, "Decompressed data", rawSvrData); } else { segHeader.bulkData.data = rawSvrData; } segHeadList.Add(segHeader); } else { segHeader.descriptor = DescriptorTypes.MULTIPART; segHeader.uncompressedSize = (uint)(rawSvrData.Length); int totalLength = rawSvrData.Length; if (totalLength % segmentPartSize == 0) { segHeader.segmentCount = (ushort)(totalLength / segmentPartSize); } else { segHeader.segmentCount = (ushort)(totalLength / segmentPartSize + 1); } segHeader.segmentArray = new RDP_DATA_SEGMENT[segHeader.segmentCount]; uint baseIndex = 0; uint cnt = 0; while (cnt < segHeader.segmentCount) { Byte[] rawPartData; if (cnt + 1 < segHeader.segmentCount) { rawPartData = new Byte[segmentPartSize]; Array.Copy(rawSvrData, baseIndex, rawPartData, 0, segmentPartSize); } else // Last segment. { rawPartData = new Byte[(uint)totalLength - baseIndex]; Array.Copy(rawSvrData, baseIndex, rawPartData, 0, (uint)totalLength - baseIndex); } segHeader.segmentArray[cnt] = new RDP_DATA_SEGMENT(); if (compressFlag == ((byte)PACKET_COMPR_FLAG.PACKET_COMPR_TYPE_RDP8 | (byte)PACKET_COMPR_FLAG.PACKET_COMPRESSED)) { CompressFactory cpf = new CompressFactory(); byte[] compressData = cpf.Compress(rawPartData); segHeader.segmentArray[cnt].bulkData = new RDP8_BULK_ENCODED_DATA(); segHeader.segmentArray[cnt].bulkData.header = compressFlag; segHeader.segmentArray[cnt].bulkData.data = compressData; segHeader.segmentArray[cnt].size = (uint)(segHeader.segmentArray[cnt].bulkData.data.Length + 1); // ETW Provider Dump message string messageName = "DecompressedData"; ExtendedLogger.DumpMessage(messageName, RdpbcgrUtility.DumpLevel_Layer3, "Decompressed data", rawPartData); } else { segHeader.segmentArray[cnt].bulkData = new RDP8_BULK_ENCODED_DATA(); segHeader.segmentArray[cnt].bulkData.header = compressFlag; segHeader.segmentArray[cnt].bulkData.data = rawPartData; segHeader.segmentArray[cnt].size = (uint)(segHeader.segmentArray[cnt].bulkData.data.Length + 1); } baseIndex += segmentPartSize; cnt++; } // Add segmented data into segHeadList. segHeadList.Add(segHeader); } }
public VRCEUiVolumeControl(string name, Vector2 position, string text, float value = 1f, Transform parent = null) { // Get required information Transform orgVolumeMaster = VRCEUi.InternalSettingsScreen.VolumeMaster; if (orgVolumeMaster == null) { ExtendedLogger.LogError("Could not find VolumeMaster!"); Success = false; return; } // Duplicate object GameObject goVolumeControl = GameObject.Instantiate(orgVolumeMaster.gameObject); if (goVolumeControl == null) { ExtendedLogger.LogError("Could not duplicate VolumeMaster!"); Success = false; return; } // Set UI properties VolumeControl = goVolumeControl.transform; FillArea = VolumeControl.Find("FillArea"); SliderLabel = VolumeControl.Find("SliderLabel"); Label = VolumeControl.Find("Label"); // Remove components that may cause issues GameObject.DestroyImmediate(VolumeControl.GetComponent <UiSettingConfig>()); GameObject.DestroyImmediate(VolumeControl.GetComponent <RectTransform>()); // Set control properties Text = Label.GetComponent <Text>(); Slider = VolumeControl.GetComponent <Slider>(); // Set required parts if (parent != null) { VolumeControl.SetParent(parent); } goVolumeControl.name = name; // Modify RectTransform Position = VolumeControl.GetComponent <RectTransform>(); RectTransform tmpRT = orgVolumeMaster.GetComponent <RectTransform>(); Position.localScale = tmpRT.localScale; Position.anchoredPosition = tmpRT.anchoredPosition; Position.sizeDelta = tmpRT.sizeDelta; Position.localPosition = new Vector3(position.x, position.y, 0f); Position.localRotation = tmpRT.localRotation; Label.GetComponent <RectTransform>().localPosition = Label.GetComponent <RectTransform>().localPosition + new Vector3(50f, 0f, 0f); // Change UI properties Text.text = text; Slider.value = value; // Finish Success = true; }
internal static void Setup() { // Network manager setup _networkManagerType = typeof(PlayerManager).Assembly.GetType("NetworkManager"); if (_networkManagerType == null) { ExtendedLogger.LogError("Failed to get NetworkManager!"); return; } ExtendedLogger.Log("Found NetworkManager!"); _networkManagerInstance = _networkManagerType.GetField("Instance", BindingFlags.Public | BindingFlags.Static); if (_networkManagerInstance == null) { ExtendedLogger.LogError("Failed to get NetworkManager Instance!"); return; } ExtendedLogger.Log("Found NetworkManager Instance!"); FieldInfo onPlayerJoinedEvent = _networkManagerType.GetField("OnPlayerJoinedEvent", BindingFlags.Public | BindingFlags.Instance); if (onPlayerJoinedEvent == null) { ExtendedLogger.LogError("Failed to get NetworkManager OnPlayerJoinedEvent!"); return; } ExtendedLogger.Log("Found NetworkManager OnPlayerJoinedEvent!"); FieldInfo onPlayerLeftEvent = _networkManagerType.GetField("OnPlayerLeftEvent", BindingFlags.Public | BindingFlags.Instance); if (onPlayerLeftEvent == null) { ExtendedLogger.LogError("Failed to get NetworkManager OnPlayerLeftEvent!"); return; } ExtendedLogger.Log("Found NetworkManager OnPlayerLeftEvent!"); Type unityActionInternalType = onPlayerJoinedEvent.FieldType; if (unityActionInternalType == null) { ExtendedLogger.LogError("Failed to get UnityActionInternal!"); return; } ExtendedLogger.Log("Found UnityActionInternal named " + unityActionInternalType.Name + "!"); _networkManager_OnPlayerJoinedEvent = new OBFUnityActionInternal <Player>(unityActionInternalType, onPlayerJoinedEvent.GetValue(_networkManagerInstance.GetValue(null))); _networkManager_OnPlayerLeftEvent = new OBFUnityActionInternal <Player>(unityActionInternalType, onPlayerLeftEvent.GetValue(_networkManagerInstance.GetValue(null))); _networkManager_OnPlayerJoinedEvent.Add(new UnityAction <Player>(delegate(Player player) { if (OnPlayerJoined != null) { OnPlayerJoined(new VRCEPlayer(player)); } })); _networkManager_OnPlayerLeftEvent.Add(new UnityAction <Player>(delegate(Player player) { if (OnPlayerLeft != null) { OnPlayerLeft(new VRCEPlayer(player)); } })); }