Merge remote-tracking branch 'upstream/main'
This commit is contained in:
@@ -330,7 +330,31 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
lastAnimContext = Context;
|
||||
}
|
||||
|
||||
public function getAnim(name:String):OneOfTwo<FlxAnimation, FlxSymbolAnimation> {
|
||||
public inline function addAnim(name:String, prefix:String, frameRate:Float = 24, ?looped:Bool, ?forced:Bool, ?indices:Array<Int>, x:Float = 0, y:Float = 0, animType:XMLAnimType = NONE)
|
||||
{
|
||||
return XMLUtil.addAnimToSprite(this, {
|
||||
name: name,
|
||||
anim: prefix,
|
||||
fps: frameRate,
|
||||
loop: looped == null ? animType == LOOP : looped,
|
||||
animType: animType,
|
||||
x: x,
|
||||
y: y,
|
||||
indices: indices,
|
||||
forced: forced
|
||||
});
|
||||
}
|
||||
|
||||
public inline function removeAnim(name:String)
|
||||
{
|
||||
if (animateAtlas != null)
|
||||
@:privateAccess animateAtlas.anim.animsMap.remove(name);
|
||||
else
|
||||
animation.remove(name);
|
||||
}
|
||||
|
||||
public function getAnim(name:String):OneOfTwo<FlxAnimation, FlxSymbolAnimation>
|
||||
{
|
||||
if(animateAtlas != null)
|
||||
return animateAtlas.anim.getByName(name);
|
||||
return animation.getByName(name);
|
||||
@@ -343,7 +367,7 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
return FlxPoint.weak(0, 0);
|
||||
}
|
||||
|
||||
public inline function hasAnimation(AnimName:String):Bool @:privateAccess
|
||||
public inline function hasAnim(AnimName:String):Bool @:privateAccess
|
||||
return animateAtlas != null ? (animateAtlas.anim.animsMap.exists(AnimName)
|
||||
|| animateAtlas.anim.symbolDictionary.exists(AnimName)) : animation.exists(AnimName);
|
||||
|
||||
@@ -355,13 +379,6 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
return animateAtlas != null ? animateAtlas.anim.reversed : animation.curAnim != null ? animation.curAnim.reversed : false;
|
||||
}
|
||||
|
||||
public inline function removeAnimation(name:String) {
|
||||
if (animateAtlas != null)
|
||||
@:privateAccess animateAtlas.anim.animsMap.remove(name);
|
||||
else
|
||||
animation.remove(name);
|
||||
}
|
||||
|
||||
public inline function getNameList():Array<String> {
|
||||
if (animateAtlas != null)
|
||||
return [for (name in @:privateAccess animateAtlas.anim.animsMap.keys()) name];
|
||||
@@ -369,7 +386,8 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
return animation.getNameList();
|
||||
}
|
||||
|
||||
public inline function stopAnimation() {
|
||||
public inline function stopAnim()
|
||||
{
|
||||
if (animateAtlas != null)
|
||||
animateAtlas.anim.pause();
|
||||
else
|
||||
@@ -383,6 +401,11 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
public inline function isAnimAtEnd() {
|
||||
return animateAtlas != null ? animateAtlas.anim.isAtEnd : (animation.curAnim != null ? animation.curAnim.isAtEnd : false);
|
||||
}
|
||||
|
||||
// Backwards compat (the names used to be all different and it sucked, please lets use the same format in the future) - Nex
|
||||
public inline function hasAnimation(AnimName:String) return hasAnim(AnimName);
|
||||
public inline function removeAnimation(name:String) return removeAnim(name);
|
||||
public inline function stopAnimation() return stopAnim();
|
||||
#end
|
||||
|
||||
// Getter / Setters
|
||||
|
||||
@@ -93,6 +93,9 @@ class MusicBeatState extends FlxState implements IBeatReceiver
|
||||
|
||||
public var scriptsAllowed:Bool = true;
|
||||
|
||||
public static var lastScriptName:String = null;
|
||||
public static var lastStateName:String = null;
|
||||
|
||||
public var scriptName:String = null;
|
||||
|
||||
public static var skipTransOut:Bool = false;
|
||||
@@ -108,7 +111,12 @@ class MusicBeatState extends FlxState implements IBeatReceiver
|
||||
public function new(scriptsAllowed:Bool = true, ?scriptName:String) {
|
||||
super();
|
||||
this.scriptsAllowed = #if SOFTCODED_STATES scriptsAllowed #else false #end;
|
||||
this.scriptName = scriptName;
|
||||
|
||||
if(lastStateName != (lastStateName = Type.getClassName(Type.getClass(this)))) {
|
||||
lastScriptName = null;
|
||||
}
|
||||
this.scriptName = scriptName != null ? scriptName : lastScriptName;
|
||||
lastScriptName = this.scriptName;
|
||||
}
|
||||
|
||||
function loadScript() {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package funkin.backend.chart;
|
||||
|
||||
import funkin.backend.chart.ChartData;
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.backend.chart.ChartData;
|
||||
import haxe.Json;
|
||||
@@ -11,7 +12,63 @@ import sys.FileSystem;
|
||||
|
||||
using StringTools;
|
||||
|
||||
enum abstract ChartFormat(Int) {
|
||||
var CODENAME = 0;
|
||||
var LEGACY = 1; // also used by many other engines (old Psych, Kade and more) - Nex
|
||||
var VSLICE = 2;
|
||||
var PSYCH_NEW = 3;
|
||||
|
||||
@:to public function toString():String {
|
||||
return switch(cast (this, ChartFormat)) {
|
||||
case CODENAME: "CODENAME";
|
||||
case LEGACY: "LEGACY";
|
||||
case VSLICE: "VSLICE";
|
||||
case PSYCH_NEW: "PSYCH_NEW";
|
||||
}
|
||||
}
|
||||
|
||||
public static function fromString(str:String, def:ChartFormat = ChartFormat.LEGACY) {
|
||||
str = str.toLowerCase();
|
||||
str = StringTools.replace(str, " ", "");
|
||||
str = StringTools.replace(str, "_", "");
|
||||
str = StringTools.replace(str, ".", "");
|
||||
|
||||
if(StringTools.startsWith(str, "psychv1") || StringTools.startsWith(str, "psych1"))
|
||||
return PSYCH_NEW;
|
||||
|
||||
return switch(str) {
|
||||
case "codename" | "codenameengine": CODENAME;
|
||||
case "newpsych" | "psychnew": PSYCH_NEW;
|
||||
default: def;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Chart {
|
||||
public static function cleanSongData(data:Dynamic):Dynamic {
|
||||
if (Reflect.hasField(data, "song")) {
|
||||
var field:Dynamic = Reflect.field(data, "song");
|
||||
if (field != null && Type.typeof(field) == TObject) // Cant use Reflect.isObject, because it detects strings for some reason
|
||||
return field;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public static function detectChartFormat(data:Dynamic):ChartFormat {
|
||||
var __temp:Dynamic; // imma reuse this var so the program doesnt have to get values multiple times - Nex
|
||||
|
||||
if ((__temp = data.codenameChart) == true || __temp == "true")
|
||||
return CODENAME;
|
||||
|
||||
if (Reflect.hasField(data, "version") && Reflect.hasField(data, "scrollSpeed"))
|
||||
return VSLICE;
|
||||
|
||||
if ((__temp = cleanSongData(data).format) != null && __temp is String && StringTools.startsWith(__temp, "psych_v1"))
|
||||
return PSYCH_NEW;
|
||||
|
||||
return LEGACY;
|
||||
}
|
||||
|
||||
public static function loadEventsJson(songName:String) {
|
||||
var path = Paths.file('songs/${songName.toLowerCase()}/events.json');
|
||||
var data:Array<ChartEvent> = null;
|
||||
@@ -28,8 +85,9 @@ class Chart {
|
||||
public static function loadChartMeta(songName:String, ?difficulty:String, fromMods:Bool = true) {
|
||||
if (difficulty == null) difficulty = Flags.DEFAULT_DIFFICULTY;
|
||||
|
||||
var metaPath = Paths.file('songs/${songName.toLowerCase()}/meta.json');
|
||||
var metaDiffPath = Paths.file('songs/${songName.toLowerCase()}/meta-${difficulty.toLowerCase()}.json');
|
||||
var songNameLower = songName.toLowerCase();
|
||||
var metaPath = Paths.file('songs/${songNameLower}/meta.json');
|
||||
var metaDiffPath = Paths.file('songs/${songNameLower}/meta-${difficulty.toLowerCase()}.json');
|
||||
|
||||
var data:ChartMetaData = null;
|
||||
var fromMods:Bool = fromMods;
|
||||
@@ -62,7 +120,7 @@ class Chart {
|
||||
data.setFieldDefault("parsedColor", data.color.getColorFromDynamic().getDefault(Flags.DEFAULT_COLOR));
|
||||
|
||||
if (data.difficulties.length <= 0) {
|
||||
data.difficulties = [for(f in Paths.getFolderContent('songs/${songName.toLowerCase()}/charts/', false, fromMods ? MODS : SOURCE)) if (Path.extension(f = f.toUpperCase()) == "JSON") Path.withoutExtension(f)];
|
||||
data.difficulties = [for(f in Paths.getFolderContent('songs/${songNameLower}/charts/', false, fromMods ? MODS : SOURCE)) if (Path.extension(f = f.toUpperCase()) == "JSON") Path.withoutExtension(f)];
|
||||
if (data.difficulties.length == 3) {
|
||||
var hasHard = false, hasNormal = false, hasEasy = false;
|
||||
for(d in data.difficulties) {
|
||||
@@ -113,12 +171,12 @@ class Chart {
|
||||
Logs.trace('Could not parse chart for song ${songName} ($difficulty): ${Std.string(e)}', ERROR, RED);
|
||||
}
|
||||
|
||||
if (data != null) {
|
||||
/**
|
||||
* CHART CONVERSION
|
||||
*/
|
||||
#if REGION
|
||||
if (Reflect.hasField(data, "codenameChart") && Reflect.field(data, "codenameChart") == true) {
|
||||
if (data != null) switch (detectChartFormat(data)) {
|
||||
case CODENAME:
|
||||
// backward compat on events since its caused problems
|
||||
var eventTypesToString:Map<Int, String> = [
|
||||
-1 => "HScript Call",
|
||||
@@ -129,27 +187,22 @@ class Chart {
|
||||
];
|
||||
|
||||
if (data.events == null) data.events = [];
|
||||
for (event in cast(data.events, Array<Dynamic>)) {
|
||||
if (Reflect.hasField(event, "type")) {
|
||||
for (event in cast(data.events, Array<Dynamic>)) if (Reflect.hasField(event, "type")) {
|
||||
if (event.type != null)
|
||||
event.name = eventTypesToString[event.type];
|
||||
Reflect.deleteField(event, "type");
|
||||
}
|
||||
}
|
||||
|
||||
// codename chart
|
||||
base = data;
|
||||
} else {
|
||||
// base game chart
|
||||
FNFLegacyParser.parse(data, base);
|
||||
case PSYCH_NEW: PsychParser.parse(data, base);
|
||||
case VSLICE: // TODO
|
||||
case LEGACY: FNFLegacyParser.parse(data, base);
|
||||
}
|
||||
#end
|
||||
}
|
||||
|
||||
if (base.meta == null)
|
||||
base.meta = loadChartMeta(songName, difficulty, base.fromMods);
|
||||
else {
|
||||
var loadedMeta = loadChartMeta(songName, difficulty, base.fromMods);
|
||||
if (base.meta == null) base.meta = loadedMeta;
|
||||
else {
|
||||
for (field in Reflect.fields(base.meta)) {
|
||||
var f = Reflect.field(base.meta, field);
|
||||
if (f != null)
|
||||
|
||||
@@ -6,12 +6,7 @@ import funkin.backend.system.Conductor;
|
||||
class FNFLegacyParser {
|
||||
public static function parse(data:Dynamic, result:ChartData) {
|
||||
// base fnf chart parsing
|
||||
var data:SwagSong = data;
|
||||
if (Reflect.hasField(data, "song")) {
|
||||
var field:Dynamic = Reflect.field(data, "song");
|
||||
if (!(field is String))
|
||||
data = field;
|
||||
}
|
||||
var data:SwagSong = Chart.cleanSongData(data);
|
||||
|
||||
result.scrollSpeed = data.speed;
|
||||
result.stage = data.stage;
|
||||
@@ -29,7 +24,7 @@ class FNFLegacyParser {
|
||||
position: "boyfriend",
|
||||
notes: []
|
||||
});
|
||||
var gfName = data.gf != null ? data.gf : (data.gfVersion != null ? data.gfVersion : "gf");
|
||||
var gfName = data.gf != null ? data.gf : (data.gfVersion != null ? data.gfVersion : (data.player3 != null ? data.player3 : "gf"));
|
||||
if (!p2isGF && gfName != "none") {
|
||||
result.strumLines.push({
|
||||
characters: [gfName],
|
||||
@@ -214,6 +209,7 @@ typedef SwagSong =
|
||||
|
||||
var player1:String;
|
||||
var player2:String;
|
||||
var ?player3:String; // alt for gf but idr if it was just used in psych or what but eh whatever maybe its better here anyways - Nex
|
||||
var ?gf:String;
|
||||
var ?gfVersion:String;
|
||||
var validScore:Bool;
|
||||
|
||||
@@ -6,15 +6,33 @@ import funkin.backend.chart.FNFLegacyParser.SwagSong;
|
||||
import funkin.backend.system.Conductor;
|
||||
|
||||
class PsychParser {
|
||||
// Alreadly parsed in sections
|
||||
// Already parsed in sections
|
||||
public static var ignoreEvents:Array<String> = [
|
||||
"Camera Movement",
|
||||
"Alt Animation Toggle",
|
||||
"BPM Change"
|
||||
];
|
||||
|
||||
public static function parse(data:Dynamic, result:ChartData)
|
||||
/**
|
||||
* Converts 1.0 Psych charts to older ones
|
||||
*/
|
||||
public static function standardize(data:Dynamic, result:ChartData) {
|
||||
var sectionsData:Array<Dynamic> = Chart.cleanSongData(data).notes;
|
||||
if (sectionsData == null) return;
|
||||
|
||||
for (section in sectionsData) for (note in cast(section.sectionNotes, Array<Dynamic>)) {
|
||||
var gottaHitNote:Bool = section.mustHitSection == (note[1] >= 4);
|
||||
note[1] = (note[1] % 4) + (gottaHitNote ? 4 : 0);
|
||||
|
||||
if (note[3] != null && Std.isOfType(note[3], String))
|
||||
note[3] = Chart.addNoteType(result, note[3]);
|
||||
}
|
||||
}
|
||||
|
||||
public static function parse(data:Dynamic, result:ChartData) {
|
||||
if (Chart.detectChartFormat(data) == PSYCH_NEW) standardize(data, result);
|
||||
FNFLegacyParser.parse(data, result);
|
||||
}
|
||||
|
||||
public static function encode(chart:ChartData):Dynamic {
|
||||
var base:SwagSong = FNFLegacyParser.__convertToSwagSong(chart);
|
||||
|
||||
@@ -215,8 +215,8 @@ class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
|
||||
if(value == null)
|
||||
value = ShaderTemplates.defaultFragmentSource;
|
||||
glRawFragmentSource = value;
|
||||
value = value.replace("#pragma header", ShaderTemplates.fragHeader).replace("#pragma body", ShaderTemplates.fragBody);
|
||||
value = processImports(value, FRAGMENT_SHADER);
|
||||
value = value.replace("#pragma header", ShaderTemplates.fragHeader).replace("#pragma body", ShaderTemplates.fragBody);
|
||||
if (value != __glFragmentSource)
|
||||
{
|
||||
__glSourceDirty = true;
|
||||
@@ -230,8 +230,19 @@ class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
|
||||
if(value == null)
|
||||
value = ShaderTemplates.defaultVertexSource;
|
||||
glRawVertexSource = value;
|
||||
value = value.replace("#pragma header", ShaderTemplates.vertHeader).replace("#pragma body", ShaderTemplates.vertBody);
|
||||
value = processImports(value, VERTEX_SHADER);
|
||||
|
||||
var useBackCompat:Bool = true;
|
||||
for (regex in ShaderTemplates.vertBackCompatVarList) if (!regex.match(value)) {
|
||||
useBackCompat = false;
|
||||
break;
|
||||
}
|
||||
|
||||
var header = useBackCompat ? ShaderTemplates.vertHeaderBackCompat : ShaderTemplates.vertHeader;
|
||||
var body = useBackCompat ? ShaderTemplates.vertBodyBackCompat : ShaderTemplates.vertBody;
|
||||
|
||||
value = value.replace("#pragma header", header).replace("#pragma body", body);
|
||||
|
||||
if (value != __glVertexSource)
|
||||
{
|
||||
__glSourceDirty = true;
|
||||
@@ -673,6 +684,38 @@ if(hasColorTransform) {
|
||||
|
||||
gl_Position = openfl_Matrix * openfl_Position;";
|
||||
|
||||
// TODO: make this ignore comments
|
||||
public static final vertBackCompatVarList:Array<EReg> = [
|
||||
~/attribute float alpha/,
|
||||
~/attribute vec4 colorMultiplier/,
|
||||
~/attribute vec4 colorOffset/,
|
||||
~/uniform bool hasColorTransform/
|
||||
];
|
||||
|
||||
public static final vertHeaderBackCompat:String = "attribute float openfl_Alpha;
|
||||
attribute vec4 openfl_ColorMultiplier;
|
||||
attribute vec4 openfl_ColorOffset;
|
||||
attribute vec4 openfl_Position;
|
||||
attribute vec2 openfl_TextureCoord;
|
||||
|
||||
varying float openfl_Alphav;
|
||||
varying vec4 openfl_ColorMultiplierv;
|
||||
varying vec4 openfl_ColorOffsetv;
|
||||
varying vec2 openfl_TextureCoordv;
|
||||
|
||||
uniform mat4 openfl_Matrix;
|
||||
uniform bool openfl_HasColorTransform;
|
||||
uniform vec2 openfl_TextureSize;";
|
||||
|
||||
public static final vertBodyBackCompat:String = "openfl_Alphav = openfl_Alpha;
|
||||
openfl_TextureCoordv = openfl_TextureCoord;
|
||||
|
||||
if(openfl_HasColorTransform) {
|
||||
openfl_ColorMultiplierv = openfl_ColorMultiplier;
|
||||
openfl_ColorOffsetv = openfl_ColorOffset / 255.0;
|
||||
}
|
||||
|
||||
gl_Position = openfl_Matrix * openfl_Position;";
|
||||
|
||||
public static final defaultVertexSource:String = "#pragma header
|
||||
|
||||
|
||||
@@ -170,8 +170,7 @@ class XMLUtil {
|
||||
if(node.hasNode.anim) {
|
||||
for(anim in node.nodes.anim)
|
||||
addXMLAnimation(spr, anim);
|
||||
} else {
|
||||
if (spr.frames != null && spr.frames.frames != null) {
|
||||
} else if (spr.frames != null && spr.frames.frames != null) {
|
||||
addAnimToSprite(spr, {
|
||||
name: "idle",
|
||||
anim: null,
|
||||
@@ -183,7 +182,6 @@ class XMLUtil {
|
||||
indices: [for(i in 0...spr.frames.frames.length) i]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return spr;
|
||||
}
|
||||
@@ -244,16 +242,17 @@ class XMLUtil {
|
||||
if(animData.anim == null)
|
||||
return MISSING_PROPERTY;
|
||||
|
||||
if (animData.indices.length > 0)
|
||||
if (animData.indices != null && animData.indices.length > 0)
|
||||
animateAnim.addBySymbolIndices(animData.name, animData.anim, animData.indices, animData.fps, animData.loop);
|
||||
else
|
||||
animateAnim.addBySymbol(animData.name, animData.anim, animData.fps, animData.loop);
|
||||
} else {
|
||||
if (animData.anim == null && animData.indices.length > 0)
|
||||
if (animData.indices != null && animData.indices.length > 0) {
|
||||
if (animData.anim == null)
|
||||
sprite.animation.add(animData.name, animData.indices, animData.fps, animData.loop);
|
||||
else if (animData.indices.length > 0)
|
||||
sprite.animation.addByIndices(animData.name, animData.anim, animData.indices, "", animData.fps, animData.loop);
|
||||
else
|
||||
sprite.animation.addByIndices(animData.name, animData.anim, animData.indices, "", animData.fps, animData.loop);
|
||||
} else
|
||||
sprite.animation.addByPrefix(animData.name, animData.anim, animData.fps, animData.loop);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user