Skip to content

Commit

Permalink
Merge branch 'FNF-CNE-Devs:main' into cne-pr
Browse files Browse the repository at this point in the history
  • Loading branch information
LilyRoss19 authored Oct 18, 2024
2 parents 9b80a3f + d197205 commit 2f0057a
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 69 deletions.
21 changes: 21 additions & 0 deletions source/funkin/backend/scripting/events/CharacterNodeEvent.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package funkin.backend.scripting.events;

import funkin.game.Character;
import haxe.xml.Access;

final class CharacterNodeEvent extends CancellableEvent {
/**
* The character instance
*/
public var character:Character;

/**
* The node which is currently being parsed
*/
public var node:Access;

/**
* The name of the node, quicker access than e.node.name
*/
public var name:String;
}
16 changes: 16 additions & 0 deletions source/funkin/backend/scripting/events/CharacterXMLEvent.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package funkin.backend.scripting.events;

import funkin.game.Character;
import haxe.xml.Access;

final class CharacterXMLEvent extends CancellableEvent {
/**
* The character instance
*/
public var character:Character;

/**
* The xml
*/
public var xml:Access;
}
1 change: 1 addition & 0 deletions source/funkin/backend/system/modules/AudioSwitchFix.hx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class AudioSwitchFix {
}
}

@:dox(hide)
typedef PlayingSound = {
var sound:FlxSound;
var time:Float;
Expand Down
48 changes: 48 additions & 0 deletions source/funkin/backend/utils/XMLUtil.hx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import funkin.backend.system.ErrorCode;
import funkin.backend.FunkinSprite.XMLAnimType;
import flixel.util.FlxColor;
import haxe.xml.Access;
import funkin.backend.scripting.Script;
import funkin.backend.scripting.DummyScript;
import funkin.backend.scripting.ScriptPack;
import flixel.util.typeLimit.OneOfTwo;
import funkin.backend.system.interfaces.IOffsetCompatible;

Expand Down Expand Up @@ -326,6 +329,51 @@ class XMLUtil {
}
}

class XMLImportedScriptInfo {
public var path:String;
public var shortLived:Bool = false;
public var loadBefore:Bool = true;
public var importStageSprites:Bool = false; // maybe will change later?? - Nex
public var parentScriptPack:ScriptPack = null;

public function new(path:String, parentScriptPack:ScriptPack) {
this.parentScriptPack = parentScriptPack;
this.path = path;
}

public function getScript():Script
return parentScriptPack == null ? null : parentScriptPack.getByPath(path);

public static function prepareInfos(node:Access, parentScriptPack:ScriptPack, ?onScriptPreLoad:XMLImportedScriptInfo->Void):XMLImportedScriptInfo {
if (!node.has.script || parentScriptPack == null) return null;

var folder = node.getAtt("folder").getDefault("data/scripts/");
if (!folder.endsWith("/")) folder += "/";

var path = Paths.script(folder + node.getAtt("script"));
var daScript = Script.create(path);
if (daScript is DummyScript) {
Logs.trace('Script Extension at ${path} does not exist.', ERROR);
return null;
}

var infos = new XMLImportedScriptInfo(daScript.path, parentScriptPack);
infos.shortLived = node.getAtt("isShortLived") == "true" || node.getAtt("shortLived") == "true";
infos.importStageSprites = node.getAtt("importStageSprites") == "true";
@:privateAccess infos.loadBefore = shouldLoadBefore(node);

if (onScriptPreLoad != null) onScriptPreLoad(infos);
parentScriptPack.add(daScript);
daScript.set("scriptInfo", infos);
daScript.load();

return infos;
}

@:dox(hide) public static inline function shouldLoadBefore(node:Access):Bool
return node.getAtt("loadBefore") != "false";
}

typedef AnimData = {
var name:String;
var anim:String;
Expand Down
95 changes: 73 additions & 22 deletions source/funkin/game/Character.hx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import flixel.util.FlxColor;
import funkin.backend.FunkinSprite;
import funkin.backend.scripting.DummyScript;
import funkin.backend.scripting.Script;
import funkin.backend.scripting.ScriptPack;
import funkin.backend.scripting.events.CharacterNodeEvent;
import funkin.backend.scripting.events.CharacterXMLEvent;
import funkin.backend.scripting.events.DanceEvent;
import funkin.backend.scripting.events.DirectionAnimEvent;
import funkin.backend.scripting.events.PlayAnimEvent;
Expand Down Expand Up @@ -44,8 +47,13 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
public var cameraOffset:FlxPoint = FlxPoint.get(0, 0);
public var globalOffset:FlxPoint = FlxPoint.get(0, 0);

public var script:Script;
public var xml:Access;
public var scripts:ScriptPack;
public var xmlImportedScripts:Array<XMLImportedScriptInfo> = [];
public var script(default, set):Script;

public function prepareInfos(node:Access)
return XMLImportedScriptInfo.prepareInfos(node, scripts, (infos) -> xmlImportedScripts.push(infos));

public var idleSuffix:String = "";
public var stunned(default, set):Bool = false;
Expand All @@ -71,16 +79,15 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
script = Script.create(Paths.script(Path.withoutExtension(Paths.xml('characters/$curCharacter')), null, true));
else
script = new DummyScript(curCharacter);
script.setParent(this);
script.load();

buildCharacter(xml);
script.call("create");
scripts.call("create");

if (script == null)
script = new DummyScript(curCharacter);

script.call("postCreate");
scripts.call("postCreate");
}

@:noCompletion var __swappedLeftRightAnims:Bool = false;
Expand All @@ -92,9 +99,9 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
__autoInterval = autoInterval;

// character is flipped
if (isPlayer != playerOffsets && switchAnims)
if (isPlayer != playerOffsets && switchAnims)
swapLeftRightAnimations();

frameOffset.set(getAnimOffset(getAnimName()).x, getAnimOffset(getAnimName()).y);
if (isPlayer) flipX = !flipX;
__baseFlipped = flipX;
Expand All @@ -115,7 +122,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset

override function update(elapsed:Float) {
super.update(elapsed);
script.call("update", [elapsed]);
scripts.call("update", [elapsed]);
if (stunned) {
__stunnedTime += elapsed;
if (__stunnedTime > 5 / 60)
Expand All @@ -134,7 +141,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
if(debugMode) return;

var event = EventManager.get(DanceEvent).recycle(danced);
script.call("onDance", [event]);
scripts.call("onDance", [event]);
if (event.cancelled) return;

if (isDanceLeftDanceRight)
Expand Down Expand Up @@ -164,14 +171,14 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
*/
public var danceOnBeat:Bool = true;
public override function beatHit(curBeat:Int) {
script.call("beatHit", [curBeat]);
scripts.call("beatHit", [curBeat]);

if (danceOnBeat && (curBeat + beatOffset) % beatInterval == 0 && !__lockAnimThisFrame)
tryDance();
}

public override function stepHit(curStep:Int)
script.call("stepHit", [curStep]);
scripts.call("stepHit", [curStep]);

@:noCompletion var __reverseDrawProcedure:Bool = false;
public override function getScreenBounds(?newRect:FlxRect, ?camera:FlxCamera):FlxRect {
Expand Down Expand Up @@ -209,14 +216,14 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
public var singAnims = ["singLEFT", "singDOWN", "singUP", "singRIGHT"];
public function playSingAnim(direction:Int, suffix:String = "", Context:PlayAnimContext = SING, ?Force:Null<Bool> = null, Reversed:Bool = false, Frame:Int = 0) {
var event = EventManager.get(DirectionAnimEvent).recycle(singAnims[direction % singAnims.length] + suffix, direction, suffix, Context, Reversed, Frame, Force);
script.call("onPlaySingAnim", [event]);
scripts.call("onPlaySingAnim", [event]);
if (!event.cancelled)
playAnim(event.animName, event.force, event.context, event.reversed, event.frame);
}

public override function playAnim(AnimName:String, ?Force:Bool, Context:PlayAnimContext = NONE, Reversed:Bool = false, Frame:Int = 0) {
var event = EventManager.get(PlayAnimEvent).recycle(AnimName, Force, Reversed, Frame, Context);
script.call("onPlayAnim", [event]);
scripts.call("onPlayAnim", [event]);
if (event.cancelled) return;

super.playAnim(event.animName, event.force, event.context, event.reverse, event.startingFrame);
Expand All @@ -231,15 +238,15 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
var event = EventManager.get(PointEvent).recycle(
midpoint.x + (isPlayer ? -100 : 150) + globalOffset.x + cameraOffset.x,
midpoint.y - 100 + globalOffset.y + cameraOffset.y);
script.call("onGetCamPos", [event]);
scripts.call("onGetCamPos", [event]);

midpoint.put();
return new FlxPoint(event.x, event.y);
}

public override function destroy() {
script.call('destroy');
script.destroy();
scripts.call('destroy');
scripts.destroy();
super.destroy();

cameraOffset.put();
Expand Down Expand Up @@ -281,9 +288,18 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
}

public inline function buildCharacter(xml:Access) {
this.xml = xml; // Modders wassup :D
for(node in xml.elements)
switch(node.name) {
case "use-extension" | "extension" | "ext":
if (!XMLImportedScriptInfo.shouldLoadBefore(node)) continue;
prepareInfos(node);
}

xml = scripts.event("onCharacterXMLParsed", EventManager.get(CharacterXMLEvent).recycle(this, xml)).xml;

sprite = curCharacter;
spriteAnimType = BEAT;
this.xml = xml; // Modders wassup :D

if (xml.x.exists("isPlayer")) playerOffsets = (xml.x.get("isPlayer") == "true");
if (xml.x.exists("x")) globalOffset.x = Std.parseFloat(xml.x.get("x"));
Expand All @@ -307,21 +323,39 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
if (hasInterval) beatInterval = Std.parseInt(xml.x.get("interval"));

loadSprite(Paths.image('characters/$sprite'));
for(node in xml.elements) {
switch(node.name) {
case "anim":
XMLUtil.addXMLAnimation(this, node);
case "use-extension" | "extension" | "ext":
if (XMLImportedScriptInfo.shouldLoadBefore(node)) continue;
prepareInfos(node);
default:
// nothing
}

for (anim in xml.nodes.anim)
XMLUtil.addXMLAnimation(this, anim);
scripts.event("onCharacterNodeParsed", EventManager.get(CharacterNodeEvent).recycle(this, node, node.name));
}

for (attribute in xml.x.attributes())
if (!characterProperties.contains(attribute))
extra[attribute] = xml.x.get(attribute);

fixChar(__switchAnims, !hasInterval);
dance();

for (info in xmlImportedScripts) if (info.shortLived) {
var script = info.getScript();
if (script == null) continue;

scripts.remove(script);
script.destroy();
}
}

public static var characterProperties:Array<String> = [
"x", "y", "sprite", "scale", "antialiasing",
"flipX", "camx", "camy", "isPlayer", "icon",
"x", "y", "sprite", "scale", "antialiasing",
"flipX", "camx", "camy", "isPlayer", "icon",
"color", "gameOverChar", "holdTime"
];
public static var characterAnimProperties:Array<String> = [
Expand All @@ -331,7 +365,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
public inline function buildXML(?animsOrder:Array<String>):Xml {
var xml:Xml = Xml.createElement("character");
xml.attributeOrder = characterProperties.copy();

if (globalOffset.x != 0) xml.set("x", Std.string(FlxMath.roundDecimal(globalOffset.x, 2)));
if (globalOffset.y != 0) xml.set("y", Std.string(FlxMath.roundDecimal(globalOffset.y, 2)));

Expand Down Expand Up @@ -400,13 +434,30 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
return stunned = b;
}

// ---- Backwards compat ----
// Interval at which the character will dance (higher number = slower dance)
@:noCompletion public var danceInterval(get, set):Int;
@:noCompletion private function set_danceInterval(v:Int)
return beatInterval = v;
@:noCompletion private function get_danceInterval()
return beatInterval;

private function set_script(script:Script):Script {
if (scripts == null) (scripts = new ScriptPack("Character")).setParent(this);

var lastIndex = scripts.scripts.indexOf(this.script);
if(lastIndex >= 0) {
if(script == null) // last != null && new == null
scripts.scripts.splice(lastIndex, 1);
else // last != null && new != null
scripts.scripts[lastIndex] = script;
} else if(script != null) // last == null
scripts.insert(0, script);

return this.script = script;
}
// ---- end of Backwards compat ----


public static var FALLBACK_CHARACTER:String = "bf";
public static var FALLBACK_DEAD_CHARACTER:String = "bf-dead";
Expand Down Expand Up @@ -436,7 +487,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
Logs.trace('Error while loading character ${character}: ${e}', ERROR);

character = FALLBACK_CHARACTER;
if (char != null)
if (char != null)
char.curCharacter = character;
continue;
}
Expand Down
Loading

0 comments on commit 2f0057a

Please sign in to comment.