1
0
mirror of synced 2025-02-17 11:18:31 +01:00

Merge branch 'release/v2.1.0'

This commit is contained in:
Fluto 2022-02-11 19:37:28 +11:00
commit 9ed3bfdb68
24 changed files with 256 additions and 374 deletions

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RiderProjectSettingsUpdater">
<option name="vcsConfiguration" value="2" />
</component>
</project>

View File

@ -1,63 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="60ebaf1c-1dab-40a1-8bf8-3441a6a2ec2d" name="Changes" comment="">
<change beforePath="$PROJECT_DIR$/MusicPatch.cs" beforeDir="false" afterPath="$PROJECT_DIR$/MusicPatch.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/TaikoMods.csproj" beforeDir="false" afterPath="$PROJECT_DIR$/TaikoMods.csproj" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="HighlightingSettingsPerFile">
<setting file="file://$PROJECT_DIR$/Taiko-Mod/obj/Debug/net48/PluginInfo.cs" root0="SKIP_HIGHLIGHTING" />
</component>
<component name="MarkdownSettingsMigration">
<option name="stateVersion" value="1" />
</component>
<component name="ProjectId" id="24dLyJ1Va0ctK1BymSu6FiSfNMK" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
<property name="WebServerToolWindowFactoryState" value="false" />
<property name="rider.run.widget.enabled.cache" value="false" />
<property name="vue.rearranger.settings.migration" value="true" />
</component>
<component name="RunManager">
<configuration name="Attach to Unity Editor" type="UNITY_DEBUG_RUN_CONFIGURATION" factoryName="Unity Debug" show_console_on_std_err="false" show_console_on_std_out="false" port="50000" address="localhost">
<option name="allowRunningInParallel" value="false" />
<option name="listenPortForConnections" value="false" />
<option name="pid" />
<option name="projectPathOnTarget" />
<option name="selectedOptions">
<list />
</option>
<method v="2" />
</configuration>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="60ebaf1c-1dab-40a1-8bf8-3441a6a2ec2d" name="Changes" comment="" />
<created>1643955770420</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1643955770420</updated>
<workItem from="1643955775940" duration="810000" />
</task>
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
<component name="UnityProjectConfiguration" hasMinimizedUI="null" />
<component name="UnityUnitTestConfiguration" currentTestLauncher="NUnit" />
<component name="VcsManagerConfiguration">
<option name="CLEAR_INITIAL_COMMIT_MESSAGE" value="true" />
</component>
</project>

View File

@ -1,5 +0,0 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/AddReferences/RecentPaths/=D_003A_005CXboxGames_005CT_0020Tablet_005CContent_005CTaiko_0020no_0020Tatsujin_005FData_005CManaged_005CAssembly_002DCSharp_002Edll/@EntryIndexedValue">True</s:Boolean>
<s:String x:Key="/Default/Environment/AssemblyExplorer/XmlDocument/@EntryValue">&lt;AssemblyExplorer&gt;&#xD;
&lt;Assembly Path="C:\git\public-git\taiko-mods\Taiko-Mod\bin\Debug\net48\Assembly-CSharp-firstpass.dll" /&gt;&#xD;
&lt;/AssemblyExplorer&gt;</s:String></wpf:ResourceDictionary>

View File

@ -22,6 +22,9 @@ namespace TJAConvert
{ {
public static class Program public static class Program
{ {
public const int PaddedSongTime = 2 * 1000; // in ms
public const float TjaOffsetForPaddingSong = -1.0f; // in ms
public static async Task Main(string[] args) public static async Task Main(string[] args)
{ {
if (args.Length != 1) if (args.Length != 1)
@ -108,14 +111,16 @@ namespace TJAConvert
var copyFilePath = Path.Combine(newDirectory, Path.GetFileName(originalAudioPath)); var copyFilePath = Path.Combine(newDirectory, Path.GetFileName(originalAudioPath));
File.Copy(originalAudioPath, copyFilePath); File.Copy(originalAudioPath, copyFilePath);
int millisecondsAddedSilence = metadata.Offset > TjaOffsetForPaddingSong ? PaddedSongTime : 0;
var audioExtension = Path.GetExtension(copyFilePath).TrimStart('.'); var audioExtension = Path.GetExtension(copyFilePath).TrimStart('.');
switch (audioExtension.ToLowerInvariant()) switch (audioExtension.ToLowerInvariant())
{ {
case "wav": case "wav":
if (passed >= 0) passed = WavToACB(copyFilePath, tempOutDirectory, tjaHash) ? 0 : -1; if (passed >= 0) passed = WavToACB(copyFilePath, tempOutDirectory, tjaHash, millisecondsAddedSilence: millisecondsAddedSilence) ? 0 : -1;
break; break;
case "ogg": case "ogg":
if (passed >= 0) passed = OGGToACB(copyFilePath, tempOutDirectory, tjaHash) ? 0 : -1; if (passed >= 0) passed = OGGToACB(copyFilePath, tempOutDirectory, tjaHash, millisecondsAddedSilence) ? 0 : -1;
break; break;
default: default:
Console.WriteLine($"Do not support {audioExtension} audio files"); Console.WriteLine($"Do not support {audioExtension} audio files");
@ -202,6 +207,7 @@ namespace TJAConvert
{ {
try try
{ {
var addedTime = metadata.Offset > TjaOffsetForPaddingSong ? PaddedSongTime : 0;
var musicInfo = new CustomSong var musicInfo = new CustomSong
{ {
id = tjaHash.ToString(), id = tjaHash.ToString(),
@ -212,8 +218,8 @@ namespace TJAConvert
branchHard = false, branchHard = false,
branchMania = false, branchMania = false,
branchUra = false, branchUra = false,
previewPos = (int) (metadata.PreviewTime * 1000), previewPos = (int) (metadata.PreviewTime * 1000) + addedTime,
fumenOffsetPos = (int) (metadata.Offset * 10), fumenOffsetPos = (int) (metadata.Offset * 10) + (addedTime),
tjaFileHash = tjaHash, tjaFileHash = tjaHash,
songName = new TextEntry() songName = new TextEntry()
{ {
@ -264,49 +270,91 @@ namespace TJAConvert
foreach (var course in metadata.Courses) foreach (var course in metadata.Courses)
{ {
var isDouble = course.PlayStyle == TJAMetadata.PlayStyle.Double;
var shinuti = EstimateScoreBasedOnNotes(course);
//todo figure out the best score? //todo figure out the best score?
switch (course.CourseType) switch (course.CourseType)
{ {
case CourseType.Easy: case CourseType.Easy:
musicInfo.starEasy = course.Level; musicInfo.starEasy = course.Level;
musicInfo.shinutiEasy = 10170; musicInfo.scoreEasy = 1000000;
musicInfo.shinutiEasyDuet = 10170; musicInfo.branchEasy = musicInfo.branchEasy || course.IsBranching;
musicInfo.scoreEasy = 360090; if (isDouble)
musicInfo.branchEasy = course.IsBranching; musicInfo.shinutiEasyDuet = shinuti;
else
musicInfo.shinutiEasy = shinuti;
break; break;
case CourseType.Normal: case CourseType.Normal:
musicInfo.starNormal = course.Level; musicInfo.starNormal = course.Level;
musicInfo.shinutiNormal = 6010; musicInfo.scoreNormal = 1000000;
musicInfo.shinutiNormalDuet = 6010; musicInfo.branchNormal = musicInfo.branchNormal || course.IsBranching;
musicInfo.scoreNormal = 650150; if (isDouble)
musicInfo.branchNormal = course.IsBranching; musicInfo.shinutiNormalDuet = shinuti;
else
musicInfo.shinutiNormal = shinuti;
break; break;
case CourseType.Hard: case CourseType.Hard:
musicInfo.starHard = course.Level; musicInfo.starHard = course.Level;
musicInfo.shinutiHard = 3010; musicInfo.scoreHard = 1000000;
musicInfo.shinutiHardDuet = 3010; musicInfo.branchHard = musicInfo.branchHard || course.IsBranching;
musicInfo.scoreHard = 800210; if (isDouble)
musicInfo.branchHard = course.IsBranching; musicInfo.shinutiHardDuet = shinuti;
else
musicInfo.shinutiHard = shinuti;
break; break;
case CourseType.Oni: case CourseType.Oni:
musicInfo.starMania = course.Level; musicInfo.starMania = course.Level;
musicInfo.shinutiMania = 1000; musicInfo.scoreMania = 1000000;
musicInfo.shinutiManiaDuet = 1000; musicInfo.branchMania = musicInfo.branchMania || course.IsBranching;
musicInfo.scoreMania = 10000; if (isDouble)
musicInfo.branchMania = course.IsBranching; musicInfo.shinutiManiaDuet = shinuti;
else
musicInfo.shinutiMania = shinuti;
break; break;
case CourseType.UraOni: case CourseType.UraOni:
musicInfo.starUra = course.Level; musicInfo.starUra = course.Level;
musicInfo.shinutiUra = 1000; musicInfo.scoreUra = 1000000;
musicInfo.shinutiUraDuet = 1000; musicInfo.branchUra = musicInfo.branchUra || course.IsBranching;
musicInfo.scoreUra = 10000; if (isDouble)
musicInfo.branchUra = course.IsBranching; musicInfo.shinutiUraDuet = shinuti;
else
musicInfo.shinutiUra = shinuti;
break; break;
default: default:
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
} }
// make sure each course as a score
if (musicInfo.shinutiEasy == 0)
musicInfo.shinutiEasy = musicInfo.shinutiEasyDuet != 0 ? musicInfo.shinutiEasyDuet : 7352;
if (musicInfo.shinutiNormal == 0)
musicInfo.shinutiNormal = musicInfo.shinutiNormalDuet != 0 ? musicInfo.shinutiNormalDuet : 4830;
if (musicInfo.shinutiHard == 0)
musicInfo.shinutiHard = musicInfo.shinutiHardDuet != 0 ? musicInfo.shinutiHardDuet : 3144;
if (musicInfo.shinutiMania == 0)
musicInfo.shinutiMania = musicInfo.shinutiManiaDuet != 0 ? musicInfo.shinutiManiaDuet : 2169;
if (musicInfo.shinutiUra == 0)
musicInfo.shinutiUra = musicInfo.shinutiUraDuet != 0 ? musicInfo.shinutiUraDuet : 1420;
if (musicInfo.shinutiEasyDuet == 0)
musicInfo.shinutiEasyDuet = musicInfo.shinutiEasy;
if (musicInfo.shinutiNormalDuet == 0)
musicInfo.shinutiNormalDuet = musicInfo.shinutiNormal;
if (musicInfo.shinutiHardDuet == 0)
musicInfo.shinutiHardDuet = musicInfo.shinutiHard;
if (musicInfo.shinutiManiaDuet == 0)
musicInfo.shinutiManiaDuet = musicInfo.shinutiMania;
if (musicInfo.shinutiUraDuet == 0)
musicInfo.shinutiUraDuet = musicInfo.shinutiUra;
int EstimateScoreBasedOnNotes(TJAMetadata.Course course)
{
return Math.Max(1, 1000000 / course.EstimatedNotes);
}
var json = JsonConvert.SerializeObject(musicInfo, Formatting.Indented); var json = JsonConvert.SerializeObject(musicInfo, Formatting.Indented);
File.WriteAllText($"{outputPath}/data.json", json); File.WriteAllText($"{outputPath}/data.json", json);
return true; return true;
@ -637,7 +685,7 @@ namespace TJAConvert
attempts--; attempts--;
// todo: Not sure how to solve this, so ignore it for now // todo: Not sure how to solve this, so ignore it for now
if (result.Contains("branches must have same measure count") || result.Contains("invalid #BRANCHSTART")) if (result.Contains("branches must have same measure count"))
return -2; return -2;
async Task RunProcess() async Task RunProcess()
@ -816,10 +864,40 @@ namespace TJAConvert
return true; return true;
} }
if (result.Contains("invalid #BRANCHSTART"))
{
var currentLines = File.ReadLines(newPath).ToList();
for (var i = 0; i < currentLines.Count; i++)
{
var line = currentLines[i];
if (!line.StartsWith("#BRANCHSTART p,", StringComparison.InvariantCultureIgnoreCase))
continue;
var arguments = line.Substring("#BRANCHSTART ".Length).Split(',');
// This invalid branch start error needs to be manually resolved
if (arguments.Length != 3)
return false;
float number1;
float number2;
if (!float.TryParse(arguments[1], out var test))
return false;
number1 = test;
if (!float.TryParse(arguments[2], out test))
return false;
number2 = test;
currentLines[i] = $"#BRANCHSTART p,{(int) Math.Ceiling(number1)},{(int) Math.Ceiling(number2)}";
}
File.WriteAllLines(newPath, currentLines);
return true;
}
if (result.Contains("#E must be after the #N branch") || result.Contains("#M must be after the #E branch")) if (result.Contains("#E must be after the #N branch") || result.Contains("#M must be after the #E branch"))
{ {
var currentLines = File.ReadLines(newPath).ToList(); var currentLines = File.ReadLines(newPath).ToList();
// var problematicCourse = GetCourseWithProblems();
string currentBranch = ""; string currentBranch = "";
int startOfBranch = -1; int startOfBranch = -1;
@ -988,7 +1066,7 @@ namespace TJAConvert
} }
} }
private static bool OGGToACB(string oggPath, string outDirectory, int tjaHash) private static bool OGGToACB(string oggPath, string outDirectory, int tjaHash, int millisecondsAddedSilence = 0)
{ {
try try
{ {
@ -1001,7 +1079,7 @@ namespace TJAConvert
using (FileStream compressedFileStream = File.Create($"{acbPath}.acb")) using (FileStream compressedFileStream = File.Create($"{acbPath}.acb"))
decompressor.CopyTo(compressedFileStream); decompressor.CopyTo(compressedFileStream);
var hca = OggToHca(oggPath); var hca = OggToHca(oggPath, millisecondsAddedSilence);
if (hca == null) if (hca == null)
return false; return false;
@ -1021,7 +1099,7 @@ namespace TJAConvert
} }
} }
private static bool WavToACB(string wavPath, string outDirectory, int tjaHash, bool deleteWav = false) private static bool WavToACB(string wavPath, string outDirectory, int tjaHash, bool deleteWav = false, int millisecondsAddedSilence = 0)
{ {
try try
{ {
@ -1034,7 +1112,7 @@ namespace TJAConvert
using (FileStream compressedFileStream = File.Create($"{acbPath}.acb")) using (FileStream compressedFileStream = File.Create($"{acbPath}.acb"))
decompressor.CopyTo(compressedFileStream); decompressor.CopyTo(compressedFileStream);
var hca = WavToHca(wavPath); var hca = WavToHca(wavPath, millisecondsAddedSilence);
File.WriteAllBytes($"{acbPath}/00000.hca", hca); File.WriteAllBytes($"{acbPath}/00000.hca", hca);
Pack(acbPath); Pack(acbPath);
if (File.Exists($"{outDirectory}/song_{tjaHash}.bin")) if (File.Exists($"{outDirectory}/song_{tjaHash}.bin"))
@ -1054,22 +1132,53 @@ namespace TJAConvert
} }
} }
private static byte[] WavToHca(string path) private static byte[] WavToHca(string path, int millisecondSilence = 0)
{ {
var wavReader = new WaveReader();
var hcaWriter = new HcaWriter(); var hcaWriter = new HcaWriter();
var waveReader = new WaveReader();
var audioData = waveReader.Read(File.ReadAllBytes(path)); if (millisecondSilence > 0)
{
WaveFileReader reader = new WaveFileReader(path);
var memoryStream = new MemoryStream();
var trimmed = new OffsetSampleProvider(reader.ToSampleProvider())
{
DelayBy = TimeSpan.FromMilliseconds(millisecondSilence)
};
WaveFileWriter.WriteWavFileToStream(memoryStream, trimmed.ToWaveProvider16());
var audioData = wavReader.Read(memoryStream.ToArray());
return hcaWriter.GetFile(audioData); return hcaWriter.GetFile(audioData);
} }
else
{
var audioData = wavReader.Read(File.ReadAllBytes(path));
return hcaWriter.GetFile(audioData);
}
}
private static byte[] OggToHca(string inPath) private static byte[] OggToHca(string inPath, int millisecondSilence = 0)
{ {
try try
{ {
using FileStream fileIn = new FileStream(inPath, FileMode.Open); using FileStream fileIn = new FileStream(inPath, FileMode.Open);
var vorbis = new VorbisWaveReader(fileIn); var vorbis = new VorbisWaveReader(fileIn);
var wavProvider = new SampleToWaveProvider16(vorbis);
var memoryStream = new MemoryStream(); var memoryStream = new MemoryStream();
WaveFileWriter.WriteWavFileToStream(memoryStream, new SampleToWaveProvider16(vorbis));
if (millisecondSilence > 0)
{
var trimmed = new OffsetSampleProvider(wavProvider.ToSampleProvider())
{
DelayBy = TimeSpan.FromMilliseconds(millisecondSilence)
};
WaveFileWriter.WriteWavFileToStream(memoryStream, trimmed.ToWaveProvider16());
}
else
{
WaveFileWriter.WriteWavFileToStream(memoryStream, wavProvider);
}
var hcaWriter = new HcaWriter(); var hcaWriter = new HcaWriter();
var waveReader = new WaveReader(); var waveReader = new WaveReader();

View File

@ -39,6 +39,7 @@
</ItemGroup> </ItemGroup>
<Target Name="PostBuildCopy" AfterTargets="PostBuildEvent"> <Target Name="PostBuildCopy" AfterTargets="PostBuildEvent">
<Copy SourceFiles="$(TargetDir)TJAConvert.exe" DestinationFolder="$(ProjectDir)\..\..\TakoTako\Executables" SkipUnchangedFiles="true" /> <Copy SourceFiles="$(ProjectDir)..\TakoTako\Executables\tja2bin.exe" DestinationFolder="$(TargetDir)" SkipUnchangedFiles="true" />
<Copy SourceFiles="$(TargetDir)TJAConvert.exe" DestinationFolder="$(ProjectDir)..\TakoTako\Executables" SkipUnchangedFiles="true" />
</Target> </Target>
</Project> </Project>

View File

@ -160,9 +160,7 @@ internal class TJAMetadata
currentCourse.SongDataIndexEnd = courseStartIndex; currentCourse.SongDataIndexEnd = courseStartIndex;
if (newContent) // is this branching?
Courses.Add(currentCourse);
for (int i = currentCourse.SongDataIndexStart; i < currentCourse.SongDataIndexEnd; i++) for (int i = currentCourse.SongDataIndexStart; i < currentCourse.SongDataIndexEnd; i++)
{ {
var line = lines[i]; var line = lines[i];
@ -173,6 +171,52 @@ internal class TJAMetadata
} }
} }
// calculate roughly the amount of song notes in this course
int noteCount = 0;
int branchNoteCount = 0;
int branches = 0;
bool inBranch = false;
for (int i = currentCourse.SongDataIndexStart; i < currentCourse.SongDataIndexEnd; i++)
{
var line = lines[i].Trim();
if (line.Equals("#N", StringComparison.InvariantCultureIgnoreCase)
|| line.Equals("#E", StringComparison.InvariantCultureIgnoreCase)
|| line.Equals("#M", StringComparison.InvariantCultureIgnoreCase))
branches++;
var branchStart = line.StartsWith("#BRANCHSTART", StringComparison.InvariantCultureIgnoreCase);
if (inBranch && (branchStart || line.StartsWith("#BRANCHEND", StringComparison.InvariantCultureIgnoreCase)))
{
noteCount += branchNoteCount / Math.Max(1, branches);
inBranch = false;
}
if (!inBranch && branchStart)
{
inBranch = true;
branchNoteCount = 0;
branches = 0;
}
if (!line.EndsWith(","))
continue;
var notes = line.Count(x => x is '1' or '2' or '3' or '4');
if (inBranch)
branchNoteCount += notes;
else
noteCount += notes;
}
if (currentCourse.PlayStyle == PlayStyle.Double)
currentCourse.EstimatedNotes = noteCount / 2;
else
currentCourse.EstimatedNotes = noteCount;
if (newContent)
Courses.Add(currentCourse);
// duplicate the existing course // duplicate the existing course
currentCourse = new Course(currentCourse); currentCourse = new Course(currentCourse);
// find the next start // find the next start
@ -241,8 +285,6 @@ internal class TJAMetadata
return CourseType.UraOni; return CourseType.UraOni;
} }
} }
public const string TJAFieldRegexTemplate = "^{0}:\\s*(?<VALUE>.*?)\\s*$"; public const string TJAFieldRegexTemplate = "^{0}:\\s*(?<VALUE>.*?)\\s*$";
@ -290,6 +332,8 @@ internal class TJAMetadata
public int SongDataIndexStart; public int SongDataIndexStart;
public int SongDataIndexEnd; public int SongDataIndexEnd;
public int EstimatedNotes = 0;
public Course() public Course()
{ {
} }

View File

@ -9,7 +9,7 @@
<ItemGroup> <ItemGroup>
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=null"> <Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=null">
<HintPath>..\..\TakoTako\References\Newtonsoft.Json.dll</HintPath> <HintPath>..\TakoTako\References\Newtonsoft.Json.dll</HintPath>
</Reference> </Reference>
</ItemGroup> </ItemGroup>

View File

@ -1,10 +1,13 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TakoTako.Common", "TakoTakoScripts\TakoTako.Common\TakoTako.Common.csproj", "{DDD2BC9B-15CB-47AE-A104-F45A3C65C7B1}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TakoTako.Common", "TakoTako.Common\TakoTako.Common.csproj", "{DDD2BC9B-15CB-47AE-A104-F45A3C65C7B1}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TJAConvert", "TakoTakoScripts\TJAConvert\TJAConvert.csproj", "{9ED2476B-FB39-4BE9-8661-21311AD9A3E8}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TJAConvert", "TJAConvert\TJAConvert.csproj", "{9ED2476B-FB39-4BE9-8661-21311AD9A3E8}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TakoTako", "TakoTako\TakoTako.csproj", "{3B286FDB-8AB8-49B0-852E-5180AFBC20D5}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TakoTako", "TakoTako\TakoTako.csproj", "{3B286FDB-8AB8-49B0-852E-5180AFBC20D5}"
ProjectSection(ProjectDependencies) = postProject
{9ED2476B-FB39-4BE9-8661-21311AD9A3E8} = {9ED2476B-FB39-4BE9-8661-21311AD9A3E8}
EndProjectSection
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution

View File

@ -1,7 +1,7 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=ACB/@EntryIndexedValue">ACB</s:String> <s:Boolean x:Key="/Default/UserDictionary/Words/=shinuti/@EntryIndexedValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OGG/@EntryIndexedValue">OGG</s:String> <s:Boolean x:Key="/Default/UserDictionary/Words/=Fluto/@EntryIndexedValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=TJA/@EntryIndexedValue">TJA</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=fumen/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=fumen/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Fumens/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Fumens/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Taiko/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary> <s:Boolean x:Key="/Default/UserDictionary/Words/=Taiko/@EntryIndexedValue">True</s:Boolean>
</wpf:ResourceDictionary>

View File

@ -192,7 +192,7 @@ public class MusicPatch
{ {
if (IsTjaConverted(musicDirectory, out var conversionStatus) && conversionStatus != null) if (IsTjaConverted(musicDirectory, out var conversionStatus) && conversionStatus != null)
{ {
foreach (var item in conversionStatus.Items.Where(item => item.Successful)) foreach (var item in conversionStatus.Items.Where(item => item.Successful && item.Version == ConversionStatus.ConversionItem.CurrentVersion))
SubmitDirectory(Path.Combine(musicDirectory, item.FolderName), true); SubmitDirectory(Path.Combine(musicDirectory, item.FolderName), true);
return; return;
} }
@ -239,14 +239,14 @@ public class MusicPatch
if (!match.Success) if (!match.Success)
continue; continue;
var resultInt = int.Parse(match.Groups["ID"].Value); var resultCode = int.Parse(match.Groups["ID"].Value);
var folderPath = match.Groups["PATH"].Value; var folderPath = match.Groups["PATH"].Value;
folderPath = Path.GetFullPath(folderPath).Replace(Path.GetFullPath(musicDirectory), "."); folderPath = Path.GetFullPath(folderPath).Replace(Path.GetFullPath(musicDirectory), ".");
var existingEntry = conversionStatus.Items.FirstOrDefault(x => x.FolderName == folderPath); var existingEntry = conversionStatus.Items.FirstOrDefault(x => x.FolderName == folderPath);
var asciiFolderPath = Regex.Replace(folderPath, @"[^\u0000-\u007F]+", string.Empty); var asciiFolderPath = Regex.Replace(folderPath, @"[^\u0000-\u007F]+", string.Empty);
if (resultInt >= 0) if (resultCode >= 0)
Log.LogInfo($"Converted {asciiFolderPath} successfully"); Log.LogInfo($"Converted {asciiFolderPath} successfully");
else else
Log.LogError($"Could not convert {asciiFolderPath}"); Log.LogError($"Could not convert {asciiFolderPath}");
@ -257,13 +257,17 @@ public class MusicPatch
{ {
Attempts = 1, Attempts = 1,
FolderName = folderPath, FolderName = folderPath,
Successful = resultInt >= 0, Successful = resultCode >= 0,
ResultCode = resultCode,
Version = ConversionStatus.ConversionItem.CurrentVersion,
}); });
} }
else else
{ {
existingEntry.Attempts++; existingEntry.Attempts++;
existingEntry.Successful = resultInt >= 0; existingEntry.Successful = resultCode >= 0;
existingEntry.ResultCode = resultCode;
existingEntry.Version = ConversionStatus.ConversionItem.CurrentVersion;
} }
} }
@ -422,7 +426,7 @@ public class MusicPatch
if (conversionStatus == null) if (conversionStatus == null)
return false; return false;
return conversionStatus.Items.Count != 0 && conversionStatus.Items.All(x => x.Successful); return conversionStatus.Items.Count != 0 && conversionStatus.Items.All(x => x.Successful && x.Version == ConversionStatus.ConversionItem.CurrentVersion);
} }
catch catch
{ {
@ -625,7 +629,7 @@ public class MusicPatch
void Add(string key, TextEntry textEntry) void Add(string key, TextEntry textEntry)
{ {
var (text, font) = GetValuesTextEntry(textEntry); var (text, font) = GetValuesTextEntry(textEntry, languageValue);
musicInfoAccessors.Add(new WordDataInterface.WordListInfoAccesser(key, text, font)); musicInfoAccessors.Add(new WordDataInterface.WordListInfoAccesser(key, text, font));
} }
} }
@ -684,11 +688,11 @@ public class MusicPatch
return (text, font); return (text, font);
} }
(string text, int font) GetValuesTextEntry(TextEntry textEntry) (string text, int font) GetValuesTextEntry(TextEntry textEntry, string selectedLanguage)
{ {
string text; string text;
int font; int font;
switch (languageValue) switch (selectedLanguage)
{ {
case "Japanese": case "Japanese":
text = textEntry.jpText; text = textEntry.jpText;
@ -735,7 +739,31 @@ public class MusicPatch
break; break;
} }
if (!string.IsNullOrEmpty(text)) return (text, font); // if this text is default, and we're not English / Japanese default to one of them
if (string.IsNullOrEmpty(text) && selectedLanguage != "Japanese" && selectedLanguage != "English")
{
string fallbackLanguage;
switch (selectedLanguage)
{
case "Chinese":
case "ChineseT":
case "ChineseTraditional":
case "ChineseSimplified":
case "ChineseS":
case "Korean":
fallbackLanguage = "Japanese";
break;
default:
fallbackLanguage = "English";
break;
}
return GetValuesTextEntry(textEntry, fallbackLanguage);
}
if (!string.IsNullOrEmpty(text))
return (text, font);
text = textEntry.text; text = textEntry.text;
font = textEntry.font; font = textEntry.font;
@ -1881,13 +1909,14 @@ public class MusicPatch
public class ConversionItem public class ConversionItem
{ {
[JsonIgnore] public const int CurrentVersion = 1; [JsonIgnore] public const int CurrentVersion = 2;
[JsonIgnore] public const int MaxAttempts = 3; [JsonIgnore] public const int MaxAttempts = 3;
[JsonProperty("f")] public string FolderName; [JsonProperty("f")] public string FolderName;
[JsonProperty("a")] public int Attempts; [JsonProperty("a")] public int Attempts;
[JsonProperty("s")] public bool Successful; [JsonProperty("s")] public bool Successful;
[JsonProperty("v")] public int Version = CurrentVersion; [JsonProperty("v")] public int Version;
[JsonProperty("e")] public int ResultCode;
public override string ToString() public override string ToString()
{ {

View File

@ -4,12 +4,12 @@
<TargetFramework>net48</TargetFramework> <TargetFramework>net48</TargetFramework>
<AssemblyName>com.fluto.takotako</AssemblyName> <AssemblyName>com.fluto.takotako</AssemblyName>
<Description>Fixes Taiko issues and allows custom songs</Description> <Description>Fixes Taiko issues and allows custom songs</Description>
<Version>2.0.0</Version> <Version>2.1.0</Version>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<RootNamespace>TakoTako</RootNamespace> <RootNamespace>TakoTako</RootNamespace>
<PackageId>com.fluto.takotako</PackageId> <PackageId>com.fluto.takotako</PackageId>
<PackageVersion>2.0.0</PackageVersion> <PackageVersion>2.1.0</PackageVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@ -55,7 +55,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\TakoTakoScripts\TakoTako.Common\TakoTako.Common.csproj" /> <ProjectReference Include="..\TakoTako.Common\TakoTako.Common.csproj" />
</ItemGroup> </ItemGroup>
<Target Name="PostBuildCopy" AfterTargets="PostBuildEvent"> <Target Name="PostBuildCopy" AfterTargets="PostBuildEvent">

View File

@ -1,35 +0,0 @@
# Common IntelliJ Platform excludes
# User specific
**/.idea/**/workspace.xml
**/.idea/**/tasks.xml
**/.idea/shelf/*
**/.idea/dictionaries
**/.idea/httpRequests/
# Sensitive or high-churn files
**/.idea/**/dataSources/
**/.idea/**/dataSources.ids
**/.idea/**/dataSources.xml
**/.idea/**/dataSources.local.xml
**/.idea/**/sqlDataSources.xml
**/.idea/**/dynamic.xml
# Rider
# Rider auto-generates .iml files, and contentModel.xml
**/.idea/**/*.iml
**/.idea/**/contentModel.xml
**/.idea/**/modules.xml
*.suo
*.user
.vs/
[Bb]in/
[Oo]bj/
_UpgradeReport_Files/
[Pp]ackages/
Thumbs.db
Desktop.ini
.DS_Store
ShortcutFolder.lnk

View File

@ -1,13 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/modules.xml
/.idea.TakoTakoScripts.iml
/projectSettingsUpdater.xml
/contentModel.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>

View File

@ -1,141 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="Costura" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="IncludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="IncludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged32Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="PreloadOrder" type="xs:string">
<xs:annotation>
<xs:documentation>The order of preloaded assemblies, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:all>
<xs:attribute name="CreateTemporaryAssemblies" type="xs:boolean">
<xs:annotation>
<xs:documentation>This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeDebugSymbols" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls if .pdbs for reference assemblies are also embedded.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeRuntimeReferences" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls if runtime assemblies are also embedded.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="UseRuntimeReferencePaths" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls whether the runtime assemblies are embedded with their full path or only with their assembly name.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableCompression" type="xs:boolean">
<xs:annotation>
<xs:documentation>Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableCleanup" type="xs:boolean">
<xs:annotation>
<xs:documentation>As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="LoadAtModuleInit" type="xs:boolean">
<xs:annotation>
<xs:documentation>Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IgnoreSatelliteAssemblies" type="xs:boolean">
<xs:annotation>
<xs:documentation>Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ExcludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ExcludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Unmanaged32Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Unmanaged64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="PreloadOrder" type="xs:string">
<xs:annotation>
<xs:documentation>The order of preloaded assemblies, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@ -1,16 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net48</TargetFramework>
<RootNamespace>TakoTako.Common</RootNamespace>
<AssemblyName>TakoTako.Common</AssemblyName>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=null">
<HintPath>..\..\TakoTako\References\Newtonsoft.Json.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

View File

@ -1,7 +0,0 @@
{
"sdk": {
"version": "5.0.0",
"rollForward": "latestMinor",
"allowPrerelease": false
}
}