2020-04-02 23:46:27 +02:00
|
|
|
|
|
|
|
/* vim: set filetype=c ts=8 noexpandtab: */
|
|
|
|
|
|
|
|
#include "common.h"
|
|
|
|
#include <windows.h>
|
|
|
|
#include "io.h"
|
|
|
|
#include "vendor/SDK/amx/amx.h"
|
|
|
|
#include "vendor/SDK/plugincommon.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
typedef void (*logprintf_t)(char* format, ...);
|
|
|
|
logprintf_t logprintf;
|
|
|
|
extern void *pAMXFunctions;
|
|
|
|
|
|
|
|
EXPECT_SIZE(char, 1);
|
|
|
|
EXPECT_SIZE(short, 2);
|
|
|
|
EXPECT_SIZE(int, 4);
|
|
|
|
EXPECT_SIZE(cell, 4);
|
|
|
|
EXPECT_SIZE(float, 4);
|
|
|
|
|
|
|
|
/*in cells*/
|
|
|
|
#define STACK_HEAP_SIZE 1024
|
|
|
|
|
|
|
|
AMX *amx;
|
|
|
|
struct FAKEAMX_DATA {
|
|
|
|
union {
|
|
|
|
cell ascell[144];
|
|
|
|
char aschr[144 * sizeof(cell)];
|
|
|
|
float asflt[144];
|
|
|
|
} a144;
|
|
|
|
cell _stackheap[STACK_HEAP_SIZE];
|
|
|
|
} fakeamx_data;
|
|
|
|
#define basea ((int) &fakeamx_data)
|
|
|
|
#define buf144a ((int) &fakeamx_data.a144 - basea)
|
|
|
|
#define buf144 (fakeamx_data.a144.ascell)
|
|
|
|
#define cbuf144 fakeamx_data.a144.aschr
|
|
|
|
#define fbuf144 fakeamx_data.a144.asflt
|
|
|
|
|
|
|
|
union NCDATA {
|
|
|
|
cell asint[20];
|
|
|
|
float asflt[20];
|
|
|
|
} nc_params;
|
|
|
|
|
|
|
|
struct NATIVE {
|
|
|
|
char *name;
|
|
|
|
AMX_NATIVE fp;
|
|
|
|
};
|
|
|
|
struct NATIVE natives[] = {
|
|
|
|
/*this needs to be synced with NC_ definitions*/
|
|
|
|
{ "CreateObject", 0 },
|
|
|
|
{ "DestroyObject", 0 },
|
|
|
|
{ "SetObjectMaterial", 0 },
|
|
|
|
{ "SetObjectMaterialText", 0 },
|
|
|
|
{ "SetObjectPos", 0 },
|
|
|
|
{ "SetObjectRot", 0 },
|
|
|
|
{ "AddPlayerClass", 0 },
|
|
|
|
{ "EditObject", 0 },
|
|
|
|
{ "CreateVehicle", 0 },
|
|
|
|
{ "DestroyVehicle", 0 },
|
|
|
|
{ "SetWorldTime", 0 },
|
|
|
|
{ "SetWeather", 0 },
|
|
|
|
};
|
|
|
|
#define NUMNATIVES (sizeof(natives)/sizeof(struct NATIVE))
|
|
|
|
#define NC_CreateObject 0
|
|
|
|
#define NC_DestroyObject 1
|
|
|
|
#define NC_SetObjectMaterial 2
|
|
|
|
#define NC_SetObjectMaterialText 3
|
|
|
|
#define NC_SetObjectPos 4
|
|
|
|
#define NC_SetObjectRot 5
|
|
|
|
#define NC_AddPlayerClass 6
|
|
|
|
#define NC_EditObject 7
|
|
|
|
#define NC_CreateVehicle 8
|
|
|
|
#define NC_DestroyVehicle 9
|
|
|
|
#define NC_SetWorldTime 10
|
|
|
|
#define NC_SetWeather 11
|
|
|
|
|
|
|
|
PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports()
|
|
|
|
{
|
|
|
|
return SUPPORTS_VERSION | SUPPORTS_AMX_NATIVES | SUPPORTS_PROCESS_TICK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
void gen_gamemode_script()
|
|
|
|
{
|
|
|
|
#define cellsize 4
|
|
|
|
#define PUBLICS 0
|
|
|
|
|
|
|
|
FILE *f;
|
|
|
|
int tmp, size;
|
|
|
|
#if PUBLICS > 0
|
|
|
|
char pubtbl[PUBLICS * 8];
|
|
|
|
#endif
|
|
|
|
char nattbl[NUMNATIVES * 8];
|
|
|
|
int pubidx, i;
|
|
|
|
int cod, cip, dat;
|
|
|
|
union {
|
|
|
|
char i1;
|
|
|
|
short i2;
|
|
|
|
int i4;
|
|
|
|
char buf[4];
|
|
|
|
} data;
|
|
|
|
struct {
|
|
|
|
int addr, sym;
|
|
|
|
} *table_entry;
|
|
|
|
|
|
|
|
/*error handling is.. missing*/
|
|
|
|
f = fopen("samp-re.amx", "wb");
|
|
|
|
|
|
|
|
/*header*/
|
|
|
|
fwrite(data.buf, 4, 1, f); /*size, to be set when done*/
|
|
|
|
data.i2 = 0xF1E0;
|
|
|
|
fwrite(data.buf, 2, 1, f); /*magic*/
|
|
|
|
data.i1 = 0x8;
|
|
|
|
fwrite(data.buf, 1, 1, f); /*file version*/
|
|
|
|
data.i1 = 0x8;
|
|
|
|
fwrite(data.buf, 1, 1, f); /*amx version*/
|
|
|
|
data.i2 = 0x14;
|
|
|
|
fwrite(data.buf, 2, 1, f); /*flags*/
|
|
|
|
data.i2 = 0x8;
|
|
|
|
fwrite(data.buf, 2, 1, f); /*defsize*/
|
|
|
|
data.i4 = 0; /*done later*/
|
|
|
|
fwrite(data.buf, 4, 1, f); /*cod*/
|
|
|
|
data.i4 = 0; /*done later*/
|
|
|
|
fwrite(data.buf, 4, 1, f); /*dat*/
|
|
|
|
data.i4 = 0; /*done later*/
|
|
|
|
fwrite(data.buf, 4, 1, f); /*hea*/
|
|
|
|
data.i4 = 0; /*done later*/
|
|
|
|
fwrite(data.buf, 4, 1, f); /*stp*/
|
|
|
|
data.i4 = 0; /*done later*/
|
|
|
|
fwrite(data.buf, 4, 1, f); /*cip*/
|
|
|
|
data.i4 = 0x38;
|
|
|
|
fwrite(data.buf, 4, 1, f); /*publictable*/
|
|
|
|
#if PUBLICS > 0
|
|
|
|
data.i4 += sizeof(pubtbl);
|
|
|
|
#endif
|
|
|
|
fwrite(data.buf, 4, 1, f); /*nativetable*/
|
|
|
|
data.i4 += sizeof(nattbl);
|
|
|
|
fwrite(data.buf, 4, 1, f); /*libraries*/
|
|
|
|
fwrite(data.buf, 4, 1, f); /*pubvars*/
|
|
|
|
fwrite(data.buf, 4, 1, f); /*tags*/
|
|
|
|
fwrite(data.buf, 4, 1, f); /*nametable*/
|
|
|
|
size = 0x38; /*header*/
|
|
|
|
|
|
|
|
/*pubtbl, dummy at this point*/
|
|
|
|
#if PUBLICS > 0
|
|
|
|
fwrite(pubtbl, sizeof(pubtbl), 1, f);
|
|
|
|
size += sizeof(pubtbl);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*nattbl, dummy at this point*/
|
|
|
|
fwrite(nattbl, sizeof(nattbl), 1, f);
|
|
|
|
size += sizeof(nattbl);
|
|
|
|
|
|
|
|
/*namtbl*/
|
|
|
|
data.i2 = 31;
|
|
|
|
fwrite(data.buf, 2, 1, f); /*max name len (I suppose?)*/
|
|
|
|
size += 2;
|
|
|
|
pubidx = 0;
|
|
|
|
#define PUBLIC(NAME) \
|
|
|
|
tmp=strlen(NAME)+1;\
|
|
|
|
fwrite(NAME,tmp,1,f);\
|
|
|
|
table_entry->addr=(2+pubidx*4)*cellsize;\
|
|
|
|
table_entry->sym=size;\
|
|
|
|
table_entry++;\
|
|
|
|
pubidx++;\
|
|
|
|
size+=tmp;
|
|
|
|
/*first [PUBLICS] amount of natives should be the names of the
|
|
|
|
native plugin functions to passthrough callbacks to*/
|
|
|
|
#if PUBLICS > 0
|
|
|
|
table_entry = (void*) pubtbl;
|
|
|
|
PUBLIC("MM");
|
|
|
|
PUBLIC("dummies");
|
|
|
|
#endif
|
|
|
|
table_entry = (void*) nattbl;
|
|
|
|
for (i = 0; i < NUMNATIVES; i++) {
|
|
|
|
tmp = strlen(natives[i].name) + 1;
|
|
|
|
fwrite(natives[i].name, tmp, 1, f);
|
|
|
|
table_entry->addr = 0;
|
|
|
|
table_entry->sym = size;
|
|
|
|
table_entry++;
|
|
|
|
size += tmp;
|
|
|
|
}
|
|
|
|
#undef PUBLIC
|
|
|
|
|
|
|
|
cod = size;
|
|
|
|
|
|
|
|
/*code segment*/
|
|
|
|
cip = 0;
|
|
|
|
dat = 0;
|
|
|
|
data.i1 = 0x80; /*???*/
|
|
|
|
fwrite(data.buf, 1, 1, f);
|
|
|
|
data.i1 = 0x78; /*OP_HALT*/
|
|
|
|
fwrite(data.buf, 1, 1, f);
|
|
|
|
data.i1 = 0x00; /*param*/
|
|
|
|
fwrite(data.buf, 1, 1, f);
|
|
|
|
size += 3;
|
|
|
|
dat += 2;
|
|
|
|
/*publics*/
|
|
|
|
#if PUBLICS > 0
|
|
|
|
/*TODO: something makes the amx not accept this...*/
|
|
|
|
for (tmp = 0; tmp < PUBLICS; tmp++) {
|
|
|
|
data.buf[0] = 46; /*OP_PROC*/
|
|
|
|
data.buf[1] = 123; /*OP_SYSREC_C*/
|
|
|
|
data.buf[2] = tmp; /*name table entry*/
|
|
|
|
data.buf[3] = 48; /*OP_RETN*/
|
|
|
|
fwrite(data.buf, 4, 1, f);
|
|
|
|
size += 4;
|
|
|
|
dat += 4;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
/*entrypoint*/
|
|
|
|
cip = (size - cod) * cellsize;
|
|
|
|
data.i1 = 46; /*OP_PROC*/
|
|
|
|
fwrite(data.buf, 1, 1, f);
|
|
|
|
data.i1 = 48; /*OP_RETN*/
|
|
|
|
fwrite(data.buf, 1, 1, f);
|
|
|
|
size += 2;
|
|
|
|
dat += 2;
|
|
|
|
dat = cod + dat * cellsize;
|
|
|
|
|
|
|
|
fseek(f, 0, SEEK_SET);
|
|
|
|
data.i4 = size;
|
|
|
|
fwrite(data.buf, 4, 1, f); /*size*/
|
|
|
|
fseek(f, 0xC, SEEK_SET);
|
|
|
|
data.i4 = cod;
|
|
|
|
fwrite(data.buf, 4, 1, f); /*cod*/
|
|
|
|
data.i4 = dat;
|
|
|
|
fwrite(data.buf, 4, 1, f); /*dat*/
|
|
|
|
fwrite(data.buf, 4, 1, f); /*hea*/
|
|
|
|
data.i4 += STACK_HEAP_SIZE * cellsize;
|
|
|
|
fwrite(data.buf, 4, 1, f); /*stp*/
|
|
|
|
data.i4 = cip;
|
|
|
|
fwrite(data.buf, 4, 1, f); /*cip*/
|
|
|
|
|
|
|
|
fseek(f, 0x38, SEEK_SET);
|
|
|
|
#if PUBLICS > 0
|
|
|
|
fwrite(pubtbl, sizeof(pubtbl), 1, f); /*pubtbl*/
|
|
|
|
#endif
|
|
|
|
fwrite(nattbl, sizeof(nattbl), 1, f); /*nattbl*/
|
|
|
|
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
PLUGIN_EXPORT int PLUGIN_CALL Load(void **ppData)
|
|
|
|
{
|
2020-04-04 21:24:06 +02:00
|
|
|
void nethandler_init();
|
2020-04-02 23:46:27 +02:00
|
|
|
|
|
|
|
pAMXFunctions = ppData[PLUGIN_DATA_AMX_EXPORTS];
|
|
|
|
logprintf = (logprintf_t) ppData[PLUGIN_DATA_LOGPRINTF];
|
|
|
|
gen_gamemode_script();
|
|
|
|
|
|
|
|
nethandler_init();
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
PLUGIN_EXPORT void PLUGIN_CALL Unload()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
#define REGISTERNATIVE(X) {#X, X}
|
|
|
|
AMX_NATIVE_INFO PluginNatives[] =
|
|
|
|
{
|
|
|
|
{0, 0}
|
|
|
|
};
|
|
|
|
|
|
|
|
static
|
|
|
|
void collect_natives()
|
|
|
|
{
|
|
|
|
struct NATIVE *n = natives;
|
|
|
|
AMX_HEADER *header;
|
|
|
|
unsigned char *nattabl;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
header = (AMX_HEADER*) amx->base;
|
|
|
|
nattabl = (unsigned char*) header + header->natives;
|
|
|
|
|
|
|
|
for (i = 0; i < NUMNATIVES; i++) {
|
|
|
|
/*skipping some steps here...*/
|
|
|
|
natives[i].fp = (AMX_NATIVE) *((int*) (nattabl + i * 8));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PLUGIN_EXPORT int PLUGIN_CALL AmxLoad(AMX *a)
|
|
|
|
{
|
|
|
|
AMX_HEADER *hdr;
|
|
|
|
int tmp;
|
|
|
|
|
|
|
|
amx = a;
|
|
|
|
collect_natives();
|
|
|
|
|
|
|
|
nc_params.asint[1] = 0;
|
|
|
|
nc_params.asflt[2] = 0.0f;
|
|
|
|
nc_params.asflt[3] = 0.0f;
|
|
|
|
nc_params.asflt[4] = 4.5f;
|
|
|
|
nc_params.asflt[5] = 0.0f;
|
|
|
|
nc_params.asint[6] = nc_params.asint[8] = nc_params.asint[10] = 0;
|
|
|
|
nc_params.asint[7] = nc_params.asint[9] = nc_params.asint[11] = 0;
|
|
|
|
natives[NC_AddPlayerClass].fp(amx, nc_params.asint);
|
|
|
|
|
|
|
|
/*relocate the data segment*/
|
|
|
|
hdr = (AMX_HEADER*) amx->base;
|
|
|
|
tmp = hdr->hea - hdr->dat;
|
|
|
|
if (tmp) {
|
|
|
|
/*data section will be cleared so whoever references it
|
|
|
|
will probably overwrite our precious data*/
|
|
|
|
logprintf("WARN: data section is not empty! (%d)", tmp);
|
|
|
|
}
|
|
|
|
tmp = hdr->stp - hdr->hea - STACK_HEAP_SIZE * sizeof(cell);
|
|
|
|
if (tmp) {
|
|
|
|
logprintf("ERR: stack/heap size mismatch! "
|
|
|
|
"(excess %d cells)",
|
|
|
|
tmp / sizeof(cell));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/*copy content of stack/heap to our data segment (this is most
|
|
|
|
likely empty, but better safe than sorry)*/
|
|
|
|
memcpy(fakeamx_data._stackheap,
|
|
|
|
amx->base + hdr->hea,
|
|
|
|
STACK_HEAP_SIZE * sizeof(cell));
|
|
|
|
/*finally do the relocation*/
|
|
|
|
amx->data = (unsigned char*) &fakeamx_data;
|
|
|
|
/*adjust pointers since the data segment grew*/
|
|
|
|
tmp = (char*) &fakeamx_data._stackheap - (char*) &fakeamx_data;
|
|
|
|
amx->frm += tmp;
|
|
|
|
amx->hea += tmp;
|
|
|
|
amx->hlw += tmp;
|
|
|
|
amx->stk += tmp;
|
|
|
|
amx->stp += tmp;
|
|
|
|
/*samp core doesn't seem to use amx_SetString or amx_GetString
|
|
|
|
so the data offset needs to be adjusted*/
|
|
|
|
hdr->dat = (int) &fakeamx_data - (int) hdr;
|
|
|
|
/*this won't work on linux because linux builds have assertions
|
|
|
|
enabled, but this is only targeted for windows anyways*/
|
|
|
|
|
|
|
|
return amx_Register(a, PluginNatives, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
PLUGIN_EXPORT int PLUGIN_CALL AmxUnload(AMX *a)
|
|
|
|
{
|
|
|
|
return AMX_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PLUGIN_EXPORT void PLUGIN_CALL ProcessTick()
|
|
|
|
{
|
|
|
|
}
|