Funkin/source/funkin/data/event/SongEventSchema.hx

176 lines
4.1 KiB
Haxe
Raw Normal View History

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;
@:forward(name, title, type, keys, min, max, step, units, defaultValue, iterator)
abstract SongEventSchema(SongEventSchemaRaw)
{
public function new(?fields:Array<SongEventSchemaField>)
{
this = fields;
}
@:arrayAccess
2024-01-18 04:25:15 -05:00
public function getByName(name:String):SongEventSchemaField
{
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
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:
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:
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:
var valueString:String = Std.string(value);
2024-01-18 04:25:15 -05:00
for (key in field.keys.keys())
{
// 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
}
return valueString;
2024-01-18 04:25:15 -05:00
default:
return 'Unknown';
}
}
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;
// These units look better when placed immediately next to the value, rather than after a space.
if (unit == 'x' || unit == '°') return value + '${unit}';
return value + ' ${unit}';
}
}
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,
/**
* Used for INTEGER and FLOAT values.
* The units that the value is expressed in (pixels, percent, etc).
*/
?units:String,
/**
* 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";
}