diff --git a/assets/data/editors/layouts/stage/animEditScreen.xml b/assets/data/editors/layouts/stage/animEditScreen.xml
new file mode 100644
index 0000000000..39c3303ca5
--- /dev/null
+++ b/assets/data/editors/layouts/stage/animEditScreen.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+ function col(c:Int) {
+ return MARGIN + (200 + XOFFSET) * c;
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+ var prevText:String = animID.label.text;
+ function onUpdate() {
+ if (animID.label.text != prevText)
+ self.winTitle = self.titleSpr.text = translate('win-title', null, [animID.label.text]);
+ prevText = animID.label.text;
+
+ labelText.y = (useFrameLabel.y + (useFrameLabel.height / 2)) - (labelText.height / 2);
+ }
+
+ function onSave() {
+ button.animData.name = animID.label.text;
+ button.animData.animType = animType.value;
+ button.animData.anim = animPrefix.label.text;
+ button.animData.fps = animFPS.value;
+ button.animData.x = offsetX.value; button.animData.y = offsetY.value;
+ button.animData.loop = loop.checked;
+ button.animData.forced = forcedPlay.checked;
+ button.animData.indices = CoolUtil.parseNumberRange(animIndices.label.text);
+ button.animData.label = useFrameLabel.checked;
+ button.updateDisplay();
+ }
+
+
\ No newline at end of file
diff --git a/assets/data/editors/layouts/stage/spriteEditScreen.xml b/assets/data/editors/layouts/stage/spriteEditScreen.xml
index de6e70bb27..80bb4d26f7 100644
--- a/assets/data/editors/layouts/stage/spriteEditScreen.xml
+++ b/assets/data/editors/layouts/stage/spriteEditScreen.xml
@@ -6,15 +6,21 @@
function col(c:Int) {
- return 20 + (200 + XOFFSET) * c;
+ return MARGIN + (200 + XOFFSET) * c;
}
if(sprite.animateAtlas == null) {
- previewSprite = new FunkinSprite(50, self.winHeight - 100);
+ previewSprite = new FunkinSprite(MARGIN, self.winHeight - (100 + MARGIN));
previewSprite.frame = sprite.frame;
self.add(previewSprite);
}
+
+ function animTypeToString(animType:AnimType) {
+ return ["none", "beat", "loop"][animType];
+ }
+ if (getEx('anims') == null)
+ setEx('anims', sprite.animDatas.copy());
@@ -25,7 +31,7 @@
-
+
@@ -77,30 +81,39 @@
- buttonlist.addButton.exists = false;
-
-
-
+ for (animData in getEx('anims')) {
+ if (animData.name == 'idle' && animData.anim == null) continue; // Skips dummy animation added by XMLUtil.loadSpriteFromXML
+ addAnimBtn(animData);
+ }
+
@@ -111,10 +124,37 @@
+
+ var prevText = spriteTextBox.label.text;
+ var prevID = nameTextBox.label.text;
+ var spriteExists = true;
+ var ratio = sprite.width / sprite.height;
+
+ spriteTextBox.onChange = function(text) {
+ var newSprite = stage.spritesParentFolder + text;
+ var animated = Paths.framesExists(newSprite, true);
+ spriteExists = ( animated || Assets.exists(Paths.image(newSprite)) );
+
+ if (text != prevText && spriteExists) {
+ if (animated) previewSprite.frames = Paths.getFrames(newSprite, previewSprite.animateSettings);
+ else previewSprite.loadGraphic(Paths.image(newSprite));
+ previewSprite.updateHitbox();
+
+ ratio = previewSprite.width / previewSprite.height;
+ previewSprite.colorTransform.__identity();
+ } else if (!spriteExists) {
+ previewSprite.colorTransform.color = 0xFFEF0202;
+ }
+ prevText = text;
+ }
+
function onUpdate() {
+ if (nameTextBox.label.text != prevID)
+ self.winTitle = self.titleSpr.text = translate('win-sprite-title', [nameTextBox.label.text]);
+ prevID = nameTextBox.label.text;
+
if(previewSprite == null) return;
previewSprite.color = 0xFFFFFFFF; // TODO: Color Wheel
previewSprite.skew.x = skewXStepper.value;
@@ -122,11 +162,10 @@
previewSprite.angle = angleStepper.value;
previewSprite.alpha = alphaStepper.value;
previewSprite.antialiasing = antialiasingCheckbox.checked;
- var ratio = sprite.width / sprite.height;
- previewSprite.setGraphicSize(50 * scaleXStepper.value * ratio, 50 * scaleYStepper.value);
+ previewSprite.setGraphicSize(85 * scaleXStepper.value * ratio, 85 * scaleYStepper.value);
previewSprite.updateHitbox();
}
-
+
function onSave() {
sprite.name = nameTextBox.label.text;
setEx("imageFile", spriteTextBox.label.text);
@@ -134,12 +173,12 @@
setEx("highMemory", highMemoryRadio.checked);
setEx("lowMemory", lowMemoryRadio.checked);
- //sprite.x = xStepper.value;
- //sprite.y = yStepper.value;
- //sprite.zoomFactor = zoomFactorStepper.value;
- //sprite.antialiasing = antialiasingCheckbox.checked;
+ sprite.x = xStepper.value;
+ sprite.y = yStepper.value;
+ sprite.zoomFactor = zoomFactorStepper.value;
+ sprite.antialiasing = antialiasingCheckbox.checked;
//sprite.color = colorWheel.color;
- //sprite.spriteAnimType = animType.value;
+ sprite.spriteAnimType = animTypeToString(animType.value);
sprite.angle = angleStepper.value;
sprite.alpha = alphaStepper.value;
@@ -171,15 +210,48 @@
button.xml.set("x", xStepper.value);
button.xml.set("y", yStepper.value);
button.xml.set("zoom", zoomFactorStepper.value);
- button.xml.set("type", animType.key);
+ button.xml.set("type", animTypeToString(animType.value));
button.xml.set("antialiasing", antialiasingCheckbox.checked);
button.xml.set("angle", angleStepper.value);
button.xml.set("alpha", alphaStepper.value);
+ getEx('anims').clear();
+ var allowedAnims:Array<String> = [for (b in animations.buttons.members) b.animData.name];
+ for (node in button.xml.elementsNamed('anim')) if (!allowedAnims.contains( node.get('name') ))
+ button.xml.removeChild(node);
+
+ for (i in 0...animations.buttons.length) {
+ var actualChildren:Array<Xml> = button.xml.children.filter((f) -> f.nodeType == 0);
+ if (i > actualChildren.length - 1) {
+ var newAnim = Xml.createElement('anim');
+ button.xml.addChild(newAnim);
+ actualChildren.push(newAnim);
+ //trace("added new at " + i + ": " + newAnim);
+ }
+
+ final animData:AnimData = animations.buttons.members[i].animData;
+ final animNode:Xml = actualChildren[i];
+ //trace(animNode + "(" + i + ") before");
+ animNode.set("name", animData.name);
+ animNode.set("type", animTypeToString(animData.animType)); // XMLAnimType is abstract of int, the code is treating it as just int
+ animNode.set("anim", animData.anim);
+ animNode.set("fps", animData.fps);
+ animNode.set("x", animData.x);
+ animNode.set("y", animData.y);
+ animNode.set("loop", animData.loop);
+ animNode.set("forced", CoolUtil.getDefault(animData.forced, false));
+ animNode.set("indices", CoolUtil.formatNumberRange(animData.indices));
+ animNode.set("label", animData.label);
+ //trace(animNode + "(" + i + ")");
+ getEx('anims').set(animData.name, animData);
+ }
+
saveXY(sprite.scrollFactor, "scroll", scrollXStepper, scrollYStepper);
saveXY(sprite.scale, "scale", scaleXStepper, scaleYStepper);
saveXY(sprite.skew, "skew", skewXStepper, skewYStepper);
XMLUtil.loadSpriteFromXML(sprite, button.xml, stage.spritesParentFolder);
+ button.updateInfo();
+ setEx('node', button.xml);
}
\ No newline at end of file
diff --git a/assets/languages/en/Editors.xml b/assets/languages/en/Editors.xml
index 3c98c70f01..ca440fe98d 100644
--- a/assets/languages/en/Editors.xml
+++ b/assets/languages/en/Editors.xml
@@ -594,8 +594,9 @@
Stage Info
Stage Name
Sprite Path\n(Needs Refresh)
- Start Camera Position (X, Y)
+ Start Camera Position\n(X, Y)
Zoom
+ Custom Attributes
@@ -609,7 +610,7 @@
Element Name
Name Identifier
- Image File (WIP: needs reload)\nIn (${stage.spritesParentFolder})
+ Image File\n(in "{0}")
Scroll {0}
Scale {0}
Camera {0}
@@ -625,6 +626,7 @@
Low Memory
Attributes
Transform Preview:
+ Animations
Animation Type
@@ -633,6 +635,8 @@
LOOP
Tip: To access custom properties,\nHold Shift when clicking edit
+
+ Name on Anim Data
@@ -647,6 +651,7 @@
Scale: {0}, {1}
Scroll: {0}, {1}
+ Unknown Sprite:\n{0}
@@ -656,6 +661,14 @@
Character
Creating a box isnt implemented yet!
+
+
+ Editing "{0}" Anim
+ Anim Data
+ Use Frame Labels?
+ Offset (X, Y)
+ Forced Playing?
+
diff --git a/assets/languages/en/Options.xml b/assets/languages/en/Options.xml
index d1958961fc..1cde775d71 100644
--- a/assets/languages/en/Options.xml
+++ b/assets/languages/en/Options.xml
@@ -177,6 +177,9 @@
Editor SFXs
If checked, will play sound effects when working on editors (ex: will play sfxs when checking checkboxes...)
+ Swap Event Sides
+ If checked, global events will be on the left of the strumlines.
+
Chart Pretty Print
If checked, the saved files from the chart editor will be formatted to be easily viewable
diff --git a/assets/languages/es/Editors.xml b/assets/languages/es/Editors.xml
index f8f23dd52d..8e4da69a0f 100644
--- a/assets/languages/es/Editors.xml
+++ b/assets/languages/es/Editors.xml
@@ -551,7 +551,7 @@
Info. del Escenario
Nombre del Escenario
Ubicación de Imágenes\n(Necesita Refrescar)
- Posición inicial de la cámara (X, Y)
+ Posición inicial de la cámara\n(X, Y)
Zoom
@@ -566,7 +566,7 @@
Nombre del Elemento
Identificador de Nombre
- Imagen (WIP: necesita refrescar)\nEn (${stage.spritesParentFolder})
+ Imagen\n(en "{0}")
Desplazamiento {0}
Tamaño {0}
Cámara {0}
@@ -580,6 +580,7 @@
Baja Memoria
Atributos
Preview:
+ Animaciónes
Tipo de Animación
@@ -602,6 +603,7 @@
Tamaño: {0}, {1}
Desplazamiento: {0}, {1}
+ Sprite Desconocido:\n{0}
diff --git a/assets/languages/es/Options.xml b/assets/languages/es/Options.xml
index bd25ee90b8..60ad120cd9 100644
--- a/assets/languages/es/Options.xml
+++ b/assets/languages/es/Options.xml
@@ -117,7 +117,7 @@
Transmición de Música
Si está activado, la música será transmitida en tiempo real, liberando un montón de RAM, aunque usará más CPU si hay mucho audio al mismo tiempo (EXPERIMENTAL). Desactivarlo consumirá más RAM, especialmente en canciones más largas. Si no estás seguro, déjalo activado.
-
+
Transmición de Vocales
Si está activado, las vocales también serán transmitidas, impactará el rendimiento si hay muchas vocales (EXPERIMENTAL). Si no estás seguro, déjalo desactivade.
@@ -158,10 +158,13 @@
Desactivar Tamaño Mínimo
Desactiva el tamaño mínimo de los editores (Editores Adaptables debe estar activado).
-
+
Sonidos del Editor
Si está activado, habran sonidos en los editores (ej: al activar opciones...)
+ Cambiar Lados de Eventos
+ Si está activado, eventos globales estarán a la izquierda de las pistas.
+
Si está activado, los charts se guardarán de forma más legible (no aplica a XMLs)
Difuminado Intensivo
diff --git a/assets/languages/it/Editors.xml b/assets/languages/it/Editors.xml
index 90853b8587..d0968dc16a 100644
--- a/assets/languages/it/Editors.xml
+++ b/assets/languages/it/Editors.xml
@@ -561,7 +561,7 @@
Informazioni Palcoscenico
Nome Palcoscenico
Percorso file Sprite\n(E' necessario ricaricare la pagina)
- Posizioni iniziali della Telecamera (X, Y)
+ Posizioni iniziali della Telecamera\n(X, Y)
Zoom
@@ -576,7 +576,7 @@
Nome Elemento
Nome Identificatore
- File Immagine (WIP: reload necessario)\nIn (${stage.spritesParentFolder})
+ File Immagine\n(in "{0}")
Scorrimento {0}
Scala {0}
Teleamera {0}
diff --git a/assets/languages/pl/Editors.xml b/assets/languages/pl/Editors.xml
index 694e66c3d9..86ff120c14 100644
--- a/assets/languages/pl/Editors.xml
+++ b/assets/languages/pl/Editors.xml
@@ -568,7 +568,7 @@
Info Sceny
Nazwa Sceny
Ścieżka Plikowa Sprite'a\n(Wymaga Odświeżenia)
- Pozycja Startowa Kamery (X, Y)
+ Pozycja Startowa Kamery\n(X, Y)
Przybliżenie
@@ -583,7 +583,7 @@
Nazwa Elementu
Nazwa Identyfikatora
- Plik Obrazu (W TRACKIE PRACY: wymaga odświeżenia)\nIn (${stage.spritesParentFolder})
+ Plik Obrazu\n(in "{0}")
Przewijanie {0}
Skala {0}
Kamera {0}
diff --git a/assets/languages/pt/Editors.xml b/assets/languages/pt/Editors.xml
index aa718df294..2d0a05208d 100644
--- a/assets/languages/pt/Editors.xml
+++ b/assets/languages/pt/Editors.xml
@@ -588,7 +588,7 @@
Info. do Cenário
Nome do Cenário
Caminho do Sprite\n(Requer Recarregamento)
- Posição inicial da Câmara (X, Y)
+ Posição inicial da Câmara\n(X, Y)
Zoom
Atributos Especiais
@@ -604,7 +604,7 @@
Nome do Elemento
Nome Identificador
- Imagem (WIP: precisa recarregar)\nEm (${stage.spritesParentFolder})
+ Imagem\n(em "{0}")
Scroll {0}
Tamanho {0}
Câmara {0}
@@ -629,6 +629,8 @@
REPETIR
Dica: Para aceder a mais dados,\nSegure em Shift quando Editar
+
+ Nome em Dados de Animação
@@ -643,6 +645,7 @@
Tamanho: {0}, {1}
Deslocamento: {0}, {1}
+ Sprite Desconhecido:\n{0}
@@ -652,6 +655,14 @@
Personagem
Criar caixas ainda não foi implementado!
+
+
+ A Editar a Animação "{0}"
+ Dados da Animação
+ Usar Rótulos\nde Quadro?
+ Posições (X, Y)
+ Reprodução Forçada?
+
diff --git a/assets/languages/pt/Options.xml b/assets/languages/pt/Options.xml
index c9f02aac1e..82ce97c7d7 100644
--- a/assets/languages/pt/Options.xml
+++ b/assets/languages/pt/Options.xml
@@ -177,6 +177,9 @@
Sons de Editor
Se marcado, tocará efeitos sonoros nos editores (ex: ao carregar em caixas...)
+ Trocar Lados de Eventos
+ Se marcado, eventos globais estarão no lado esquerdo das pistas.
+
Mapas Legíveis
Se marcado, os ficheiros guardados no editor de mapas serão formatados para serem fácilmente legíveis.
diff --git a/source/flx3d/Flx3DCamera.hx b/source/flx3d/Flx3DCamera.hx
index d4f76229e8..48089857b7 100644
--- a/source/flx3d/Flx3DCamera.hx
+++ b/source/flx3d/Flx3DCamera.hx
@@ -25,19 +25,25 @@ import flx3d.Flx3DUtil;
import haxe.io.Path;
import openfl.Assets;
#end
-
import flixel.FlxCamera;
-class Flx3DCamera extends FlxCamera {
+class Flx3DCamera extends FlxCamera
+{
#if THREE_D_SUPPORT
private static var __3DIDS:Int = 0;
public var view:View3D;
var meshes:Array = [];
- public function new(X:Int = 0, Y:Int = 0, Width:Int = 0, Height:Int = 0, DefaultZoom:Float = 1) {
+
+ public function new(X:Int = 0, Y:Int = 0, Width:Int = 0, Height:Int = 0, DefaultZoom:Float = 1)
+ {
if (!Flx3DUtil.is3DAvailable())
- throw "[Flx3DCamera] 3D is not available on this platform. Stages in use: " + Flx3DUtil.getTotal3D() + ", Max stages allowed: " + FlxG.stage.stage3Ds.length + ".";
+ throw "[Flx3DCamera] 3D is not available on this platform. Stages in use: "
+ + Flx3DUtil.getTotal3D()
+ + ", Max stages allowed: "
+ + FlxG.stage.stage3Ds.length
+ + ".";
super(X, Y, Width, Height, DefaultZoom);
__cur3DStageID = __3DIDS++;
@@ -49,7 +55,8 @@ class Flx3DCamera extends FlxCamera {
FlxG.stage.addChild(view);
}
- public override function render() {
+ public override function render()
+ {
super.render();
view.x = FlxG.game.x + FlxG.game.scaleX * (flashSprite.x + flashSprite.scaleX * (_scrollRect.x + _scrollRect.scaleX * (_scrollRect.scrollRect.x)));
@@ -65,7 +72,8 @@ class Flx3DCamera extends FlxCamera {
view.render();
}
- public function addModel(assetPath:String, callback:Asset3DEvent->Void, ?texturePath:String, smoothTexture:Bool = true) {
+ public function addModel(assetPath:String, callback:Asset3DEvent->Void, ?texturePath:String, smoothTexture:Bool = true)
+ {
var model = Assets.getBytes(assetPath);
if (model == null)
throw 'Model at ${assetPath} was not found.';
@@ -79,36 +87,43 @@ class Flx3DCamera extends FlxCamera {
if (texturePath != null)
material = new TextureMaterial(Cast.bitmapTexture(Assets.getBitmapData(texturePath, true, false)), smoothTexture);
- return loadData(model, context, switch(Path.extension(assetPath).toLowerCase()) {
+ return loadData(model, context, switch (Path.extension(assetPath).toLowerCase())
+ {
case "dae": new DAEParser();
case "md2": new MD2Parser();
case "md5": new MD5MeshParser();
case "awd": new AWDParser();
- default: new OBJParser();
- }, (event:Asset3DEvent) -> {
- if (event.asset != null && event.asset.assetType == Asset3DType.MESH) {
- var mesh:Mesh = cast event.asset;
- if (material != null)
- mesh.material = material;
- meshes.push(mesh);
- }
- callback(event);
- });
+ default: new OBJParser();
+ }, (event:Asset3DEvent) ->
+ {
+ if (event.asset != null && event.asset.assetType == Asset3DType.MESH)
+ {
+ var mesh:Mesh = cast event.asset;
+ if (material != null)
+ mesh.material = material;
+ meshes.push(mesh);
+ }
+ callback(event);
+ });
}
private var __cur3DStageID:Int;
private var _loaders:Map = [];
- private function loadData(data:Dynamic, context:AssetLoaderContext, parser:ParserBase, onAssetCallback:Asset3DEvent->Void):AssetLoaderToken {
+ private function loadData(data:Dynamic, context:AssetLoaderContext, parser:ParserBase, onAssetCallback:Asset3DEvent->Void):AssetLoaderToken
+ {
var token:AssetLoaderToken;
var lib:Asset3DLibraryBundle = Asset3DLibraryBundle.getInstance('Flx3DView-${__cur3DStageID}');
token = lib.loadData(data, context, null, parser);
- token.addEventListener(Asset3DEvent.ASSET_COMPLETE, (event:Asset3DEvent) -> {
+ token.addEventListener(Asset3DEvent.ASSET_COMPLETE, (event:Asset3DEvent) ->
+ {
// ! Taken from Loader3D https://github.com/openfl/away3d/blob/master/away3d/loaders/Loader3D.hx#L207-L232
- if (event.type == Asset3DEvent.ASSET_COMPLETE) {
- var obj:ObjectContainer3D = switch (event.asset.assetType) {
+ if (event.type == Asset3DEvent.ASSET_COMPLETE)
+ {
+ var obj:ObjectContainer3D = switch (event.asset.assetType)
+ {
case Asset3DType.LIGHT: expect(event.asset, LightBase);
case Asset3DType.CONTAINER: expect(event.asset, ObjectContainer3D);
case Asset3DType.MESH: expect(event.asset, Mesh);
@@ -126,25 +141,29 @@ class Flx3DCamera extends FlxCamera {
onAssetCallback(event);
});
- token.addEventListener(LoaderEvent.RESOURCE_COMPLETE, (_) -> {
+ token.addEventListener(LoaderEvent.RESOURCE_COMPLETE, (_) ->
+ {
trace("Loader Finished...");
});
- _loaders.set(lib,token);
+ _loaders.set(lib, token);
return token;
}
- override function destroy() {
+ override function destroy()
+ {
if (meshes != null)
- for(mesh in meshes)
+ for (mesh in meshes)
mesh.dispose();
var bundle = Asset3DLibraryBundle.getInstance('Flx3DView-${__cur3DStageID}');
bundle.stopAllLoadingSessions();
@:privateAccess {
- if (bundle._loadingSessions != null) {
- for(load in bundle._loadingSessions) {
+ if (bundle._loadingSessions != null)
+ {
+ for (load in bundle._loadingSessions)
+ {
load.dispose();
}
}
@@ -152,10 +171,12 @@ class Flx3DCamera extends FlxCamera {
}
FlxG.stage.removeChild(view);
- try {
+ try
+ {
view.dispose();
- } catch(e) {
-
+ }
+ catch (e)
+ {
}
super.destroy();
@@ -164,4 +185,4 @@ class Flx3DCamera extends FlxCamera {
public function addChild(c)
view.scene.addChild(c);
#end
-}
\ No newline at end of file
+}
diff --git a/source/flx3d/Flx3DView.hx b/source/flx3d/Flx3DView.hx
index 59413e77db..9004d27af8 100644
--- a/source/flx3d/Flx3DView.hx
+++ b/source/flx3d/Flx3DView.hx
@@ -25,20 +25,27 @@ import away3d.utils.Utils.expect;
#end
// FlxView3D with helpers for easier updating
-class Flx3DView extends FlxView3D {
+class Flx3DView extends FlxView3D
+{
#if THREE_D_SUPPORT
private static var __3DIDS:Int = 0;
var meshes:Array = [];
- public function new(x:Float = 0, y:Float = 0, width:Int = -1, height:Int = -1) {
+
+ public function new(x:Float = 0, y:Float = 0, width:Int = -1, height:Int = -1)
+ {
if (!Flx3DUtil.is3DAvailable())
- throw "[Flx3DView] 3D is not available on this platform. Stages in use: " + Flx3DUtil.getUsed3D() + ", Max stages allowed: " + Flx3DUtil.getTotal3D() + ".";
+ throw "[Flx3DView] 3D is not available on this platform. Stages in use: "
+ + Flx3DUtil.getUsed3D()
+ + ", Max stages allowed: "
+ + Flx3DUtil.getTotal3D()
+ + ".";
super(x, y, width, height);
__cur3DStageID = __3DIDS++;
}
- public function addModel(assetPath:String, callback:Asset3DEvent->Void, ?texturePath:String, smoothTexture:Bool = true) {
-
+ public function addModel(assetPath:String, callback:Asset3DEvent->Void, ?texturePath:String, smoothTexture:Bool = true)
+ {
var model = Assets.getBytes(assetPath);
if (model == null)
throw 'Model at ${assetPath} was not found.';
@@ -52,37 +59,44 @@ class Flx3DView extends FlxView3D {
if (texturePath != null)
material = new TextureMaterial(Cast.bitmapTexture(Assets.getBitmapData(texturePath, true, false)), smoothTexture);
- return loadData(model, context, switch(Path.extension(assetPath).toLowerCase()) {
+ return loadData(model, context, switch (Path.extension(assetPath).toLowerCase())
+ {
case "dae": new DAEParser();
case "md2": new MD2Parser();
case "md5": new MD5MeshParser();
case "awd": new AWDParser();
- default: new OBJParser();
- }, (event:Asset3DEvent) -> {
- if (event.asset != null && event.asset.assetType == Asset3DType.MESH) {
- var mesh:Mesh = cast event.asset;
- if (material != null)
- mesh.material = material;
- meshes.push(mesh);
- }
- callback(event);
- });
+ default: new OBJParser();
+ }, (event:Asset3DEvent) ->
+ {
+ if (event.asset != null && event.asset.assetType == Asset3DType.MESH)
+ {
+ var mesh:Mesh = cast event.asset;
+ if (material != null)
+ mesh.material = material;
+ meshes.push(mesh);
+ }
+ callback(event);
+ });
}
private var __cur3DStageID:Int;
private var _loaders:Map = [];
- private function loadData(data:Dynamic, context:AssetLoaderContext, parser:ParserBase, onAssetCallback:Asset3DEvent->Void):AssetLoaderToken {
+ private function loadData(data:Dynamic, context:AssetLoaderContext, parser:ParserBase, onAssetCallback:Asset3DEvent->Void):AssetLoaderToken
+ {
var token:AssetLoaderToken;
var lib:Asset3DLibraryBundle;
lib = Asset3DLibraryBundle.getInstance('Flx3DView-${__cur3DStageID}');
token = lib.loadData(data, context, null, parser);
- token.addEventListener(Asset3DEvent.ASSET_COMPLETE, (event:Asset3DEvent) -> {
+ token.addEventListener(Asset3DEvent.ASSET_COMPLETE, (event:Asset3DEvent) ->
+ {
// ! Taken from Loader3D https://github.com/openfl/away3d/blob/master/away3d/loaders/Loader3D.hx#L207-L232
- if (event.type == Asset3DEvent.ASSET_COMPLETE) {
- var obj:ObjectContainer3D = switch (event.asset.assetType) {
+ if (event.type == Asset3DEvent.ASSET_COMPLETE)
+ {
+ var obj:ObjectContainer3D = switch (event.asset.assetType)
+ {
case Asset3DType.LIGHT: expect(event.asset, LightBase);
case Asset3DType.CONTAINER: expect(event.asset, ObjectContainer3D);
case Asset3DType.MESH: expect(event.asset, Mesh);
@@ -100,26 +114,29 @@ class Flx3DView extends FlxView3D {
onAssetCallback(event);
});
- token.addEventListener(LoaderEvent.RESOURCE_COMPLETE, (_) -> {
+ token.addEventListener(LoaderEvent.RESOURCE_COMPLETE, (_) ->
+ {
trace("Loader Finished...");
-
});
- _loaders.set(lib,token);
+ _loaders.set(lib, token);
return token;
}
- override function destroy() {
+ override function destroy()
+ {
if (meshes != null)
- for(mesh in meshes)
+ for (mesh in meshes)
mesh.dispose();
var bundle = Asset3DLibraryBundle.getInstance('Flx3DView-${__cur3DStageID}');
bundle.stopAllLoadingSessions();
@:privateAccess {
- if (bundle._loadingSessions != null) {
- for(load in bundle._loadingSessions) {
+ if (bundle._loadingSessions != null)
+ {
+ for (load in bundle._loadingSessions)
+ {
load.dispose();
}
}
@@ -132,4 +149,4 @@ class Flx3DView extends FlxView3D {
public function addChild(c)
view.scene.addChild(c);
#end
-}
\ No newline at end of file
+}
diff --git a/source/flx3d/FlxView3D.hx b/source/flx3d/FlxView3D.hx
index 11137eed3f..b07b78e213 100644
--- a/source/flx3d/FlxView3D.hx
+++ b/source/flx3d/FlxView3D.hx
@@ -1,6 +1,7 @@
package flx3d;
#if THREE_D_SUPPORT
+import flx3d._internal.TextureView3D;
import away3d.containers.View3D;
import away3d.library.assets.IAsset;
import flixel.FlxG;
@@ -18,7 +19,35 @@ import flixel.FlxSprite;
class FlxView3D extends FlxSprite
{
#if THREE_D_SUPPORT
- @:noCompletion private var bmp:BitmapData;
+ @:noCompletion private var bmp:BitmapData = null;
+ private var _textureView:TextureView3D;
+ private var legacyRender:Bool = false;
+
+ // With new rendering, it seems to only work if 2 or more views are being rendered.
+ // This workaround creates a second instance if there is only one view.
+ // "There is nothing more permanent than a temporary solution"
+ // -idk who said this i just wanted to quote it
+ private static var workaroundInstance:FlxView3D;
+ private static var createdWorkaround:Bool = false;
+
+ private inline function createWorkaround()
+ {
+ if (!createdWorkaround && !legacyRender)
+ {
+ createdWorkaround = true;
+ workaroundInstance = new FlxView3D(0, 0, 1, 1);
+ FlxG.state.add(workaroundInstance);
+ }
+ }
+
+ private inline function destroyWorkaround()
+ {
+ if (workaroundInstance == this)
+ {
+ workaroundInstance = null;
+ createdWorkaround = false;
+ }
+ }
/**
* The Away3D View
@@ -40,19 +69,39 @@ class FlxView3D extends FlxSprite
*/
public function new(x:Float = 0, y:Float = 0, width:Int = -1, height:Int = -1)
{
+ legacyRender = false;
+
super(x, y);
+ if (legacyRender)
+ {
+ view = new View3D();
+ }
+ else
+ {
+ _textureView = new TextureView3D();
+ _textureView.onUpdateBitmap = function(bitmap)
+ {
+ bmp = bitmap;
+ loadGraphic(bmp);
+ }
+
+ view = _textureView;
+ }
- view = new View3D();
view.visible = false;
- view.width = width == -1 ? FlxG.width : width;
- view.height = height == -1 ? FlxG.height : height;
+ this.width = width == -1 ? FlxG.width : width;
+ this.height = height == -1 ? FlxG.height : height;
+ if (legacyRender)
+ {
+ bmp = new BitmapData(Std.int(view.width), Std.int(view.height), true, 0x0);
+ loadGraphic(bmp);
+ }
view.backgroundAlpha = 0;
FlxG.stage.addChildAt(view, 0);
- bmp = new BitmapData(Std.int(view.width), Std.int(view.height), true, 0x0);
- loadGraphic(bmp);
+ createWorkaround();
}
/**
@@ -84,26 +133,34 @@ class FlxView3D extends FlxSprite
view.dispose();
view = null;
}
+
+ destroyWorkaround();
}
@:noCompletion override function draw()
{
- super.draw();
-
if (dirty3D)
{
- view.visible = false;
- FlxG.stage.addChildAt(view, 0);
-
- var old = FlxG.game.filters;
- FlxG.game.filters = null;
-
- view.renderer.queueSnapshot(bmp);
- view.render();
-
- FlxG.game.filters = old;
- FlxG.stage.removeChild(view);
+ if (legacyRender)
+ {
+ view.visible = false;
+ FlxG.stage.addChildAt(view, 0);
+
+ var old = FlxG.game.filters;
+ FlxG.game.filters = null;
+
+ view.renderer.queueSnapshot(bmp);
+ view.render();
+
+ FlxG.game.filters = old;
+ FlxG.stage.removeChild(view);
+ }
+ else
+ {
+ view.render();
+ }
}
+ super.draw();
}
@:noCompletion override function set_width(newWidth:Float):Float
diff --git a/source/flx3d/_internal/TextureView3D.hx b/source/flx3d/_internal/TextureView3D.hx
new file mode 100644
index 0000000000..efce9b9a4f
--- /dev/null
+++ b/source/flx3d/_internal/TextureView3D.hx
@@ -0,0 +1,177 @@
+package flx3d._internal;
+
+import flixel.FlxG;
+import haxe.Exception;
+import away3d.containers.View3D;
+import away3d.containers.Scene3D;
+import away3d.cameras.Camera3D;
+import away3d.core.render.RendererBase;
+import away3d.core.managers.Stage3DManager;
+import away3d.core.managers.Stage3DProxy;
+import openfl.display3D.textures.TextureBase;
+import openfl.display3D.textures.RectangleTexture;
+import openfl.display3D.Context3D;
+import openfl.display.BitmapData;
+import openfl.events.Event;
+import openfl.geom.Point;
+
+class TextureView3D extends View3D
+{
+ public var bitmap:BitmapData;
+
+ private var _framebuffer:TextureBase = null;
+
+ public var onUpdateBitmap:(BitmapData) -> Void;
+
+ /**
+ * Prevents the engine from disposing Flixel's Stage3D/Context3D instance
+ */
+ public override function dispose() @:privateAccess {
+ _stage3DProxy = null;
+ super.dispose();
+ }
+
+ private override function set_height(value:Float):Float
+ {
+ if (_height == value)
+ return value;
+ super.set_height(value);
+ _createFramebuffer();
+ return value;
+ }
+
+ private override function set_width(value:Float):Float
+ {
+ if (_width == value)
+ return value;
+ super.set_width(value);
+ _createFramebuffer();
+ return value;
+ }
+
+ public function new(scene:Scene3D = null, camera:Camera3D = null, renderer:RendererBase = null, forceSoftware:Bool = false, profile:String = "baseline",
+ contextIndex:Int = -1)
+ {
+ super(scene, camera, renderer, forceSoftware, profile, contextIndex);
+
+ _stage3DProxy = Stage3DManager.getInstance(FlxG.stage).getStage3DProxy(0);
+ _createFramebuffer();
+ }
+
+ private function _createFramebuffer()
+ {
+ if (width == 0 || height == 0)
+ return;
+ if (_framebuffer != null)
+ _framebuffer.dispose();
+ _framebuffer = FlxG.stage.context3D.createRectangleTexture(Std.int(_width), Std.int(_height), BGRA, true);
+ bitmap = BitmapDataCrashFix.fromTextureCrashFix(_framebuffer);
+ onUpdateBitmap(bitmap);
+ }
+
+ /**
+ * Renders the view.
+ */
+ public override function render():Void
+ {
+ Stage3DProxy.drawTriangleCount = 0;
+
+ // if context3D has Disposed by the OS,don't render at this frame
+ if (stage3DProxy.context3D == null || !stage3DProxy.recoverFromDisposal())
+ {
+ _backBufferInvalid = true;
+ return;
+ }
+
+ // reset or update render settings
+ if (_backBufferInvalid)
+ updateBackBuffer();
+
+ if (_shareContext && _layeredView)
+ stage3DProxy.clearDepthBuffer();
+
+ if (!_parentIsStage)
+ {
+ var globalPos:Point = parent.localToGlobal(_localTLPos);
+ if (_globalPos.x != globalPos.x || _globalPos.y != globalPos.y)
+ {
+ _globalPos = globalPos;
+ _globalPosDirty = true;
+ }
+ }
+
+ if (_globalPosDirty)
+ updateGlobalPos();
+
+ updateTime();
+
+ updateViewSizeData();
+
+ _entityCollector.clear();
+
+ // collect stuff to render
+ _scene.traversePartitions(_entityCollector);
+
+ // update picking
+ _mouse3DManager.updateCollider(this);
+ _touch3DManager.updateCollider();
+
+ if (_requireDepthRender)
+ renderSceneDepthToTexture(_entityCollector);
+
+ // todo: perform depth prepass after light update and before final render
+ if (_depthPrepass)
+ renderDepthPrepass(_entityCollector);
+
+ @:privateAccess _renderer.clearOnRender = !_depthPrepass;
+
+ if (_filter3DRenderer != null && _stage3DProxy.context3D != null)
+ {
+ _renderer.render(_entityCollector, _filter3DRenderer.getMainInputTexture(_stage3DProxy), _rttBufferManager.renderToTextureRect);
+ _filter3DRenderer.render(_stage3DProxy, camera, _depthRender);
+ }
+ else
+ {
+ @:privateAccess _renderer.shareContext = _shareContext;
+ if (_shareContext)
+ _renderer.render(_entityCollector, _framebuffer, _scissorRect);
+ else
+ _renderer.render(_entityCollector, _framebuffer);
+ }
+
+ if (!_shareContext)
+ {
+ stage3DProxy.present();
+
+ // fire collected mouse events
+ _mouse3DManager.fireMouseEvents();
+ _touch3DManager.fireTouchEvents();
+ }
+
+ // clean up data for this render
+ _entityCollector.cleanUp();
+
+ // register that a view has been rendered
+ stage3DProxy.bufferClear = false;
+ }
+}
+
+class BitmapDataCrashFix extends BitmapData
+{
+ public static function fromTextureCrashFix(texture:TextureBase):BitmapDataCrashFix @:privateAccess {
+ if (texture == null)
+ return null;
+
+ var bitmapData = new BitmapDataCrashFix(texture.__width, texture.__height, true, 0);
+ bitmapData.readable = false;
+ bitmapData.__texture = texture;
+ bitmapData.__textureContext = texture.__textureContext;
+ bitmapData.image = null;
+ return bitmapData;
+ }
+
+ @:dox(hide) public override function getTexture(context:Context3D):TextureBase
+ {
+ return __texture;
+ }
+}
diff --git a/source/funkin/backend/assets/AssetsLibraryList.hx b/source/funkin/backend/assets/AssetsLibraryList.hx
index d512626856..10c1d33208 100644
--- a/source/funkin/backend/assets/AssetsLibraryList.hx
+++ b/source/funkin/backend/assets/AssetsLibraryList.hx
@@ -228,7 +228,7 @@ class AssetsLibraryList extends AssetLibrary {
}
#end
- __defaultLibraries.push(ModsFolder.loadLibraryFromFolder('assets', rootDirectory, true, SOURCE));
+ __defaultLibraries.push(ModsFolder.loadLibraryFromFolder('assets', rootDirectory, true, null, SOURCE));
#end
diff --git a/source/funkin/backend/assets/ModsFolder.hx b/source/funkin/backend/assets/ModsFolder.hx
index 8eb9dd4318..0e33f999ed 100644
--- a/source/funkin/backend/assets/ModsFolder.hx
+++ b/source/funkin/backend/assets/ModsFolder.hx
@@ -2,6 +2,8 @@ package funkin.backend.assets;
import flixel.util.FlxSignal.FlxTypedSignal;
import funkin.backend.system.MainState;
+import funkin.backend.utils.CoolUtil;
+import haxe.ds.StringMap;
import haxe.io.Path;
import lime.text.Font;
import openfl.text.Font as OpenFLFont;
@@ -42,6 +44,8 @@ class ModsFolder {
* Whenever its the first time mods has been reloaded.
*/
private static var __firstTime:Bool = true;
+
+ @:dox(hide) public static var modsListSortCache:StringMap> = new StringMap();
/**
* Initializes `mods` folder.
@@ -94,7 +98,7 @@ class ModsFolder {
#end
}
- public static function getModsList():Array {
+ public static function getModsList(?sortingOptions:ModSortingOptions):Array {
var mods:Array = [];
#if MOD_SUPPORT
// Mods directory does not exist yet, create it
@@ -108,6 +112,28 @@ class ModsFolder {
if (FileSystem.isDirectory(modsPath + modFolder)) mods.push(modFolder);
else if (Flags.ALLOWED_ZIP_EXTENSIONS.contains(Path.extension(modFolder))) mods.push(Path.withoutExtension(modFolder));
}
+
+ if (sortingOptions != null) {
+ var sortForge:StringBuf = new StringBuf();
+ for (i in mods) {
+ sortForge.add(i);
+ sortForge.add("::");
+ }
+
+ sortForge.add(Std.string(sortingOptions.descending ? 1 : 0));
+
+ sortForge.add(sortingOptions.mode);
+
+ final sortForgePure:String = sortForge.toString();
+
+ if (modsListSortCache.exists(sortForgePure))
+ mods = modsListSortCache.get(sortForgePure);
+ if (mods.length > 0 && mods[mods.length - 1] == null) mods.pop();
+ else {
+ ModSortingController.sort(sortingOptions, mods);
+ modsListSortCache.set(sortForgePure, mods);
+ }
+ }
#end
return mods;
}
@@ -167,3 +193,48 @@ class ModsFolder {
}
#end
}
+
+/**
+ * Describes how mods should be sorted when getting the mods list.
+ */
+typedef ModSortingOptions = {
+ /**
+ * Whether or not the list should go in descending order (e.g. `[2, 1, 0]`).
+ */
+ var descending:Bool;
+ /**
+ * The sorting mode to use.
+ */
+ var mode:ModSortingMode;
+}
+
+/**
+ * This class performs the actual sorting for the mods list.
+ */
+class ModSortingController {
+ /**
+ * Sort the mods list, according to the provided sorting options.
+ */
+ public static function sort(sortingOptions:ModSortingOptions, list:Array):Void {
+ switch (sortingOptions.mode) {
+ case ModSortingMode.CLEAN: {}
+ case ModSortingMode.ALPHABETICAL: CoolUtil.sortAlphabetically(list);
+ }
+ if (sortingOptions.descending) list.reverse();
+ }
+}
+
+/**
+ * The mods list can be sorted in all of the ways provided by this enum.
+ */
+enum abstract ModSortingMode(String) {
+ /**
+ * Use the original list received from reading the directory. This may depend
+ * on the current platform, but remains for legacy purposes.
+ */
+ var CLEAN;
+ /**
+ * The list should be in alphabetical order.
+ */
+ var ALPHABETICAL;
+}
\ No newline at end of file
diff --git a/source/funkin/editors/charter/Charter.hx b/source/funkin/editors/charter/Charter.hx
index 00843e1b9f..a06118f425 100644
--- a/source/funkin/editors/charter/Charter.hx
+++ b/source/funkin/editors/charter/Charter.hx
@@ -443,25 +443,26 @@ class Charter extends UIState {
gridBackdrops = new CharterBackdropGroup(strumLines);
gridBackdrops.notesGroup = this.notesGroup;
- leftEventRowText = new UIText(0, -40, 0, translate("info.localEvents"), 12);
+ leftEventRowText = new UIText(0, -40, 0, translate("info." + (Options.charterSwapEventSides ? "globalEvents" : "localEvents")), 12);
leftEventRowText.alignment = "center"; leftEventRowText.alpha = 0.75;
leftEventsBackdrop = new EventBackdrop(false);
leftEventsBackdrop.x = -leftEventsBackdrop.width;
leftEventRowText.cameras = leftEventsBackdrop.cameras = leftEventsGroup.cameras = [charterCamera];
- leftEventsGroup.eventsBackdrop = leftEventsBackdrop;
- leftEventsGroup.eventsRowText = leftEventRowText;
- rightEventRowText = new UIText(0, -40, 0, translate("info.globalEvents"), 12);
+ rightEventRowText = new UIText(0, -40, 0, translate("info." + (Options.charterSwapEventSides ? "localEvents" : "globalEvents")), 12);
rightEventRowText.alignment = "center"; rightEventRowText.alpha = 0.75;
rightEventsBackdrop = new EventBackdrop(true);
rightEventsBackdrop.x = 0;
rightEventRowText.cameras = rightEventsBackdrop.cameras = rightEventsGroup.cameras = [charterCamera];
- rightEventsGroup.eventsBackdrop = rightEventsBackdrop;
- rightEventsGroup.eventsRowText = rightEventRowText;
+
+ leftEventsGroup.eventsBackdrop = Options.charterSwapEventSides ? rightEventsBackdrop : leftEventsBackdrop;
+ leftEventsGroup.eventsRowText = Options.charterSwapEventSides ? rightEventRowText : leftEventRowText;
+ rightEventsGroup.eventsBackdrop = Options.charterSwapEventSides ? leftEventsBackdrop : rightEventsBackdrop;
+ rightEventsGroup.eventsRowText = Options.charterSwapEventSides ? leftEventRowText : rightEventRowText;
// thank you neo for pointing out im stupid -lunar
// this is future lunar i completely forgot what neo pointed out but hes awesome go follow him on twitter
@@ -537,12 +538,12 @@ class Charter extends UIState {
strumlineInfoBG.cameras = [charterCamera];
strumLines.cameras = [charterCamera];
- localAddEventSpr = new CharterEventAdd(false);
+ localAddEventSpr = new CharterEventAdd(Options.charterSwapEventSides);
localAddEventSpr.x -= localAddEventSpr.bWidth;
localAddEventSpr.cameras = [charterCamera];
localAddEventSpr.alpha = 0;
- globalAddEventSpr = new CharterEventAdd(true);
+ globalAddEventSpr = new CharterEventAdd(!Options.charterSwapEventSides);
globalAddEventSpr.x = 0;
globalAddEventSpr.cameras = [charterCamera];
globalAddEventSpr.alpha = 0;
@@ -920,11 +921,12 @@ class Charter extends UIState {
n.cursor = HAND;
}, function (e:CharterEvent) {
e.snappedToGrid = false;
- e.setPosition(e.eventsBackdrop.x + (e.global ? 0 : e.eventsBackdrop.width - e.bWidth) + (mousePos.x - dragStartPos.x), e.step * 40 + (mousePos.y - dragStartPos.y) - 17);
+ var isGlobal = e.global != Options.charterSwapEventSides;
+ e.setPosition(e.eventsBackdrop.x + (isGlobal ? 0 : e.eventsBackdrop.width - e.bWidth) + (mousePos.x - dragStartPos.x), e.step * 40 + (mousePos.y - dragStartPos.y) - 17);
e.y = CoolUtil.bound(e.y, -17, (__endStep*40)-17);
e.cursor = HAND;
- e.displayGlobal = e.x + (e.bWidth/2) > ((strumLines.totalKeyCount*40)/2);
+ e.displayGlobal = e.x + (e.bWidth/2) > ((strumLines.totalKeyCount*40)/2) != Options.charterSwapEventSides;
});
currentCursor = HAND;
} else {
@@ -1045,7 +1047,7 @@ class Charter extends UIState {
var e:CharterEvent = cast s;
var newEvent = new CharterEvent(e.step, [for (event in e.events) Reflect.copy(event)], e.global);
newEvent.refreshEventIcons();
- (e.global ? rightEventsGroup : leftEventsGroup).add(newEvent);
+ ((e.global != Options.charterSwapEventSides) ? rightEventsGroup : leftEventsGroup).add(newEvent);
newSelection.push(newEvent);
}
}
@@ -1123,11 +1125,12 @@ class Charter extends UIState {
// Event Spr
for (addEventSpr in [localAddEventSpr, globalAddEventSpr]) {
addEventSpr.incorporeal = true;
- if ((!addEventSpr.global ? mousePos.x < 0 : mousePos.x > strumLines.totalKeyCount * 40) && gridActionType == NONE && inBoundsY) {
+ var onLeft:Bool = (!addEventSpr.global) != Options.charterSwapEventSides;
+ if ((onLeft ? mousePos.x < 0 : mousePos.x > strumLines.totalKeyCount * 40) && gridActionType == NONE && inBoundsY) {
var event = getHoveredEvent(mousePos.y, !addEventSpr.global ? leftEventsGroup : rightEventsGroup);
var hoveredWidth:Float = event != null ? 27 + 40 + event.bWidth : addEventSpr.bWidth;
- if ((!addEventSpr.global ? mousePos.x > -hoveredWidth : mousePos.x < strumLines.totalKeyCount * 40 + hoveredWidth)) {
+ if ((onLeft ? mousePos.x > -hoveredWidth : mousePos.x < strumLines.totalKeyCount * 40 + hoveredWidth)) {
addEventSpr.incorporeal = false;
if (event != null) addEventSpr.updateEdit(event);
diff --git a/source/funkin/editors/charter/CharterEvent.hx b/source/funkin/editors/charter/CharterEvent.hx
index 7ccf5dc23d..a9e14419ce 100644
--- a/source/funkin/editors/charter/CharterEvent.hx
+++ b/source/funkin/editors/charter/CharterEvent.hx
@@ -50,7 +50,7 @@ class CharterEvent extends UISliceSprite implements ICharterSelectable {
if (snappedToGrid && eventsBackdrop != null) {
bWidth = 37 + (icons.length * 22);
- x = eventsBackdrop.x + (global ? 0 : eventsBackdrop.width - bWidth);
+ x = eventsBackdrop.x + ((global != Options.charterSwapEventSides) ? 0 : eventsBackdrop.width - bWidth);
}
for(k=>i in icons) {
@@ -68,7 +68,7 @@ class CharterEvent extends UISliceSprite implements ICharterSelectable {
selectedColorTransform(sprite.colorTransform);
}
- flipX = displayGlobal;
+ flipX = (displayGlobal != Options.charterSwapEventSides);
}
@:noCompletion private inline function selectedColorTransform(transform:ColorTransform) {
@@ -411,7 +411,7 @@ class CharterEvent extends UISliceSprite implements ICharterSelectable {
draggable = true;
bWidth = 37 + (icons.length * 22);
- x = (snappedToGrid && eventsBackdrop != null && global ? eventsBackdrop.x - bWidth : (global ? 0 : -bWidth));
+ x = (snappedToGrid && eventsBackdrop != null && (global != Options.charterSwapEventSides) ? eventsBackdrop.x - bWidth : ((global != Options.charterSwapEventSides) ? 0 : -bWidth));
}
}
diff --git a/source/funkin/editors/charter/CharterEventAdd.hx b/source/funkin/editors/charter/CharterEventAdd.hx
index dca9d30891..ee7ec48ec7 100644
--- a/source/funkin/editors/charter/CharterEventAdd.hx
+++ b/source/funkin/editors/charter/CharterEventAdd.hx
@@ -13,7 +13,8 @@ class CharterEventAdd extends UISliceSprite {
public function new(global:Bool) {
super(0, 0, 100, 34, 'editors/charter/event-spr-add');
- this.global = flipX = global;
+ this.global = global;
+ flipX = (global != Options.charterSwapEventSides);
sideText = new UIText(0, -40, 0, TU.translate("charter.eventType-" + (global ? "global" : "local")), 12);
sideText.alignment = "center"; sideText.alpha = 0.75;
@@ -49,7 +50,7 @@ class CharterEventAdd extends UISliceSprite {
super.update(elapsed);
if (FlxG.state.subState != null) return;
- text.follow(this, global ? bWidth - text.width - (text.text == TU.translate("charter.addEvent") ? 15 : 20) : 20, (bHeight - text.height) / 2);
+ text.follow(this, (global != Options.charterSwapEventSides) ? bWidth - text.width - (text.text == TU.translate("charter.addEvent") ? 15 : 20) : 20, (bHeight - text.height) / 2);
sideText.follow(this, (bWidth/2) - (sideText.fieldWidth/2), -(sideText.height + 2));
alpha = sprAlpha * 0.75;
text.alpha = sprAlpha;
@@ -64,7 +65,8 @@ class CharterEventAdd extends UISliceSprite {
this.y = (step * 40) - (bHeight / 2);
text.text = TU.translate("charter.addEvent");
framesOffset = 0; bWidth = 37 + Math.ceil(text.width);
- x = global ? Charter.instance.strumLines.members[Charter.instance.strumLines.members.length-1].x + (40*Charter.instance.strumLines.members[Charter.instance.strumLines.members.length-1].keyCount) : -(bWidth);
+ x = (global != Options.charterSwapEventSides) ? Charter.instance.strumLines.members[Charter.instance.strumLines.members.length-1].x + (40*Charter.instance.strumLines.members[Charter.instance.strumLines.members.length-1].keyCount) : -(bWidth);
+ sideText.text = TU.translate("charter.eventType-" + (global ? "global" : "local"));
}
public function updateEdit(event:CharterEvent) {
@@ -73,6 +75,7 @@ class CharterEventAdd extends UISliceSprite {
this.y = event.y;
text.text = TU.translate("charter.editEvent");
framesOffset = 9; bWidth = 27 + Math.ceil(text.width) + event.bWidth;
- x = global ? Charter.instance.strumLines.members[Charter.instance.strumLines.members.length-1].x + (40*Charter.instance.strumLines.members[Charter.instance.strumLines.members.length-1].keyCount) : -(bWidth);
+ x = (event.global != Options.charterSwapEventSides) ? Charter.instance.strumLines.members[Charter.instance.strumLines.members.length-1].x + (40*Charter.instance.strumLines.members[Charter.instance.strumLines.members.length-1].keyCount) : -(bWidth);
+ sideText.text = TU.translate("charter.eventType-" + (event.global ? "global" : "local"));
}
}
\ No newline at end of file
diff --git a/source/funkin/editors/stage/StageEditor.hx b/source/funkin/editors/stage/StageEditor.hx
index 8b54a2c695..89c2a33473 100644
--- a/source/funkin/editors/stage/StageEditor.hx
+++ b/source/funkin/editors/stage/StageEditor.hx
@@ -260,6 +260,7 @@ class StageEditor extends UIState {
stageSpritesWindow.add(button);
} else if(sprite == null) {
var basic = new FlxBasic(); // prevent awkward layering
+ basic.exists = false;
insert(i, basic);
var button = new StageUnknownButton(0,0, basic, xml);
stageSpritesWindow.add(button);
@@ -308,8 +309,8 @@ class StageEditor extends UIState {
sprite.extra.set(exID("type"), node.name);
sprite.extra.set(exID("imageFile"), '${node.getAtt("sprite").getDefault(sprite.name)}');
sprite.extra.set(exID("parentNode"), parent);
- sprite.extra.set(exID("highMemory"), parent.name == "highMemory");
- sprite.extra.set(exID("lowMemory"), parent.name == "lowMemory");
+ sprite.extra.set(exID("highMemory"), parent.name == "high-memory");
+ sprite.extra.set(exID("lowMemory"), parent.name == "low-memory");
//sprite.active = false;
}
if(sprite is StageCharPos)
@@ -374,6 +375,7 @@ class StageEditor extends UIState {
}
char.name = charName;
char.debugMode = true;
+ char.useRenderTexture = true;
// Play first anim, and make it the last frame
var animToPlay = char.getAnimOrder()[0];
char.playAnim(animToPlay, true, NONE);
@@ -392,8 +394,8 @@ class StageEditor extends UIState {
char.extra.set(exID("camY"), charPos.camyoffset);
char.extra.set(exID("parentNode"), parent);
- char.extra.set(exID("highMemory"), parent.name == "highMemory");
- char.extra.set(exID("lowMemory"), parent.name == "lowMemory");
+ char.extra.set(exID("highMemory"), parent.name == "high-memory");
+ char.extra.set(exID("lowMemory"), parent.name == "low-memory");
chars.push(char);
stage.applyCharStuff(char, charPos.name, 0);
@@ -668,6 +670,8 @@ class StageEditor extends UIState {
saveToXml(spriteXML, "color", sprite.color.toWebString(), "#FFFFFF");
// TODO: save custom parameters
//saveToXml(spriteXML, "flipX", sprite.flipX, false);
+ if (node.hasNode.anim) for (animNode in node.nodes.anim)
+ spriteXML.addChild(animNode.x);
newNode = spriteXML;
} else if(button is StageCharacterButton) {
var button:StageCharacterButton = cast button;
diff --git a/source/funkin/editors/stage/elements/StageSolidButton.hx b/source/funkin/editors/stage/elements/StageSolidButton.hx
index 6ded6d26e8..49ffd1925b 100644
--- a/source/funkin/editors/stage/elements/StageSolidButton.hx
+++ b/source/funkin/editors/stage/elements/StageSolidButton.hx
@@ -8,6 +8,7 @@ class StageSolidButton extends StageSpriteButton {
public function new(x:Float,y:Float, sprite:FunkinSprite, xml:Access) {
super(x,y, sprite, xml);
color = 0xFFD9FF50;
+ hasAdvancedEdit = false;
}
public override function onEdit() {
diff --git a/source/funkin/editors/stage/elements/StageSpriteAnimButton.hx b/source/funkin/editors/stage/elements/StageSpriteAnimButton.hx
new file mode 100644
index 0000000000..651b736da5
--- /dev/null
+++ b/source/funkin/editors/stage/elements/StageSpriteAnimButton.hx
@@ -0,0 +1,99 @@
+package funkin.editors.stage.elements;
+
+import funkin.backend.utils.XMLUtil.AnimData;
+import haxe.xml.Access;
+import funkin.editors.extra.PropertyButton;
+
+class StageSpriteAnimButton extends PropertyButton
+{
+ public var fpsStepper:UINumericStepper;
+ public var editButton:UIButton;
+ public var editIcon:FlxSprite;
+ @:unreflective private var __initialized:Bool = false;
+
+ public var spriteXML:Access;
+ public var animData(default, null):AnimData;
+
+ public function new(anim:AnimData, parent, width:Int = 280, height:Int = 35, nameWidth:Int = 100, valueWidth:Int = 135, inputHeight:Int = 25)
+ {
+ super("", "", parent, width, height, nameWidth, valueWidth, inputHeight);
+ animData = anim;
+ propertyText.onChange = (text) -> animData.name = text;
+ valueText.onChange = (text) -> animData.anim = text;
+
+ var editSize = height - 5 * 2;
+ editButton = new UIButton(deleteButton.x - deleteButton.bWidth - 5, 5, null, openAnimEdit, editSize, editSize);
+ editButton.frames = Paths.getFrames("editors/ui/grayscale-button");
+ editButton.color = 0xFFFF5B0F;
+ editButton.autoAlpha = false;
+ members.insert(members.indexOf(deleteButton), editButton);
+
+ editIcon = new FlxSprite(editButton.x + 8, editButton.y + 10).loadGraphic(Paths.image('editors/stage/edit-button'), true, 16, 16);
+ editIcon.animation.add("advanced", [1]);
+ editIcon.animation.play("advanced");
+ editIcon.antialiasing = false;
+ members.insert(members.indexOf(editButton) + 1, editIcon);
+
+ fpsStepper = new UINumericStepper(valueText.x + valueText.bWidth + 15, 5, 0, 1, 2, 0, null, Math.round(width / 4), 25);
+ fpsStepper.onChange = (text) ->
+ {
+ @:privateAccess fpsStepper.__onChange(text);
+ animData.fps = fpsStepper.value;
+ };
+ members.insert(members.indexOf(deleteButton), fpsStepper);
+
+ __initialized = true;
+ updateDisplay();
+ }
+
+ public function openAnimEdit()
+ {
+ final parent = (FlxG.state.subState is UISoftcodedWindow) ? FlxG.state.subState : FlxG.state;
+ parent.openSubState(new SpriteAnimEditScreen(spriteXML, this, null));
+ }
+
+ public override function updatePos()
+ {
+ super.updatePos();
+ if (!__initialized) return;
+
+ fpsStepper.follow(this, valueText.x + valueText.bWidth, bHeight/2 - (fpsStepper.bHeight/2));
+ editButton.follow(this, deleteButton.x - deleteButton.bWidth - 5, bHeight/2 - (editButton.bHeight/2));
+ editIcon.follow(editButton, editButton.bWidth / 2 - editIcon.width / 2, editButton.bHeight / 2 - editIcon.height / 2);
+ }
+
+ public inline function updateDisplay()
+ {
+ propertyText.label.text = animData.name;
+ valueText.label.text = animData.anim;
+ fpsStepper.value = animData.fps;
+ }
+}
+
+class SpriteAnimEditScreen extends UISoftcodedWindow
+{
+ public var saveCallback:Void->Void;
+ public var parentButton:StageSpriteAnimButton;
+ public var xml:Access;
+
+ inline function translate(id:String, prefix:String = "stageSpriteAnimEditScreen.", ?args:Array)
+ return TU.translate(prefix + id, args);
+
+ public function new(xml:Access, parentButton:StageSpriteAnimButton, saveCallback:Void->Void) {
+ this.saveCallback = saveCallback;
+ this.parentButton = parentButton;
+ this.xml = xml;
+ super("layouts/stage/animEditScreen", [
+ "stage" => StageEditor.instance.stage,
+ "xml" => xml,
+ "exID" => StageEditor.exID,
+ "translate" => translate,
+ "button" => parentButton
+ ]);
+ }
+
+ override function saveData() {
+ super.saveData();
+ if(saveCallback != null) saveCallback();
+ }
+}
\ No newline at end of file
diff --git a/source/funkin/editors/stage/elements/StageUnknownButton.hx b/source/funkin/editors/stage/elements/StageUnknownButton.hx
index a3fb09492a..6c0e5a623c 100644
--- a/source/funkin/editors/stage/elements/StageUnknownButton.hx
+++ b/source/funkin/editors/stage/elements/StageUnknownButton.hx
@@ -8,12 +8,13 @@ class StageUnknownButton extends StageElementButton {
public var lowMemory:Bool = false;
public var highMemory:Bool = false;
public var basic:FlxBasic;
+ var dummy:FunkinSprite; // to allow it to be saved
public function new(x:Float,y:Float, basic:FlxBasic, xml:Access) {
this.basic = basic;
- super(x,y, xml);
+ super(x, y, xml);
- if(xml.x.parent != null) {
+ if (xml.x.parent != null) {
lowMemory = xml.x.parent.nodeName == "low-memory";
highMemory = xml.x.parent.nodeName == "high-memory";
}
@@ -27,8 +28,12 @@ class StageUnknownButton extends StageElementButton {
members.remove(visibilityIcon);
setEditAdvanced();
-
updateInfo();
+
+ dummy = new FunkinSprite();
+ dummy.extra.set(StageEditor.exID("lowMemory"), lowMemory);
+ dummy.extra.set(StageEditor.exID("highMemory"), highMemory);
+ dummy.extra.set(StageEditor.exID("button"), this);
}
public override function update(elapsed:Float) {
@@ -40,11 +45,7 @@ class StageUnknownButton extends StageElementButton {
}
public override function getSprite():FunkinSprite {
- var sprite = new FunkinSprite(); // to allow it to be saved
- sprite.extra.set(StageEditor.exID("lowMemory"), lowMemory);
- sprite.extra.set(StageEditor.exID("highMemory"), highMemory);
- sprite.extra.set(StageEditor.exID("button"), this);
- return sprite;
+ return dummy;
}
public override function canRender() {
@@ -58,10 +59,12 @@ class StageUnknownButton extends StageElementButton {
FlxG.state.openSubState(new StageUnknownEditScreen(this));
}
- //public override function onEdit() {
- // UIState.state.displayNotification(new UIBaseNotification("Editing a character isnt implemented yet!", 2, BOTTOM_LEFT));
- // CoolUtil.playMenuSFX(WARNING, 0.45);
- //}
+ public override function onDelete() {
+ basic.destroy();
+ dummy.destroy();
+ xml.x.parent.removeChild(xml.x);
+ StageEditor.instance.stageSpritesWindow.remove(this);
+ }
public override function onVisiblityToggle() {
}
diff --git a/source/funkin/game/PlayState.hx b/source/funkin/game/PlayState.hx
index 83ff8e51b6..0534011d08 100644
--- a/source/funkin/game/PlayState.hx
+++ b/source/funkin/game/PlayState.hx
@@ -1300,7 +1300,7 @@ class PlayState extends MusicBeatState
paused = true;
// 1 / 1000 chance for Gitaroo Man easter egg
- if (allowGitaroo && FlxG.random.bool(Flags.GITAROO_CHANCE))
+ if (!chartingMode && allowGitaroo && FlxG.random.bool(Flags.GITAROO_CHANCE))
{
// gitaroo man easter egg
FlxG.switchState(new GitarooPause());
diff --git a/source/funkin/game/SplashGroup.hx b/source/funkin/game/SplashGroup.hx
index 7600f479e0..00e964e76c 100644
--- a/source/funkin/game/SplashGroup.hx
+++ b/source/funkin/game/SplashGroup.hx
@@ -92,8 +92,8 @@ class SplashGroup extends FlxTypedGroup {
}
function pregenerateSplashes(splash:Splash) {
- // make 7 additional splashes
- for(i in 0...7) {
+ // TODO: Fix a crash somewhere here https://github.com/CodenameCrew/CodenameEngine/pull/963
+ for (i in 0...Flags.MAX_SPLASHES - 1) {
var spr = Splash.copyFrom(splash);
spr.animation.finishCallback = function(name:String) {
spr.active = spr.visible = false;
@@ -133,4 +133,4 @@ class SplashGroup extends FlxTypedGroup {
return __splash;
}
-}
\ No newline at end of file
+}
diff --git a/source/funkin/game/cutscenes/VideoCutscene.hx b/source/funkin/game/cutscenes/VideoCutscene.hx
index f979376f77..9d035f8d60 100644
--- a/source/funkin/game/cutscenes/VideoCutscene.hx
+++ b/source/funkin/game/cutscenes/VideoCutscene.hx
@@ -25,7 +25,7 @@ class VideoCutscene extends Cutscene {
var localPath:String;
#if VIDEO_CUTSCENES
- var video:FlxVideoSprite;
+ final video:FlxVideoSprite = new FlxVideoSprite();
final mutex = new sys.thread.Mutex();
var cutsceneCamera:FlxCamera;
@@ -58,7 +58,7 @@ class VideoCutscene extends Cutscene {
parseSubtitles();
- add(video = new FlxVideoSprite());
+ add(video);
video.antialiasing = true;
video.bitmap.onEndReached.add(close);
video.bitmap.onFormatSetup.add(function() if (video.bitmap != null && video.bitmap.bitmapData != null) {
diff --git a/source/funkin/menus/ModSwitchMenu.hx b/source/funkin/menus/ModSwitchMenu.hx
index 3414af7f08..c6465339ab 100644
--- a/source/funkin/menus/ModSwitchMenu.hx
+++ b/source/funkin/menus/ModSwitchMenu.hx
@@ -29,7 +29,10 @@ class ModSwitchMenu extends MusicBeatSubstate {
bg.alpha = 0;
FlxTween.tween(bg, {alpha: 0.5}, 0.25, {ease: FlxEase.cubeOut});
- mods = ModsFolder.getModsList();
+ mods = ModsFolder.getModsList({
+ descending: false,
+ mode: CLEAN,
+ });
mods.push(null);
alphabets = new FlxTypedGroup();
diff --git a/source/funkin/options/Options.hx b/source/funkin/options/Options.hx
index 9f4e8ab971..83a7123693 100644
--- a/source/funkin/options/Options.hx
+++ b/source/funkin/options/Options.hx
@@ -58,6 +58,7 @@ class Options
*/
public static var intensiveBlur:Bool = true;
public static var editorSFX:Bool = true;
+ public static var charterSwapEventSides:Bool = false;
public static var editorCharterPrettyPrint:Bool = false;
public static var editorCharacterPrettyPrint:Bool = true;
diff --git a/source/funkin/options/categories/DebugOptions.hx b/source/funkin/options/categories/DebugOptions.hx
index 74b2eb8a7d..4f63da38be 100644
--- a/source/funkin/options/categories/DebugOptions.hx
+++ b/source/funkin/options/categories/DebugOptions.hx
@@ -13,6 +13,7 @@ class DebugOptions extends TreeMenuScreen {
add(new Checkbox(getNameID("editorCharterPrettyPrint"), getDescID("editorCharterPrettyPrint"), "editorCharterPrettyPrint"));
add(new Checkbox(getNameID("editorCharacterPrettyPrint"), getDescID("editorCharacterPrettyPrint"), "editorCharacterPrettyPrint"));
add(new Checkbox(getNameID("editorStagePrettyPrint"), getDescID("editorStagePrettyPrint"), "editorStagePrettyPrint"));
+ add(new Checkbox(getNameID("charterSwapEventSides"), getDescID("charterSwapEventSides"), "charterSwapEventSides"));
add(new Checkbox(getNameID("intensiveBlur"), getDescID("intensiveBlur"), "intensiveBlur"));
add(new Checkbox(getNameID("charterAutoSaves"), getDescID("charterAutoSaves"), "charterAutoSaves"));
add(new NumOption(getNameID("charterAutoSaveTime"), getDescID("charterAutoSaveTime"), 60, 60*10, 1, "charterAutoSaveTime"));