diff --git a/amxmodx/CForward.cpp b/amxmodx/CForward.cpp index 49952f5d..1ea5d2e4 100755 --- a/amxmodx/CForward.cpp +++ b/amxmodx/CForward.cpp @@ -59,7 +59,7 @@ cell CForward::execute(cell *params, ForwardPreparedArray *preparedArrays) if (pDebugger) pDebugger->BeginExec(); - // handle strings & arrays + // handle strings & arrays & values by reference int i; for (i = 0; i < m_NumParams; ++i) @@ -70,7 +70,7 @@ cell CForward::execute(cell *params, ForwardPreparedArray *preparedArrays) cell *tmp; if (!str) str = ""; - amx_Allot(iter->pPlugin->getAMX(), (m_ParamTypes[i] == FP_STRING) ? strlen(str) + 1 : STRINGEX_MAXLENGTH, &realParams[i], &tmp); + amx_Allot(amx, (m_ParamTypes[i] == FP_STRING) ? strlen(str) + 1 : STRINGEX_MAXLENGTH, &realParams[i], &tmp); amx_SetStringOld(tmp, str, 0, 0); physAddrs[i] = tmp; } @@ -89,7 +89,24 @@ cell CForward::execute(cell *params, ForwardPreparedArray *preparedArrays) for (unsigned int j = 0; j < preparedArrays[params[i]].size; ++j) *tmp++ = (static_cast(*data++)) & 0xFF; } - } else { + } + else if (m_ParamTypes[i] == FP_CELL_BYREF || m_ParamTypes[i] == FP_FLOAT_BYREF) + { + cell *tmp; + amx_Allot(amx, 1, &realParams[i], &tmp); + physAddrs[i] = tmp; + + if (m_ParamTypes[i] == FP_CELL_BYREF) + { + memcpy(tmp, reinterpret_cast(params[i]), sizeof(cell)); + } + else + { + memcpy(tmp, reinterpret_cast(params[i]), sizeof(REAL)); + } + } + else + { realParams[i] = params[i]; } } @@ -127,18 +144,18 @@ cell CForward::execute(cell *params, ForwardPreparedArray *preparedArrays) if (pDebugger) pDebugger->EndExec(); - // cleanup strings & arrays + // cleanup strings & arrays & values by reference for (i = 0; i < m_NumParams; ++i) { if (m_ParamTypes[i] == FP_STRING) { - amx_Release(iter->pPlugin->getAMX(), realParams[i]); + amx_Release(amx, realParams[i]); } else if (m_ParamTypes[i] == FP_STRINGEX) { // copy back amx_GetStringOld(reinterpret_cast(params[i]), physAddrs[i], 0); - amx_Release(iter->pPlugin->getAMX(), realParams[i]); + amx_Release(amx, realParams[i]); } else if (m_ParamTypes[i] == FP_ARRAY) { @@ -156,7 +173,21 @@ cell CForward::execute(cell *params, ForwardPreparedArray *preparedArrays) *data++ = static_cast(*tmp++ & 0xFF); } } - amx_Release(iter->pPlugin->getAMX(), realParams[i]); + amx_Release(amx, realParams[i]); + } + else if (m_ParamTypes[i] == FP_CELL_BYREF || m_ParamTypes[i] == FP_FLOAT_BYREF) + { + //copy back + cell *tmp = physAddrs[i]; + if (m_ParamTypes[i] == FP_CELL_BYREF) + { + memcpy(reinterpret_cast(params[i]), tmp, sizeof(cell)); + } + else + { + memcpy(reinterpret_cast(params[i]), tmp, sizeof(REAL)); + } + amx_Release(amx, realParams[i]); } } @@ -236,7 +267,7 @@ cell CSPForward::execute(cell *params, ForwardPreparedArray *preparedArrays) if (pDebugger) pDebugger->BeginExec(); - // handle strings & arrays + // handle strings & arrays & values by reference int i; for (i = 0; i < m_NumParams; ++i) @@ -266,7 +297,24 @@ cell CSPForward::execute(cell *params, ForwardPreparedArray *preparedArrays) for (unsigned int j = 0; j < preparedArrays[params[i]].size; ++j) *tmp++ = (static_cast(*data++)) & 0xFF; } - } else { + } + else if (m_ParamTypes[i] == FP_CELL_BYREF || m_ParamTypes[i] == FP_FLOAT_BYREF) + { + cell *tmp; + amx_Allot(m_Amx, 1, &realParams[i], &tmp); + physAddrs[i] = tmp; + + if (m_ParamTypes[i] == FP_CELL_BYREF) + { + memcpy(tmp, reinterpret_cast(params[i]), sizeof(cell)); + } + else + { + memcpy(tmp, reinterpret_cast(params[i]), sizeof(REAL)); + } + } + else + { realParams[i] = params[i]; } } @@ -300,7 +348,7 @@ cell CSPForward::execute(cell *params, ForwardPreparedArray *preparedArrays) m_Amx->error = AMX_ERR_NONE; - // cleanup strings & arrays + // cleanup strings & arrays & values by reference for (i = 0; i < m_NumParams; ++i) { if (m_ParamTypes[i] == FP_STRING) @@ -331,6 +379,20 @@ cell CSPForward::execute(cell *params, ForwardPreparedArray *preparedArrays) } amx_Release(m_Amx, realParams[i]); } + else if (m_ParamTypes[i] == FP_CELL_BYREF || m_ParamTypes[i] == FP_FLOAT_BYREF) + { + //copy back + cell *tmp = physAddrs[i]; + if (m_ParamTypes[i] == FP_CELL_BYREF) + { + memcpy(reinterpret_cast(params[i]), tmp, sizeof(cell)); + } + else + { + memcpy(reinterpret_cast(params[i]), tmp, sizeof(REAL)); + } + amx_Release(m_Amx, realParams[i]); + } } m_InExec = false; @@ -683,13 +745,26 @@ cell executeForwards(int id, ...) va_list argptr; va_start(argptr, id); + + ForwardParam param_type; for (int i = 0; i < paramsNum && i < FORWARD_MAX_PARAMS; ++i) { - if (g_forwards.getParamType(id, i) == FP_FLOAT) + param_type = g_forwards.getParamType(id, i); + if (param_type == FP_FLOAT) { REAL tmp = (REAL)va_arg(argptr, double); // floats get converted to doubles - params[i] = *(cell*)&tmp; + params[i] = amx_ftoc(tmp); + } + else if(param_type == FP_FLOAT_BYREF) + { + REAL *tmp = reinterpret_cast(va_arg(argptr, double*)); + params[i] = reinterpret_cast(tmp); + } + else if(param_type == FP_CELL_BYREF) + { + cell *tmp = reinterpret_cast(va_arg(argptr, cell*)); + params[i] = reinterpret_cast(tmp); } else params[i] = (cell)va_arg(argptr, cell); diff --git a/amxmodx/CForward.h b/amxmodx/CForward.h index 4065bbad..89596aaf 100755 --- a/amxmodx/CForward.h +++ b/amxmodx/CForward.h @@ -46,6 +46,8 @@ enum ForwardParam FP_STRING, // string FP_STRINGEX, // string; will be updated to the last function's value FP_ARRAY, // array; use the return value of prepareArray. + FP_CELL_BYREF, // cell; pass by reference + FP_FLOAT_BYREF, // float; pass by reference }; // for prepareArray diff --git a/amxmodx/amxmodx.cpp b/amxmodx/amxmodx.cpp index 9a06649b..53968f74 100755 --- a/amxmodx/amxmodx.cpp +++ b/amxmodx/amxmodx.cpp @@ -4118,9 +4118,13 @@ static cell AMX_NATIVE_CALL ExecuteForward(AMX *amx, cell *params) LogError(amx, AMX_ERR_NATIVE, "Expected %d parameters, got %d", g_forwards.getParamsNum(id), count-2); return 0; } + + ForwardParam param_type; + for (cell i=3; i<=count; i++) { - if (g_forwards.getParamType(id, i-3) == FP_STRING) + param_type = g_forwards.getParamType(id, i-3); + if (param_type == FP_STRING) { char *tmp = get_amxstring(amx, params[i], 0, len); cell num = len / sizeof(cell) + 1; @@ -4131,7 +4135,14 @@ static cell AMX_NATIVE_CALL ExecuteForward(AMX *amx, cell *params) } strcpy((char *)allots[i-3].phys_addr, tmp); ps[i-3] = (cell)allots[i-3].phys_addr; - } else { + } + else if (param_type == FP_CELL_BYREF) + { + cell *temp = get_amxaddr(amx, params[i]); + ps[i-3] = reinterpret_cast(temp); + } + else + { ps[i-3] = *get_amxaddr(amx, params[i]); } } diff --git a/plugins/include/amxconst.inc b/plugins/include/amxconst.inc index 96dfcd21..1207a500 100755 --- a/plugins/include/amxconst.inc +++ b/plugins/include/amxconst.inc @@ -403,6 +403,7 @@ enum #define FP_FLOAT 1 #define FP_STRING 2 #define FP_ARRAY 4 +#define FP_VAL_BYREF 5 //cell & float are handled in the same way /** * @endsection @@ -450,4 +451,4 @@ enum HashType Hash_Keccak_512 // Provides Keccak 512 bit hashing }; -#include // To keep backward compatibility \ No newline at end of file +#include // To keep backward compatibility diff --git a/plugins/testsuite/fwdreftest1.sma b/plugins/testsuite/fwdreftest1.sma new file mode 100644 index 00000000..a1096769 --- /dev/null +++ b/plugins/testsuite/fwdreftest1.sma @@ -0,0 +1,61 @@ +// vim: set ts=4 sw=4 tw=99 noet: +// +// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO"). +// Copyright (C) The AMX Mod X Development Team. +// +// This software is licensed under the GNU General Public License, version 3 or higher. +// Additional exceptions apply. For full license details, see LICENSE.txt or visit: +// https://alliedmods.net/amxmodx-license + +#include + +new g_hMultiForward; +new g_hOneForward; + +public plugin_init() +{ + register_plugin("Forward Test (Reference) (1)", "1.0", "Ni3znajomy"); + + g_hMultiForward = CreateMultiForward("multi_forward_reference", ET_IGNORE, FP_VAL_BYREF, FP_VAL_BYREF); + g_hOneForward = CreateOneForward(find_plugin_byfile("fwdreftest2.amxx"), "one_forward_reference", FP_VAL_BYREF, FP_VAL_BYREF); + + register_srvcmd("fwdref_multi_test", "cmdForwardRefMultiTest"); + register_srvcmd("fwdref_one_test", "cmdForwardRefOneTest"); +} + +public cmdForwardRefMultiTest() +{ + new sTestValue[10]; + + read_argv(1, sTestValue, charsmax(sTestValue)); + new iTestValue1 = str_to_num(sTestValue); + + read_argv(2, sTestValue, charsmax(sTestValue)); + new Float:fTestValue2 = str_to_float(sTestValue); + + server_print("PLUGIN1: MULTI FORWARD START: val1 = %i | val2 = %f", iTestValue1, fTestValue2); + new dump; + ExecuteForward(g_hMultiForward, dump, iTestValue1, fTestValue2); + server_print("PLUGIN1: MULTI FORWARD END: val1 = %i | val2 = %f", iTestValue1, fTestValue2); +} + +public cmdForwardRefOneTest() +{ + new sTestValue[10]; + + read_argv(1, sTestValue, charsmax(sTestValue)); + new iTestValue1 = str_to_num(sTestValue); + + read_argv(2, sTestValue, charsmax(sTestValue)); + new Float:fTestValue2 = str_to_float(sTestValue); + + server_print("PLUGIN1: ONE FORWARD START: val1 = %i | val2 = %f", iTestValue1, fTestValue2); + new dump; + ExecuteForward(g_hOneForward, dump, iTestValue1, fTestValue2); + server_print("PLUGIN1: ONE FORWARD END: val1 = %i | val2 = %f", iTestValue1, fTestValue2); +} + + + + + diff --git a/plugins/testsuite/fwdreftest2.sma b/plugins/testsuite/fwdreftest2.sma new file mode 100644 index 00000000..88da11c1 --- /dev/null +++ b/plugins/testsuite/fwdreftest2.sma @@ -0,0 +1,55 @@ +// vim: set ts=4 sw=4 tw=99 noet: +// +// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO"). +// Copyright (C) The AMX Mod X Development Team. +// +// This software is licensed under the GNU General Public License, version 3 or higher. +// Additional exceptions apply. For full license details, see LICENSE.txt or visit: +// https://alliedmods.net/amxmodx-license + +#include + +new g_iTestValue1 = 0 +new Float:g_fTestValue2 = 0.0; + +public plugin_init() +{ + register_plugin("Forward Test (Reference) (2)", "1.0", "Ni3znajomy"); + + register_srvcmd("fwdref_set_test_values", "cmdSetTestValues"); +} + +public cmdSetTestValues() +{ + new sTestValue[10]; + + read_argv(1, sTestValue, charsmax(sTestValue)); + g_iTestValue1 = str_to_num(sTestValue); + + read_argv(2, sTestValue, charsmax(sTestValue)); + g_fTestValue2 = str_to_float(sTestValue); + + server_print("PLUGIN2: TEST VALUES: val1 = %i | val2 = %f", g_iTestValue1, g_fTestValue2); +} + +public multi_forward_reference(&val1, &Float:val2) +{ + server_print("PLUGIN2: MULTI FORWARD START: val1 = %i | val2 = %f", val1, val2); + + val1 = g_iTestValue1; + val2 = g_fTestValue2; + + server_print("PLUGIN2: MULTI FORWARD END: val1 = %i | val2 = %f", val1, val2); +} + +public one_forward_reference(&val1, &Float:val2) +{ + server_print("PLUGIN2: ONE FORWARD START: val1 = %i | val2 = %f", val1, val2); + + val1 = g_iTestValue1; + val2 = g_fTestValue2; + + server_print("PLUGIN2: ONE FORWARD END: val1 = %i | val2 = %f", val1, val2); +} + + diff --git a/public/sdk/amxxmodule.h b/public/sdk/amxxmodule.h index 279d4f68..bdcddde4 100644 --- a/public/sdk/amxxmodule.h +++ b/public/sdk/amxxmodule.h @@ -2087,6 +2087,8 @@ enum ForwardParam FP_STRING, // string FP_STRINGEX, // string; will be updated to the last function's value FP_ARRAY, // array; use the return value of prepareArray. + FP_CELL_BYREF, // cell; pass by reference + FP_FLOAT_BYREF, // float; pass by reference }; enum PlayerProp