// Prints the properties of a given type public static void PrintProps <T>(T t) { MelonModLogger.Log("====== Type " + t.ToString() + "======"); System.Reflection.PropertyInfo[] props = typeof(T).GetProperties(); foreach (var pi in props) { //if (pi.PropertyType.IsPrimitive) try { var val = pi.GetValue(t); if (val != null) { MelonModLogger.Log(pi.Name + ": " + val.ToString()); } else { MelonModLogger.Log(pi.Name + ": null"); } } catch { MelonModLogger.LogError("Error tring to get property " + pi.Name); } } }
private IEnumerator ProcessRunBeforeFlowManager() { // Wait for the 'Application2' scene (the one with VRCFlowManagerVRC) while (SceneManager.GetActiveScene().buildIndex != 0) { yield return(null); } // Discard if there is nothing queued if (preFlowManagerQueue.Count == 0) { MelonModLogger.LogError("Discarting PreFlowManager process, since there is no queued methods."); preFlowManagerProcessed = true; yield break; } // Get VRCFlowManagerVRC and disable it, plus stop all running coroutine VRCFlowManagerVRC flowManager = VRCFlowManagerVRC.field_VRCFlowManager_0.Cast <VRCFlowManagerVRC>(); flowManager.StopAllCoroutines(); // Load the 'Ui' scene if (GameObject.Find("UserInterface") == null) { MelonModLogger.Log("Loading additive scene \"ui\""); SceneManager.LoadScene("ui", LoadSceneMode.Single); } MelonModLogger.Log("Waiting for VRCUiManager..."); // Wait for VRCUiManager to load while (VRCUiManager.field_VRCUiManager_0 == null) { yield return(null); } MelonModLogger.Log("Processing pre-FlowManager routines"); // Process all sheduled actions before flow Manager init while (preFlowManagerQueue.Count > 0) { MelonModLogger.Log("Remaining routines in queue: " + preFlowManagerQueue.Count); yield return(preFlowManagerQueue.Dequeue()); } MelonModLogger.Log("Done! Starting game"); preFlowManagerProcessed = true; // Start the VRCFlowManagerVRC Coroutine Type[] types = typeof(VRCFlowManagerVRC).GetNestedTypes().Where(t => t.GetMethod("MoveNext") != null).ToArray(); Type vrcFlowManagerEnumeratorType = types[0].GetProperties().Length > types[1].GetProperties().Length ? types[1] : types[0]; System.Reflection.ConstructorInfo constructor = vrcFlowManagerEnumeratorType.GetConstructor(new Type[] { typeof(int) }); object o = constructor.Invoke(new object[] { 0 }); MelonModLogger.Log("Instanciated object: " + o); o.GetType().GetProperty("field_Il2CppStructArray_1_Nested0_0").SetValue(o, (Il2CppStructArray <VRCFlowManager.Nested0>) new VRCFlowManager.Nested0[] { VRCFlowManager.Nested0.ShowUI }); o.GetType().GetProperty("field_VRCFlowManagerVRC_0").SetValue(o, flowManager); flowManager.StartCoroutine(((Il2CppSystem.Object)o).Cast <Il2CppSystem.Collections.IEnumerator>()); MelonModLogger.Log("FlowManager coroutine started"); }
public static Command CreateInstance(String className, Client client, bool log = true) { if (log) { MelonModLogger.Log("Creating command instance " + className + ". Client: " + client); } if (commands.TryGetValue(className, out Type commandClass)) { try { Command command = (Command)Activator.CreateInstance(commandClass); long outId; lock (counter) { outId = (long)(counter.NextDouble() * long.MaxValue); } command.SetLog(log); command.SetClient(client); command.SetOutId(className + " " + outId); if (!runningCommands.TryGetValue(className, out Dictionary <string, Command> commandContainer)) { commandContainer = new Dictionary <String, Command>(); runningCommands.Add(className, commandContainer); } commandContainer.Add("" + outId, command); return(command); } catch (Exception e) { MelonModLogger.LogError(e.ToString()); } } return(null); }
public void Disconnect() { ui.SetState(MultiplayerUIState.PreConnect); try { foreach (PlayerRep r in playerObjects.Values) { r.Destroy(); } } catch (Exception) { MelonModLogger.LogError("Caught exception destroying player objects"); } MelonModLogger.Log("Disconnecting..."); isConnected = false; ServerId = 0; playerObjects.Clear(); playerNames.Clear(); largePlayerIds.Clear(); smallPlayerIds.Clear(); if (connection.IsConnected) { connection.Disconnect(); } //PlayerHooks.OnPlayerGrabObject -= PlayerHooks_OnPlayerGrabObject; //PlayerHooks.OnPlayerLetGoObject -= PlayerHooks_OnPlayerLetGoObject; //SteamNetworking.OnP2PConnectionFailed = null; //SteamNetworking.OnP2PSessionRequest = null; }
public Client(string address, int port, string clientVersion) { this.address = address; this.port = port; this.clientVersion = clientVersion; keepaliveThread = new Thread(() => { while (true) { if (listen) { try { WriteLine("KEEPALIVE"); } catch (Exception e) { MelonModLogger.LogError("Error while trying to send keepalive: " + e); } } Thread.Sleep(3000); } }); keepaliveThread.Name = "VRCMod Networking Thread (Keepalive)"; keepaliveThread.IsBackground = true; }
public void Disconnect() { try { foreach (PlayerRep r in playerObjects.Values) { r.Destroy(); } } catch (Exception) { MelonModLogger.LogError("Caught exception destroying player objects"); } MelonModLogger.Log("Disconnecting..."); isConnected = false; ServerId = 0; playerObjects.Clear(); playerNames.Clear(); largePlayerIds.Clear(); smallPlayerIds.Clear(); SteamNetworking.CloseP2PSessionWithUser(ServerId); //PlayerHooks.OnPlayerGrabObject -= PlayerHooks_OnPlayerGrabObject; //PlayerHooks.OnPlayerLetGoObject -= PlayerHooks_OnPlayerLetGoObject; RichPresence.OnJoin -= RichPresence_OnJoin; RichPresence.SetActivity(new Activity() { Details = "Idle", Assets = { LargeImage = "jobsim" } }); }
public override void OnStart() { try { var HarmonyInstance = Manager.CreateInstance("Quality Assurance"); var API = SDK.GetClass("VRC.Core", "API"); var Amp = SDK.GetClass("AmplitudeSDKWrapper", "AmplitudeWrapper"); var Photon = SDK.GetClass("Photon.Pun", "PhotonView"); var AvatarManager = SDK.GetClass("", "VRCAvatarManager"); var moderationManager = SDK.GetClass("", "ModerationManager"); HarmonyInstance.Patch(API.GetMethod("DeviceID"), AccessTools.Method(typeof(Protections), "HWIDSpoofer")); HarmonyInstance.Patch(Amp.GetMethod("InitializeDeviceId"), AccessTools.Method(typeof(Protections), "HWIDSpoofer")); HarmonyInstance.Patch(Photon.GetMethod("Method_Public_Type1595182416_Type2348106871_2"), AccessTools.Method(typeof(Protections), "SerializeView")); //Last function to take class, struct parameters only. } catch (Exception e) { MelonModLogger.LogError("An exception has occurred. Dm Yaekith#1337 on discord. This mod may be outdated."); MelonModLogger.LogError(e.ToString()); } finally { MelonModLogger.Log("Protections have been applied."); MelonModLogger.Log("Your New HWID: " + VRC.Core.API.DeviceID); MelonModLogger.Log("IsOffline: " + VRC.Core.API.IsOffline()); } }
public static void RunCommand(String line, Client client) { string[] parts = line.Split(new char[] { ' ' }, 3); if (runningCommands.TryGetValue(parts[0], out Dictionary <string, Command> commandContainer) && commandContainer.TryGetValue(parts[1], out Command command)) { if (parts[2].StartsWith("ERROR")) { command.RemoteError(parts[2].Split(new char[] { ' ' }, 2)[1]); } else { command.Handle(parts[2]); } } else { if (commands.TryGetValue(parts[0], out Type commandClass)) { try { command = (Command)Activator.CreateInstance(commandClass); command.SetClient(client); command.SetOutId(parts[0] + " " + parts[1]); commandContainer = runningCommands[parts[0]]; if (commandContainer == null) { commandContainer = new Dictionary <String, Command>(); runningCommands.Add(parts[0], commandContainer); } commandContainer.Add(parts[1], command); Command commandHandled = command; Thread commandThread = new Thread(() => { if (commandHandled != null) { try { commandHandled.Handle(parts[2]); } catch (Exception e) { commandHandled.WriteLine("ERROR " + e.Message.ToUpper()); } } }); commandThread.Name = "COMMAND_" + parts[0] + "_" + parts[1]; commandThread.Start(); } catch (Exception e) { MelonModLogger.LogError(e.ToString()); } } else { client.WriteLine(parts[0] + " " + parts[1] + " ERROR COMMAND_NOT_FOUND"); } } }
private IEnumerator WaitAndRegisterEmojiButtons() { while (QuickMenu.prop_QuickMenu_0 == null) { yield return(null); } var emojiMenuRoot = QuickMenu.prop_QuickMenu_0.transform.Find("EmojiMenu"); if (emojiMenuRoot == null) { MelonModLogger.LogError("Emoji menu root not found"); yield break; } var emojiMenu = emojiMenuRoot.GetComponent <EmojiMenu>(); var storeGo = new GameObject("ClonedPageStore"); storeGo.transform.SetParent(emojiMenu.transform); storeGo.SetActive(false); for (var index = 0; index < emojiMenu.pages.Count; index++) { var pageGo = emojiMenu.pages[index]; var clone = new GameObject($"Page{index}Button", new [] { Il2CppType.Of <RectTransform>() }); clone.transform.SetParent(storeGo.transform, false); var grid = clone.AddComponent <GridLayoutGroup>(); grid.constraint = GridLayoutGroup.Constraint.FixedColumnCount; grid.cellSize = new Vector2(33, 33); grid.startAxis = GridLayoutGroup.Axis.Horizontal; grid.startCorner = GridLayoutGroup.Corner.UpperLeft; grid.constraintCount = 3; foreach (var buttonXformObject in pageGo.transform) { var buttonTransform = buttonXformObject.Cast <Transform>(); if (!buttonTransform.gameObject.activeSelf) { continue; } var buttonClone = Object.Instantiate(buttonTransform.gameObject, clone.transform, false); CleanStuff(buttonClone); } var index1 = index; ExpansionKitApi.RegisterSimpleMenuButton(ExpandedMenu.EmojiQuickMenu, "", () => { emojiMenu.pages[emojiMenu.field_Private_Int32_0].SetActive(false); pageGo.SetActive(true); emojiMenu.field_Private_Int32_0 = index1; }, buttonGo => { Object.Instantiate(clone, buttonGo.transform, false); }); } }
public static void LoadPlayer() { bundle = AssetBundle.LoadFromFile("playermodels.mp"); if (bundle == null) { MelonModLogger.LogError("Failed to load the asset bundle"); } }
public override void RemoteError(string error) { base.RemoteError(error); if (Log) { MelonModLogger.LogError("[RPCCommand] Server returned error for RPC " + rpcId + " : " + error); } onError?.Invoke(error); }
private static IEnumerable <CodeInstruction> UnhollowerTranspiler(MethodBase method, IEnumerable <CodeInstruction> instructionsIn) { List <CodeInstruction> instructions = new List <CodeInstruction>(instructionsIn); PatchInfo patchInfo = HarmonySharedState.GetPatchInfo(method); IntPtr copiedMethodInfo = patchInfo.copiedMethodInfoPointer; bool found = false; int replaceIdx = 0; int replaceCount = 0; for (int i = instructions.Count - 2; i >= 0; --i) { if (instructions[i].opcode != OpCodes.Ldsfld) { continue; } found = true; CodeInstruction next = instructions[i + 1]; if (next.opcode == OpCodes.Call && ((MethodInfo)next.operand).Name == "il2cpp_object_get_virtual_method") { // Virtual method: Replace the sequence // - ldarg.0 // - call native int[UnhollowerBaseLib] UnhollowerBaseLib.IL2CPP::Il2CppObjectBaseToPtr(class [UnhollowerBaseLib] UnhollowerBaseLib.Il2CppObjectBase) // - ldsfld native int SomeClass::NativeMethodInfoPtr_Etc // - call native int[UnhollowerBaseLib] UnhollowerBaseLib.IL2CPP::il2cpp_object_get_virtual_method(native int, native int) replaceIdx = i - 2; replaceCount = 4; } else { // Everything else: Just replace the static load replaceIdx = i; replaceCount = 1; } break; } if (!found) { MelonModLogger.LogError("Harmony transpiler could not rewrite Unhollower method. Expect a stack overflow."); return(instructions); } CodeInstruction[] replacement = { new CodeInstruction(OpCodes.Ldc_I8, copiedMethodInfo.ToInt64()), new CodeInstruction(OpCodes.Conv_I) }; instructions.RemoveRange(replaceIdx, replaceCount); instructions.InsertRange(replaceIdx, replacement); return(instructions); }
public static void RunBeforeFlowManager(IEnumerator func) { if (preFlowManagerProcessed) { MelonModLogger.LogError("Trying run a method before FlowManager, but FlowManager has already been ran"); return; } preFlowManagerQueue.Enqueue(func); }
/// <summary> /// Sets the specified GameObject as a prefab for given settings category. The prefab will be instantiated each time "Undo changes" is pressed, in addition to instantiating it on menu creation. /// </summary> /// <param name="categoryName">String passed as first parameter of <see cref="ModPrefs.RegisterCategory"/></param> /// <param name="categoryUi">Prefab that acts as category settings UI</param> public static void RegisterCustomSettingsCategory(string categoryName, GameObject categoryUi) { if (CustomCategoryUIs.ContainsKey(categoryName)) { MelonModLogger.LogError($"Custom UI for category {categoryName} is already registered"); return; } CustomCategoryUIs[categoryName] = categoryUi; }
public static void RegisterCommand(string name, Type command) { if (!commands.TryGetValue(name, out Type cmd)) { commands.Add(name, command); } else { MelonModLogger.LogError("Trying to register a command twice (" + name + ")"); } }
public static bool UpdateIfDirty() { if (_dirty <= 0) { return(false); } _dirty = 0; MelonModLogger.Log($"Updating ColliderMod configs at \"{FullPath}\""); var oldJson = ""; if (!File.Exists(FullPath)) { MelonModLogger.Log( $"No config file found, using default" ); ColliderModConfig = new ColliderModConfig(); } else { try { oldJson = File.ReadAllText(FullPath); JSON.MakeInto(JSON.Load(oldJson), out ColliderModConfig); } catch (Exception e) { ColliderModConfig = new ColliderModConfig(); MelonModLogger.LogError(e.ToString()); MelonModLogger.Log( "Something went wrong when deserializing json. " + "Delete the config to reset everything to default" ); return(true); } } var json = JSON.Dump( ColliderModConfig, EncodeOptions.PrettyPrint | EncodeOptions.NoTypeHints ); if (oldJson == json) { return(true); } File.WriteAllText(FullPath, json); _dirty--; return(true); }
private void OnP2PConnectionFailed(SteamId id, P2PSessionError err) { if (id == ServerId) { MelonModLogger.LogError("Got P2P connection error " + err.ToString()); foreach (PlayerRep pr in playerObjects.Values) { pr.Destroy(); } } }
private void OnP2PConnectionFailed(SteamId id, P2PSessionError error) { if (error == P2PSessionError.NoRightsToApp) { MelonModLogger.LogError("You don't own the game on Steam."); } else if (error == P2PSessionError.NotRunningApp) { // Probably a leaver if (smallPlayerIds.ContainsKey(id)) { MelonModLogger.Log("Player left with SteamID: " + id); byte smallId = smallPlayerIds[id]; 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 == id); smallPlayerIds.Remove(id); } } else if (error == P2PSessionError.Timeout) { MelonModLogger.LogError("Connection with " + id + "timed out."); byte smallId = smallPlayerIds[id]; 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 == id); smallPlayerIds.Remove(id); } else { MelonModLogger.LogError("Unhandled P2P error: " + error.ToString()); } }
private void OnP2PSessionRequest(SteamId id) { if (id != ServerId) { MelonModLogger.LogError("Got a P2P session request from something that is not the server."); } else { SteamNetworking.AcceptP2PSessionWithUser(id); } }
public static void ErrLog(string log, bool debug = false) { if (debug) { if (!Imports.IsDebugMode()) { return; } log = "[DEBUG] " + log; } MelonModLogger.LogError(log); }
public override void OnApplicationStart() { AudioConfiguration a = AudioSettings.GetConfiguration(); a.speakerMode = AudioSpeakerMode.Mode7point1; if (AudioSettings.Reset(a)) { MelonModLogger.Log("Successful change"); } else { MelonModLogger.LogError("Change failed"); } }
private IEnumerator Setup() { // TODO check for updates MelonModLogger.Log("Initialising VRCModNetwork"); MelonModLogger.Log("Overwriting login button event"); VRCUiPageAuthentication loginPage = Resources.FindObjectsOfTypeAll <VRCUiPageAuthentication>().FirstOrDefault((page) => page.gameObject.name == "LoginUserPass"); MelonModLogger.Log("loginPage: " + loginPage); if (loginPage != null) { Button loginButton = loginPage.transform.Find("ButtonDone (1)")?.GetComponent <Button>(); if (loginButton != null) { ButtonClickedEvent bce = loginButton.onClick; loginButton.onClick = new ButtonClickedEvent(); loginButton.onClick.AddListener(new Action(() => { VRCModNetworkManager.SetCredentials(Uri.EscapeDataString(loginPage.loginUserName.field_String_2) + ":" + Uri.EscapeDataString(loginPage.loginPassword.field_String_2)); bce?.Invoke(); })); } else { MelonModLogger.Log("Unable to find login button in login page"); } } try { VRCModNetworkStatus.Setup(); VRCModNetworkLogin.SetupVRCModNetworkLoginPage(); //ModdedUsersManager.Init(); } catch (Exception e) { MelonModLogger.LogError(e.ToString()); } MelonModLogger.Log("Injecting VRCModNetwork login page"); VRCModNetworkLogin.InjectVRCModNetworkLoginPage(); MelonModLogger.Log("Connecting"); yield return(VRCModNetworkManager.ConnectInit()); MelonModLogger.Log("VRCModNetwork sucessfully initialized!"); Initialized = true; }
public static bool UpdateIfDirty() { if (!_dirty) { return(false); } _dirty = false; if (!File.Exists(FullPath)) { MelonModLogger.Log( $"Creating default config file at \"{FullPath}\"" ); var sampleConfig = new List <GravityConfig> { new GravityConfig(), new GravityConfig { gravity = new SerializedVector3(0, 9.81f, 0), trigger = KeyCode.O, holdToActivate = true, }, }; var json = JSON.Dump( sampleConfig, EncodeOptions.PrettyPrint | EncodeOptions.NoTypeHints ); File.WriteAllText(FullPath, json); } MelonModLogger.Log("Updating gravity configs"); GravityConfigs.Clear(); try { var json = File.ReadAllText(FullPath); JSON.MakeInto(JSON.Load(json), out GravityConfigs); } catch (Exception e) { MelonModLogger.LogError(e.ToString()); } GravityConfigs = GravityConfigs ?? new List <GravityConfig>(); return(true); }
private void TransportLayer_OnConnectionClosed(ITransportConnection connection, ConnectionClosedReason reason) { if (connection.ConnectedTo != ServerId) { MelonModLogger.LogError("Connection with non-server ID was closed - but we're a client???"); return; } ui.SetState(MultiplayerUIState.PreConnect); MelonModLogger.LogError("Got P2P connection error " + reason.ToString()); foreach (PlayerRep pr in playerObjects.Values) { pr.Destroy(); } }
// Async operations //Task<Facepunch.Steamworks.Data.Image?> task_asyncLoadPlayerIcon; //public bool isPlayerIconLoaded = false; public static void LoadFord() { fordBundle = AssetBundle.LoadFromFile("ford.ford"); if (fordBundle == null) { MelonModLogger.LogError("Failed to load Ford asset bundle"); } GameObject fordPrefab = fordBundle.LoadAsset("Assets/brett_body.prefab").Cast <GameObject>(); if (fordPrefab == null) { MelonModLogger.LogError("Failed to load Ford from the asset bundle???"); } }
private static void ToggleMap(IntPtr selfPtr, IntPtr ownerPtr) { if (OnToggleMap == null) { OrigToggleMap?.Invoke(selfPtr, ownerPtr); return; } try { OnToggleMap(OrigToggleMap, selfPtr.ToGameObject(ptr => new MenuManager(ptr)), ownerPtr.ToGameObject(ptr => new CharacterUI(ptr))); } catch (Exception e) { MelonModLogger.LogError($"An error occurred while executing MenuManagerHooks.OnToggleMap hooks: {e}"); } }
// Prints the properties of a given component type public static void PrintComponentProps <T>(GameObject go) { try { if (go == null) { MelonModLogger.LogError("go was null???"); } T t = go.GetComponent <T>(); if (t == null) { MelonModLogger.LogError("Couldn't find component " + t.GetType().Name); } MelonModLogger.Log("====== Component type " + t.ToString() + "======"); System.Reflection.PropertyInfo[] props = typeof(T).GetProperties(); foreach (var pi in props) { //if (pi.PropertyType.IsPrimitive) try { var val = pi.GetValue(t); if (val != null) { MelonModLogger.Log(pi.Name + ": " + val.ToString()); } else { MelonModLogger.Log(pi.Name + ": null"); } } catch { MelonModLogger.LogError("Error tring to get property " + pi.Name); } } } catch { MelonModLogger.LogError("i don't know anymore"); } }
// Recreates the UI... public void Recreate() { try { GameObject uiPrefab = uiBundle.LoadAsset("Assets/Prefabs/Canvas.prefab").Cast <GameObject>(); uiObj = Instantiate(uiPrefab); uiObj.GetComponent <Canvas>().worldCamera = Camera.current; DontDestroyOnLoad(uiObj); Transform panelTransform = uiObj.transform.Find("Panel"); statusText = panelTransform.Find("StatusText").GetComponent <Text>(); SetState(currentState); } catch (NullReferenceException) { MelonModLogger.LogError("Error loading UI"); } }
public override void OnLevelWasLoaded(int level) { localplayer = Player.prop_Player_0; try { if (localplayer != null) { jump = localplayer.gameObject.GetComponent <PlayerModComponentJump>(); if (jump == null) { jump = localplayer.gameObject.AddComponent <PlayerModComponentJump>(); } } } catch (Exception e) { MelonModLogger.LogError("A Error Has Occured In Initialization \n" + e.ToString()); } }
private static void CreateMaterials() { #if FindObjectsOfTypeAll var shaders = Resources.FindObjectsOfTypeAll <Shader>(); #else MelonModLogger.LogWarning("Temporary fix for not being able to use Resources.FindObjectsOfTypeAll"); var shaders = new Shader[0]; #endif var selectedShader = Shader.Find(ShaderName); if (selectedShader == null) { MelonModLogger.LogError( $"Failed to find shader with name {ShaderName}. Valid shaders:\n" + string.Join("\n", shaders.Select(shader => shader.name)) ); selectedShader = shaders.FirstOrDefault( shader => shader.isSupported && shader.name.Contains("Transparent") ); } if (selectedShader == null) { MelonModLogger.LogError( "Failed to find transparent shader for colliders" ); selectedShader = shaders.FirstOrDefault(); } else { MelonModLogger.Log( "Creating material with shader " + selectedShader.name ); } _triggerMaterial = new Material(selectedShader); _solidMaterial = new Material(selectedShader); _triggerMaterial.color = new Color(1, 0, 0, 0.25f); _solidMaterial.color = new Color(0, 1, 0, 0.25f); Resources.UnloadUnusedAssets(); }