diff --git a/core/CellArray.h b/core/CellArray.h index 0e010aef..39e9197b 100644 --- a/core/CellArray.h +++ b/core/CellArray.h @@ -138,6 +138,17 @@ public: m_Size = count; return true; } + + CellArray *clone() + { + CellArray *array = new CellArray(m_BlockSize); + array->m_AllocSize = m_AllocSize; + array->m_Size = m_Size; + array->m_Data = (cell_t *)malloc(sizeof(cell_t) * m_BlockSize * m_AllocSize); + memcpy(array->m_Data, m_Data, sizeof(cell_t) * m_BlockSize * m_Size); + return array; + } + private: bool GrowIfNeeded(size_t count) { diff --git a/core/smn_adt_array.cpp b/core/smn_adt_array.cpp index f74f0566..a16fd479 100644 --- a/core/smn_adt_array.cpp +++ b/core/smn_adt_array.cpp @@ -484,6 +484,79 @@ static cell_t SwapArrayItems(IPluginContext *pContext, const cell_t *params) return 1; } +static cell_t CloneArray(IPluginContext *pContext, const cell_t *params) +{ + CellArray *oldArray; + HandleError err; + HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent); + + if ((err = g_HandleSys.ReadHandle(params[1], htCellArray, &sec, (void **)&oldArray)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err); + } + + CellArray *array = oldArray->clone(); + + Handle_t hndl = g_HandleSys.CreateHandle(htCellArray, array, pContext->GetIdentity(), g_pCoreIdent, NULL); + if (!hndl) + { + delete array; + } + + return hndl; +} + +static cell_t FindStringInArray(IPluginContext *pContext, const cell_t *params) +{ + CellArray *array; + HandleError err; + HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent); + + if ((err = g_HandleSys.ReadHandle(params[1], htCellArray, &sec, (void **)&array)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err); + } + + char *str; + pContext->LocalToString(params[2], &str); + + for (unsigned int i = 0; i < array->size(); i++) + { + const char *array_str = (const char *)array->at(i); + if (strcmp(str, array_str) == 0) + { + return (cell_t) i; + } + } + + return -1; +} + +static cell_t FindValueInArray(IPluginContext *pContext, const cell_t *params) +{ + CellArray *array; + HandleError err; + HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent); + + if ((err = g_HandleSys.ReadHandle(params[1], htCellArray, &sec, (void **)&array)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err); + } + + for (unsigned int i = 0; i < array->size(); i++) + { + if (params[2] == *array->at(i)) + { + return (cell_t) i; + } + } + + return -1; +} + REGISTER_NATIVES(cellArrayNatives) { {"ClearArray", ClearArray}, @@ -502,5 +575,8 @@ REGISTER_NATIVES(cellArrayNatives) {"SetArrayArray", SetArrayArray}, {"ShiftArrayUp", ShiftArrayUp}, {"SwapArrayItems", SwapArrayItems}, + {"CloneArray", CloneArray}, + {"FindStringInArray", FindStringInArray}, + {"FindValueInArray", FindValueInArray}, {NULL, NULL}, }; diff --git a/plugins/include/adt_array.inc b/plugins/include/adt_array.inc index 98db273d..e8e0f621 100644 --- a/plugins/include/adt_array.inc +++ b/plugins/include/adt_array.inc @@ -79,6 +79,17 @@ native Handle:CreateArray(blocksize=1, startsize=0); */ native ClearArray(Handle:array); +/** + * Clones an array, returning a new handle with the same size and data. This should NOT + * be confused with CloneHandle. This is a completely new handle with the same data but + * no relation to the original. You MUST close it. + * + * @param array Array handle to be cloned + * @return New handle to the cloned array object + * @error Invalid Handle + */ + native Handle:CloneArray(Handle:array); + /** * Resizes an array. If the size is smaller than the current size, * the array is truncated. @@ -250,25 +261,33 @@ native RemoveFromArray(Handle:array, index); native SwapArrayItems(Handle:array, index1, index2); /** - * Returns true is the supplied string exists within the supplied array. + * Returns the index for the first occurance of the provided string. If the string + * cannot be located, -1 will be returned. * * @param array Array Handle. * @param item String to search for - * @return True if found, false if not - * @error Invalid handle + * @return Array index, or -1 on failure + * @error Invalid Handle */ +native FindStringInArray(Handle:array, const String:item[]); + +/** + * Returns the index for the first occurance of the provided value. If the value + * cannot be located, -1 will be returned. + * + * @param array Array Handle. + * @param item Value to search for + * @return Array index, or -1 on failure + * @error Invalid Handle + */ +native FindValueInArray(Handle:array, item); + +/** + * Backwards compatible stock - Use FindStringInArray() + * @deprecated Replaced by FindStringInArray() + */ +#pragma deprecated Use FindStringInArray() instead stock bool:IsStringInArray(Handle:array, const String:item[]) { - decl String:curItem[64]; - - for (new i = 0; i < GetArraySize(array); i++) - { - GetArrayString(array, i, curItem, sizeof(curItem)); - if(strcmp(item, curItem, false) == 0) - { - return true; - } - } - - return false; -} + return (FindStringInArray(array, item) != -1); +} \ No newline at end of file diff --git a/plugins/include/helpers.inc b/plugins/include/helpers.inc index 8ba81d7f..5e6bbad1 100644 --- a/plugins/include/helpers.inc +++ b/plugins/include/helpers.inc @@ -275,6 +275,11 @@ stock FindTarget(client, const String:target[], bool:nobots = false, bool:immuni { continue; } + + if (FindStringInArray(array, buffer) != -1) + { + continue; + } PushArrayString(array, buffer); } diff --git a/plugins/mapchooser.sp b/plugins/mapchooser.sp index 04cd9708..4508c18b 100644 --- a/plugins/mapchooser.sp +++ b/plugins/mapchooser.sp @@ -83,9 +83,10 @@ public OnPluginStart() { LoadTranslations("mapchooser.phrases"); - g_MapList = CreateArray(33); - g_OldMapList = CreateArray(33); - g_NextMapList = CreateArray(33); + new arraySize = ByteCountToCells(33); + g_MapList = CreateArray(arraySize); + g_OldMapList = CreateArray(arraySize); + g_NextMapList = CreateArray(arraySize); g_TeamScores = CreateArray(2); g_Cvar_StartTime = CreateConVar("sm_mapvote_start", "3.0", "Specifies when to start the vote based on time remaining.", _, true, 1.0); @@ -512,31 +513,31 @@ CreateNextVote() ClearArray(g_NextMapList); } - new Handle:tempMaps = CreateArray(33); decl String:map[32]; - for (new i = 0; i < GetArraySize(g_MapList); i++) - { - GetArrayString(g_MapList, i, map, sizeof(map)); - PushArrayString(tempMaps, map); - } + new Handle:tempMaps = CloneArray(g_MapList); - if (GetArraySize(tempMaps) > GetConVarInt(g_Cvar_ExcludeMaps)) + if (GetConVarInt(g_Cvar_ExcludeMaps) && GetArraySize(tempMaps) > GetConVarInt(g_Cvar_ExcludeMaps)) { for (new i = 0; i < GetArraySize(g_OldMapList); i++) { GetArrayString(g_OldMapList, i, map, sizeof(map)); - for (new j = 0; j < GetArraySize(tempMaps); j++) + new index = FindStringInArray(tempMaps, map); + if (index != -1) { - decl String:temp[32]; - GetArrayString(tempMaps, j, temp, sizeof(temp)); - if (strcmp(temp, map) == 0) - { - RemoveFromArray(tempMaps, j); - break; - } + RemoveFromArray(tempMaps, index); } } } + else + { + // If we didn't check against ExcludeMaps, we have to remove the current map. + GetCurrentMap(map, sizeof(map)); + new index = FindStringInArray(tempMaps, map); + if (index != -1) + { + RemoveFromArray(tempMaps, index); + } + } new limit = (GetConVarInt(g_Cvar_IncludeMaps) < GetArraySize(tempMaps) ? GetConVarInt(g_Cvar_IncludeMaps) : GetArraySize(tempMaps)); for (new i = 0; i < limit; i++) diff --git a/plugins/randomcycle.sp b/plugins/randomcycle.sp index bbd7cda9..5d4137ca 100644 --- a/plugins/randomcycle.sp +++ b/plugins/randomcycle.sp @@ -53,8 +53,9 @@ new g_mapFileTime; public OnPluginStart() { - g_MapList = CreateArray(33); - g_OldMapList = CreateArray(33); + new arraySize = ByteCountToCells(33); + g_MapList = CreateArray(arraySize); + g_OldMapList = CreateArray(arraySize); g_Cvar_Mapfile = CreateConVar("sm_randomcycle_file", "configs/maps.ini", "Map file to use. (Def sourcemod/configs/maps.ini)"); g_Cvar_ExcludeMaps = CreateConVar("sm_randomcycle_exclude", "5", "Specifies how many past maps to exclude from the vote.", _, true, 0.0); @@ -83,7 +84,7 @@ public Action:Timer_RandomizeNextmap(Handle:timer) decl String:map[32]; new bool:oldMaps = false; - if (GetArraySize(g_MapList) > GetConVarInt(g_Cvar_ExcludeMaps)) + if (GetConVarInt(g_Cvar_ExcludeMaps) && GetArraySize(g_MapList) > GetConVarInt(g_Cvar_ExcludeMaps)) { oldMaps = true; } @@ -91,7 +92,7 @@ public Action:Timer_RandomizeNextmap(Handle:timer) new b = GetRandomInt(0, GetArraySize(g_MapList) - 1); GetArrayString(g_MapList, b, map, sizeof(map)); - while (oldMaps && IsStringInArray(g_OldMapList, map)) + while (oldMaps && FindStringInArray(g_OldMapList, map) != -1) { b = GetRandomInt(0, GetArraySize(g_MapList) - 1); GetArrayString(g_MapList, b, map, sizeof(map)); diff --git a/plugins/rockthevote.sp b/plugins/rockthevote.sp index ac822522..1e0d9ee0 100644 --- a/plugins/rockthevote.sp +++ b/plugins/rockthevote.sp @@ -71,8 +71,9 @@ public OnPluginStart() LoadTranslations("common.phrases"); LoadTranslations("rockthevote.phrases"); - g_MapList = CreateArray(33); - g_RTVMapList = CreateArray(33); + new arraySize = ByteCountToCells(33); + g_MapList = CreateArray(arraySize); + g_RTVMapList = CreateArray(arraySize); g_Cvar_Needed = CreateConVar("sm_rtv_needed", "0.60", "Percentage of players needed to rockthevote (Def 60%)", 0, true, 0.05, true, 1.0); g_Cvar_File = CreateConVar("sm_rtv_file", "configs/maps.ini", "Map file to use. (Def configs/maps.ini)"); @@ -161,23 +162,18 @@ public Action:Command_Addmap(client, args) decl String:mapname[64]; GetCmdArg(1, mapname, sizeof(mapname)); - if (!IsStringInArray(g_MapList, mapname)) + if (FindStringInArray(g_MapList, mapname) == -1) { ReplyToCommand(client, "%t", "Map was not found", mapname); return Plugin_Handled; } if (GetArraySize(g_RTVMapList) > 0) - { - for (new i = 0; i < GetArraySize(g_RTVMapList); i++) - { - decl String:nextmap[64]; - GetArrayString(g_RTVMapList, i, nextmap, sizeof(nextmap)); - if (strcmp(mapname, nextmap, false) == 0) - { - ReplyToCommand(client, "%t", "Map Already In Vote", mapname); - return Plugin_Handled; - } + { + if (FindStringInArray(g_RTVMapList, mapname) != -1) + { + ReplyToCommand(client, "%t", "Map Already In Vote", mapname); + return Plugin_Handled; } ShiftArrayUp(g_RTVMapList, 0); @@ -336,13 +332,8 @@ public Action:Timer_StartRTV(Handle:timer) new Handle:MapVoteMenu = CreateMenu(Handler_MapMapVoteMenu, MenuAction:MENU_ACTIONS_ALL); SetMenuTitle(MapVoteMenu, "Rock The Vote"); - new Handle:tempMaps = CreateArray(33); + new Handle:tempMaps = CloneArray(g_MapList); decl String:map[32]; - for (new i = 0; i < GetArraySize(g_MapList); i++) - { - GetArrayString(g_MapList, i, map, sizeof(map)); - PushArrayString(tempMaps, map); - } // We assume that g_RTVMapList is within the correct limits, based on the logic for nominations for (new i = 0; i < GetArraySize(g_RTVMapList); i++) @@ -350,15 +341,10 @@ public Action:Timer_StartRTV(Handle:timer) GetArrayString(g_RTVMapList, i, map, sizeof(map)); AddMenuItem(MapVoteMenu, map, map); - for (new j = 0; j < GetArraySize(tempMaps); j++) + new index = FindStringInArray(tempMaps, map); + if (index != -1) { - decl String:temp[32]; - GetArrayString(tempMaps, j, temp, sizeof(temp)); - if (strcmp(map, temp) == 0) - { - RemoveFromArray(tempMaps, j); - break; - } + RemoveFromArray(tempMaps, index); } } @@ -489,7 +475,7 @@ public Handler_MapSelectMenu(Handle:menu, MenuAction:action, param1, param2) decl String:map[64], String:name[64]; GetMenuItem(menu, param2, map, sizeof(map)); - if (IsStringInArray(g_RTVMapList, map)) + if (FindStringInArray(g_RTVMapList, map) != -1) { PrintToChat(param1, "[SM] %t", "Map Already Nominated"); return;