Merge branch 'new-editors' into zoro-charterstuffs

This commit is contained in:
TheZoroForce240
2024-08-25 14:49:21 +01:00
301 changed files with 1384 additions and 158 deletions
+632
View File
@@ -0,0 +1,632 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
import haxe.iterators.StringIterator;
import haxe.iterators.StringKeyValueIterator;
#if cpp
using cpp.NativeString;
#end
/**
This class provides advanced methods on Strings. It is ideally used with
`using StringTools` and then acts as an [extension](https://haxe.org/manual/lf-static-extension.html)
to the `String` class.
If the first argument to any of the methods is null, the result is
unspecified.
**/
class StringTools {
/**
Encode an URL by using the standard format.
**/
#if (!java && !cpp && !lua && !eval) inline #end public static function urlEncode(s:String):String {
#if flash
return untyped __global__["encodeURIComponent"](s);
#elseif neko
return untyped new String(_urlEncode(s.__s));
#elseif js
return untyped encodeURIComponent(s);
#elseif cpp
return untyped s.__URLEncode();
#elseif java
return postProcessUrlEncode(java.net.URLEncoder.encode(s, "UTF-8"));
#elseif python
return python.lib.urllib.Parse.quote(s, "");
#elseif hl
var len = 0;
var b = @:privateAccess s.bytes.urlEncode(len);
return @:privateAccess String.__alloc__(b, len);
#elseif lua
s = lua.NativeStringTools.gsub(s, "\n", "\r\n");
s = lua.NativeStringTools.gsub(s, "([^%w %-%_%.%~])", function(c) {
return lua.NativeStringTools.format("%%%02X", lua.NativeStringTools.byte(c) + '');
});
s = lua.NativeStringTools.gsub(s, " ", "+");
return s;
#else
return null;
#end
}
#if java
private static function postProcessUrlEncode(s:String):String {
var ret = new StringBuf();
var i = 0, len = s.length;
while (i < len) {
switch (_charAt(s, i++)) {
case '+'.code:
ret.add('%20');
case '%'.code if (i <= len - 2):
var c1 = _charAt(s, i++), c2 = _charAt(s, i++);
switch [c1, c2] {
case ['2'.code, '1'.code]:
ret.addChar('!'.code);
case ['2'.code, '7'.code]:
ret.addChar('\''.code);
case ['2'.code, '8'.code]:
ret.addChar('('.code);
case ['2'.code, '9'.code]:
ret.addChar(')'.code);
case ['7'.code, 'E'.code] | ['7'.code, 'e'.code]:
ret.addChar('~'.code);
case _:
ret.addChar('%'.code);
ret.addChar(cast c1);
ret.addChar(cast c2);
}
case var chr:
ret.addChar(cast chr);
}
}
return ret.toString();
}
#end
/**
Decode an URL using the standard format.
**/
#if (!java && !cpp && !lua && !eval) inline #end public static function urlDecode(s:String):String {
#if flash
return untyped __global__["decodeURIComponent"](s.split("+").join(" "));
#elseif neko
return untyped new String(_urlDecode(s.__s));
#elseif js
return untyped decodeURIComponent(s.split("+").join(" "));
#elseif cpp
return untyped s.__URLDecode();
#elseif java
try
return java.net.URLDecoder.decode(s, "UTF-8")
catch (e:Dynamic)
throw e;
#elseif python
return python.lib.urllib.Parse.unquote(s);
#elseif hl
var len = 0;
var b = @:privateAccess s.bytes.urlDecode(len);
return @:privateAccess String.__alloc__(b, len);
#elseif lua
s = lua.NativeStringTools.gsub(s, "+", " ");
s = lua.NativeStringTools.gsub(s, "%%(%x%x)", function(h) {
return lua.NativeStringTools.char(lua.Lua.tonumber(h, 16));
});
s = lua.NativeStringTools.gsub(s, "\r\n", "\n");
return s;
#else
return null;
#end
}
/**
Escapes HTML special characters of the string `s`.
The following replacements are made:
- `&` becomes `&amp`;
- `<` becomes `&lt`;
- `>` becomes `&gt`;
If `quotes` is true, the following characters are also replaced:
- `"` becomes `&quot`;
- `'` becomes `&#039`;
**/
public static function htmlEscape(s:String, ?quotes:Bool):String {
var buf = new StringBuf();
for (code in #if neko iterator(s) #else new haxe.iterators.StringIteratorUnicode(s) #end) {
switch (code) {
case '&'.code:
buf.add("&amp;");
case '<'.code:
buf.add("&lt;");
case '>'.code:
buf.add("&gt;");
case '"'.code if (quotes):
buf.add("&quot;");
case '\''.code if (quotes):
buf.add("&#039;");
case _:
buf.addChar(code);
}
}
return buf.toString();
}
/**
Unescapes HTML special characters of the string `s`.
This is the inverse operation to htmlEscape, i.e. the following always
holds: `htmlUnescape(htmlEscape(s)) == s`
The replacements follow:
- `&amp;` becomes `&`
- `&lt;` becomes `<`
- `&gt;` becomes `>`
- `&quot;` becomes `"`
- `&#039;` becomes `'`
**/
public static function htmlUnescape(s:String):String {
return s.split("&gt;")
.join(">")
.split("&lt;")
.join("<")
.split("&quot;")
.join('"')
.split("&#039;")
.join("'")
.split("&amp;")
.join("&");
}
/**
Returns `true` if `s` contains `value` and `false` otherwise.
When `value` is `null`, the result is unspecified.
**/
public static inline function contains(s:String, value:String):Bool {
#if (js && js_es >= 6)
return (cast s).includes(value);
#else
return s.indexOf(value) != -1;
#end
}
/**
Tells if the string `s` starts with the string `start`.
If `start` is `null`, the result is unspecified.
If `start` is the empty String `""`, the result is true.
**/
public static #if (java || python || (js && js_es >= 6)) inline #end function startsWith(s:String, start:String):Bool {
#if java
return (cast s : java.NativeString).startsWith(start);
#elseif hl
return @:privateAccess (s.length >= start.length && s.bytes.compare(0, start.bytes, 0, start.length << 1) == 0);
#elseif python
return python.NativeStringTools.startswith(s, start);
#elseif (js && js_es >= 6)
return (cast s).startsWith(start);
#elseif lua
return untyped __lua__("{0}:sub(1, #{1}) == {1}", s, start);
#else
return (s.length >= start.length && s.indexOf(start, 0) == 0);
#end
}
/**
Tells if the string `s` ends with the string `end`.
If `end` is `null`, the result is unspecified.
If `end` is the empty String `""`, the result is true.
**/
public static #if (java || python || (js && js_es >= 6)) inline #end function endsWith(s:String, end:String):Bool {
#if java
return (cast s : java.NativeString).endsWith(end);
#elseif hl
var elen = end.length;
var slen = s.length;
return @:privateAccess (slen >= elen && s.bytes.compare((slen - elen) << 1, end.bytes, 0, elen << 1) == 0);
#elseif python
return python.NativeStringTools.endswith(s, end);
#elseif (js && js_es >= 6)
return (cast s).endsWith(end);
#elseif lua
return end == "" || untyped __lua__("{0}:sub(-#{1}) == {1}", s, end);
#else
var elen = end.length;
var slen = s.length;
return (slen >= elen && s.lastIndexOf(end, (slen - elen)) == (slen - elen));
#end
}
/**
Tells if the character in the string `s` at position `pos` is a space.
A character is considered to be a space character if its character code
is 9,10,11,12,13 or 32.
If `s` is the empty String `""`, or if pos is not a valid position within
`s`, the result is false.
**/
public static function isSpace(s:String, pos:Int):Bool {
#if (python || lua)
if (s.length == 0 || pos < 0 || pos >= s.length)
return false;
#end
var c = StringTools.fastCodeAt(s, pos);
return (c > 8 && c < 14) || c == 32;
}
/**
Removes leading space characters of `s`.
This function internally calls `isSpace()` to decide which characters to
remove.
If `s` is the empty String `""` or consists only of space characters, the
result is the empty String `""`.
**/
public inline static function ltrim(s:String):String {
var l = s.length;
var r = 0;
while (r < l && isSpace(s, r)) {
r++;
}
if (r > 0)
return s.substr(r, l - r);
else
return s;
}
/**
Removes trailing space characters of `s`.
This function internally calls `isSpace()` to decide which characters to
remove.
If `s` is the empty String `""` or consists only of space characters, the
result is the empty String `""`.
**/
public inline static function rtrim(s:String):String {
var l = s.length;
var r = 0;
while (r < l && isSpace(s, l - r - 1)) {
r++;
}
if (r > 0) {
return s.substr(0, l - r);
} else {
return s;
}
}
/**
Removes leading and trailing space characters of `s`.
This is a convenience function for `ltrim(rtrim(s))`.
**/
public #if java inline #end static function trim(s:String):String {
#if java
return (cast s : java.NativeString).trim();
#else
//return ltrim(rtrim(s));
var l = s.length;
var start = 0;
var end = l;
// Trim leading spaces
while (start < l && isSpace(s, start)) {
start++;
}
// Trim trailing spaces
while (end > start && isSpace(s, end - 1)) {
end--;
}
return (start > 0 || end < l) ? s.substr(start, end - start) : s;
#end
}
/**
Concatenates `c` to `s` until `s.length` is at least `l`.
If `c` is the empty String `""` or if `l` does not exceed `s.length`,
`s` is returned unchanged.
If `c.length` is 1, the resulting String length is exactly `l`.
Otherwise the length may exceed `l`.
If `c` is null, the result is unspecified.
**/
public static function lpad(s:String, c:String, l:Int):String {
if (c.length <= 0)
return s;
var buf = new StringBuf();
l -= s.length;
while (buf.length < l) {
buf.add(c);
}
buf.add(s);
return buf.toString();
}
/**
Appends `c` to `s` until `s.length` is at least `l`.
If `c` is the empty String `""` or if `l` does not exceed `s.length`,
`s` is returned unchanged.
If `c.length` is 1, the resulting String length is exactly `l`.
Otherwise the length may exceed `l`.
If `c` is null, the result is unspecified.
**/
public static function rpad(s:String, c:String, l:Int):String {
if (c.length <= 0)
return s;
var buf = new StringBuf();
buf.add(s);
while (buf.length < l) {
buf.add(c);
}
return buf.toString();
}
/**
Replace all occurrences of the String `sub` in the String `s` by the
String `by`.
If `sub` is the empty String `""`, `by` is inserted after each character
of `s` except the last one. If `by` is also the empty String `""`, `s`
remains unchanged.
If `sub` or `by` are null, the result is unspecified.
**/
public static function replace(s:String, sub:String, by:String):String {
#if java
if (sub.length == 0)
return s.split(sub).join(by);
else
return (cast s : java.NativeString).replace(sub, by);
#else
return s.split(sub).join(by);
#end
}
/**
Encodes `n` into a hexadecimal representation.
If `digits` is specified, the resulting String is padded with "0" until
its `length` equals `digits`.
**/
public static function hex(n:Int, ?digits:Int) {
#if flash
var n:UInt = n;
var s:String = untyped n.toString(16);
s = s.toUpperCase();
#else
var s = "";
var hexChars = "0123456789ABCDEF";
do {
s = hexChars.charAt(n & 15) + s;
n >>>= 4;
} while (n > 0);
#end
#if python
if (digits != null && s.length < digits) {
var diff = digits - s.length;
for (_ in 0...diff) {
s = "0" + s;
}
}
#else
if (digits != null)
while (s.length < digits)
s = "0" + s;
#end
return s;
}
/**
Returns the character code at position `index` of String `s`, or an
end-of-file indicator at if `position` equals `s.length`.
This method is faster than `String.charCodeAt()` on some platforms, but
the result is unspecified if `index` is negative or greater than
`s.length`.
End of file status can be checked by calling `StringTools.isEof()` with
the returned value as argument.
This operation is not guaranteed to work if `s` contains the `\0`
character.
**/
public static #if !eval inline #end function fastCodeAt(s:String, index:Int):Int {
#if neko
return untyped __dollar__sget(s.__s, index);
#elseif cpp
return untyped s.cca(index);
#elseif flash
return untyped s.cca(index);
#elseif java
return (index < s.length) ? cast(_charAt(s, index), Int) : -1;
#elseif js
return (cast s).charCodeAt(index);
#elseif python
return if (index >= s.length) -1 else python.internal.UBuiltins.ord(python.Syntax.arrayAccess(s, index));
#elseif hl
return @:privateAccess s.bytes.getUI16(index << 1);
#elseif lua
#if lua_vanilla
return lua.NativeStringTools.byte(s, index + 1);
#else
return lua.lib.luautf8.Utf8.byte(s, index + 1);
#end
#else
return untyped s.cca(index);
#end
}
/**
Returns the character code at position `index` of String `s`, or an
end-of-file indicator at if `position` equals `s.length`.
This method is faster than `String.charCodeAt()` on some platforms, but
the result is unspecified if `index` is negative or greater than
`s.length`.
This operation is not guaranteed to work if `s` contains the `\0`
character.
**/
public static #if !eval inline #end function unsafeCodeAt(s:String, index:Int):Int {
#if neko
return untyped __dollar__sget(s.__s, index);
#elseif cpp
return untyped s.cca(index);
#elseif flash
return untyped s.cca(index);
#elseif java
return cast(_charAt(s, index), Int);
#elseif js
return (cast s).charCodeAt(index);
#elseif python
return python.internal.UBuiltins.ord(python.Syntax.arrayAccess(s, index));
#elseif hl
return @:privateAccess s.bytes.getUI16(index << 1);
#elseif lua
#if lua_vanilla
return lua.NativeStringTools.byte(s, index + 1);
#else
return lua.lib.luautf8.Utf8.byte(s, index + 1);
#end
#else
return untyped s.cca(index);
#end
}
/**
Returns an iterator of the char codes.
Note that char codes may differ across platforms because of different
internal encoding of strings in different runtimes.
For the consistent cross-platform UTF8 char codes see `haxe.iterators.StringIteratorUnicode`.
**/
public static inline function iterator(s:String):StringIterator {
return new StringIterator(s);
}
/**
Returns an iterator of the char indexes and codes.
Note that char codes may differ across platforms because of different
internal encoding of strings in different of runtimes.
For the consistent cross-platform UTF8 char codes see `haxe.iterators.StringKeyValueIteratorUnicode`.
**/
public static inline function keyValueIterator(s:String):StringKeyValueIterator {
return new StringKeyValueIterator(s);
}
/**
Tells if `c` represents the end-of-file (EOF) character.
**/
@:noUsing public static inline function isEof(c:Int):Bool {
#if (flash || cpp || hl)
return c == 0;
#elseif js
return c != c; // fast NaN
#elseif (neko || lua || eval)
return c == null;
#elseif (java || python)
return c == -1;
#else
return false;
#end
}
/**
Returns a String that can be used as a single command line argument
on Unix.
The input will be quoted, or escaped if necessary.
**/
@:noCompletion
@:deprecated('StringTools.quoteUnixArg() is deprecated. Use haxe.SysTools.quoteUnixArg() instead.')
public static function quoteUnixArg(argument:String):String {
return inline haxe.SysTools.quoteUnixArg(argument);
}
/**
Character codes of the characters that will be escaped by `quoteWinArg(_, true)`.
**/
@:noCompletion
@:deprecated('StringTools.winMetaCharacters is deprecated. Use haxe.SysTools.winMetaCharacters instead.')
public static var winMetaCharacters:Array<Int> = cast haxe.SysTools.winMetaCharacters;
/**
Returns a String that can be used as a single command line argument
on Windows.
The input will be quoted, or escaped if necessary, such that the output
will be parsed as a single argument using the rule specified in
http://msdn.microsoft.com/en-us/library/ms880421
Examples:
```haxe
quoteWinArg("abc") == "abc";
quoteWinArg("ab c") == '"ab c"';
```
**/
@:noCompletion
@:deprecated('StringTools.quoteWinArg() is deprecated. Use haxe.SysTools.quoteWinArg() instead.')
public static function quoteWinArg(argument:String, escapeMetaCharacters:Bool):String {
return inline haxe.SysTools.quoteWinArg(argument, escapeMetaCharacters);
}
#if java
private static inline function _charAt(str:String, idx:Int):java.StdTypes.Char16
return (cast str : java.NativeString).charAt(idx);
#end
#if neko
private static var _urlEncode = neko.Lib.load("std", "url_encode", 1);
private static var _urlDecode = neko.Lib.load("std", "url_decode", 1);
#end
#if utf16
static inline var MIN_SURROGATE_CODE_POINT = 65536;
static inline function utf16CodePointAt(s:String, index:Int):Int {
var c = StringTools.fastCodeAt(s, index);
if (c >= 0xD800 && c <= 0xDBFF) {
c = ((c - 0xD7C0) << 10) | (StringTools.fastCodeAt(s, index + 1) & 0x3FF);
}
return c;
}
#end
}
+1 -1
View File
@@ -14,7 +14,7 @@ import flixel.FlxG;
* @see https://twitter.com/Ne_Eo_Twitch
*/
@:access(away3d.core.managers.Stage3DManager)
class Flx3DUtil
final class Flx3DUtil
{
#if THREE_D_SUPPORT
/**
+2
View File
@@ -181,10 +181,12 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
animateAtlas.flipX = flipX;
animateAtlas.flipY = flipY;
animateAtlas.shader = shader;
animateAtlas.shaderEnabled = shaderEnabled;
animateAtlas.antialiasing = antialiasing;
animateAtlas.skew = skew;
animateAtlas.transformMatrix = transformMatrix;
animateAtlas.matrixExposed = matrixExposed;
animateAtlas.colorTransform = colorTransform;
}
}
+1 -1
View File
@@ -11,7 +11,7 @@ import sys.FileSystem;
using StringTools;
class Chart {
final class Chart {
/**
* Default background colors for songs without bg color
*/
+5 -1
View File
@@ -9,7 +9,7 @@ import openfl.Assets;
using StringTools;
class EventsData {
final class EventsData {
public static var defaultEventsList:Array<String> = ["HScript Call", "Camera Movement", "Add Camera Zoom", "Camera Modulo Change", "Camera Flash", "BPM Change", "Scroll Speed Change", "Alt Animation Toggle", "Play Animation"];
public static var defaultEventsParams:Map<String, Array<EventParamInfo>> = [
"HScript Call" => [
@@ -70,6 +70,8 @@ class EventsData {
hscriptInterp.variables.set("StrumLine", TStrumLine);
hscriptInterp.variables.set("ColorWheel", TColorWheel);
hscriptInterp.variables.set("DropDown", Reflect.makeVarArgs((args) -> {return args.length > 0 ? TDropDown([for (arg in args) Std.string(arg)]) : TDropDown(["null"]);}));
hscriptInterp.variables.set("Character", TCharacter);
hscriptInterp.variables.set("Stage", TStage);
var hscriptParser:Parser = new Parser();
hscriptParser.allowJSON = hscriptParser.allowMetadata = false;
@@ -127,4 +129,6 @@ enum EventParamType {
TStrumLine;
TColorWheel;
TDropDown(?options:Array<String>);
TCharacter;
TStage;
}
@@ -3,7 +3,7 @@ package funkin.backend.scripting;
import flixel.FlxState;
import funkin.backend.scripting.events.*;
class EventManager {
final class EventManager {
// map doesnt work for that
public static var eventValues:Array<CancellableEvent> = [];
public static var eventKeys:Array<Class<CancellableEvent>> = [];
@@ -11,7 +11,11 @@ import funkin.backend.system.Conductor;
class GlobalScript {
public static var scripts:ScriptPack;
private static var initalized:Bool = false;
public static function init() {
if(initalized) return;
initalized = true;
#if MOD_SUPPORT
ModsFolder.onModSwitch.add(onModSwitch);
#end
@@ -0,0 +1,13 @@
package funkin.backend.scripting.events;
final class HealthIconChangeEvent extends CancellableEvent {
/**
* Amount
*/
public var amount:Int;
/**
* The health icon
*/
public var healthIcon:funkin.game.HealthIcon;
}
+4 -41
View File
@@ -457,14 +457,7 @@ vec4 flixel_texture2D(sampler2D bitmap, vec2 coord)
}
color = vec4(color.rgb / color.a, color.a);
mat4 colorMultiplier = mat4(0);
colorMultiplier[0][0] = openfl_ColorMultiplierv.x;
colorMultiplier[1][1] = openfl_ColorMultiplierv.y;
colorMultiplier[2][2] = openfl_ColorMultiplierv.z;
colorMultiplier[3][3] = openfl_ColorMultiplierv.w;
color = clamp(openfl_ColorOffsetv + (color * colorMultiplier), 0.0, 1.0);
color = clamp(openfl_ColorOffsetv + (color * openfl_ColorMultiplierv), 0.0, 1.0);
if (color.a > 0.0)
{
@@ -491,39 +484,9 @@ vec4 textureCam(sampler2D bitmap, vec2 pos) {
return flixel_texture2D(bitmap, camToOg(pos));
}";
public static final fragBody:String = "vec4 color = texture2D (bitmap, openfl_TextureCoordv);
if (color.a == 0.0) {
gl_FragColor = vec4 (0.0, 0.0, 0.0, 0.0);
} else if (openfl_HasColorTransform) {
color = vec4 (color.rgb / color.a, color.a);
mat4 colorMultiplier = mat4 (0);
colorMultiplier[0][0] = openfl_ColorMultiplierv.x;
colorMultiplier[1][1] = openfl_ColorMultiplierv.y;
colorMultiplier[2][2] = openfl_ColorMultiplierv.z;
colorMultiplier[3][3] = 1.0; // openfl_ColorMultiplierv.w;
color = clamp (openfl_ColorOffsetv + (color * colorMultiplier), 0.0, 1.0);
if (color.a > 0.0) {
gl_FragColor = vec4 (color.rgb * color.a * openfl_Alphav, color.a * openfl_Alphav);
} else {
gl_FragColor = vec4 (0.0, 0.0, 0.0, 0.0);
}
} else {
gl_FragColor = color * openfl_Alphav;
}";
public static final fragBody:String = "vec4 color = flixel_texture2D (bitmap, openfl_TextureCoordv);
gl_FragColor = color;
";
public static final vertHeader:String = "attribute float openfl_Alpha;
attribute vec4 openfl_ColorMultiplier;
attribute vec4 openfl_ColorOffset;
@@ -75,18 +75,18 @@ const int EFFECT_TYPE_FLAG = 4;
uniform int effectType;
/**
* How fast the waves move over time
*/
* How fast the waves move over time
*/
uniform float uSpeed;
/**
* Number of waves over time
*/
* Number of waves over time
*/
uniform float uFrequency;
/**
* How much the pixels are going to stretch over the waves
*/
* How much the pixels are going to stretch over the waves
*/
uniform float uWaveAmplitude;
vec2 sineWave(vec2 pt)
@@ -2,7 +2,7 @@ package funkin.backend.system;
#if sys
import sys.FileSystem;
class CommandLineHandler {
final class CommandLineHandler {
public static function parseCommandLine(cmd:Array<String>) {
var i:Int = 0;
while(i < cmd.length) {
+1 -1
View File
@@ -6,7 +6,7 @@ import funkin.backend.utils.NativeAPI.ConsoleColor;
import funkin.backend.utils.NativeAPI;
import haxe.Log;
class Logs {
final class Logs {
private static var __showing:Bool = false;
public static var nativeTrace = Log.trace;
@@ -5,6 +5,7 @@ using StringTools;
#if macro
class BuildInfo {
public static function printBuildInfo() {
if(haxe.macro.Context.defined("display")) return;
var haxeVersion = haxe.macro.Context.definedValue("haxe");
Sys.println('--- BUILD INFO ---');
Sys.println('Haxe Version: ${haxeVersion}');
@@ -11,7 +11,7 @@ import lime.media.AudioManager;
* hi gray itsa me yoshicrafter29 i fixed it hehe
*/
@:dox(hide)
class AudioSwitchFix {
final class AudioSwitchFix {
@:noCompletion
private static function onStateSwitch(state:FlxState):Void {
#if windows
@@ -7,7 +7,7 @@ import openfl.errors.Error;
import openfl.events.ErrorEvent;
import openfl.events.UncaughtErrorEvent;
class CrashHandler {
final class CrashHandler {
public static function init() {
Lib.current.loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, onUncaughtError);
#if cpp
+1 -1
View File
@@ -5,7 +5,7 @@ import openfl.display.BitmapData;
import openfl.geom.Point;
import openfl.geom.Rectangle;
class BitmapUtil {
final class BitmapUtil {
/**
* Returns the most present color in a Bitmap.
* @param bmap Bitmap
+1 -1
View File
@@ -42,7 +42,7 @@ import flixel.math.FlxPoint;
using StringTools;
@:allow(funkin.game.PlayState)
class CoolUtil
final class CoolUtil
{
public static function getLastExceptionStack():String {
return CallStack.toString(CallStack.exceptionStack());
+52 -1
View File
@@ -1,5 +1,6 @@
package funkin.backend.utils;
import flixel.util.FlxSignal.FlxTypedSignal;
import flixel.sound.FlxSound;
import flixel.util.typeLimit.OneOfTwo;
import funkin.backend.scripting.*; // lazy
@@ -16,7 +17,7 @@ import lime.app.Application;
import sys.thread.Thread;
#end
class DiscordUtil
final class DiscordUtil
{
public static var currentID(default, set):String = null;
public static var discordThread:#if DISCORD_RPC Thread #else Dynamic #end = null;
@@ -107,14 +108,28 @@ class DiscordUtil
public static function loadScript()
{
#if DISCORD_RPC
if (script != null)
{
call("destroy");
script = FlxDestroyUtil.destroy(script);
}
script = Script.create(Paths.script('data/discord'));
script.set("ActivityType", {
Playing: ActivityType.Playing,
PLAYING: ActivityType.Playing,
Streaming: ActivityType.Streaming,
STREAMING: ActivityType.Streaming,
Watching: ActivityType.Watching,
WATCHING: ActivityType.Watching,
Listening: ActivityType.Listening,
LISTENING: ActivityType.Listening,
Competing: ActivityType.Competing,
COMPETING: ActivityType.Competing
});
// script.setParent(DiscordUtil);
script.load();
#end
}
public static function changePresence(details:String, state:String, ?smallImageKey:String)
@@ -218,6 +233,8 @@ class DiscordUtil
Utils.safeSetWrapper(dp.joinSecret, data.joinSecret, fixString);
Utils.safeSetWrapper(dp.spectateSecret, data.spectateSecret, fixString);
Utils.safeSet(dp.instance, data.instance);
Utils.safeSet(dp.activityType, data.activityType);
Utils.safeSetWrapper(dp.streamUrl, data.streamUrl, fixString);
if (data.matchSecret == null && data.joinSecret == null && data.spectateSecret == null)
{
Utils.safeSetWrapper(dp.button1Label, data.button1Label, fixString);
@@ -252,6 +269,7 @@ class DiscordUtil
handlers.joinGame = cpp.Function.fromStaticFunction(onJoin);
handlers.joinRequest = cpp.Function.fromStaticFunction(onJoinReq);
handlers.spectateGame = cpp.Function.fromStaticFunction(onSpectate);
handlers.anyResponse = cpp.Function.fromStaticFunction(onAnyResponse);
Discord.Initialize(id, cpp.RawPointer.addressOf(handlers), 1, null);
stopThread = false;
@@ -351,7 +369,38 @@ class DiscordUtil
var req:DUser = DUser.initRaw(request);
call("onJoinRequest", [req]);
}
public static var anyResponse:FlxTypedSignal<String->Void> = new FlxTypedSignal<String->Void>();
private static function onAnyResponse(data:cpp.ConstCharStar):Void
{
call("onAnyResponse", [data]);
anyResponse.dispatch(data);
}
#end
private static function getUUID():String {
var uuid = new StringBuf();
for (i in 0...16) {
uuid.add(StringTools.hex(Math.floor(Math.random() * 16), 1));
}
return uuid.toString();
}
public static function sendCustomCommand(data:Dynamic) {
#if DISCORD_RPC
if(data == null) return;
if(data.nonce == null) data.nonce = getUUID();
var json = Json.stringify(data);
Discord.SendCustomCommand(json);
#end
}
public static function setDebugMode(mode:Bool) {
#if DISCORD_RPC
Discord.SetDebugMode(mode);
#end
}
}
typedef DiscordJson =
@@ -476,6 +525,8 @@ typedef DPresence =
var ?button1Url:String; /* max 512 bytes */
var ?button2Label:String; /* max 32 bytes */
var ?button2Url:String; /* max 512 bytes */
var ?activityType:ActivityType;
var ?streamUrl:String; /* max 512 bytes */
}
typedef DEvents =
+1 -1
View File
@@ -4,7 +4,7 @@ import flixel.util.FlxColor;
import flixel.math.FlxAngle;
import flixel.math.FlxPoint;
class DrawUtil {
final class DrawUtil {
public static var line:FlxSprite = null;
public static var dot:FlxSprite = null;
+1 -1
View File
@@ -3,7 +3,7 @@ package funkin.backend.utils;
import funkin.backend.scripting.MultiThreadedScript;
import funkin.backend.scripting.Script;
class EngineUtil {
final class EngineUtil {
/**
* Starts a new multithreaded script.
* This script will share all the variables with the current one, which means already existing callbacks will be replaced by new ones on conflict.
+1 -1
View File
@@ -2,7 +2,7 @@ package funkin.backend.utils;
import haxe.Http;
class HttpUtil
final class HttpUtil
{
public static var userAgent:String = "request";
public static function requestText(url:String)
+1 -1
View File
@@ -3,7 +3,7 @@ package funkin.backend.utils;
/**
* DOESNT SUPPORT CATEGORIES YET!!
*/
class IniUtil {
final class IniUtil {
public static inline function parseAsset(assetPath:String, ?defaultVariables:Map<String, String>)
return parseString(Assets.getText(assetPath), defaultVariables);
+1 -1
View File
@@ -3,7 +3,7 @@ package funkin.backend.utils;
import flixel.text.FlxText;
import flixel.util.FlxColor;
class MarkdownUtil {
final class MarkdownUtil {
public static function applyMarkdownText(text:FlxText, str:String) {
text.textField.htmlText = Markdown.markdownToHtml(prepareMarkdown(str));
var changes:Array<FlxTextFormatMarkerPair> = [
+1 -1
View File
@@ -2,7 +2,7 @@ package funkin.backend.utils;
import haxe.macro.Expr;
class MathUtil {
final class MathUtil {
/**
* Returns the maximum value in the arguments.
* @param args Array of values
+1 -1
View File
@@ -9,7 +9,7 @@ interface IPrePostDraw {
public function postDraw():Void;
}
class MatrixUtil {
final class MatrixUtil {
public static function getMatrixPosition(sprite:FlxSprite, points:OneOfTwo<FlxPoint, Array<FlxPoint>>, ?camera:FlxCamera, _width:Float = 1, _height:Float = 1):Array<FlxPoint>
{
//if(_width == -1) _width = sprite.width;
+1 -1
View File
@@ -14,7 +14,7 @@ import openfl.system.System;
using StringTools;
class MemoryUtil {
final class MemoryUtil {
public static var disableCount:Int = 0;
public static function askDisable() {
+1 -1
View File
@@ -14,7 +14,7 @@ package funkin.backend.utils;
* - The Function cannot be found in the NDLL
* then an empty function will be returned instead, and a message will be shown in logs.
*/
class NdllUtil {
final class NdllUtil {
#if NDLLS_SUPPORTED
#if windows public static final os:String = "windows"; #end
#if linux public static final os:String = "linux"; #end
@@ -2,7 +2,7 @@ package funkin.backend.utils;
import openfl.display.Sprite;
class ShaderResizeFix {
final class ShaderResizeFix {
public static var doResizeFix:Bool = true;
public static function init() {
@@ -3,7 +3,7 @@ package funkin.backend.utils;
/**
* All types of utils only usable in a sorted array.
*/
class SortedArrayUtil {
final class SortedArrayUtil {
/**
* Gets the index of a possible new element of an Array of T using an efficient algorithm.
* @param array Array of T to check in
+1 -1
View File
@@ -1,7 +1,7 @@
package funkin.backend.utils;
#if ALLOW_MULTITHREADING
class ThreadUtil {
final class ThreadUtil {
/**
* Creates a new Thread with an error handler.
* @param func Function to execute
+1 -1
View File
@@ -2,7 +2,7 @@ package funkin.backend.utils;
import openfl.Lib;
class WindowUtils {
final class WindowUtils {
public static var winTitle(default, set):String;
private static function set_winTitle(value:String):String {
winTitle = value;
+1 -1
View File
@@ -15,7 +15,7 @@ typedef TextFormat = { text:String, format:Dynamic }
/**
* Class made to make XML parsing easier.
*/
class XMLUtil {
final class XMLUtil {
/**
* Applies a property XML node to an object.
+1 -1
View File
@@ -23,7 +23,7 @@ using StringTools;
// import ZipUtils; ZipUtils.uncompressZip(ZipUtils.openZip("E:\\Desktop\\test\\termination lua.ycemod"), "E:\\Desktop\\test\\uncompressed\\");
// import ZipUtils; var e = ZipUtils.createZipFile("gjnsdghs.ycemod"); ZipUtils.writeFolderToZip(e, "./mods/Friday Night Funkin'/", "Friday Night Funkin'/"); e.flush(); e.close();
class ZipUtil {
final class ZipUtil {
public static var bannedNames:Array<String> = [".git", ".gitignore", ".github", ".vscode", ".gitattributes", "readme.txt"];
/**
+2 -1
View File
@@ -2,7 +2,8 @@ package funkin.backend.utils.native;
#if linux
@:cppFileCode("#include <stdio.h>")
class Linux {
@:dox(hide)
final class Linux {
@:functionCode('
FILE *meminfo = fopen("/proc/meminfo", "r");
+2 -1
View File
@@ -5,7 +5,8 @@ import funkin.backend.utils.NativeAPI.CodeCursor;
import openfl.ui.Mouse;
@:headerInclude('sys/sysctl.h')
class Mac
@:dox(hide)
final class Mac
{
@:functionCode('
int mib [] = { CTL_HW, HW_MEMSIZE };
@@ -114,7 +114,7 @@ class AudioFixClient : public IMMNotificationClient {
AudioFixClient *curAudioFix;
')
@:dox(hide)
class Windows {
final class Windows {
public static var __audioChangeCallback:Void->Void = function() {
trace("test");
+4
View File
@@ -1,6 +1,7 @@
package funkin.editors.charter;
// ! FUCK YOU CHUF (your biggest fan -lunar) <3
import flixel.FlxLayer;
import funkin.editors.extra.CameraHoverDummy;
import flixel.input.keyboard.FlxKey;
import flixel.math.FlxPoint;
@@ -88,6 +89,8 @@ class Charter extends UIState {
public static var clipboard:Array<CharterCopyboardObject> = [];
public static var waveformHandler:CharterWaveformHandler;
public var textLayer:FlxLayer;
public function new(song:String, diff:String, reload:Bool = true) {
super();
if (song != null) {
@@ -484,6 +487,7 @@ class Charter extends UIState {
// adds grid and notes so that they're ALWAYS behind the UI
add(gridBackdrops);
add(textLayer = new FlxLayer());
add(eventsBackdrop);
add(addEventSpr);
add(eventsGroup);
@@ -6,6 +6,37 @@ import funkin.backend.system.Conductor;
import openfl.geom.Rectangle;
import funkin.backend.shaders.CustomShader;
class FlxFastTypedGroup<T:FlxBasic> extends FlxTypedGroup<T> {
public function new(?maxSize:Int = 0) {
super(maxSize);
}
override public function add(Object:T):T
{
if (Object == null)
{
FlxG.log.warn("Cannot add a `null` object to a FlxGroup.");
return null;
}
// removed the check for multiple
// removed the check for null reuse
// If the group is full, return the Object
if (maxSize > 0 && length >= maxSize)
return Object;
// If we made it this far, we need to add the object to the group.
members.push(Object);
length++;
if (_memberAdded != null)
_memberAdded.dispatch(Object);
return Object;
}
}
class CharterBackdropGroup extends FlxTypedGroup<CharterBackdrop> {
public var strumLineGroup:CharterStrumLineGroup;
public var notesGroup:CharterNoteGroup;
@@ -56,9 +87,11 @@ class CharterBackdropGroup extends FlxTypedGroup<CharterBackdrop> {
grid.notesGroup.clear();
notesGroup.forEach((n) -> {
var onStr:Bool = (n.snappedToStrumline ? n.strumLineID : CoolUtil.boundInt(Std.int((n.x+n.width)/(40*strumLine.keyCount)), 0, strumLineGroup.members.length-1)) == i;
if(n.exists && n.visible && onStr)
grid.notesGroup.add(n);
if(n.exists && n.visible) {
var onStr:Bool = (n.snappedToStrumline ? n.strumLineID : CoolUtil.boundInt(Std.int((n.x+n.width)/(40*strumLine.keyCount)), 0, strumLineGroup.members.length-1)) == i;
if(onStr)
grid.notesGroup.add(n);
}
});
grid.active = grid.visible = true;
@@ -97,7 +130,7 @@ class CharterBackdropGroup extends FlxTypedGroup<CharterBackdrop> {
}
}
class CharterBackdrop extends FlxTypedGroup<Dynamic> {
class CharterBackdrop extends FlxTypedGroup<FlxBasic> {
public var gridBackDrop:FlxBackdrop;
public var topLimit:FlxSprite;
public var topSeparator:FlxSprite;
@@ -110,7 +143,7 @@ class CharterBackdrop extends FlxTypedGroup<Dynamic> {
public var beatSeparator:FlxBackdrop;
public var sectionSeparator:FlxBackdrop;
public var notesGroup:FlxTypedGroup<CharterNote> = new FlxTypedGroup<CharterNote>();
public var notesGroup:FlxFastTypedGroup<CharterNote> = new FlxFastTypedGroup<CharterNote>();
public var strumLine:CharterStrumline;
public var gridShader:CustomShader = new CustomShader("engine/charterGrid");
@@ -127,7 +160,7 @@ class CharterBackdrop extends FlxTypedGroup<Dynamic> {
waveformSprite = new FlxSprite().makeSolid(1, 1, 0xFF000000);
waveformSprite.scale.set(160, 1);
waveformSprite.updateHitbox();
waveformSprite.updateHitbox();
add(waveformSprite);
sectionSeparator = new FlxBackdrop(null, Y, 0, 0);
@@ -65,12 +65,17 @@ class CharterDeleteAnim extends CharterNote {
sustainSpr.updateHitbox(); sustainSpr.follow(this, 15, 20);
sustainSpr.exists = deleteData.note.susLength != 0; sustainSpr.alpha = .8;
typeText.text = Std.string(deleteData.note.type);
typeText.exists = deleteData.note.type != 0; typeText.alpha = .4;
typeText.follow(this, 20 - (typeText.frameWidth/2), 20 - (typeText.frameHeight/2));
type = deleteData.note.type;
typeAlpha = .4;
//typeText.text = Std.string(deleteData.note.type);
//typeText.exists = deleteData.note.type != 0; typeAlpha = .4;
//typeText.follow(this, 20 - (typeText.frameWidth/2), 20 - (typeText.frameHeight/2));
for (member in [this, sustainSpr, typeText])
member.alpha *= FlxEase.quadInOut(deleteData.time/deleteTime);
var mult = FlxEase.quadInOut(deleteData.time/deleteTime);
for (member in [this, sustainSpr])
member.alpha *= mult;
typeAlpha *= mult;
super.draw();
}
@@ -5,6 +5,8 @@ import flixel.util.FlxColor;
import funkin.backend.chart.ChartData.ChartEvent;
import funkin.backend.chart.EventsData;
import funkin.backend.system.Conductor;
import funkin.game.Character;
import funkin.game.Stage;
using StringTools;
@@ -163,6 +165,20 @@ class CharterEventScreen extends UISubstateWindow {
var dropdown = new UIDropDown(eventName.x, y, 320, 32, options, Std.int(Math.abs(options.indexOf(cast value))));
paramsPanel.add(dropdown); paramsFields.push(dropdown);
dropdown;
case TCharacter:
addLabel();
var charFileList = Character.getList(false);
var textBox:UIAutoCompleteTextBox = new UIAutoCompleteTextBox(eventName.x, y, cast value);
textBox.suggestItems = charFileList;
paramsPanel.add(textBox); paramsFields.push(textBox);
textBox;
case TStage:
addLabel();
var stageFileList = Stage.getList(false);
var textBox:UIAutoCompleteTextBox = new UIAutoCompleteTextBox(eventName.x, y, cast value);
textBox.suggestItems = stageFileList;
paramsPanel.add(textBox); paramsFields.push(textBox);
textBox;
default:
paramsFields.push(null);
null;
+32 -14
View File
@@ -29,6 +29,8 @@ class CharterNote extends UISprite implements ICharterSelectable {
public var selected:Bool = false;
public var draggable:Bool = true;
static var noteTypeTexts:Array<UIText> = [];
public function new() {
super();
@@ -43,7 +45,7 @@ class CharterNote extends UISprite implements ICharterSelectable {
sustainSpr.scale.set(10, 0);
members.push(sustainSpr);
typeText = new UIText(x, y, 0, Std.string(type));
this.type = 0;
cursor = sustainSpr.cursor = CLICK;
moves = false;
@@ -57,7 +59,22 @@ class CharterNote extends UISprite implements ICharterSelectable {
public var step:Float;
public var id:Int;
public var susLength:Float;
public var type:Int;
public var type(default, set):Null<Int> = null;
public var typeVisible:Bool = true;
public var typeAlpha:Float = 1;
function set_type(v:Null<Int>) {
if(v != this.type) {
if(noteTypeTexts[v] == null || noteTypeTexts[v].graphic.isDestroyed) {
noteTypeTexts[v] = new UIText(x, y, 0, Std.string(v));
noteTypeTexts[v].exists = v != 0;
noteTypeTexts[v].layer = (Charter.instance != null) ? Charter.instance.textLayer : null;
}
typeText = noteTypeTexts[v];
}
return this.type = v;
}
public var strumLine:CharterStrumline;
public var strumLineID(get, default):Int = -1;
@@ -77,9 +94,7 @@ class CharterNote extends UISprite implements ICharterSelectable {
this.type = type;
if (strumLine != null) this.strumLine = strumLine;
typeText.exists = type != 0;
typeText.text = Std.string(this.type);
typeText.follow(this, 20 - (typeText.frameWidth/2), 20 - (typeText.frameHeight/2));
sustainSpr.exists = susLength != 0;
y = step * 40;
@@ -132,10 +147,12 @@ class CharterNote extends UISprite implements ICharterSelectable {
public override function update(elapsed:Float) {
super.update(elapsed);
var sprLength:Float = (40 * (susLength+tempSusLength)) + ((susLength+tempSusLength) != 0 ? (height/2) : 0);
sustainSpr.scale.set(10, __susInstaLerp ? sprLength : CoolUtil.fpsLerp(sustainSpr.scale.y, sprLength, 1/2));
sustainSpr.updateHitbox();
sustainSpr.follow(this, 15, 20);
if(susLength != 0) {
var sprLength:Float = (40 * (susLength+tempSusLength)) + ((susLength+tempSusLength) != 0 ? (height/2) : 0);
sustainSpr.scale.set(10, __susInstaLerp ? sprLength : CoolUtil.fpsLerp(sustainSpr.scale.y, sprLength, 1/2));
sustainSpr.updateHitbox();
sustainSpr.follow(this, 15, 20);
}
sustainDraggable = false;
if (!hovered && susLength != 0) {
@@ -143,9 +160,6 @@ class CharterNote extends UISprite implements ICharterSelectable {
sustainDraggable = UIState.state.isOverlapping(sustainSpr, @:privateAccess sustainSpr.__rect);
}
if (typeText.exists)
typeText.follow(this, 20 - (typeText.frameWidth/2), 20 - (typeText.frameHeight/2));
if (__passed != (__passed = step < Conductor.curStepFloat)) {
if (__passed && FlxG.sound.music.playing && Charter.instance.hitsoundsEnabled(strumLineID))
Charter.instance.hitsound.replay();
@@ -153,7 +167,7 @@ class CharterNote extends UISprite implements ICharterSelectable {
if (strumLine != null) {
sustainSpr.alpha = alpha = !strumLine.strumLine.visible ? (__passed ? 0.2 : 0.4) : (__passed ? 0.6 : 1);
typeText.alpha = !strumLine.strumLine.visible ? (__passed ? 0.4 : 0.6) : (__passed ? 0.8 : 1);
typeAlpha = !strumLine.strumLine.visible ? (__passed ? 0.4 : 0.6) : (__passed ? 0.8 : 1);
}
colorTransform.redMultiplier = colorTransform.greenMultiplier = colorTransform.blueMultiplier = selected ? 0.75 : 1;
@@ -186,6 +200,10 @@ class CharterNote extends UISprite implements ICharterSelectable {
drawMembers();
drawSuper();
if(typeText.exists && typeText.visible) typeText.draw();
if(typeText.exists && typeText.visible && typeVisible) {
typeText.alpha = typeAlpha;
typeText.follow(this, 20 - (typeText.frameWidth/2), 20 - (typeText.frameHeight/2));
typeText.draw();
}
}
}
@@ -7,7 +7,7 @@ class CharterNoteHoverer extends CharterNote {
super();
snappedToStrumline = selectable = autoAlpha = false; visible = sustainSpr.visible = false;
@:privateAccess __animSpeed = 1.25; typeText.visible = false; alpha = 0.4;
@:privateAccess __animSpeed = 1.25; typeVisible = false; alpha = 0.4;
}
@:noCompletion var __mousePos:FlxPoint = FlxPoint.get();
@@ -19,7 +19,7 @@ class CharterNoteHoverer extends CharterNote {
var inBoundsY:Bool = (__mousePos.y > 0 && __mousePos.y < (Charter.instance.__endStep)*40);
if ((__mousePos.x > 0 && __mousePos.x < Charter.instance.strumLines.totalKeyCount * 40 && inBoundsY) && showHoverer) {
step = CoolUtil.bound(FlxG.keys.pressed.SHIFT ? ((__mousePos.y-20) / 40) : Charter.instance.quantStep(__mousePos.y/40), 0, Charter.instance.__endStep-1);
id = Math.floor(__mousePos.x / 40); y = step * 40; x = id * 40; visible = true; sustainSpr.visible = typeText.visible = false;
id = Math.floor(__mousePos.x / 40); y = step * 40; x = id * 40; visible = true; sustainSpr.visible = typeVisible = false;
angle = switch(animation.curAnim.curFrame = ((id - Charter.instance.strumLines.getStrumlineFromID(id).startingID) % 4)) {
case 0: -90;
case 1: 180;
@@ -30,9 +30,9 @@ class CharterNoteHoverer extends CharterNote {
} else
visible = false;
case NOTE_DRAG:
visible = sustainSpr.visible = typeText.visible = true; __doAnim = false;
visible = sustainSpr.visible = typeVisible = true; __doAnim = false;
default:
visible = sustainSpr.visible = typeText.visible = false; __doAnim = false;
visible = sustainSpr.visible = typeVisible = false; __doAnim = false;
}
}
+3 -3
View File
@@ -28,6 +28,8 @@ class UIState extends MusicBeatState {
private var __rect:FlxRect;
private var __mousePos:FlxPoint;
static var __point:FlxPoint = new FlxPoint();
private inline static function get_state()
return FlxG.state is UIState ? cast FlxG.state : null;
@@ -70,17 +72,15 @@ class UIState extends MusicBeatState {
public function isOverlapping(spr:UISprite, rect:FlxRect) {
for(camera in spr.__lastDrawCameras) {
var pos = FlxG.mouse.getScreenPosition(camera, FlxPoint.get());
var pos = FlxG.mouse.getScreenPosition(camera, __point);
__rect.copyFrom(rect);
__rect.x -= camera.scroll.x * spr.scrollFactor.x;
__rect.y -= camera.scroll.y * spr.scrollFactor.y;
if (((pos.x > __rect.x) && (pos.x < __rect.x + __rect.width)) && ((pos.y > __rect.y) && (pos.y < __rect.y + __rect.height))) {
pos.put();
return true;
}
pos.put();
}
return false;
}
+13 -1
View File
@@ -24,6 +24,11 @@ class HealthIcon extends FlxSprite
*/
public var healthSteps:Map<Int, Int> = null;
/**
* current animation state
*/
public var curAnimState:Int = -1;
/**
* Helper for HScript who can't make maps
* @param steps Something like this: `[[0, 1], [20, 0]]`
@@ -91,7 +96,14 @@ class HealthIcon extends FlxSprite
i = icon;
}
}
if (i >= 0) animation.curAnim.curFrame = i;
if (i >= 0 && curAnimState != i) {
var event = EventManager.get(funkin.backend.scripting.events.HealthIconChangeEvent).recycle(i, this);
funkin.backend.scripting.GlobalScript.event("onHealthIconAnimChange", event);
if (!event.cancelled)
animation.curAnim.curFrame = event.amount;
curAnimState = event.amount;
}
}
}
}
+2
View File
@@ -1428,6 +1428,8 @@ class PlayState extends MusicBeatState
FlxG.sound.music.stop();
for (strumLine in strumLines.members) strumLine.vocals.stop();
deathCounter++;
openSubState(new GameOverSubstate(event.x, event.y, event.deathCharID, event.isPlayer, event.gameOverSong, event.lossSFX, event.retrySFX));
scripts.event("onPostGameOver", event);
+4 -1
View File
@@ -40,7 +40,10 @@ class SplashHandler extends FlxTypedGroup<FunkinSprite> {
var __grp:SplashGroup;
public function showSplash(name:String, strum:Strum) {
__grp = getSplashGroup(name);
add(__grp.showOnStrum(strum));
var event = funkin.backend.scripting.EventManager.get(funkin.backend.scripting.events.DynamicEvent).recycle(__grp.showOnStrum(strum), strum);
event = PlayState.instance.scripts.event("onSplashShown", event);
if (!event.cancelled)
add(event.value1);
// max 8 rendered splashes
while(members.length > 8)
+2
View File
@@ -14,6 +14,8 @@ class Strum extends FlxSprite {
public var cpu = false; // Unused
public var lastHit:Float = -5000;
public var strumLine = null;
public var scrollSpeed:Null<Float> = null; // custom scroll speed per strum
public var noteAngle:Null<Float> = null;
+10 -3
View File
@@ -148,6 +148,11 @@ class StrumLine extends FlxTypedGroup<Strum> {
}
}
notes.sortNotes();
var scrollSpeed = strumLine.scrollSpeed;
if(scrollSpeed == null) if (PlayState.instance != null) scrollSpeed = PlayState.instance.scrollSpeed;
if(scrollSpeed == null) scrollSpeed = 1;
notes.limit = 1500 / scrollSpeed;
}
public override function update(elapsed:Float) {
@@ -179,10 +184,11 @@ class StrumLine extends FlxTypedGroup<Strum> {
if (__updateNote_event.cancelled) return;
if (__updateNote_event.__updateHitWindow) {
daNote.canBeHit = (daNote.strumTime > __updateNote_songPos - (PlayState.instance.hitWindow * daNote.latePressWindow)
&& daNote.strumTime < __updateNote_songPos + (PlayState.instance.hitWindow * daNote.earlyPressWindow));
var hitWindow = PlayState.instance.hitWindow;
daNote.canBeHit = (daNote.strumTime > __updateNote_songPos - (hitWindow * daNote.latePressWindow)
&& daNote.strumTime < __updateNote_songPos + (hitWindow * daNote.earlyPressWindow));
if (daNote.strumTime < __updateNote_songPos - PlayState.instance.hitWindow && !daNote.wasGoodHit)
if (daNote.strumTime < __updateNote_songPos - hitWindow && !daNote.wasGoodHit)
daNote.tooLate = true;
}
@@ -303,6 +309,7 @@ class StrumLine extends FlxTypedGroup<Strum> {
animPrefix = strumAnimPrefix[i % strumAnimPrefix.length];
var babyArrow:Strum = new Strum(startingPos.x + ((Note.swagWidth * strumScale * (4 / (data.keyCount != null ? data.keyCount : 4))) * i), startingPos.y);
babyArrow.ID = i;
babyArrow.strumLine = this;
if(data.scrollSpeed != null)
babyArrow.scrollSpeed = data.scrollSpeed;
@@ -56,8 +56,13 @@ class VideoCutscene extends Cutscene {
parseSubtitles();
video = new FlxVideo();
video.onEndReached.add(video.dispose);
video.onEndReached.add(function()
{
video.dispose();
FlxG.removeChild(video);
});
video.onEndReached.add(close);
FlxG.addChildBelowMouse(video);
//cover = new FlxSprite(0, FlxG.height * 0.85).makeSolid(FlxG.width + 50, FlxG.height + 50, 0xFF000000);
//cover.scrollFactor.set(0, 0);
+19 -1
View File
@@ -196,6 +196,10 @@ class FreeplayState extends MusicBeatState
* Path to the currently playing song instrumental.
*/
public var curPlayingInst:String = null;
/**
* If it should play the song automatically.
*/
public var autoplayShouldPlay:Bool = true;
#end
override function update(elapsed:Float)
@@ -236,7 +240,17 @@ class FreeplayState extends MusicBeatState
autoplayElapsed += elapsed;
if (!disableAutoPlay && !songInstPlaying && (autoplayElapsed > timeUntilAutoplay || FlxG.keys.justPressed.SPACE)) {
if (curPlayingInst != (curPlayingInst = Paths.inst(songs[curSelected].name, songs[curSelected].difficulties[curDifficulty]))) {
var huh:Void->Void = function() FlxG.sound.playMusic(curPlayingInst, 0);
var huh:Void->Void = function() {
var soundPath = curPlayingInst;
var sound = null;
if (Assets.exists(soundPath, SOUND) || Assets.exists(soundPath, MUSIC))
sound = Assets.getSound(soundPath);
else
FlxG.log.error('Could not find a Sound asset with an ID of \'$soundPath\'.');
if (sound != null && autoplayShouldPlay)
FlxG.sound.playMusic(sound, 0);
}
if(!disableAsyncLoading) Main.execAsync(huh);
else huh();
}
@@ -289,6 +303,10 @@ class FreeplayState extends MusicBeatState
if (event.cancelled) return;
#if PRELOAD_ALL
autoplayShouldPlay = false;
#end
Options.freeplayLastSong = songs[curSelected].name;
Options.freeplayLastDifficulty = songs[curSelected].difficulties[curDifficulty];
+9 -5
View File
@@ -19,8 +19,10 @@ class MainMenuState extends MusicBeatState
var optionShit:Array<String> = CoolUtil.coolTextFile(Paths.txt("config/menuItems"));
var bg:FlxSprite;
var magenta:FlxSprite;
var camFollow:FlxObject;
var versionText:FunkinText;
public var canAccessDebugMenus:Bool = true;
@@ -32,7 +34,7 @@ class MainMenuState extends MusicBeatState
CoolUtil.playMenuSong();
var bg:FlxSprite = new FlxSprite(-80).loadAnimatedGraphic(Paths.image('menus/menuBG'));
bg = new FlxSprite(-80).loadAnimatedGraphic(Paths.image('menus/menuBG'));
add(bg);
camFollow = new FlxObject(0, 0, 1, 1);
@@ -70,15 +72,16 @@ class MainMenuState extends MusicBeatState
FlxG.camera.follow(camFollow, null, 0.06);
var versionShit:FunkinText = new FunkinText(5, FlxG.height - 2, 0, 'Codename Engine v${Application.current.meta.get('version')}\nCommit ${funkin.backend.system.macros.GitCommitMacro.commitNumber} (${funkin.backend.system.macros.GitCommitMacro.commitHash})\n[${controls.getKeyName(SWITCHMOD)}] Open Mods menu\n');
versionShit.y -= versionShit.height;
versionShit.scrollFactor.set();
add(versionShit);
versionText = new FunkinText(5, FlxG.height - 2, 0, 'Codename Engine v${Application.current.meta.get('version')}\nCommit ${funkin.backend.system.macros.GitCommitMacro.commitNumber} (${funkin.backend.system.macros.GitCommitMacro.commitHash})\n[${controls.getKeyName(SWITCHMOD)}] Open Mods menu\n');
versionText.y -= versionText.height;
versionText.scrollFactor.set();
add(versionText);
changeItem();
}
var selectedSomethin:Bool = false;
var forceCenterX:Bool = true;
override function update(elapsed:Float)
{
@@ -127,6 +130,7 @@ class MainMenuState extends MusicBeatState
super.update(elapsed);
if (forceCenterX)
menuItems.forEach(function(spr:FlxSprite)
{
spr.screenCenter(X);
+347
View File
@@ -0,0 +1,347 @@
package lime.utils;
import haxe.ds.ObjectMap;
/**
A generic object pool for reusing objects.
**/
#if !lime_debug
@:fileXml('tags="haxe,release"')
@:noDebug
#end
#if !js @:generic #end class ObjectPool<T>
{
/**
The number of active objects in the pool.
**/
public var activeObjects(default, null):Int;
/**
The number of inactive objects in the pool.
**/
public var inactiveObjects(default, null):Int;
/**
The total size of the object pool (both active and inactive objects).
**/
public var size(get, set):Null<Int>;
@:noCompletion private var __inactiveObject0:T;
@:noCompletion private var __inactiveObject1:T;
@:noCompletion private var __inactiveObjectList:List<T>;
@:noCompletion private var __pool:Map<T, Bool>;
@:noCompletion private var __size:Null<Int>;
/**
Creates a new ObjectPool instance.
@param create A function that creates a new instance of type T.
@param clean A function that cleans up an instance of type T before it is reused.
@param size The maximum size of the object pool.
**/
public function new(create:Void->T = null, clean:T->Void = null, size:Null<Int> = null)
{
__pool = cast new ObjectMap();
activeObjects = 0;
inactiveObjects = 0;
__inactiveObject0 = null;
__inactiveObject1 = null;
__inactiveObjectList = new List<T>();
if (create != null)
{
this.create = create;
}
if (clean != null)
{
this.clean = clean;
}
if (size != null)
{
this.size = size;
}
}
/**
Adds an object to the object pool.
@param object The object to add to the pool.
**/
public function add(object:T):Void
{
if (object != null && !__pool.exists(object))
{
__pool.set(object, false);
clean(object);
__addInactive(object);
}
}
/**
Dynamic function.
Cleans up an object before returning it to the pool.
@param object The object to clean up.
**/
public dynamic function clean(object:T):Void {}
/**
Clears the object pool, removing all objects.
**/
public function clear():Void
{
__pool = cast new ObjectMap();
activeObjects = 0;
inactiveObjects = 0;
__inactiveObject0 = null;
__inactiveObject1 = null;
__inactiveObjectList.clear();
}
/**
Dynamic function.
Creates a new Object.
**/
public dynamic function create():T
{
return null;
}
/**
Creates a new object and adds it to the pool, or returns an existing inactive object from the pool.
@return The object retrieved from the pool, or null if the pool is full and no new objects can be created.
**/
public function get():T
{
var object = null;
if (inactiveObjects > 0)
{
object = __getInactive();
}
else if (__size == null || activeObjects < __size)
{
object = create();
if (object != null)
{
__pool.set(object, true);
activeObjects++;
}
}
return object;
}
/**
Releases an active object back into the pool.
@param object The object to release.
**/
public function release(object:T):Void
{
#if lime_pool_debug
if (object == null || !__pool.exists(object))
{
Log.error("Object is not a member of the pool");
}
else if (!__pool.get(object))
{
Log.error("Object has already been released");
}
#end
activeObjects--;
if (__size == null || activeObjects + inactiveObjects < __size)
{
clean(object);
__addInactive(object);
}
else
{
__pool.remove(object);
}
}
/**
Removes an object from the pool.
@param object The object to remove from the pool.
**/
public function remove(object:T):Void
{
if (object != null && __pool.exists(object))
{
__pool.remove(object);
if (__inactiveObject0 == object)
{
__inactiveObject0 = null;
inactiveObjects--;
}
else if (__inactiveObject1 == object)
{
__inactiveObject1 = null;
inactiveObjects--;
}
else if (__inactiveObjectList.remove(object))
{
inactiveObjects--;
}
else
{
activeObjects--;
}
}
}
@:noCompletion private inline function __addInactive(object:T):Void
{
#if lime_pool_debug
__pool.set(object, false);
#end
if (__inactiveObject0 == null)
{
__inactiveObject0 = object;
}
else if (__inactiveObject1 == null)
{
__inactiveObject1 = object;
}
else
{
__inactiveObjectList.add(object);
}
inactiveObjects++;
}
@:noCompletion private inline function __getInactive():T
{
var object = null;
if (__inactiveObject0 != null)
{
object = __inactiveObject0;
__inactiveObject0 = null;
}
else if (__inactiveObject1 != null)
{
object = __inactiveObject1;
__inactiveObject1 = null;
}
else
{
object = __inactiveObjectList.pop();
if (__inactiveObjectList.length > 0)
{
__inactiveObject0 = __inactiveObjectList.pop();
}
if (__inactiveObjectList.length > 0)
{
__inactiveObject1 = __inactiveObjectList.pop();
}
}
#if lime_pool_debug
__pool.set(object, true);
#end
inactiveObjects--;
activeObjects++;
return object;
}
@:noCompletion private function __removeInactive(count:Int):Void
{
if (count <= 0 || inactiveObjects == 0) return;
if (__inactiveObject0 != null)
{
__pool.remove(__inactiveObject0);
__inactiveObject0 = null;
inactiveObjects--;
count--;
}
if (count == 0 || inactiveObjects == 0) return;
if (__inactiveObject1 != null)
{
__pool.remove(__inactiveObject1);
__inactiveObject1 = null;
inactiveObjects--;
count--;
}
if (count == 0 || inactiveObjects == 0) return;
for (object in __inactiveObjectList)
{
__pool.remove(object);
__inactiveObjectList.remove(object);
inactiveObjects--;
count--;
if (count == 0 || inactiveObjects == 0) return;
}
}
// Get & Set Methods
@:noCompletion private function get_size():Null<Int>
{
return __size;
}
@:noCompletion private function set_size(value:Null<Int>):Null<Int>
{
if (value == null)
{
__size = null;
}
else
{
var current = inactiveObjects + activeObjects;
__size = value;
if (current > value)
{
__removeInactive(current - value);
}
else if (value > current)
{
var object;
for (i in 0...(value - current))
{
object = create();
if (object != null)
{
__pool.set(object, false);
__inactiveObjectList.add(object);
inactiveObjects++;
}
else
{
break;
}
}
}
}
return value;
}
}