mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-11-27 01:55:52 -05:00
Merge branch 'rewrite/master' into feature/separate-character-vocal-volumes
This commit is contained in:
commit
ef11f89632
30 changed files with 483 additions and 630 deletions
4
hmm.json
4
hmm.json
|
@ -11,7 +11,7 @@
|
||||||
"name": "flixel",
|
"name": "flixel",
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"dir": null,
|
"dir": null,
|
||||||
"ref": "a83738673e7edbf8acba3a1426af284dfe6719fe",
|
"ref": "07c6018008801972d12275690fc144fcc22e3de6",
|
||||||
"url": "https://github.com/FunkinCrew/flixel"
|
"url": "https://github.com/FunkinCrew/flixel"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -37,7 +37,7 @@
|
||||||
"name": "flxanimate",
|
"name": "flxanimate",
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"dir": null,
|
"dir": null,
|
||||||
"ref": "d7c5621be742e2c98d523dfe5af7528835eaff1e",
|
"ref": "9bacdd6ea39f5e3a33b0f5dfb7bc583fe76060d4",
|
||||||
"url": "https://github.com/FunkinCrew/flxanimate"
|
"url": "https://github.com/FunkinCrew/flxanimate"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,11 +20,11 @@ import openfl.display.BitmapData;
|
||||||
import funkin.data.level.LevelRegistry;
|
import funkin.data.level.LevelRegistry;
|
||||||
import funkin.data.notestyle.NoteStyleRegistry;
|
import funkin.data.notestyle.NoteStyleRegistry;
|
||||||
import funkin.data.event.SongEventRegistry;
|
import funkin.data.event.SongEventRegistry;
|
||||||
|
import funkin.data.stage.StageRegistry;
|
||||||
import funkin.play.cutscene.dialogue.ConversationDataParser;
|
import funkin.play.cutscene.dialogue.ConversationDataParser;
|
||||||
import funkin.play.cutscene.dialogue.DialogueBoxDataParser;
|
import funkin.play.cutscene.dialogue.DialogueBoxDataParser;
|
||||||
import funkin.play.cutscene.dialogue.SpeakerDataParser;
|
import funkin.play.cutscene.dialogue.SpeakerDataParser;
|
||||||
import funkin.data.song.SongRegistry;
|
import funkin.data.song.SongRegistry;
|
||||||
import funkin.play.stage.StageData.StageDataParser;
|
|
||||||
import funkin.play.character.CharacterData.CharacterDataParser;
|
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||||
import funkin.modding.module.ModuleHandler;
|
import funkin.modding.module.ModuleHandler;
|
||||||
import funkin.ui.title.TitleState;
|
import funkin.ui.title.TitleState;
|
||||||
|
@ -217,8 +217,9 @@ class InitState extends FlxState
|
||||||
ConversationDataParser.loadConversationCache();
|
ConversationDataParser.loadConversationCache();
|
||||||
DialogueBoxDataParser.loadDialogueBoxCache();
|
DialogueBoxDataParser.loadDialogueBoxCache();
|
||||||
SpeakerDataParser.loadSpeakerCache();
|
SpeakerDataParser.loadSpeakerCache();
|
||||||
StageDataParser.loadStageCache();
|
StageRegistry.instance.loadEntries();
|
||||||
CharacterDataParser.loadCharacterCache();
|
CharacterDataParser.loadCharacterCache();
|
||||||
|
|
||||||
ModuleHandler.buildModuleCallbacks();
|
ModuleHandler.buildModuleCallbacks();
|
||||||
ModuleHandler.loadModuleCache();
|
ModuleHandler.loadModuleCache();
|
||||||
|
|
||||||
|
|
0
source/funkin/data/character/TODO.md
Normal file
0
source/funkin/data/character/TODO.md
Normal file
0
source/funkin/data/conversation/TODO.md
Normal file
0
source/funkin/data/conversation/TODO.md
Normal file
0
source/funkin/data/dialogue/TODO.md
Normal file
0
source/funkin/data/dialogue/TODO.md
Normal file
|
@ -7,9 +7,9 @@ import funkin.ui.story.ScriptedLevel;
|
||||||
class LevelRegistry extends BaseRegistry<Level, LevelData>
|
class LevelRegistry extends BaseRegistry<Level, LevelData>
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The current version string for the stage data format.
|
* The current version string for the level data format.
|
||||||
* Handle breaking changes by incrementing this value
|
* Handle breaking changes by incrementing this value
|
||||||
* and adding migration to the `migrateStageData()` function.
|
* and adding migration to the `migrateLevelData()` function.
|
||||||
*/
|
*/
|
||||||
public static final LEVEL_DATA_VERSION:thx.semver.Version = "1.0.0";
|
public static final LEVEL_DATA_VERSION:thx.semver.Version = "1.0.0";
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,7 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata>
|
||||||
variation = variation == null ? Constants.DEFAULT_VARIATION : variation;
|
variation = variation == null ? Constants.DEFAULT_VARIATION : variation;
|
||||||
|
|
||||||
var parser = new json2object.JsonParser<SongMetadata>();
|
var parser = new json2object.JsonParser<SongMetadata>();
|
||||||
parser.ignoreUnknownVariables = false;
|
parser.ignoreUnknownVariables = true;
|
||||||
|
|
||||||
switch (loadEntryMetadataFile(id, variation))
|
switch (loadEntryMetadataFile(id, variation))
|
||||||
{
|
{
|
||||||
|
@ -150,7 +150,7 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata>
|
||||||
variation = variation == null ? Constants.DEFAULT_VARIATION : variation;
|
variation = variation == null ? Constants.DEFAULT_VARIATION : variation;
|
||||||
|
|
||||||
var parser = new json2object.JsonParser<SongMetadata>();
|
var parser = new json2object.JsonParser<SongMetadata>();
|
||||||
parser.ignoreUnknownVariables = false;
|
parser.ignoreUnknownVariables = true;
|
||||||
parser.fromJson(contents, fileName);
|
parser.fromJson(contents, fileName);
|
||||||
|
|
||||||
if (parser.errors.length > 0)
|
if (parser.errors.length > 0)
|
||||||
|
@ -210,7 +210,7 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata>
|
||||||
variation = variation == null ? Constants.DEFAULT_VARIATION : variation;
|
variation = variation == null ? Constants.DEFAULT_VARIATION : variation;
|
||||||
|
|
||||||
var parser = new json2object.JsonParser<SongMetadata_v2_1_0>();
|
var parser = new json2object.JsonParser<SongMetadata_v2_1_0>();
|
||||||
parser.ignoreUnknownVariables = false;
|
parser.ignoreUnknownVariables = true;
|
||||||
|
|
||||||
switch (loadEntryMetadataFile(id, variation))
|
switch (loadEntryMetadataFile(id, variation))
|
||||||
{
|
{
|
||||||
|
@ -232,7 +232,7 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata>
|
||||||
variation = variation == null ? Constants.DEFAULT_VARIATION : variation;
|
variation = variation == null ? Constants.DEFAULT_VARIATION : variation;
|
||||||
|
|
||||||
var parser = new json2object.JsonParser<SongMetadata_v2_0_0>();
|
var parser = new json2object.JsonParser<SongMetadata_v2_0_0>();
|
||||||
parser.ignoreUnknownVariables = false;
|
parser.ignoreUnknownVariables = true;
|
||||||
|
|
||||||
switch (loadEntryMetadataFile(id, variation))
|
switch (loadEntryMetadataFile(id, variation))
|
||||||
{
|
{
|
||||||
|
@ -252,7 +252,7 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata>
|
||||||
function parseEntryMetadataRaw_v2_1_0(contents:String, ?fileName:String = 'raw'):Null<SongMetadata>
|
function parseEntryMetadataRaw_v2_1_0(contents:String, ?fileName:String = 'raw'):Null<SongMetadata>
|
||||||
{
|
{
|
||||||
var parser = new json2object.JsonParser<SongMetadata_v2_1_0>();
|
var parser = new json2object.JsonParser<SongMetadata_v2_1_0>();
|
||||||
parser.ignoreUnknownVariables = false;
|
parser.ignoreUnknownVariables = true;
|
||||||
parser.fromJson(contents, fileName);
|
parser.fromJson(contents, fileName);
|
||||||
|
|
||||||
if (parser.errors.length > 0)
|
if (parser.errors.length > 0)
|
||||||
|
@ -266,7 +266,7 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata>
|
||||||
function parseEntryMetadataRaw_v2_0_0(contents:String, ?fileName:String = 'raw'):Null<SongMetadata>
|
function parseEntryMetadataRaw_v2_0_0(contents:String, ?fileName:String = 'raw'):Null<SongMetadata>
|
||||||
{
|
{
|
||||||
var parser = new json2object.JsonParser<SongMetadata_v2_0_0>();
|
var parser = new json2object.JsonParser<SongMetadata_v2_0_0>();
|
||||||
parser.ignoreUnknownVariables = false;
|
parser.ignoreUnknownVariables = true;
|
||||||
parser.fromJson(contents, fileName);
|
parser.fromJson(contents, fileName);
|
||||||
|
|
||||||
if (parser.errors.length > 0)
|
if (parser.errors.length > 0)
|
||||||
|
@ -347,7 +347,7 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata>
|
||||||
variation = variation == null ? Constants.DEFAULT_VARIATION : variation;
|
variation = variation == null ? Constants.DEFAULT_VARIATION : variation;
|
||||||
|
|
||||||
var parser = new json2object.JsonParser<SongChartData>();
|
var parser = new json2object.JsonParser<SongChartData>();
|
||||||
parser.ignoreUnknownVariables = false;
|
parser.ignoreUnknownVariables = true;
|
||||||
|
|
||||||
switch (loadEntryChartFile(id, variation))
|
switch (loadEntryChartFile(id, variation))
|
||||||
{
|
{
|
||||||
|
@ -370,7 +370,7 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata>
|
||||||
variation = variation == null ? Constants.DEFAULT_VARIATION : variation;
|
variation = variation == null ? Constants.DEFAULT_VARIATION : variation;
|
||||||
|
|
||||||
var parser = new json2object.JsonParser<SongChartData>();
|
var parser = new json2object.JsonParser<SongChartData>();
|
||||||
parser.ignoreUnknownVariables = false;
|
parser.ignoreUnknownVariables = true;
|
||||||
parser.fromJson(contents, fileName);
|
parser.fromJson(contents, fileName);
|
||||||
|
|
||||||
if (parser.errors.length > 0)
|
if (parser.errors.length > 0)
|
||||||
|
|
0
source/funkin/data/speaker/TODO.md
Normal file
0
source/funkin/data/speaker/TODO.md
Normal file
199
source/funkin/data/stage/StageData.hx
Normal file
199
source/funkin/data/stage/StageData.hx
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
package funkin.data.stage;
|
||||||
|
|
||||||
|
import funkin.data.animation.AnimationData;
|
||||||
|
|
||||||
|
@:nullSafety
|
||||||
|
class StageData
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The sematic version number of the stage data JSON format.
|
||||||
|
* Supports fancy comparisons like NPM does it's neat.
|
||||||
|
*/
|
||||||
|
@:default(funkin.data.stage.StageRegistry.STAGE_DATA_VERSION)
|
||||||
|
public var version:String;
|
||||||
|
|
||||||
|
public var name:String = 'Unknown';
|
||||||
|
public var props:Array<StageDataProp> = [];
|
||||||
|
public var characters:StageDataCharacters;
|
||||||
|
|
||||||
|
@:default(1.0)
|
||||||
|
@:optional
|
||||||
|
public var cameraZoom:Null<Float>;
|
||||||
|
|
||||||
|
public function new()
|
||||||
|
{
|
||||||
|
this.version = StageRegistry.STAGE_DATA_VERSION;
|
||||||
|
this.characters = makeDefaultCharacters();
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeDefaultCharacters():StageDataCharacters
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
bf:
|
||||||
|
{
|
||||||
|
zIndex: 0,
|
||||||
|
position: [0, 0],
|
||||||
|
cameraOffsets: [-100, -100]
|
||||||
|
},
|
||||||
|
dad:
|
||||||
|
{
|
||||||
|
zIndex: 0,
|
||||||
|
position: [0, 0],
|
||||||
|
cameraOffsets: [100, -100]
|
||||||
|
},
|
||||||
|
gf:
|
||||||
|
{
|
||||||
|
zIndex: 0,
|
||||||
|
position: [0, 0],
|
||||||
|
cameraOffsets: [0, 0]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert this StageData into a JSON string.
|
||||||
|
*/
|
||||||
|
public function serialize(pretty:Bool = true):String
|
||||||
|
{
|
||||||
|
var writer = new json2object.JsonWriter<StageData>();
|
||||||
|
return writer.write(this, pretty ? ' ' : null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef StageDataCharacters =
|
||||||
|
{
|
||||||
|
var bf:StageDataCharacter;
|
||||||
|
var dad:StageDataCharacter;
|
||||||
|
var gf:StageDataCharacter;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef StageDataProp =
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name of the prop for later lookup by scripts.
|
||||||
|
* Optional; if unspecified, the prop can't be referenced by scripts.
|
||||||
|
*/
|
||||||
|
@:optional
|
||||||
|
var name:String;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The asset used to display the prop.
|
||||||
|
* NOTE: As of Stage data v1.0.1, you can also use a color here to create a rectangle, like "#ff0000".
|
||||||
|
* In this case, the `scale` property will be used to determine the size of the prop.
|
||||||
|
*/
|
||||||
|
var assetPath:String;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The position of the prop as an [x, y] array of two floats.
|
||||||
|
*/
|
||||||
|
var position:Array<Float>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A number determining the stack order of the prop, relative to other props and the characters in the stage.
|
||||||
|
* Props with lower numbers render below those with higher numbers.
|
||||||
|
* This is just like CSS, it isn't hard.
|
||||||
|
* @default 0
|
||||||
|
*/
|
||||||
|
@:optional
|
||||||
|
@:default(0)
|
||||||
|
var zIndex:Int;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set to true, anti-aliasing will be forcibly disabled on the sprite.
|
||||||
|
* This prevents blurry images on pixel-art levels.
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
@:optional
|
||||||
|
@:default(false)
|
||||||
|
var isPixel:Bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Either the scale of the prop as a float, or the [w, h] scale as an array of two floats.
|
||||||
|
* Pro tip: On pixel-art levels, save the sprite small and set this value to 6 or so to save memory.
|
||||||
|
*/
|
||||||
|
@:jcustomparse(funkin.data.DataParse.eitherFloatOrFloats)
|
||||||
|
@:jcustomwrite(funkin.data.DataWrite.eitherFloatOrFloats)
|
||||||
|
@:optional
|
||||||
|
var scale:haxe.ds.Either<Float, Array<Float>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The alpha of the prop, as a float.
|
||||||
|
* @default 1.0
|
||||||
|
*/
|
||||||
|
@:optional
|
||||||
|
@:default(1.0)
|
||||||
|
var alpha:Float;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If not zero, this prop will play an animation every X beats of the song.
|
||||||
|
* This requires animations to be defined. If `danceLeft` and `danceRight` are defined,
|
||||||
|
* they will alternated between, otherwise the `idle` animation will be used.
|
||||||
|
*
|
||||||
|
* @default 0
|
||||||
|
*/
|
||||||
|
@:default(0)
|
||||||
|
@:optional
|
||||||
|
var danceEvery:Int;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How much the prop scrolls relative to the camera. Used to create a parallax effect.
|
||||||
|
* Represented as an [x, y] array of two floats.
|
||||||
|
* [1, 1] means the prop moves 1:1 with the camera.
|
||||||
|
* [0.5, 0.5] means the prop half as much as the camera.
|
||||||
|
* [0, 0] means the prop is not moved.
|
||||||
|
* @default [0, 0]
|
||||||
|
*/
|
||||||
|
@:optional
|
||||||
|
@:default([0, 0])
|
||||||
|
var scroll:Array<Float>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An optional array of animations which the prop can play.
|
||||||
|
* @default Prop has no animations.
|
||||||
|
*/
|
||||||
|
@:optional
|
||||||
|
@:default([])
|
||||||
|
var animations:Array<AnimationData>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If animations are used, this is the name of the animation to play first.
|
||||||
|
* @default Don't play an animation.
|
||||||
|
*/
|
||||||
|
@:optional
|
||||||
|
var startingAnimation:Null<String>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The animation type to use.
|
||||||
|
* Options: "sparrow", "packer"
|
||||||
|
* @default "sparrow"
|
||||||
|
*/
|
||||||
|
@:default("sparrow")
|
||||||
|
@:optional
|
||||||
|
var animType:String;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef StageDataCharacter =
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* A number determining the stack order of the character, relative to props and other characters in the stage.
|
||||||
|
* Again, just like CSS.
|
||||||
|
* @default 0
|
||||||
|
*/
|
||||||
|
@:optional
|
||||||
|
@:default(0)
|
||||||
|
var zIndex:Int;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The position to render the character at.
|
||||||
|
*/
|
||||||
|
@:optional
|
||||||
|
@:default([0, 0])
|
||||||
|
var position:Array<Float>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The camera offsets to apply when focusing on the character on this stage.
|
||||||
|
* @default [-100, -100] for BF, [100, -100] for DAD/OPPONENT, [0, 0] for GF
|
||||||
|
*/
|
||||||
|
@:optional
|
||||||
|
var cameraOffsets:Array<Float>;
|
||||||
|
};
|
103
source/funkin/data/stage/StageRegistry.hx
Normal file
103
source/funkin/data/stage/StageRegistry.hx
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
package funkin.data.stage;
|
||||||
|
|
||||||
|
import funkin.data.stage.StageData;
|
||||||
|
import funkin.play.stage.Stage;
|
||||||
|
import funkin.play.stage.ScriptedStage;
|
||||||
|
|
||||||
|
class StageRegistry extends BaseRegistry<Stage, StageData>
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The current version string for the stage data format.
|
||||||
|
* Handle breaking changes by incrementing this value
|
||||||
|
* and adding migration to the `migrateStageData()` function.
|
||||||
|
*/
|
||||||
|
public static final STAGE_DATA_VERSION:thx.semver.Version = "1.0.1";
|
||||||
|
|
||||||
|
public static final STAGE_DATA_VERSION_RULE:thx.semver.VersionRule = "1.0.x";
|
||||||
|
|
||||||
|
public static final instance:StageRegistry = new StageRegistry();
|
||||||
|
|
||||||
|
public function new()
|
||||||
|
{
|
||||||
|
super('STAGE', 'stages', STAGE_DATA_VERSION_RULE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read, parse, and validate the JSON data and produce the corresponding data object.
|
||||||
|
*/
|
||||||
|
public function parseEntryData(id:String):Null<StageData>
|
||||||
|
{
|
||||||
|
// JsonParser does not take type parameters,
|
||||||
|
// otherwise this function would be in BaseRegistry.
|
||||||
|
var parser = new json2object.JsonParser<StageData>();
|
||||||
|
parser.ignoreUnknownVariables = false;
|
||||||
|
|
||||||
|
switch (loadEntryFile(id))
|
||||||
|
{
|
||||||
|
case {fileName: fileName, contents: contents}:
|
||||||
|
parser.fromJson(contents, fileName);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser.errors.length > 0)
|
||||||
|
{
|
||||||
|
printErrors(parser.errors, id);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return parser.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse and validate the JSON data and produce the corresponding data object.
|
||||||
|
*
|
||||||
|
* NOTE: Must be implemented on the implementation class.
|
||||||
|
* @param contents The JSON as a string.
|
||||||
|
* @param fileName An optional file name for error reporting.
|
||||||
|
*/
|
||||||
|
public function parseEntryDataRaw(contents:String, ?fileName:String):Null<StageData>
|
||||||
|
{
|
||||||
|
var parser = new json2object.JsonParser<StageData>();
|
||||||
|
parser.ignoreUnknownVariables = false;
|
||||||
|
parser.fromJson(contents, fileName);
|
||||||
|
|
||||||
|
if (parser.errors.length > 0)
|
||||||
|
{
|
||||||
|
printErrors(parser.errors, fileName);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return parser.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createScriptedEntry(clsName:String):Stage
|
||||||
|
{
|
||||||
|
return ScriptedStage.init(clsName, "unknown");
|
||||||
|
}
|
||||||
|
|
||||||
|
function getScriptedClassNames():Array<String>
|
||||||
|
{
|
||||||
|
return ScriptedStage.listScriptClasses();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of all the stages from the base game, in order.
|
||||||
|
* TODO: Should this be hardcoded?
|
||||||
|
*/
|
||||||
|
public function listBaseGameStageIds():Array<String>
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
"mainStage", "spookyMansion", "phillyTrain", "limoRide", "mallXmas", "mallEvil", "school", "schoolEvil", "tankmanBattlefield", "phillyStreets",
|
||||||
|
"phillyBlazin",
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of all installed story weeks that are not from the base game.
|
||||||
|
*/
|
||||||
|
public function listModdedStageIds():Array<String>
|
||||||
|
{
|
||||||
|
return listEntryIds().filter(function(id:String):Bool {
|
||||||
|
return listBaseGameStageIds().indexOf(id) == -1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
53
source/funkin/graphics/FunkinSprite.hx
Normal file
53
source/funkin/graphics/FunkinSprite.hx
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
package funkin.graphics;
|
||||||
|
|
||||||
|
import flixel.FlxSprite;
|
||||||
|
import flixel.util.FlxColor;
|
||||||
|
import flixel.graphics.FlxGraphic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An FlxSprite with additional functionality.
|
||||||
|
*/
|
||||||
|
class FunkinSprite extends FlxSprite
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param x Starting X position
|
||||||
|
* @param y Starting Y position
|
||||||
|
*/
|
||||||
|
public function new(?x:Float = 0, ?y:Float = 0)
|
||||||
|
{
|
||||||
|
super(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acts similarly to `makeGraphic`, but with improved memory usage,
|
||||||
|
* at the expense of not being able to paint onto the sprite.
|
||||||
|
*
|
||||||
|
* @param width The target width of the sprite.
|
||||||
|
* @param height The target height of the sprite.
|
||||||
|
* @param color The color to fill the sprite with.
|
||||||
|
*/
|
||||||
|
public function makeSolidColor(width:Int, height:Int, color:FlxColor = FlxColor.WHITE):FunkinSprite
|
||||||
|
{
|
||||||
|
var graphic:FlxGraphic = FlxG.bitmap.create(2, 2, color, false, 'solid#${color.toHexString(true, false)}');
|
||||||
|
frames = graphic.imageFrame;
|
||||||
|
scale.set(width / 2, height / 2);
|
||||||
|
updateHitbox();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure scale is applied when cloning a sprite.
|
||||||
|
* The default `clone()` method acts kinda weird TBH.
|
||||||
|
* @return A clone of this sprite.
|
||||||
|
*/
|
||||||
|
public override function clone():FunkinSprite
|
||||||
|
{
|
||||||
|
var result = new FunkinSprite(this.x, this.y);
|
||||||
|
result.frames = this.frames;
|
||||||
|
result.scale.set(this.scale.x, this.scale.y);
|
||||||
|
result.updateHitbox();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,11 +4,12 @@ import funkin.util.macro.ClassMacro;
|
||||||
import funkin.modding.module.ModuleHandler;
|
import funkin.modding.module.ModuleHandler;
|
||||||
import funkin.play.character.CharacterData.CharacterDataParser;
|
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||||
import funkin.data.song.SongData;
|
import funkin.data.song.SongData;
|
||||||
import funkin.play.stage.StageData;
|
import funkin.data.stage.StageData;
|
||||||
import polymod.Polymod;
|
import polymod.Polymod;
|
||||||
import polymod.backends.PolymodAssets.PolymodAssetType;
|
import polymod.backends.PolymodAssets.PolymodAssetType;
|
||||||
import polymod.format.ParseRules.TextFileFormat;
|
import polymod.format.ParseRules.TextFileFormat;
|
||||||
import funkin.data.event.SongEventRegistry;
|
import funkin.data.event.SongEventRegistry;
|
||||||
|
import funkin.data.stage.StageRegistry;
|
||||||
import funkin.util.FileUtil;
|
import funkin.util.FileUtil;
|
||||||
import funkin.data.level.LevelRegistry;
|
import funkin.data.level.LevelRegistry;
|
||||||
import funkin.data.notestyle.NoteStyleRegistry;
|
import funkin.data.notestyle.NoteStyleRegistry;
|
||||||
|
@ -275,7 +276,7 @@ class PolymodHandler
|
||||||
ConversationDataParser.loadConversationCache();
|
ConversationDataParser.loadConversationCache();
|
||||||
DialogueBoxDataParser.loadDialogueBoxCache();
|
DialogueBoxDataParser.loadDialogueBoxCache();
|
||||||
SpeakerDataParser.loadSpeakerCache();
|
SpeakerDataParser.loadSpeakerCache();
|
||||||
StageDataParser.loadStageCache();
|
StageRegistry.instance.loadEntries();
|
||||||
CharacterDataParser.loadCharacterCache();
|
CharacterDataParser.loadCharacterCache();
|
||||||
ModuleHandler.loadModuleCache();
|
ModuleHandler.loadModuleCache();
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import flixel.sound.FlxSound;
|
||||||
import funkin.ui.story.StoryMenuState;
|
import funkin.ui.story.StoryMenuState;
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
import flixel.util.FlxTimer;
|
import flixel.util.FlxTimer;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
import funkin.ui.MusicBeatSubState;
|
import funkin.ui.MusicBeatSubState;
|
||||||
import funkin.modding.events.ScriptEvent;
|
import funkin.modding.events.ScriptEvent;
|
||||||
import funkin.modding.events.ScriptEventDispatcher;
|
import funkin.modding.events.ScriptEventDispatcher;
|
||||||
|
@ -94,7 +95,7 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
//
|
//
|
||||||
|
|
||||||
// Add a black background to the screen.
|
// Add a black background to the screen.
|
||||||
var bg = new FlxSprite().makeGraphic(FlxG.width * 2, FlxG.height * 2, FlxColor.BLACK);
|
var bg = new FunkinSprite().makeSolidColor(FlxG.width * 2, FlxG.height * 2, FlxColor.BLACK);
|
||||||
// We make this transparent so that we can see the stage underneath during debugging,
|
// We make this transparent so that we can see the stage underneath during debugging,
|
||||||
// but it's normally opaque.
|
// but it's normally opaque.
|
||||||
bg.alpha = transparent ? 0.25 : 1.0;
|
bg.alpha = transparent ? 0.25 : 1.0;
|
||||||
|
|
|
@ -50,11 +50,11 @@ import funkin.play.notes.SustainTrail;
|
||||||
import funkin.play.scoring.Scoring;
|
import funkin.play.scoring.Scoring;
|
||||||
import funkin.play.song.Song;
|
import funkin.play.song.Song;
|
||||||
import funkin.data.song.SongRegistry;
|
import funkin.data.song.SongRegistry;
|
||||||
|
import funkin.data.stage.StageRegistry;
|
||||||
import funkin.data.song.SongData.SongEventData;
|
import funkin.data.song.SongData.SongEventData;
|
||||||
import funkin.data.song.SongData.SongNoteData;
|
import funkin.data.song.SongData.SongNoteData;
|
||||||
import funkin.data.song.SongData.SongCharacterData;
|
import funkin.data.song.SongData.SongCharacterData;
|
||||||
import funkin.play.stage.Stage;
|
import funkin.play.stage.Stage;
|
||||||
import funkin.play.stage.StageData.StageDataParser;
|
|
||||||
import funkin.ui.transition.LoadingState;
|
import funkin.ui.transition.LoadingState;
|
||||||
import funkin.play.components.PopUpStuff;
|
import funkin.play.components.PopUpStuff;
|
||||||
import funkin.ui.options.PreferencesMenu;
|
import funkin.ui.options.PreferencesMenu;
|
||||||
|
@ -1353,7 +1353,7 @@ class PlayState extends MusicBeatSubState
|
||||||
*/
|
*/
|
||||||
function loadStage(id:String):Void
|
function loadStage(id:String):Void
|
||||||
{
|
{
|
||||||
currentStage = StageDataParser.fetchStage(id);
|
currentStage = StageRegistry.instance.fetchEntry(id);
|
||||||
|
|
||||||
if (currentStage != null)
|
if (currentStage != null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,6 +9,7 @@ import flixel.math.FlxMath;
|
||||||
import flixel.math.FlxPoint.FlxCallbackPoint;
|
import flixel.math.FlxPoint.FlxCallbackPoint;
|
||||||
import flixel.math.FlxPoint;
|
import flixel.math.FlxPoint;
|
||||||
import flixel.math.FlxRect;
|
import flixel.math.FlxRect;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
import flixel.system.FlxAssets.FlxGraphicAsset;
|
import flixel.system.FlxAssets.FlxGraphicAsset;
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
import flixel.util.FlxDestroyUtil;
|
import flixel.util.FlxDestroyUtil;
|
||||||
|
@ -621,7 +622,7 @@ class AnimateAtlasCharacter extends BaseCharacter
|
||||||
* This functionality isn't supported in SpriteGroup
|
* This functionality isn't supported in SpriteGroup
|
||||||
* @return this sprite group
|
* @return this sprite group
|
||||||
*/
|
*/
|
||||||
public override function loadGraphicFromSprite(Sprite:FlxSprite):FlxSprite
|
public override function loadGraphicFromSprite(Sprite:FlxSprite):FunkinSprite
|
||||||
{
|
{
|
||||||
#if FLX_DEBUG
|
#if FLX_DEBUG
|
||||||
throw "This function is not supported in FlxSpriteGroup";
|
throw "This function is not supported in FlxSpriteGroup";
|
||||||
|
|
|
@ -5,13 +5,16 @@ import flixel.group.FlxSpriteGroup;
|
||||||
import flixel.math.FlxPoint;
|
import flixel.math.FlxPoint;
|
||||||
import flixel.system.FlxAssets.FlxShader;
|
import flixel.system.FlxAssets.FlxShader;
|
||||||
import flixel.util.FlxSort;
|
import flixel.util.FlxSort;
|
||||||
|
import flixel.util.FlxColor;
|
||||||
import funkin.modding.IScriptedClass;
|
import funkin.modding.IScriptedClass;
|
||||||
import funkin.modding.events.ScriptEvent;
|
import funkin.modding.events.ScriptEvent;
|
||||||
import funkin.modding.events.ScriptEventType;
|
import funkin.modding.events.ScriptEventType;
|
||||||
import funkin.modding.events.ScriptEventDispatcher;
|
import funkin.modding.events.ScriptEventDispatcher;
|
||||||
import funkin.play.character.BaseCharacter;
|
import funkin.play.character.BaseCharacter;
|
||||||
import funkin.play.stage.StageData.StageDataCharacter;
|
import funkin.data.IRegistryEntry;
|
||||||
import funkin.play.stage.StageData.StageDataParser;
|
import funkin.data.stage.StageData;
|
||||||
|
import funkin.data.stage.StageData.StageDataCharacter;
|
||||||
|
import funkin.data.stage.StageRegistry;
|
||||||
import funkin.play.stage.StageProp;
|
import funkin.play.stage.StageProp;
|
||||||
import funkin.util.SortUtil;
|
import funkin.util.SortUtil;
|
||||||
import funkin.util.assets.FlxAnimationUtil;
|
import funkin.util.assets.FlxAnimationUtil;
|
||||||
|
@ -23,14 +26,25 @@ typedef StagePropGroup = FlxTypedSpriteGroup<StageProp>;
|
||||||
*
|
*
|
||||||
* A Stage is comprised of one or more props, each of which is a FlxSprite.
|
* A Stage is comprised of one or more props, each of which is a FlxSprite.
|
||||||
*/
|
*/
|
||||||
class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
|
class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass implements IRegistryEntry<StageData>
|
||||||
{
|
{
|
||||||
public final stageId:String;
|
public final id:String;
|
||||||
public final stageName:String;
|
|
||||||
|
|
||||||
final _data:StageData;
|
public final _data:StageData;
|
||||||
|
|
||||||
public var camZoom:Float = 1.0;
|
public var stageName(get, never):String;
|
||||||
|
|
||||||
|
function get_stageName():String
|
||||||
|
{
|
||||||
|
return _data?.name ?? 'Unknown';
|
||||||
|
}
|
||||||
|
|
||||||
|
public var camZoom(get, never):Float;
|
||||||
|
|
||||||
|
function get_camZoom():Float
|
||||||
|
{
|
||||||
|
return _data?.cameraZoom ?? 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
var namedProps:Map<String, StageProp> = new Map<String, StageProp>();
|
var namedProps:Map<String, StageProp> = new Map<String, StageProp>();
|
||||||
var characters:Map<String, BaseCharacter> = new Map<String, BaseCharacter>();
|
var characters:Map<String, BaseCharacter> = new Map<String, BaseCharacter>();
|
||||||
|
@ -41,21 +55,18 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
|
||||||
* They're used to cache the data needed to build the stage,
|
* They're used to cache the data needed to build the stage,
|
||||||
* then accessed and fleshed out when the stage needs to be built.
|
* then accessed and fleshed out when the stage needs to be built.
|
||||||
*
|
*
|
||||||
* @param stageId
|
* @param id
|
||||||
*/
|
*/
|
||||||
public function new(stageId:String)
|
public function new(id:String)
|
||||||
{
|
{
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.stageId = stageId;
|
this.id = id;
|
||||||
_data = StageDataParser.parseStageData(this.stageId);
|
_data = _fetchData(id);
|
||||||
|
|
||||||
if (_data == null)
|
if (_data == null)
|
||||||
{
|
{
|
||||||
throw 'Could not find stage data for stageId: $stageId';
|
throw 'Could not find stage data for stage id: $id';
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.stageName = _data.name;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,9 +140,7 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
|
||||||
*/
|
*/
|
||||||
function buildStage():Void
|
function buildStage():Void
|
||||||
{
|
{
|
||||||
trace('Building stage for display: ${this.stageId}');
|
trace('Building stage for display: ${this.id}');
|
||||||
|
|
||||||
this.camZoom = _data.cameraZoom;
|
|
||||||
|
|
||||||
this.debugIconGroup = new FlxSpriteGroup();
|
this.debugIconGroup = new FlxSpriteGroup();
|
||||||
|
|
||||||
|
@ -139,6 +148,7 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
|
||||||
{
|
{
|
||||||
trace(' Placing prop: ${dataProp.name} (${dataProp.assetPath})');
|
trace(' Placing prop: ${dataProp.name} (${dataProp.assetPath})');
|
||||||
|
|
||||||
|
var isSolidColor = dataProp.assetPath.startsWith('#');
|
||||||
var isAnimated = dataProp.animations.length > 0;
|
var isAnimated = dataProp.animations.length > 0;
|
||||||
|
|
||||||
var propSprite:StageProp;
|
var propSprite:StageProp;
|
||||||
|
@ -162,6 +172,22 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
|
||||||
propSprite.frames = Paths.getSparrowAtlas(dataProp.assetPath);
|
propSprite.frames = Paths.getSparrowAtlas(dataProp.assetPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (isSolidColor)
|
||||||
|
{
|
||||||
|
var width:Int = 1;
|
||||||
|
var height:Int = 1;
|
||||||
|
switch (dataProp.scale)
|
||||||
|
{
|
||||||
|
case Left(value):
|
||||||
|
width = Std.int(value);
|
||||||
|
height = Std.int(value);
|
||||||
|
|
||||||
|
case Right(values):
|
||||||
|
width = Std.int(values[0]);
|
||||||
|
height = Std.int(values[1]);
|
||||||
|
}
|
||||||
|
propSprite.makeSolidColor(width, height, FlxColor.fromString(dataProp.assetPath));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Initalize static sprite.
|
// Initalize static sprite.
|
||||||
|
@ -177,13 +203,16 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (dataProp.scale)
|
if (!isSolidColor)
|
||||||
{
|
{
|
||||||
case Left(value):
|
switch (dataProp.scale)
|
||||||
propSprite.scale.set(value);
|
{
|
||||||
|
case Left(value):
|
||||||
|
propSprite.scale.set(value);
|
||||||
|
|
||||||
case Right(values):
|
case Right(values):
|
||||||
propSprite.scale.set(values[0], values[1]);
|
propSprite.scale.set(values[0], values[1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
propSprite.updateHitbox();
|
propSprite.updateHitbox();
|
||||||
|
|
||||||
|
@ -195,15 +224,8 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
|
||||||
// If pixel, disable antialiasing.
|
// If pixel, disable antialiasing.
|
||||||
propSprite.antialiasing = !dataProp.isPixel;
|
propSprite.antialiasing = !dataProp.isPixel;
|
||||||
|
|
||||||
switch (dataProp.scroll)
|
propSprite.scrollFactor.x = dataProp.scroll[0];
|
||||||
{
|
propSprite.scrollFactor.y = dataProp.scroll[1];
|
||||||
case Left(value):
|
|
||||||
propSprite.scrollFactor.x = value;
|
|
||||||
propSprite.scrollFactor.y = value;
|
|
||||||
case Right(values):
|
|
||||||
propSprite.scrollFactor.x = values[0];
|
|
||||||
propSprite.scrollFactor.y = values[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
propSprite.zIndex = dataProp.zIndex;
|
propSprite.zIndex = dataProp.zIndex;
|
||||||
|
|
||||||
|
@ -731,6 +753,11 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
|
||||||
return Sprite;
|
return Sprite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static function _fetchData(id:String):Null<StageData>
|
||||||
|
{
|
||||||
|
return StageRegistry.instance.parseEntryDataWithMigration(id, StageRegistry.instance.fetchEntryVersion(id));
|
||||||
|
}
|
||||||
|
|
||||||
public function onScriptEvent(event:ScriptEvent) {}
|
public function onScriptEvent(event:ScriptEvent) {}
|
||||||
|
|
||||||
public function onPause(event:PauseScriptEvent) {}
|
public function onPause(event:PauseScriptEvent) {}
|
||||||
|
|
|
@ -1,548 +0,0 @@
|
||||||
package funkin.play.stage;
|
|
||||||
|
|
||||||
import funkin.data.animation.AnimationData;
|
|
||||||
import funkin.play.stage.ScriptedStage;
|
|
||||||
import funkin.play.stage.Stage;
|
|
||||||
import funkin.util.VersionUtil;
|
|
||||||
import funkin.util.assets.DataAssets;
|
|
||||||
import haxe.Json;
|
|
||||||
import openfl.Assets;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains utilities for loading and parsing stage data.
|
|
||||||
*/
|
|
||||||
class StageDataParser
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The current version string for the stage data format.
|
|
||||||
* Handle breaking changes by incrementing this value
|
|
||||||
* and adding migration to the `migrateStageData()` function.
|
|
||||||
*/
|
|
||||||
public static final STAGE_DATA_VERSION:String = "1.0.0";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The current version rule check for the stage data format.
|
|
||||||
*/
|
|
||||||
public static final STAGE_DATA_VERSION_RULE:String = "1.0.x";
|
|
||||||
|
|
||||||
static final stageCache:Map<String, Stage> = new Map<String, Stage>();
|
|
||||||
|
|
||||||
static final DEFAULT_STAGE_ID = 'UNKNOWN';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses and preloads the game's stage data and scripts when the game starts.
|
|
||||||
*
|
|
||||||
* If you want to force stages to be reloaded, you can just call this function again.
|
|
||||||
*/
|
|
||||||
public static function loadStageCache():Void
|
|
||||||
{
|
|
||||||
// Clear any stages that are cached if there were any.
|
|
||||||
clearStageCache();
|
|
||||||
trace("Loading stage cache...");
|
|
||||||
|
|
||||||
//
|
|
||||||
// SCRIPTED STAGES
|
|
||||||
//
|
|
||||||
var scriptedStageClassNames:Array<String> = ScriptedStage.listScriptClasses();
|
|
||||||
trace(' Instantiating ${scriptedStageClassNames.length} scripted stages...');
|
|
||||||
for (stageCls in scriptedStageClassNames)
|
|
||||||
{
|
|
||||||
var stage:Stage = ScriptedStage.init(stageCls, DEFAULT_STAGE_ID);
|
|
||||||
if (stage != null)
|
|
||||||
{
|
|
||||||
trace(' Loaded scripted stage: ${stage.stageName}');
|
|
||||||
// Disable the rendering logic for stage until it's loaded.
|
|
||||||
// Note that kill() =/= destroy()
|
|
||||||
stage.kill();
|
|
||||||
|
|
||||||
// Then store it.
|
|
||||||
stageCache.set(stage.stageId, stage);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
trace(' Failed to instantiate scripted stage class: ${stageCls}');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// UNSCRIPTED STAGES
|
|
||||||
//
|
|
||||||
var stageIdList:Array<String> = DataAssets.listDataFilesInPath('stages/');
|
|
||||||
var unscriptedStageIds:Array<String> = stageIdList.filter(function(stageId:String):Bool {
|
|
||||||
return !stageCache.exists(stageId);
|
|
||||||
});
|
|
||||||
trace(' Instantiating ${unscriptedStageIds.length} non-scripted stages...');
|
|
||||||
for (stageId in unscriptedStageIds)
|
|
||||||
{
|
|
||||||
var stage:Stage;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
stage = new Stage(stageId);
|
|
||||||
if (stage != null)
|
|
||||||
{
|
|
||||||
trace(' Loaded stage data: ${stage.stageName}');
|
|
||||||
stageCache.set(stageId, stage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (e)
|
|
||||||
{
|
|
||||||
trace(' An error occurred while loading stage data: ${stageId}');
|
|
||||||
// Assume error was already logged.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trace(' Successfully loaded ${Lambda.count(stageCache)} stages.');
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function fetchStage(stageId:String):Null<Stage>
|
|
||||||
{
|
|
||||||
if (stageCache.exists(stageId))
|
|
||||||
{
|
|
||||||
trace('Successfully fetch stage: ${stageId}');
|
|
||||||
var stage:Stage = stageCache.get(stageId);
|
|
||||||
stage.revive();
|
|
||||||
return stage;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
trace('Failed to fetch stage, not found in cache: ${stageId}');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static function clearStageCache():Void
|
|
||||||
{
|
|
||||||
if (stageCache != null)
|
|
||||||
{
|
|
||||||
for (stage in stageCache)
|
|
||||||
{
|
|
||||||
stage.destroy();
|
|
||||||
}
|
|
||||||
stageCache.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load a stage's JSON file, parse its data, and return it.
|
|
||||||
*
|
|
||||||
* @param stageId The stage to load.
|
|
||||||
* @return The stage data, or null if validation failed.
|
|
||||||
*/
|
|
||||||
public static function parseStageData(stageId:String):Null<StageData>
|
|
||||||
{
|
|
||||||
var rawJson:String = loadStageFile(stageId);
|
|
||||||
|
|
||||||
var stageData:StageData = migrateStageData(rawJson, stageId);
|
|
||||||
|
|
||||||
return validateStageData(stageId, stageData);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function listStageIds():Array<String>
|
|
||||||
{
|
|
||||||
return stageCache.keys().array();
|
|
||||||
}
|
|
||||||
|
|
||||||
static function loadStageFile(stagePath:String):String
|
|
||||||
{
|
|
||||||
var stageFilePath:String = Paths.json('stages/${stagePath}');
|
|
||||||
var rawJson = Assets.getText(stageFilePath).trim();
|
|
||||||
|
|
||||||
while (!rawJson.endsWith("}"))
|
|
||||||
{
|
|
||||||
rawJson = rawJson.substr(0, rawJson.length - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rawJson;
|
|
||||||
}
|
|
||||||
|
|
||||||
static function migrateStageData(rawJson:String, stageId:String):Null<StageData>
|
|
||||||
{
|
|
||||||
// If you update the stage data format in a breaking way,
|
|
||||||
// handle migration here by checking the `version` value.
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var parser = new json2object.JsonParser<StageData>();
|
|
||||||
parser.ignoreUnknownVariables = false;
|
|
||||||
parser.fromJson(rawJson, '$stageId.json');
|
|
||||||
|
|
||||||
if (parser.errors.length > 0)
|
|
||||||
{
|
|
||||||
trace('[STAGE] Failed to parse stage data');
|
|
||||||
|
|
||||||
for (error in parser.errors)
|
|
||||||
funkin.data.DataError.printError(error);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return parser.value;
|
|
||||||
}
|
|
||||||
catch (e)
|
|
||||||
{
|
|
||||||
trace(' Error parsing data for stage: ${stageId}');
|
|
||||||
trace(' ${e}');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static final DEFAULT_ANIMTYPE:String = "sparrow";
|
|
||||||
static final DEFAULT_CAMERAZOOM:Float = 1.0;
|
|
||||||
static final DEFAULT_DANCEEVERY:Int = 0;
|
|
||||||
static final DEFAULT_ISPIXEL:Bool = false;
|
|
||||||
static final DEFAULT_NAME:String = "Untitled Stage";
|
|
||||||
static final DEFAULT_OFFSETS:Array<Float> = [0, 0];
|
|
||||||
static final DEFAULT_CAMERA_OFFSETS_BF:Array<Float> = [-100, -100];
|
|
||||||
static final DEFAULT_CAMERA_OFFSETS_DAD:Array<Float> = [150, -100];
|
|
||||||
static final DEFAULT_POSITION:Array<Float> = [0, 0];
|
|
||||||
static final DEFAULT_SCALE:Float = 1.0;
|
|
||||||
static final DEFAULT_ALPHA:Float = 1.0;
|
|
||||||
static final DEFAULT_SCROLL:Array<Float> = [0, 0];
|
|
||||||
static final DEFAULT_ZINDEX:Int = 0;
|
|
||||||
|
|
||||||
static final DEFAULT_CHARACTER_DATA:StageDataCharacter =
|
|
||||||
{
|
|
||||||
zIndex: DEFAULT_ZINDEX,
|
|
||||||
position: DEFAULT_POSITION,
|
|
||||||
cameraOffsets: DEFAULT_OFFSETS,
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set unspecified parameters to their defaults.
|
|
||||||
* If the parameter is mandatory, print an error message.
|
|
||||||
* @param id
|
|
||||||
* @param input
|
|
||||||
* @return The validated stage data
|
|
||||||
*/
|
|
||||||
static function validateStageData(id:String, input:StageData):Null<StageData>
|
|
||||||
{
|
|
||||||
if (input == null)
|
|
||||||
{
|
|
||||||
trace('ERROR: Could not parse stage data for "${id}".');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (input.version == null)
|
|
||||||
{
|
|
||||||
trace('ERROR: Could not load stage data for "$id": missing version');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!VersionUtil.validateVersionStr(input.version, STAGE_DATA_VERSION_RULE))
|
|
||||||
{
|
|
||||||
trace('ERROR: Could not load stage data for "$id": bad version (got ${input.version}, expected ${STAGE_DATA_VERSION_RULE})');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (input.name == null)
|
|
||||||
{
|
|
||||||
trace('WARN: Stage data for "$id" missing name');
|
|
||||||
input.name = DEFAULT_NAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (input.cameraZoom == null)
|
|
||||||
{
|
|
||||||
input.cameraZoom = DEFAULT_CAMERAZOOM;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (input.props == null)
|
|
||||||
{
|
|
||||||
input.props = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (inputProp in input.props)
|
|
||||||
{
|
|
||||||
// It's fine for inputProp.name to be null
|
|
||||||
|
|
||||||
if (inputProp.assetPath == null)
|
|
||||||
{
|
|
||||||
trace('ERROR: Could not load stage data for "$id": missing assetPath for prop "${inputProp.name}"');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputProp.position == null)
|
|
||||||
{
|
|
||||||
inputProp.position = DEFAULT_POSITION;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputProp.zIndex == null)
|
|
||||||
{
|
|
||||||
inputProp.zIndex = DEFAULT_ZINDEX;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputProp.isPixel == null)
|
|
||||||
{
|
|
||||||
inputProp.isPixel = DEFAULT_ISPIXEL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputProp.danceEvery == null)
|
|
||||||
{
|
|
||||||
inputProp.danceEvery = DEFAULT_DANCEEVERY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputProp.animType == null)
|
|
||||||
{
|
|
||||||
inputProp.animType = DEFAULT_ANIMTYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (inputProp.scale)
|
|
||||||
{
|
|
||||||
case null:
|
|
||||||
inputProp.scale = Right([DEFAULT_SCALE, DEFAULT_SCALE]);
|
|
||||||
case Left(value):
|
|
||||||
inputProp.scale = Right([value, value]);
|
|
||||||
case Right(_):
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (inputProp.scroll)
|
|
||||||
{
|
|
||||||
case null:
|
|
||||||
inputProp.scroll = Right(DEFAULT_SCROLL);
|
|
||||||
case Left(value):
|
|
||||||
inputProp.scroll = Right([value, value]);
|
|
||||||
case Right(_):
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputProp.alpha == null)
|
|
||||||
{
|
|
||||||
inputProp.alpha = DEFAULT_ALPHA;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputProp.animations == null)
|
|
||||||
{
|
|
||||||
inputProp.animations = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputProp.animations.length == 0 && inputProp.startingAnimation != null)
|
|
||||||
{
|
|
||||||
trace('ERROR: Could not load stage data for "$id": missing animations for prop "${inputProp.name}"');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (inputAnimation in inputProp.animations)
|
|
||||||
{
|
|
||||||
if (inputAnimation.name == null)
|
|
||||||
{
|
|
||||||
trace('ERROR: Could not load stage data for "$id": missing animation name for prop "${inputProp.name}"');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputAnimation.frameRate == null)
|
|
||||||
{
|
|
||||||
inputAnimation.frameRate = 24;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputAnimation.offsets == null)
|
|
||||||
{
|
|
||||||
inputAnimation.offsets = DEFAULT_OFFSETS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputAnimation.looped == null)
|
|
||||||
{
|
|
||||||
inputAnimation.looped = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputAnimation.flipX == null)
|
|
||||||
{
|
|
||||||
inputAnimation.flipX = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputAnimation.flipY == null)
|
|
||||||
{
|
|
||||||
inputAnimation.flipY = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (input.characters == null)
|
|
||||||
{
|
|
||||||
trace('ERROR: Could not load stage data for "$id": missing characters');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (input.characters.bf == null)
|
|
||||||
{
|
|
||||||
input.characters.bf = DEFAULT_CHARACTER_DATA;
|
|
||||||
}
|
|
||||||
if (input.characters.dad == null)
|
|
||||||
{
|
|
||||||
input.characters.dad = DEFAULT_CHARACTER_DATA;
|
|
||||||
}
|
|
||||||
if (input.characters.gf == null)
|
|
||||||
{
|
|
||||||
input.characters.gf = DEFAULT_CHARACTER_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (inputCharacter in [input.characters.bf, input.characters.dad, input.characters.gf])
|
|
||||||
{
|
|
||||||
if (inputCharacter.position == null || inputCharacter.position.length != 2)
|
|
||||||
{
|
|
||||||
inputCharacter.position = [0, 0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// All good!
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class StageData
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The sematic version number of the stage data JSON format.
|
|
||||||
* Supports fancy comparisons like NPM does it's neat.
|
|
||||||
*/
|
|
||||||
public var version:String;
|
|
||||||
|
|
||||||
public var name:String;
|
|
||||||
public var cameraZoom:Null<Float>;
|
|
||||||
public var props:Array<StageDataProp>;
|
|
||||||
public var characters:StageDataCharacters;
|
|
||||||
|
|
||||||
public function new()
|
|
||||||
{
|
|
||||||
this.version = StageDataParser.STAGE_DATA_VERSION;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert this StageData into a JSON string.
|
|
||||||
*/
|
|
||||||
public function serialize(pretty:Bool = true):String
|
|
||||||
{
|
|
||||||
var writer = new json2object.JsonWriter<StageData>();
|
|
||||||
return writer.write(this, pretty ? ' ' : null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef StageDataCharacters =
|
|
||||||
{
|
|
||||||
var bf:StageDataCharacter;
|
|
||||||
var dad:StageDataCharacter;
|
|
||||||
var gf:StageDataCharacter;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef StageDataProp =
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The name of the prop for later lookup by scripts.
|
|
||||||
* Optional; if unspecified, the prop can't be referenced by scripts.
|
|
||||||
*/
|
|
||||||
@:optional
|
|
||||||
var name:String;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The asset used to display the prop.
|
|
||||||
*/
|
|
||||||
var assetPath:String;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The position of the prop as an [x, y] array of two floats.
|
|
||||||
*/
|
|
||||||
var position:Array<Float>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A number determining the stack order of the prop, relative to other props and the characters in the stage.
|
|
||||||
* Props with lower numbers render below those with higher numbers.
|
|
||||||
* This is just like CSS, it isn't hard.
|
|
||||||
* @default 0
|
|
||||||
*/
|
|
||||||
@:optional
|
|
||||||
@:default(0)
|
|
||||||
var zIndex:Int;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If set to true, anti-aliasing will be forcibly disabled on the sprite.
|
|
||||||
* This prevents blurry images on pixel-art levels.
|
|
||||||
* @default false
|
|
||||||
*/
|
|
||||||
@:optional
|
|
||||||
@:default(false)
|
|
||||||
var isPixel:Bool;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Either the scale of the prop as a float, or the [w, h] scale as an array of two floats.
|
|
||||||
* Pro tip: On pixel-art levels, save the sprite small and set this value to 6 or so to save memory.
|
|
||||||
*/
|
|
||||||
@:jcustomparse(funkin.data.DataParse.eitherFloatOrFloats)
|
|
||||||
@:jcustomwrite(funkin.data.DataWrite.eitherFloatOrFloats)
|
|
||||||
@:optional
|
|
||||||
var scale:haxe.ds.Either<Float, Array<Float>>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The alpha of the prop, as a float.
|
|
||||||
* @default 1.0
|
|
||||||
*/
|
|
||||||
@:optional
|
|
||||||
@:default(1.0)
|
|
||||||
var alpha:Float;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If not zero, this prop will play an animation every X beats of the song.
|
|
||||||
* This requires animations to be defined. If `danceLeft` and `danceRight` are defined,
|
|
||||||
* they will alternated between, otherwise the `idle` animation will be used.
|
|
||||||
*
|
|
||||||
* @default 0
|
|
||||||
*/
|
|
||||||
@:default(0)
|
|
||||||
@:optional
|
|
||||||
var danceEvery:Int;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* How much the prop scrolls relative to the camera. Used to create a parallax effect.
|
|
||||||
* Represented as a float or as an [x, y] array of two floats.
|
|
||||||
* [1, 1] means the prop moves 1:1 with the camera.
|
|
||||||
* [0.5, 0.5] means the prop half as much as the camera.
|
|
||||||
* [0, 0] means the prop is not moved.
|
|
||||||
* @default [0, 0]
|
|
||||||
*/
|
|
||||||
@:jcustomparse(funkin.data.DataParse.eitherFloatOrFloats)
|
|
||||||
@:jcustomwrite(funkin.data.DataWrite.eitherFloatOrFloats)
|
|
||||||
@:optional
|
|
||||||
var scroll:haxe.ds.Either<Float, Array<Float>>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An optional array of animations which the prop can play.
|
|
||||||
* @default Prop has no animations.
|
|
||||||
*/
|
|
||||||
@:optional
|
|
||||||
var animations:Array<AnimationData>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If animations are used, this is the name of the animation to play first.
|
|
||||||
* @default Don't play an animation.
|
|
||||||
*/
|
|
||||||
@:optional
|
|
||||||
var startingAnimation:Null<String>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The animation type to use.
|
|
||||||
* Options: "sparrow", "packer"
|
|
||||||
* @default "sparrow"
|
|
||||||
*/
|
|
||||||
@:default("sparrow")
|
|
||||||
@:optional
|
|
||||||
var animType:String;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef StageDataCharacter =
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* A number determining the stack order of the character, relative to props and other characters in the stage.
|
|
||||||
* Again, just like CSS.
|
|
||||||
* @default 0
|
|
||||||
*/
|
|
||||||
var zIndex:Int;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The position to render the character at.
|
|
||||||
*/
|
|
||||||
var position:Array<Float>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The camera offsets to apply when focusing on the character on this stage.
|
|
||||||
* @default [-100, -100] for BF, [100, -100] for DAD/OPPONENT, [0, 0] for GF
|
|
||||||
*/
|
|
||||||
var cameraOffsets:Array<Float>;
|
|
||||||
};
|
|
|
@ -1,10 +1,10 @@
|
||||||
package funkin.play.stage;
|
package funkin.play.stage;
|
||||||
|
|
||||||
import funkin.modding.events.ScriptEvent;
|
import funkin.modding.events.ScriptEvent;
|
||||||
import flixel.FlxSprite;
|
import funkin.graphics.FunkinSprite;
|
||||||
import funkin.modding.IScriptedClass.IStateStageProp;
|
import funkin.modding.IScriptedClass.IStateStageProp;
|
||||||
|
|
||||||
class StageProp extends FlxSprite implements IStateStageProp
|
class StageProp extends FunkinSprite implements IStateStageProp
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* An internal name for this prop.
|
* An internal name for this prop.
|
||||||
|
|
|
@ -12,6 +12,7 @@ import flixel.FlxCamera;
|
||||||
import flixel.FlxSprite;
|
import flixel.FlxSprite;
|
||||||
import flixel.FlxSubState;
|
import flixel.FlxSubState;
|
||||||
import flixel.group.FlxSpriteGroup;
|
import flixel.group.FlxSpriteGroup;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
import flixel.input.keyboard.FlxKey;
|
import flixel.input.keyboard.FlxKey;
|
||||||
import flixel.math.FlxMath;
|
import flixel.math.FlxMath;
|
||||||
import flixel.math.FlxPoint;
|
import flixel.math.FlxPoint;
|
||||||
|
@ -56,7 +57,7 @@ import funkin.data.song.SongData.SongNoteData;
|
||||||
import funkin.data.song.SongData.SongCharacterData;
|
import funkin.data.song.SongData.SongCharacterData;
|
||||||
import funkin.data.song.SongDataUtils;
|
import funkin.data.song.SongDataUtils;
|
||||||
import funkin.ui.debug.charting.commands.ChartEditorCommand;
|
import funkin.ui.debug.charting.commands.ChartEditorCommand;
|
||||||
import funkin.play.stage.StageData;
|
import funkin.data.stage.StageData;
|
||||||
import funkin.save.Save;
|
import funkin.save.Save;
|
||||||
import funkin.ui.debug.charting.commands.AddEventsCommand;
|
import funkin.ui.debug.charting.commands.AddEventsCommand;
|
||||||
import funkin.ui.debug.charting.commands.AddNotesCommand;
|
import funkin.ui.debug.charting.commands.AddNotesCommand;
|
||||||
|
@ -2271,7 +2272,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
var playheadWidth:Int = GRID_SIZE * (STRUMLINE_SIZE * 2 + 1) + (PLAYHEAD_SCROLL_AREA_WIDTH * 2);
|
var playheadWidth:Int = GRID_SIZE * (STRUMLINE_SIZE * 2 + 1) + (PLAYHEAD_SCROLL_AREA_WIDTH * 2);
|
||||||
var playheadBaseYPos:Float = GRID_INITIAL_Y_POS;
|
var playheadBaseYPos:Float = GRID_INITIAL_Y_POS;
|
||||||
gridPlayhead.setPosition(GRID_X_POS, playheadBaseYPos);
|
gridPlayhead.setPosition(GRID_X_POS, playheadBaseYPos);
|
||||||
var playheadSprite:FlxSprite = new FlxSprite().makeGraphic(playheadWidth, PLAYHEAD_HEIGHT, PLAYHEAD_COLOR);
|
var playheadSprite:FunkinSprite = new FunkinSprite().makeSolidColor(playheadWidth, PLAYHEAD_HEIGHT, PLAYHEAD_COLOR);
|
||||||
playheadSprite.x = -PLAYHEAD_SCROLL_AREA_WIDTH;
|
playheadSprite.x = -PLAYHEAD_SCROLL_AREA_WIDTH;
|
||||||
playheadSprite.y = 0;
|
playheadSprite.y = 0;
|
||||||
gridPlayhead.add(playheadSprite);
|
gridPlayhead.add(playheadSprite);
|
||||||
|
|
|
@ -13,7 +13,7 @@ import funkin.play.character.BaseCharacter;
|
||||||
import funkin.play.character.CharacterData;
|
import funkin.play.character.CharacterData;
|
||||||
import funkin.play.character.CharacterData.CharacterDataParser;
|
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||||
import funkin.play.song.Song;
|
import funkin.play.song.Song;
|
||||||
import funkin.play.stage.StageData;
|
import funkin.data.stage.StageData;
|
||||||
import funkin.ui.debug.charting.dialogs.ChartEditorAboutDialog;
|
import funkin.ui.debug.charting.dialogs.ChartEditorAboutDialog;
|
||||||
import funkin.ui.debug.charting.dialogs.ChartEditorBaseDialog.DialogDropTarget;
|
import funkin.ui.debug.charting.dialogs.ChartEditorBaseDialog.DialogDropTarget;
|
||||||
import funkin.ui.debug.charting.dialogs.ChartEditorCharacterIconSelectorMenu;
|
import funkin.ui.debug.charting.dialogs.ChartEditorCharacterIconSelectorMenu;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package funkin.ui.debug.charting.handlers;
|
package funkin.ui.debug.charting.handlers;
|
||||||
|
|
||||||
import funkin.play.stage.StageData.StageDataParser;
|
import funkin.data.stage.StageData;
|
||||||
import funkin.play.stage.StageData;
|
|
||||||
import funkin.play.character.CharacterData;
|
import funkin.play.character.CharacterData;
|
||||||
import funkin.play.character.CharacterData.CharacterDataParser;
|
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||||
import haxe.ui.components.HorizontalSlider;
|
import haxe.ui.components.HorizontalSlider;
|
||||||
|
@ -16,8 +15,7 @@ import funkin.play.character.CharacterData;
|
||||||
import funkin.play.character.CharacterData.CharacterDataParser;
|
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||||
import funkin.play.event.SongEvent;
|
import funkin.play.event.SongEvent;
|
||||||
import funkin.play.song.SongSerializer;
|
import funkin.play.song.SongSerializer;
|
||||||
import funkin.play.stage.StageData;
|
import funkin.data.stage.StageData;
|
||||||
import funkin.play.stage.StageData.StageDataParser;
|
|
||||||
import haxe.ui.RuntimeComponentBuilder;
|
import haxe.ui.RuntimeComponentBuilder;
|
||||||
import funkin.ui.debug.charting.util.ChartEditorDropdowns;
|
import funkin.ui.debug.charting.util.ChartEditorDropdowns;
|
||||||
import funkin.ui.haxeui.components.CharacterPlayer;
|
import funkin.ui.haxeui.components.CharacterPlayer;
|
||||||
|
|
|
@ -2,7 +2,7 @@ package funkin.ui.debug.charting.toolboxes;
|
||||||
|
|
||||||
import funkin.play.character.BaseCharacter.CharacterType;
|
import funkin.play.character.BaseCharacter.CharacterType;
|
||||||
import funkin.play.character.CharacterData;
|
import funkin.play.character.CharacterData;
|
||||||
import funkin.play.stage.StageData;
|
import funkin.data.stage.StageData;
|
||||||
import funkin.play.event.SongEvent;
|
import funkin.play.event.SongEvent;
|
||||||
import funkin.data.event.SongEventSchema;
|
import funkin.data.event.SongEventSchema;
|
||||||
import funkin.ui.debug.charting.commands.ChangeStartingBPMCommand;
|
import funkin.ui.debug.charting.commands.ChangeStartingBPMCommand;
|
||||||
|
|
|
@ -2,7 +2,8 @@ package funkin.ui.debug.charting.toolboxes;
|
||||||
|
|
||||||
import funkin.play.character.BaseCharacter.CharacterType;
|
import funkin.play.character.BaseCharacter.CharacterType;
|
||||||
import funkin.play.character.CharacterData;
|
import funkin.play.character.CharacterData;
|
||||||
import funkin.play.stage.StageData;
|
import funkin.data.stage.StageData;
|
||||||
|
import funkin.data.stage.StageRegistry;
|
||||||
import funkin.ui.debug.charting.commands.ChangeStartingBPMCommand;
|
import funkin.ui.debug.charting.commands.ChangeStartingBPMCommand;
|
||||||
import funkin.ui.debug.charting.util.ChartEditorDropdowns;
|
import funkin.ui.debug.charting.util.ChartEditorDropdowns;
|
||||||
import haxe.ui.components.Button;
|
import haxe.ui.components.Button;
|
||||||
|
@ -13,6 +14,7 @@ import haxe.ui.components.Label;
|
||||||
import haxe.ui.components.NumberStepper;
|
import haxe.ui.components.NumberStepper;
|
||||||
import haxe.ui.components.Slider;
|
import haxe.ui.components.Slider;
|
||||||
import haxe.ui.components.TextField;
|
import haxe.ui.components.TextField;
|
||||||
|
import funkin.play.stage.Stage;
|
||||||
import haxe.ui.containers.Box;
|
import haxe.ui.containers.Box;
|
||||||
import haxe.ui.containers.Frame;
|
import haxe.ui.containers.Frame;
|
||||||
import haxe.ui.events.UIEvent;
|
import haxe.ui.events.UIEvent;
|
||||||
|
@ -199,11 +201,11 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox
|
||||||
inputTimeSignature.value = {id: currentTimeSignature, text: currentTimeSignature};
|
inputTimeSignature.value = {id: currentTimeSignature, text: currentTimeSignature};
|
||||||
|
|
||||||
var stageId:String = chartEditorState.currentSongMetadata.playData.stage;
|
var stageId:String = chartEditorState.currentSongMetadata.playData.stage;
|
||||||
var stageData:Null<StageData> = StageDataParser.parseStageData(stageId);
|
var stage:Null<Stage> = StageRegistry.instance.fetchEntry(stageId);
|
||||||
if (inputStage != null)
|
if (inputStage != null)
|
||||||
{
|
{
|
||||||
inputStage.value = (stageData != null) ?
|
inputStage.value = (stage != null) ?
|
||||||
{id: stageId, text: stageData.name} :
|
{id: stage.id, text: stage.stageName} :
|
||||||
{id: "mainStage", text: "Main Stage"};
|
{id: "mainStage", text: "Main Stage"};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,11 @@ package funkin.ui.debug.charting.util;
|
||||||
|
|
||||||
import funkin.data.notestyle.NoteStyleRegistry;
|
import funkin.data.notestyle.NoteStyleRegistry;
|
||||||
import funkin.play.notes.notestyle.NoteStyle;
|
import funkin.play.notes.notestyle.NoteStyle;
|
||||||
import funkin.play.stage.StageData;
|
import funkin.data.stage.StageData;
|
||||||
import funkin.play.stage.StageData.StageDataParser;
|
import funkin.data.stage.StageRegistry;
|
||||||
import funkin.play.character.CharacterData;
|
import funkin.play.character.CharacterData;
|
||||||
import haxe.ui.components.DropDown;
|
import haxe.ui.components.DropDown;
|
||||||
|
import funkin.play.stage.Stage;
|
||||||
import funkin.play.character.BaseCharacter.CharacterType;
|
import funkin.play.character.BaseCharacter.CharacterType;
|
||||||
import funkin.play.character.CharacterData.CharacterDataParser;
|
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||||
|
|
||||||
|
@ -60,16 +61,16 @@ class ChartEditorDropdowns
|
||||||
{
|
{
|
||||||
dropDown.dataSource.clear();
|
dropDown.dataSource.clear();
|
||||||
|
|
||||||
var stageIds:Array<String> = StageDataParser.listStageIds();
|
var stageIds:Array<String> = StageRegistry.instance.listEntryIds();
|
||||||
|
|
||||||
var returnValue:DropDownEntry = {id: "mainStage", text: "Main Stage"};
|
var returnValue:DropDownEntry = {id: "mainStage", text: "Main Stage"};
|
||||||
|
|
||||||
for (stageId in stageIds)
|
for (stageId in stageIds)
|
||||||
{
|
{
|
||||||
var stage:Null<StageData> = StageDataParser.parseStageData(stageId);
|
var stage:Null<Stage> = StageRegistry.instance.fetchEntry(stageId);
|
||||||
if (stage == null) continue;
|
if (stage == null) continue;
|
||||||
|
|
||||||
var value = {id: stageId, text: stage.name};
|
var value = {id: stage.id, text: stage.stageName};
|
||||||
if (startingStageId == stageId) returnValue = value;
|
if (startingStageId == stageId) returnValue = value;
|
||||||
|
|
||||||
dropDown.dataSource.add(value);
|
dropDown.dataSource.add(value);
|
||||||
|
|
|
@ -5,15 +5,17 @@ import flixel.input.mouse.FlxMouseEvent;
|
||||||
import flixel.math.FlxPoint;
|
import flixel.math.FlxPoint;
|
||||||
import funkin.play.character.BaseCharacter;
|
import funkin.play.character.BaseCharacter;
|
||||||
import funkin.play.PlayState;
|
import funkin.play.PlayState;
|
||||||
import funkin.play.stage.StageData;
|
import funkin.data.stage.StageData;
|
||||||
import funkin.play.stage.StageProp;
|
import funkin.play.stage.StageProp;
|
||||||
import funkin.graphics.shaders.StrokeShader;
|
import funkin.graphics.shaders.StrokeShader;
|
||||||
import funkin.ui.haxeui.HaxeUISubState;
|
import funkin.ui.haxeui.HaxeUISubState;
|
||||||
import funkin.ui.debug.stage.StageEditorCommand;
|
import funkin.ui.debug.stage.StageEditorCommand;
|
||||||
import funkin.util.SerializerUtil;
|
import funkin.util.SerializerUtil;
|
||||||
|
import funkin.data.stage.StageRegistry;
|
||||||
import funkin.util.MouseUtil;
|
import funkin.util.MouseUtil;
|
||||||
import haxe.ui.containers.ListView;
|
import haxe.ui.containers.ListView;
|
||||||
import haxe.ui.core.Component;
|
import haxe.ui.core.Component;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
import haxe.ui.events.UIEvent;
|
import haxe.ui.events.UIEvent;
|
||||||
import haxe.ui.RuntimeComponentBuilder;
|
import haxe.ui.RuntimeComponentBuilder;
|
||||||
import openfl.events.Event;
|
import openfl.events.Event;
|
||||||
|
@ -354,7 +356,13 @@ class StageOffsetSubState extends HaxeUISubState
|
||||||
|
|
||||||
function prepStageStuff():String
|
function prepStageStuff():String
|
||||||
{
|
{
|
||||||
var stageLol:StageData = StageDataParser.parseStageData(PlayState.instance.currentStageId);
|
var stageLol:StageData = StageRegistry.instance.fetchEntry(PlayState.instance.currentStageId)?._data;
|
||||||
|
|
||||||
|
if (stageLol == null)
|
||||||
|
{
|
||||||
|
FlxG.log.error("Stage not found in registry!");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
for (prop in stageLol.props)
|
for (prop in stageLol.props)
|
||||||
{
|
{
|
||||||
|
@ -378,6 +386,6 @@ class StageOffsetSubState extends HaxeUISubState
|
||||||
stageLol.characters.gf.position[0] = Std.int(GF_FEET_SNIIIIIIIIIIIIIFFFF.x);
|
stageLol.characters.gf.position[0] = Std.int(GF_FEET_SNIIIIIIIIIIIIIFFFF.x);
|
||||||
stageLol.characters.gf.position[1] = Std.int(GF_FEET_SNIIIIIIIIIIIIIFFFF.y);
|
stageLol.characters.gf.position[1] = Std.int(GF_FEET_SNIIIIIIIIIIIIIFFFF.y);
|
||||||
|
|
||||||
return SerializerUtil.toJSON(stageLol);
|
return stageLol.serialize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import flixel.group.FlxGroup;
|
||||||
import flixel.input.actions.FlxActionInput;
|
import flixel.input.actions.FlxActionInput;
|
||||||
import flixel.input.gamepad.FlxGamepadInputID;
|
import flixel.input.gamepad.FlxGamepadInputID;
|
||||||
import flixel.input.keyboard.FlxKey;
|
import flixel.input.keyboard.FlxKey;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
import funkin.input.Controls;
|
import funkin.input.Controls;
|
||||||
import funkin.ui.AtlasText;
|
import funkin.ui.AtlasText;
|
||||||
import funkin.ui.MenuList;
|
import funkin.ui.MenuList;
|
||||||
|
@ -61,8 +62,8 @@ class ControlsMenu extends funkin.ui.options.OptionsState.Page
|
||||||
|
|
||||||
if (FlxG.gamepads.numActiveGamepads > 0)
|
if (FlxG.gamepads.numActiveGamepads > 0)
|
||||||
{
|
{
|
||||||
var devicesBg:FlxSprite = new FlxSprite();
|
var devicesBg:FunkinSprite = new FunkinSprite();
|
||||||
devicesBg.makeGraphic(FlxG.width, 100, 0xFFFAFD6D);
|
devicesBg.makeSolidColor(FlxG.width, 100, 0xFFFAFD6D);
|
||||||
add(devicesBg);
|
add(devicesBg);
|
||||||
deviceList = new TextMenuList(Horizontal, None);
|
deviceList = new TextMenuList(Horizontal, None);
|
||||||
add(deviceList);
|
add(deviceList);
|
||||||
|
|
|
@ -10,6 +10,7 @@ import flixel.group.FlxGroup.FlxTypedGroup;
|
||||||
import flixel.text.FlxText;
|
import flixel.text.FlxText;
|
||||||
import flixel.addons.transition.FlxTransitionableState;
|
import flixel.addons.transition.FlxTransitionableState;
|
||||||
import flixel.tweens.FlxEase;
|
import flixel.tweens.FlxEase;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
import funkin.ui.MusicBeatState;
|
import funkin.ui.MusicBeatState;
|
||||||
import flixel.tweens.FlxTween;
|
import flixel.tweens.FlxTween;
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
|
@ -153,7 +154,7 @@ class StoryMenuState extends MusicBeatState
|
||||||
|
|
||||||
updateBackground();
|
updateBackground();
|
||||||
|
|
||||||
var black:FlxSprite = new FlxSprite(levelBackground.x, 0).makeGraphic(FlxG.width, Std.int(400 + levelBackground.y), FlxColor.BLACK);
|
var black:FunkinSprite = new FunkinSprite(levelBackground.x, 0).makeSolidColor(FlxG.width, Std.int(400 + levelBackground.y), FlxColor.BLACK);
|
||||||
black.zIndex = levelBackground.zIndex - 1;
|
black.zIndex = levelBackground.zIndex - 1;
|
||||||
add(black);
|
add(black);
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ class OutdatedSubState extends MusicBeatState
|
||||||
override function create()
|
override function create()
|
||||||
{
|
{
|
||||||
super.create();
|
super.create();
|
||||||
var bg:FlxSprite = new FlxSprite().makeGraphic(FlxG.width, FlxG.height, FlxColor.BLACK);
|
var bg:FunkinSprite = new FunkinSprite().makeSolidColor(FlxG.width, FlxG.height, FlxColor.BLACK);
|
||||||
add(bg);
|
add(bg);
|
||||||
var ver = "v" + Application.current.meta.get('version');
|
var ver = "v" + Application.current.meta.get('version');
|
||||||
var txt:FlxText = new FlxText(0, 0, FlxG.width,
|
var txt:FlxText = new FlxText(0, 0, FlxG.width,
|
||||||
|
|
|
@ -13,6 +13,7 @@ import funkin.audio.visualize.SpectogramSprite;
|
||||||
import funkin.graphics.shaders.ColorSwap;
|
import funkin.graphics.shaders.ColorSwap;
|
||||||
import funkin.graphics.shaders.LeftMaskShader;
|
import funkin.graphics.shaders.LeftMaskShader;
|
||||||
import funkin.data.song.SongRegistry;
|
import funkin.data.song.SongRegistry;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
import funkin.ui.MusicBeatState;
|
import funkin.ui.MusicBeatState;
|
||||||
import funkin.data.song.SongData.SongMusicData;
|
import funkin.data.song.SongData.SongMusicData;
|
||||||
import funkin.graphics.shaders.TitleOutline;
|
import funkin.graphics.shaders.TitleOutline;
|
||||||
|
@ -118,7 +119,8 @@ class TitleState extends MusicBeatState
|
||||||
|
|
||||||
persistentUpdate = true;
|
persistentUpdate = true;
|
||||||
|
|
||||||
var bg:FlxSprite = new FlxSprite().makeGraphic(FlxG.width, FlxG.height, FlxColor.BLACK);
|
var bg:FunkinSprite = new FunkinSprite().makeSolidColor(FlxG.width, FlxG.height, FlxColor.BLACK);
|
||||||
|
bg.screenCenter();
|
||||||
add(bg);
|
add(bg);
|
||||||
|
|
||||||
logoBl = new FlxSprite(-150, -100);
|
logoBl = new FlxSprite(-150, -100);
|
||||||
|
|
|
@ -13,6 +13,7 @@ import funkin.play.song.Song.SongDifficulty;
|
||||||
import funkin.ui.mainmenu.MainMenuState;
|
import funkin.ui.mainmenu.MainMenuState;
|
||||||
import funkin.ui.MusicBeatState;
|
import funkin.ui.MusicBeatState;
|
||||||
import haxe.io.Path;
|
import haxe.io.Path;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
import lime.app.Future;
|
import lime.app.Future;
|
||||||
import lime.app.Promise;
|
import lime.app.Promise;
|
||||||
import lime.utils.AssetLibrary;
|
import lime.utils.AssetLibrary;
|
||||||
|
@ -42,7 +43,7 @@ class LoadingState extends MusicBeatState
|
||||||
|
|
||||||
override function create():Void
|
override function create():Void
|
||||||
{
|
{
|
||||||
var bg:FlxSprite = new FlxSprite().makeGraphic(FlxG.width, FlxG.height, 0xFFcaff4d);
|
var bg:FlxSprite = new FunkinSprite().makeSolidColor(FlxG.width, FlxG.height, 0xFFcaff4d);
|
||||||
add(bg);
|
add(bg);
|
||||||
|
|
||||||
funkay = new FlxSprite();
|
funkay = new FlxSprite();
|
||||||
|
@ -53,7 +54,7 @@ class LoadingState extends MusicBeatState
|
||||||
funkay.scrollFactor.set();
|
funkay.scrollFactor.set();
|
||||||
funkay.screenCenter();
|
funkay.screenCenter();
|
||||||
|
|
||||||
loadBar = new FlxSprite(0, FlxG.height - 20).makeGraphic(FlxG.width, 10, 0xFFff16d2);
|
loadBar = new FunkinSprite(0, FlxG.height - 20).makeSolidColor(FlxG.width, 10, 0xFFff16d2);
|
||||||
loadBar.screenCenter(X);
|
loadBar.screenCenter(X);
|
||||||
add(loadBar);
|
add(loadBar);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue