2024-01-03 21:10:14 -05:00
|
|
|
package funkin.data.event;
|
|
|
|
|
|
|
|
import funkin.play.event.SongEvent;
|
|
|
|
import funkin.data.event.SongEventSchema;
|
|
|
|
import funkin.data.song.SongData.SongEventData;
|
|
|
|
import funkin.util.macro.ClassMacro;
|
|
|
|
import funkin.play.event.ScriptedSongEvent;
|
|
|
|
|
2024-01-24 22:31:25 -05:00
|
|
|
@:forward(name, title, type, keys, min, max, step, units, defaultValue, iterator)
|
2024-01-03 21:10:14 -05:00
|
|
|
abstract SongEventSchema(SongEventSchemaRaw)
|
|
|
|
{
|
2024-02-02 22:38:34 -05:00
|
|
|
/**
|
|
|
|
* These units look better when placed immediately next to the value, rather than after a space.
|
|
|
|
*/
|
|
|
|
static final NO_SPACE_UNITS:Array<String> = ['x', '°', '%'];
|
|
|
|
|
2024-01-03 21:10:14 -05:00
|
|
|
public function new(?fields:Array<SongEventSchemaField>)
|
|
|
|
{
|
|
|
|
this = fields;
|
|
|
|
}
|
|
|
|
|
|
|
|
@:arrayAccess
|
2024-01-18 04:25:15 -05:00
|
|
|
public function getByName(name:String):SongEventSchemaField
|
2024-01-03 21:10:14 -05:00
|
|
|
{
|
|
|
|
for (field in this)
|
|
|
|
{
|
|
|
|
if (field.name == name) return field;
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getFirstField():SongEventSchemaField
|
|
|
|
{
|
|
|
|
return this[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
@:arrayAccess
|
|
|
|
public inline function get(key:Int)
|
|
|
|
{
|
|
|
|
return this[key];
|
|
|
|
}
|
|
|
|
|
|
|
|
@:arrayAccess
|
|
|
|
public inline function arrayWrite(k:Int, v:SongEventSchemaField):SongEventSchemaField
|
|
|
|
{
|
|
|
|
return this[k] = v;
|
|
|
|
}
|
2024-01-18 04:25:15 -05:00
|
|
|
|
2024-01-24 22:31:25 -05:00
|
|
|
public function stringifyFieldValue(name:String, value:Dynamic, addUnits:Bool = true):String
|
2024-01-18 04:25:15 -05:00
|
|
|
{
|
|
|
|
var field:SongEventSchemaField = getByName(name);
|
|
|
|
if (field == null) return 'Unknown';
|
|
|
|
|
|
|
|
switch (field.type)
|
|
|
|
{
|
|
|
|
case SongEventFieldType.STRING:
|
|
|
|
return Std.string(value);
|
|
|
|
case SongEventFieldType.INTEGER:
|
2024-01-24 22:31:25 -05:00
|
|
|
var returnValue:String = Std.string(value);
|
|
|
|
if (addUnits) return addUnitsToString(returnValue, field);
|
|
|
|
return returnValue;
|
2024-01-18 04:25:15 -05:00
|
|
|
case SongEventFieldType.FLOAT:
|
2024-01-24 22:31:25 -05:00
|
|
|
var returnValue:String = Std.string(value);
|
|
|
|
if (addUnits) return addUnitsToString(returnValue, field);
|
|
|
|
return returnValue;
|
2024-01-18 04:25:15 -05:00
|
|
|
case SongEventFieldType.BOOL:
|
|
|
|
return Std.string(value);
|
|
|
|
case SongEventFieldType.ENUM:
|
2024-01-24 22:31:25 -05:00
|
|
|
var valueString:String = Std.string(value);
|
2024-01-18 04:25:15 -05:00
|
|
|
for (key in field.keys.keys())
|
|
|
|
{
|
2024-01-24 22:31:25 -05:00
|
|
|
// Comparing these values as strings because comparing Dynamic variables is jank.
|
|
|
|
if (Std.string(field.keys.get(key)) == valueString) return key;
|
2024-01-18 04:25:15 -05:00
|
|
|
}
|
2024-01-24 22:31:25 -05:00
|
|
|
return valueString;
|
2024-01-18 04:25:15 -05:00
|
|
|
default:
|
|
|
|
return 'Unknown';
|
|
|
|
}
|
|
|
|
}
|
2024-01-24 22:31:25 -05:00
|
|
|
|
|
|
|
function addUnitsToString(value:String, field:SongEventSchemaField)
|
|
|
|
{
|
|
|
|
if (field.units == null || field.units == '') return value;
|
|
|
|
|
2024-01-26 20:51:36 -05:00
|
|
|
var unit:String = field.units;
|
|
|
|
|
2024-02-02 22:38:34 -05:00
|
|
|
return value + (NO_SPACE_UNITS.contains(unit) ? '' : ' ') + '${unit}';
|
2024-01-24 22:31:25 -05:00
|
|
|
}
|
2024-01-03 21:10:14 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
typedef SongEventSchemaRaw = Array<SongEventSchemaField>;
|
|
|
|
|
|
|
|
typedef SongEventSchemaField =
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* The name of the property as it should be saved in the event data.
|
|
|
|
*/
|
|
|
|
name:String,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The title of the field to display in the UI.
|
|
|
|
*/
|
|
|
|
title:String,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The type of the field.
|
|
|
|
*/
|
|
|
|
type:SongEventFieldType,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Used only for ENUM values.
|
|
|
|
* The key is the display name and the value is the actual value.
|
|
|
|
*/
|
|
|
|
?keys:Map<String, Dynamic>,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Used for INTEGER and FLOAT values.
|
|
|
|
* The minimum value that can be entered.
|
|
|
|
* @default No minimum
|
|
|
|
*/
|
|
|
|
?min:Float,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Used for INTEGER and FLOAT values.
|
|
|
|
* The maximum value that can be entered.
|
|
|
|
* @default No maximum
|
|
|
|
*/
|
|
|
|
?max:Float,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Used for INTEGER and FLOAT values.
|
|
|
|
* The step value that will be used when incrementing/decrementing the value.
|
|
|
|
* @default `0.1`
|
|
|
|
*/
|
|
|
|
?step:Float,
|
|
|
|
|
2024-01-24 22:31:25 -05:00
|
|
|
/**
|
|
|
|
* Used for INTEGER and FLOAT values.
|
|
|
|
* The units that the value is expressed in (pixels, percent, etc).
|
|
|
|
*/
|
|
|
|
?units:String,
|
|
|
|
|
2024-01-03 21:10:14 -05:00
|
|
|
/**
|
|
|
|
* An optional default value for the field.
|
|
|
|
*/
|
|
|
|
?defaultValue:Dynamic,
|
|
|
|
}
|
|
|
|
|
|
|
|
enum abstract SongEventFieldType(String) from String to String
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* The STRING type will display as a text field.
|
|
|
|
*/
|
|
|
|
var STRING = "string";
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The INTEGER type will display as a text field that only accepts numbers.
|
|
|
|
*/
|
|
|
|
var INTEGER = "integer";
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The FLOAT type will display as a text field that only accepts numbers.
|
|
|
|
*/
|
|
|
|
var FLOAT = "float";
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The BOOL type will display as a checkbox.
|
|
|
|
*/
|
|
|
|
var BOOL = "bool";
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The ENUM type will display as a dropdown.
|
|
|
|
* Make sure to specify the `keys` field in the schema.
|
|
|
|
*/
|
|
|
|
var ENUM = "enum";
|
|
|
|
}
|