// native Array:ArrayClone(Array:which); static cell AMX_NATIVE_CALL ArrayClone(AMX* amx, cell* params) { CellArray* vec = HandleToVector(amx, params[1]); if (vec == NULL) { return 0; } CellArray *clonevec = vec->clone(); // Scan through the vector list to see if any are NULL. // NULL means the vector was previously destroyed. for (unsigned int i = 0; i < VectorHolder.length(); ++i) { if (VectorHolder[i] == NULL) { VectorHolder[i] = clonevec; return i + 1; } } VectorHolder.append(clonevec); return VectorHolder.length(); }
void genheapfree(int stop_id) { for (size_t i = sHeapScopes.length() - 1; i < sHeapScopes.length(); i--) { const MemoryScope& scope = sHeapScopes[i]; if (scope.scope_id <= stop_id) break; modheap_for_scope(scope); } }
void genstackfree(int stop_id) { for (size_t i = sStackScopes.length() - 1; i < sStackScopes.length(); i--) { const MemoryScope& scope = sStackScopes[i]; if (scope.scope_id <= stop_id) break; modstk_for_scope(scope); } }
int GetPEL() { for (int i=0; i<(int)PEL.length(); i++) { if (PEL[i]->isFree()) return i; } RegEx *x = new RegEx(); PEL.append(x); return (int)PEL.length() - 1; }
//Makes a new menu handle (-1 for failure) //native csdm_makemenu(title[]); static cell AMX_NATIVE_CALL menu_create(AMX *amx, cell *params) { int len; char *title = get_amxstring(amx, params[1], 0, len); validate_menu_text(title); char *handler = get_amxstring(amx, params[2], 1, len); int func = registerSPForwardByName(amx, handler, FP_CELL, FP_CELL, FP_CELL, FP_DONE); if (func == -1) { LogError(amx, AMX_ERR_NOTFOUND, "Invalid function \"%s\"", handler); return 0; } Menu *pMenu = new Menu(title, amx, func); if (g_MenuFreeStack.empty()) { g_NewMenus.append(pMenu); pMenu->thisId = (int)g_NewMenus.length() - 1; } else { int pos = g_MenuFreeStack.front(); g_MenuFreeStack.pop(); g_NewMenus[pos] = pMenu; pMenu->thisId = pos; } return pMenu->thisId; }
// native regex_substr(Regex:id, str_id, buffer[], maxLen); static cell AMX_NATIVE_CALL regex_substr(AMX *amx, cell *params) { int id = params[1]-1; if (id >= (int)PEL.length() || id < 0 || PEL[id]->isFree()) { MF_LogError(amx, AMX_ERR_NATIVE, "Invalid regex handle %d", id); return 0; } RegEx *x = PEL[id]; static char buffer[16384]; // Same as AMXX buffer. size_t length; size_t maxLength = ke::Min<size_t>(params[4], sizeof(buffer) - 1); const char *ret = x->GetSubstring(params[2], buffer, maxLength, &length); if (ret == NULL) { return 0; } if (length >= maxLength && ret[length - 1] & 1 << 7) { maxLength -= UTIL_CheckValidChar((char *)ret + length - 1); } MF_SetAmxString(amx, params[3], ret, maxLength); return 1; }
Menu *get_menu_by_id(int id) { if (id < 0 || size_t(id) >= g_NewMenus.length() || !g_NewMenus[id]) return NULL; return g_NewMenus[id]; }
//native regex_replace(Regex:pattern, string[], maxLen, const replace[], flags = REGEX_FORMAT_DEFAULT, &errcode = 0); static cell AMX_NATIVE_CALL regex_replace(AMX *amx, cell *params) { int id = params[1] - 1; if (id >= (int)PEL.length() || id < 0 || PEL[id]->isFree()) { MF_LogError(amx, AMX_ERR_NATIVE, "Invalid regex handle %d", id); return 0; } int textLen, replaceLen; char *text = MF_GetAmxString(amx, params[2], 0, &textLen); const char *replace = MF_GetAmxString(amx, params[4], 1, &replaceLen); cell *erroCode = MF_GetAmxAddr(amx, params[6]); RegEx *x = PEL[id]; int e = x->Replace(text, params[3] + 1, replace, replaceLen, params[5]); if (e == -1) { *erroCode = x->mErrorOffset; x->ClearMatch(); return -2; } else if (e == 0) { *erroCode = 0; x->ClearMatch(); return 0; } MF_SetAmxString(amx, params[2], text, params[3]); return e; }
void pfnTouch(edict_t *pToucher, edict_t *pTouched) { unsigned int i = 0; int retVal = 0; const char *ptrClass = STRING(pToucher->v.classname); const char *ptdClass = STRING(pTouched->v.classname); int ptrIndex = ENTINDEX(pToucher); int ptdIndex = ENTINDEX(pTouched); META_RES res=MRES_IGNORED; for (i=0; i<Touches.length(); i++) { if (Touches[i]->Toucher.isVoid()) { if (Touches[i]->Touched.isVoid()) { retVal = MF_ExecuteForward(Touches[i]->Forward, (cell)ptrIndex, (cell)ptdIndex); if (retVal & 2/*PLUGIN_HANDLED_MAIN*/) RETURN_META(MRES_SUPERCEDE); else if (retVal) res=MRES_SUPERCEDE; } else if (Touches[i]->Touched.compare(ptdClass)==0) { retVal = MF_ExecuteForward(Touches[i]->Forward, (cell)ptrIndex, (cell)ptdIndex); if (retVal & 2/*PLUGIN_HANDLED_MAIN*/) RETURN_META(MRES_SUPERCEDE); else if (retVal) res=MRES_SUPERCEDE; } } else if (Touches[i]->Toucher.compare(ptrClass)==0) { if (Touches[i]->Touched.isVoid()) { retVal = MF_ExecuteForward(Touches[i]->Forward, (cell)ptrIndex, (cell)ptdIndex); if (retVal & 2/*PLUGIN_HANDLED_MAIN*/) RETURN_META(MRES_SUPERCEDE); else if (retVal) res=MRES_SUPERCEDE; } else if (Touches[i]->Touched.compare(ptdClass)==0) { retVal = MF_ExecuteForward(Touches[i]->Forward, (cell)ptrIndex, (cell)ptdIndex); if (retVal & 2/*PLUGIN_HANDLED_MAIN*/) RETURN_META(MRES_SUPERCEDE); else if (retVal) res=MRES_SUPERCEDE; } } } /* Execute pfnTouch forwards */ if (pfnTouchForward != -1) { retVal = MF_ExecuteForward(pfnTouchForward, (cell)ptrIndex, (cell)ptdIndex); if (retVal) RETURN_META(MRES_SUPERCEDE); } if (VexdTouchForward != -1) { retVal = MF_ExecuteForward(VexdTouchForward, (cell)ptrIndex, (cell)ptdIndex); if (retVal) RETURN_META(MRES_SUPERCEDE); } RETURN_META(res); }
void ClearPluginLibraries() { ClearLibraries(LibSource_Plugin); for (size_t i=0; i<g_RegNatives.length(); i++) { delete [] g_RegNatives[i]->pfn; delete g_RegNatives[i]; } g_RegNatives.clear(); }
void OnAmxxDetach() { for (int i = 0; i<(int)PEL.length(); i++) { if (PEL[i]) { delete PEL[i]; PEL[i] = 0; } } PEL.clear(); }
void ClearMenus() { for (size_t i = 0; i < g_NewMenus.length(); i++) { delete g_NewMenus[i]; } g_NewMenus.clear(); while (!g_MenuFreeStack.empty()) { g_MenuFreeStack.pop(); } }
// Array:ArrayCreate(cellsize=1, reserved=32); static cell AMX_NATIVE_CALL ArrayCreate(AMX* amx, cell* params) { // params[1] (cellsize) is how big in cells each element is. // this MUST be greater than 0! int cellsize = params[1]; // params[2] (reserved) is how many elements to allocate // immediately when the list is created. int reserved = params[2]; if (cellsize <= 0) { LogError(amx, AMX_ERR_NATIVE, "Invalid array size (%d)", cellsize); return -1; } if (reserved < 0) { reserved = 0; } // Scan through the vector list to see if any are NULL. // NULL means the vector was previously destroyed. for (unsigned int i=0; i < VectorHolder.length(); ++i) { if (VectorHolder[i]==NULL) { VectorHolder[i] = new CellArray(cellsize, reserved); return i + 1; } } // None are NULL, create a new vector CellArray* NewVector = new CellArray(cellsize, reserved); VectorHolder.append(NewVector); return VectorHolder.length(); }
//register_native(const name[], const handler[]) static cell AMX_NATIVE_CALL register_native(AMX *amx, cell *params) { if (!g_Initialized) amxx_DynaInit((void *)(amxx_DynaCallback)); g_Initialized = true; int len; char *name = get_amxstring(amx, params[1], 0, len); char *func = get_amxstring(amx, params[2], 1, len); int idx, err; if ( (err=amx_FindPublic(amx, func, &idx)) != AMX_ERR_NONE) { LogError(amx, err, "Function \"%s\" was not found", func); return 0; } regnative *pNative = new regnative; pNative->amx = amx; pNative->func = idx; //we'll apply a safety buffer too //make our function int size = amxx_DynaCodesize(); #if defined(_WIN32) DWORD temp; pNative->pfn = new char[size + 10]; VirtualProtect(pNative->pfn, size+10, PAGE_EXECUTE_READWRITE, &temp); #elif defined(__GNUC__) # if defined(__APPLE__) pNative->pfn = (char *)valloc(size+10); # else pNative->pfn = (char *)memalign(sysconf(_SC_PAGESIZE), size+10); # endif mprotect((void *)pNative->pfn, size+10, PROT_READ|PROT_WRITE|PROT_EXEC); #endif int id = (int)g_RegNatives.length(); amxx_DynaMake(pNative->pfn, id); pNative->func = idx; pNative->style = params[3]; g_RegNatives.append(pNative); pNative->name = name; return 1; }
AMX_NATIVE_INFO *BuildNativeTable() { if (g_RegNatives.length() < 1) { return NULL; } AMX_NATIVE_INFO *pNatives = new AMX_NATIVE_INFO[g_RegNatives.length() + 1]; AMX_NATIVE_INFO info; regnative *pNative; for (size_t i=0; i<g_RegNatives.length(); i++) { pNative = g_RegNatives[i]; info.name = pNative->name.chars(); info.func = (AMX_NATIVE)((void *)(pNative->pfn)); pNatives[i] = info; } pNatives[g_RegNatives.length()].name = NULL; pNatives[g_RegNatives.length()].func = NULL; //this needs to be deleted return pNatives; }
cell match_c(AMX *amx, cell *params, bool all) { int id = params[2] - 1; if (id >= (int)PEL.length() || id < 0 || PEL[id]->isFree()) { MF_LogError(amx, AMX_ERR_NATIVE, "Invalid regex handle %d", id); return 0; } int len; const char *str = MF_GetAmxString(amx, params[1], 0, &len); cell *errorCode = MF_GetAmxAddr(amx, params[3]); RegEx *x = PEL[id]; int e; if (all) e = x->MatchAll(str); else e = x->Match(str); if (e == -1) { /* there was a match error. move on. */ *errorCode = x->mErrorOffset; /* only clear the match results, since the regex object may still be referenced later */ x->ClearMatch(); return -2; } else if (e == 0) { *errorCode = 0; /* only clear the match results, since the regex object may still be referenced later */ x->ClearMatch(); return 0; } else { *errorCode = x->Count(); return x->Count(); } }
static cell AMX_NATIVE_CALL regex_free(AMX *amx, cell *params) { cell *c = MF_GetAmxAddr(amx, params[1]); int id = *c; *c = 0; id -= 1; if (id >= (int)PEL.length() || id < 0 || PEL[id]->isFree()) { MF_LogError(amx, AMX_ERR_NATIVE, "Invalid regex handle %d", id); return 0; } RegEx *x = PEL[id]; x->Clear(); return 1; }
static cell AMX_NATIVE_CALL free_kvd(AMX *amx, cell *params) { if (params[1] == 0) { return 0; } KVD_Wrapper *kvdw = reinterpret_cast<KVD_Wrapper *>(params[1]); for (size_t i = 0; i < g_KVDWs.length(); ++i) { if (g_KVDWs[i] == kvdw) { g_KVDWs.remove(i); g_FreeKVDWs.append(kvdw); return 1; } } return 0; }
void CmdStart(const edict_t *player, const struct usercmd_s *_cmd, unsigned int random_seed) { unsigned int i = 0; int retVal = 0; edict_t *pEntity = (edict_t *)player; g_cmd = (struct usercmd_s *)_cmd; int origImpulse = g_cmd->impulse; // incase a plugin alters it for (i=0; i<Impulses.length(); i++) { if (Impulses[i]->Check == g_cmd->impulse) { retVal = MF_ExecuteForward(Impulses[i]->Forward, (cell)ENTINDEX(pEntity), (cell)origImpulse); // don't return SUPERCEDE in any way here, // we don't want to break client_impulse forward and access to cmd with [g/s]et_usercmd if (retVal) g_cmd->impulse = 0; } } // client_impulse if (ClientImpulseForward != -1 && origImpulse != 0) { retVal = MF_ExecuteForward(ClientImpulseForward, (cell)ENTINDEX(pEntity), (cell)origImpulse); if (retVal) g_cmd->impulse = 0; } // client_CmdStart if (CmdStartForward != -1) { incmd = true; retVal = MF_ExecuteForward(CmdStartForward, (cell)ENTINDEX(pEntity)); incmd = false; if (retVal) RETURN_META(MRES_SUPERCEDE); } RETURN_META(MRES_IGNORED); }
void Think(edict_t *pent) { unsigned int i = 0; const char *cls = STRING(pent->v.classname); META_RES res=MRES_IGNORED; int retVal=0; for (i=0; i<Thinks.length(); i++) { if (Thinks[i]->Class.compare(cls)==0) { retVal=MF_ExecuteForward(Thinks[i]->Forward, (cell)ENTINDEX(pent)); if (retVal & 2/*PLUGIN_HANDLED_MAIN*/) RETURN_META(MRES_SUPERCEDE); else if (retVal) res=MRES_SUPERCEDE; } } retVal=MF_ExecuteForward(pfnThinkForward, (cell)ENTINDEX(pent)); if (retVal) res=MRES_SUPERCEDE; RETURN_META(res); }
int amxx_DynaCallback(int idx, AMX *amx, cell *params) { if (idx < 0 || idx >= (int)g_RegNatives.length()) { LogError(amx, AMX_ERR_NATIVE, "Invalid dynamic native called"); return 0; } regnative *pNative = g_RegNatives[idx]; int numParams = params[0] / sizeof(cell); if (numParams > CALLFUNC_MAXPARAMS) { LogError(amx, AMX_ERR_NATIVE, "Called dynanative with too many parameters (%d)", CALLFUNC_MAXPARAMS); return 0; } CPluginMngr::CPlugin *pPlugin = g_plugins.findPluginFast(amx); CPluginMngr::CPlugin *pNativePlugin = g_plugins.findPluginFast(pNative->amx); if (!pNativePlugin->isExecutable(pNative->func)) { LogError(amx, AMX_ERR_NATIVE, "Called dynanative into a paused plugin."); pPlugin->setStatus(ps_paused); return 0; } /* Save old values on ZE STACK */ AMX *pSaveCaller = g_pCaller; cell saveParams[CALLFUNC_MAXPARAMS]; regnative *pSaveNative = g_pCurNative; int saveError = g_CurError; if (pSaveNative) { for (ucell i = 0; i <= g_Params[0] / sizeof(cell); i++) { saveParams[i] = g_Params[i]; } } /* Save current info */ g_CurError = AMX_ERR_NONE; g_pCaller = amx; g_pCurNative = pNative; int err = 0; cell ret = 0; if (pNative->style == 0) { amx_Push(pNative->amx, numParams); amx_Push(pNative->amx, pPlugin->getId()); for (int i=numParams; i>=0; i--) { g_Params[i] = params[i]; } } else if (pNative->style == 1) { /** * use dJeyL's system .. very clever! * NOTE: clever, but doesn't work at all since the JIT does bounds checking * this should REALLY be deprecated */ for (int i=numParams; i>=1; i--) { amx_Push(pNative->amx, params[i]); } } Debugger *pDebugger = (Debugger *)pNative->amx->userdata[UD_DEBUGGER]; if (pDebugger) { pDebugger->BeginExec(); } err=amx_Exec(pNative->amx, &ret, pNative->func); if (err != AMX_ERR_NONE) { if (pDebugger && pDebugger->ErrorExists()) { //don't care } else if (err != -1) { //nothing logged the error LogError(pNative->amx, err, NULL); } pNative->amx->error = AMX_ERR_NONE; //furthermore, log an error in the parent plugin. LogError(amx, AMX_ERR_NATIVE, "Unhandled dynamic native error"); } else if (g_CurError != AMX_ERR_NONE) { LogError(amx, g_CurError, g_errorStr); } if (pDebugger) { pDebugger->EndExec(); } /* Restore everything */ g_pCurNative = pSaveNative; g_CurError = saveError; g_pCaller = pSaveCaller; if (pSaveNative) { for (ucell i = 0; i <= saveParams[0] / sizeof(cell); i++) { g_Params[i] = saveParams[i]; } } return ret; }
static cell AMX_NATIVE_CALL set_kvd(AMX *amx, cell *params) { KVD_Wrapper *kvdw = nullptr; KeyValueData *kvd = nullptr; KVD_Wrapper *tmpw = reinterpret_cast<KVD_Wrapper *>(params[1]); if (params[1] == 0 || tmpw == &g_kvd_glb) { kvdw = &g_kvd_glb; kvd = &(kvdw->kvd); } else { for (size_t i = 0; i < g_KVDWs.length(); ++i) { if (g_KVDWs[i] == tmpw) { kvdw = tmpw; kvd = &(kvdw->kvd); } } if (kvdw == nullptr) { kvdw = &g_kvd_ext; kvd = reinterpret_cast<KeyValueData *>(tmpw); } } if (*params / sizeof(cell) < 3) { MF_LogError(amx, AMX_ERR_NATIVE, "No data passed"); return 0; } cell *ptr = MF_GetAmxAddr(amx, params[3]); int len; switch (params[2]) { case KV_fHandled: { kvd->fHandled = (int)*ptr; return 1; break; } case KV_ClassName: { kvdw->cls = MF_GetAmxString(amx, params[3], 0, &len); kvd->szClassName = const_cast<char *>(kvdw->cls.chars()); return 1; break; } case KV_KeyName: { kvdw->key = MF_GetAmxString(amx, params[3], 0, &len); kvd->szKeyName = const_cast<char *>(kvdw->key.chars()); return 1; break; } case KV_Value: { kvdw->val = MF_GetAmxString(amx, params[3], 0, &len); kvd->szValue = const_cast<char *>(kvdw->val.chars()); return 1; break; } } MF_LogError(amx, AMX_ERR_NATIVE, "Invalid KeyValueData member: %d", params[2]); return 0; }