727 lines
26 KiB
C#
727 lines
26 KiB
C#
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;
|
|
using static Dreamteck.Splines.SplineSampleModifier;
|
|
|
|
[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<FMOD.Studio.EventDescription> eventDescriptions = new List<EventDescription>();
|
|
public List<string> strings = new List<string>();
|
|
|
|
// 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<Beatmap>();
|
|
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<string, int>(), Modifiers.None);
|
|
|
|
LoggerInstance.Msg("Adding song to list: " + beatmapItem.Path);
|
|
|
|
// This whole part would be needed for AddSongList()
|
|
beatmapItem.Beatmap = ScriptableObject.CreateInstance<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<string, bool> expandedStates = new Dictionary<string, bool>();
|
|
|
|
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 Custom 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;
|
|
item.Song = new Song(beatmapName);
|
|
TextAsset asset = new TextAsset(beatmapContent);
|
|
asset.name = beatmapName;
|
|
item.BeatmapInfo = new BeatmapInfo(asset,difficulty);
|
|
item.Beatmap = ScriptableObject.CreateInstance<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<string, int>(), 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<Song> __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<string, BeatmapItem> songList = traverse.Field("_songDatabase").GetValue<Dictionary<string, BeatmapItem>>();
|
|
|
|
|
|
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);
|
|
|
|
|
|
}
|
|
|
|
[HarmonyPatch(typeof(ArcadeSongDatabase), "Awake")]
|
|
public class ArcadeSongDatabasePatch
|
|
{
|
|
public static void Postfix(ref ArcadeSongDatabase __instance)
|
|
{
|
|
var LoggerInstance = Core.GetLogger();
|
|
|
|
Traverse traverse = Traverse.Create(__instance);
|
|
BeatmapIndex beatmapIndex = traverse.Field("_beatmapIndex").GetValue<BeatmapIndex>();
|
|
Dictionary<string, BeatmapItem> songDatabase = traverse.Field("_songDatabase").GetValue<Dictionary<string, BeatmapItem>>();
|
|
List<BeatmapItem> songList = traverse.Field("_songList").GetValue<List<BeatmapItem>>();
|
|
|
|
string beatmapPath = "C:\\Program Files (x86)\\Steam\\steamapps\\common\\UNBEATABLE Demo\\SUnbeatable-Loader\\Songs\\Empty Diary (Custom)\\beatmap.dat";
|
|
|
|
//test song - Empty Diaryaaa
|
|
string beatmap = File.ReadAllText(beatmapPath);
|
|
|
|
string songName = "audio.mp3";
|
|
using (var songNameReader = new StringReader(beatmap.Substring(beatmap.IndexOf("Title:") + 6).Trim()))
|
|
{
|
|
//songName = songNameReader.ReadLine();
|
|
}
|
|
LoggerInstance.Msg(songName);
|
|
|
|
string difficulty = beatmap.Substring(beatmap.IndexOf("Version:") + 8 /* adding 8, the length of the string "Version:" */ , beatmap.IndexOf(" ", beatmap.IndexOf("Version:")) - (beatmap.IndexOf("Version:") + 8));
|
|
LoggerInstance.Msg(difficulty);
|
|
|
|
string path = songName+"/"+difficulty;
|
|
BeatmapIndex.Song mapSong = new Song(songName);
|
|
mapSong.stageScene = "TrainStationRhythm";
|
|
TextAsset asset = new TextAsset(beatmap);
|
|
BeatmapInfo info = new BeatmapInfo(asset,difficulty);
|
|
Beatmap map = ScriptableObject.CreateInstance<Beatmap>();
|
|
map.metadata.title = songName;
|
|
map.metadata.titleUnicode = songName;
|
|
map.metadata.artist = "Not You";
|
|
map.metadata.artistUnicode = "Not You";
|
|
map.metadata.tagData.Level = 10;
|
|
//map.metadata.tagData.SongLength = float.Parse(beatmap.Substring(beatmap.IndexOf("SongLength\":")+13,beatmap.IndexOf("}", beatmap.IndexOf("SongLength\":") + 13)));
|
|
|
|
BeatmapItem item = new BeatmapItem();
|
|
item.Path = path;
|
|
item.BeatmapInfo = info;
|
|
item.Beatmap = map;
|
|
item.Highscore = new HighScoreItem(path, 0, 0f, 0, cleared: false, new Dictionary<string, int>(), Modifiers.None);
|
|
item.Unlocked = true;
|
|
item.Song = mapSong;
|
|
LoggerInstance.Msg("about to parse beatmap");
|
|
BeatmapParserEngine engine = new BeatmapParserEngine();
|
|
engine.ReadBeatmap(info.text, ref map, BeatmapParserEngine.SectionTypes.Everything);
|
|
|
|
|
|
|
|
songList.Add(item);
|
|
songDatabase.TryAdd(songName, item);
|
|
LoggerInstance.Msg("added " + songName + " " + difficulty);
|
|
|
|
|
|
/*public string Path;
|
|
|
|
public BeatmapIndex.Song Song;
|
|
|
|
public BeatmapInfo BeatmapInfo;
|
|
|
|
public Beatmap Beatmap;
|
|
|
|
public HighScoreItem Highscore;
|
|
|
|
public bool Unlocked;
|
|
|
|
public override string ToString()
|
|
{
|
|
return Path;
|
|
}*/
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
} |