fixed bootstrapping and asset handling
This commit is contained in:
@@ -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