Merge branch 'rewrite/master' into feature/chart-editor-context-menus

This commit is contained in:
Cameron Taylor
2024-01-05 20:11:38 -05:00
32 changed files with 840 additions and 627 deletions
+88 -28
View File
@@ -4,6 +4,7 @@ import funkin.data.event.SongEventRegistry;
import funkin.data.event.SongEventSchema;
import funkin.data.song.SongRegistry;
import thx.semver.Version;
import funkin.util.tools.ICloneable;
/**
* Data containing information about a song.
@@ -11,7 +12,7 @@ import thx.semver.Version;
* Data which is only necessary in-game should be stored in the SongChartData.
*/
@:nullSafety
class SongMetadata
class SongMetadata implements ICloneable<SongMetadata>
{
/**
* A semantic versioning string for the song data format.
@@ -86,16 +87,16 @@ class SongMetadata
* @param newVariation Set to a new variation ID to change the new metadata.
* @return The cloned SongMetadata
*/
public function clone(?newVariation:String = null):SongMetadata
public function clone():SongMetadata
{
var result:SongMetadata = new SongMetadata(this.songName, this.artist, newVariation == null ? this.variation : newVariation);
var result:SongMetadata = new SongMetadata(this.songName, this.artist, this.variation);
result.version = this.version;
result.timeFormat = this.timeFormat;
result.divisions = this.divisions;
result.offsets = this.offsets;
result.timeChanges = this.timeChanges;
result.offsets = this.offsets.clone();
result.timeChanges = this.timeChanges.deepClone();
result.looped = this.looped;
result.playData = this.playData;
result.playData = this.playData.clone();
result.generatedBy = this.generatedBy;
return result;
@@ -130,7 +131,7 @@ enum abstract SongTimeFormat(String) from String to String
var MILLISECONDS = 'ms';
}
class SongTimeChange
class SongTimeChange implements ICloneable<SongTimeChange>
{
public static final DEFAULT_SONGTIMECHANGE:SongTimeChange = new SongTimeChange(0, 100);
@@ -151,7 +152,7 @@ class SongTimeChange
*/
@:optional
@:alias("b")
public var beatTime:Null<Float>;
public var beatTime:Float;
/**
* Quarter notes per minute (float). Cannot be empty in the first element of the list,
@@ -197,6 +198,11 @@ class SongTimeChange
this.beatTuplets = beatTuplets == null ? DEFAULT_BEAT_TUPLETS : beatTuplets;
}
public function clone():SongTimeChange
{
return new SongTimeChange(this.timeStamp, this.bpm, this.timeSignatureNum, this.timeSignatureDen, this.beatTime, this.beatTuplets);
}
/**
* Produces a string representation suitable for debugging.
*/
@@ -211,7 +217,7 @@ class SongTimeChange
* These are intended to correct for issues with the chart, or with the song's audio (for example a 10ms delay before the song starts).
* This is independent of the offsets applied in the user's settings, which are applied after these offsets and intended to correct for the user's hardware.
*/
class SongOffsets
class SongOffsets implements ICloneable<SongOffsets>
{
/**
* The offset, in milliseconds, to apply to the song's instrumental relative to the chart.
@@ -281,6 +287,15 @@ class SongOffsets
return value;
}
public function clone():SongOffsets
{
var result:SongOffsets = new SongOffsets(this.instrumental);
result.altInstrumentals = this.altInstrumentals.clone();
result.vocals = this.vocals.clone();
return result;
}
/**
* Produces a string representation suitable for debugging.
*/
@@ -294,7 +309,7 @@ class SongOffsets
* Metadata for a song only used for the music.
* For example, the menu music.
*/
class SongMusicData
class SongMusicData implements ICloneable<SongMusicData>
{
/**
* A semantic versioning string for the song data format.
@@ -348,13 +363,13 @@ class SongMusicData
this.variation = variation == null ? Constants.DEFAULT_VARIATION : variation;
}
public function clone(?newVariation:String = null):SongMusicData
public function clone():SongMusicData
{
var result:SongMusicData = new SongMusicData(this.songName, this.artist, newVariation == null ? this.variation : newVariation);
var result:SongMusicData = new SongMusicData(this.songName, this.artist, this.variation);
result.version = this.version;
result.timeFormat = this.timeFormat;
result.divisions = this.divisions;
result.timeChanges = this.timeChanges;
result.timeChanges = this.timeChanges.clone();
result.looped = this.looped;
result.generatedBy = this.generatedBy;
@@ -370,7 +385,7 @@ class SongMusicData
}
}
class SongPlayData
class SongPlayData implements ICloneable<SongPlayData>
{
/**
* The variations this song has. The associated metadata files should exist.
@@ -419,6 +434,20 @@ class SongPlayData
ratings = new Map<String, Int>();
}
public function clone():SongPlayData
{
var result:SongPlayData = new SongPlayData();
result.songVariations = this.songVariations.clone();
result.difficulties = this.difficulties.clone();
result.characters = this.characters.clone();
result.stage = this.stage;
result.noteStyle = this.noteStyle;
result.ratings = this.ratings.clone();
result.album = this.album;
return result;
}
/**
* Produces a string representation suitable for debugging.
*/
@@ -432,7 +461,7 @@ class SongPlayData
* Information about the characters used in this variation of the song.
* Create a new variation if you want to change the characters.
*/
class SongCharacterData
class SongCharacterData implements ICloneable<SongCharacterData>
{
@:optional
@:default('')
@@ -462,6 +491,14 @@ class SongCharacterData
this.instrumental = instrumental;
}
public function clone():SongCharacterData
{
var result:SongCharacterData = new SongCharacterData(this.player, this.girlfriend, this.opponent, this.instrumental);
result.altInstrumentals = this.altInstrumentals.clone();
return result;
}
/**
* Produces a string representation suitable for debugging.
*/
@@ -471,7 +508,7 @@ class SongCharacterData
}
}
class SongChartData
class SongChartData implements ICloneable<SongChartData>
{
@:default(funkin.data.song.SongRegistry.SONG_CHART_DATA_VERSION)
@:jcustomparse(funkin.data.DataParse.semverVersion)
@@ -541,6 +578,24 @@ class SongChartData
return writer.write(this, pretty ? ' ' : null);
}
public function clone():SongChartData
{
// We have to manually perform the deep clone here because Map.deepClone() doesn't work.
var noteDataClone:Map<String, Array<SongNoteData>> = new Map<String, Array<SongNoteData>>();
for (key in this.notes.keys())
{
noteDataClone.set(key, this.notes.get(key).deepClone());
}
var eventDataClone:Array<SongEventData> = this.events.deepClone();
var result:SongChartData = new SongChartData(this.scrollSpeed.clone(), eventDataClone, noteDataClone);
result.version = this.version;
result.generatedBy = this.generatedBy;
result.variation = this.variation;
return result;
}
/**
* Produces a string representation suitable for debugging.
*/
@@ -550,7 +605,7 @@ class SongChartData
}
}
class SongEventDataRaw
class SongEventDataRaw implements ICloneable<SongEventDataRaw>
{
/**
* The timestamp of the event. The timestamp is in the format of the song's time format.
@@ -604,14 +659,19 @@ class SongEventDataRaw
{
if (_stepTime != null && !force) return _stepTime;
return _stepTime = Conductor.getTimeInSteps(this.time);
return _stepTime = Conductor.instance.getTimeInSteps(this.time);
}
public function clone():SongEventDataRaw
{
return new SongEventDataRaw(this.time, this.event, this.value);
}
}
/**
* Wrap SongEventData in an abstract so we can overload operators.
*/
@:forward(time, event, value, activated, getStepTime)
@:forward(time, event, value, activated, getStepTime, clone)
abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataRaw
{
public function new(time:Float, event:String, value:Dynamic = null)
@@ -691,11 +751,6 @@ abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataR
return this.value == null ? null : cast Reflect.field(this.value, key);
}
public function clone():SongEventData
{
return new SongEventData(this.time, this.event, this.value);
}
@:op(A == B)
public function op_equals(other:SongEventData):Bool
{
@@ -741,7 +796,7 @@ abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataR
}
}
class SongNoteDataRaw
class SongNoteDataRaw implements ICloneable<SongNoteDataRaw>
{
/**
* The timestamp of the note. The timestamp is in the format of the song's time format.
@@ -825,7 +880,7 @@ class SongNoteDataRaw
{
if (_stepTime != null && !force) return _stepTime;
return _stepTime = Conductor.getTimeInSteps(this.time);
return _stepTime = Conductor.instance.getTimeInSteps(this.time);
}
@:jignored
@@ -841,7 +896,7 @@ class SongNoteDataRaw
if (_stepLength != null && !force) return _stepLength;
return _stepLength = Conductor.getTimeInSteps(this.time + this.length) - getStepTime();
return _stepLength = Conductor.instance.getTimeInSteps(this.time + this.length) - getStepTime();
}
public function setStepLength(value:Float):Void
@@ -852,11 +907,16 @@ class SongNoteDataRaw
}
else
{
var lengthMs:Float = Conductor.getStepTimeInMs(value) - this.time;
var lengthMs:Float = Conductor.instance.getStepTimeInMs(value) - this.time;
this.length = lengthMs;
}
_stepLength = null;
}
public function clone():SongNoteDataRaw
{
return new SongNoteDataRaw(this.time, this.data, this.length, this.kind);
}
}
/**