summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorshennetsind <ind@henn.et>2013-08-04 12:19:25 -0300
committershennetsind <ind@henn.et>2013-08-08 15:07:40 -0300
commit6b9f58446c46877ecfc5fe40847636145acf5af8 (patch)
tree81b71aa95a47e611a5415528cf72efefe0d552b1
parentdefac0ef9714121a872ab48c3f6c4ddd177ae509 (diff)
downloadhercules-6b9f58446c46877ecfc5fe40847636145acf5af8.tar.gz
hercules-6b9f58446c46877ecfc5fe40847636145acf5af8.tar.bz2
hercules-6b9f58446c46877ecfc5fe40847636145acf5af8.tar.xz
hercules-6b9f58446c46877ecfc5fe40847636145acf5af8.zip
HPM Update
- Custom Packet Support - Custom Data Struct Support (currently append-able to map_session_data and socket_data) - Char Server Support - Login Server Support http://hercules.ws/board/topic/1934-hercules-plugin-manager-update/ Documentation will soon be updated in http://hercules.ws/wiki/HPM Signed-off-by: shennetsind <ind@henn.et>
-rw-r--r--src/char/char.c34
-rw-r--r--src/common/HPM.c267
-rw-r--r--src/common/HPM.h32
-rw-r--r--src/common/HPMi.h29
-rw-r--r--src/common/malloc.c7
-rw-r--r--src/common/malloc.h11
-rw-r--r--src/common/socket.c26
-rw-r--r--src/common/socket.h7
-rw-r--r--src/login/account.h2
-rw-r--r--src/login/account_sql.c3
-rw-r--r--src/login/login.c49
-rw-r--r--src/map/HPMmap.c89
-rw-r--r--src/map/HPMmap.h18
-rw-r--r--src/map/Makefile.in4
-rw-r--r--src/map/chrif.c14
-rw-r--r--src/map/clif.c9
-rw-r--r--src/map/map.c5
-rw-r--r--src/map/pc.h3
-rw-r--r--src/map/pc_groups.c1
-rw-r--r--src/map/unit.c11
-rw-r--r--src/plugins/sample.c82
21 files changed, 639 insertions, 64 deletions
diff --git a/src/char/char.c b/src/char/char.c
index b6ea8e2f6..e6e8732db 100644
--- a/src/char/char.c
+++ b/src/char/char.c
@@ -14,6 +14,7 @@
#include "../common/timer.h"
#include "../common/utils.h"
#include "../common/console.h"
+#include "../common/HPM.h"
#include "int_guild.h"
#include "int_homun.h"
#include "int_mercenary.h"
@@ -2150,6 +2151,14 @@ int parse_fromlogin(int fd) {
while(RFIFOREST(fd) >= 2) {
uint16 command = RFIFOW(fd,0);
+
+ if( HPM->packetsc[hpParse_FromLogin] ) {
+ if( (i = HPM->parse_packets(fd,hpParse_FromLogin)) ) {
+ if( i == 1 ) continue;
+ if( i == 2 ) return 0;
+ }
+ }
+
switch( command ) {
// acknowledgement of connect-to-loginserver request
@@ -2704,6 +2713,14 @@ int parse_frommap(int fd)
}
while(RFIFOREST(fd) >= 2) {
+
+ if( HPM->packetsc[hpParse_FromMap] ) {
+ if( (i = HPM->parse_packets(fd,hpParse_FromMap)) ) {
+ if( i == 1 ) continue;
+ if( i == 2 ) return 0;
+ }
+ }
+
switch(RFIFOW(fd,0)) {
case 0x2b0a:
@@ -3752,6 +3769,13 @@ int parse_char(int fd)
//For use in packets that depend on an sd being present [Skotlex]
#define FIFOSD_CHECK(rest) { if(RFIFOREST(fd) < rest) return 0; if (sd==NULL || !sd->auth) { RFIFOSKIP(fd,rest); return 0; } }
+ if( HPM->packetsc[hpParse_Char] ) {
+ if( (i = HPM->parse_packets(fd,hpParse_Char)) ) {
+ if( i == 1 ) continue;
+ if( i == 2 ) return 0;
+ }
+ }
+
cmd = RFIFOW(fd,0);
switch( cmd ) {
@@ -4874,8 +4898,11 @@ int char_config_read(const char* cfgName)
void do_final(void) {
int i;
+
ShowStatus("Terminating...\n");
+ HPM->event(HPET_FINAL);
+
set_all_offline(-1);
set_all_offline_sql();
@@ -4967,6 +4994,11 @@ int do_init(int argc, char **argv) {
auth_db = idb_alloc(DB_OPT_RELEASE_DATA);
online_char_db = idb_alloc(DB_OPT_RELEASE_DATA);
+
+ HPM->share(sql_handle,"sql_handle");
+ HPM->config_read();
+ HPM->event(HPET_INIT);
+
mmo_char_sql_init();
char_read_fame_list(); //Read fame lists.
@@ -5034,5 +5066,7 @@ int do_init(int argc, char **argv) {
runflag = CHARSERVER_ST_RUNNING;
}
+ HPM->event(HPET_READY);
+
return 0;
}
diff --git a/src/common/HPM.c b/src/common/HPM.c
index 53059d224..3b79febd7 100644
--- a/src/common/HPM.c
+++ b/src/common/HPM.c
@@ -22,6 +22,9 @@
#include <unistd.h>
#endif
+struct malloc_interface iMalloc_HPM;
+struct malloc_interface *HPMiMalloc;
+
void hplugin_trigger_event(enum hp_event_types type) {
unsigned int i;
for( i = 0; i < HPM->plugin_count; i++ ) {
@@ -189,12 +192,17 @@ void hplugin_load(const char* filename) {
if( !HPM->populate(plugin,filename) )
return;
-
- if( SERVER_TYPE == SERVER_TYPE_MAP ) {
- plugin->hpi->addCommand = HPM->import_symbol("addCommand");
- plugin->hpi->addScript = HPM->import_symbol("addScript");
- plugin->hpi->addCPCommand = HPM->import_symbol("addCPCommand");
- }
+ /* id */
+ plugin->hpi->pid = plugin->idx;
+ /* core */
+ plugin->hpi->addCPCommand = HPM->import_symbol("addCPCommand");
+ plugin->hpi->addPacket = HPM->import_symbol("addPacket");
+ plugin->hpi->addToSession = HPM->import_symbol("addToSession");
+ plugin->hpi->getFromSession = HPM->import_symbol("getFromSession");
+ plugin->hpi->removeFromSession = HPM->import_symbol("removeFromSession");
+ /* server specific */
+ if( HPM->load_sub )
+ HPM->load_sub(plugin);
plugin->info = info;
plugin->filename = aStrdup(filename);
@@ -209,7 +217,8 @@ void hplugin_unload(struct hplugin* plugin) {
aFree(plugin->filename);
if( plugin->dll )
plugin_close(plugin->dll);
-
+ /* TODO: for manual packet unload */
+ /* - Go thru known packets and unlink any belonging to the plugin being removed */
aFree(plugin);
if( !HPM->off ) {
HPM->plugins[i] = NULL;
@@ -253,11 +262,191 @@ void hplugins_config_read(void) {
if( HPM->plugin_count )
ShowStatus("HPM: There are '"CL_WHITE"%d"CL_RESET"' plugins loaded, type '"CL_WHITE"plugins"CL_RESET"' to list them\n", HPM->plugin_count);
}
+CPCMD(plugins) {
+ if( HPM->plugin_count == 0 ) {
+ ShowInfo("HPC: there are no plugins loaded\n");
+ } else {
+ unsigned int i;
+
+ ShowInfo("HPC: There are '"CL_WHITE"%d"CL_RESET"' plugins loaded\n",HPM->plugin_count);
+
+ for(i = 0; i < HPM->plugin_count; i++) {
+ ShowInfo("HPC: - '"CL_WHITE"%s"CL_RESET"' (%s)\n",HPM->plugins[i]->info->name,HPM->plugins[i]->filename);
+ }
+ }
+}
+
+void hplugins_addToSession(struct socket_data *sess, void *data, unsigned int id, unsigned int type, bool autofree) {
+ struct HPluginData *HPData;
+ unsigned int i;
+
+ for(i = 0; i < sess->hdatac; i++) {
+ if( sess->hdata[i]->pluginID == id && sess->hdata[i]->type == type ) {
+ ShowError("HPM->addToSession:%s: error! attempting to insert duplicate struct of id %u and type %u\n",HPM->pid2name(id),id,type);
+ return;
+ }
+ }
+
+ //HPluginData is always same size, probably better to use the ERS
+ CREATE(HPData, struct HPluginData, 1);
+
+ HPData->pluginID = id;
+ HPData->type = type;
+ HPData->flag.free = autofree ? 1 : 0;
+ HPData->data = data;
+
+ RECREATE(sess->hdata,struct HPluginData *,++sess->hdatac);
+ sess->hdata[sess->hdatac - 1] = HPData;
+}
+void *hplugins_getFromSession(struct socket_data *sess, unsigned int id, unsigned int type) {
+ unsigned int i;
+
+ for(i = 0; i < sess->hdatac; i++) {
+ if( sess->hdata[i]->pluginID == id && sess->hdata[i]->type == type ) {
+ break;
+ }
+ }
+
+ if( i != sess->hdatac )
+ return sess->hdata[i]->data;
+
+ return NULL;
+}
+void hplugins_removeFromSession(struct socket_data *sess, unsigned int id, unsigned int type) {
+ unsigned int i;
+
+ for(i = 0; i < sess->hdatac; i++) {
+ if( sess->hdata[i]->pluginID == id && sess->hdata[i]->type == type ) {
+ break;
+ }
+ }
+
+ if( i != sess->hdatac ) {
+ unsigned int cursor;
+
+ aFree(sess->hdata[i]->data);
+ aFree(sess->hdata[i]);
+ sess->hdata[i] = NULL;
+
+ for(i = 0, cursor = 0; i < sess->hdatac; i++) {
+ if( sess->hdata[i] == NULL )
+ continue;
+ if( i != cursor )
+ sess->hdata[cursor] = sess->hdata[i];
+ cursor++;
+ }
+ sess->hdatac = cursor;
+ }
+
+}
+
+bool hplugins_addpacket(unsigned short cmd, short length,void (*receive) (int fd),unsigned int point,unsigned int pluginID) {
+ struct HPluginPacket *packet;
+ unsigned int i;
+
+ if( point >= hpPHP_MAX ) {
+ ShowError("HPM->addPacket:%s: unknown point '%u' specified for packet 0x%04x (len %d)\n",HPM->pid2name(pluginID),point,cmd,length);
+ return false;
+ }
+
+ for(i = 0; i < HPM->packetsc[point]; i++) {
+ if( HPM->packets[point][i].cmd == cmd ) {
+ ShowError("HPM->addPacket:%s: can't add packet 0x%04x, already in use by '%s'!",HPM->pid2name(pluginID),cmd,HPM->pid2name(HPM->packets[point][i].pluginID));
+ return false;
+ }
+ }
+
+ RECREATE(HPM->packets[point], struct HPluginPacket, ++HPM->packetsc[point]);
+ packet = &HPM->packets[point][HPM->packetsc[point] - 1];
+
+ packet->pluginID = pluginID;
+ packet->cmd = cmd;
+ packet->len = length;
+ packet->receive = receive;
+
+ return true;
+}
+/*
+ 0 = unknown
+ 1 = OK
+ 2 = incomplete
+ */
+unsigned char hplugins_parse_packets(int fd, enum HPluginPacketHookingPoints point) {
+ unsigned int i;
+
+ for(i = 0; i < HPM->packetsc[point]; i++) {
+ if( HPM->packets[point][i].cmd == RFIFOW(fd,0) )
+ break;
+ }
+
+ if( i != HPM->packetsc[point] ) {
+ struct HPluginPacket *packet = &HPM->packets[point][i];
+ short length;
+
+ if( (length = packet->len) == -1 ) {
+ if( (length = RFIFOW(fd, 2)) < (int)RFIFOREST(fd) )
+ return 2;
+ }
+
+ packet->receive(fd);
+ RFIFOSKIP(fd, length);
+ return 1;
+ }
+
+ return 0;
+}
+
+char *hplugins_id2name (unsigned int pid) {
+ unsigned int i;
+
+ for( i = 0; i < HPM->plugin_count; i++ ) {
+ if( HPM->plugins[i]->idx == pid )
+ return HPM->plugins[i]->info->name;
+ }
+
+ return "UnknownPlugin";
+}
+char* HPM_file2ptr(const char *file) {
+ unsigned int i;
+
+ for(i = 0; i < HPM->fnamec; i++) {
+ if( HPM->fnames[i].addr == file )
+ return HPM->fnames[i].name;
+ }
+
+ i = HPM->fnamec;
+
+ /* we handle this memory outside of the server's memory manager because we need it to exist after the memory manager goes down */
+ HPM->fnames = realloc(HPM->fnames,(++HPM->fnamec)*sizeof(struct HPMFileNameCache));
+
+ HPM->fnames[i].addr = file;
+ HPM->fnames[i].name = strdup(file);
+
+ return HPM->fnames[i].name;
+}
+void* HPM_mmalloc(size_t size, const char *file, int line, const char *func) {
+ return iMalloc->malloc(size,HPM_file2ptr(file),line,func);
+}
+void* HPM_calloc(size_t num, size_t size, const char *file, int line, const char *func) {
+ return iMalloc->calloc(num,size,HPM_file2ptr(file),line,func);
+}
+void* HPM_realloc(void *p, size_t size, const char *file, int line, const char *func) {
+ return iMalloc->realloc(p,size,HPM_file2ptr(file),line,func);
+}
+char* HPM_astrdup(const char *p, const char *file, int line, const char *func) {
+ return iMalloc->astrdup(p,HPM_file2ptr(file),line,func);
+}
+
void hplugins_share_defaults(void) {
/* console */
#ifdef CONSOLE_INPUT
HPM->share(console->addCommand,"addCPCommand");
#endif
+ /* our own */
+ HPM->share(hplugins_addpacket,"addPacket");
+ HPM->share(hplugins_addToSession,"addToSession");
+ HPM->share(hplugins_getFromSession,"getFromSession");
+ HPM->share(hplugins_removeFromSession,"removeFromSession");
/* core */
HPM->share(&runflag,"runflag");
HPM->share(arg_v,"arg_v");
@@ -267,15 +456,13 @@ void hplugins_share_defaults(void) {
HPM->share((void*)get_svn_revision,"get_svn_revision");
HPM->share((void*)get_git_hash,"get_git_hash");
HPM->share(DB, "DB");
- HPM->share(iMalloc, "iMalloc");
+ HPM->share(HPMiMalloc, "iMalloc");
/* socket */
HPM->share(RFIFOSKIP,"RFIFOSKIP");
HPM->share(WFIFOSET,"WFIFOSET");
HPM->share(do_close,"do_close");
HPM->share(make_connection,"make_connection");
- HPM->share(session,"session");
- HPM->share(&fd_max,"fd_max");
- HPM->share(addr_,"addr");
+ //session,fd_max and addr_ are shared from within socket.c
/* strlib */
HPM->share(strlib,"strlib");
HPM->share(sv,"sv");
@@ -286,31 +473,34 @@ void hplugins_share_defaults(void) {
HPM->share(iTimer,"iTimer");
}
-CPCMD(plugins) {
- if( HPM->plugin_count == 0 ) {
- ShowInfo("HPC: there are no plugins loaded\n");
- } else {
- unsigned int i;
-
- ShowInfo("HPC: There are '"CL_WHITE"%d"CL_RESET"' plugins loaded\n",HPM->plugin_count);
-
- for(i = 0; i < HPM->plugin_count; i++) {
- ShowInfo("HPC: - '"CL_WHITE"%s"CL_RESET"' (%s)\n",HPM->plugins[i]->info->name,HPM->plugins[i]->filename);
- }
- }
-}
+
void hpm_init(void) {
+ unsigned int i;
+
HPM->symbols = NULL;
HPM->plugins = NULL;
HPM->plugin_count = HPM->symbol_count = 0;
HPM->off = false;
+ memcpy(&iMalloc_HPM, iMalloc, sizeof(struct malloc_interface));
+ HPMiMalloc = &iMalloc_HPM;
+ HPMiMalloc->malloc = HPM_mmalloc;
+ HPMiMalloc->calloc = HPM_calloc;
+ HPMiMalloc->realloc = HPM_realloc;
+ HPMiMalloc->astrdup = HPM_astrdup;
+
sscanf(HPM_VERSION, "%d.%d", &HPM->version[0], &HPM->version[1]);
if( HPM->version[0] == 0 && HPM->version[1] == 0 ) {
ShowError("HPM:init:failed to retrieve HPM version!!\n");
return;
}
+
+ for(i = 0; i < hpPHP_MAX; i++) {
+ HPM->packets[i] = NULL;
+ HPM->packetsc[i] = 0;
+ }
+
HPM->symbol_defaults();
#ifdef CONSOLE_INPUT
@@ -318,7 +508,18 @@ void hpm_init(void) {
#endif
return;
}
-
+void hpm_memdown(void) {
+ unsigned int i;
+
+ /* this memory is handled outside of the server's memory manager and thus cleared after memory manager goes down */
+
+ for( i = 0; i < HPM->fnamec; i++ ) {
+ free(HPM->fnames[i].name);
+ }
+
+ if( HPM->fnames )
+ free(HPM->fnames);
+}
void hpm_final(void) {
unsigned int i;
@@ -337,12 +538,23 @@ void hpm_final(void) {
if( HPM->symbols )
aFree(HPM->symbols);
-
+
+ for( i = 0; i < hpPHP_MAX; i++ ) {
+ if( HPM->packets[i] )
+ aFree(HPM->packets[i]);
+ }
+
+ /* HPM->fnames is cleared after the memory manager goes down */
+ iMalloc->post_shutdown = hpm_memdown;
+
return;
}
void hpm_defaults(void) {
HPM = &HPM_s;
+ HPM->fnames = NULL;
+ HPM->fnamec = 0;
+
HPM->init = hpm_init;
HPM->final = hpm_final;
@@ -358,4 +570,7 @@ void hpm_defaults(void) {
HPM->config_read = hplugins_config_read;
HPM->populate = hplugin_populate;
HPM->symbol_defaults_sub = NULL;
+ HPM->pid2name = hplugins_id2name;
+ HPM->parse_packets = hplugins_parse_packets;
+ HPM->load_sub = NULL;
}
diff --git a/src/common/HPM.h b/src/common/HPM.h
index 10b1f0e79..d2a1308f2 100644
--- a/src/common/HPM.h
+++ b/src/common/HPM.h
@@ -49,6 +49,27 @@ struct hpm_symbol {
void *ptr;
};
+struct HPluginData {
+ unsigned int pluginID;
+ unsigned int type;
+ struct {
+ unsigned int free : 1;
+ } flag;
+ void *data;
+};
+
+struct HPluginPacket {
+ unsigned int pluginID;
+ unsigned short cmd;
+ short len;
+ void (*receive) (int fd);
+};
+
+struct HPMFileNameCache {
+ const char *addr;
+ char *name;
+};
+
/* Hercules Plugin Manager Interface */
struct HPM_interface {
/* vars */
@@ -59,6 +80,12 @@ struct HPM_interface {
unsigned int plugin_count;
struct hpm_symbol **symbols;
unsigned int symbol_count;
+ /* packet hooking points */
+ struct HPluginPacket *packets[hpPHP_MAX];
+ unsigned int packetsc[hpPHP_MAX];
+ /* plugin file ptr caching */
+ struct HPMFileNameCache *fnames;
+ unsigned int fnamec;
/* funcs */
void (*init) (void);
void (*final) (void);
@@ -73,7 +100,10 @@ struct HPM_interface {
void (*symbol_defaults) (void);
void (*config_read) (void);
bool (*populate) (struct hplugin *plugin,const char *filename);
- void (*symbol_defaults_sub) (void);
+ void (*symbol_defaults_sub) (void);//TODO drop
+ char *(*pid2name) (unsigned int pid);
+ unsigned char (*parse_packets) (int fd, enum HPluginPacketHookingPoints point);
+ void (*load_sub) (struct hplugin *plugin);
} HPM_s;
struct HPM_interface *HPM;
diff --git a/src/common/HPMi.h b/src/common/HPMi.h
index 3cdb804e0..5e44b80c7 100644
--- a/src/common/HPMi.h
+++ b/src/common/HPMi.h
@@ -11,6 +11,8 @@
struct script_state;
struct AtCommandInfo;
+struct socket_data;
+struct map_session_data;
#ifdef WIN32
#define HPExport __declspec(dllexport)
@@ -33,7 +35,7 @@ struct AtCommandInfo;
/* after */
#include "../common/showmsg.h"
-#define HPM_VERSION "0.1"
+#define HPM_VERSION "0.2"
struct hplugin_info {
char* name;
@@ -56,12 +58,37 @@ enum hp_event_types {
HPET_MAX,
};
+enum HPluginPacketHookingPoints {
+ hpClif_Parse, /* map-server (client-map) */
+ hpChrif_Parse, /* map-server (char-map) */
+ hpParse_FromMap, /* char-server (map-char) */
+ hpParse_FromLogin, /* char-server (login-char) */
+ hpParse_Char, /* char-server (client-char) */
+ hpParse_FromChar, /* login-server (char-login) */
+ hpParse_Login, /* login-server (client-login) */
+ /* */
+ hpPHP_MAX,
+};
+
/* Hercules Plugin Mananger Include Interface */
HPExport struct HPMi_interface {
+ /* */
+ unsigned int pid;
+ /* */
void (*event[HPET_MAX]) (void);
bool (*addCommand) (char *name, bool (*func)(const int fd, struct map_session_data* sd, const char* command, const char* message,struct AtCommandInfo *info));
bool (*addScript) (char *name, char *args, bool (*func)(struct script_state *st));
void (*addCPCommand) (char *name, CParseFunc func);
+ /* map_session_data */
+ void (*addToMSD) (struct map_session_data *sd, void *data, unsigned int id, unsigned int type, bool autofree);
+ void *(*getFromMSD) (struct map_session_data *sd, unsigned int id, unsigned int type);
+ void (*removeFromMSD) (struct map_session_data *sd, unsigned int id, unsigned int type);
+ /* session[] */
+ void (*addToSession) (struct socket_data *sess, void *data, unsigned int id, unsigned int type, bool autofree);
+ void *(*getFromSession) (struct socket_data *sess, unsigned int id, unsigned int type);
+ void (*removeFromSession) (struct socket_data *sess, unsigned int id, unsigned int type);
+ /* packet */
+ bool (*addPacket) (unsigned short cmd, unsigned short length, void (*receive)(int fd), unsigned int point, unsigned int pluginID);
} HPMi_s;
#ifndef _HPM_H_
HPExport struct HPMi_interface *HPMi;
diff --git a/src/common/malloc.c b/src/common/malloc.c
index d629aa63f..4d2c93b77 100644
--- a/src/common/malloc.c
+++ b/src/common/malloc.c
@@ -11,6 +11,8 @@
#include <string.h>
#include <time.h>
+struct malloc_interface iMalloc_s;
+
////////////// Memory Libraries //////////////////
#if defined(MEMWATCH)
@@ -672,7 +674,7 @@ void memmgr_report (int extra) {
if( extra != 0 )
msize = extra;
-
+
while (block) {
if (block->unit_used) {
int i;
@@ -784,6 +786,8 @@ void malloc_final (void) {
memmgr_final ();
#endif
MEMORY_CHECK();
+ if( iMalloc->post_shutdown )
+ iMalloc->post_shutdown();
}
void malloc_init (void) {
@@ -825,4 +829,5 @@ void malloc_defaults(void) {
iMalloc->astrdup = aStrdup_;
iMalloc->free = aFree_;
#endif
+ iMalloc->post_shutdown = NULL;
}
diff --git a/src/common/malloc.h b/src/common/malloc.h
index 834781905..bc8aa9a20 100644
--- a/src/common/malloc.h
+++ b/src/common/malloc.h
@@ -67,18 +67,21 @@
void malloc_defaults(void);
struct malloc_interface {
+ void (*init) (void);
+ void (*final) (void);
+ /* */
void* (*malloc )(size_t size, const char *file, int line, const char *func);
void* (*calloc )(size_t num, size_t size, const char *file, int line, const char *func);
void* (*realloc )(void *p, size_t size, const char *file, int line, const char *func);
char* (*astrdup )(const char *p, const char *file, int line, const char *func);
void (*free )(void *p, const char *file, int line, const char *func);
-
+ /* */
void (*memory_check)(void);
bool (*verify_ptr)(void* ptr);
size_t (*usage) (void);
- void (*init) (void);
- void (*final) (void);
-} iMalloc_s;
+ /* */
+ void (*post_shutdown) (void);
+};
void memmgr_report (int extra);
diff --git a/src/common/socket.c b/src/common/socket.c
index f6d5849be..4f2e386ec 100644
--- a/src/common/socket.c
+++ b/src/common/socket.c
@@ -9,6 +9,7 @@
#include "../common/showmsg.h"
#include "../common/strlib.h"
#include "../config/core.h"
+#include "../common/HPM.h"
#include "socket.h"
#include <stdio.h>
@@ -239,8 +240,6 @@ static time_t socket_data_last_tick = 0;
// The connection is closed if it goes over the limit.
#define WFIFO_MAX (1*1024*1024)
-struct socket_data* session[FD_SETSIZE];
-
#ifdef SEND_SHORTLIST
int send_shortlist_array[FD_SETSIZE];// we only support FD_SETSIZE sockets, limit the array to that
int send_shortlist_count = 0;// how many fd's are in the shortlist
@@ -594,13 +593,15 @@ static int create_session(int fd, RecvFunc func_recv, SendFunc func_send, ParseF
session[fd]->func_parse = func_parse;
session[fd]->rdata_tick = last_tick;
session[fd]->session_data = NULL;
+ session[fd]->hdata = NULL;
+ session[fd]->hdatac = 0;
return 0;
}
static void delete_session(int fd)
{
- if( session_isValid(fd) )
- {
+ if( session_isValid(fd) ) {
+ unsigned int i;
#ifdef SHOW_SERVER_STATS
socket_data_qi -= session[fd]->rdata_size - session[fd]->rdata_pos;
socket_data_qo -= session[fd]->wdata_size;
@@ -609,6 +610,14 @@ static void delete_session(int fd)
aFree(session[fd]->wdata);
if( session[fd]->session_data )
aFree(session[fd]->session_data);
+ for(i = 0; i < session[fd]->hdatac; i++) {
+ if( session[fd]->hdata[i]->flag.free ) {
+ aFree(session[fd]->hdata[i]->data);
+ aFree(session[fd]->hdata[i]);
+ }
+ }
+ if( session[fd]->hdata )
+ aFree(session[fd]->hdata);
aFree(session[fd]);
session[fd] = NULL;
}
@@ -1214,6 +1223,8 @@ void socket_final(void)
aFree(session[0]->rdata);
aFree(session[0]->wdata);
aFree(session[0]);
+
+ aFree(session);
}
/// Closes a socket.
@@ -1375,6 +1386,8 @@ void socket_init(void)
memset(send_shortlist_set, 0, sizeof(send_shortlist_set));
#endif
+ CREATE(session, struct socket_data *, FD_SETSIZE);
+
socket_config_read(SOCKET_CONF_FILENAME);
// initialise last send-receive tick
@@ -1392,6 +1405,11 @@ void socket_init(void)
#endif
ShowInfo("Server supports up to '"CL_WHITE"%u"CL_RESET"' concurrent connections.\n", rlim_cur);
+
+ /* Hercules Plugin Manager */
+ HPM->share(session,"session");
+ HPM->share(&fd_max,"fd_max");
+ HPM->share(addr_,"addr");
}
bool session_isValid(int fd)
diff --git a/src/common/socket.h b/src/common/socket.h
index 82f8b84c3..0e34da660 100644
--- a/src/common/socket.h
+++ b/src/common/socket.h
@@ -18,6 +18,8 @@
#include <time.h>
+struct HPluginData;
+
#define FIFOSIZE_SERVERLINK 256*1024
// socket I/O macros
@@ -96,6 +98,9 @@ struct socket_data
ParseFunc func_parse;
void* session_data; // stores application-specific data related to the session
+
+ struct HPluginData **hdata;
+ unsigned int hdatac;
};
struct hSockOpt {
@@ -105,7 +110,7 @@ struct hSockOpt {
// Data prototype declaration
-extern struct socket_data* session[FD_SETSIZE];
+struct socket_data **session;
extern int fd_max;
diff --git a/src/login/account.h b/src/login/account.h
index 999c93075..f55e38b0c 100644
--- a/src/login/account.h
+++ b/src/login/account.h
@@ -135,6 +135,6 @@ struct AccountDB
AccountDBIterator* (*iterator)(AccountDB* self);
};
-void account_db_sql_up(AccountDB* self);
+Sql *account_db_sql_up(AccountDB* self);
#endif // __ACCOUNT_H_INCLUDED__
diff --git a/src/login/account_sql.c b/src/login/account_sql.c
index 218248c82..533b3d860 100644
--- a/src/login/account_sql.c
+++ b/src/login/account_sql.c
@@ -687,10 +687,11 @@ static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, boo
return result;
}
-void account_db_sql_up(AccountDB* self) {
+Sql* account_db_sql_up(AccountDB* self) {
AccountDB_SQL* db = (AccountDB_SQL*)self;
Sql_HerculesUpdateCheck(db->accounts);
#ifdef CONSOLE_INPUT
console->setSQL(db->accounts);
#endif
+ return db->accounts;
}
diff --git a/src/login/login.c b/src/login/login.c
index a17faa058..f92f0094d 100644
--- a/src/login/login.c
+++ b/src/login/login.c
@@ -11,6 +11,7 @@
#include "../common/socket.h"
#include "../common/strlib.h"
#include "../common/timer.h"
+#include "../common/HPM.h"
#include "account.h"
#include "ipban.h"
#include "login.h"
@@ -372,12 +373,17 @@ int parse_fromchar(int fd)
ipl = server[id].ip;
ip2str(ipl, ip);
- while( RFIFOREST(fd) >= 2 )
- {
+ while( RFIFOREST(fd) >= 2 ) {
uint16 command = RFIFOW(fd,0);
- switch( command )
- {
+ if( HPM->packetsc[hpParse_FromChar] ) {
+ if( (j = HPM->parse_packets(fd,hpParse_FromChar)) ) {
+ if( j == 1 ) continue;
+ if( j == 2 ) return 0;
+ }
+ }
+
+ switch( command ) {
case 0x2712: // request from char-server to authenticate an account
if( RFIFOREST(fd) < 23 )
@@ -1324,12 +1330,17 @@ int parse_login(int fd)
sd->fd = fd;
}
- while( RFIFOREST(fd) >= 2 )
- {
+ while( RFIFOREST(fd) >= 2 ) {
uint16 command = RFIFOW(fd,0);
- switch( command )
- {
+ if( HPM->packetsc[hpParse_Login] ) {
+ if( (result = HPM->parse_packets(fd,hpParse_Login)) ) {
+ if( result == 1 ) continue;
+ if( result == 2 ) return 0;
+ }
+ }
+
+ switch( command ) {
case 0x0200: // New alive packet: structure: 0x200 <account.userid>.24B. used to verify if client is always alive.
if (RFIFOREST(fd) < 26)
@@ -1688,15 +1699,17 @@ void do_final(void)
int i;
struct client_hash_node *hn = login_config.client_hash_nodes;
- while (hn)
- {
+ ShowStatus("Terminating...\n");
+
+ HPM->event(HPET_FINAL);
+
+ while (hn) {
struct client_hash_node *tmp = hn;
hn = hn->next;
aFree(tmp);
}
login_log(0, "login server", 100, "login server shutdown");
- ShowStatus("Terminating...\n");
if( login_config.log_login )
loginlog_final();
@@ -1770,7 +1783,7 @@ int do_init(int argc, char** argv)
login_lan_config_read((argc > 2) ? argv[2] : LAN_CONF_NAME);
rnd_init();
-
+
for( i = 0; i < ARRAYLENGTH(server); ++i )
chrif_server_init(i);
@@ -1780,7 +1793,7 @@ int do_init(int argc, char** argv)
// initialize static and dynamic ipban system
ipban_init();
-
+
// Online user database init
online_db = idb_alloc(DB_OPT_RELEASE_DATA);
iTimer->add_timer_func_list(waiting_disconnect_timer, "waiting_disconnect_timer");
@@ -1814,6 +1827,10 @@ int do_init(int argc, char** argv)
}
}
+ HPM->share(account_db_sql_up(accounts),"sql_handle");
+ HPM->config_read();
+ HPM->event(HPET_INIT);
+
// server port open & binding
if( (login_fd = make_listen_bind(login_config.login_ip,login_config.login_port)) == -1 ) {
ShowFatalError("Failed to bind to port '"CL_WHITE"%d"CL_RESET"'\n",login_config.login_port);
@@ -1824,11 +1841,11 @@ int do_init(int argc, char** argv)
shutdown_callback = do_shutdown;
runflag = LOGINSERVER_ST_RUNNING;
}
-
- account_db_sql_up(accounts);
ShowStatus("The login-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %u).\n\n", login_config.login_port);
login_log(0, "login server", 100, "login server started");
-
+
+ HPM->event(HPET_READY);
+
return 0;
}
diff --git a/src/map/HPMmap.c b/src/map/HPMmap.c
new file mode 100644
index 000000000..17d72bc98
--- /dev/null
+++ b/src/map/HPMmap.c
@@ -0,0 +1,89 @@
+// Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// See the LICENSE file
+
+#include "../common/cbasetypes.h"
+#include "../common/malloc.h"
+#include "../common/showmsg.h"
+#include "../common/HPM.h"
+
+#include "HPMmap.h"
+#include "pc.h"
+#include "map.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+
+void HPM_map_addToMSD(struct map_session_data *sd, void *data, unsigned int id, unsigned int type, bool autofree) {
+ struct HPluginData *HPData;
+ unsigned int i;
+
+ for(i = 0; i < sd->hdatac; i++) {
+ if( sd->hdata[i]->pluginID == id && sd->hdata[i]->type == type ) {
+ ShowError("HPMi->addToMSD:%s: error! attempting to insert duplicate struct of type %u on '%s'\n",HPM->pid2name(id),type,sd->status.name);
+ return;
+ }
+ }
+
+ CREATE(HPData, struct HPluginData, 1);
+
+ HPData->pluginID = id;
+ HPData->type = type;
+ HPData->flag.free = autofree ? 1 : 0;
+ HPData->data = data;
+
+ RECREATE(sd->hdata,struct HPluginData *,++sd->hdatac);
+ sd->hdata[sd->hdatac - 1] = HPData;
+}
+void *HPM_map_getFromMSD(struct map_session_data *sd, unsigned int id, unsigned int type) {
+ unsigned int i;
+
+ for(i = 0; i < sd->hdatac; i++) {
+ if( sd->hdata[i]->pluginID == id && sd->hdata[i]->type == type ) {
+ break;
+ }
+ }
+
+ if( i != sd->hdatac )
+ return sd->hdata[i]->data;
+
+ return NULL;
+}
+void HPM_map_removeFromMSD(struct map_session_data *sd, unsigned int id, unsigned int type) {
+ unsigned int i;
+
+ for(i = 0; i < sd->hdatac; i++) {
+ if( sd->hdata[i]->pluginID == id && sd->hdata[i]->type == type ) {
+ break;
+ }
+ }
+
+ if( i != sd->hdatac ) {
+ unsigned int cursor;
+
+ aFree(sd->hdata[i]->data);
+ aFree(sd->hdata[i]);
+ sd->hdata[i] = NULL;
+
+ for(i = 0, cursor = 0; i < sd->hdatac; i++) {
+ if( sd->hdata[i] == NULL )
+ continue;
+ if( i != cursor )
+ sd->hdata[cursor] = sd->hdata[i];
+ cursor++;
+ }
+
+ sd->hdatac = cursor;
+ }
+
+}
+void HPM_map_plugin_load_sub(struct hplugin *plugin) {
+ plugin->hpi->addCommand = HPM->import_symbol("addCommand");
+ plugin->hpi->addScript = HPM->import_symbol("addScript");
+ /* */
+ plugin->hpi->addToMSD = HPM->import_symbol("addToMSD");
+ plugin->hpi->getFromMSD = HPM->import_symbol("getFromMSD");
+ plugin->hpi->removeFromMSD = HPM->import_symbol("removeFromMSD");
+}
diff --git a/src/map/HPMmap.h b/src/map/HPMmap.h
new file mode 100644
index 000000000..a6cac4ace
--- /dev/null
+++ b/src/map/HPMmap.h
@@ -0,0 +1,18 @@
+// Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// See the LICENSE file
+
+#ifndef _HPM_MAP_
+#define _HPM_MAP_
+
+#include "../common/cbasetypes.h"
+
+struct hplugin;
+struct map_session_data;
+
+void HPM_map_addToMSD(struct map_session_data *sd, void *data, unsigned int id, unsigned int type, bool autofree);
+void *HPM_map_getFromMSD(struct map_session_data *sd, unsigned int id, unsigned int type);
+void HPM_map_removeFromMSD(struct map_session_data *sd, unsigned int id, unsigned int type);
+
+void HPM_map_plugin_load_sub(struct hplugin *plugin);
+
+#endif /* _HPM_MAP_ */
diff --git a/src/map/Makefile.in b/src/map/Makefile.in
index 70c0cd900..588d19eae 100644
--- a/src/map/Makefile.in
+++ b/src/map/Makefile.in
@@ -17,7 +17,7 @@ MAP_OBJ = map.o chrif.o clif.o pc.o status.o npc.o \
storage.o skill.o atcommand.o battle.o battleground.o \
intif.o trade.o party.o vending.o guild.o pet.o \
log.o mail.o date.o unit.o homunculus.o mercenary.o quest.o instance.o \
- buyingstore.o searchstore.o duel.o pc_groups.o elemental.o irc-bot.o
+ buyingstore.o searchstore.o duel.o pc_groups.o elemental.o irc-bot.o HPMmap.o
MAP_SQL_OBJ = $(MAP_OBJ:%=obj_sql/%) \
obj_sql/mapreg_sql.o
MAP_H = map.h chrif.h clif.h pc.h status.h npc.h \
@@ -27,7 +27,7 @@ MAP_H = map.h chrif.h clif.h pc.h status.h npc.h \
log.h mail.h date.h unit.h homunculus.h mercenary.h quest.h instance.h mapreg.h \
buyingstore.h searchstore.h duel.h pc_groups.h \
../config/core.h ../config/renewal.h ../config/secure.h ../config/const.h \
- ../config/classes/general.h elemental.h packets.h packets_struct.h irc-bot.h
+ ../config/classes/general.h elemental.h packets.h packets_struct.h irc-bot.h HPMmap.h
HAVE_MYSQL=@HAVE_MYSQL@
ifeq ($(HAVE_MYSQL),yes)
diff --git a/src/map/chrif.c b/src/map/chrif.c
index d44ccf721..6b0397b56 100644
--- a/src/map/chrif.c
+++ b/src/map/chrif.c
@@ -10,6 +10,7 @@
#include "../common/showmsg.h"
#include "../common/strlib.h"
#include "../common/ers.h"
+#include "../common/HPM.h"
#include "map.h"
#include "battle.h"
@@ -1396,7 +1397,7 @@ void chrif_skillid2idx(int fd) {
*
*------------------------------------------*/
int chrif_parse(int fd) {
- int packet_len, cmd;
+ int packet_len, cmd, r;
// only process data from the char-server
if ( fd != char_fd ) {
@@ -1421,9 +1422,18 @@ int chrif_parse(int fd) {
}
while ( RFIFOREST(fd) >= 2 ) {
+
+ if( HPM->packetsc[hpChrif_Parse] ) {
+ if( (r = HPM->parse_packets(fd,hpChrif_Parse)) ) {
+ if( r == 1 ) continue;
+ if( r == 2 ) return 0;
+ }
+ }
+
cmd = RFIFOW(fd,0);
+
if (cmd < 0x2af8 || cmd >= 0x2af8 + ARRAYLENGTH(packet_len_table) || packet_len_table[cmd-0x2af8] == 0) {
- int r = intif->parse(fd); // Passed on to the intif
+ r = intif->parse(fd); // Passed on to the intif
if (r == 1) continue; // Treated in intif
if (r == 2) return 0; // Didn't have enough data (len==-1)
diff --git a/src/map/clif.c b/src/map/clif.c
index 44df5b607..7171a48be 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -14,6 +14,7 @@
#include "../common/utils.h"
#include "../common/ers.h"
#include "../common/conf.h"
+#include "../common/HPM.h"
#include "map.h"
#include "chrif.h"
@@ -17621,6 +17622,14 @@ int clif_parse(int fd) {
if (RFIFOREST(fd) < 2)
return 0;
+
+ if( HPM->packetsc[hpClif_Parse] ) {
+ int r;
+ if( (r = HPM->parse_packets(fd,hpClif_Parse)) ) {
+ if( r == 1 ) continue;
+ if( r == 2 ) return 0;
+ }
+ }
if( sd )
parse_cmd_func = sd->parse_cmd_func;
diff --git a/src/map/map.c b/src/map/map.c
index 713577495..5753fbc1d 100644
--- a/src/map/map.c
+++ b/src/map/map.c
@@ -51,6 +51,7 @@
#include "log.h"
#include "mail.h"
#include "irc-bot.h"
+#include "HPMmap.h"
#include <stdio.h>
#include <stdlib.h>
@@ -5172,6 +5173,9 @@ void map_hp_symbols(void) {
/* specific */
HPM->share(atcommand->create,"addCommand");
HPM->share(script->addScript,"addScript");
+ HPM->share(HPM_map_addToMSD,"addToMSD");
+ HPM->share(HPM_map_getFromMSD,"getFromMSD");
+ HPM->share(HPM_map_removeFromMSD,"removeFromMSD");
/* vars */
HPM->share(map,"map");
}
@@ -5379,6 +5383,7 @@ int do_init(int argc, char *argv[])
iTimer->add_timer_func_list(map_removemobs_timer, "map_removemobs_timer");
iTimer->add_timer_interval(iTimer->gettick()+1000, map_freeblock_timer, 0, 0, 60*1000);
+ HPM->load_sub = HPM_map_plugin_load_sub;
HPM->symbol_defaults_sub = map_hp_symbols;
HPM->config_read();
HPM->event(HPET_INIT);
diff --git a/src/map/pc.h b/src/map/pc.h
index 1f1538e1f..c2e834d1c 100644
--- a/src/map/pc.h
+++ b/src/map/pc.h
@@ -507,6 +507,9 @@ struct map_session_data {
unsigned char delayed_damage;//ref. counter bugreport:7307 [Ind/Hercules]
+ struct HPluginData **hdata;
+ unsigned int hdatac;
+
// temporary debugging of bug #3504
const char* delunit_prevfile;
int delunit_prevline;
diff --git a/src/map/pc_groups.c b/src/map/pc_groups.c
index 9ca0fd17a..be02b5f15 100644
--- a/src/map/pc_groups.c
+++ b/src/map/pc_groups.c
@@ -2,6 +2,7 @@
// See the LICENSE file
// Portions Copyright (c) Athena Dev Teams
+#include "../common/cbasetypes.h"
#include "../common/conf.h"
#include "../common/db.h"
#include "../common/malloc.h"
diff --git a/src/map/unit.c b/src/map/unit.c
index 9becb128e..41d661169 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -8,6 +8,7 @@
#include "../common/db.h"
#include "../common/malloc.h"
#include "../common/random.h"
+#include "../common/HPM.h"
#include "map.h"
#include "path.h"
@@ -2330,6 +2331,7 @@ int unit_free(struct block_list *bl, clr_type clrtype)
{
struct map_session_data *sd = (struct map_session_data*)bl;
int i;
+ unsigned int k;
if( iStatus->isdead(bl) )
pc->setrestartvalue(sd,2);
@@ -2397,6 +2399,15 @@ int unit_free(struct block_list *bl, clr_type clrtype)
aFree(sd->queues);
sd->queues = NULL;
}
+
+ for( k = 0; k < sd->hdatac; k++ ) {
+ if( sd->hdata[k]->flag.free ) {
+ aFree(sd->hdata[k]->data);
+ aFree(sd->hdata[k]);
+ }
+ }
+ if( sd->hdata )
+ aFree(sd->hdata);
break;
}
case BL_PET:
diff --git a/src/plugins/sample.c b/src/plugins/sample.c
index 7f7528cb7..4a8402560 100644
--- a/src/plugins/sample.c
+++ b/src/plugins/sample.c
@@ -4,9 +4,15 @@
#include <stdio.h>
#include <string.h>
+#include <stdlib.h>
+
#include "../common/HPMi.h"
+#include "../common/mmo.h"
+#include "../common/socket.h"
+#include "../common/malloc.h"
#include "../map/script.h"
#include "../map/pc.h"
+#include "../map/clif.h"
HPExport struct hplugin_info pinfo = {
"Sample", // Plugin name
@@ -26,18 +32,81 @@ BUILDIN(sample) {//script command 'sample(num);' - 1 param: struct script_state*
CPCMD(sample) {//console command 'sample' - 1 param: char *line
ShowInfo("I'm being run! arg -> '%s'\n",line?line:"NONE");
}
-struct script_interface *script;/* used by script commands */
+struct sample_data_struct {
+ struct point lastMSGPosition;
+ unsigned int someNumber;
+};
+/* sample packet implementation */
+/* cmd 0xf3 - it is a client-server existent id, for clif_parse_GlobalMessage */
+/* in this sample we do nothing and simply redirect */
+void sample_packet0f3(int fd) {
+ struct map_session_data *sd = session[fd]->session_data;
+ struct sample_data_struct *data;
+
+ if( !sd ) return;/* socket didn't fully log-in? this packet shouldn't do anything then! */
+
+ ShowInfo("sample_packet0f3: Hello World! received 0xf3 for '%s', redirecting!\n",sd->status.name);
+
+ /* sample usage of appending data to a socket_data (session[]) entry */
+ if( !(data = HPMi->getFromSession(session[fd],HPMi->pid,0)) ) {
+ CREATE(data,struct sample_data_struct,1);
+
+ data->lastMSGPosition.map = sd->status.last_point.map;
+ data->lastMSGPosition.x = sd->status.last_point.x;
+ data->lastMSGPosition.y = sd->status.last_point.y;
+ data->someNumber = rand()%777;
+
+ ShowInfo("Created Appended session[] data, %d %d %d %d\n",data->lastMSGPosition.map,data->lastMSGPosition.x,data->lastMSGPosition.y,data->someNumber);
+ HPMi->addToSession(session[fd],data,HPMi->pid,0,true);
+ } else {
+ ShowInfo("Existent Appended session[] data, %d %d %d %d\n",data->lastMSGPosition.map,data->lastMSGPosition.x,data->lastMSGPosition.y,data->someNumber);
+ if( rand()%4 == 2 ) {
+ ShowInfo("Removing Appended session[] data\n");
+ HPMi->removeFromSession(session[fd],HPMi->pid,0);
+ }
+ }
+
+ /* sample usage of appending data to a map_session_data (sd) entry */
+ if( !(data = HPMi->getFromMSD(sd,HPMi->pid,0)) ) {
+ CREATE(data,struct sample_data_struct,1);
+
+ data->lastMSGPosition.map = sd->status.last_point.map;
+ data->lastMSGPosition.x = sd->status.last_point.x;
+ data->lastMSGPosition.y = sd->status.last_point.y;
+ data->someNumber = rand()%777;
+
+ ShowInfo("Created Appended map_session_data data, %d %d %d %d\n",data->lastMSGPosition.map,data->lastMSGPosition.x,data->lastMSGPosition.y,data->someNumber);
+ HPMi->addToMSD(sd,data,HPMi->pid,0,true);
+ } else {
+ ShowInfo("Existent Appended map_session_data data, %d %d %d %d\n",data->lastMSGPosition.map,data->lastMSGPosition.x,data->lastMSGPosition.y,data->someNumber);
+ if( rand()%4 == 2 ) {
+ ShowInfo("Removing Appended map_session_data data\n");
+ HPMi->removeFromMSD(sd,HPMi->pid,0);
+ }
+ }
+
+
+ clif->pGlobalMessage(fd,sd);
+}
/* run when server starts */
HPExport void plugin_init (void) {
char *server_type;
char *server_name;
-
- //get the symbols from the server
+
+ /* core vars */
server_type = GET_SYMBOL("SERVER_TYPE");
server_name = GET_SYMBOL("SERVER_NAME");
+ /* core interfaces */
+ iMalloc = GET_SYMBOL("iMalloc");
+
+ /* map-server interfaces */
script = GET_SYMBOL("script");
-
+ clif = GET_SYMBOL("clif");
+
+ /* session[] */
+ session = GET_SYMBOL("session");
+
ShowInfo ("Server type is ");
switch (*server_type) {
@@ -59,6 +128,11 @@ HPExport void plugin_init (void) {
if( HPMi->addCPCommand != NULL ) {//link our 'sample' console command
HPMi->addCPCommand("this:is:a:sample",CPCMD_A(sample));
}
+
+ if( HPMi->addPacket != NULL ) {//link our 'sample' packet to map-server
+ HPMi->addPacket(0xf3,-1,sample_packet0f3,hpClif_Parse,HPMi->pid);
+ }
+
}
/* run when server is ready (online) */
HPExport void server_online (void) {