fixed bootstrapping and asset handling
This commit is contained in:
@@ -1,136 +1,331 @@
|
||||
package;
|
||||
|
||||
import openfl.Lib;
|
||||
import lime.utils.AssetType;
|
||||
import lime.tools.Asset;
|
||||
import lime.ui.WindowAttributes;
|
||||
import openfl.system.System;
|
||||
import openfl.display.Application;
|
||||
import openfl.display.Stage;
|
||||
import openfl.events.Event;
|
||||
import openfl.events.FullScreenEvent;
|
||||
#if macro
|
||||
import haxe.macro.Compiler;
|
||||
import haxe.macro.Context;
|
||||
import haxe.macro.Expr;
|
||||
#end
|
||||
|
||||
|
||||
@:access(lime.app.Application)
|
||||
@:access(lime.system.System)
|
||||
@:access(openfl.display.Stage)
|
||||
@:access(openfl.events.UncaughtErrorEvents)
|
||||
class ApplicationMain {
|
||||
public static function main() {
|
||||
lime.system.System.__registerEntryPoint("src/DocumentClass.hx", create);
|
||||
@:dox(hide)
|
||||
class ApplicationMain
|
||||
{
|
||||
#if !macro
|
||||
public static function main()
|
||||
{
|
||||
lime.system.System.__registerEntryPoint("MinimalApplication", create);
|
||||
|
||||
#if (js && html5)
|
||||
#if (munit || (utest && openfl_enable_utest_legacy_mode))
|
||||
lime.system.System.embed("MinimalApplication", null, 800, 600);
|
||||
#end
|
||||
#else
|
||||
create(null);
|
||||
#end
|
||||
}
|
||||
|
||||
// public static function create(config):Void {
|
||||
// try {
|
||||
// trace("Creating minimal application");
|
||||
// var app = new Application();
|
||||
|
||||
// // Initialize assets via macro-generated code
|
||||
// Assets.initializeAssets();
|
||||
// trace("Assets initialized");
|
||||
|
||||
// // Minimal metadata
|
||||
// app.meta["name"] = "Debug Application";
|
||||
|
||||
// // Simple window
|
||||
// var attributes:WindowAttributes = {
|
||||
// height: 600,
|
||||
// width: 800,
|
||||
// title: "Debug Window"
|
||||
// };
|
||||
|
||||
// app.createWindow(attributes);
|
||||
|
||||
// // Skip preloader, just call start directly
|
||||
// start(app.window.stage);
|
||||
|
||||
// var result = app.exec();
|
||||
// lime.system.System.exit(result);
|
||||
// } catch (e:Dynamic) {
|
||||
// trace("Error: " + e);
|
||||
// }
|
||||
// }
|
||||
|
||||
public static function create(config):Void
|
||||
{
|
||||
var app = new Application();
|
||||
app.meta["build"] = "1.0.0"; // Replace with actual build number
|
||||
app.meta["company"] = "Your Company"; // Replace with your company name
|
||||
app.meta["file"] = "src/Main.hx"; // Path to your main application file
|
||||
app.meta["name"] = "Your Application"; // Replace with your application title
|
||||
app.meta["packageName"] = "com.yourcompany.yourapp"; // Replace with your package name
|
||||
app.meta["version"] = "1.0.0"; // Replace with your application version
|
||||
// var asset = new Asset();
|
||||
// asset.sourcePath = "src/assets"; // Path to your assets
|
||||
// asset.targetPath = "assets"; // Target path for assets
|
||||
// asset.type = AssetType.IMAGE; // Type of asset
|
||||
if (config.hxtelemetry != null)
|
||||
{
|
||||
app.meta["hxtelemetry-allocations"] = config.hxtelemetry.allocations;
|
||||
app.meta["hxtelemetry-host"] = config.hxtelemetry.host;
|
||||
}
|
||||
var attributes:WindowAttributes = {
|
||||
allowHighDPI: true, // Set to true or false as needed
|
||||
alwaysOnTop: false, // Set to true or false as needed
|
||||
borderless: false, // Set to true or false as needed
|
||||
frameRate: 60, // Set your desired frame rate
|
||||
height: 600, // Set your desired window height
|
||||
hidden: false, // Set to true or false as needed
|
||||
maximized: false, // Set to true or false as needed
|
||||
minimized: false, // Set to true or false as needed
|
||||
resizable: true, // Set to true or false as needed
|
||||
title: "Your Application", // Replace with your application title
|
||||
width: 800, // Set your desired window width
|
||||
x: 100, // Set your desired x position
|
||||
y: 100 // Set your desired y position
|
||||
};
|
||||
app.createWindow(attributes);
|
||||
var preloader = getPreloader();
|
||||
app.preloader.onProgress.add(function(loaded, total)
|
||||
{
|
||||
@:privateAccess preloader.update(loaded, total);
|
||||
});
|
||||
app.preloader.onComplete.add(function()
|
||||
{
|
||||
@:privateAccess preloader.start();
|
||||
});
|
||||
preloader.onComplete.add(start.bind(app.window.stage));
|
||||
app.preloader.load();
|
||||
var result = app.exec();
|
||||
lime.system.System.exit(result);
|
||||
var app = new openfl.display.Application();
|
||||
|
||||
#if !disable_preloader_assets
|
||||
ManifestResources.init(config);
|
||||
#end
|
||||
|
||||
app.meta["build"] = "48";
|
||||
app.meta["company"] = "Company Name";
|
||||
app.meta["file"] = "MinimalApplication";
|
||||
app.meta["name"] = "MinimalApplication";
|
||||
app.meta["packageName"] = "com.sample.minimalapplication";
|
||||
app.meta["version"] = "1.0.0";
|
||||
|
||||
|
||||
|
||||
#if !flash
|
||||
|
||||
var attributes:lime.ui.WindowAttributes = {
|
||||
allowHighDPI: false,
|
||||
alwaysOnTop: false,
|
||||
borderless: false,
|
||||
// display: 0,
|
||||
element: null,
|
||||
frameRate: 30,
|
||||
#if !web fullscreen: false, #end
|
||||
height: 600,
|
||||
hidden: #if munit true #else false #end,
|
||||
maximized: false,
|
||||
minimized: false,
|
||||
parameters: {},
|
||||
resizable: true,
|
||||
title: "MinimalApplication",
|
||||
width: 800,
|
||||
x: null,
|
||||
y: null,
|
||||
};
|
||||
|
||||
attributes.context = {
|
||||
antialiasing: 0,
|
||||
background: 16777215,
|
||||
colorDepth: 32,
|
||||
depth: true,
|
||||
hardware: true,
|
||||
stencil: true,
|
||||
type: null,
|
||||
vsync: false
|
||||
};
|
||||
|
||||
if (app.window == null)
|
||||
{
|
||||
if (config != null)
|
||||
{
|
||||
for (field in Reflect.fields(config))
|
||||
{
|
||||
if (Reflect.hasField(attributes, field))
|
||||
{
|
||||
Reflect.setField(attributes, field, Reflect.field(config, field));
|
||||
}
|
||||
else if (Reflect.hasField(attributes.context, field))
|
||||
{
|
||||
Reflect.setField(attributes.context, field, Reflect.field(config, field));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if sys
|
||||
lime.system.System.__parseArguments(attributes);
|
||||
#end
|
||||
}
|
||||
|
||||
app.createWindow(attributes);
|
||||
|
||||
#elseif air
|
||||
app.window.title = "MinimalApplication";
|
||||
#else
|
||||
app.window.context.attributes.background = 16777215;
|
||||
app.window.frameRate = 30;
|
||||
#end
|
||||
|
||||
var preloader = getPreloader();
|
||||
app.preloader.onProgress.add (function(loaded, total)
|
||||
{
|
||||
@:privateAccess preloader.update(loaded, total);
|
||||
});
|
||||
app.preloader.onComplete.add(function()
|
||||
{
|
||||
@:privateAccess preloader.start();
|
||||
});
|
||||
|
||||
preloader.onComplete.add(start.bind((cast app.window:openfl.display.Window).stage));
|
||||
|
||||
#if !disable_preloader_assets
|
||||
for (library in ManifestResources.preloadLibraries)
|
||||
{
|
||||
app.preloader.addLibrary(library);
|
||||
}
|
||||
|
||||
for (name in ManifestResources.preloadLibraryNames)
|
||||
{
|
||||
app.preloader.addLibraryName(name);
|
||||
}
|
||||
#end
|
||||
|
||||
app.preloader.load();
|
||||
|
||||
var result = app.exec();
|
||||
|
||||
#if (sys && !ios && !nodejs && !emscripten)
|
||||
lime.system.System.exit(result);
|
||||
#end
|
||||
}
|
||||
|
||||
public static function start(stage:Stage):Void {
|
||||
if (stage.__uncaughtErrorEvents.__enabled) {
|
||||
try {
|
||||
// Instantiate and add DocumentClass
|
||||
var documentClass = new DocumentClass();
|
||||
Lib.current.addChild(documentClass);
|
||||
|
||||
public static function start(stage:openfl.display.Stage):Void
|
||||
{
|
||||
#if flash
|
||||
ApplicationMain.getEntryPoint();
|
||||
#else
|
||||
if (stage.__uncaughtErrorEvents.__enabled)
|
||||
{
|
||||
try
|
||||
{
|
||||
ApplicationMain.getEntryPoint();
|
||||
|
||||
// Then dispatch events
|
||||
stage.dispatchEvent(new Event(Event.RESIZE, false, false));
|
||||
if (stage.window.fullscreen) {
|
||||
stage.dispatchEvent(new FullScreenEvent(FullScreenEvent.FULL_SCREEN, false, false, true, true));
|
||||
stage.dispatchEvent(new openfl.events.Event(openfl.events.Event.RESIZE, false, false));
|
||||
|
||||
if (stage.window.fullscreen)
|
||||
{
|
||||
stage.dispatchEvent(new openfl.events.FullScreenEvent(openfl.events.FullScreenEvent.FULL_SCREEN, false, false, true, true));
|
||||
}
|
||||
} catch (e:Dynamic) {
|
||||
stage.__handleError(e);
|
||||
}
|
||||
} else {
|
||||
// Instantiate and add DocumentClass
|
||||
var documentClass = new DocumentClass();
|
||||
Lib.current.addChild(documentClass);
|
||||
|
||||
|
||||
// Then dispatch events
|
||||
stage.dispatchEvent(new Event(Event.RESIZE, false, false));
|
||||
if (stage.window.fullscreen) {
|
||||
stage.dispatchEvent(new FullScreenEvent(FullScreenEvent.FULL_SCREEN, false, false, true, true));
|
||||
catch (e:Dynamic)
|
||||
{
|
||||
#if !display
|
||||
stage.__handleError(e);
|
||||
#end
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ApplicationMain.getEntryPoint();
|
||||
|
||||
stage.dispatchEvent(new openfl.events.Event(openfl.events.Event.RESIZE, false, false));
|
||||
|
||||
if (stage.window.fullscreen)
|
||||
{
|
||||
stage.dispatchEvent(new openfl.events.FullScreenEvent(openfl.events.FullScreenEvent.FULL_SCREEN, false, false, true, true));
|
||||
}
|
||||
}
|
||||
#end
|
||||
}
|
||||
#end
|
||||
|
||||
macro public static function getEntryPoint()
|
||||
{
|
||||
var hasMain = false;
|
||||
|
||||
switch (Context.follow(Context.getType("Main")))
|
||||
{
|
||||
case TInst(t, params):
|
||||
|
||||
var type = t.get();
|
||||
for (method in type.statics.get())
|
||||
{
|
||||
if (method.name == "main")
|
||||
{
|
||||
hasMain = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasMain)
|
||||
{
|
||||
return Context.parse("@:privateAccess Main.main()", Context.currentPos());
|
||||
}
|
||||
else if (type.constructor != null)
|
||||
{
|
||||
return macro
|
||||
{
|
||||
var current = stage.getChildAt (0);
|
||||
|
||||
if (current == null || !(current is openfl.display.DisplayObjectContainer))
|
||||
{
|
||||
current = new openfl.display.MovieClip();
|
||||
stage.addChild(current);
|
||||
}
|
||||
|
||||
new DocumentClass(cast current);
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.fatalError("Main class \"Main\" has neither a static main nor a constructor.", Context.currentPos());
|
||||
}
|
||||
|
||||
default:
|
||||
|
||||
Context.fatalError("Main class \"Main\" isn't a class.", Context.currentPos());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function getPreloader() {
|
||||
return new openfl.display.Preloader();
|
||||
macro public static function getPreloader()
|
||||
{
|
||||
|
||||
return macro
|
||||
{
|
||||
new openfl.display.Preloader(new openfl.display.Preloader.DefaultPreloader());
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#if !macro
|
||||
@:noCompletion @:dox(hide) public static function __init__()
|
||||
{
|
||||
var init = lime.app.Application;
|
||||
|
||||
#if neko
|
||||
// Copy from https://github.com/HaxeFoundation/haxe/blob/development/std/neko/_std/Sys.hx#L164
|
||||
// since Sys.programPath () isn't available in __init__
|
||||
var sys_program_path = {
|
||||
var m = neko.vm.Module.local().name;
|
||||
try
|
||||
{
|
||||
sys.FileSystem.fullPath(m);
|
||||
}
|
||||
catch (e:Dynamic)
|
||||
{
|
||||
// maybe the neko module name was supplied without .n extension...
|
||||
if (!StringTools.endsWith(m, ".n"))
|
||||
{
|
||||
try
|
||||
{
|
||||
sys.FileSystem.fullPath(m + ".n");
|
||||
}
|
||||
catch (e:Dynamic)
|
||||
{
|
||||
m;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var loader = new neko.vm.Loader(untyped $loader);
|
||||
loader.addPath(haxe.io.Path.directory(#if (haxe_ver >= 3.3) sys_program_path #else Sys.executablePath() #end));
|
||||
loader.addPath("./");
|
||||
loader.addPath("@executable_path/");
|
||||
#end
|
||||
}
|
||||
#end
|
||||
}
|
||||
|
||||
#if !macro
|
||||
@:build(DocumentClass.build())
|
||||
@:keep @:dox(hide) class DocumentClass extends Main {}
|
||||
#else
|
||||
class DocumentClass
|
||||
{
|
||||
macro public static function build():Array<Field>
|
||||
{
|
||||
var classType = Context.getLocalClass().get();
|
||||
var searchTypes = classType;
|
||||
|
||||
while (searchTypes != null)
|
||||
{
|
||||
if (searchTypes.module == "openfl.display.DisplayObject" || searchTypes.module == "flash.display.DisplayObject")
|
||||
{
|
||||
var fields = Context.getBuildFields();
|
||||
|
||||
var method = macro
|
||||
{
|
||||
current.addChild(this);
|
||||
super();
|
||||
dispatchEvent(new openfl.events.Event(openfl.events.Event.ADDED_TO_STAGE, false, false));
|
||||
}
|
||||
|
||||
fields.push({ name: "new", access: [ APublic ], kind: FFun({ args: [ { name: "current", opt: false, type: macro :openfl.display.DisplayObjectContainer, value: null } ], expr: method, params: [], ret: macro :Void }), pos: Context.currentPos() });
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
if (searchTypes.superClass != null)
|
||||
{
|
||||
searchTypes = searchTypes.superClass.t.get();
|
||||
}
|
||||
else
|
||||
{
|
||||
searchTypes = null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
@@ -1,8 +1,29 @@
|
||||
package;
|
||||
|
||||
class Assets{
|
||||
|
||||
/**
|
||||
* Asset definition class using meta tags instead of project.xml
|
||||
* The AssetMacro will process these declarations at compile time
|
||||
*/
|
||||
@:keep
|
||||
@:build(macros.AssetMacro.build()) // Fix: use fully qualified path with package name
|
||||
class Assets {
|
||||
// Define image assets
|
||||
@:Assets("assets/images/", "images")
|
||||
public static var images:String;
|
||||
|
||||
|
||||
|
||||
// Define sound assets
|
||||
@:Assets("assets/sounds/", "sounds")
|
||||
public static var sounds:String;
|
||||
|
||||
// Define font assets
|
||||
@:Assets("assets/fonts/", "fonts")
|
||||
public static var fonts:String;
|
||||
|
||||
// Define data assets
|
||||
@:Assets("assets/data/", "data")
|
||||
public static var data:String;
|
||||
|
||||
// You can also define individual files if needed
|
||||
@:Assets("assets/images/logo.png", "images", "logo.png")
|
||||
public static var logo:String;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package;
|
||||
|
||||
import openfl.events.EventDispatcher;
|
||||
import openfl.display.Sprite;
|
||||
import openfl.events.Event;
|
||||
import openfl.display.DisplayObjectContainer;
|
||||
import openfl.events.MouseEvent;
|
||||
|
||||
class DocumentClass extends Sprite
|
||||
{
|
||||
public function new()
|
||||
{
|
||||
super();
|
||||
dispatchEvent(new openfl.events.Event(openfl.events.Event.ADDED_TO_STAGE, false, false));
|
||||
graphics.beginFill(0xFFF00F, 1);
|
||||
graphics.drawRect(0, 0, 800, 600);
|
||||
graphics.endFill();
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,22 @@
|
||||
package;
|
||||
|
||||
import openfl.utils.AssetType;
|
||||
import openfl.display.Sprite;
|
||||
import openfl.Assets;
|
||||
import openfl.Lib;
|
||||
import sys.FileSystem;
|
||||
import Assets;
|
||||
|
||||
class Main extends Sprite {
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
|
||||
Lib.current.addChild(this);
|
||||
|
||||
// Draw background to verify app is running
|
||||
graphics.beginFill(0x3498db, 1);
|
||||
graphics.drawRect(0, 0, 800, 600);
|
||||
graphics.endFill();
|
||||
|
||||
var testAsset = Assets.getText("assets/data/img/placeholder.txt");
|
||||
trace(testAsset);
|
||||
|
||||
var testAsset = openfl.Assets.getText("img/placeholder.txt");
|
||||
trace("Successfully loaded asset: " + testAsset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,118 +1,40 @@
|
||||
package;
|
||||
|
||||
import haxe.io.Bytes;
|
||||
import haxe.io.Path;
|
||||
import lime.utils.AssetBundle;
|
||||
import lime.utils.AssetLibrary;
|
||||
import lime.utils.AssetManifest;
|
||||
import lime.utils.Assets;
|
||||
|
||||
#if sys
|
||||
import lime.utils.Assets as LimeAssets;
|
||||
import sys.FileSystem;
|
||||
#end
|
||||
|
||||
#if disable_preloader_assets
|
||||
@:dox(hide) class ManifestResources {
|
||||
public static var preloadLibraries:Array<Dynamic>;
|
||||
public static var preloadLibraryNames:Array<String>;
|
||||
public static var rootPath:String;
|
||||
|
||||
public static function init (config:Dynamic):Void {
|
||||
preloadLibraries = new Array ();
|
||||
preloadLibraryNames = new Array ();
|
||||
}
|
||||
}
|
||||
#else
|
||||
@:access(lime.utils.Assets)
|
||||
@:keep class ManifestResources {
|
||||
public static var preloadLibraries:Array<AssetLibrary> = [];
|
||||
public static var preloadLibraryNames:Array<String> = [];
|
||||
public static var rootPath:String;
|
||||
|
||||
public static function init(config:Dynamic):Void {
|
||||
rootPath = "";
|
||||
|
||||
@:keep @:dox(hide) class ManifestResources {
|
||||
#if sys
|
||||
var manifestPath = Path.join(["manifest", "data.json"]);
|
||||
if (!FileSystem.exists(manifestPath)) {
|
||||
trace("Manifest file not found: " + manifestPath);
|
||||
return;
|
||||
}
|
||||
#end
|
||||
|
||||
|
||||
public static var preloadLibraries:Array<AssetLibrary>;
|
||||
public static var preloadLibraryNames:Array<String>;
|
||||
public static var rootPath:String;
|
||||
|
||||
|
||||
public static function init (config:Dynamic):Void {
|
||||
|
||||
preloadLibraries = new Array ();
|
||||
preloadLibraryNames = new Array ();
|
||||
|
||||
rootPath = null;
|
||||
|
||||
if (config != null && Reflect.hasField (config, "rootPath")) {
|
||||
|
||||
rootPath = Reflect.field (config, "rootPath");
|
||||
|
||||
if(!StringTools.endsWith (rootPath, "/")) {
|
||||
|
||||
rootPath += "/";
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (rootPath == null) {
|
||||
|
||||
#if (ios || tvos || webassembly)
|
||||
rootPath = "assets/";
|
||||
#elseif android
|
||||
rootPath = "";
|
||||
#elseif (console || sys)
|
||||
rootPath = lime.system.System.applicationDirectory;
|
||||
#else
|
||||
rootPath = "./";
|
||||
#end
|
||||
|
||||
}
|
||||
|
||||
#if (openfl && !flash && !display)
|
||||
|
||||
#end
|
||||
|
||||
var data, manifest, library, bundle;
|
||||
|
||||
Assets.libraryPaths["default"] = rootPath + "manifest/default.json";
|
||||
|
||||
|
||||
library = Assets.getLibrary ("default");
|
||||
if (library != null) preloadLibraries.push (library);
|
||||
else preloadLibraryNames.push ("default");
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#if !display
|
||||
#if flash
|
||||
|
||||
@:keep @:bind @:noCompletion #if display private #end class __ASSET__assets_data_img_placeholder_txt extends null { }
|
||||
@:keep @:bind @:noCompletion #if display private #end class __ASSET__manifest_default_json extends null { }
|
||||
|
||||
|
||||
#elseif (desktop || cpp)
|
||||
|
||||
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
|
||||
#end
|
||||
|
||||
#if (openfl && !flash)
|
||||
|
||||
#if html5
|
||||
|
||||
#else
|
||||
|
||||
#end
|
||||
|
||||
#end
|
||||
#end
|
||||
|
||||
#end
|
||||
try {
|
||||
var manifest = AssetManifest.fromFile(manifestPath);
|
||||
if (manifest != null) {
|
||||
var library = AssetLibrary.fromManifest(manifest);
|
||||
if (library != null) {
|
||||
preloadLibraries.push(library);
|
||||
preloadLibraryNames.push("default");
|
||||
LimeAssets.registerLibrary("default", library);
|
||||
}
|
||||
}
|
||||
} catch (e:Dynamic) {
|
||||
trace("Error loading asset manifest: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,238 @@
|
||||
package macros;
|
||||
|
||||
class AssetMacro{
|
||||
|
||||
public static function buildAssets(){
|
||||
import haxe.macro.Context;
|
||||
import haxe.macro.Expr;
|
||||
import haxe.macro.Type;
|
||||
import sys.FileSystem;
|
||||
import sys.io.File;
|
||||
import haxe.Json;
|
||||
using StringTools;
|
||||
|
||||
/**
|
||||
* Macro for processing @:Assets meta tags and building asset manifests
|
||||
*/
|
||||
@:keep
|
||||
class AssetMacro {
|
||||
// Track all assets processed
|
||||
private static var assetMap:Map<String, Array<{id:String, path:String, size:Int, type:String}>> = new Map();
|
||||
|
||||
/**
|
||||
* Entry point for the macro - called during compilation
|
||||
*/
|
||||
public static function build():Array<Field> {
|
||||
#if macro
|
||||
Sys.println("AssetMacro.build() called - macro is running");
|
||||
Context.warning("AssetMacro is running", Context.currentPos());
|
||||
#end
|
||||
|
||||
// Get current build context
|
||||
var fields = Context.getBuildFields();
|
||||
var localClass = Context.getLocalClass().get();
|
||||
|
||||
#if macro
|
||||
Sys.println("Processing class: " + localClass.name);
|
||||
#end
|
||||
|
||||
// Get the output directory from build.hxml
|
||||
var outputDir = getOutputDir();
|
||||
var manifestDir = outputDir + "/manifest";
|
||||
var assetsOutputDir = outputDir + "/assets";
|
||||
|
||||
// Create directories if they don't exist
|
||||
createDirectory(manifestDir);
|
||||
createDirectory(assetsOutputDir);
|
||||
|
||||
// Process asset fields
|
||||
for (field in fields) {
|
||||
processField(field, assetsOutputDir);
|
||||
}
|
||||
|
||||
// Build the manifest files
|
||||
buildManifests(manifestDir);
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a field for @:Assets meta
|
||||
*/
|
||||
private static function processField(field:Field, assetsOutputDir:String) {
|
||||
// Look for our custom meta
|
||||
var assetsMeta = findAssetsMeta(field.meta);
|
||||
if (assetsMeta == null) return;
|
||||
|
||||
var params = assetsMeta.params;
|
||||
if (params.length < 2) {
|
||||
Context.error("@:Assets meta requires at least 2 parameters: source path and library name", assetsMeta.pos);
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract parameters
|
||||
var sourcePath = extractString(params[0]);
|
||||
var libraryName = extractString(params[1]);
|
||||
var targetPath = params.length > 2 ? extractString(params[2]) : null;
|
||||
|
||||
// Process directory or single file
|
||||
if (FileSystem.exists(sourcePath)) {
|
||||
if (FileSystem.isDirectory(sourcePath)) {
|
||||
processDirectory(sourcePath, libraryName, assetsOutputDir);
|
||||
} else {
|
||||
processSingleFile(sourcePath, libraryName, targetPath, assetsOutputDir);
|
||||
}
|
||||
} else {
|
||||
Context.warning('Asset source not found: ${sourcePath}', field.pos);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a directory of assets
|
||||
*/
|
||||
private static function processDirectory(sourcePath:String, libraryName:String, assetsOutputDir:String) {
|
||||
if (!sourcePath.endsWith("/")) sourcePath += "/";
|
||||
var targetDir = assetsOutputDir + "/" + libraryName + "/";
|
||||
createDirectory(targetDir);
|
||||
|
||||
function scanDir(path:String, relPath:String = "") {
|
||||
if (!FileSystem.exists(path)) return;
|
||||
|
||||
for (entry in FileSystem.readDirectory(path)) {
|
||||
var fullPath = path + entry;
|
||||
var relAssetPath = relPath + entry;
|
||||
|
||||
if (FileSystem.isDirectory(fullPath)) {
|
||||
var newRelPath = relPath + entry + "/";
|
||||
var newTargetDir = targetDir + newRelPath;
|
||||
createDirectory(newTargetDir);
|
||||
scanDir(fullPath + "/", newRelPath);
|
||||
} else {
|
||||
// Copy file and register in asset map
|
||||
var targetPath = targetDir + relAssetPath;
|
||||
try {
|
||||
File.copy(fullPath, targetPath);
|
||||
|
||||
// Register asset
|
||||
if (!assetMap.exists(libraryName)) {
|
||||
assetMap.set(libraryName, []);
|
||||
}
|
||||
|
||||
assetMap.get(libraryName).push({
|
||||
id: relAssetPath,
|
||||
path: relAssetPath,
|
||||
size: FileSystem.stat(fullPath).size,
|
||||
type: getAssetType(fullPath)
|
||||
});
|
||||
} catch (e) {
|
||||
Context.warning('Failed to copy asset: ${fullPath} -> ${targetPath}. Error: ${e}', Context.currentPos());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scanDir(sourcePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a single file asset
|
||||
*/
|
||||
private static function processSingleFile(sourcePath:String, libraryName:String, targetPath:String, assetsOutputDir:String) {
|
||||
var targetDir = assetsOutputDir + "/" + libraryName + "/";
|
||||
createDirectory(targetDir);
|
||||
|
||||
var fileName = targetPath != null ? targetPath : sourcePath.split("/").pop();
|
||||
var destPath = targetDir + fileName;
|
||||
|
||||
try {
|
||||
File.copy(sourcePath, destPath);
|
||||
|
||||
// Register asset
|
||||
if (!assetMap.exists(libraryName)) {
|
||||
assetMap.set(libraryName, []);
|
||||
}
|
||||
|
||||
assetMap.get(libraryName).push({
|
||||
id: fileName,
|
||||
path: fileName,
|
||||
size: FileSystem.stat(sourcePath).size,
|
||||
type: getAssetType(sourcePath)
|
||||
});
|
||||
} catch (e) {
|
||||
Context.warning('Failed to copy asset: ${sourcePath} -> ${destPath}. Error: ${e}', Context.currentPos());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build manifest JSON files for each library
|
||||
*/
|
||||
private static function buildManifests(manifestDir:String) {
|
||||
for (library in assetMap.keys()) {
|
||||
var assets = assetMap.get(library);
|
||||
var manifest = {
|
||||
name: library,
|
||||
assets: assets,
|
||||
rootPath: "../assets/" + library + "/"
|
||||
};
|
||||
|
||||
var manifestPath = manifestDir + "/" + library + ".json";
|
||||
try {
|
||||
var content = Json.stringify(manifest, null, " ");
|
||||
File.saveContent(manifestPath, content);
|
||||
Context.info('Built manifest: ${manifestPath} with ${assets.length} assets', Context.currentPos());
|
||||
} catch (e) {
|
||||
Context.warning('Failed to write manifest: ${manifestPath}. Error: ${e}', Context.currentPos());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
|
||||
private static function getOutputDir():String {
|
||||
// Try to parse the --cpp argument from the build.hxml
|
||||
var args = Sys.args();
|
||||
for (i in 0...args.length) {
|
||||
if (args[i] == "--cpp" && i < args.length - 1) {
|
||||
return args[i + 1];
|
||||
}
|
||||
}
|
||||
return "bin/cpp"; // Default output directory
|
||||
}
|
||||
|
||||
private static function createDirectory(path:String) {
|
||||
if (!FileSystem.exists(path)) {
|
||||
try {
|
||||
FileSystem.createDirectory(path);
|
||||
} catch (e) {
|
||||
Context.warning('Failed to create directory: ${path}. Error: ${e}', Context.currentPos());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static function findAssetsMeta(metaAccess:Array<MetadataEntry>):MetadataEntry {
|
||||
if (metaAccess == null) return null;
|
||||
|
||||
for (meta in metaAccess) {
|
||||
if (meta.name == ":Assets" || meta.name == "Assets") {
|
||||
return meta;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static function extractString(expr:Expr):String {
|
||||
switch (expr.expr) {
|
||||
case EConst(CString(s)): return s;
|
||||
default: Context.error("Expected string literal", expr.pos);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static function getAssetType(path:String):String {
|
||||
var ext = path.split(".").pop().toLowerCase();
|
||||
return (switch (ext) {
|
||||
case "jpg", "jpeg", "png", "gif", "bmp": "image";
|
||||
case "mp3", "ogg", "wav": "sound";
|
||||
case "ttf", "otf": "font";
|
||||
case "json", "xml", "txt": "text";
|
||||
default: "binary";
|
||||
}).toUpperCase();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user