Skip to content

Instantly share code, notes, and snippets.

@gamedevsam
Last active December 16, 2015 03:59
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gamedevsam/5374314 to your computer and use it in GitHub Desktop.
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.
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