CppPlugins/src/main/cpp/src/libplugin.cpp

229 lines
6.6 KiB
C++

#include "de_mrbesen_cppplugins_CppPlugin.h"
#include "de_mrbesen_cppplugins_CppPlugin_CppListener.h"
#include <iostream>
#include <dlfcn.h> //dynamic linking
#include <libplugin.h>
JNIEXPORT jboolean JNICALL Java_de_mrbesen_cppplugins_CppPlugin_init_1(JNIEnv* env, jobject thisobj) {
std::cout << "init libplugin loading java references, 1 = good, 0 = bad" << std::endl;
CPPPLUGINCLASS = env->FindClass("de/mrbesen/cppplugins/CppPlugin");
EVENTCLASS = env->FindClass("de/mrbesen/cppplugins/CppEvent");
MAPCLASS = env->FindClass("java/util/Map");
LISTENERCLASS = env->FindClass("de/mrbesen/cppplugins/CppPlugin$CppListener");
std::cout << "find classes: " << (!!CPPPLUGINCLASS) << (!!EVENTCLASS) << (!!MAPCLASS) << (!!LISTENERCLASS) << std::endl;
EVENTDATAF = env->GetFieldID(EVENTCLASS, "data", "Ljava/util/Map;");
EVENTNAMEF = env->GetFieldID(EVENTCLASS, "name", "Ljava/lang/String;");
std::cout << "findfields: " << (!!EVENTDATAF) << (!!EVENTNAMEF) << std::endl;
MAPGET = env->GetMethodID(MAPCLASS, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
MAPPUT = env->GetMethodID(MAPCLASS, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
LISTENERCONTR = env->GetMethodID(LISTENERCLASS, "<init>", "(Ljava/lang/String;J)V");
std::cout << "find methods: " << (!!MAPGET) << (!!MAPPUT) << (!!LISTENERCONTR) << std::endl;
return ((!CPPPLUGINCLASS) + (!EVENTCLASS) + (!MAPCLASS) + (!EVENTDATAF) + (!EVENTNAMEF) + (!MAPGET) + (!MAPPUT) + (!LISTENERCONTR)) == 0; //one nullptr -> inverted to 1 -> ends up at end -> false
}
/**
* 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
std::cout << "open plugin " << cpath << std::endl;
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
initfptr initf = (initfptr) dlsym(handle, "init");
if(!initf) {
std::cout << "Could not find function init: " << dlerror() << std::endl;
dlclose(handle);
return false;
}
plugin = initf();
plugin->handle = handle;
//store data
//setData(data, env, thisobj);
std::cout << "plugin: " << (bool)plugin << std::endl;
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) {
//TODO
std::cout << "lib::onLoad()" << std::endl;
plugin->onLoad();
}
/*
* Class: de_mrbesen_cppplugins_CppPlugin
* Method: onEnable_
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_de_mrbesen_cppplugins_CppPlugin_onEnable_1(JNIEnv* env, jobject thisobj) {
//TODO
std::cout << "lib::onEnable()" << std::endl;
plugin->onEnable();
}
/*
* Class: de_mrbesen_cppplugins_CppPlugin
* Method: onDisable_
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_de_mrbesen_cppplugins_CppPlugin_onDisable_1(JNIEnv* env, jobject thisobj) {
//TODO
std::cout << "lib::onDisable()" << std::endl;
plugin->onDisable();
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) {
std::cout << "lib::fireEvent()" << std::endl;
if(functionid == 0) {
std::cout << "invalid function id" << std::endl;
return jevent;
}
//cast function
eventfptr f = reinterpret_cast<eventfptr>(functionid);
//cast event
Event event(env, jevent);
//call it
f(plugin, &event);
//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;)Z
*/
JNIEXPORT jboolean JNICALL Java_de_mrbesen_cppplugins_CppPlugin_onCmd(JNIEnv* env, jobject thisobj, jobject sender, jobject cmd, jstring label, jobjectArray args) {
//TODO
return false;
}
/*
* 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) {
//call getEvents
std::map<std::string, eventfptr> events;
getEventsfptr getEventsf = (getEventsfptr) dlsym(plugin->handle, "getEvents");
if(getEventsf) {
//only non null
events = getEventsf();
}
//create array
jclass clas = env->FindClass("de/mrbesen/cppplugins/CppPlugin/CppListener");
jobjectArray arr = env->NewObjectArray(events.size(), clas, 0);
//populate array
int i = 0;
for(auto it : events) {
//create object
jstring eventname = env->NewStringUTF(it.first.c_str());
jobject listener = env->NewObject(LISTENERCLASS, LISTENERCONTR, eventname, it.second);
env->DeleteLocalRef(eventname);
//set array
env->SetObjectArrayElement(arr, i++, listener);
}
return arr;
}
///////// EVENTS
jobject Event::getMap(JNIEnv* env) {
return env->GetObjectField(input, EVENTDATAF);
}
const std::string& Event::getName() {
return name;
}
void* Event::getData(JNIEnv* env, const std::string& name) {
std::cout << "Try to access " << name << std::endl;
//search in map
auto it = data.find(name);
if(it == data.end()) {
//search in original object
//construct string
jstring term = env->NewStringUTF(name.c_str());
//call data.get()
jobject map = getMap(env);
jobject content = env->CallObjectMethod(map, MAPGET, term);
//data.insert for next time
data.insert({name, content});
//delete string
env->DeleteLocalRef(term);
} else {
return it->second;
}
return nullptr;
}
void Event::setData(const std::string& name, void* d) {
//just put it in the map
data.insert({name, d});
}
void Event::reapply(JNIEnv* env, jobject jevent) {
jobject map = getMap(env);
for(auto it : data) {
std::cout << "write back to java: " << it.first << std::endl;
jstring key = env->NewStringUTF(it.first.c_str());
env->CallObjectMethod(map, MAPPUT, key, it.second);
env->DeleteLocalRef(key);
}
}
Event::Event(JNIEnv* env, jobject jevent) {
//get name
jstring name = (jstring) env->GetObjectField(jevent, EVENTNAMEF);
this->name = std::string(env->GetStringUTFChars(name, 0));
input = jevent;
}