From 8de2a16998876cc1ca74b62e4c2782c74f4658c0 Mon Sep 17 00:00:00 2001 From: Yoshman29 <81191621+YoshiCrafter29@users.noreply.github.com> Date: Sun, 2 Apr 2023 23:44:24 +0200 Subject: [PATCH] subtitles --- source/funkin/cutscenes/VideoCutscene.hx | 88 ++++++++++++++++++++++-- source/funkin/scripting/ModState.hx | 5 +- source/funkin/scripting/ModSubState.hx | 7 +- 3 files changed, 93 insertions(+), 7 deletions(-) diff --git a/source/funkin/cutscenes/VideoCutscene.hx b/source/funkin/cutscenes/VideoCutscene.hx index c863e2fb..bd8fde6f 100644 --- a/source/funkin/cutscenes/VideoCutscene.hx +++ b/source/funkin/cutscenes/VideoCutscene.hx @@ -1,10 +1,12 @@ package funkin.cutscenes; +import haxe.io.Path; import flixel.addons.display.FlxBackdrop; #if sys import sys.io.File; #end import funkin.ui.FunkinText; +import haxe.xml.Access; /** @@ -24,7 +26,12 @@ class VideoCutscene extends Cutscene { var text:FunkinText; var loadingBackdrop:FlxBackdrop; var videoReady:Bool = false; - + + var bg:FlxSprite; + var subtitle:FunkinText; + + public var subtitles:Array = []; + public function new(path:String, callback:Void->Void) { super(callback); localPath = Assets.getPath(this.path = path); @@ -32,12 +39,14 @@ class VideoCutscene extends Cutscene { public override function create() { super.create(); - + cutsceneCamera = new FlxCamera(); cutsceneCamera.bgColor = 0; FlxG.cameras.add(cutsceneCamera, false); - + #if VIDEO_CUTSCENES + parseSubtitles(); + video = new MP4Handler(); video.finishCallback = close; video.canvasWidth = cutsceneCamera.width; @@ -46,7 +55,14 @@ class VideoCutscene extends Cutscene { videoSprite = new FlxSprite(); videoSprite.cameras = [cutsceneCamera]; videoSprite.antialiasing = true; - + + bg = new FlxSprite(0, FlxG.height * 0.85).makeGraphic(1, 1, 0xFF000000); + bg.alpha = 0.5; + bg.visible = false; + + subtitle = new FunkinText(0, FlxG.height * 0.875, 0, "", 20); + subtitle.visible = false; + if (localPath.startsWith("[ZIP]")) { text = new FunkinText(10, 10, Std.int(FlxG.width / 2), "Loading video..."); text.cameras = [cutsceneCamera]; @@ -71,11 +87,54 @@ class VideoCutscene extends Cutscene { video.playMP4(localPath, false, videoSprite); } add(videoSprite); + add(bg); + add(subtitle); #end cameras = [cutsceneCamera]; } + public function parseSubtitles() { + var subtitlesPath = '${Path.withoutExtension(path)}.xml'; + trace(subtitlesPath); + + if (Assets.exists(subtitlesPath)) { + // subtitles found + var subtitleData:Access = null; + try { + subtitleData = new Access(Xml.parse(Assets.getText(subtitlesPath))); + } catch(e) { + Logs.trace('Subtitles XML couldn\'t be parsed: ${e}', ERROR, RED); + } + + if (subtitleData != null) { + // subtitles parsed correctly, cycling + for(node in subtitleData.nodes.subtitles) { + for(sNode in node.nodes.subtitle) { + if (!sNode.has.time) continue; + + var timeSplit:Array> = [for(e in sNode.att.time.split(":")) Std.parseFloat(e)]; + var multipliers:Array = [1, 60, 3600, 86400]; // no way a cutscene will last longer than days + var time:Float = 0; + + for(k=>i in timeSplit) { + var mul = multipliers[timeSplit.length - 1 - k]; + if (i != null) + time += i * mul; + } + + subtitles.push({ + subtitle: sNode.innerData, + time: time * 1000 + }); + } + } + } + } + + trace(subtitles); + } + public override function update(elapsed:Float) { super.update(elapsed); #if VIDEO_CUTSCENES @@ -85,6 +144,11 @@ class VideoCutscene extends Cutscene { if (loadingBackdrop != null) loadingBackdrop.visible = false; } + @:privateAccess + var time = video.bitmap.getTime(); + while (subtitles.length > 0 && subtitles[0].time < time) + setSubtitle(subtitles.shift()); + if (loadingBackdrop != null) { loadingBackdrop.x -= elapsed * FlxG.width * 0.5; } @@ -92,8 +156,24 @@ class VideoCutscene extends Cutscene { close(); #end } + + public function setSubtitle(sub:CutsceneSubtitle) { + if (bg.visible = subtitle.visible = (sub.subtitle.length > 0)) { + subtitle.text = sub.subtitle; + subtitle.screenCenter(X); + bg.scale.set(subtitle.width + 8, subtitle.height + 8); + bg.updateHitbox(); + bg.setPosition(subtitle.x - 4, subtitle.y - 4); + } + } + public override function destroy() { FlxG.cameras.remove(cutsceneCamera, true); super.destroy(); } +} + +typedef CutsceneSubtitle = { + var time:Float; // time in ms + var subtitle:String; // subtitle text } \ No newline at end of file diff --git a/source/funkin/scripting/ModState.hx b/source/funkin/scripting/ModState.hx index f549c2b6..6ff123f6 100644 --- a/source/funkin/scripting/ModState.hx +++ b/source/funkin/scripting/ModState.hx @@ -1,7 +1,10 @@ package funkin.scripting; class ModState extends MusicBeatState { + public static var lastName:String = null; public function new(stateName:String) { - super(true, stateName); + if (stateName != null) + lastName = stateName; + super(true, lastName); } } \ No newline at end of file diff --git a/source/funkin/scripting/ModSubState.hx b/source/funkin/scripting/ModSubState.hx index ee8e1a21..c66cb9c8 100644 --- a/source/funkin/scripting/ModSubState.hx +++ b/source/funkin/scripting/ModSubState.hx @@ -1,7 +1,10 @@ package funkin.scripting; class ModSubState extends MusicBeatSubstate { - public function new(scriptName:String) { - super(true, scriptName); + public static var lastName:String = null; + public function new(stateName:String) { + if (stateName != null) + lastName = stateName; + super(true, lastName); } } \ No newline at end of file