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:
parent
718ca0edcf
commit
6144c64f18
@ -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;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
{
|
{
|
Loading…
Reference in New Issue
Block a user