2022-09-06 00:59:54 -04:00
|
|
|
package funkin.play.song;
|
|
|
|
|
2022-09-07 19:07:08 -04:00
|
|
|
import funkin.play.song.SongData.SongDataParser;
|
2022-09-16 15:37:00 -04:00
|
|
|
import funkin.play.song.SongData.SongEventData;
|
2022-09-07 19:07:08 -04:00
|
|
|
import funkin.play.song.SongData.SongMetadata;
|
2022-09-16 15:37:00 -04:00
|
|
|
import funkin.play.song.SongData.SongNoteData;
|
|
|
|
import funkin.play.song.SongData.SongPlayableChar;
|
2022-09-13 01:09:30 -04:00
|
|
|
import funkin.play.song.SongData.SongTimeChange;
|
|
|
|
import funkin.play.song.SongData.SongTimeFormat;
|
2022-09-07 19:07:08 -04:00
|
|
|
|
2022-09-06 00:59:54 -04:00
|
|
|
/**
|
|
|
|
* This is a data structure managing information about the current song.
|
|
|
|
* This structure is created when the game starts, and includes all the data
|
|
|
|
* from the `metadata.json` file.
|
|
|
|
* It also includes the chart data, but only when this is the currently loaded song.
|
|
|
|
*
|
|
|
|
* It also receives script events; scripted classes which extend this class
|
|
|
|
* can be used to perform custom gameplay behaviors only on specific songs.
|
|
|
|
*/
|
2022-09-07 19:07:08 -04:00
|
|
|
class Song // implements IPlayStateScriptedClass
|
2022-09-06 00:59:54 -04:00
|
|
|
{
|
2022-09-13 01:09:30 -04:00
|
|
|
public final songId:String;
|
2022-09-06 00:59:54 -04:00
|
|
|
|
2022-09-13 01:09:30 -04:00
|
|
|
final _metadata:Array<SongMetadata>;
|
2022-09-06 00:59:54 -04:00
|
|
|
|
2022-09-16 15:37:00 -04:00
|
|
|
final variations:Array<String>;
|
2022-09-13 01:09:30 -04:00
|
|
|
final difficulties:Map<String, SongDifficulty>;
|
2022-09-06 00:59:54 -04:00
|
|
|
|
|
|
|
public function new(id:String)
|
|
|
|
{
|
2022-09-07 19:07:08 -04:00
|
|
|
this.songId = id;
|
2022-09-06 00:59:54 -04:00
|
|
|
|
2022-09-16 15:37:00 -04:00
|
|
|
variations = [];
|
2022-09-13 01:09:30 -04:00
|
|
|
difficulties = new Map<String, SongDifficulty>();
|
|
|
|
|
2022-09-07 19:07:08 -04:00
|
|
|
_metadata = SongDataParser.parseSongMetadata(songId);
|
2022-09-13 01:09:30 -04:00
|
|
|
if (_metadata == null || _metadata.length == 0)
|
2022-09-06 00:59:54 -04:00
|
|
|
{
|
|
|
|
throw 'Could not find song data for songId: $songId';
|
|
|
|
}
|
2022-09-13 01:09:30 -04:00
|
|
|
|
|
|
|
populateFromMetadata();
|
2022-09-16 15:37:00 -04:00
|
|
|
|
|
|
|
// TODO: Disable later.
|
|
|
|
cacheCharts();
|
2022-09-13 01:09:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
function populateFromMetadata()
|
|
|
|
{
|
|
|
|
// Variations may have different artist, time format, generatedBy, etc.
|
|
|
|
for (metadata in _metadata)
|
|
|
|
{
|
|
|
|
for (diffId in metadata.playData.difficulties)
|
|
|
|
{
|
|
|
|
var difficulty = new SongDifficulty(diffId, metadata.variation);
|
|
|
|
|
2022-09-16 15:37:00 -04:00
|
|
|
variations.push(metadata.variation);
|
|
|
|
|
2022-09-13 01:09:30 -04:00
|
|
|
difficulty.songName = metadata.songName;
|
|
|
|
difficulty.songArtist = metadata.artist;
|
|
|
|
difficulty.timeFormat = metadata.timeFormat;
|
|
|
|
difficulty.divisions = metadata.divisions;
|
|
|
|
difficulty.timeChanges = metadata.timeChanges;
|
|
|
|
difficulty.loop = metadata.loop;
|
|
|
|
difficulty.generatedBy = metadata.generatedBy;
|
|
|
|
|
2022-09-16 15:37:00 -04:00
|
|
|
difficulty.stage = metadata.playData.stage;
|
|
|
|
// difficulty.noteSkin = metadata.playData.noteSkin;
|
|
|
|
|
|
|
|
difficulty.chars = new Map<String, SongPlayableChar>();
|
|
|
|
for (charId in metadata.playData.playableChars.keys())
|
|
|
|
{
|
|
|
|
var char = metadata.playData.playableChars.get(charId);
|
|
|
|
|
|
|
|
difficulty.chars.set(charId, char);
|
|
|
|
}
|
|
|
|
|
2022-09-13 01:09:30 -04:00
|
|
|
difficulties.set(diffId, difficulty);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse and cache the chart for all difficulties of this song.
|
|
|
|
*/
|
|
|
|
public function cacheCharts()
|
|
|
|
{
|
2022-09-16 15:37:00 -04:00
|
|
|
trace('Caching ${variations.length} chart files for song $songId');
|
|
|
|
for (variation in variations)
|
2022-09-13 01:09:30 -04:00
|
|
|
{
|
2022-09-16 15:37:00 -04:00
|
|
|
var chartData = SongDataParser.parseSongChartData(songId, variation);
|
|
|
|
|
|
|
|
for (diffId in chartData.notes.keys())
|
|
|
|
{
|
|
|
|
trace(' Difficulty $diffId');
|
|
|
|
var difficulty = difficulties.get(diffId);
|
|
|
|
if (difficulty == null)
|
|
|
|
{
|
|
|
|
trace('Could not find difficulty $diffId for song $songId');
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
difficulty.notes = chartData.notes.get(diffId);
|
|
|
|
difficulty.scrollSpeed = chartData.scrollSpeed.get(diffId);
|
|
|
|
difficulty.events = chartData.events;
|
|
|
|
}
|
2022-09-13 01:09:30 -04:00
|
|
|
}
|
2022-09-16 15:37:00 -04:00
|
|
|
trace('Done caching charts.');
|
2022-09-13 01:09:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve the metadata for a specific difficulty, including the chart if it is loaded.
|
|
|
|
*/
|
|
|
|
public function getDifficulty(diffId:String):SongDifficulty
|
|
|
|
{
|
|
|
|
return difficulties.get(diffId);
|
2022-09-06 00:59:54 -04:00
|
|
|
}
|
|
|
|
|
2022-09-13 01:09:30 -04:00
|
|
|
/**
|
|
|
|
* Purge the cached chart data for each difficulty of this song.
|
|
|
|
*/
|
|
|
|
public function clearCharts()
|
2022-09-06 00:59:54 -04:00
|
|
|
{
|
2022-09-13 01:09:30 -04:00
|
|
|
for (diff in difficulties)
|
|
|
|
{
|
|
|
|
diff.clearChart();
|
|
|
|
}
|
2022-09-06 00:59:54 -04:00
|
|
|
}
|
2022-09-07 19:07:08 -04:00
|
|
|
|
|
|
|
public function toString():String
|
|
|
|
{
|
|
|
|
return 'Song($songId)';
|
|
|
|
}
|
2022-09-06 00:59:54 -04:00
|
|
|
}
|
2022-09-13 01:09:30 -04:00
|
|
|
|
|
|
|
class SongDifficulty
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* The difficulty ID, such as `easy` or `hard`.
|
|
|
|
*/
|
|
|
|
public final difficulty:String;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The metadata file that contains this difficulty.
|
|
|
|
*/
|
|
|
|
public final variation:String;
|
|
|
|
|
|
|
|
public var songName:String = SongValidator.DEFAULT_SONGNAME;
|
|
|
|
public var songArtist:String = SongValidator.DEFAULT_ARTIST;
|
|
|
|
public var timeFormat:SongTimeFormat = SongValidator.DEFAULT_TIMEFORMAT;
|
|
|
|
public var divisions:Int = SongValidator.DEFAULT_DIVISIONS;
|
|
|
|
public var loop:Bool = SongValidator.DEFAULT_LOOP;
|
|
|
|
public var generatedBy:String = SongValidator.DEFAULT_GENERATEDBY;
|
|
|
|
|
|
|
|
public var timeChanges:Array<SongTimeChange> = [];
|
|
|
|
|
2022-09-16 15:37:00 -04:00
|
|
|
public var stage:String = SongValidator.DEFAULT_STAGE;
|
|
|
|
public var chars:Map<String, SongPlayableChar> = null;
|
2022-09-13 01:09:30 -04:00
|
|
|
|
2022-09-16 15:37:00 -04:00
|
|
|
public var scrollSpeed:Float = SongValidator.DEFAULT_SCROLLSPEED;
|
|
|
|
|
|
|
|
public var notes:Array<SongNoteData>;
|
|
|
|
public var events:Array<SongEventData>;
|
2022-09-13 01:09:30 -04:00
|
|
|
|
|
|
|
public function new(diffId:String, variation:String)
|
|
|
|
{
|
|
|
|
this.difficulty = diffId;
|
|
|
|
this.variation = variation;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function clearChart():Void
|
|
|
|
{
|
2022-09-16 15:37:00 -04:00
|
|
|
notes = null;
|
2022-09-13 01:09:30 -04:00
|
|
|
}
|
|
|
|
}
|