diff --git a/modules/fakemeta/dllfunc.cpp b/modules/fakemeta/dllfunc.cpp index 8aa0429d..f4263b0f 100644 --- a/modules/fakemeta/dllfunc.cpp +++ b/modules/fakemeta/dllfunc.cpp @@ -72,12 +72,14 @@ static cell AMX_NATIVE_CALL dllfunc(AMX *amx,cell *params) index=cRet[0]; CHECK_ENTITY(index); cRet = MF_GetAmxAddr(amx, params[3]); - KVD_Wrapper *kvdw; + + KeyValueData *kvd; if (*cRet == 0) - kvdw = &g_kvd_glb; + kvd = &(g_kvd_glb.kvd); else - kvdw = reinterpret_cast(*cRet); - gpGamedllFuncs->dllapi_table->pfnKeyValue(INDEXENT2(index), kvdw->kvd); + kvd = reinterpret_cast(*cRet); + + gpGamedllFuncs->dllapi_table->pfnKeyValue(INDEXENT2(index), kvd); return 1; } diff --git a/modules/fakemeta/fakemeta_amxx.cpp b/modules/fakemeta/fakemeta_amxx.cpp index 67e9e611..77f2f9da 100644 --- a/modules/fakemeta/fakemeta_amxx.cpp +++ b/modules/fakemeta/fakemeta_amxx.cpp @@ -29,13 +29,16 @@ void OnAmxxAttach() MF_AddNatives(glb_natives); MF_AddNatives(ext2_natives); MF_AddNatives(misc_natives); - g_kvd_2.szClassName = ""; - g_kvd_2.szKeyName = ""; - g_kvd_2.szValue = ""; - g_kvd_glb.kvd = &g_kvd_2; + g_kvd_glb.kvd.szClassName = const_cast(g_kvd_glb.cls.chars()); + g_kvd_glb.kvd.szKeyName = const_cast(g_kvd_glb.key.chars()); + g_kvd_glb.kvd.szValue = const_cast(g_kvd_glb.val.chars()); + g_kvd_glb.kvd.fHandled = 0; } extern CStack g_FreeTRs; +extern ke::Vector g_KVDWs; +extern ke::Vector g_FreeKVDWs; + void OnAmxxDetach() { while (!g_FreeTRs.empty()) @@ -43,6 +46,12 @@ void OnAmxxDetach() delete g_FreeTRs.front(); g_FreeTRs.pop(); } + + while (!g_KVDWs.empty()) + delete g_KVDWs.popCopy(); + + while (!g_FreeKVDWs.empty()) + delete g_FreeKVDWs.popCopy(); } int GetHullBounds(int hullnumber, float *mins, float *maxs); diff --git a/modules/fakemeta/fm_tr.h b/modules/fakemeta/fm_tr.h index e381ce17..e14eb40d 100644 --- a/modules/fakemeta/fm_tr.h +++ b/modules/fakemeta/fm_tr.h @@ -20,7 +20,6 @@ extern TraceResult *gfm_tr; //these also don't fit in here but gaben does not care. GABEN DOES NOT CARE!!! extern TraceResult g_tr_2; -extern KeyValueData g_kvd_2; extern clientdata_t g_cd_glb; extern clientdata_t *g_cd_hook; extern entity_state_t g_es_glb; @@ -30,14 +29,13 @@ extern usercmd_t *g_uc_hook; struct KVD_Wrapper { - KeyValueData *kvd; + KeyValueData kvd; ke::AString cls; ke::AString key; ke::AString val; }; extern KVD_Wrapper g_kvd_glb; -extern KVD_Wrapper g_kvd_hook; enum { diff --git a/modules/fakemeta/fm_tr2.cpp b/modules/fakemeta/fm_tr2.cpp index 7840f238..754ab261 100644 --- a/modules/fakemeta/fm_tr2.cpp +++ b/modules/fakemeta/fm_tr2.cpp @@ -15,9 +15,12 @@ #include "sh_stack.h" TraceResult g_tr_2; -KeyValueData g_kvd_2; KVD_Wrapper g_kvd_glb; +KVD_Wrapper g_kvd_ext; + +ke::Vectorg_KVDWs; +ke::Vectorg_FreeKVDWs; clientdata_t g_cd_glb; entity_state_t g_es_glb; @@ -206,13 +209,11 @@ static cell AMX_NATIVE_CALL get_tr2(AMX *amx, cell *params) static cell AMX_NATIVE_CALL get_kvd(AMX *amx, cell *params) { - KVD_Wrapper *kvdw; KeyValueData *kvd; if (params[1] == 0) - kvdw = &g_kvd_glb; + kvd = &(g_kvd_glb.kvd); else - kvdw = reinterpret_cast(params[1]); - kvd = kvdw->kvd; + kvd = reinterpret_cast(params[1]); switch (params[2]) { @@ -263,13 +264,26 @@ static cell AMX_NATIVE_CALL get_kvd(AMX *amx, cell *params) static cell AMX_NATIVE_CALL set_kvd(AMX *amx, cell *params) { - KVD_Wrapper *kvdw; - KeyValueData *kvd; - if (params[1] == 0) + KVD_Wrapper *kvdw = nullptr; + KeyValueData *kvd = nullptr; + + KVD_Wrapper *tmpw = reinterpret_cast(params[1]); + if (params[1] == 0 || tmpw == &g_kvd_glb) { kvdw = &g_kvd_glb; - else - kvdw = reinterpret_cast(params[1]); - kvd = kvdw->kvd; + 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(tmpw); + } + } if (*params / sizeof(cell) < 3) { @@ -1257,12 +1271,55 @@ static cell AMX_NATIVE_CALL free_tr2(AMX *amx, cell *params) return 1; } +static cell AMX_NATIVE_CALL create_kvd(AMX *amx, cell *params) +{ + KVD_Wrapper *kvdw; + if (g_FreeKVDWs.empty()) { + kvdw = new KVD_Wrapper; + } else { + kvdw = g_FreeKVDWs.popCopy(); + } + + kvdw->cls = ""; + kvdw->kvd.szClassName = const_cast(kvdw->cls.chars()); + kvdw->key = ""; + kvdw->kvd.szKeyName = const_cast(kvdw->key.chars()); + kvdw->val = ""; + kvdw->kvd.szValue = const_cast(kvdw->val.chars()); + kvdw->kvd.fHandled = 0; + + g_KVDWs.append(kvdw); + + return reinterpret_cast(kvdw); +} + +static cell AMX_NATIVE_CALL free_kvd(AMX *amx, cell *params) { + if (params[1] == 0) { + return 0; + } + + KVD_Wrapper *kvdw = reinterpret_cast(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; +} + AMX_NATIVE_INFO ext2_natives[] = { {"create_tr2", create_tr2}, {"free_tr2", free_tr2}, {"get_tr2", get_tr2}, {"set_tr2", set_tr2}, + {"create_kvd", create_kvd}, + {"free_kvd", free_kvd}, {"get_kvd", get_kvd}, {"set_kvd", set_kvd}, {"get_cd", get_cd}, diff --git a/modules/fakemeta/forward.cpp b/modules/fakemeta/forward.cpp index dde12a86..b796d468 100644 --- a/modules/fakemeta/forward.cpp +++ b/modules/fakemeta/forward.cpp @@ -262,15 +262,13 @@ typedef struct KeyValueData_s */ void KeyValue(edict_t* entity, KeyValueData* data) { - g_kvd_hook.kvd = data; - FM_ENG_HANDLE(FM_KeyValue, (Engine[FM_KeyValue].at(i), (cell)ENTINDEX(entity), (cell)(&g_kvd_hook))); + FM_ENG_HANDLE(FM_KeyValue, (Engine[FM_KeyValue].at(i), (cell)ENTINDEX(entity), (cell)(data))); RETURN_META(mswi(lastFmRes)); } void KeyValue_post(edict_t* entity, KeyValueData* data) { - g_kvd_hook.kvd = data; - FM_ENG_HANDLE_POST(FM_KeyValue, (EnginePost[FM_KeyValue].at(i), (cell)ENTINDEX(entity), (cell)(&g_kvd_hook))); + FM_ENG_HANDLE_POST(FM_KeyValue, (EnginePost[FM_KeyValue].at(i), (cell)ENTINDEX(entity), (cell)(data))); RETURN_META(MRES_IGNORED); } diff --git a/plugins/include/fakemeta.inc b/plugins/include/fakemeta.inc index b530844a..26e34cd7 100755 --- a/plugins/include/fakemeta.inc +++ b/plugins/include/fakemeta.inc @@ -473,6 +473,24 @@ native get_kvd(kvd_handle, KeyValueData:member, any:...); // keyvalues structure rather than changing the internal engine strings. native set_kvd(kvd_handle, KeyValueData:member, any:...); +/** + * Creates a KeyValueData handle. + * + * @note Handles should be freed using free_kvd(). + * + * @return New KeyValueData handle + */ +native create_kvd(); + +/** + * Frees a KeyValueData handle. + * + * @param kvd_handle KeyValueData handle + * + * @noreturn + */ +native free_kvd(kvd_handle); + // These functions are used with the clientdata data structure (FM_UpdateClientData) // Get: 0 extra params - Return integer; 1 extra param - by ref float or vector; 2 extra params - string and length // Set: Use anything diff --git a/plugins/include/ham_const.inc b/plugins/include/ham_const.inc index 8c6a31e1..b7564fca 100644 --- a/plugins/include/ham_const.inc +++ b/plugins/include/ham_const.inc @@ -70,7 +70,7 @@ enum Ham /** * Description: Typically this is similar to an engine keyvalue call. * Use the kvd natives from fakemeta to handle the kvd_handle passed. - * NOTE: Do not pass handle 0 to this! Use get_kvd_handle(0) from fakemeta instead! + * NOTE: Do not pass handle 0 to this! Use create_kvd() from fakemeta instead! * Forward params: function(this, kvd_handle); * Return type: None. * Execute params: ExecuteHam(Ham_Keyvalue, this, kvd_handle);