initial, onEnable, onDisable working

This commit is contained in:
mrbesen 2020-02-20 04:28:05 +01:00
commit 4c8cf080e7
Signed by: MrBesen
GPG Key ID: 596B2350DCD67504
17 changed files with 827 additions and 0 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
testserver
*.so
*.class
target
*.jar
.idea/
.vscode/

2
Cppplugin.iml Normal file
View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4" />

30
Makefile Normal file
View File

@ -0,0 +1,30 @@
CXX = g++
CFLAGS = -Wall -pedantic-errors -std=c++17 -g #-O2
SRCDIR = src/main/cpp/src/
BUILDDIR = target/
INCDIR = src/main/cpp/inc/
LDFLAGS = -I/usr/lib/jvm/java-8-openjdk-amd64/include/ -I/usr/lib/jvm/java-8-openjdk-amd64/include/linux/ -I$(INCDIR) -Iinc/
NAME = libplugin.so
SRCFILES = $(wildcard $(SRCDIR)*.cpp)
OBJFILES = $(patsubst $(SRCDIR)%, $(BUILDDIR)%, $(patsubst %.cpp,%.so,$(SRCFILES)))
all: createhfiles $(BUILDDIR)$(NAME)
$(BUILDDIR)%.so: $(SRCDIR)%.cpp $(BUILDDIR)
$(CXX) -fPIC -shared $(CFLAGS) $(SRCDIR)$*.cpp $(LDFLAGS) -o $@
$(BUILDDIR)%: $(SRCDIR)%.cpp $(BUILDDIR)
$(CXX) $(CFLAGS) $(SRCDIR)$*.cpp -o $@
clean:
rm -fr $(BUILDDIR)
$(BUILDDIR):
mkdir -p $@
createhfiles:
rm -fr $(INCDIR)
javah -d $(INCDIR) -classpath target/classes/:$(HOME)/.m2/repository/org/bukkit/craftbukkit/1.7.10-R0.1-SNAPSHOT/craftbukkit-1.7.10-R0.1-SNAPSHOT.jar de.mrbesen.cppplugins.CppPlugin
.phony: createhfiles clean

12
c_cpp_properties.json Normal file
View File

@ -0,0 +1,12 @@
{
"configurations": [
{
"name": "main",
"cppStandard": "c++17",
"cStandard": "c99",
"includePath": ["${myDefaultIncludePath}", "/usr/lib/jvm/java-8-openjdk-amd64/include/", "/usr/lib/jvm/java-8-openjdk-amd64/include/linux/", "inc/"],
"forcedInclude": ["${myDefaultIncludePath}", "/usr/lib/jvm/java-8-openjdk-amd64/include/", "/usr/lib/jvm/java-8-openjdk-amd64/include/linux/"]
}
],
"version": 0
}

11
inc/cppplugin.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
class CppPlugin {
public:
virtual void onLoad() = 0;
virtual void onEnable() = 0;
virtual void onDisable() = 0;
};
typedef CppPlugin* (*initfptr)();

101
pom.xml Normal file
View File

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>de.mrbesen</groupId>
<artifactId>Cppplugin</artifactId>
<version>0.1-SNAPSHOT</version>
<name>Cppplugins</name>
<repositories>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
</repositories>
<build>
<resources>
<resource>
<directory>src/main/res</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>false</minimizeJar>
<shadedClassifierName>final</shadedClassifierName>
<shadedArtifactAttached>true</shadedArtifactAttached>
<artifactSet>
<includes>
<include>de.playftb</include>
</includes>
</artifactSet>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/**</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<!--This adds the Spigot API artifact to the build -->
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.12.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<!--This adds the Bukkit API artifact to the build -->
<!-- Do not include this in the pom.xml file if the Spigot API is already added -->
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.12.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.avaje</groupId>
<artifactId>ebean</artifactId>
<version>2.8.1</version>
</dependency>
</dependencies>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

8
runall.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/bash
mvn package
make -j1 all #that makefile is not paralllizable
mkdir -p testserver/plugins/CppPlugins
cp target/Cppplugin-0.1-SNAPSHOT-final.jar testserver/plugins/
cp target/libplugin.so testserver/plugins/CppPlugins
cd testserver
java -jar spigot-1.12.2.jar

View File

@ -0,0 +1,77 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class de_mrbesen_cppplugins_CppPlugin */
#ifndef _Included_de_mrbesen_cppplugins_CppPlugin
#define _Included_de_mrbesen_cppplugins_CppPlugin
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: de_mrbesen_cppplugins_CppPlugin
* Method: init_
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_de_mrbesen_cppplugins_CppPlugin_init_1
(JNIEnv *, jobject);
/*
* Class: de_mrbesen_cppplugins_CppPlugin
* Method: loadPlugin
* Signature: (Ljava/lang/String;)Z
*/
JNIEXPORT jboolean JNICALL Java_de_mrbesen_cppplugins_CppPlugin_loadPlugin
(JNIEnv *, jobject, jstring);
/*
* Class: de_mrbesen_cppplugins_CppPlugin
* Method: onLoad
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_de_mrbesen_cppplugins_CppPlugin_onLoad
(JNIEnv *, jobject);
/*
* Class: de_mrbesen_cppplugins_CppPlugin
* Method: onEnable_
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_de_mrbesen_cppplugins_CppPlugin_onEnable_1
(JNIEnv *, jobject);
/*
* Class: de_mrbesen_cppplugins_CppPlugin
* Method: onDisable_
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_de_mrbesen_cppplugins_CppPlugin_onDisable_1
(JNIEnv *, jobject);
/*
* 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 *, jobject, jobject, jint);
/*
* 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 *, jobject, jobject, jobject, jstring, jobjectArray);
/*
* Class: de_mrbesen_cppplugins_CppPlugin
* Method: getListener
* Signature: ()[Lde/mrbesen/cppplugins/CppPlugin/CppListener;
*/
JNIEXPORT jobjectArray JNICALL Java_de_mrbesen_cppplugins_CppPlugin_getListener
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,13 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class de_mrbesen_cppplugins_CppPlugin_CppListener */
#ifndef _Included_de_mrbesen_cppplugins_CppPlugin_CppListener
#define _Included_de_mrbesen_cppplugins_CppPlugin_CppListener
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,129 @@
#include "de_mrbesen_cppplugins_CppPlugin.h"
#include "de_mrbesen_cppplugins_CppPlugin_CppListener.h"
#include <iostream>
#include <dlfcn.h> //dynamic linking
#include "cppplugin.h" //plugin definitions
//jfieldID DATAFIELDID = 0;
jclass CPPPLUGINCLASS = 0;
CppPlugin* plugin = 0;
/*
void setData(CppPlugin* d, JNIEnv* env, jobject thisobj) {
std::cout << "set data: " << DATAFIELDID << std::endl;
env->SetLongField(thisobj, DATAFIELDID, reinterpret_cast<jlong>(d));
}
CppPlugin* getData(JNIEnv* env, jobject thisobj) {
std::cout << "get data: " << DATAFIELDID << std::endl;
return reinterpret_cast<CppPlugin*>(env->GetLongField(thisobj, DATAFIELDID));
}*/
JNIEXPORT jboolean JNICALL Java_de_mrbesen_cppplugins_CppPlugin_init_1(JNIEnv* env, jobject thisobj) {
std::cout << "init!! aus cpp!!!" << std::endl;
CPPPLUGINCLASS = env->FindClass("de/mrbesen/cppplugins/CppPlugin");
std::cout << "findclass: " << (!CPPPLUGINCLASS) << std::endl;
//DATAFIELDID = env->GetFieldID(CPPPLUGINCLASS, "data", "J");
//std::cout << "findfield " << (!DATAFIELDID) << std::endl;
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
std::cout << "open plugin " << cpath << std::endl;
void* handle = dlopen(cpath, RTLD_LAZY);
if (!handle)
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" << std::endl;
dlclose(handle);
return false;
}
plugin = initf();
//store data
//setData(data, env, thisobj);
return true;
}
/*
* 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();
}
/*
* 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 event, jint functionid) {
//TODO
return event;
}
/*
* 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) {
jclass clas = env->FindClass("de/mrbesen/cppplugins/CppPlugin/CppListener");
jobjectArray arr = env->NewObjectArray(0, clas, 0);
return arr;
}

View File

@ -0,0 +1,57 @@
package de.mrbesen.cppplugins;
import lombok.RequiredArgsConstructor;
import org.bukkit.event.Event;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
@RequiredArgsConstructor
public class CppEvent {
private final String name;
Map<String, Object> data = new HashMap<>();
public static CppEvent cppify(Event e) {
System.out.println("cppifying event: " + e.getClass().getSimpleName());
CppEvent cppe = new CppEvent(e.getClass().getSimpleName());
for(Field field : e.getClass().getFields()) {
System.out.println("try to read Field: " + field.getName());
if(!field.isAccessible()) field.setAccessible(true);
try {
cppe.data.put(field.getName(), field.get(e));
} catch (IllegalAccessException ex) {
ex.printStackTrace();
}
}
return cppe;
}
public static void uncppify(CppEvent cppe, Event original) {
System.out.println("uncppifying event: " + original.getClass().getSimpleName());
if(!original.getClass().getSimpleName().equals(cppe.name))
throw new IllegalArgumentException("CppEvent does not match original event type!");
for(Field field : original.getClass().getFields()) {
System.out.println("try to set Field: " + field.getName());
if(!field.isAccessible()) field.setAccessible(true);
Object value = cppe.data.get(field.getName());
if(value == null) {
System.out.println("Data not available - skip");
continue;
}
try {
field.set(original, value);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}

View File

@ -0,0 +1,116 @@
package de.mrbesen.cppplugins;
import org.bukkit.Server;
import org.bukkit.event.*;
import org.bukkit.plugin.*;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Pattern;
public class CppLoader implements PluginLoader {
protected Server serv;
public CppLoader(Server serv) {
this.serv = serv;
}
private static final String[] search = {
//"org.bukkit.event",
"", //needed to support event from other plugins
"org.bukkit.event.block.",
"org.bukkit.event.enchantment.",
"org.bukkit.event.entity.",
"org.bukkit.event.hanging.",
"org.bukkit.event.invnetory.",
"org.bukkit.event.painting.",
"org.bukkit.event.player.",
"org.bukkit.event.server.",
"org.bukkit.event.vehicle.",
"org.bukkit.event.weather.",
"org.bukkit.event.world."
};
@Override
public Plugin loadPlugin(File file) throws InvalidPluginException, UnknownDependencyException {
System.out.println("try to load: " + file.getName());
return new CppPlugin(file, this);
}
@Override
public PluginDescriptionFile getPluginDescription(File file) throws InvalidDescriptionException {
return new PluginDescriptionFile(file.getName(), "1.0", CppPlugin.class.getName());
}
@Override
public Pattern[] getPluginFileFilters() {
//only allow .so files
return new Pattern[]{ Pattern.compile(".*\\.so") };
}
@Override
public Map<Class<? extends Event>, Set<RegisteredListener>> createRegisteredListeners(Listener listenerabcdeg, Plugin plugin) {
CppPlugin.CppListener[] listener = ((CppPlugin) plugin).getListener();
Map<Class<? extends Event>, Set<RegisteredListener>> out = new HashMap<>();
Package bukkitevents = Package.getPackage("org.bukkit.event");
for(CppPlugin.CppListener lis : listener) {
//search for Class
Class clas = findClass(lis.eventfilter);
AdapterExecutor adapt = new AdapterExecutor();
Set<RegisteredListener> lisset = out.getOrDefault(clas, new TreeSet<>());
lisset.add(new RegisteredListener(lis, adapt, EventPriority.NORMAL, plugin, true));
if(lisset.size() == 1) //nur wenn neu
out.put(clas, lisset);
}
return out;
}
/**
* simple name of event -> Class of that event
* @param name
* @return
*/
private Class<? extends Event> findClass(String name) {
for(String prefix : search) {
try {
return (Class<? extends Event>) Class.forName(prefix + name);
} catch (ClassNotFoundException e) {}
}
return null;
}
@Override
public void enablePlugin(Plugin plugin) {
plugin.onEnable();
}
@Override
public void disablePlugin(Plugin plugin) {
plugin.onDisable();
}
private class AdapterExecutor implements EventExecutor {
CppPlugin plugin;
int functionid;
@Override
public void execute(Listener listener, Event event) throws EventException {
//cppify event
CppEvent cppe = CppEvent.cppify(event);
cppe = plugin.fireEvent(cppe, functionid);
//uncppify
CppEvent.uncppify(cppe, event);
}
}
}

View File

@ -0,0 +1,172 @@
package de.mrbesen.cppplugins;
import com.avaje.ebean.EbeanServer;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.event.Listener;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginLoader;
import java.io.File;
import java.io.InputStream;
import java.util.List;
import java.util.logging.Logger;
public class CppPlugin implements Plugin {
private boolean enabled = false;
@Getter
private String name;
private static boolean initdone = false;
private CppLoader loader;
private long data; //for JNI, do not remove
//library operations
protected native boolean init_(); //false: failed, true: success
protected native boolean loadPlugin(String path); //false = failed, true: success
//plugin operations
public native void onLoad();
public native void onEnable_();
public native void onDisable_();
protected native CppEvent fireEvent(CppEvent e, int functionid);
protected native boolean onCmd(CommandSender sender, Command cmd, String label, String[] args);
native CppListener[] getListener();
public CppPlugin(File f, CppLoader l) {
loader = l;
this.name = f.getName();
if(!initdone) {
initdone = init();
if(!initdone) {
throw new RuntimeException("Init returned with error");
}
}
if(!loadPlugin(f.getAbsolutePath())) {
throw new RuntimeException("loadPlugin returened with error");
}
}
protected boolean init() {
File folder = CppPlugins.getInstance().getDataFolder();
folder.mkdirs();
String path = folder.getAbsolutePath() + "/libplugin.so";
System.out.println("load library from: " + path);
try {
System.load(path);
System.out.println("run init_()");
return init_();
} catch(UnsatisfiedLinkError e) {
e.printStackTrace();
}
return false;
}
@Override
public void onEnable() {
onEnable_();
enabled = true;
}
@Override
public void onDisable() {
onDisable_();
enabled = false;
}
public PluginDescriptionFile getDescription() {
return new PluginDescriptionFile(name, "1.0", getClass().getName());
}
@Override
public File getDataFolder() {
return null;
}
@Override
public FileConfiguration getConfig() {
return null;
}
@Override
public InputStream getResource(String s) {
return null;
}
@Override
public void saveConfig() {
}
@Override
public void saveDefaultConfig() {
}
@Override
public void saveResource(String s, boolean b) {
}
@Override
public void reloadConfig() {
}
@Override
public PluginLoader getPluginLoader() {
return loader;
}
@Override
public Server getServer() {
return Bukkit.getServer();
}
@Override
public boolean isEnabled() {
return enabled;
}
@Override
public boolean isNaggable() {
return false;
}
@Override
public void setNaggable(boolean b) {
}
@Override
public ChunkGenerator getDefaultWorldGenerator(String s, String s1) {
return null;
}
@Override
public Logger getLogger() {
return null;
}
@Override
public boolean onCommand(CommandSender commandSender, Command command, String s, String[] strings) {
return onCmd(commandSender, command, s, strings);
}
@Override
public List<String> onTabComplete(CommandSender commandSender, Command command, String s, String[] strings) {
return null;
}
public class CppListener implements Listener {
String eventfilter;
int functionid;
}
}

View File

@ -0,0 +1,48 @@
package de.mrbesen.cppplugins;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.plugin.InvalidDescriptionException;
import org.bukkit.plugin.InvalidPluginException;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
public class CppPlugins extends JavaPlugin {
@Getter
private static CppPlugins instance;
public CppPlugins() {
instance = this;
}
@Override
public void onLoad() {
Bukkit.getPluginManager().registerInterface(CppLoader.class);
getLogger().info("registered");
try {
Bukkit.getPluginManager().loadPlugin(new File("plugins/verysimpleplugin.so")); //TODO: do loading in another way
System.out.println("loaded verysimpleplugin.so");
//TODO: trigger onLoad in those Plugins
} catch (InvalidDescriptionException | InvalidPluginException e) {
e.printStackTrace();
}
}
@Override
public void onDisable() {
Plugin[] pls = Bukkit.getPluginManager().getPlugins();
for (int i = 0; i < pls.length; i++) {
Plugin p = pls[i];
if(p.isEnabled()) {
if(p.getPluginLoader().getClass().equals(CppLoader.class)) {
p.getPluginLoader().disablePlugin(p);
}
}
}
}
}

4
src/main/res/plugin.yml Normal file
View File

@ -0,0 +1,4 @@
name: CppPlugins
main: de.mrbesen.cppplugins.CppPlugins
author: MrBesen
version: 0.1

View File

@ -0,0 +1,9 @@
CFLAGS = -Wall -O2 -pedantic-errors -std=c++17 -g
SRCDIR = src/
INCDIR = ../../inc
LDFLAGS = -I/usr/lib/jvm/java-8-openjdk-amd64/include/ -I/usr/lib/jvm/java-8-openjdk-amd64/include/linux/ -I$(INCDIR)
NAME = verysimpleplugin.so
all:
g++ -fPIC -shared $(CFLAGS) $(SRCDIR)*.cpp $(LDFLAGS) -o $(NAME)

View File

@ -0,0 +1,31 @@
#include "cppplugin.h"
#include <iostream>
extern "C" {
class MyPlugin : public CppPlugin {
public:
virtual void onLoad();
virtual void onEnable();
virtual void onDisable();
};
void MyPlugin::onLoad() {
std::cout << "onload();" << std::endl;
}
void MyPlugin::onEnable() {
std::cout << "onEnable();" << std::endl;
}
void MyPlugin::onDisable() {
std::cout << "onDisable();" << std::endl;
}
CppPlugin* init() {
std::cout << "init im plugin!" << std::endl;
return new MyPlugin();
}
}//extern "C"