From 25b558cdb963b12c5bdd2535d2b7d8dcef898a1d Mon Sep 17 00:00:00 2001 From: goaaats Date: Mon, 7 Feb 2022 13:11:27 +0100 Subject: [PATCH 1/5] Generate deterministic UIDs for official songs + TJA, DLC compatibility --- TakoTako/MurmurHash2.cs | 85 +++++++++++++++++++++++++++++++ TakoTako/MusicPatch.cs | 110 ++++++++-------------------------------- TakoTako/Plugin.cs | 9 +--- 3 files changed, 107 insertions(+), 97 deletions(-) create mode 100644 TakoTako/MurmurHash2.cs diff --git a/TakoTako/MurmurHash2.cs b/TakoTako/MurmurHash2.cs new file mode 100644 index 0000000..b11e7e3 --- /dev/null +++ b/TakoTako/MurmurHash2.cs @@ -0,0 +1,85 @@ +using System.Text; + +// MIT License +// +// Copyright (c) 2017 Jitbit, 2022 TaikoMods contributors +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +namespace TaikoMods; + +public class MurmurHash2 +{ + public static uint Hash(string data) + { + return Hash(Encoding.UTF8.GetBytes(data)); + } + + public static uint Hash(byte[] data) + { + return Hash(data, 0xc58f1a7a); + } + + private const uint m = 0x5bd1e995; + private const int r = 24; + + public static uint Hash(byte[] data, uint seed) + { + var length = data.Length; + if (length == 0) + return 0; + var h = seed ^ (uint)length; + var currentIndex = 0; + while (length >= 4) + { + var k = (uint)(data[currentIndex++] | (data[currentIndex++] << 8) | (data[currentIndex++] << 16) | + (data[currentIndex++] << 24)); + k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k; + length -= 4; + } + + switch (length) + { + case 3: + h ^= (ushort)(data[currentIndex++] | (data[currentIndex++] << 8)); + h ^= (uint)(data[currentIndex] << 16); + h *= m; + break; + case 2: + h ^= (ushort)(data[currentIndex++] | (data[currentIndex] << 8)); + h *= m; + break; + case 1: + h ^= data[currentIndex]; + h *= m; + break; + } + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; + } +} \ No newline at end of file diff --git a/TakoTako/MusicPatch.cs b/TakoTako/MusicPatch.cs index def04d6..9061b97 100644 --- a/TakoTako/MusicPatch.cs +++ b/TakoTako/MusicPatch.cs @@ -15,6 +15,7 @@ using System.Threading.Tasks; using BepInEx.Logging; using HarmonyLib; using Newtonsoft.Json; +using TaikoMods; using TakoTako.Common; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; @@ -372,24 +373,32 @@ public class MusicPatch song.genreNo = 7; } - var instanceId = Guid.NewGuid().ToString(); + if (isTjaSong) + { + song.id = song.songName?.text + song.songSubtitle?.text + song.songDetail?.text; + if (string.IsNullOrEmpty(song.id)) + throw new Exception($"Song at {directory} does not have name, subtitle or detail text"); + + song.id += song.fumenOffsetPos + song.previewPos; + } + song.SongName = song.id; song.FolderPath = directory; - song.id = instanceId; - if (uniqueIdToSong.ContainsKey(song.uniqueId) || (song.uniqueId >= 0 && song.uniqueId <= SaveDataMax)) + // Clip off the last bit of the hash to make sure that the number is positive. This will lead to more collisions, but we should be fine. + song.uniqueId = (int)(MurmurHash2.Hash(song.id) & 0xFFFF_FFF); + if (song.uniqueId <= SaveDataMax) + song.uniqueId += SaveDataMax; + + if (uniqueIdToSong.ContainsKey(song.uniqueId)) { - var uniqueIdTest = unchecked(song.id.GetHashCode() + song.previewPos + song.fumenOffsetPos); - while (uniqueIdToSong.ContainsKey(uniqueIdTest) || (uniqueIdTest >= 0 && uniqueIdTest <= SaveDataMax)) - uniqueIdTest = unchecked((uniqueIdTest + 1) * (uniqueIdTest + 1)); - - song.uniqueId = uniqueIdTest; + throw new Exception($"Song \"{song.id}\" has collision with \"{uniqueIdToSong[song.uniqueId].id}\", bailing out..."); } customSongsList.Add(song); idToSong[song.id] = song; uniqueIdToSong[song.uniqueId] = song; - Log.LogInfo($"Added {(isTjaSong ? "TJA" : "")} Song {song.songName.text}"); + Log.LogInfo($"Added{(isTjaSong ? " TJA" : "")} Song {song.songName.text}({song.uniqueId})"); } } @@ -456,10 +465,10 @@ public class MusicPatch $"song_{song.id}", song.order, song.genreNo, - !Plugin.Instance.ConfigDisableCustomDLCSongs.Value, + true, // We always want to mark songs as DLC, otherwise ranked games will be broken as you are gonna match songs that other people don't have false, 0, false, - 0, + 2, // Always mark custom songs as "both players need to have this song to play it" new[] { song.branchEasy, @@ -1287,83 +1296,6 @@ public class MusicPatch #pragma warning restore Harmony003 } - /// - /// Allow for a song id less than 0 - /// - [HarmonyPatch(typeof(EnsoDataManager), "DecideSetting")] - [HarmonyPrefix] - public static bool DecideSetting_Prefix(EnsoDataManager __instance) - { - var ensoSettings = (EnsoData.Settings) typeof(EnsoDataManager).GetField("ensoSettings", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(__instance); - // if (ensoSettings.musicuid.Length <= 0) - // { - // MusicDataInterface.MusicInfoAccesser infoByUniqueId = TaikoSingletonMonoBehaviour.Instance.MyDataManager.MusicData.GetInfoByUniqueId(ensoSettings.musicUniqueId); - // if (infoByUniqueId != null) - // { - // ensoSettings.musicuid = infoByUniqueId.Id; - // } - // } - // else if (ensoSettings.musicUniqueId <= DataConst.InvalidId) - // { - // MusicDataInterface.MusicInfoAccesser infoById = TaikoSingletonMonoBehaviour.Instance.MyDataManager.MusicData.GetInfoById(ensoSettings.musicuid); - // if (infoById != null) - // { - // ensoSettings.musicUniqueId = infoById.UniqueId; - // } - // } - if (ensoSettings.musicuid.Length <= 0 /* || ensoSettings.musicUniqueId <= DataConst.InvalidId*/) - { - List musicInfoAccessers = TaikoSingletonMonoBehaviour.Instance.MyDataManager.MusicData.musicInfoAccessers; - for (int i = 0; i < musicInfoAccessers.Count; i++) - { - if (!musicInfoAccessers[i].Debug) - { - ensoSettings.musicuid = musicInfoAccessers[i].Id; - ensoSettings.musicUniqueId = musicInfoAccessers[i].UniqueId; - } - } - } - - MusicDataInterface.MusicInfoAccesser infoByUniqueId2 = TaikoSingletonMonoBehaviour.Instance.MyDataManager.MusicData.GetInfoByUniqueId(ensoSettings.musicUniqueId); - if (infoByUniqueId2 != null) - { - ensoSettings.songFilePath = infoByUniqueId2.SongFileName; - } - - __instance.DecidePartsSetting(); - if (ensoSettings.ensoType == EnsoData.EnsoType.Normal) - { - int num = 0; - int dlcType = 2; - if (ensoSettings.rankMatchType == EnsoData.RankMatchType.None) - { - num = ((ensoSettings.playerNum != 1) ? 1 : 0); - } - else if (ensoSettings.rankMatchType == EnsoData.RankMatchType.RankMatch) - { - num = 2; - ensoSettings.isRandomSelect = false; - ensoSettings.isDailyBonus = false; - } - else - { - num = 3; - ensoSettings.isRandomSelect = false; - ensoSettings.isDailyBonus = false; - } - - TaikoSingletonMonoBehaviour.Instance.CosmosLib._kpiListCommon._musicKpiInfo.SetMusicSortSettings(num, dlcType, ensoSettings.isRandomSelect, ensoSettings.isDailyBonus); - } - else - { - ensoSettings.isRandomSelect = false; - ensoSettings.isDailyBonus = false; - } - - typeof(EnsoDataManager).GetField("ensoSettings", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(__instance, ensoSettings); - return false; - } - #endregion #region Read Fumen @@ -1950,4 +1882,4 @@ public class MusicPatch public string FolderPath; public string SongName; } -} +} \ No newline at end of file diff --git a/TakoTako/Plugin.cs b/TakoTako/Plugin.cs index 703bde2..0a099b8 100644 --- a/TakoTako/Plugin.cs +++ b/TakoTako/Plugin.cs @@ -20,7 +20,6 @@ namespace TakoTako public ConfigEntry ConfigSongDirectory; public ConfigEntry ConfigSaveEnabled; public ConfigEntry ConfigSaveDirectory; - public ConfigEntry ConfigDisableCustomDLCSongs; public ConfigEntry ConfigOverrideDefaultSongLanguage; public ConfigEntry ConfigApplyGenreOverride; @@ -64,12 +63,6 @@ namespace TakoTako $"{userFolder}/Documents/{typeof(Plugin).Namespace}/saves", "The directory where saves are stored"); - ConfigDisableCustomDLCSongs = Config.Bind("CustomSongs", - "DisableCustomDLCSongs", - false, - "By default, DLC is enabled for custom songs, this is to reduce any hiccups when playing online with other people. " + - "Set this to true if you want DLC to be marked as false, be aware that the fact you're playing a custom song will be sent over the internet"); - ConfigOverrideDefaultSongLanguage = Config.Bind("CustomSongs", "ConfigOverrideDefaultSongLanguage", string.Empty, @@ -124,4 +117,4 @@ namespace TakoTako StartCoroutine(enumerator); } } -} +} \ No newline at end of file From 0efa910b5883663c836652f8fe134e845fa0b679 Mon Sep 17 00:00:00 2001 From: goaaats Date: Mon, 7 Feb 2022 13:30:40 +0100 Subject: [PATCH 2/5] Don't actually change song IDs for TJA --- TakoTako/MusicPatch.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/TakoTako/MusicPatch.cs b/TakoTako/MusicPatch.cs index 9061b97..00fc34a 100644 --- a/TakoTako/MusicPatch.cs +++ b/TakoTako/MusicPatch.cs @@ -373,20 +373,21 @@ public class MusicPatch song.genreNo = 7; } + var tempId = song.id; if (isTjaSong) { - song.id = song.songName?.text + song.songSubtitle?.text + song.songDetail?.text; - if (string.IsNullOrEmpty(song.id)) + tempId = song.songName?.text + song.songSubtitle?.text + song.songDetail?.text; + if (string.IsNullOrEmpty(tempId)) throw new Exception($"Song at {directory} does not have name, subtitle or detail text"); - song.id += song.fumenOffsetPos + song.previewPos; + tempId += song.fumenOffsetPos + song.previewPos; } song.SongName = song.id; song.FolderPath = directory; // Clip off the last bit of the hash to make sure that the number is positive. This will lead to more collisions, but we should be fine. - song.uniqueId = (int)(MurmurHash2.Hash(song.id) & 0xFFFF_FFF); + song.uniqueId = (int)(MurmurHash2.Hash(tempId) & 0xFFFF_FFF); if (song.uniqueId <= SaveDataMax) song.uniqueId += SaveDataMax; From 718ca0edcf3364ed4e249cbde3a800f10d1c4518 Mon Sep 17 00:00:00 2001 From: goaaats Date: Mon, 7 Feb 2022 14:42:45 +0100 Subject: [PATCH 3/5] TaikoMods => TakoTako --- TakoTako/MurmurHash2.cs | 4 ++-- TakoTako/MusicPatch.cs | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/TakoTako/MurmurHash2.cs b/TakoTako/MurmurHash2.cs index b11e7e3..95e1706 100644 --- a/TakoTako/MurmurHash2.cs +++ b/TakoTako/MurmurHash2.cs @@ -2,7 +2,7 @@ // MIT License // -// Copyright (c) 2017 Jitbit, 2022 TaikoMods contributors +// Copyright (c) 2017 Jitbit, 2022 TakoTako contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -22,7 +22,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -namespace TaikoMods; +namespace TakoTako; public class MurmurHash2 { diff --git a/TakoTako/MusicPatch.cs b/TakoTako/MusicPatch.cs index 00fc34a..f1054e5 100644 --- a/TakoTako/MusicPatch.cs +++ b/TakoTako/MusicPatch.cs @@ -15,7 +15,6 @@ using System.Threading.Tasks; using BepInEx.Logging; using HarmonyLib; using Newtonsoft.Json; -using TaikoMods; using TakoTako.Common; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; From 6144c64f18d0a909c109ce20df6c596236889c30 Mon Sep 17 00:00:00 2001 From: goaaats Date: Mon, 7 Feb 2022 15:29:14 +0100 Subject: [PATCH 4/5] Use TJA hash as unique id, string id This also prevents a game bug wherein the game can't handle two songs with the same string ID --- TakoTako/MusicPatch.cs | 25 +++---- TakoTakoScripts/TJAConvert/Program.cs | 65 ++++++++++--------- TakoTakoScripts/TakoTako.Common/CustomSong.cs | 5 +- .../TakoTako.Common}/MurmurHash2.cs | 2 +- 4 files changed, 52 insertions(+), 45 deletions(-) rename {TakoTako => TakoTakoScripts/TakoTako.Common}/MurmurHash2.cs (98%) diff --git a/TakoTako/MusicPatch.cs b/TakoTako/MusicPatch.cs index f1054e5..e7dd811 100644 --- a/TakoTako/MusicPatch.cs +++ b/TakoTako/MusicPatch.cs @@ -372,21 +372,24 @@ public class MusicPatch song.genreNo = 7; } - var tempId = song.id; - if (isTjaSong) - { - tempId = song.songName?.text + song.songSubtitle?.text + song.songDetail?.text; - if (string.IsNullOrEmpty(tempId)) - throw new Exception($"Song at {directory} does not have name, subtitle or detail text"); - - tempId += song.fumenOffsetPos + song.previewPos; - } - song.SongName = song.id; song.FolderPath = directory; // Clip off the last bit of the hash to make sure that the number is positive. This will lead to more collisions, but we should be fine. - song.uniqueId = (int)(MurmurHash2.Hash(tempId) & 0xFFFF_FFF); + if (isTjaSong) + { + // For TJAs, we need to hash the TJA file. + song.uniqueId = song.tjaFileHash; + + if (song.uniqueId == 0) + throw new Exception("Converted TJA had no hash."); + } + else + { + // For official songs, we can just use the hash of the song internal name. + song.uniqueId = (int)(MurmurHash2.Hash(song.id) & 0xFFFF_FFF); + } + if (song.uniqueId <= SaveDataMax) song.uniqueId += SaveDataMax; diff --git a/TakoTakoScripts/TJAConvert/Program.cs b/TakoTakoScripts/TJAConvert/Program.cs index 4338f0d..1814b79 100644 --- a/TakoTakoScripts/TJAConvert/Program.cs +++ b/TakoTakoScripts/TJAConvert/Program.cs @@ -99,9 +99,11 @@ namespace TJAConvert Directory.Delete(tempOutDirectory, true); Directory.CreateDirectory(tempOutDirectory); - var passed = await TJAToFumens(metadata, tjaPath, tempOutDirectory); + var originalTjaData = File.ReadAllBytes(tjaPath); + var tjaHash = (int)(MurmurHash2.Hash(originalTjaData) & 0xFFFF_FFF); - if (passed >= 0) passed = CreateMusicFile(metadata, tempOutDirectory) ? 0 : -1; + var passed = await TJAToFumens(metadata, tjaPath, tjaHash, tempOutDirectory); + if (passed >= 0) passed = CreateMusicFile(metadata, tjaHash, tempOutDirectory) ? 0 : -1; var copyFilePath = Path.Combine(newDirectory, Path.GetFileName(originalAudioPath)); File.Copy(originalAudioPath, copyFilePath); @@ -110,10 +112,10 @@ namespace TJAConvert switch (audioExtension.ToLowerInvariant()) { case "wav": - if (passed >= 0) passed = WavToACB(copyFilePath, tempOutDirectory) ? 0 : -1; + if (passed >= 0) passed = WavToACB(copyFilePath, tempOutDirectory, tjaHash) ? 0 : -1; break; case "ogg": - if (passed >= 0) passed = OGGToACB(copyFilePath, tempOutDirectory) ? 0 : -1; + if (passed >= 0) passed = OGGToACB(copyFilePath, tempOutDirectory, tjaHash) ? 0 : -1; break; default: Console.WriteLine($"Do not support {audioExtension} audio files"); @@ -196,14 +198,14 @@ namespace TJAConvert acbFile.Save(acbPath, bufferSize); } - private static bool CreateMusicFile(TJAMetadata metadata, string outputPath) + private static bool CreateMusicFile(TJAMetadata metadata, int tjaHash, string outputPath) { try { var musicInfo = new CustomSong { uniqueId = metadata.Title.GetHashCode(), - id = metadata.Id, + id = tjaHash.ToString(), order = 0, genreNo = (int) metadata.Genre, branchEasy = false, @@ -213,6 +215,7 @@ namespace TJAConvert branchUra = false, previewPos = (int) (metadata.PreviewTime * 1000), fumenOffsetPos = (int) (metadata.Offset * 10), + tjaFileHash = tjaHash, songName = new TextEntry() { text = metadata.Title, @@ -316,7 +319,7 @@ namespace TJAConvert } } - private static async Task TJAToFumens(TJAMetadata metadata, string tjaPath, string outputPath) + private static async Task TJAToFumens(TJAMetadata metadata, string tjaPath, int tjaHash, string outputPath) { var fileName = Path.GetFileName(tjaPath); var newPath = Path.Combine(outputPath, fileName); @@ -332,7 +335,7 @@ namespace TJAConvert if (metadata.Courses.Any(x => x.CourseType == CourseType.UraOni)) { // tja2bin doesn't support Ura Oni, so rip it out and change the course type to oni, then rename the final file - passed = await ConvertUraOni(metadata, newPath); + passed = await ConvertUraOni(metadata, newPath, tjaHash); if (passed < 0) return passed; // for every .bin in this directory, we can now add the prefix _x @@ -365,7 +368,7 @@ namespace TJAConvert { // will need to create additional files to splice them out - passed = await SpliceDoubles(metadata, newPath); + passed = await SpliceDoubles(metadata, newPath, tjaHash); if (passed < 0) return passed; @@ -380,7 +383,7 @@ namespace TJAConvert } if (metadata.Courses.All(x => x.PlayStyle != TJAMetadata.PlayStyle.Double)) - passed = await Convert(newPath, outputPath); + passed = await Convert(newPath, outputPath, tjaHash); if (passed < 0) return passed; @@ -395,7 +398,7 @@ namespace TJAConvert return passed; } - private static async Task ConvertUraOni(TJAMetadata metadata, string newPath) + private static async Task ConvertUraOni(TJAMetadata metadata, string newPath, int tjaHash) { var directory = Path.GetDirectoryName(newPath); var fileName = Path.GetFileNameWithoutExtension(newPath); @@ -427,7 +430,7 @@ namespace TJAConvert var path = $"{directory}/{fileName}.tja"; File.WriteAllLines(path, file); - var passed = await Convert(path, directory); + var passed = await Convert(path, directory, tjaHash); if (passed < 0) return passed; @@ -435,7 +438,7 @@ namespace TJAConvert } else { - var passed = await SplitP1P2(lines, course, directory, fileName, CourseType.Oni); + var passed = await SplitP1P2(lines, course, directory, fileName, tjaHash, CourseType.Oni); if (passed < 0) return passed; } @@ -449,7 +452,7 @@ namespace TJAConvert /// /// This aims to separate P1 and P2 tracks for TJA2BIN to read /// - private static async Task SpliceDoubles(TJAMetadata metadata, string newPath) + private static async Task SpliceDoubles(TJAMetadata metadata, string newPath, int tjaHash) { var directory = Path.GetDirectoryName(newPath); var fileName = Path.GetFileNameWithoutExtension(newPath); @@ -482,7 +485,7 @@ namespace TJAConvert // remove doubles section foreach (var course in doubleCourses) { - var passed = await SplitP1P2(lines, course, directory, fileName); + var passed = await SplitP1P2(lines, course, directory, fileName, tjaHash); if (passed < 0) return passed; } @@ -491,7 +494,7 @@ namespace TJAConvert return 0; } - private static async Task SplitP1P2(List lines, TJAMetadata.Course course, string directory, string fileName, CourseType? courseTypeOverride = null) + private static async Task SplitP1P2(List lines, TJAMetadata.Course course, string directory, string fileName, int tjaHash, CourseType? courseTypeOverride = null) { // metadata end int courseStartIndex = lines.FindLastIndex(x => @@ -528,7 +531,7 @@ namespace TJAConvert var path = $"{directory}/{fileName}_1.tja"; File.WriteAllLines(path, p1File); - var passed = await Convert(path, directory); + var passed = await Convert(path, directory, tjaHash); if (passed < 0) return passed; @@ -540,7 +543,7 @@ namespace TJAConvert path = $"{directory}/{fileName}_2.tja"; File.WriteAllLines(path, p2File); - passed = await Convert(path, directory); + passed = await Convert(path, directory, tjaHash); if (passed < 0) return passed; @@ -558,9 +561,9 @@ namespace TJAConvert } } - private static async Task Convert(string tjaPath, string outputPath) + private static async Task Convert(string tjaPath, string outputPath, int tjaHash) { - var fileName = Path.GetFileNameWithoutExtension(tjaPath); + var fileName = tjaHash.ToString(); TJAMetadata metadata; try @@ -572,7 +575,7 @@ namespace TJAConvert return -2; } - var newPath = $"{outputPath}\\{Path.GetFileName(tjaPath)}"; + var newPath = $"{outputPath}\\{fileName}"; if (metadata.Courses.Count == 1) { var coursePostfix = metadata.Courses[0].CourseType.ToShort(); @@ -986,12 +989,11 @@ namespace TJAConvert } } - private static bool OGGToACB(string oggPath, string outDirectory) + private static bool OGGToACB(string oggPath, string outDirectory, int tjaHash) { try { var directory = Path.GetDirectoryName(oggPath); - var fileName = Path.GetFileNameWithoutExtension(oggPath); var acbPath = $"{directory}/{Guid.NewGuid().ToString()}"; Directory.CreateDirectory(acbPath); @@ -1006,10 +1008,10 @@ namespace TJAConvert File.WriteAllBytes($"{acbPath}/00000.hca", hca); Pack(acbPath); - if (File.Exists($"{outDirectory}/song_{fileName}.bin")) - File.Delete($"{outDirectory}/song_{fileName}.bin"); + if (File.Exists($"{outDirectory}/song_{tjaHash}.bin")) + File.Delete($"{outDirectory}/song_{tjaHash}.bin"); - File.Move($"{acbPath}.acb", $"{outDirectory}/song_{fileName}.bin"); + File.Move($"{acbPath}.acb", $"{outDirectory}/song_{tjaHash}.bin"); Directory.Delete(acbPath, true); return true; } @@ -1020,12 +1022,11 @@ namespace TJAConvert } } - private static bool WavToACB(string wavPath, string outDirectory, bool deleteWav = false) + private static bool WavToACB(string wavPath, string outDirectory, int tjaHash, bool deleteWav = false) { try { var directory = Path.GetDirectoryName(wavPath); - var fileName = Path.GetFileNameWithoutExtension(wavPath); var acbPath = $"{directory}/{Guid.NewGuid().ToString()}"; Directory.CreateDirectory(acbPath); @@ -1037,10 +1038,10 @@ namespace TJAConvert var hca = WavToHca(wavPath); File.WriteAllBytes($"{acbPath}/00000.hca", hca); Pack(acbPath); - if (File.Exists($"{outDirectory}/song_{fileName}.bin")) - File.Delete($"{outDirectory}/song_{fileName}.bin"); + if (File.Exists($"{outDirectory}/song_{tjaHash}.bin")) + File.Delete($"{outDirectory}/song_{tjaHash}.bin"); - File.Move($"{acbPath}.acb", $"{outDirectory}/song_{fileName}.bin"); + File.Move($"{acbPath}.acb", $"{outDirectory}/song_{tjaHash}.bin"); if (deleteWav) File.Delete(wavPath); @@ -1138,4 +1139,4 @@ namespace TJAConvert return 3; } } -} +} \ No newline at end of file diff --git a/TakoTakoScripts/TakoTako.Common/CustomSong.cs b/TakoTakoScripts/TakoTako.Common/CustomSong.cs index 2080763..16b788a 100644 --- a/TakoTakoScripts/TakoTako.Common/CustomSong.cs +++ b/TakoTakoScripts/TakoTako.Common/CustomSong.cs @@ -41,6 +41,9 @@ namespace TakoTako.Common [DataMember] public int scoreMania; [DataMember] public int scoreUra; + // Used for UID + [DataMember] public int tjaFileHash; + // Preview Details [DataMember] public int previewPos; [DataMember] public int fumenOffsetPos; @@ -201,4 +204,4 @@ namespace TakoTako.Common [JsonProperty(NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore)] public int krFont; } -} +} \ No newline at end of file diff --git a/TakoTako/MurmurHash2.cs b/TakoTakoScripts/TakoTako.Common/MurmurHash2.cs similarity index 98% rename from TakoTako/MurmurHash2.cs rename to TakoTakoScripts/TakoTako.Common/MurmurHash2.cs index 95e1706..177c2c3 100644 --- a/TakoTako/MurmurHash2.cs +++ b/TakoTakoScripts/TakoTako.Common/MurmurHash2.cs @@ -22,7 +22,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -namespace TakoTako; +namespace TakoTako.Common; public class MurmurHash2 { From 29f08bc9be9ae8e23f01ac01077a6e0278b7a98f Mon Sep 17 00:00:00 2001 From: goaaats Date: Tue, 8 Feb 2022 13:28:34 +0100 Subject: [PATCH 5/5] Move uniqueId from CustomSong to SongInstance --- .gitignore | 1 + TakoTako/MusicPatch.cs | 21 ++++++++++--------- TakoTakoScripts/TJAConvert/Program.cs | 1 - TakoTakoScripts/TakoTako.Common/CustomSong.cs | 1 - 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 1f732d5..bd476dd 100644 --- a/.gitignore +++ b/.gitignore @@ -396,5 +396,6 @@ FodyWeavers.xsd # JetBrains Rider *.sln.iml +.idea TakoTako/Executables/TJAConvert.exe \ No newline at end of file diff --git a/TakoTako/MusicPatch.cs b/TakoTako/MusicPatch.cs index e7dd811..cd7f074 100644 --- a/TakoTako/MusicPatch.cs +++ b/TakoTako/MusicPatch.cs @@ -379,29 +379,29 @@ public class MusicPatch if (isTjaSong) { // For TJAs, we need to hash the TJA file. - song.uniqueId = song.tjaFileHash; + song.UniqueId = song.tjaFileHash; - if (song.uniqueId == 0) + if (song.UniqueId == 0) throw new Exception("Converted TJA had no hash."); } else { // For official songs, we can just use the hash of the song internal name. - song.uniqueId = (int)(MurmurHash2.Hash(song.id) & 0xFFFF_FFF); + song.UniqueId = (int)(MurmurHash2.Hash(song.id) & 0xFFFF_FFF); } - if (song.uniqueId <= SaveDataMax) - song.uniqueId += SaveDataMax; + if (song.UniqueId <= SaveDataMax) + song.UniqueId += SaveDataMax; - if (uniqueIdToSong.ContainsKey(song.uniqueId)) + if (uniqueIdToSong.ContainsKey(song.UniqueId)) { - throw new Exception($"Song \"{song.id}\" has collision with \"{uniqueIdToSong[song.uniqueId].id}\", bailing out..."); + throw new Exception($"Song \"{song.id}\" has collision with \"{uniqueIdToSong[song.UniqueId].id}\", bailing out..."); } customSongsList.Add(song); idToSong[song.id] = song; - uniqueIdToSong[song.uniqueId] = song; - Log.LogInfo($"Added{(isTjaSong ? " TJA" : "")} Song {song.songName.text}({song.uniqueId})"); + uniqueIdToSong[song.UniqueId] = song; + Log.LogInfo($"Added{(isTjaSong ? " TJA" : "")} Song {song.songName.text}({song.UniqueId})"); } } @@ -463,7 +463,7 @@ public class MusicPatch continue; musicInfoAccessors.Add(new MusicDataInterface.MusicInfoAccesser( - song.uniqueId, + song.UniqueId, // From SongInstance, as we always recalculate it now song.id, $"song_{song.id}", song.order, @@ -1884,5 +1884,6 @@ public class MusicPatch { public string FolderPath; public string SongName; + public int UniqueId; } } \ No newline at end of file diff --git a/TakoTakoScripts/TJAConvert/Program.cs b/TakoTakoScripts/TJAConvert/Program.cs index 1814b79..46a349a 100644 --- a/TakoTakoScripts/TJAConvert/Program.cs +++ b/TakoTakoScripts/TJAConvert/Program.cs @@ -204,7 +204,6 @@ namespace TJAConvert { var musicInfo = new CustomSong { - uniqueId = metadata.Title.GetHashCode(), id = tjaHash.ToString(), order = 0, genreNo = (int) metadata.Genre, diff --git a/TakoTakoScripts/TakoTako.Common/CustomSong.cs b/TakoTakoScripts/TakoTako.Common/CustomSong.cs index 16b788a..142adab 100644 --- a/TakoTakoScripts/TakoTako.Common/CustomSong.cs +++ b/TakoTakoScripts/TakoTako.Common/CustomSong.cs @@ -11,7 +11,6 @@ namespace TakoTako.Common public class CustomSong { // Song Details - [DataMember] public int uniqueId; [DataMember] public string id; [DataMember] public int order; [DataMember] public int genreNo;