Склад полезного кода [Source]

Сообщения
443
Реакции
316
Помог
13 раз(а)
Выглядит.
А стека используется больше.
 
Сообщения
10
Реакции
12
Shel, к сожалению, быть может Вы можете предложить более эффективную альтернативу?
 
Сообщения
202
Реакции
421
Помог
10 раз(а)
Ну, собственно, я сразу написал ему, что алгоритм не оч оптимален:
1586156879278.png
Мы тут в первую очередь за читаемостью кода гонимся, а не за оптимальностью расходования памяти и пр.. Это всё подождёт.
 
Сообщения
1,488
Реакции
1,325
Помог
22 раз(а)
А зачем цикл наоборот?
 
Сообщения
202
Реакции
421
Помог
10 раз(а)
В моём случае было так, что, как правило, искомое значение было где-то сзади, а не спереди. Потому для себя я так делал.
Если кому действительно нужен будет этот сток - переделает, не проблема.
 
Сообщения
443
Реакции
316
Помог
13 раз(а)
Предложить не могу, не особо знаком с sourcepawn ВМ, замечание было сделано лишь в сторону работы с памятью, память vs читаемость (которую ты поставил на первое место) - память.
 
Сообщения
2,596
Реакции
2,773
Помог
57 раз(а)
C++:
#include <sourcemod>
#include <cstrike>

public void OnPluginStart()
{
    int aPlayers[MAXPLAYERS], count;

    get_players(aPlayers, count);
    // or
    get_playersnum_ex(GetPlayers_ExcludeBots);
    // or
    get_playersnum();
}
 
enum GetPlayersFlags (<<=1) {
    GetPlayers_None = 0,
    GetPlayers_ExcludeDead = 1,
    GetPlayers_ExcludeAlive,
    GetPlayers_ExcludeBots,
    GetPlayers_ExcludeHuman,
    GetPlayers_MatchTeam,
    GetPlayers_MatchNameSubstring,
    GetPlayers_CaseInsensitive,
    GetPlayers_ExcludeHLTV,
    GetPlayers_IncludeConnecting
}


/**
 * Returns the number of clients on the server.
 *
 * @param flag      Count clients still in the connecting process if nonzero
 *
 * @return          Number of clients on the server
 */
stock int get_playersnum(int flag = 0) {
    int num = 0;

    for (int i = 1; i <= MaxClients; i++) {
        if (IsClientConnected(i) || (flag && IsClientInGame(i)) {
            num++;
        }
    }

    return num;
}

/**
 * Stores a filtered list of client indexes to an array.
 *
 * @note Example retrieving all alive CTs:
 *       get_players_ex(players, num, GetPlayers_ExcludeDead | GetPlayers_MatchTeam, "CT")
 *
 * @param players   Array to store indexes to
 * @param num       Variable to store number of indexes to
 * @param flags     Optional filtering flags (enum GetPlayersFlags); valid flags are:
 *                    GetPlayers_None - No filter (Default)
 *                    GetPlayers_ExcludeDead - do not include dead clients
 *                    GetPlayers_ExcludeAlive - do not include alive clients
 *                    GetPlayers_ExcludeBots - do not include bots
 *                    GetPlayers_ExcludeHuman - do not include human clients
 *                    GetPlayers_MatchTeam - match with team
 *                    GetPlayers_MatchNameSubstring - match with part of name
 *                    GetPlayers_CaseInsensitive - match case insensitive
 *                    GetPlayers_ExcludeHLTV - do not include SourceTV proxies
 *                    GetPlayers_IncludeConnecting - include connecting clients
 * @param team      String to match against if the "MatchTeam" or "GetPlayers_MatchNameSubstring" flag is specified
 *
 * @noreturn
 */
stock void get_players(int players[MAXPLAYERS] = {}, int &num, GetPlayersFlags flags = GetPlayers_None, const char[] buffer = "") {
    int team = CS_TEAM_NONE;
    char name[MAX_NAME_LENGTH];
    
    if (flags & GetPlayers_MatchTeam) {
        team = TeamFromName(buffer, !(flags & GetPlayers_CaseInsensitive));
    }

    for (int i = 1; i <= MaxClients; i++) {
        if (IsClientConnected(i) || ((flags & GetPlayers_IncludeConnecting) && IsClientInGame(i))) {
            if (IsPlayerAlive(i) ? (flags & GetPlayers_ExcludeAlive) : (flags & GetPlayers_ExcludeDead))
                continue;
            if (IsFakeClient(i) ? (flags & GetPlayers_ExcludeBots) : (flags & GetPlayers_ExcludeHuman))
                continue;
            if ((flags & GetPlayers_MatchTeam) && GetClientTeam(i) != team)
                continue;
            if ((flags & GetPlayers_ExcludeHLTV) && IsClientSourceTV(i))
                continue;
            if (flags & GetPlayers_MatchNameSubstring) {
                GetClientName(i, name, sizeof name);

                if (!StrContains(buffer, name, !(flags & GetPlayers_CaseInsensitive)))
                    continue;
            }

            players[num++] = i;
        }
    }
}

/**
 * Returns the number of clients on the server that match the specified flags.
 *
 * @note Example retrieving all alive CTs:
 *       new AliveCt = get_playersnum_ex(GetPlayers_ExcludeDead | GetPlayers_MatchTeam, "CT")
 *
 * @param flags     Optional filtering flags (enum GetPlayersFlags); valid flags are:
 *                    GetPlayers_None - No filter (Default)
 *                    GetPlayers_ExcludeDead - do not include dead clients
 *                    GetPlayers_ExcludeAlive - do not include alive clients
 *                    GetPlayers_ExcludeBots - do not include bots
 *                    GetPlayers_ExcludeHuman - do not include human clients
 *                    GetPlayers_MatchTeam - match with team
 *                    GetPlayers_MatchNameSubstring - match with part of name
 *                    GetPlayers_CaseInsensitive - match case insensitive
 *                    GetPlayers_ExcludeHLTV - do not include SourceTV proxies
 *                    GetPlayers_IncludeConnecting - include connecting clients
 * @param team      String to match against if the GetPlayers_MatchTeam or GetPlayers_MatchNameSubstring flag is specified
 *
 * @return          Number of clients on the server that match the specified flags
 */
stock int get_playersnum_ex(GetPlayersFlags flags = GetPlayers_None, const char[] buffer = "") {
    int players[MAXPLAYERS], num;
    get_players_ex(_, num, flags, buffer);
    return num;
}

stock int TeamFromName(const char[] team, bool caseSensitive = true) {
    if(strcmp(team, "TERRORIST", caseSensitive) == 0)
        return CS_TEAM_T;
    if(strcmp(team, "СT", caseSensitive) == 0)
        return CS_TEAM_CT;
    if(strcmp(team, "SPECTATOR", caseSensitive) == 0)
        return CS_TEAM_SPECTATOR;
    
    return CS_TEAM_NONE;
}
 
Сообщения
202
Реакции
421
Помог
10 раз(а)
Подготавливая апдейт для своего ядра демок, и в очередной раз "задрючившись" не забывать закрывать хендлы жсонов, придумал небольшой сток. Чистоты кода ради - он тут же возвращает переданный на него хендл.
C-like:
/**
 * Requests the closing handle in next frame and returns passed handle.
 *
 * @param     hHandle   Handle for lazy closing.
 * @return              Passed handle.
 */
stock Handle LazyCloseHandle(Handle hHandle)
{
  if (hHandle)
  {
    RequestFrame(OnHandleShouldBeClosed, hHandle);
  }

  return hHandle;
}

static void OnHandleShouldBeClosed(Handle hHndl)
{
  hHndl.Close();
}
Идея заключается в том, чтобы "запланировать закрытие хендла" в следующем кадре (т.е. когда-то после завершения выполнения функции). Это не подходит для ситуаций, когда одна функция создаёт единомоментно - много хендлов (больше 5000, например), но там и сам Сурсмод, на самом деле, "разозлится" на частое создание и удаление хендлов, и выгрузит плагин. [OFF]У меня кстати СМ в этом плане странно работает: он выгружает не всегда тот плагин, который делал много хендлов; иногда просто рандомный берёт и убивает. Баг?..[/OFF]
Ну и коротенький пример, как это можно использовать: есть натив, который записывает какие-то данные в JSON-массив, который достаётся из JSON-объекта. Кто работал с рипом - знает, что любая попытка достать JSON-объект или массив, создаёт хендл для него, что заставляет постоянно следить за этим.
C-like:
/**
 * Params for this native:
 * -> szEventName (string const)
 * -> hMetaData (StringMap)
 */
public int API_TriggerEvent(Handle hPlugin, int iNumParams) {
  if (!g_bRecording)
    return; //ignore this event.

  char szEventName[64];
  GetNativeString(1, szEventName, sizeof(szEventName));

  StringMap hEventData = GetNativeCell(2);
  if (hEventData) {
    hEventData = view_as<StringMap>(UTIL_LazyCloseHandle(CloneHandle(hEventData, g_hCorePlugin)));
  }

  any data = (iNumParams < 3 ? 0 : GetNativeCell(3));
  if (!UTIL_TriggerEventListeners(szEventName, sizeof(szEventName), hEventData, data))
  {
    return;
  }

  JSONArray hEvents = view_as<JSONArray>(UTIL_LazyCloseHandle(g_hMetaInfo.Get("events")));
  JSONObject hEvent = view_as<JSONObject>(UTIL_LazyCloseHandle(new JSONObject()));
  hEvent.SetInt("time", GetTime());
  hEvent.SetInt("tick", SourceTV_GetRecordingTick());
  hEvent.SetString("event_name", szEventName);
  hEvent.Set("data", view_as<JSON>(UTIL_LazyCloseHandle(UTIL_StringMapToJSON(hEventData))));
  hEvents.Push(hEvent);
}
Ну и для сравнения, этот же код, но без этого стока:
C-like:
/**
 * Params for this native:
 * -> szEventName (string const)
 * -> hMetaData (StringMap)
 */
public int API_TriggerEvent(Handle hPlugin, int iNumParams) {
  if (!g_bRecording)
    return; //ignore this event.

  char szEventName[64];
  GetNativeString(1, szEventName, sizeof(szEventName));

  StringMap hEventData = GetNativeCell(2);
  if (hEventData) {
    hEventData = view_as<StringMap>(CloneHandle(hEventData, g_hCorePlugin));
  }

  any data = (iNumParams < 3 ? 0 : GetNativeCell(3));
  if (!UTIL_TriggerEventListeners(szEventName, sizeof(szEventName), hEventData, data))
  {
    hEventData.Close();
    return;
  }

  JSONArray hEvents = view_as<JSONArray>(g_hMetaInfo.Get("events"));
  JSONObject hEvent = view_as<JSONObject>(new JSONObject());
  JSONObject hEventDataJSON = UTIL_StringMapToJSON(hEventData);

  hEvent.SetInt("time", GetTime());
  hEvent.SetInt("tick", SourceTV_GetRecordingTick());
  hEvent.SetString("event_name", szEventName);
  hEvent.Set("data", hEventDataJSON);
  hEvents.Push(hEvent);

  hEventDataJSON.Close();
  hEventData.Close();
  hEvents.Close();
  hEvent.Close();
}
 

Пользователи, просматривающие эту тему

Сейчас на форуме нет ни одного пользователя.
Сверху Снизу