├── README.md ├── Events.cs ├── Logger.cs ├── AstralCore.cs ├── Utils ├── MemoryUtils.cs └── PatternScan.cs ├── Hooks ├── OnPlayerJL.cs └── Hooks.cs ├── LICENSE ├── Managers ├── SelectionManager.cs └── LogManager.cs ├── Types ├── Player.cs └── VRCNetworkingClient.cs ├── AstralCore.csproj └── .gitignore /README.md: -------------------------------------------------------------------------------- 1 | # AstralCore 2 | Optional core to add additional functionality to mods. 3 | 4 | [AstralRCON](https://github.com/Astrum-Project/AstralRCON/) is the recommended way to interact with the Module system. 5 | -------------------------------------------------------------------------------- /Events.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Astrum.AstralCore 4 | { 5 | public static class Events 6 | { 7 | public static Action OnUpdate = new(() => { }); 8 | public static Action OnUIInit = new(() => { }); 9 | public static Action OnPlayerJoined = new(_ => { }); 10 | public static Action OnPlayerLeft = new(_ => { }); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Logger.cs: -------------------------------------------------------------------------------- 1 | namespace Astrum.AstralCore 2 | { 3 | public static class Logger 4 | { 5 | public static void Trace(object obj) => Managers.LogManager.OnTrace(obj.ToString()); 6 | public static void Debug(object obj) => Managers.LogManager.OnDebug(obj.ToString()); 7 | public static void Info (object obj) => Managers.LogManager.OnInfo (obj.ToString()); 8 | public static void Notif(object obj) => Managers.LogManager.OnNotif(obj.ToString()); 9 | public static void Warn (object obj) => Managers.LogManager.OnWarn (obj.ToString()); 10 | public static void Error(object obj) => Managers.LogManager.OnError(obj.ToString()); 11 | public static void Fatal(object obj) => Managers.LogManager.OnFatal(obj.ToString()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /AstralCore.cs: -------------------------------------------------------------------------------- 1 | using MelonLoader; 2 | using System; 3 | 4 | [assembly: MelonInfo(typeof(Astrum.AstralCore.Loader), nameof(Astrum.AstralCore), "0.8.1", downloadLink: "github.com/Astrum-Project/" + nameof(Astrum.AstralCore))] 5 | [assembly: MelonGame("VRChat", "VRChat")] 6 | [assembly: MelonColor(ConsoleColor.DarkMagenta)] 7 | 8 | namespace Astrum.AstralCore 9 | { 10 | public class Loader : MelonMod 11 | { 12 | public override void OnApplicationStart() 13 | { 14 | Hooks.Hooks.Initialize(HarmonyInstance); 15 | 16 | Events.OnUIInit += Managers.LogManager.Initialize; 17 | } 18 | 19 | public override void OnUpdate() => Events.OnUpdate(); 20 | 21 | public override void OnSceneWasLoaded(int index, string _) 22 | { 23 | if (index == 1) Events.OnUIInit(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Utils/MemoryUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace Astrum.AstralCore.Utils 6 | { 7 | public static class MemoryUtils 8 | { 9 | const uint PAGE_EXECUTE_READWRITE = 0x40; 10 | 11 | public static void WriteBytes(IntPtr address, byte[] bytes) 12 | { 13 | IntPtr process = Process.GetCurrentProcess().Handle; 14 | VirtualProtectEx(process, address, (UIntPtr)bytes.Length, PAGE_EXECUTE_READWRITE, out uint oldProtect); 15 | Marshal.Copy(bytes, 0, address, bytes.Length); 16 | VirtualProtectEx(process, address, (UIntPtr)bytes.Length, oldProtect, out _); 17 | } 18 | 19 | [DllImport("kernel32.dll")] static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Hooks/OnPlayerJL.cs: -------------------------------------------------------------------------------- 1 | using Astrum.AstralCore.Types; 2 | using MelonLoader; 3 | using UnityEngine; 4 | 5 | namespace Astrum.AstralCore.Hooks 6 | { 7 | public static class OnPlayerJL 8 | { 9 | public static void Initialize(HarmonyLib.Harmony harmony) 10 | { 11 | harmony.Patch(Player.Type.GetMethod("OnNetworkReady"), null, typeof(OnPlayerJL).GetMethod(nameof(OnPlayerJL.OnPlayerJoined), Hooks.PrivateStatic).ToNewHarmonyMethod()); 12 | harmony.Patch(Player.Type.GetMethod("OnDestroy"), typeof(OnPlayerJL).GetMethod(nameof(OnPlayerJL.OnPlayerLeft), Hooks.PrivateStatic).ToNewHarmonyMethod()); 13 | } 14 | 15 | private static void OnPlayerJoined(MonoBehaviour __instance) => Events.OnPlayerJoined(new Player(__instance)); 16 | private static void OnPlayerLeft(MonoBehaviour __instance) => Events.OnPlayerLeft(new Player(__instance)); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Astral Astrum 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Hooks/Hooks.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Reflection; 4 | 5 | namespace Astrum.AstralCore.Hooks 6 | { 7 | public static class Hooks 8 | { 9 | public const BindingFlags PrivateStatic = BindingFlags.NonPublic | BindingFlags.Static; 10 | 11 | public static Assembly AssemblyCSharp; 12 | 13 | public static void Initialize(HarmonyLib.Harmony harmony) 14 | { 15 | Preload(); 16 | 17 | // in the future this should be changed to 18 | // reflectively initalizing everything inside 19 | // of the Hooks namespace, excluding self 20 | OnPlayerJL.Initialize(harmony); 21 | } 22 | 23 | // if this function fails, then Assembly-CSharp has not been loaded 24 | // i'm not sure why that happened to someone as this mod refereneces it 25 | // a simple fix would be to add something alphabetically before this mod 26 | // such as ActionMenuApi or AdvancedSafety 27 | private static void Preload() 28 | { 29 | AssemblyCSharp = AppDomain.CurrentDomain.GetAssemblies().First(f => f.GetName().Name == "Assembly-CSharp"); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Managers/SelectionManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Reflection; 4 | 5 | namespace Astrum.AstralCore.Managers 6 | { 7 | public static class SelectionManager 8 | { 9 | public static Type UserSelectionManager_T; 10 | public static PropertyInfo m_Instance; 11 | public static PropertyInfo m_APIUser0; 12 | public static PropertyInfo m_APIUser1; 13 | 14 | public static object Instance; 15 | 16 | static SelectionManager() 17 | { 18 | UserSelectionManager_T = Hooks.Hooks.AssemblyCSharp.GetTypes() 19 | .Where(t => t.BaseType == typeof(UnityEngine.MonoBehaviour)) 20 | .FirstOrDefault(t => t.Namespace == "VRC.DataModel"); 21 | 22 | m_Instance = UserSelectionManager_T.GetProperties().FirstOrDefault(x => x.PropertyType == UserSelectionManager_T); 23 | Instance = m_Instance.GetValue(null); 24 | 25 | PropertyInfo[] m_APIUsers = UserSelectionManager_T.GetProperties().Where(x => x.PropertyType == typeof(VRC.Core.APIUser)).ToArray(); 26 | m_APIUser0 = m_APIUsers[0]; // im not entirely sure is caching these is any more optimized 27 | m_APIUser1 = m_APIUsers[1]; 28 | } 29 | 30 | public static Types.Player TargetPlayer; 31 | public static VRC.Core.APIUser SelectedPlayer 32 | { 33 | get => TargetPlayer?.APIUser ?? InGameSelectedPlayer; 34 | } 35 | 36 | public static VRC.Core.APIUser InGameSelectedPlayer 37 | { 38 | // if you know a reliable way to get which of these isn't dead, 39 | // please make an issue or a pull request 40 | get => (VRC.Core.APIUser)(m_APIUser0.GetValue(Instance) ?? m_APIUser1.GetValue(Instance)); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Types/Player.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Reflection; 4 | using UnityEngine; 5 | using VRC.Core; 6 | using VRC.SDKBase; 7 | 8 | namespace Astrum.AstralCore.Types 9 | { 10 | public class Player 11 | { 12 | public static readonly Type Type; 13 | 14 | private static readonly PropertyInfo m_APIUser; 15 | private static readonly PropertyInfo m_VRCPlayerApi; 16 | 17 | static Player() 18 | { 19 | Type = Hooks.Hooks.AssemblyCSharp.GetExportedTypes() 20 | .Where(f => f.Namespace == "VRC") 21 | .OrderByDescending(f => f.GetProperties().Count(f1 => f1.PropertyType == typeof(bool))) 22 | .FirstOrDefault(); 23 | 24 | m_APIUser = Type.GetProperties().FirstOrDefault(f => f.PropertyType == typeof(APIUser)); 25 | m_VRCPlayerApi = Type.GetProperties().FirstOrDefault(f => f.PropertyType == typeof(VRCPlayerApi)); 26 | } 27 | 28 | public readonly MonoBehaviour Inner; 29 | public readonly APIUser APIUser; 30 | public readonly VRCPlayerApi VRCPlayerApi; 31 | 32 | public Player(MonoBehaviour inner) 33 | { 34 | Inner = inner; 35 | APIUser = m_APIUser?.GetValue(inner) as APIUser; 36 | VRCPlayerApi = m_VRCPlayerApi?.GetValue(inner) as VRCPlayerApi; 37 | } 38 | 39 | // someone should probably test these 40 | public override int GetHashCode() => this?.Inner.GetHashCode() ?? 0; 41 | public override bool Equals(object obj) => this?.Inner.Equals(obj) ?? obj is null; 42 | public static bool operator == (Player self, Player other) => ReferenceEquals(self?.Inner, other?.Inner); 43 | public static bool operator != (Player self, Player other) => !(self == other); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Utils/PatternScan.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace Astrum.AstralCore.Utils 6 | { 7 | // writen by dom1n1k and Patrick 8 | // converted to c# by atom0s [aka Wiccaan] 9 | // adapted by Astral Astrum 10 | // changes: 11 | // works on 64 bit 12 | // static instead of instance 13 | // todo: 14 | // cache result 15 | public static class PatternScanner 16 | { 17 | private static bool MaskCheck(byte[] mem, int nOffset, string pattern) 18 | { 19 | for (int x = 0; x < pattern.Length / 2; x++) 20 | { 21 | string bite = pattern.Substring(x * 2, 2); 22 | if (bite == "??") continue; 23 | if (byte.Parse(bite, System.Globalization.NumberStyles.HexNumber) != mem[nOffset + x]) return false; 24 | } 25 | 26 | return true; 27 | } 28 | 29 | public static IntPtr Scan(string module, string pattern, int offset = 0) 30 | { 31 | Process process = Process.GetCurrentProcess(); 32 | IntPtr baseAddr = GetModuleHandle(module); 33 | 34 | if (!GetModuleInformation(process.Handle, baseAddr, out MODULEINFO info, 24)) 35 | return IntPtr.Zero; 36 | 37 | int size = (int)info.SizeOfImage; 38 | 39 | pattern = pattern.Replace(" ", ""); 40 | 41 | try 42 | { 43 | if (baseAddr == IntPtr.Zero) return IntPtr.Zero; 44 | if (size == 0) return IntPtr.Zero; 45 | 46 | byte[] mem = new byte[size]; 47 | 48 | if (!ReadProcessMemory(process.Handle, baseAddr, mem, size, out int nBytesRead) || nBytesRead != size) 49 | return IntPtr.Zero; 50 | 51 | for (int x = 0; x < mem.Length; x++) 52 | if (MaskCheck(mem, x, pattern)) 53 | return new IntPtr(baseAddr.ToInt64() + x + offset); 54 | 55 | return IntPtr.Zero; 56 | } 57 | catch { return IntPtr.Zero; } 58 | } 59 | 60 | [DllImport("kernel32.dll", SetLastError = true)] private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out()] byte[] lpBuffer, int dwSize, out int lpNumberOfBytesRead); 61 | [DllImport("kernel32.dll", CharSet = CharSet.Auto)] public static extern IntPtr GetModuleHandle(string lpModuleName); 62 | [DllImport("psapi.dll", SetLastError = true)] static extern bool GetModuleInformation(IntPtr hProcess, IntPtr hModule, out MODULEINFO lpmodinfo, uint cb); 63 | [StructLayout(LayoutKind.Sequential)] 64 | public struct MODULEINFO 65 | { 66 | public IntPtr lpBaseOfDll; 67 | public uint SizeOfImage; 68 | public IntPtr EntryPoint; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Types/VRCNetworkingClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Reflection; 4 | 5 | namespace Astrum.AstralCore.Types 6 | { 7 | public static class VRCNetworkingClient 8 | { 9 | public static Type Type; 10 | public static object Instance; 11 | 12 | public static MethodInfo m_OpRaiseEvent; 13 | public static PropertyInfo m_Instance; 14 | 15 | static VRCNetworkingClient() 16 | { 17 | Type = Hooks.Hooks.AssemblyCSharp.GetExportedTypes() 18 | .Where(x => !x.IsGenericType) 19 | .Where(x => x.DeclaringType == null) 20 | .Where(x => x.BaseType?.BaseType == typeof(Il2CppSystem.Object)) 21 | .FirstOrDefault(x => x.Namespace == "VRC.Core"); 22 | 23 | if (Type is null) 24 | { 25 | Logger.Warn($"Failed to find {nameof(VRCNetworkingClient)}"); 26 | return; 27 | } else Logger.Debug($"{nameof(VRCNetworkingClient)}={Type}"); 28 | 29 | m_OpRaiseEvent = Type.GetMethods() 30 | .Where(x => x.DeclaringType == Type.BaseType) 31 | .Where(x => x.ReturnType == typeof(bool)) 32 | .FirstOrDefault(x => 33 | { 34 | ParameterInfo[] args = x.GetParameters(); 35 | return args.Length == 4 36 | && args[0].ParameterType == typeof(byte) 37 | && args[1].ParameterType == typeof(Il2CppSystem.Object) 38 | && !args[2].ParameterType.IsValueType 39 | && args[3].ParameterType.IsValueType; 40 | }); 41 | 42 | if (m_OpRaiseEvent is null) 43 | Logger.Warn($"Failed to find {nameof(VRCNetworkingClient)}::{nameof(OpRaiseEvent)}"); 44 | else Logger.Debug($"{nameof(VRCNetworkingClient)}::{nameof(OpRaiseEvent)}={m_OpRaiseEvent}"); 45 | 46 | m_Instance = Type.GetProperties() 47 | .FirstOrDefault(x => x.PropertyType == Type); 48 | 49 | if (m_Instance is null) 50 | Logger.Warn($"Failed to find {nameof(VRCNetworkingClient)}::{nameof(Instance)}"); 51 | else 52 | { 53 | Logger.Debug($"{nameof(VRCNetworkingClient)}::{nameof(Instance)}={m_Instance}"); 54 | 55 | Instance = m_Instance.GetValue(null); 56 | if (Instance is null) 57 | MelonLoader.MelonCoroutines.Start(GetInstance()); 58 | } 59 | } 60 | 61 | // instance is created right after OnApplicationStart 62 | private static System.Collections.IEnumerator GetInstance() 63 | { 64 | yield return null; 65 | Instance = m_Instance.GetValue(null); 66 | } 67 | 68 | // TODO: bake the MethodInfo to a delegate 69 | public static bool OpRaiseEvent(byte eventCode, object customEventContent, object raiseEventOptions, object sendOptions) => 70 | (bool)m_OpRaiseEvent.Invoke(Instance, new object[] { eventCode, customEventContent, raiseEventOptions, sendOptions }); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Managers/LogManager.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS0618 // Type or member is obsolete 2 | 3 | using MelonLoader; 4 | using System; 5 | using System.Collections.Generic; 6 | using UnityEngine; 7 | using UnityEngine.UI; 8 | using VRC.SDKBase; 9 | 10 | namespace Astrum.AstralCore.Managers 11 | { 12 | public static class LogManager 13 | { 14 | static LogManager() 15 | { 16 | if (MelonDebug.IsEnabled() || Environment.CommandLine.ToLower().Contains("--astral.debug")) 17 | { 18 | OnTrace += s => MelonLogger.Msg("\r[\x1b[35mAstral \x1b[0mTrace] \x1b[K" + s); 19 | OnDebug += s => MelonLogger.Msg("\r[\x1b[35mAstral \x1b[34mDebug\x1b[0m] \x1b[K" + s); 20 | 21 | Logger.Trace("Logger loaded"); 22 | } 23 | } 24 | 25 | private static Text log; 26 | private static readonly Queue lines = new Queue(); 27 | 28 | internal static void Initialize() 29 | { 30 | GameObject gameObject = new("AstralLog"); 31 | log = gameObject.AddComponent(); 32 | 33 | gameObject.transform.SetParent(GameObject.Find("UserInterface/UnscaledUI/HudContent_Old/Hud").transform, false); 34 | gameObject.transform.localPosition = new Vector3(15, 300); 35 | 36 | gameObject.GetComponent().sizeDelta = new Vector2(1000, 30); 37 | 38 | // raleway might look better here 39 | log.font = Resources.GetBuiltinResource("Arial.ttf"); 40 | log.horizontalOverflow = HorizontalWrapMode.Wrap; 41 | log.verticalOverflow = VerticalWrapMode.Overflow; 42 | log.alignment = TextAnchor.UpperLeft; 43 | log.fontStyle = FontStyle.Bold; 44 | log.supportRichText = true; 45 | log.fontSize = 30; 46 | 47 | OnNotif += s => MelonCoroutines.Start(DisplayOnScreen(s, 3)); 48 | } 49 | 50 | public static System.Collections.IEnumerator DisplayOnScreen(string message, float duration) 51 | { 52 | // this should sync us with the main thread 53 | // that way we won't have to lock lines whilst using it 54 | // unfortunately messages will be a frame late due to it 55 | yield return null; 56 | 57 | foreach (VRCPlayerApi player in VRCPlayerApi.AllPlayers) 58 | message = message.Replace(player.displayName, $"{player.displayName}"); 59 | 60 | lines.Enqueue(message); 61 | log.text = string.Join("\n", lines); 62 | yield return new WaitForSecondsRealtime(duration); 63 | lines.Dequeue(); 64 | log.text = string.Join("\n", lines); 65 | } 66 | 67 | public static Action OnTrace = new(_ => {}); 68 | public static Action OnDebug = new(_ => {}); 69 | public static Action OnInfo = new(s => MelonLogger.Msg("\r[\x1b[35mAstral \x1b[36mInfo \x1b[0m] \x1b[K" + s)); 70 | public static Action OnNotif = new(s => MelonLogger.Msg("\r[\x1b[35mAstral \x1b[36mNotif\x1b[0m] \x1b[K" + s)); 71 | public static Action OnWarn = new(s => MelonLogger.Msg("\r[\x1b[35mAstral \x1b[33mWarn \x1b[0m] \x1b[K" + s)); 72 | public static Action OnError = new(s => MelonLogger.Msg("\r[\x1b[35mAstral \x1b[31mError\x1b[0m] \x1b[K" + s)); 73 | public static Action OnFatal = new(s => MelonLogger.Msg("\r[\x1b[35mAstral \x1b[31mFatal\x1b[0m] \x1b[K" + s)); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /AstralCore.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {6FDB7F7D-1848-4C9B-8277-32672DF03DD7} 8 | Library 9 | Properties 10 | Astrum.AstralCore 11 | AstralCore 12 | v4.7.2 13 | preview 14 | 512 15 | true 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | OnOutputUpdated 36 | 37 | 38 | 39 | False 40 | C:\Program Files (x86)\Steam\steamapps\common\VRChat\MelonLoader\0Harmony.dll 41 | 42 | 43 | C:\Program Files (x86)\Steam\steamapps\common\VRChat\MelonLoader\Managed\Assembly-CSharp.dll 44 | 45 | 46 | C:\Program Files (x86)\Steam\steamapps\common\VRChat\MelonLoader\Managed\Il2Cppmscorlib.dll 47 | 48 | 49 | C:\Program Files (x86)\Steam\steamapps\common\VRChat\MelonLoader\MelonLoader.dll 50 | 51 | 52 | 53 | 54 | 55 | False 56 | C:\Program Files (x86)\Steam\steamapps\common\VRChat\MelonLoader\Managed\UnhollowerBaseLib.dll 57 | 58 | 59 | C:\Program Files (x86)\Steam\steamapps\common\VRChat\MelonLoader\Managed\UnhollowerRuntimeLib.dll 60 | 61 | 62 | False 63 | C:\Program Files (x86)\Steam\steamapps\common\VRChat\MelonLoader\Managed\UnityEngine.CoreModule.dll 64 | 65 | 66 | 67 | C:\Program Files (x86)\Steam\steamapps\common\VRChat\MelonLoader\Managed\UnityEngine.UI.dll 68 | 69 | 70 | C:\Program Files (x86)\Steam\steamapps\common\VRChat\MelonLoader\Managed\VRCCore-Standalone.dll 71 | 72 | 73 | C:\Program Files (x86)\Steam\steamapps\common\VRChat\MelonLoader\Managed\VRCSDKBase.dll 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | COPY "$(TargetPath)" "C:\Program Files (x86)\Steam\steamapps\common\VRChat\Mods\$(TargetFileName)" 95 | 96 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | KiraiLib.dll 2 | Build/ 3 | DebugBuild/ 4 | 5 | ## Ignore Visual Studio temporary files, build results, and 6 | ## files generated by popular Visual Studio add-ons. 7 | ## 8 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 9 | 10 | # User-specific files 11 | *.rsuser 12 | *.suo 13 | *.user 14 | *.userosscache 15 | *.sln.docstates 16 | 17 | # User-specific files (MonoDevelop/Xamarin Studio) 18 | *.userprefs 19 | 20 | # Build results 21 | [Dd]ebug/ 22 | [Dd]ebugPublic/ 23 | [Rr]elease/ 24 | [Rr]eleases/ 25 | x64/ 26 | x86/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUNIT 47 | *.VisualState.xml 48 | TestResult.xml 49 | 50 | # Build Results of an ATL Project 51 | [Dd]ebugPS/ 52 | [Rr]eleasePS/ 53 | dlldata.c 54 | 55 | # Benchmark Results 56 | BenchmarkDotNet.Artifacts/ 57 | 58 | # .NET Core 59 | project.lock.json 60 | project.fragment.lock.json 61 | artifacts/ 62 | 63 | # StyleCop 64 | StyleCopReport.xml 65 | 66 | # Files built by Visual Studio 67 | *_i.c 68 | *_p.c 69 | *_h.h 70 | *.ilk 71 | *.meta 72 | *.obj 73 | *.iobj 74 | *.pch 75 | *.pdb 76 | *.ipdb 77 | *.pgc 78 | *.pgd 79 | *.rsp 80 | *.sbr 81 | *.tlb 82 | *.tli 83 | *.tlh 84 | *.tmp 85 | *.tmp_proj 86 | *_wpftmp.csproj 87 | *.log 88 | *.vspscc 89 | *.vssscc 90 | .builds 91 | *.pidb 92 | *.svclog 93 | *.scc 94 | 95 | # Chutzpah Test files 96 | _Chutzpah* 97 | 98 | # Visual C++ cache files 99 | ipch/ 100 | *.aps 101 | *.ncb 102 | *.opendb 103 | *.opensdf 104 | *.sdf 105 | *.cachefile 106 | *.VC.db 107 | *.VC.VC.opendb 108 | 109 | # Visual Studio profiler 110 | *.psess 111 | *.vsp 112 | *.vspx 113 | *.sap 114 | 115 | # Visual Studio Trace Files 116 | *.e2e 117 | 118 | # TFS 2012 Local Workspace 119 | $tf/ 120 | 121 | # Guidance Automation Toolkit 122 | *.gpState 123 | 124 | # ReSharper is a .NET coding add-in 125 | _ReSharper*/ 126 | *.[Rr]e[Ss]harper 127 | *.DotSettings.user 128 | 129 | # JustCode is a .NET coding add-in 130 | .JustCode 131 | 132 | # TeamCity is a build add-in 133 | _TeamCity* 134 | 135 | # DotCover is a Code Coverage Tool 136 | *.dotCover 137 | 138 | # AxoCover is a Code Coverage Tool 139 | .axoCover/* 140 | !.axoCover/settings.json 141 | 142 | # Visual Studio code coverage results 143 | *.coverage 144 | *.coveragexml 145 | 146 | # NCrunch 147 | _NCrunch_* 148 | .*crunch*.local.xml 149 | nCrunchTemp_* 150 | 151 | # MightyMoose 152 | *.mm.* 153 | AutoTest.Net/ 154 | 155 | # Web workbench (sass) 156 | .sass-cache/ 157 | 158 | # Installshield output folder 159 | [Ee]xpress/ 160 | 161 | # DocProject is a documentation generator add-in 162 | DocProject/buildhelp/ 163 | DocProject/Help/*.HxT 164 | DocProject/Help/*.HxC 165 | DocProject/Help/*.hhc 166 | DocProject/Help/*.hhk 167 | DocProject/Help/*.hhp 168 | DocProject/Help/Html2 169 | DocProject/Help/html 170 | 171 | # Click-Once directory 172 | publish/ 173 | 174 | # Publish Web Output 175 | *.[Pp]ublish.xml 176 | *.azurePubxml 177 | # Note: Comment the next line if you want to checkin your web deploy settings, 178 | # but database connection strings (with potential passwords) will be unencrypted 179 | *.pubxml 180 | *.publishproj 181 | 182 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 183 | # checkin your Azure Web App publish settings, but sensitive information contained 184 | # in these scripts will be unencrypted 185 | PublishScripts/ 186 | 187 | # NuGet Packages 188 | *.nupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | 214 | # Visual Studio cache files 215 | # files ending in .cache can be ignored 216 | *.[Cc]ache 217 | # but keep track of directories ending in .cache 218 | !?*.[Cc]ache/ 219 | 220 | # Others 221 | ClientBin/ 222 | ~$* 223 | *~ 224 | *.dbmdl 225 | *.dbproj.schemaview 226 | *.jfm 227 | *.pfx 228 | *.publishsettings 229 | orleans.codegen.cs 230 | 231 | # Including strong name files can present a security risk 232 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 233 | #*.snk 234 | 235 | # Since there are multiple workflows, uncomment next line to ignore bower_components 236 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 237 | #bower_components/ 238 | 239 | # RIA/Silverlight projects 240 | Generated_Code/ 241 | 242 | # Backup & report files from converting an old project file 243 | # to a newer Visual Studio version. Backup files are not needed, 244 | # because we have git ;-) 245 | _UpgradeReport_Files/ 246 | Backup*/ 247 | UpgradeLog*.XML 248 | UpgradeLog*.htm 249 | ServiceFabricBackup/ 250 | *.rptproj.bak 251 | 252 | # SQL Server files 253 | *.mdf 254 | *.ldf 255 | *.ndf 256 | 257 | # Business Intelligence projects 258 | *.rdl.data 259 | *.bim.layout 260 | *.bim_*.settings 261 | *.rptproj.rsuser 262 | *- Backup*.rdl 263 | 264 | # Microsoft Fakes 265 | FakesAssemblies/ 266 | 267 | # GhostDoc plugin setting file 268 | *.GhostDoc.xml 269 | 270 | # Node.js Tools for Visual Studio 271 | .ntvs_analysis.dat 272 | node_modules/ 273 | 274 | # Visual Studio 6 build log 275 | *.plg 276 | 277 | # Visual Studio 6 workspace options file 278 | *.opt 279 | 280 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 281 | *.vbw 282 | 283 | # Visual Studio LightSwitch build output 284 | **/*.HTMLClient/GeneratedArtifacts 285 | **/*.DesktopClient/GeneratedArtifacts 286 | **/*.DesktopClient/ModelManifest.xml 287 | **/*.Server/GeneratedArtifacts 288 | **/*.Server/ModelManifest.xml 289 | _Pvt_Extensions 290 | 291 | # Paket dependency manager 292 | .paket/paket.exe 293 | paket-files/ 294 | 295 | # FAKE - F# Make 296 | .fake/ 297 | 298 | # JetBrains Rider 299 | .idea/ 300 | *.sln.iml 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | --------------------------------------------------------------------------------