Skip to content

Creating Score Format Plugins

George Wu edited this page Sep 23, 2017 · 2 revisions

Score format plugins allow MilliSim to read, write, and convert different score formats.

Background

For a single score, there may be many ways to represent and store its information.

For example, when porting CGSS (DereSute, デレステ) scores to MLTD (MiriSita, ミリシタ), where the latter is the superset of the former, it is a good practice to support both. However there are differences:

  • CGSS stores its scores in CSV texts; MLTD stores its scores in serialized MonoBehaviors.
  • CGSS packs its scores into SQLite databases; MLTD packs its scores into Unity3D Asset Bundles.
  • CGSS scores cannot be recovered to a editable state; MLTD scores can.

Moreover, since the original formats are game-targeted and game-exclusive, they are not user-friendly to community beatmap makers. Other simulators, like Deleste Simulator, have their own formats.

Concepts

To solve these problems, score objects are abstracted as a 2-phase model.

Phase 1 is source phase. Scores in this phase are easily editable (by other tools) and usually store more information, such as measure information, tempo instructions, author information, etc.

Phase 2 is compiled phase. Scores in this phase are optimized for playing and usually not easily recoverable. Irrelevant information is dropped out. All exact timestamps are calculated. Compiled scores are "compiled" from source scores, as executables are compiled from source code.

MilliSim plays only compiled scores. However if a score format supports being read and write as a source score, it will be a great advantage, because it can then be converted into other formats using MilliSim.

API Overview

Every score format plugin class implements OpenMLTD.MilliSim.Core.Entities.Extending.IScoreFormat interface. Then it should be marked with ExportAttribute. Example:

[Export(IScoreFormat)]
public class ExamplePlugin : IScoreFormat {
    // ...
}

For the members to be implemented, please see the interface definition and its XML document.

In the loading process, MilliSim will call its methods to determine if the file is supported by this format. If it is, MilliSim will try to load the score using this format. If all loading trials fail, the next format will be tested, and the whole loop starts all over again.

Whether a file is supported is determined by calling IScoreFormat.SupportsReadingFileType(). If the method returns true, MilliSim will look at IScoreFormat.CanReadAsSource property. If the latter is also true, MilliSim will call IScoreFormat.CreateReader() function to create an IScoreReader, and then IScoreReader.ReadSourceScore() to read the file as a source score. After retrieving the source score, MilliSim will call IScoreFormat.CreateCompiler() to create an IScoreCompiler to compile the source score to a compiled score. If IScoreFormat.CanReadAsSource returns false (e.g. CSV scores from CGSS), MilliSim will try IScoreFormat.CanReadAsCompiled. If it is true, then an IScoreReader will be created, and its IScoreReader.ReadCompiledScore() method will be called to directly reads the score as a compiled score.

Clone this wiki locally