#include "de_mrbesen_cppplugins_CppPlugin.h" #include "de_mrbesen_cppplugins_CppPlugin_CppListener.h" #include #include //dynamic linking #include //basename #include //thread id #include "libplugin.h" #include "plugin.h" namespace Plugin { jclass CPPPLUGINCLASS; jclass EVENTCLASS; jclass MAPCLASS; jclass LISTENERCLASS; jclass CMDCLASS; jclass BUKKITCLASS; jclass CBSERVERCLASS; jclass CMDMAPCLASS; jclass CMDSENDERCLASS; jfieldID EVENTDATAF; jfieldID EVENTNAMEF; jfieldID PLUGINIDF; jfieldID BUKKITSERVER; jfieldID SERVERCMDMAP; jmethodID MAPGET; jmethodID MAPPUT; jmethodID MAPCLEAR; jmethodID LISTENERCONTR; jmethodID LISTENERSMALLCONTR; jmethodID CMDCONSTR; jmethodID CMDMAPREGISTER; jmethodID CMDSENDERSEND; std::vector plugins; /* void fixcap(JNIEnv* env) { DEB("ensure 1024" ); env->EnsureLocalCapacity(1024); DEB("push frame 1024" ); env->PushLocalFrame(1024); }*/ CppPlugin* getPlugin(JNIEnv* env, jobject thisobj, int id) { //get id if(id < 0) { load(env, JNI_PLUGINIDFIELD); id = env->GetIntField(thisobj, PLUGINIDF); } return plugins.at(id); } void load(JNIEnv* env, long data) { if(data & (JNI_PLUGINCLASS | JNI_PLUGINIDFIELD)) CPPPLUGINCLASS = env->FindClass("de/mrbesen/cppplugins/CppPlugin"); if(data & (JNI_EVENTCLASS | JNI_EVENTDATAFIELD | JNI_EVENTNAMEFIELD)) EVENTCLASS = env->FindClass("de/mrbesen/cppplugins/CppEvent"); if(data & (JNI_MAPCLASS | JNI_MAPCLEARMETH | JNI_MAPGETMETH | JNI_MAPPUTMETH)) MAPCLASS = env->FindClass("java/util/Map"); if(data & (JNI_LISTENERCLASS | JNI_LISTENERCONSTR | JNI_LISTENERSMALLCONSTR)) LISTENERCLASS = env->FindClass("de/mrbesen/cppplugins/CppPlugin$CppListener"); if(data & (JNI_CMDCLASS | JNI_CMDCONSTR)) CMDCLASS = env->FindClass("de/mrbesen/cppplugins/CppPlugin$CppCommand"); if(data & JNI_BUKKITCLASS) BUKKITCLASS = env->FindClass("org/bukkit/Bukkit"); if(data & (JNI_CBSERVERCLASS | JNI_SERVERCMDMAPFIELD)) CBSERVERCLASS = env->FindClass("org/bukkit/craftbukkit/v1_12_R1/CraftServer"); if(data & (JNI_CMDMAPCLASS | JNI_CMDMAPREGISTERMETH)) CMDMAPCLASS = env->FindClass("org/bukkit/command/SimpleCommandMap"); if(data & (JNI_CMDSENDERCLASS | JNI_CMDSENDERSENDMETH)) CMDSENDERCLASS = env->FindClass("org/bukkit/command/CommandSender"); if(data & JNI_EVENTDATAFIELD) EVENTDATAF = env->GetFieldID(EVENTCLASS, "data", "Ljava/util/Map;"); if(data & JNI_EVENTNAMEFIELD) EVENTNAMEF = env->GetFieldID(EVENTCLASS, "name", "Ljava/lang/String;"); if(data & JNI_PLUGINIDFIELD) PLUGINIDF = env->GetFieldID(CPPPLUGINCLASS, "id", "I"); if(data & JNI_BUKKITSERVFIELD) BUKKITSERVER = env->GetStaticFieldID(BUKKITCLASS, "server", "Lorg/bukkit/Server;"); if(data & JNI_SERVERCMDMAPFIELD) SERVERCMDMAP = env->GetFieldID(CBSERVERCLASS, "commandMap", "Lorg/bukkit/command/SimpleCommandMap;"); if(data & JNI_MAPGETMETH) MAPGET = env->GetMethodID(MAPCLASS, "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); if(data & JNI_MAPPUTMETH) MAPPUT = env->GetMethodID(MAPCLASS, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); if(data & JNI_MAPCLEARMETH) MAPCLEAR = env->GetMethodID(MAPCLASS, "clear", "()V"); if(data & JNI_LISTENERCONSTR) LISTENERCONTR = env->GetMethodID(LISTENERCLASS, "", "(Ljava/lang/String;J)V"); if(data & JNI_LISTENERSMALLCONSTR) LISTENERSMALLCONTR = env->GetMethodID(LISTENERCLASS, "", "()V"); if(data & JNI_CMDCONSTR) CMDCONSTR = env->GetMethodID(CMDCLASS, "", "(Ljava/lang/String;JI)V"); if(data & JNI_CMDMAPREGISTERMETH) CMDMAPREGISTER = env->GetMethodID(CMDMAPCLASS, "register", "(Ljava/lang/String;Lorg/bukkit/command/Command;)Z"); if(data & JNI_CMDSENDERSENDMETH) CMDSENDERSEND = env->GetMethodID(CMDSENDERCLASS, "sendMessage", "(Ljava/lang/String;)V"); if(((!CPPPLUGINCLASS) + (!EVENTCLASS) + (!MAPCLASS) + (!LISTENERCLASS) + (!CMDCLASS) + (!BUKKITCLASS) + (!CBSERVERCLASS) + (!CMDMAPCLASS)//wenn eins == nullptr ist -> wird zu 1 -> endergebniss != 0 -> fehler + (!EVENTDATAF) + (!EVENTNAMEF) + (!PLUGINIDF) + (!BUKKITSERVER) + (!SERVERCMDMAP) + (!MAPGET) + (!MAPPUT) + (!MAPCLEAR) + (!LISTENERCONTR) + (!LISTENERSMALLCONTR) + (!CMDCONSTR) + (!CMDMAPREGISTER)) != 0) { DEB(CRED << "Error loading a Java Information:"); DEB("find classes: " << (!!CPPPLUGINCLASS) << (!!EVENTCLASS) << (!!MAPCLASS) << (!!LISTENERCLASS) << (!!CMDCLASS) << (!!BUKKITCLASS) << (!!CBSERVERCLASS) << (!!CMDMAPCLASS)); DEB("find fields: " << (!!EVENTDATAF) << (!!EVENTNAMEF) << (!!PLUGINIDF) << (!!BUKKITSERVER) << (!!SERVERCMDMAP)); DEB("find methods: " << (!!MAPGET) << (!!MAPPUT) << (!!MAPCLEAR) << (!!LISTENERCONTR) << (!!LISTENERSMALLCONTR) << (!!CMDCONSTR) << (!!CMDMAPREGISTER)); } } bool registerCmd(JNIEnv* env, CppPlugin* plugin, std::string& cname, cmdfptr function) { DEB(CYELLOW << "Register Cmd " << CGREEN << cname << CYELLOW << " for " << CGREEN << plugin->name); load(env, JNI_BUKKITCLASS | JNI_SERVERCMDMAPFIELD | JNI_CMDCONSTR | JNI_CMDMAPREGISTERMETH); // create cnd jstring name = env->NewStringUTF(cname.c_str()); jobject cmd = env->NewObject(CMDCLASS, CMDCONSTR, name, reinterpret_cast(function), plugin->id); env->DeleteLocalRef(name); //call register // ((CraftServer) Bukkit.getServer()).getCommandMap().register(fallbackprefix, cmd); jobject jserver = env->GetStaticObjectField(BUKKITCLASS, BUKKITSERVER); jobject cmdmap = env->GetObjectField(jserver, SERVERCMDMAP); jstring fallbackprefix = env->NewStringUTF(plugin->name.c_str()); return env->CallBooleanMethod(cmdmap, CMDMAPREGISTER, fallbackprefix, cmd); } void send(JNIEnv* env, jobject sender, const char* text) { load(env, JNI_CMDSENDERSENDMETH); jstring jtext = env->NewStringUTF(text); env->CallVoidMethod(sender, CMDSENDERSEND, jtext); env->DeleteLocalRef(jtext); } } //namespace JNIEXPORT jboolean JNICALL Java_de_mrbesen_cppplugins_CppPlugin_init_1(JNIEnv* env, jclass pluginclass) { Plugin::load(env, Plugin::JNI_ALL); return true; } /** * Class: de_mrbesen_cppplugins_CppPlugin * Method: loadPlugin * Signature: (Ljava/lang/String;)Z */ JNIEXPORT jboolean JNICALL Java_de_mrbesen_cppplugins_CppPlugin_loadPlugin(JNIEnv* env, jobject thisobj, jstring path) { const char* cpath = env->GetStringUTFChars(path, 0); //open plugin DEB(CBLUE << "open plugin " << cpath); void* handle = dlopen(cpath, RTLD_LAZY); if (!handle) { std::cout << "could not create handle of: " << cpath << " error: " << dlerror() << std::endl; return false; } //throw std::string("Error: plugin could not be opend. ") + dlerror(); //load function pointer Plugin::initfptr initf = (Plugin::initfptr) dlsym(handle, "init"); if(!initf) { std::cout << "Could not find function init: " << dlerror() << std::endl; dlclose(handle); return false; } Plugin::CppPlugin* plugin = initf(); DEB(CGREY << "Initilized"); plugin->handle = handle; //set name / handle id plugin->name = std::string(cpath); plugin->name = plugin->name.substr(plugin->name.rfind('/')+1); DEB(CGREY << "name set"); // add to vector Plugin::plugins.push_back(plugin); int id = Plugin::plugins.size()-1; plugin->id = id; DEB(CGREY << "plugin added to vector"); //store id Plugin::load(env,Plugin:: JNI_ALL); env->SetIntField(thisobj,Plugin:: PLUGINIDF, id); DEB(CGREY << "Internal id set"); return (bool) plugin; // converted to boolean here } /* * Class: de_mrbesen_cppplugins_CppPlugin * Method: onLoad * Signature: ()V */ JNIEXPORT void JNICALL Java_de_mrbesen_cppplugins_CppPlugin_onLoad(JNIEnv* env, jobject thisobj) { DEB(CGREY << "lib::onLoad()"); Plugin::getPlugin(env, thisobj)->onLoad(env); } /* * Class: de_mrbesen_cppplugins_CppPlugin * Method: onEnable_ * Signature: ()V */ JNIEXPORT void JNICALL Java_de_mrbesen_cppplugins_CppPlugin_onEnable_1(JNIEnv* env, jobject thisobj) { DEB(CGREY << "lib::onEnable()"); Plugin::getPlugin(env, thisobj)->onEnable(env); } /* * Class: de_mrbesen_cppplugins_CppPlugin * Method: onDisable_ * Signature: ()V */ JNIEXPORT void JNICALL Java_de_mrbesen_cppplugins_CppPlugin_onDisable_1(JNIEnv* env, jobject thisobj) { //TODO DEB(CGREY << "lib::onDisable()"); Plugin::CppPlugin* plugin = Plugin::getPlugin(env, thisobj); plugin->onDisable(env); dlclose(plugin->handle); } /* * Class: de_mrbesen_cppplugins_CppPlugin * Method: fireEvent * Signature: (Lde/mrbesen/cppplugins/CppEvent;I)Lde/mrbesen/cppplugins/CppEvent; */ JNIEXPORT jobject JNICALL Java_de_mrbesen_cppplugins_CppPlugin_fireEvent(JNIEnv* env, jobject thisobj, jobject jevent, jlong functionid) { DEB(CGREY << "lib::fireEvent()"); if(functionid == 0) { DEB(CRED << "invalid function id"); return jevent; } Plugin::load(env, Plugin::JNI_EVENT | Plugin::JNI_MAP); //cast function Plugin::eventfptr f = reinterpret_cast(functionid); //cast event Plugin::Event event(env, jevent); //get Plugin Plugin::CppPlugin* plugin = Plugin::getPlugin(env, thisobj); //call it try { f(env, plugin, &event); } catch(...) { std::cout << CRED << "Error while processing Event " << event.getName() << " in plugin: " << plugin->name << CRESET << std::endl; return jevent; } //put changed fields back in the jevent event.reapply(env, jevent); return jevent; } /* * Class: de_mrbesen_cppplugins_CppPlugin * Method: onCmd * Signature: (Lorg/bukkit/command/CommandSender;Lorg/bukkit/command/Command;Ljava/lang/String;[Ljava/lang/String;J)Z */ JNIEXPORT jboolean JNICALL Java_de_mrbesen_cppplugins_CppPlugin_onCmd(JNIEnv* env, jclass cppplugin, jobject sender, jobject cmd, jstring label, jobjectArray args, jlong fid, jint pluginid) { if(fid == 0) return false; Plugin::CppPlugin* plugin = Plugin::getPlugin(pluginid); //parse args int argsize = env->GetArrayLength(args); std::vector cargs(argsize); for(int i = 0; i < argsize; i++) { jstring ar = (jstring) env->GetObjectArrayElement(args, i); cargs[i] = env->GetStringUTFChars(ar, 0); } //parse label std::string clabel = env->GetStringUTFChars(label, 0); //call function Plugin::cmdfptr cmdf = reinterpret_cast(fid); bool result = false; try { result = cmdf(env, plugin, sender, cmd, clabel, cargs); } catch(...) { std::cout << CRED << "Error while executing Command " << clabel << " in plugin: " << plugin->name << CRESET << std::endl; return false; } return result; } /* * Class: de_mrbesen_cppplugins_CppPlugin * Method: getListener * Signature: ()[Lde/mrbesen/cppplugins/CppPlugin/CppListener; */ JNIEXPORT jobjectArray JNICALL Java_de_mrbesen_cppplugins_CppPlugin_getListener(JNIEnv* env, jobject thisobj) { Plugin::load(env, Plugin::JNI_LISTENER); //call getEvents std::map events = Plugin::getPlugin(env, thisobj)->getEvents(); DEB(CYELLOW << "found " << events.size() << " Events" ); //create array jobject initial = env->NewObject(Plugin::LISTENERCLASS, Plugin::LISTENERSMALLCONTR); jobjectArray arr = env->NewObjectArray(events.size(), Plugin::LISTENERCLASS, initial); DEB(CGREY << "populate array" ); //populate array int i = 0; for(auto it : events) { //create object jstring eventname = env->NewStringUTF(it.first.c_str()); jobject listener = env->NewObject(Plugin::LISTENERCLASS, Plugin::LISTENERCONTR, eventname, it.second); env->DeleteLocalRef(eventname); //set array env->SetObjectArrayElement(arr, i++, listener); } DEB(CGREY << "Array finished" ); return arr; }