Funkin/source/funkin/play/song/Song.hx

176 lines
4.6 KiB
Haxe
Raw Normal View History

2022-09-06 00:59:54 -04:00
package funkin.play.song;
import funkin.play.song.SongData.SongDataParser;
2022-09-16 15:37:00 -04:00
import funkin.play.song.SongData.SongEventData;
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-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.
*/
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)
{
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>();
_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
}
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
}
}