Merge branch 'develop' into 8.3.0-Dev

This commit is contained in:
Josh Tynjala
2025-08-20 07:33:22 -07:00
9 changed files with 170 additions and 76 deletions

View File

@@ -117,6 +117,7 @@ jobs:
rm /usr/local/bin/idle3* rm /usr/local/bin/idle3*
rm /usr/local/bin/pydoc3* rm /usr/local/bin/pydoc3*
rm /usr/local/bin/python3* rm /usr/local/bin/python3*
rm /usr/local/bin/pip3*
brew bundle brew bundle
popd popd

View File

@@ -1,5 +1,5 @@
<xml> <xml>
<include name="${HXCPP}/project/thirdparty/mbedtls_files.xml" noerror="true" if="static_link"/> <include name="${HXCPP}/project/thirdparty/mbedtls-files.xml" noerror="true" if="static_link" />
<set name="HAS_HXCPP_MBEDTLS_FLAGS" value="1" if="MBEDTLS_DIR" /> <set name="HAS_HXCPP_MBEDTLS_FLAGS" value="1" if="MBEDTLS_DIR" />
<include name="${HXCPP}/src/hx/libs/ssl/Build.xml" unless="MBEDTLS_DIR"/> <include name="${HXCPP}/src/hx/libs/ssl/Build.xml" unless="MBEDTLS_DIR"/>
@@ -30,7 +30,7 @@
<compilerflag value="-I${NATIVE_TOOLKIT_PATH}/mbedtls/include" if="NATIVE_TOOLKIT_HAVE_MBEDTLS" unless="static_link"/> <compilerflag value="-I${NATIVE_TOOLKIT_PATH}/mbedtls/include" if="NATIVE_TOOLKIT_HAVE_MBEDTLS" unless="static_link"/>
<section if="static_link"> <section if="static_link">
<include name="${HXCPP}/project/thirdparty/mbedtls_flags.xml" if="HAS_HXCPP_MBEDTLS_FLAGS" /> <include name="${HXCPP}/project/thirdparty/mbedtls-flags.xml" if="HAS_HXCPP_MBEDTLS_FLAGS" />
<section unless="HAS_HXCPP_MBEDTLS_FLAGS"> <section unless="HAS_HXCPP_MBEDTLS_FLAGS">

View File

@@ -39,10 +39,10 @@
#include <SDL.h> #include <SDL.h>
#include <string> #include <string>
#ifdef HX_WINDOWS
#include <locale> #include <locale>
#include <codecvt> #include <codecvt>
#endif
using wstring_convert = std::wstring_convert<std::codecvt_utf8<wchar_t>>;
namespace lime { namespace lime {
@@ -111,13 +111,15 @@ namespace lime {
case APPLICATION: { case APPLICATION: {
char* path = SDL_GetBasePath (); char* path = SDL_GetBasePath ();
#ifdef HX_WINDOWS
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter; if (path != nullptr) {
result = new std::wstring (converter.from_bytes(path));
#else wstring_convert converter;
result = new std::wstring (path, path + strlen (path)); result = new std::wstring (converter.from_bytes(path));
#endif SDL_free (path);
SDL_free (path);
}
break; break;
} }
@@ -125,13 +127,15 @@ namespace lime {
case APPLICATION_STORAGE: { case APPLICATION_STORAGE: {
char* path = SDL_GetPrefPath (company, title); char* path = SDL_GetPrefPath (company, title);
#ifdef HX_WINDOWS
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter; if (path != nullptr) {
result = new std::wstring (converter.from_bytes(path));
#else wstring_convert converter;
result = new std::wstring (path, path + strlen (path)); result = new std::wstring (converter.from_bytes(path));
#endif SDL_free (path);
SDL_free (path);
}
break; break;
} }
@@ -145,11 +149,9 @@ namespace lime {
#elif defined (HX_WINDOWS) #elif defined (HX_WINDOWS)
char folderPath[MAX_PATH] = ""; WCHAR folderPath[MAX_PATH] = L"";
SHGetFolderPath (NULL, CSIDL_DESKTOPDIRECTORY, NULL, SHGFP_TYPE_CURRENT, folderPath); SHGetFolderPathW (NULL, CSIDL_DESKTOPDIRECTORY, NULL, SHGFP_TYPE_CURRENT, folderPath);
//WIN_StringToUTF8 (folderPath); result = new std::wstring (folderPath);
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
result = new std::wstring (converter.from_bytes (folderPath));
#elif defined (IPHONE) #elif defined (IPHONE)
@@ -159,15 +161,14 @@ namespace lime {
char const* home = getenv ("HOME"); char const* home = getenv ("HOME");
if (home == NULL) { if (home != NULL) {
return 0; std::string path = std::string (home) + std::string ("/Desktop");
wstring_convert converter;
result = new std::wstring (converter.from_bytes(path));
} }
std::string path = std::string (home) + std::string ("/Desktop");
result = new std::wstring (path.begin (), path.end ());
#endif #endif
break; break;
@@ -182,11 +183,9 @@ namespace lime {
#elif defined (HX_WINDOWS) #elif defined (HX_WINDOWS)
char folderPath[MAX_PATH] = ""; WCHAR folderPath[MAX_PATH] = L"";
SHGetFolderPath (NULL, CSIDL_MYDOCUMENTS, NULL, SHGFP_TYPE_CURRENT, folderPath); SHGetFolderPathW (NULL, CSIDL_MYDOCUMENTS, NULL, SHGFP_TYPE_CURRENT, folderPath);
//WIN_StringToUTF8 (folderPath); result = new std::wstring (folderPath);
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
result = new std::wstring (converter.from_bytes (folderPath));
#elif defined (IPHONE) #elif defined (IPHONE)
@@ -203,7 +202,8 @@ namespace lime {
if (home != NULL) { if (home != NULL) {
std::string path = std::string (home) + std::string ("/Documents"); std::string path = std::string (home) + std::string ("/Documents");
result = new std::wstring (path.begin (), path.end ()); wstring_convert converter;
result = new std::wstring (converter.from_bytes(path));
} }
@@ -220,11 +220,9 @@ namespace lime {
#elif defined (HX_WINDOWS) #elif defined (HX_WINDOWS)
char folderPath[MAX_PATH] = ""; WCHAR folderPath[MAX_PATH] = L"";
SHGetFolderPath (NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, folderPath); SHGetFolderPathW (NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, folderPath);
//WIN_StringToUTF8 (folderPath); result = new std::wstring (folderPath);
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
result = new std::wstring (converter.from_bytes (folderPath));
#elif defined (HX_MACOS) #elif defined (HX_MACOS)
@@ -260,11 +258,9 @@ namespace lime {
#elif defined (HX_WINDOWS) #elif defined (HX_WINDOWS)
char folderPath[MAX_PATH] = ""; WCHAR folderPath[MAX_PATH] = L"";
SHGetFolderPath (NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, folderPath); SHGetFolderPathW (NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, folderPath);
//WIN_StringToUTF8 (folderPath); result = new std::wstring (folderPath);
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
result = new std::wstring (converter.from_bytes (folderPath));
#elif defined (IPHONE) #elif defined (IPHONE)
@@ -281,7 +277,8 @@ namespace lime {
if (home != NULL) { if (home != NULL) {
std::string path = std::string (home); std::string path = std::string (home);
result = new std::wstring (path.begin (), path.end ()); wstring_convert converter;
result = new std::wstring (converter.from_bytes(path));
} }
@@ -909,4 +906,4 @@ namespace lime {
} }
} }

View File

@@ -189,13 +189,10 @@ class ImageCanvasUtil
if (!image.transparent) if (!image.transparent)
{ {
if (!image.transparent) buffer.__srcCanvas.setAttribute("moz-opaque", "true"); buffer.__srcCanvas.setAttribute("moz-opaque", "true");
buffer.__srcContext = untyped #if haxe4 js.Syntax.code #else __js__ #end ('buffer.__srcCanvas.getContext ("2d", { alpha: false })');
}
else
{
buffer.__srcContext = buffer.__srcCanvas.getContext("2d");
} }
buffer.__srcContext = buffer.__srcCanvas.getContext("2d", {alpha: image.transparent});
} }
#end #end
} }

View File

@@ -360,39 +360,68 @@ class IOSHelper
applicationPath = workingDirectory + "/build/" + configuration + "-iphoneos/" + project.app.file + ".app"; applicationPath = workingDirectory + "/build/" + configuration + "-iphoneos/" + project.app.file + ".app";
} }
var requireIPad = project.config.getString("ios.device", "universal") == "ipad";
var requireIPhone = project.config.getString("ios.device", "universal") == "iphone";
var xcodeVersion = Std.parseFloat(getXcodeVersion()); var xcodeVersion = Std.parseFloat(getXcodeVersion());
if (!Math.isNaN(xcodeVersion) && xcodeVersion >= 16) { if (!Math.isNaN(xcodeVersion) && xcodeVersion >= 16) {
// ios-deploy doesn't work with newer iOS SDKs where it can't // ios-deploy doesn't work with newer iOS SDKs where it can't
// find DeveloperDiskImage.dmg. however, Xcode 16 adds new // find DeveloperDiskImage.dmg. however, Xcode 16 adds new
// commands for installing and launching apps on connected // commands for installing and launching apps on connected
// devices, so we'll prefer those, if available. // devices, so we'll prefer those, if available.
var deviceUUID:String = null; var deviceUUID:String = null;
// prefer an iOS device with State == 'connected'
// Note: Platform == 'iOS' includes iPadOS // we'll try various combinations of the following filters to
var listDevicesOutput = System.runProcess("", "xcrun", ["devicectl", "list", "devices", "--hide-default-columns", "--columns", "Identifier", "--filter", "Platform == 'iOS' AND State == 'connected'"]); // select an iOS device. there may be multiple devices to choose
var ready = false; // from, so these filters help us figure out the best one.
for (line in listDevicesOutput.split("\n")) {
if (!ready) { var filterPlatformIOS = "Platform == 'iOS'"; // includes iPadOS
ready = StringTools.startsWith(line, "----"); var filterDeveloperModeEnabled = "deviceProperties.developerModeStatus == 'enabled'";
continue; var filterStateConnected = "State == 'connected'";
} var filterStateAvailable = "State == 'available (paired)'";
deviceUUID = line; var filterTransportTypeWired = "connectionProperties.transportType == 'wired'";
break; var filterTransportTypeLocalNetwork = "connectionProperties.transportType == 'localNetwork'";
var filterDeviceTypeIPhone = "hardwareProperties.deviceType == 'iPhone'";
var filterDeviceTypeIPad = "hardwareProperties.deviceType == 'iPad'";
// first, some strictly required filters:
// 1. the platform must always be iOS (which includes iPadOS).
// 2. the device must be in developer mode.
// 3. if required by the project config, limit to iPhone or iPad only
var baseFilters = [
filterPlatformIOS,
filterDeveloperModeEnabled,
];
if (requireIPad)
{
baseFilters.push(filterDeviceTypeIPad);
} }
if (deviceUUID == null || deviceUUID.length == 0) { else if (requireIPhone)
// preferred fallback is an iOS device that is both {
// available and wired baseFilters.push(filterDeviceTypeIPhone);
var listDevicesOutput = System.runProcess("", "xcrun", ["devicectl", "list", "devices", "--hide-default-columns", "--columns", "Identifier", "--filter", "Platform == 'iOS' AND State == 'available (paired)' AND connectionProperties.transportType == 'wired'"]); }
ready = false;
for (line in listDevicesOutput.split("\n")) { // after that, we have the following preferences, in order:
if (!ready) { // 1. state: "connected" preferred over "available (paired)"
ready = StringTools.startsWith(line, "----"); // 2. transportType: "wired" preferred over "localNetwork"
continue; var stateFilters = [filterStateConnected, filterStateAvailable];
var transportTypeFilters = [filterTransportTypeWired, filterTransportTypeLocalNetwork];
for (stateFilter in stateFilters)
{
for (transportTypeFilter in transportTypeFilters)
{
deviceUUID = findDeviceUUIDWithFilters(baseFilters.concat([
stateFilter,
transportTypeFilter
]));
if (deviceUUID != null && deviceUUID.length > 0)
{
break;
} }
deviceUUID = line;
break;
} }
} }
if (deviceUUID == null || deviceUUID.length == 0) { if (deviceUUID == null || deviceUUID.length == 0) {
// devices running iOS 16 and older don't support // devices running iOS 16 and older don't support
// xcrun devicectl, so if no device was found, try falling // xcrun devicectl, so if no device was found, try falling
@@ -416,6 +445,27 @@ class IOSHelper
} }
} }
private static function findDeviceUUIDWithFilters(filters:Array<String>):String
{
var listDevicesOutput = System.runProcess("", "xcrun",
[
"devicectl", "list", "devices",
"--hide-default-columns", "--columns", "Identifier",
"--filter", filters.join(" AND ")
]);
var ready = false;
for (line in listDevicesOutput.split("\n"))
{
if (!ready)
{
ready = StringTools.startsWith(line, "----");
continue;
}
return line;
}
return null;
}
private static function fallbackLaunch(project:HXProject, applicationPath:String):Void private static function fallbackLaunch(project:HXProject, applicationPath:String):Void
{ {
var templatePaths = [ var templatePaths = [

View File

@@ -14,6 +14,7 @@ import hl.Bytes as HLBytes;
import hl.NativeArray; import hl.NativeArray;
#end #end
#if sys #if sys
import sys.FileSystem;
import sys.io.File; import sys.io.File;
#end #end
#if (js && html5) #if (js && html5)
@@ -98,6 +99,29 @@ class FileDialog
{ {
if (type == null) type = FileDialogType.OPEN; if (type == null) type = FileDialogType.OPEN;
#if sys
if (defaultPath != null && defaultPath.length > 0
&& FileSystem.exists(defaultPath)
&& FileSystem.isDirectory(defaultPath))
{
// if the default path is a directory, and the default path doesn't
// end with a separator, tiny file dialogs may open its parent
// directory instead.
var lastChar = defaultPath.charAt(defaultPath.length - 1);
#if windows
if (lastChar != "/" && lastChar != "\\")
{
defaultPath = defaultPath + "\\";
}
#else
if (lastChar != "/")
{
defaultPath = defaultPath + "/";
}
#end
}
#end
#if desktop #if desktop
var worker = new ThreadPool(#if windows SINGLE_THREADED #end); var worker = new ThreadPool(#if windows SINGLE_THREADED #end);
@@ -148,6 +172,7 @@ class FileDialog
var path = null; var path = null;
#if (!macro && lime_cffi) #if (!macro && lime_cffi)
trace(defaultPath);
path = CFFI.stringValue(NativeCFFI.lime_file_dialog_open_file(title, filter, defaultPath)); path = CFFI.stringValue(NativeCFFI.lime_file_dialog_open_file(title, filter, defaultPath));
#end #end

View File

@@ -181,7 +181,23 @@ class Assets
} }
/** /**
* Gets an instance of an embedded bitmap * Gets an instance of an embedded bitmap.
*
* _Note:_ This method may behave differently, depending on the target
* platform. On targets that can quickly create a new image synchronously,
* every call to `Assets.getImage()` with the same ID will return a new
* `Image` instance. However, on other targets where creating images
* synchronously is unacceptably slow, or where images may not be created
* synchronously and must be created asynchronously, every call to
* `Assets.getImage()` with the same ID may return a single, shared `Image`
* instance.
*
* With that in mind, modifying or disposing the contents of the `Image`
* returned by `Assets.getImage()` may affect the results of future calls to
* Assets.getImage()` on some targets. To access an `Image` instance that
* may be modified without affecting future calls to `Assets.getImage()`,
* call the `Image` instance's `clone()` method to manually create a copy.
*
* @usage var bitmap = new Bitmap(Assets.getBitmapData("image.jpg")); * @usage var bitmap = new Bitmap(Assets.getBitmapData("image.jpg"));
* @param id The ID or asset path for the bitmap * @param id The ID or asset path for the bitmap
* @param useCache (Optional) Whether to use BitmapData from the cache(Default: true) * @param useCache (Optional) Whether to use BitmapData from the cache(Default: true)

View File

@@ -9,6 +9,7 @@ import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Looper;
import android.os.VibrationEffect; import android.os.VibrationEffect;
import android.os.Vibrator; import android.os.Vibrator;
import android.view.DisplayCutout; import android.view.DisplayCutout;
@@ -202,7 +203,7 @@ public class GameActivity extends SDLActivity {
} }
handler = new Handler (); handler = new Handler (Looper.getMainLooper ());
Extension.assetManager = assetManager; Extension.assetManager = assetManager;
Extension.callbackHandler = handler; Extension.callbackHandler = handler;

View File

@@ -1825,6 +1825,13 @@ class CommandLineTools
args.push("-notoolscheck"); args.push("-notoolscheck");
var projectDirectory = Path.directory(projectFile);
var localRepository = Path.combine(projectDirectory, ".haxelib");
if (FileSystem.exists(localRepository) && FileSystem.isDirectory(localRepository) && StringTools.startsWith(path, localRepository))
{
args.push("-nolocalrepocheck");
}
Sys.setCwd(path); Sys.setCwd(path);
var args = [Path.combine(path, "run.n")].concat(args); var args = [Path.combine(path, "run.n")].concat(args);
args.push(workingDirectory); args.push(workingDirectory);