/* vim: set filetype=c ts=8 noexpandtab: */ #include "common.h" #include #include "io.h" #include "vendor/SDK/amx/amx.h" #include "vendor/SDK/plugincommon.h" #include #include #include 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) { void nethandler_init(); 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() { }