1
0
mirror of synced 2024-12-18 07:25:53 +01:00

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
This commit is contained in:
goaaats 2022-02-07 15:29:14 +01:00
parent 718ca0edcf
commit 6144c64f18
No known key found for this signature in database
GPG Key ID: 49E2AA8C6A76498B
4 changed files with 52 additions and 45 deletions

View File

@ -372,21 +372,24 @@ public class MusicPatch
song.genreNo = 7; 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.SongName = song.id;
song.FolderPath = directory; 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. // 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) if (song.uniqueId <= SaveDataMax)
song.uniqueId += SaveDataMax; song.uniqueId += SaveDataMax;

View File

@ -99,9 +99,11 @@ namespace TJAConvert
Directory.Delete(tempOutDirectory, true); Directory.Delete(tempOutDirectory, true);
Directory.CreateDirectory(tempOutDirectory); 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)); var copyFilePath = Path.Combine(newDirectory, Path.GetFileName(originalAudioPath));
File.Copy(originalAudioPath, copyFilePath); File.Copy(originalAudioPath, copyFilePath);
@ -110,10 +112,10 @@ namespace TJAConvert
switch (audioExtension.ToLowerInvariant()) switch (audioExtension.ToLowerInvariant())
{ {
case "wav": case "wav":
if (passed >= 0) passed = WavToACB(copyFilePath, tempOutDirectory) ? 0 : -1; if (passed >= 0) passed = WavToACB(copyFilePath, tempOutDirectory, tjaHash) ? 0 : -1;
break; break;
case "ogg": case "ogg":
if (passed >= 0) passed = OGGToACB(copyFilePath, tempOutDirectory) ? 0 : -1; if (passed >= 0) passed = OGGToACB(copyFilePath, tempOutDirectory, tjaHash) ? 0 : -1;
break; break;
default: default:
Console.WriteLine($"Do not support {audioExtension} audio files"); Console.WriteLine($"Do not support {audioExtension} audio files");
@ -196,14 +198,14 @@ namespace TJAConvert
acbFile.Save(acbPath, bufferSize); acbFile.Save(acbPath, bufferSize);
} }
private static bool CreateMusicFile(TJAMetadata metadata, string outputPath) private static bool CreateMusicFile(TJAMetadata metadata, int tjaHash, string outputPath)
{ {
try try
{ {
var musicInfo = new CustomSong var musicInfo = new CustomSong
{ {
uniqueId = metadata.Title.GetHashCode(), uniqueId = metadata.Title.GetHashCode(),
id = metadata.Id, id = tjaHash.ToString(),
order = 0, order = 0,
genreNo = (int) metadata.Genre, genreNo = (int) metadata.Genre,
branchEasy = false, branchEasy = false,
@ -213,6 +215,7 @@ namespace TJAConvert
branchUra = false, branchUra = false,
previewPos = (int) (metadata.PreviewTime * 1000), previewPos = (int) (metadata.PreviewTime * 1000),
fumenOffsetPos = (int) (metadata.Offset * 10), fumenOffsetPos = (int) (metadata.Offset * 10),
tjaFileHash = tjaHash,
songName = new TextEntry() songName = new TextEntry()
{ {
text = metadata.Title, text = metadata.Title,
@ -316,7 +319,7 @@ namespace TJAConvert
} }
} }
private static async Task<int> TJAToFumens(TJAMetadata metadata, string tjaPath, string outputPath) private static async Task<int> TJAToFumens(TJAMetadata metadata, string tjaPath, int tjaHash, string outputPath)
{ {
var fileName = Path.GetFileName(tjaPath); var fileName = Path.GetFileName(tjaPath);
var newPath = Path.Combine(outputPath, fileName); var newPath = Path.Combine(outputPath, fileName);
@ -332,7 +335,7 @@ namespace TJAConvert
if (metadata.Courses.Any(x => x.CourseType == CourseType.UraOni)) 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 // 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) if (passed < 0)
return passed; return passed;
// for every .bin in this directory, we can now add the prefix _x // 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 // will need to create additional files to splice them out
passed = await SpliceDoubles(metadata, newPath); passed = await SpliceDoubles(metadata, newPath, tjaHash);
if (passed < 0) if (passed < 0)
return passed; return passed;
@ -380,7 +383,7 @@ namespace TJAConvert
} }
if (metadata.Courses.All(x => x.PlayStyle != TJAMetadata.PlayStyle.Double)) if (metadata.Courses.All(x => x.PlayStyle != TJAMetadata.PlayStyle.Double))
passed = await Convert(newPath, outputPath); passed = await Convert(newPath, outputPath, tjaHash);
if (passed < 0) if (passed < 0)
return passed; return passed;
@ -395,7 +398,7 @@ namespace TJAConvert
return passed; return passed;
} }
private static async Task<int> ConvertUraOni(TJAMetadata metadata, string newPath) private static async Task<int> ConvertUraOni(TJAMetadata metadata, string newPath, int tjaHash)
{ {
var directory = Path.GetDirectoryName(newPath); var directory = Path.GetDirectoryName(newPath);
var fileName = Path.GetFileNameWithoutExtension(newPath); var fileName = Path.GetFileNameWithoutExtension(newPath);
@ -427,7 +430,7 @@ namespace TJAConvert
var path = $"{directory}/{fileName}.tja"; var path = $"{directory}/{fileName}.tja";
File.WriteAllLines(path, file); File.WriteAllLines(path, file);
var passed = await Convert(path, directory); var passed = await Convert(path, directory, tjaHash);
if (passed < 0) if (passed < 0)
return passed; return passed;
@ -435,7 +438,7 @@ namespace TJAConvert
} }
else 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) if (passed < 0)
return passed; return passed;
} }
@ -449,7 +452,7 @@ namespace TJAConvert
/// <summary> /// <summary>
/// This aims to separate P1 and P2 tracks for TJA2BIN to read /// This aims to separate P1 and P2 tracks for TJA2BIN to read
/// </summary> /// </summary>
private static async Task<int> SpliceDoubles(TJAMetadata metadata, string newPath) private static async Task<int> SpliceDoubles(TJAMetadata metadata, string newPath, int tjaHash)
{ {
var directory = Path.GetDirectoryName(newPath); var directory = Path.GetDirectoryName(newPath);
var fileName = Path.GetFileNameWithoutExtension(newPath); var fileName = Path.GetFileNameWithoutExtension(newPath);
@ -482,7 +485,7 @@ namespace TJAConvert
// remove doubles section // remove doubles section
foreach (var course in doubleCourses) 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) if (passed < 0)
return passed; return passed;
} }
@ -491,7 +494,7 @@ namespace TJAConvert
return 0; return 0;
} }
private static async Task<int> SplitP1P2(List<string> lines, TJAMetadata.Course course, string directory, string fileName, CourseType? courseTypeOverride = null) private static async Task<int> SplitP1P2(List<string> lines, TJAMetadata.Course course, string directory, string fileName, int tjaHash, CourseType? courseTypeOverride = null)
{ {
// metadata end // metadata end
int courseStartIndex = lines.FindLastIndex(x => int courseStartIndex = lines.FindLastIndex(x =>
@ -528,7 +531,7 @@ namespace TJAConvert
var path = $"{directory}/{fileName}_1.tja"; var path = $"{directory}/{fileName}_1.tja";
File.WriteAllLines(path, p1File); File.WriteAllLines(path, p1File);
var passed = await Convert(path, directory); var passed = await Convert(path, directory, tjaHash);
if (passed < 0) if (passed < 0)
return passed; return passed;
@ -540,7 +543,7 @@ namespace TJAConvert
path = $"{directory}/{fileName}_2.tja"; path = $"{directory}/{fileName}_2.tja";
File.WriteAllLines(path, p2File); File.WriteAllLines(path, p2File);
passed = await Convert(path, directory); passed = await Convert(path, directory, tjaHash);
if (passed < 0) if (passed < 0)
return passed; return passed;
@ -558,9 +561,9 @@ namespace TJAConvert
} }
} }
private static async Task<int> Convert(string tjaPath, string outputPath) private static async Task<int> Convert(string tjaPath, string outputPath, int tjaHash)
{ {
var fileName = Path.GetFileNameWithoutExtension(tjaPath); var fileName = tjaHash.ToString();
TJAMetadata metadata; TJAMetadata metadata;
try try
@ -572,7 +575,7 @@ namespace TJAConvert
return -2; return -2;
} }
var newPath = $"{outputPath}\\{Path.GetFileName(tjaPath)}"; var newPath = $"{outputPath}\\{fileName}";
if (metadata.Courses.Count == 1) if (metadata.Courses.Count == 1)
{ {
var coursePostfix = metadata.Courses[0].CourseType.ToShort(); 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 try
{ {
var directory = Path.GetDirectoryName(oggPath); var directory = Path.GetDirectoryName(oggPath);
var fileName = Path.GetFileNameWithoutExtension(oggPath);
var acbPath = $"{directory}/{Guid.NewGuid().ToString()}"; var acbPath = $"{directory}/{Guid.NewGuid().ToString()}";
Directory.CreateDirectory(acbPath); Directory.CreateDirectory(acbPath);
@ -1006,10 +1008,10 @@ namespace TJAConvert
File.WriteAllBytes($"{acbPath}/00000.hca", hca); File.WriteAllBytes($"{acbPath}/00000.hca", hca);
Pack(acbPath); Pack(acbPath);
if (File.Exists($"{outDirectory}/song_{fileName}.bin")) if (File.Exists($"{outDirectory}/song_{tjaHash}.bin"))
File.Delete($"{outDirectory}/song_{fileName}.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); Directory.Delete(acbPath, true);
return 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 try
{ {
var directory = Path.GetDirectoryName(wavPath); var directory = Path.GetDirectoryName(wavPath);
var fileName = Path.GetFileNameWithoutExtension(wavPath);
var acbPath = $"{directory}/{Guid.NewGuid().ToString()}"; var acbPath = $"{directory}/{Guid.NewGuid().ToString()}";
Directory.CreateDirectory(acbPath); Directory.CreateDirectory(acbPath);
@ -1037,10 +1038,10 @@ namespace TJAConvert
var hca = WavToHca(wavPath); var hca = WavToHca(wavPath);
File.WriteAllBytes($"{acbPath}/00000.hca", hca); File.WriteAllBytes($"{acbPath}/00000.hca", hca);
Pack(acbPath); Pack(acbPath);
if (File.Exists($"{outDirectory}/song_{fileName}.bin")) if (File.Exists($"{outDirectory}/song_{tjaHash}.bin"))
File.Delete($"{outDirectory}/song_{fileName}.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) if (deleteWav)
File.Delete(wavPath); File.Delete(wavPath);

View File

@ -41,6 +41,9 @@ namespace TakoTako.Common
[DataMember] public int scoreMania; [DataMember] public int scoreMania;
[DataMember] public int scoreUra; [DataMember] public int scoreUra;
// Used for UID
[DataMember] public int tjaFileHash;
// Preview Details // Preview Details
[DataMember] public int previewPos; [DataMember] public int previewPos;
[DataMember] public int fumenOffsetPos; [DataMember] public int fumenOffsetPos;

View File

@ -22,7 +22,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE. // SOFTWARE.
namespace TakoTako; namespace TakoTako.Common;
public class MurmurHash2 public class MurmurHash2
{ {