Compare commits

...
10 Commits
Author SHA1 Message Date
Hundrec b2215482c2 Bump docs to 0.8.7
Build and Upload nightly game builds / gather-changes (push) Canceled after 0s
Build and Upload nightly game builds / gather-tags (push) Canceled after 0s
Build and Upload nightly game builds / docker-image (push) Canceled after 0s
Build and Upload nightly game builds / build-game-on-host (macos, macos) (push) Canceled after 0s
Build and Upload nightly game builds / build-game-on-host (windows, windows) (push) Canceled after 0s
Build and Upload nightly game builds / build-game-in-container (html5) (push) Canceled after 0s
Build and Upload nightly game builds / build-game-in-container (linux) (push) Canceled after 0s
2026-08-23 10:15:12 +08:00
Hundrec 59dae0f601 Bump version to 0.8.7 2026-08-23 10:15:12 +08:00
Hundrec 4d70e13629 Changelog for 0.8.7 2026-08-23 10:15:08 +08:00
Hundrec 83bc17970a Changelog platform formatting for 0.8.6 2026-08-23 10:08:03 +08:00
EricandHundrec 72078e4fec Add note hitsounds link to rejected features 2026-08-23 10:08:02 +08:00
EliteMasterEricandHundrec f5bd835496 Fix pull request label actions overriding each other 2026-08-23 10:08:02 +08:00
Karim AkraandHundrec f2fe179109 playest menu camera reset 2026-08-23 10:08:02 +08:00
MoonDroid b1d91ab5d8 FIx compression data + TouchUtil crash 2026-08-22 12:27:42 +07:00
MAJigsaw77andMoonDroid f09e89e324 Update lime and openfl 2026-08-21 20:59:06 +07:00
MoonDroidandKarim Akra 3c8f7c08ec Rewrite the FNFC java copy function for android
The old one was randomly throwing some crashes such as
* OutOfMemory
* NegativeArraySizeException
* IllegalStateException

This new one should fix those!

Co-Authored-By: Karim Akra <144803230+KarimAkra@users.noreply.github.com>
2026-08-21 14:46:57 +07:00
11 changed files with 110 additions and 75 deletions
@@ -7,6 +7,11 @@ on:
types:
- opened
# Ensure only one task can execute for a given PR at a time.
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref }}
queue: max
jobs:
# Apply `status: pending triage` to newly created pull requests
+4
View File
@@ -13,6 +13,10 @@ name: "Pull Request Labeler"
on:
- pull_request_target
# Ensure only one task can execute for a given PR at a time.
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref }}
queue: max
jobs:
# Apply labels to pull requests based on which files were edited
+13 -3
View File
@@ -4,19 +4,29 @@ All notable changes will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.8.7] - 2026-08-23
### Fixed
- [ANDROID] Fixed a crash when opening an FNFC chart file.
- [ANDROID] Fixed errors and crashes related to the lime backend.
- [ANDROID] Fixed a shader not displaying correctly in some places.
## [0.8.6] - 2026-08-12
### Added
- Added the ability to toggle Discord RPC statuses and hide song info.
- (Linux) Added support for Wayland, which the game now defaults to. (Thanks Starexify!)
- [LINUX] Added support for Wayland, which the game now defaults to. (Thanks Starexify!)
- Added the game version as a compilation flag for modders to access. ([e51ae10](https://github.com/FunkinCrew/Funkin/commit/e51ae1098a9392c7ec3a903543f3aa4fc4220da1)) - by @zxcksharks in [#7659](https://github.com/FunkinCrew/Funkin/pull/7659)
- Added a shouldBop property to HealthIconData to allow animated icons to bop. ([cc91faa](https://github.com/FunkinCrew/Funkin/commit/cc91faaccc63d2050270723bd49477f8b518ab6f)) - by @Starexify in [#6901](https://github.com/FunkinCrew/Funkin/pull/6901)
- Added album and sticker pack fields to the Chart Editor Metadata window. ([790e3fb](https://github.com/FunkinCrew/Funkin/commit/790e3fb097b7054e7cf4010d6b588264414d283a)) - by @Starexify in [#6266](https://github.com/FunkinCrew/Funkin/pull/6266)
### Changed
- (HTML5) The “Touch To Play” sprite now smoothly scales when hovered.
- [HTML5] The “Touch To Play” sprite now smoothly scales when hovered.
- Made some improvements to width/height and cliprect functionality for FunkinGroup.
- The Chart Editor now consistently exports chart data in the same order. (Thanks TechnikTil!)
- Discord RPC images can now be configured in the album and song data files.
@@ -33,7 +43,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Preprocessors that span the entire file no longer throw an error. (Thanks KoloInDaCrib!)
- Scripted class extending no longer breaks with multiple scripted layers. (Thanks TechnikTil!)
- Imports with module names (ex. `funkin.play.character.BaseCharacter.CharacterType​​`) no longer throw an import error. (Thanks NotHyper-474!)
- (iOS) Connecting a keyboard no longer freezes the game.
- [iOS] Connecting a keyboard no longer freezes the game.
- The Darken blend mode no longer renders with black boxes, fixing the Boyfriend Freeplay DJ Dad animation.
- The Open File dialog now opens from the latest directory, not the root directory.
- The Chart Editor now exports charts with correct suffixes for vocal tracks.
+1 -1
Submodule assets updated: 9300719cb2...724eba9de9
+4
View File
@@ -9,6 +9,10 @@
"asset": "assets/preload/images/NOTE_assets.png",
"blocksize": "4x4"
},
{
"asset": "assets/shared/images/characters/darnell/spritemap1.png",
"blocksize": "4x4"
},
{
"asset": "assets/preload/images/NOTE_hold_assets.png",
"blocksize": "4x4"
+2 -1
View File
@@ -60,7 +60,7 @@ This section provides guidelines to follow when [opening an issue](https://githu
## Requirements
Make sure you're playing:
- the latest version of the game (currently v0.8.6) or a public playtest version (v0.9 Feature Preview builds)
- the latest version of the game (currently v0.8.6, or v0.8.7 for Android) or a public playtest version (v0.9 Feature Preview builds)
- without any mods (unless the issue involves mods)
- on [Newgrounds](https://www.newgrounds.com/portal/view/770371) or downloaded from [itch.io](https://ninja-muffin24.itch.io/funkin)
@@ -86,6 +86,7 @@ Here's a list of commonly suggested features and the reasons why they won't be a
| Importing Charts from Psych Engine (and other mod content) | https://github.com/FunkinCrew/Funkin/issues/2586#issuecomment-2125733327 |
| Backwards Compatibility for Modding | https://github.com/FunkinCrew/Funkin/issues/3949#issuecomment-2608391329 |
| Lua Support | https://github.com/FunkinCrew/Funkin/issues/2643#issuecomment-2143718093 |
| Note Hitsounds | https://github.com/FunkinCrew/Funkin/pull/4112#issuecomment-5347549977 |
## Issue Types
Choose the issue template that best suits your needs!
+2 -2
View File
@@ -188,7 +188,7 @@
{
"name": "lime",
"type": "git",
"ref": "ad0080e7e1df97d06060ea6cf5ce8f8088c3b872",
"ref": "268dacfb2609766e14bef9ea5b669e91501852d2",
"url": "https://github.com/FunkinCrew/lime"
},
{
@@ -201,7 +201,7 @@
{
"name": "openfl",
"type": "git",
"ref": "2e5fc2062fb07b40f81b45268085a2efdb2eb9ae",
"ref": "74a51908a116d6df74be1083e219abb9fa057636",
"url": "https://github.com/FunkinCrew/openfl"
},
{
+8 -14
View File
@@ -32,13 +32,13 @@ class Project extends HXProject
* REMEMBER TO CHANGE THIS WHEN THE GAME UPDATES!
* You only have to change it here, the rest of the game will query this value.
*/
static final VERSION:String = "0.8.6";
static final VERSION:String = "0.8.7";
/**
* The build's number and version code.
* Used when publishing the game to mobile app stores. Should increment with each patch.
*/
static final BUILD_NUMBER:Int = 100;
static final BUILD_NUMBER:Int = 102;
/**
* The game's name. Used as the default window title.
@@ -105,16 +105,13 @@ class Project extends HXProject
//
/**
* The app's minimal Android SDK version.
* The app's lime Android java extensions.
*/
static final ANDROID_MINIMUM_SDK_VERSION:Int = 28;
/**
* The app's target Android SDK version.
*/
static final ANDROID_TARGET_SDK_VERSION:Int = 35;
static final ANDROID_EXTENSIONS:Array<String> = ["funkin.extensions.CallbackUtil", "funkin.extensions.FNFCExtension", "funkin.extensions.AudioSession"];
static final ANDROID_EXTENSIONS:Array<String> = [
"funkin.extensions.CallbackUtil",
"funkin.extensions.FNFCExtension",
"funkin.extensions.AudioSession"
];
/**
* The team ID to use for the iOS app. Configured in XCode.
@@ -693,9 +690,6 @@ class Project extends HXProject
this.excludeArchitectures.push(Architecture.ARMV7);
}
config.set("android.minimum-sdk-version", ANDROID_MINIMUM_SDK_VERSION);
config.set("android.target-sdk-version", ANDROID_TARGET_SDK_VERSION);
if (isRelease())
{
if (envConfig != null)
@@ -2,23 +2,26 @@ package funkin.extensions;
import android.content.Intent;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.os.Build;
import android.os.FileUtils;
import android.os.Bundle;
import android.util.Log;
import android.util.Base64;
import funkin.extensions.CallbackUtil;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import org.haxe.extension.Extension;
import org.haxe.lime.HaxeObject;
public class FNFCExtension extends Extension
{
public static final String LOG_TAG = "FNFCExtension";
@@ -69,61 +72,74 @@ public class FNFCExtension extends Extension
}
public static String copyFNFCToCache(Uri uri) throws IOException
{
if (uri != null)
{
if (uri == null) return null;
File output = null;
try
{
String fileName = new File(uri.getPath()).getName();
// Clean some Uri leftovers
if (fileName.contains(":"))
fileName = fileName.split(":")[1];
File cacheFNFC = new File(mainContext.getCacheDir(), "fnfc");
File output = new File(cacheFNFC, fileName);
if (!cacheFNFC.exists() && !cacheFNFC.mkdirs())
throw new IOException("Failed to create FNFC cache dir at: " + cacheFNFC.getAbsolutePath());
if (!cacheFNFC.exists())
cacheFNFC.mkdir();
output = new File(cacheFNFC, fnfcCacheName(uri));
if (output.exists())
output.delete();
ParcelFileDescriptor parcelFileDescriptor = null;
FileInputStream fileInputStream = null;
OutputStream out = null;
InputStream in = null;
OutputStream out = null;
try
{
parcelFileDescriptor = mainContext.getContentResolver().openFileDescriptor(uri, "r");
fileInputStream = new FileInputStream(parcelFileDescriptor.getFileDescriptor());
in = mainContext.getContentResolver().openInputStream(uri);
if (in == null)
throw new IOException("Failed to get input stream for Uri: " + uri.toString());
byte[] fileBytes = new byte[(int) parcelFileDescriptor.getStatSize()];
fileInputStream.read(fileBytes);
out = new FileOutputStream(output);
out = new FileOutputStream(output);
out.write(fileBytes);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
{
FileUtils.copy(in, out);
}
else
{
Files.copy(in, output.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
if (output.exists())
output.deleteOnExit(); // makes the file get deleted when the app closes ig?
out.flush();
}
catch (IOException e)
finally
{
Log.e(LOG_TAG, e.getMessage());
if (in != null)
in.close();
if (out != null)
out.close();
}
finally
{
if (fileInputStream != null)
fileInputStream.close();
if (parcelFileDescriptor != null)
parcelFileDescriptor.close();
if (output.length() <= 0)
throw new IOException("The copied Uri file (" + uri.toString() + ") ended empty at: " + output.getAbsolutePath());
if (out != null)
out.close();
}
return output.getAbsolutePath();
}
catch (Throwable t)
{
Log.e("trace", "Failed to copy FNFC from " + uri.toString() + ". Error message: " + t.getMessage());
if (output != null) output.delete();
return null;
}
}
return output.getAbsolutePath();
}
return null;
}
private static String fnfcCacheName(Uri uri)
{
try
{
byte[] digest = MessageDigest.getInstance("SHA-256")
.digest(uri.toString().getBytes(StandardCharsets.UTF_8));
return Base64.encodeToString(digest,
Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING) + ".fnfc";
}
catch (Exception e)
{
return Integer.toHexString(uri.toString().hashCode()) + ".fnfc";
}
}
}
@@ -39,14 +39,20 @@ class ChartPlaytestMenu extends MusicBeatState
playtestCam = new FunkinCamera('playtestCam');
playtestCam.bgColor = 0x0;
// playtestCam.alpha = 0;
FlxG.cameras.add(playtestCam, false);
cameras = [playtestCam];
FlxG.cameras.reset(playtestCam);
subStateClosed.add((_) ->
{
FlxG.cameras.reset(playtestCam = new FunkinCamera('playtestCam'));
playtestCam.bgColor = 0x0;
cameras = [playtestCam];
});
var blackBG:FunkinSprite = new FunkinSprite(0, 0);
blackBG.makeSolidColor(FlxG.width * 3, FlxG.height * 3, FlxColor.BLACK);
blackBG.scrollFactor.set();
blackBG.alpha = 0.4;
blackBG.cameras = [playtestCam];
add(blackBG);
this.filePath = filePath;
@@ -54,7 +60,6 @@ class ChartPlaytestMenu extends MusicBeatState
songName = new FlxText(0, FlxG.height * 0.1, 0, 'Loaded Song: ${targetSong.songName}',
30).setFormat(Paths.font('vcr.ttf'), 50, FlxColor.WHITE, FlxTextAlign.CENTER);
songName.screenCenter(X);
songName.cameras = [playtestCam];
add(songName);
variationButton = new ChartPlaytestMenuButtonListToggle(0, FlxG.height * 0.55, "Variation", targetSong.variations, function(value:String)
@@ -63,7 +68,6 @@ class ChartPlaytestMenu extends MusicBeatState
variationButton.screenCenter(X);
});
variationButton.screenCenter(X);
variationButton.cameras = [playtestCam];
add(variationButton);
difficultyButton = new ChartPlaytestMenuButtonListToggle(0, FlxG.height * 0.45, "Difficulty",
@@ -73,7 +77,6 @@ class ChartPlaytestMenu extends MusicBeatState
difficultyButton.screenCenter(X);
});
difficultyButton.screenCenter(X);
difficultyButton.cameras = [playtestCam];
add(difficultyButton);
playtestButton = new ChartPlaytestMenuButton(0, FlxG.height * 0.8, "Playtest Song", function()
@@ -88,7 +91,6 @@ class ChartPlaytestMenu extends MusicBeatState
}
});
playtestButton.screenCenter(X);
playtestButton.cameras = [playtestCam];
add(playtestButton);
FlxTween.tween(playtestCam, {alpha: 1}, 0.5);
+1 -2
View File
@@ -93,9 +93,8 @@ class TouchUtil
if (object == null || touch == null) return false;
if (camera == null) camera = object.cameras[0];
@:privateAccess
return object.overlapsPoint(touch.getWorldPosition(camera, object._point), true, camera);
if (object._point != null) return object.overlapsPoint(touch.getWorldPosition(camera, object._point), true, camera);
return false;
}