/** * Generates a metatable containing metafunctions for a given object type using the currently * registered {@link LuaObjectMeta}s. * * <p>This method will only generate one metatable per class type; the mapping of already made * metatables will not be cleared at any point during runtime. If a metatable had already been * generated, that metatable is returned. * * <p>It is possible for functions within each object meta to override each other when this method * generates a new metatable. * * <p>If there are no suitable meta objects for the provided object or none of the applicable meta * objects have any metafunctions to register, null is returned. * * @param obj the Object to generate a metatable for * @return the metatable for the given Object */ public static LuaTable generateMetatable(Object obj) { LuaTable copyTable = Lua.METATABLES.get(obj.getClass()); if (copyTable == null && copyTable != Lua.EMPTY_METATABLE) { LuaTable functable = new LuaTable(); Lua.metas.clear(); Lua.META.values().forEach(Lua.metas::add); Lua.PMETA.values().forEach(Lua.metas::add); Lua.metas.forEach( meta -> { if (meta.getTargetObjectClass().isInstance(obj) && meta.getMetatable() != null) { LuaUtil.iterateTable( meta.getMetatable(), vargs -> { functable.set(vargs.arg(1), vargs.arg(2)); }); } }); Lua.metas.forEach( meta -> { meta.postMetaInit(functable); }); if (LuaUtil.getTableSize(functable) > 0) { LuaTable metatable = new LuaTable(); // add the object's metatable functions metatable.set("__index", functable); // add the stuff we do for every metatable GLOBAL_METATABLE .entries() .forEach( entry -> { metatable.set(entry.key, entry.value); }); Lua.METATABLES.put(obj.getClass(), metatable); copyTable = metatable; } else { Lua.METATABLES.put(obj.getClass(), Lua.EMPTY_METATABLE); } } if (copyTable != null && copyTable != Lua.EMPTY_METATABLE) { return LuaUtil.copyTable(copyTable, true); } return null; }
static { metas = new ObjectSet<>(); META = new ObjectMap<>(); PMETA = new ObjectMap<>(); METATABLES = new ObjectMap<>(); GLOBAL_METATABLE = new ObjectMap<>(); EMPTY_METATABLE = new LuaTable(); // Metamethods implementation for all LuaObjectValues. GLOBAL_METATABLE.put( LuaValue.EQ.tojstring(), LuaUtil.asFunction( vargs -> { if (vargs.isnil(2)) { // We'll still get called for nil. Automagically return false for nil. return LuaValue.valueOf(false); } // obj1, us, is guaranteed to be an object value LuaObjectValue<? super Object> obj1 = (LuaObjectValue<? super Object>) vargs.arg(1); LuaValue obj2 = vargs.arg(2); if (obj2 instanceof LuaObjectValue) { return LuaValue.valueOf( obj1.getObject() == ((LuaObjectValue<? super Object>) obj2).getObject()); } return LuaValue.valueOf(false); })); loadMeta(LuaAudioDataMeta.class); loadMeta(LuaAudioMeta.class); loadMeta(LuaAudioPlayableMeta.class); loadMeta(LuaColliderMeta.class); loadMeta(LuaColorMeta.class); loadMeta(LuaDestructibleMeta.class); loadMeta(LuaEnvironmentMeta.class); loadMeta(LuaEventListenerMeta.class); loadMeta(LuaFontMeta.class); loadMeta(LuaIdentifiableMeta.class); loadMeta(LuaInputDataMeta.class); loadMeta(LuaLayerableMeta.class); loadMeta(LuaMusicMeta.class); loadMeta(LuaOverworldControllerMeta.class); loadMeta(LuaPositionableMeta.class); loadMeta(LuaPressDataMeta.class); loadMeta(LuaProcessableMeta.class); loadMeta(LuaRenderableMeta.class); loadMeta(LuaSchedulerMeta.class); loadMeta(LuaSoundDataMeta.class); loadMeta(LuaSoundMeta.class); loadMeta(LuaSpriteMeta.class); loadMeta(LuaSubsystemMeta.class); loadMeta(LuaTextComponentMeta.class); loadMeta(LuaTextMeta.class); loadMeta(LuaTextStyleMeta.class); loadMeta(LuaTransformMeta.class); loadMeta(LuaUIComponentMeta.class); loadMeta(LuaUIControllerMeta.class); loadMeta(LuaUIObjectMeta.class); loadMeta(LuaWorldObjectMeta.class); loadMeta(new LuaWorldRoomMeta(Undertailor.getInstance())); log.info("Finished loading lua object metadata"); log.info("Primary types list: "); Lua.PMETA .values() .forEach( meta -> { log.info(meta.getClass().getSimpleName()); }); }