Skip to content

Instantly share code, notes, and snippets.

@dstrekelj
Created March 21, 2016 16:10
Show Gist options
  • Save dstrekelj/c6c4b53a8e0afe91731e to your computer and use it in GitHub Desktop.
Save dstrekelj/c6c4b53a8e0afe91731e to your computer and use it in GitHub Desktop.
Map-creating macro
package;
class Asset
{
public var locale : String;
public var name : String;
public var resource : String;
public var type : String;
public function new(locale : String, name : String, resource : String, type : String)
{
this.locale = locale;
this.name = name;
this.resource = resource;
this.type = type;
}
}
package;
typedef AssetData =
{
var en : AssetLocaleData;
var fr : AssetLocaleData;
}
typedef AssetLocaleData =
{
var html : AssetPlatformData;
var ios : AssetPlatformData;
var android : AssetPlatformData;
}
typedef AssetPlatformData = Array<AssetEntryData>;
typedef AssetEntryData =
{
var name : String;
var type : String;
var resource : String;
var isLoaded : Bool;
}
{
"en": {
"html": [
{
"name": "textureA",
"type": "texture",
"resource": "some_url_to_a_texture.png",
"isLoaded": false
},
{
"name": "meshA",
"type": "mesh",
"resource": "some_url_to_a_texture.fbx",
"isLoaded": false
}
],
"ios": [
{
"name": "textureA",
"type": "texture",
"resource": "some_url_to_a_texture_ios.png",
"isLoaded": false
},
{
"name": "meshA",
"type": "mesh",
"resource": "some_url_to_a_texture_ios.fbx",
"isLoaded": false
}
],
"android": [
{
"name": "textureA",
"type": "texture",
"resource": "some_url_to_a_texture_android.png",
"isLoaded": false
},
{
"name": "meshA",
"type": "mesh",
"resource": "some_url_to_a_texture_android.fbx",
"isLoaded": false
}
]
},
"fr": {
"html": [
{
"name": "textureA",
"type": "texture",
"resource": "some_url_to_a_texture.png",
"isLoaded": false
},
{
"name": "meshA",
"type": "mesh",
"resource": "some_url_to_a_texture.fbx",
"isLoaded": false
}
],
"ios": [
{
"name": "textureA",
"type": "texture",
"resource": "some_url_to_a_texture_ios.png",
"isLoaded": false
},
{
"name": "meshA",
"type": "mesh",
"resource": "some_url_to_a_texture_ios.fbx",
"isLoaded": false
}
],
"android": [
{
"name": "textureA",
"type": "texture",
"resource": "some_url_to_a_texture_android.png",
"isLoaded": false
},
{
"name": "meshA",
"type": "mesh",
"resource": "some_url_to_a_texture_android.fbx",
"isLoaded": false
}
]
}
}
package;
@:build(AssetServiceBuilder.build())
class AssetService
{
}
package;
import haxe.macro.Context;
import haxe.macro.Expr;
import haxe.macro.Type;
using haxe.macro.Tools;
class AssetServiceBuilder
{
public static macro function build() : Array<Field>
{
// The build fields of the class being built
var fields = Context.getBuildFields();
// The asset data we want to store into a map
var assetData : AssetData = haxe.Json.parse(sys.io.File.getContent("res/assets.json"));
// The array of expressions representing the final map of assets
var assets = [];
// We use reflection to iterate through fields of the anonymous object that is assetData
for (locale in Reflect.fields(assetData))
{
// This is akin to assetData[locale] or assetData.locale
var l : AssetData.AssetLocaleData = Reflect.field(assetData, locale);
// The array of expressions representing the internal map of assets per platform
var localAssets = [];
for (platform in Reflect.fields(l))
{
var p : AssetData.AssetPlatformData = Reflect.field(l, platform);
// I'm only looking at the assets for a single platform to avoid duplicate keys
if (platform == "ios")
{
for (entry in p)
{
// Note the use of `macro` and expression reification (`$v{}`)
localAssets.push(macro $v{entry.name} => new Asset($v{locale}, $v{entry.name}, $v{entry.resource}, $v{entry.type}));
}
}
}
// Note the use of `macro` and expression reification (`$a{}`)
assets.push(macro $v{locale} => $a{localAssets});
}
// We "push" (add) a new field to the class
fields.push({
// Think of this as the line position that will be referenced on error
pos: Context.currentPos(),
// Field name
name: "_assets",
// We won't be adding any metadata
meta: null,
// The field will be a variable of the Map<String, Map<String, Asset>> type, and will contain the array of expressions making up a map
kind: FieldType.FVar(macro : Map<String, Map<String, Asset>>, macro $a{assets}),
// We won't be adding any documentation
doc: null,
// We'll give it private visibility
access: [Access.APrivate]
});
// Once the build macro is done it needs to return the context's build fields
return fields;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment