2024-05-27 05:59:40 +02:00
|
|
|
|
// ReSharper disable CheckNamespace
|
|
|
|
|
// ReSharper disable InconsistentNaming
|
|
|
|
|
|
|
|
|
|
using System.Xml.Serialization;
|
|
|
|
|
using Manager.MaiStudio.Serialize;
|
|
|
|
|
using MonoMod;
|
|
|
|
|
using MoreChartFormats;
|
|
|
|
|
using MoreChartFormats.MaiSxt;
|
|
|
|
|
using MoreChartFormats.Simai;
|
|
|
|
|
using MoreChartFormats.Simai.Errors;
|
|
|
|
|
|
|
|
|
|
namespace Manager;
|
|
|
|
|
|
|
|
|
|
class patch_NotesReader : NotesReader
|
|
|
|
|
{
|
|
|
|
|
private new FormatType checkFormat(string fileName) => Path.GetExtension(fileName) switch
|
|
|
|
|
{
|
|
|
|
|
".simai" => FormatType.FORMAT_M2S,
|
|
|
|
|
".srt" => FormatType.FORMAT_SRT,
|
|
|
|
|
".szt" => FormatType.FORMAT_SZT,
|
|
|
|
|
".sct" => FormatType.FORMAT_SCT,
|
|
|
|
|
".sdt" => FormatType.FORMAT_SDT,
|
|
|
|
|
_ => FormatType.FORMAT_MA2,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
[MonoModIgnore]
|
|
|
|
|
private extern bool loadMa2(string fileName, LoadType loadType = LoadType.LOAD_FULL);
|
|
|
|
|
|
|
|
|
|
[MonoModReplace]
|
|
|
|
|
public new bool load(string fileName, LoadType loadType = LoadType.LOAD_FULL)
|
|
|
|
|
{
|
|
|
|
|
if (!File.Exists(fileName))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var format = checkFormat(fileName);
|
|
|
|
|
|
|
|
|
|
return format switch
|
|
|
|
|
{
|
|
|
|
|
FormatType.FORMAT_MA2 => loadMa2(fileName, loadType),
|
|
|
|
|
FormatType.FORMAT_SRT or FormatType.FORMAT_SZT or FormatType.FORMAT_SCT or FormatType.FORMAT_SDT =>
|
|
|
|
|
loadSxt(format, fileName),
|
|
|
|
|
FormatType.FORMAT_M2S => loadSimai(fileName),
|
|
|
|
|
_ => false,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool loadSxt(FormatType format, string fileName)
|
|
|
|
|
{
|
|
|
|
|
init(_playerID);
|
|
|
|
|
fillDummyHeader(fileName);
|
|
|
|
|
_loadType = LoadType.LOAD_FULL;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// HACK: we are assuming that the chart file is stored in the same folder
|
|
|
|
|
// as the Music.xml, which it must be due to how this game loads assets.
|
|
|
|
|
// refer to `Manager.MaiStudio.Serialize.FilePath.AddPath(string parentPath)`.
|
|
|
|
|
//
|
|
|
|
|
// There must be a better way to get the song's BPM...
|
|
|
|
|
var musicFolder = Path.GetDirectoryName(fileName);
|
|
|
|
|
|
|
|
|
|
if (musicFolder == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Music.xml is contained in the root directory?!");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var serializer = new XmlSerializer(typeof(MusicData));
|
|
|
|
|
using (var musicXml = File.OpenRead(Path.Combine(musicFolder, "Music.xml")))
|
|
|
|
|
{
|
|
|
|
|
var music = (MusicData)serializer.Deserialize(musicXml);
|
|
|
|
|
var bpmChangeData = new BPMChangeData
|
|
|
|
|
{
|
|
|
|
|
bpm = music.bpm,
|
|
|
|
|
time = new NotesTime(0, 0, this),
|
|
|
|
|
};
|
|
|
|
|
_composition._bpmList.Add(bpmChangeData);
|
|
|
|
|
calcBPMList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var content = File.ReadAllText(fileName);
|
|
|
|
|
var refs = new NotesReferences
|
|
|
|
|
{
|
|
|
|
|
Reader = this,
|
|
|
|
|
Header = _header,
|
|
|
|
|
Composition = _composition,
|
|
|
|
|
Notes = _note,
|
|
|
|
|
};
|
|
|
|
|
SxtReaderBase reader = format == FormatType.FORMAT_SRT ? new SrtReader(refs) : new SxtReader(refs);
|
|
|
|
|
|
|
|
|
|
reader.Deserialize(content);
|
|
|
|
|
calcAll();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
System.Console.WriteLine("[MoreChartFormats] [SXT] Could not load SXT chart: {0}", e);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool loadSimai(string fileName)
|
|
|
|
|
{
|
|
|
|
|
init(_playerID);
|
|
|
|
|
fillDummyHeader(fileName);
|
|
|
|
|
_loadType = LoadType.LOAD_FULL;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
System.Console.WriteLine("[MoreChartFormats] [Simai] Tokenizing chart");
|
|
|
|
|
var tokens = SimaiReader.Tokenize(File.ReadAllText(fileName));
|
|
|
|
|
var refs = new NotesReferences
|
|
|
|
|
{
|
|
|
|
|
Reader = this,
|
|
|
|
|
Header = _header,
|
|
|
|
|
Composition = _composition,
|
|
|
|
|
Notes = _note,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
System.Console.WriteLine("[MoreChartFormats] [Simai] Processing BPM changes");
|
|
|
|
|
SimaiReader.ReadBpmChanges(tokens, refs);
|
|
|
|
|
calcBPMList();
|
|
|
|
|
|
|
|
|
|
System.Console.WriteLine("[MoreChartFormats] [Simai] Reading chart");
|
|
|
|
|
SimaiReader.Deserialize(tokens, refs);
|
|
|
|
|
|
|
|
|
|
System.Console.WriteLine("[MoreChartFormats] [Simai] Mirroring chart and calculating timings");
|
|
|
|
|
foreach (var note in _note._noteData)
|
|
|
|
|
{
|
|
|
|
|
note.time.calcMsec(this);
|
|
|
|
|
note.end.calcMsec(this);
|
2024-08-08 08:32:25 +02:00
|
|
|
|
|
|
|
|
|
if (note.type.isTouch() && note.touchArea is TouchSensorType.D or TouchSensorType.E)
|
|
|
|
|
{
|
|
|
|
|
note.startButtonPos = ConvertMirrorTouchEPosition(note.startButtonPos);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
note.startButtonPos = ConvertMirrorPosition(note.startButtonPos);
|
|
|
|
|
}
|
2024-05-27 05:59:40 +02:00
|
|
|
|
|
|
|
|
|
if (note.type.isSlide() || note.type == NotesTypeID.Def.ConnectSlide)
|
|
|
|
|
{
|
|
|
|
|
note.slideData.shoot.time.calcMsec(this);
|
|
|
|
|
note.slideData.arrive.time.calcMsec(this);
|
|
|
|
|
note.slideData.targetNote = ConvertMirrorPosition(note.slideData.targetNote);
|
|
|
|
|
note.slideData.type = ConvertMirrorSlide(note.slideData.type);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-08 08:32:25 +02:00
|
|
|
|
#if DEBUG
|
2024-05-27 05:59:40 +02:00
|
|
|
|
System.Console.WriteLine("[MoreChartFormats] [Simai] Calculating chart data");
|
2024-08-08 08:32:25 +02:00
|
|
|
|
#endif
|
2024-05-27 05:59:40 +02:00
|
|
|
|
calcAll();
|
2024-05-27 06:43:33 +02:00
|
|
|
|
#if DEBUG
|
2024-05-27 05:59:40 +02:00
|
|
|
|
System.Console.WriteLine("[MoreChartFormats] [Simai] Loaded {0} notes", _total.GetAllNoteNum());
|
|
|
|
|
System.Console.WriteLine("[MoreChartFormats] [Simai] > {0} taps", _total.GetTapNum());
|
|
|
|
|
System.Console.WriteLine("[MoreChartFormats] [Simai] > {0} holds", _total.GetHoldNum());
|
|
|
|
|
System.Console.WriteLine("[MoreChartFormats] [Simai] > {0} slides", _total.GetSlideNum());
|
|
|
|
|
System.Console.WriteLine("[MoreChartFormats] [Simai] > {0} touches", _total.GetTouchNum());
|
|
|
|
|
System.Console.WriteLine("[MoreChartFormats] [Simai] > {0} break", _total.GetBreakNum());
|
2024-05-27 06:43:33 +02:00
|
|
|
|
#endif
|
2024-05-27 05:59:40 +02:00
|
|
|
|
}
|
|
|
|
|
catch (SimaiException e)
|
|
|
|
|
{
|
2024-05-27 06:43:33 +02:00
|
|
|
|
System.Console.WriteLine($"[MoreChartFormats] [Simai] There was an error loading the chart at line {e.line}, col {e.character}: {e} ");
|
2024-05-27 05:59:40 +02:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
2024-05-27 06:43:33 +02:00
|
|
|
|
System.Console.WriteLine($"[MoreChartFormats] [Simai] There was an error loading the chart: {e}");
|
2024-05-27 05:59:40 +02:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void fillDummyHeader(string fileName)
|
|
|
|
|
{
|
|
|
|
|
_header._notesName = fileName;
|
|
|
|
|
_header._resolutionTime = ReaderConst.DEFAULT_RESOLUTION_TIME;
|
|
|
|
|
_header._version[0].major = 0;
|
|
|
|
|
_header._version[0].minor = 0;
|
|
|
|
|
_header._version[0].release = 0;
|
|
|
|
|
_header._version[1].major = 1;
|
|
|
|
|
_header._version[1].minor = 4;
|
|
|
|
|
_header._version[0].release = 0;
|
|
|
|
|
_header._metInfo.denomi = 4;
|
|
|
|
|
_header._metInfo.num = 4;
|
|
|
|
|
_header._clickFirst = ReaderConst.DEFAULT_RESOLUTION_TIME;
|
|
|
|
|
|
|
|
|
|
// The game doesn't care if a non-fes-mode chart uses utage mechanics.
|
|
|
|
|
// It's just a flag.
|
|
|
|
|
_header._isFes = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void calcAll()
|
|
|
|
|
{
|
|
|
|
|
calcNoteTiming();
|
|
|
|
|
calcEach();
|
|
|
|
|
calcSlide();
|
|
|
|
|
calcEndTiming();
|
|
|
|
|
calcBPMInfo();
|
|
|
|
|
calcBarList();
|
|
|
|
|
calcSoflanList();
|
|
|
|
|
calcClickList();
|
|
|
|
|
calcTotal();
|
|
|
|
|
}
|
|
|
|
|
}
|