Last active
December 16, 2015 03:59
-
-
Save gamedevsam/5374314 to your computer and use it in GitHub Desktop.
TomlConfig.hx - An assistant class to HaxeToml that provides an intuitive and type-safe approach to run-time data loading using Haxe Reflection. This class supports reloading of config files at run-time on cpp targets.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package ; | |
import haxe.Utf8; | |
import nme.Assets; | |
// requires haxetoml: https://github.com/raincole/haxetoml | |
import haxetoml.TomlParser; | |
#if cpp | |
import sys.io.File; | |
import sys.FileSystem; | |
#end | |
/** | |
* Sam Batista | |
* @author | |
*/ | |
class TomlConfig | |
{ | |
// list of file names for all configs | |
private static var TOML_CONFIG_FILES = ["Config.toml"]; | |
// path to config | |
private static var CONFIG_PATH = "assets/"; | |
// path to config relative to cpp binaries - REAL_TIME_LOAD | |
private static var CONFIG_PATH_HOT_RELOAD = "../../../../assets/"; | |
// profile duration of configs load, and print the result to the console | |
private static var CONFIG_TIME_LOAD_DURATION = true; | |
//{ PUBLIC | |
// | |
public static function register(obj:Dynamic, ?configName:String):Void | |
{ | |
if (configName == null) | |
{ | |
var objClass = Type.getClass(obj); | |
var className = Type.getClassName(objClass); | |
configName = className.lastIndexOf(".") < 0 ? className : className.substr(className.lastIndexOf(".") + 1); | |
} | |
if(registeredObjects.exists(configName)) | |
registeredObjects.get(configName).push(obj); | |
else | |
registeredObjects.set(configName, [obj]); | |
if (tomlData != null) | |
copyConfigDataToObjects(configName, [obj]); | |
} | |
public static function unregister(obj:Dynamic, ?configName:String):Void | |
{ | |
if (configName == null) | |
{ | |
var objClass = Type.getClass(obj); | |
var className = Type.getClassName(objClass); | |
configName = className.lastIndexOf(".") < 0 ? className : className.substr(className.lastIndexOf(".") + 1); | |
} | |
if(registeredObjects.exists(configName)) | |
registeredObjects.get(configName).remove(obj); | |
} | |
// Config Loading functionality - done every frame if REAL_TIME_EDIT_ASSETS is defined | |
public static function loadConfigs(forceReload:Bool = false):Void | |
{ | |
configModified = false; | |
// Perf Profiling | |
var perfTimer = 0; | |
if(CONFIG_TIME_LOAD_DURATION) | |
perfTimer = nme.Lib.getTimer(); | |
#if(!LOAD_CONFIG_REAL_TIME || neko) | |
if (!loadedConfigsOnce) { // Execute whole block once | |
#end | |
for (c in TOML_CONFIG_FILES) | |
loadConfigFile(c, forceReload, true); | |
#if(!LOAD_CONFIG_REAL_TIME || neko) } #end | |
if (configModified || forceReload) | |
{ | |
// TODO: Notify your game objects configs have been loaded | |
HxEvents.dispatch("configsLoaded"); // HxEvents: https://gist.github.com/crazysam/5370635 | |
// Perf Profiling | |
if (CONFIG_TIME_LOAD_DURATION) | |
{ | |
var configDur = (nme.Lib.getTimer() - perfTimer) / 1000; | |
trace("Config Load Duration = " + configDur); | |
} | |
} | |
loadedConfigsOnce = true; | |
} | |
public static function cleanup():Void | |
{ | |
registeredObjects = new Map(); | |
} | |
//} | |
//{ PRIVATE | |
// | |
private static function loadConfigFile(fileName:String, forceReload:Bool, isToml:Bool):Void | |
{ | |
// Only load config files that were modified if (LOAD_CONFIG_REAL_TIME) is defined | |
#if(LOAD_CONFIG_REAL_TIME && !neko) | |
try | |
{ | |
if (lastModifiedCache.exists(fileName) && !forceReload) | |
{ | |
// Load the asset located in the assets foldier, not the copies within bin folder | |
var lastModified = FileSystem.stat(CONFIG_PATH_HOT_RELOAD + fileName).mtime.getTime(); | |
var cachedModified = lastModifiedCache.get(fileName); | |
if (lastModified != cachedModified) | |
{ | |
parseTomlFile(File.getContent(CONFIG_PATH_HOT_RELOAD + fileName)); | |
lastModifiedCache.set(fileName, lastModified); | |
configModified = true; | |
} | |
} | |
else | |
{ | |
// Load the asset located in the assets foldier, not the copies within bin folder | |
parseTomlFile(File.getContent(CONFIG_PATH_HOT_RELOAD + fileName)); | |
lastModifiedCache.set(fileName, FileSystem.stat(CONFIG_PATH_HOT_RELOAD + fileName).mtime.getTime()); | |
configModified = true; | |
} | |
} | |
catch( ex:Dynamic ) | |
{ | |
FlxG.log("TomlConfig ERROR: Failed to reload '" + fileName + "'"); | |
} | |
#else | |
parseTomlFile(Assets.getText("assets/" + fileName)); | |
configModified = true; | |
#end | |
} | |
private static function parseTomlFile(fileData:String):Void | |
{ | |
var localData = TomlParser.parseString(fileData); | |
var configObjs = Reflect.fields(localData); | |
for (objName in configObjs) | |
{ | |
// store loaded config data in master object | |
Reflect.setField(tomlData, objName, Reflect.field(localData, objName)); | |
if (registeredObjects.exists(objName)) | |
copyConfigDataToObjects(objName, registeredObjects.get(objName)); | |
} | |
} | |
private static function copyConfigDataToObjects(dataType:String, objArr:Array<Dynamic>):Void | |
{ | |
var objData = Reflect.field(tomlData, dataType); | |
var objFields = Reflect.fields(objData); | |
for (obj in objArr) | |
{ | |
for (field in objFields) | |
{ | |
Reflect.setField(obj, field, Reflect.field(objData, field)); | |
} | |
} | |
} | |
private static var tomlData = {}; | |
private static var configModified = false; | |
private static var loadedConfigsOnce = false; | |
private static var registeredObjects:Map <String, Array<Dynamic>> = new Map(); | |
#if(LOAD_CONFIG_REAL_TIME) | |
private static var lastModifiedCache:Map<String, Float> = new Map(); | |
#end | |
//} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment