commit d1bad7e2e4875c620a49ca457d97b5a770488789 Author: Sunskimmer82 <92886026+Sunskimmer822@users.noreply.github.com> Date: Tue Apr 22 07:58:54 2025 -0500 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..54308a1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,135 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +.vs/ + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.svclog +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# Click-Once directory +publish/ + +# Publish Web Output +*.Publish.xml +*.pubxml +*.azurePubxml + +# NuGet Packages Directory +## TODO: If you have NuGet Package Restore enabled, uncomment the next line +packages/ +## TODO: If the tool you use requires repositories.config, also uncomment the next line +!packages/repositories.config + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +![Ss]tyle[Cc]op.targets +~$* +*~ +*.dbmdl +*.[Pp]ublish.xml + +*.publishsettings + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac desktop service store files +.DS_Store + +_NCrunch* diff --git a/Core.cs b/Core.cs new file mode 100644 index 0000000..ee48cc2 --- /dev/null +++ b/Core.cs @@ -0,0 +1,646 @@ +using MelonLoader; +using UnityEngine; +using FMODUnity; +using FMOD.Studio; +using HarmonyLib; +using Rhythm; +using static Rhythm.BeatmapIndex; +using Arcade.UI; +using System.Runtime.InteropServices; +using FMOD; +using static UnbeatableSongHack.TreeExplorer; +using Arcade.UI.SongSelect; +using static Arcade.UI.SongSelect.ArcadeSongDatabase; +using UnityEngine.UIElements; +using System.Xml.Linq; + +[assembly: MelonInfo(typeof(UnbeatableSongHack.Core), "SUnbeatable-Loader", "1.0.0", "Serena Sunskimmer82", null)] +[assembly: MelonGame("D-CELL GAMES", "UNBEATABLE [DEMO]")] + +namespace UnbeatableSongHack +{ + public class Core : MelonMod + { + + + public override void OnInitializeMelon() + { + LoggerInstance.Msg("Initialized Song Hack!"); + } + + public override void OnLateUpdate() + { + if (Input.GetKeyDown(KeyCode.N)) + { + // Stop all events + RuntimeManager.GetBus("bus:/").stopAllEvents(FMOD.Studio.STOP_MODE.ALLOWFADEOUT); + } + + if (Input.GetKeyDown(KeyCode.M)) + { + //FetchAllEvents(); + } + } + + public List eventDescriptions = new List(); + public List strings = new List(); + + // Get the events from the bank + // These can be used to play single audios in game through the tree menu + FMOD.Studio.EventDescription[] GetBankEvents(Bank bank) + { + LoggerInstance.Msg("\n> Getting Bank Events"); + bank.getEventList(out FMOD.Studio.EventDescription[] eventDescs); + foreach (FMOD.Studio.EventDescription eventDesc in eventDescs) + { + eventDesc.getPath(out string eventPath); + LoggerInstance.Msg(eventPath); + + eventDescriptions.Add(eventDesc); + } + return eventDescs; + } + + // Read all string events from the bank + void GetBankStrings(Bank bank) + { + LoggerInstance.Msg("\n> Getting Bank Strings"); + bank.getStringCount(out int stringCount); + LoggerInstance.Msg("String Count: " + stringCount); + + for (int i = 0; i < stringCount; i++) + { + bank.getStringInfo(i, out FMOD.GUID Id, out string stringPath); + LoggerInstance.Msg("String ID: " + Id); + LoggerInstance.Msg("String Path: " + stringPath); + LoggerInstance.Msg("---"); + + // Strings zur Liste hinzufügen + if (!string.IsNullOrEmpty(stringPath)) + { + strings.Add(stringPath); + } + } + } + + // Build the event tree from the event descriptions and strings + void FetchAllEvents() + { + // Listen leeren + eventDescriptions.Clear(); + strings.Clear(); + rootNode = new TreeNode("Root"); + + RuntimeManager.StudioSystem.getBankList(out Bank[] banks); + + foreach (Bank bank in banks) + { + // Get the name of the bank + bank.getPath(out string bankPath); + // Log the name of the bank + LoggerInstance.Msg("--- Bank Path: " + bankPath); + + // It's Master.strings! Read the strings from it! + if (bankPath.EndsWith("strings")) + { + GetBankStrings(bank); + } + + try + { + GetBankEvents(bank); + } + catch (System.Exception e) + { + LoggerInstance.Msg("Error fetching events: " + e.Message); + } + } + + BuildEventTree(out rootNode, eventDescriptions, strings); + } + + + // "Progessions" are some kind of class + public class CustomProgression: IProgression + { + public string stageScene = "TrainStationRhythm"; + public string filePath = "./none.txt"; + public string audioKey = "EMPTY DIARY"; + + public CustomProgression(string textFile) + { + this.filePath = textFile; + + // Look for an audio.mp3 in the same directory as the beatmap + // Might as well use the audioFilename property from the beatmap itself later + string directory = Path.GetDirectoryName(filePath); + + var audioPath = Path.Combine(directory, "audio.mp3"); + + // If an audio is found, set it to the audio path + var audioTitle = "EMPTY DIARY"; + if (File.Exists(audioPath)) + { + audioTitle = audioPath; + } + + this.audioKey = audioTitle; + this.stageScene = "TrainStationRhythm"; + } + + public string GetBeatmapPath() + { + // Placeholder + return "__CUSTOM/CUSTOMDIFF"; + } + public string GetSongName() + { + return audioKey; + } + + public string GetDifficulty() + { + // Placeholder + return "CUSTOMDIFF"; + } + + public void Finish(string sceneIndex) + { + LevelManager.LoadLevel("ScoreScreenArcadeMode"); + } + + public void Retry() + { + LevelManager.LoadLevel(stageScene); + } + + public void Back() + { + LevelManager.LoadLevel(JeffBezosController.arcadeMenuScene); + } + } + + void LoadBeatmapFromFile(string filePath="") + { + + if (filePath.Length==0) return; + + + CustomProgression customProgression = new CustomProgression(filePath); + + JeffBezosController.rhythmProgression = customProgression; + + LevelManager.LoadLevel(customProgression.stageScene); + + } + + // Detect if the beatmap is a custom one + // Since ParseBeatmap attempts to load a TextAsset (which we cant create) + // we have to patch the function and make it load from text contents instead. + [HarmonyPatch(typeof(BeatmapParser), "ParseBeatmap", new Type[] {})] + public class BeatmapParserPatch + { + public static bool Prefix(ref BeatmapParser __instance) + { + if (JeffBezosController.rhythmProgression.GetBeatmapPath().StartsWith("__CUSTOM")) + { + var progression = JeffBezosController.rhythmProgression as CustomProgression; + + __instance.beatmapIndex = BeatmapIndex.defaultIndex; + + var contents = File.ReadAllText(progression.filePath); + + BeatmapParserEngine beatmapParserEngine = new BeatmapParserEngine(); + var beatmap = ScriptableObject.CreateInstance(); + beatmapParserEngine.ReadBeatmap(contents, ref beatmap); + + __instance.beatmap = beatmap; + __instance.audioKey = progression.GetSongName(); + __instance.beatmapPath = progression.GetBeatmapPath(); + + return false; + } + return true; + } + } + + + // Patch to load beatmaps from file + // Since the game really wants to load from its own audio table, + // we need to patch this to load from a file instead + // That way we can make the game load any sound file (and in this case, + // the one from our custom level) + [HarmonyPatch(typeof(RhythmTracker), "PreloadFromTable")] + public class RhythmTrackerLoadPatch + { + public static bool Prefix(string key, ref RhythmTracker __instance) + { + if (key.Contains(".")) + { + if (File.Exists(key)) + { + __instance.PreloadFromFile(key); + return false; + } else + { + return true; + } + } + + return true; + } + } + + + void PlayFromKey(string name) + { + var arcadeBGMManger = ArcadeBGMManager.Instance; + var songList = ArcadeSongDatabase.Instance; + var beatmapIndex = BeatmapIndex.defaultIndex; + + + if (arcadeBGMManger != null && songList != null) + { + + + LoggerInstance.Msg("Adding key: " + name); + + var beatmapItem = new BeatmapItem(); + + beatmapItem.Path = "__CUSTOM" + name + "/Beginner"; + var key = beatmapItem.Path; + + + + beatmapItem.Song = new Song(name); + beatmapItem.Song.stageScene = "TrainStationRhythm"; + + beatmapItem.Unlocked = true; + + + + beatmapItem.BeatmapInfo = new BeatmapInfo(null, "Beginner"); + + + beatmapItem.Highscore = new HighScoreItem(key, 0, 0f, 0, cleared: false, new Dictionary(), Modifiers.None); + + LoggerInstance.Msg("Adding song to list: " + beatmapItem.Path); + + // This whole part would be needed for AddSongList() + beatmapItem.Beatmap = new Beatmap(); + beatmapItem.Beatmap.metadata.title = "Custom " + name; + beatmapItem.Beatmap.metadata.titleUnicode = "Custom " + name; + beatmapItem.Beatmap.metadata.artist = "Not You"; + beatmapItem.Beatmap.metadata.artistUnicode = "Not You"; + beatmapItem.Beatmap.metadata.tagData.Level = 10; + + + // This was a test and is not needed + //AddSongToArcadeList(songList,beatmapItem); + + LoggerInstance.Msg("Added Key: " + key); + + + arcadeBGMManger.PlaySongPreview(beatmapItem); + + + } + + } + + + + public static string lastEventPath = ""; + + public TreeNode rootNode = new TreeNode("Root"); + public Dictionary expandedStates = new Dictionary(); + + public Rect windowRect = new Rect(20, 20, 400, 600); + public Vector2 scrollPosition = new Vector2(0, 0); + + public string textInput = ""; + + public override void OnGUI() + { + windowRect = GUI.Window(0, windowRect, DoWindow, "Song Hack"); + + if (windowRect.width == 0) + { + if (GUI.Button(new Rect(10, 10, 32, 32), "O")) + { + windowRect = new Rect(20, 20, 400, 600); + } + } + } + + + // Draw MOD UI + void DoWindow(int windowId) + { + GUIStyle compactButtonStyle = new GUIStyle(GUI.skin.button); + compactButtonStyle.alignment = TextAnchor.MiddleLeft; + compactButtonStyle.fontSize = 14; + + GUIStyle compactEnabledButtonStyle = new GUIStyle(compactButtonStyle); + compactEnabledButtonStyle.normal.textColor = Color.green; + + GUIStyle folderStyle = new GUIStyle(GUI.skin.button); + folderStyle.alignment = TextAnchor.MiddleLeft; + folderStyle.fontSize = 14; + folderStyle.normal.textColor = Color.yellow; + + GUIStyle leafStyle = new GUIStyle(GUI.skin.button); + leafStyle.alignment = TextAnchor.MiddleLeft; + leafStyle.fontSize = 14; + leafStyle.normal.textColor = Color.white; + + GUIStyle stringStyle = new GUIStyle(GUI.skin.button); + stringStyle.alignment = TextAnchor.MiddleLeft; + stringStyle.fontSize = 14; + stringStyle.normal.textColor = Color.cyan; + + GUIStyle playableStringStyle = new GUIStyle(GUI.skin.button); + playableStringStyle.alignment = TextAnchor.MiddleLeft; + playableStringStyle.fontSize = 14; + playableStringStyle.normal.textColor = Color.green; + + GUI.DragWindow(new Rect(0, 0, 10000, 20)); + + // Create button to stop all events + if (GUI.Button(new Rect(10, 25, 110, 30), "Stop All Events")) + { + RuntimeManager.GetBus("bus:/").stopAllEvents(FMOD.Studio.STOP_MODE.ALLOWFADEOUT); + + } + + // Create button to get all events + if (GUI.Button(new Rect(120, 25, 110, 30), "Get All Events")) + { + FetchAllEvents(); + LoggerInstance.Msg($"Fetched {eventDescriptions.Count} events and {strings.Count} strings."); + } + + // Play an event from the text input + if (GUI.Button(new Rect(230, 25, 110, 30), "Sound from Text")) + { + if (!string.IsNullOrEmpty(textInput)) + { + RuntimeManager.PlayOneShot(textInput); + lastEventPath = textInput; + LoggerInstance.Msg("Playing: " + textInput); + } + } + + if (GUI.Button(new Rect(230, 55, 110, 25), "Sound from Key")) + { + if (!string.IsNullOrEmpty(textInput)) + { + PlayFromKey(textInput); + lastEventPath = "Key: " + textInput; + LoggerInstance.Msg("Playing Key: " + textInput); + } + } + + if (GUI.Button(new Rect(130, 55, 100, 25), "Play File Level")) + { + if (!string.IsNullOrEmpty(textInput)) + { + LoadBeatmapFromFile(textInput); + } else + { + LoadBeatmapFromFile(); + } + } + + if (GUI.Button(new Rect(10,120,100,25), "Add Empty Songs To Arcade")) + { + var db = Arcade.UI.SongSelect.ArcadeSongDatabase.Instance; + + string customSongDir = $"{Application.dataPath.Substring(0, Application.dataPath.LastIndexOf('/'))}/SUnbeatable-Loader/Songs/"; + if (!Directory.Exists(customSongDir)) Directory.CreateDirectory(customSongDir); + LoggerInstance.Msg($"SUnbeatable-Loader Song Directory: {customSongDir}"); + + string[] dirs = Directory.GetDirectories(customSongDir); + foreach (var dir in dirs) + { + string songDir = Path.GetFileNameWithoutExtension(dir); + LoggerInstance.Msg($"{songDir}"); + + + //new demo maps are by default stored as .dat files + string[] songFiles = Directory.GetFiles(customSongDir + songDir, "*.dat"); + foreach (var songFile in songFiles) + { + string beatmapName = Path.GetFileNameWithoutExtension(songFile); + string beatmapContent = File.ReadAllText(songFile); + string difficulty = beatmapContent.Substring(beatmapContent.IndexOf("Version:")+8 /* adding 8, the length of the string "Version:" */ , beatmapContent.IndexOf(" ", beatmapContent.IndexOf("Version:"))-(beatmapContent.IndexOf("Version:")+8)); + LoggerInstance.Msg($"{beatmapName} has difficulty {difficulty}"); + + BeatmapItem item = new BeatmapItem(); + item.Path = "__CUSTOM" + songFile+"/"+difficulty.ToUpper(); + item.Song = new Song(beatmapName); + TextAsset asset = new TextAsset(beatmapContent); + asset.name = beatmapName; + item.BeatmapInfo = new BeatmapInfo(asset,difficulty); + item.Beatmap = new Beatmap(); + item.Beatmap.name = beatmapName; + item.Beatmap.metadata.title = beatmapName; + item.Beatmap.metadata.titleUnicode = beatmapName; + item.Beatmap.metadata.artist = "ARTIST"; + item.Beatmap.metadata.artistUnicode = "ARTIST"; + item.Beatmap.metadata.tagData.Level = 10; + item.Beatmap.metadata.tagData.SongLength = 100; + AddSongToArcadeList(db, item); + LoggerInstance.Msg("adding beatmap " + beatmapName + " at " + songDir); + + + } + + + } + + + + + } + + + if (GUI.Button(new Rect(110, 120, 100, 25), "Add To Arcade")) + { + if (!string.IsNullOrEmpty(textInput)) + { + CustomProgression progression = new CustomProgression(textInput); + + var beatmapItem = new BeatmapItem(); + + beatmapItem.Path = "__CUSTOM" + progression.GetSongName() + "/Beginner"; + var key = beatmapItem.Path; + + + + beatmapItem.Song = /*new Song(progression.GetSongName().Substring(progression.GetSongName().LastIndexOf("/")+1,progression.GetSongName().LastIndexOf(".")))*/null; + beatmapItem.Song.stageScene = "TrainStationRhythm"; + + beatmapItem.Unlocked = true; + + + + beatmapItem.BeatmapInfo = new BeatmapInfo(null, "Beginner"); + + + beatmapItem.Highscore = new HighScoreItem(key, 0, 0f, 0, cleared: false, new Dictionary(), Modifiers.None); + + LoggerInstance.Msg("Adding song to list: " + beatmapItem.Path); + + beatmapItem.Beatmap = new Beatmap(); + + beatmapItem.Beatmap.metadata.title = "Custom " + progression.GetSongName(); + beatmapItem.Beatmap.metadata.titleUnicode = "Custom " + progression.GetSongName(); + beatmapItem.Beatmap.metadata.artist = "Not You"; + beatmapItem.Beatmap.metadata.artistUnicode = "Not You"; + beatmapItem.Beatmap.metadata.tagData.Level = 10; + + + var db = Arcade.UI.SongSelect.ArcadeSongDatabase.Instance; + AddSongToArcadeList(db, beatmapItem); + } + } + + + if (GUI.Button(new Rect(340, 25, 50, 30), "X")) + { + windowRect = new Rect(-100, -100, 0, 0); + } + + textInput = GUI.TextField(new Rect(10, 80, 360, 25), textInput); + + + + int totalHeight = CalculateTreeHeight(rootNode); + + scrollPosition = GUI.BeginScrollView( + new Rect(0, 180, 400, 440), + scrollPosition, + new Rect(0, 0, 380, totalHeight) + ); + + int yPos = 0; + DrawTreeNode(rootNode, 0, ref yPos, folderStyle, leafStyle, stringStyle, playableStringStyle); + + GUI.EndScrollView(); + } + + // Let other classes access the logger + public static MelonLogger.Instance GetLogger() + { + MelonBase core = Core.FindMelon("SUnbeatable-Loader", "Serena Sunskimmer82"); + return core.LoggerInstance; + } + + // Patch the song function to return all (also hidden) songs, + // so we can access hidden beatmaps + [HarmonyPatch(typeof(BeatmapIndex), "GetVisibleSongs")] + public class BeatmapIndexPatch + { + public static bool Prefix(ref BeatmapIndex __instance, ref List __result) + { + __result = __instance.GetAllSongs(); + + return false; + } + } + + + [HarmonyPatch(typeof(RhythmTracker), "HandleCreateProgrammerSound", new Type[] { typeof(EventInstance), typeof(IntPtr) })] + public static class RhythmTrackerPatch + { + + public static bool Prefix(EventInstance instance, IntPtr parameterPtr) + { + var LoggerInstance = Core.GetLogger(); + + //LoggerInstance.Msg("HandleCreateProgrammerSound called"); + + instance.getUserData(out var h_userdata); + PlayInfo h_playInfo = GCHandle.FromIntPtr(h_userdata).Target as PlayInfo; + + if (h_playInfo.source == PlaySource.FromTable) + { + string key = Marshal.PtrToStringUni(h_playInfo.key); + + // Log the key of the sound being played + // Useful since we can't find the sound name otherwise + // Was used to match the names to the unnamed soundtrack files + LoggerInstance.Msg("Now playing: " + key); + + //SOUND_INFO h_info; + //RESULT h_soundInfo = RuntimeManager.StudioSystem.getSoundInfo(key, out h_info); + + //LoggerInstance.Msg("SoundInfo: " + (h_info.name)); + + + + + } + + //instance.getVolume(out float volume); + //LoggerInstance.Msg("Volume: " + volume.ToString()); + + return true; + } + } + + + + + // Doesn't really work, but it sometimes logs when something is played + [HarmonyPatch(typeof(FMODUnity.RuntimeManager), "PlayOneShot", new Type[] { typeof(string), typeof(Vector3) })] + public class RuntimeManagerPatch + { + public static bool Prefix(string path) + { + var LoggerInstance = Core.GetLogger(); + + LoggerInstance.Msg("[Patch] Playing: " + path); + + return true; + } + } + + + + // Function to add arbitrary beatmap songs into the arcade list + // Might be useful for some custom beatmaps, although some info is fetched from + // TextAssets that we cannot create/access through mods. + // It may be a mess. + public static void AddSongToArcadeList(ArcadeSongDatabase instance, ArcadeSongDatabase.BeatmapItem item) + { + var LoggerInstance = Core.GetLogger(); + + string key = item.Path; + + item.Unlocked = true; + + Traverse traverse = Traverse.Create(instance); + Dictionary songList = traverse.Field("_songDatabase").GetValue>(); + + + LoggerInstance.Msg("trying to add " + key); + var success = songList.TryAdd(key, item); + LoggerInstance.Msg(success); + traverse.Field("_songDatabase").SetValue(songList); + + instance.RefreshSongList(); + + LoggerInstance.Msg("Adding song to list: " + item.Path); + + + } + + + + + } + + +} \ No newline at end of file diff --git a/FMODInstances.cs b/FMODInstances.cs new file mode 100644 index 0000000..39ddac3 --- /dev/null +++ b/FMODInstances.cs @@ -0,0 +1,105 @@ +using AOT; +using FMOD.Studio; +using FMOD; +using FMODUnity; +using Rhythm; +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using UnityMainThreadDispatcher; +using System.Collections; +using UnityEngine; + +namespace UnbeatableSongHack +{ + // This is unused, it's only a reference now. + internal class FMODInstances + { + [MonoPInvokeCallback(typeof(EVENT_CALLBACK))] + public static RESULT MusicEventCallback(EVENT_CALLBACK_TYPE type, IntPtr @event, IntPtr parameterPtr) + { + return type switch + { + EVENT_CALLBACK_TYPE.CREATE_PROGRAMMER_SOUND => HandleCreateProgrammerSound(new EventInstance(@event), parameterPtr), + EVENT_CALLBACK_TYPE.DESTROY_PROGRAMMER_SOUND => HandleDestroyProgrammerSound(parameterPtr), + EVENT_CALLBACK_TYPE.DESTROYED => HandleDestroyed(new EventInstance(@event)), + _ => RESULT.OK, + }; + } + + + public static RESULT HandleCreateProgrammerSound(EventInstance instance, IntPtr parameterPtr) + { + instance.getUserData(out var userdata); + PlayInfo playInfo = GCHandle.FromIntPtr(userdata).Target as PlayInfo; + MODE mODE = MODE.LOOP_NORMAL | MODE.CREATECOMPRESSEDSAMPLE | MODE.NONBLOCKING; + PROGRAMMER_SOUND_PROPERTIES properties = GetProgrammerSoundProperties(parameterPtr); + + switch (playInfo.source) + { + case PlaySource.FromTable: + { + string key = Marshal.PtrToStringUni(playInfo.key); + + SOUND_INFO info; + RESULT soundInfo = RuntimeManager.StudioSystem.getSoundInfo(key, out info); + if (soundInfo != 0) + { + return soundInfo; + } + Sound sound2; + RESULT rESULT2 = RuntimeManager.CoreSystem.createSound(info.name_or_data, mODE | info.mode, ref info.exinfo, out sound2); + if (rESULT2 == RESULT.OK) + { + properties.sound = sound2.handle; + properties.subsoundIndex = info.subsoundindex; + Marshal.StructureToPtr(properties, parameterPtr, fDeleteOld: false); + Core.GetLogger().Msg("OK Sound"); + break; + } + return rESULT2; + } + case PlaySource.FromFile: + { + string name = Marshal.PtrToStringUni(playInfo.key); + Sound sound; + RESULT rESULT = RuntimeManager.CoreSystem.createSound(name, mODE, out sound); + if (rESULT == RESULT.OK) + { + properties.sound = sound.handle; + properties.subsoundIndex = -1; + Marshal.StructureToPtr(properties, parameterPtr, fDeleteOld: false); + break; + } + return rESULT; + } + } + + return RESULT.OK; + } + + + + public static RESULT HandleDestroyProgrammerSound(IntPtr parameterPtr) + { + new Sound(GetProgrammerSoundProperties(parameterPtr).sound).release(); + return RESULT.OK; + } + + public static RESULT HandleDestroyed(EventInstance instance) + { + instance.getUserData(out var userdata); + Marshal.FreeHGlobal((GCHandle.FromIntPtr(userdata).Target as PlayInfo).key); + GCHandle.FromIntPtr(userdata).Free(); + return RESULT.OK; + } + + public static PROGRAMMER_SOUND_PROPERTIES GetProgrammerSoundProperties(IntPtr ptr) + { + return Marshal.PtrToStructure(ptr); + } + + + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..5232274 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# The "Unbeatable Song Hack" + +Most likely the first mod menu for the Unbeatable DEMO. + +To use, download MelonLoader ( https://melonwiki.xyz/ ) and put a .dll of this mod into the Mods folder. A GUI should pop up. + +### Developing this + +If you want to work on this, you should most likely replace all the `` in `UnbeatableSongHack.csproj` with your paths to the game, as well as the `` at the bottom of that file. diff --git a/TreeExplorer.cs b/TreeExplorer.cs new file mode 100644 index 0000000..c442eb7 --- /dev/null +++ b/TreeExplorer.cs @@ -0,0 +1,225 @@ +using FMOD.Studio; +using FMODUnity; +using System; +using System.Collections.Generic; +using System.Text; +using UnityEngine; +using static UnbeatableSongHack.Core; + +namespace UnbeatableSongHack +{ + public class TreeExplorer + { + + // This handles drawing the explorer that appears when clicking "Get All Events." + // It creates a tree structure of all events and strings in the game. + // It also handles the selection of events and strings, and plays them when selected. + + + public class TreeNode + { + public string Name { get; set; } + public string FullPath { get; set; } + public bool IsLeaf { get; set; } + public bool IsExpanded { get; set; } + public Dictionary Children { get; set; } + public bool IsString { get; set; } + public bool IsPlayable { get; set; } + + public TreeNode(string name, string fullPath = "", bool isLeaf = false, bool isString = false, bool isPlayable = false) + { + Name = name; + FullPath = fullPath; + IsLeaf = isLeaf; + IsExpanded = false; + Children = new Dictionary(); + IsString = isString; + IsPlayable = isPlayable; + } + } + + + public static void AddPathToTree(string path, bool isString, bool isPlayable, TreeNode root) + { + string[] parts; + string prefix = ""; + + if (path.StartsWith("event:/")) + { + prefix = "event:/"; + parts = path.Substring(7).Split('/'); + } + else if (path.StartsWith("snapshot:/")) + { + prefix = "snapshot:/"; + parts = path.Substring(10).Split('/'); + } + else + { + parts = path.Split('/'); + if (parts.Length > 0 && parts[0].Contains(":")) + { + prefix = parts[0] + "/"; + parts = parts.Skip(1).ToArray(); + } + } + + string currentPath = prefix; + TreeNode currentNode = root; + + if (!string.IsNullOrEmpty(prefix)) + { + if (!currentNode.Children.ContainsKey(prefix)) + { + currentNode.Children[prefix] = new TreeNode(prefix); + } + currentNode = currentNode.Children[prefix]; + } + + for (int i = 0; i < parts.Length; i++) + { + if (string.IsNullOrEmpty(parts[i])) continue; + + currentPath += (i > 0 ? "/" : "") + parts[i]; + + bool isLeaf = (i == parts.Length - 1); + + if (!currentNode.Children.ContainsKey(parts[i])) + { + currentNode.Children[parts[i]] = new TreeNode(parts[i], currentPath, isLeaf, isString && isLeaf, isPlayable && isLeaf); + } + else if (isLeaf) + { + currentNode.Children[parts[i]].IsLeaf = true; + currentNode.Children[parts[i]].FullPath = currentPath; + if (isString) + { + currentNode.Children[parts[i]].IsString = true; + if (isPlayable) + { + currentNode.Children[parts[i]].IsPlayable = true; + } + } + } + + currentNode = currentNode.Children[parts[i]]; + } + } + + public static void BuildEventTree(out TreeNode rootNode, List eventDescriptions, List strings) + { + rootNode = new TreeNode("Root"); + + foreach (var eventDesc in eventDescriptions) + { + eventDesc.getPath(out string eventPath); + + AddPathToTree(eventPath, false, false, rootNode); + } + + foreach (var stringPath in strings) + { + bool isPlayable = stringPath.StartsWith("event:/"); + + AddPathToTree(stringPath, true, isPlayable, rootNode); + } + } + + public static int CalculateTreeHeight(TreeNode node, int depth = 0) + { + int height = 0; + + if (depth > 0 || node.Name != "Root") + { + height += 25; + } + + if (node.IsExpanded || node.Name == "Root") + { + foreach (var child in node.Children.Values) + { + height += CalculateTreeHeight(child, depth + 1); + } + } + + return height; + } + + public static void DrawTreeNode(TreeNode node, int depth, ref int yPos, GUIStyle folderStyle, GUIStyle leafStyle, + GUIStyle stringStyle, GUIStyle playableStringStyle) + { + var LoggerInstance = GetLogger(); + + int indentation = depth * 20; + int buttonWidth = 360 - indentation; + + if (node.Name != "Root") + { + string displayName = node.Name; + string prefix = node.IsLeaf ? " " : (node.IsExpanded ? "▼ " : "► "); + + GUIStyle styleToUse; + if (!node.IsLeaf) + { + styleToUse = folderStyle; + } + else if (node.IsString) + { + if (node.IsPlayable) + { + styleToUse = playableStringStyle; + } + else + { + styleToUse = stringStyle; + } + } + else + { + styleToUse = leafStyle; + } + + if (GUI.Button(new Rect(10 + indentation, yPos, buttonWidth, 20), prefix + displayName, styleToUse)) + { + if (node.IsLeaf) + { + if (node.IsString) + { + if (node.IsPlayable) + { + RuntimeManager.PlayOneShot(node.FullPath); + lastEventPath = node.FullPath + " (String-Event)"; + LoggerInstance.Msg("Playing string-event: " + node.FullPath); + } + else + { + lastEventPath = $"String: {node.FullPath}"; + LoggerInstance.Msg($"Selected string: {node.FullPath}"); + } + } + else + { + RuntimeManager.PlayOneShot(node.FullPath); + lastEventPath = node.FullPath; + LoggerInstance.Msg("Playing: " + node.FullPath); + } + } + else + { + node.IsExpanded = !node.IsExpanded; + } + } + + yPos += 25; + } + + if (node.IsExpanded || node.Name == "Root") + { + foreach (var child in node.Children.Values) + { + DrawTreeNode(child, depth + 1, ref yPos, folderStyle, leafStyle, stringStyle, playableStringStyle); + } + } + } + } +} diff --git a/UnbeatableSongHack.csproj b/UnbeatableSongHack.csproj new file mode 100644 index 0000000..58164a6 --- /dev/null +++ b/UnbeatableSongHack.csproj @@ -0,0 +1,515 @@ + + + netstandard2.1 + enable + disable + UnbeatableSongHack + default + false + 1.0.0.0 + 1.0.0.0 + en-US + UnbeatableSongHack + latest + enable + + + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\AllIn1VfxAssmebly.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\AllIn1VfxDemoScriptAssemblies.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\AmplifyShaderEditor.Samples.BuiltIn.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Antlr4.Runtime.Standard.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Assembly-CSharp-firstpass.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Assembly-CSharp.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Cinemachine.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Coffee.UnmaskForUGUI.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\CommandsInAnAssemblyDefinition.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\CsvHelper.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\DOTween.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Dreamteck.Splines.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Dreamteck.Utilities.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\FMODUnity.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\FMODUnityResonance.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Google.Protobuf.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Lattice.Runtime.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Microsoft.CSharp.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\MPUIKit.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Newtonsoft.Json.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\PlayMaker.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Rewired_Core.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Rewired_Windows.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Sirenix.OdinInspector.Attributes.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Sirenix.OdinInspector.Modules.UnityLocalization.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Sirenix.Serialization.Config.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Sirenix.Serialization.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Sirenix.Utilities.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UIEffect.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UModelerCommon.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Addressables.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.AI.Navigation.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Animation.Rigging.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Animation.Rigging.DocCodeExamples.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Burst.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Burst.Unsafe.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Collections.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Collections.LowLevel.ILSupport.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.InternalAPIEngineBridge.013.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Localization.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Mathematics.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.MemoryProfiler.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Postprocessing.Runtime.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.ProBuilder.Csg.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.ProBuilder.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.ProBuilder.KdTree.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.ProBuilder.Poly2Tri.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.ProBuilder.Stl.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Profiling.Core.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Recorder.Base.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Recorder.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.RenderPipelines.Core.Runtime.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.RenderPipelines.Core.ShaderLibrary.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.ResourceManager.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.ScriptableBuildPipeline.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Services.Core.Analytics.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Services.Core.Configuration.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Services.Core.Device.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Services.Core.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Services.Core.Environments.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Services.Core.Environments.Internal.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Services.Core.Internal.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Services.Core.Networking.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Services.Core.Registration.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Services.Core.Scheduler.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Services.Core.Telemetry.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Services.Core.Threading.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Splines.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.TerrainTools.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.TextMeshPro.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\Unity.Timeline.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.AccessibilityModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.AIModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.AndroidJNIModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.AnimationModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.ARModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.AssetBundleModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.AudioModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.ClothModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.ClusterInputModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.ClusterRendererModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.ContentLoadModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.CoreModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.CrashReportingModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.DirectorModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.DSPGraphModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.GameCenterModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.GIModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.GridModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.HotReloadModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.ImageConversionModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.IMGUIModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.InputLegacyModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.InputModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.JSONSerializeModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.LocalizationModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.NVIDIAModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.ParticleSystemModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.PerformanceReportingModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.Physics2DModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.PhysicsModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.ProfilerModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.PropertiesModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.ScreenCaptureModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.SharedInternalsModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.SpatialTracking.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.SpriteMaskModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.SpriteShapeModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.StreamingModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.SubstanceModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.SubsystemsModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.TerrainModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.TerrainPhysicsModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.TextCoreFontEngineModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.TextCoreTextEngineModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.TextRenderingModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.TilemapModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.TLSModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.UI.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.UIElementsModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.UIModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.UmbraModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.UnityAnalyticsCommonModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.UnityAnalyticsModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.UnityConnectModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.UnityCurlModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.UnityTestProtocolModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.UnityWebRequestAssetBundleModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.UnityWebRequestAudioModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.UnityWebRequestModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.UnityWebRequestTextureModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.UnityWebRequestWWWModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.VehiclesModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.VFXModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.VideoModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.VirtualTexturingModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.VRModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.WindModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.XR.LegacyInputHelpers.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityEngine.XRModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\UnityMainThreadDispatcher.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\VisualDesignCafe.Memory.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\VisualDesignCafe.Nature.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\VisualDesignCafe.Packages.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\VisualDesignCafe.Pooling.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\VisualDesignCafe.Rendering.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\VisualDesignCafe.Rendering.Instancing.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\VisualDesignCafe.Rendering.Nature.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\VisualDesignCafe.ShaderX.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\VisualDesignCafe.Threading.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\XNode.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\XNodeOdin.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\YarnSpinner.Compiler.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\YarnSpinner.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\UNBEATABLE [DEMO]_Data\Managed\YarnSpinner.Unity.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\MelonLoader\net35\MelonLoader.dll + + + C:\Program Files (x86)\Steam\steamapps\common\UNBEATABLE Demo\MelonLoader\net35\0Harmony.dll + + + + + + True + false + + + + + + + + + + + + \ No newline at end of file diff --git a/UnbeatableSongHack.sln b/UnbeatableSongHack.sln new file mode 100644 index 0000000..76a8324 --- /dev/null +++ b/UnbeatableSongHack.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.13.35931.197 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnbeatableSongHack", "UnbeatableSongHack.csproj", "{19A78656-8E40-4FE8-BF23-84AE0B9DCD21}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {19A78656-8E40-4FE8-BF23-84AE0B9DCD21}.Debug|Any CPU.ActiveCfg = Release|Any CPU + {19A78656-8E40-4FE8-BF23-84AE0B9DCD21}.Debug|Any CPU.Build.0 = Release|Any CPU + {19A78656-8E40-4FE8-BF23-84AE0B9DCD21}.Release|Any CPU.ActiveCfg = Release|Any CPU + {19A78656-8E40-4FE8-BF23-84AE0B9DCD21}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A75DFCC8-63F2-435A-9200-4741A545A241} + EndGlobalSection +EndGlobal