Нужна помощь с кодом

Besais

Участник
Сообщения
26
Реакции
0
Решил написать плагин для ножевых раундов на основе NoZoom Rounds Voting, но есть баг из-за которого ножевые раунды начинаются и заканчиваются на 1 раунд позже. Как это можно исправить?

krv.sp:
#pragma semicolon 1

#include <sourcemod>
#include <sdkhooks>
#include <sdktools>
#include <csgo_colors>

#undef REQUIRE_PLUGIN

#pragma newdecls required

int g_iRounds, g_iCooldown, g_iPercent;

bool g_bKR, g_bVoted[MAXPLAYERS+1];
int g_iKRounds, g_iVotes, g_iTarget;
char g_sPrefix[32];

ConVar g_hCvar[4];

public Plugin myinfo =
{
    name    = "Knife Rounds Voting",
    author    = "Besais",
    version = "1.0",
    url = ""
};

public void OnPluginStart()
{
    RegConsoleCmd("sm_kr", OnVoteCmd);
    
    HookEvent("round_start", OnRoundStart);
    HookEvent("player_spawn", OnPlayerSpawn);
    

    g_hCvar[0] = CreateConVar("sm_krv_rounds", "4", "Количество ножевых раундов после успешного голосования.");
    g_hCvar[1] = CreateConVar("sm_krv_cooldown_rounds", "4", "Количество раундов между голосованиями.");
    g_hCvar[2] = CreateConVar("sm_krv_voting_percent", "50", "Процент от всех игроков, требуемый для начала ножевых раундов.");
    g_hCvar[3] = CreateConVar("sm_krv_chat_prefix", "{green}[KRV]{default}", "Префикс плагина в чате.");

    AutoExecConfig(true, "krv");
    LoadTranslations("krv.phrases");
}

public void OnConfigsExecuted()
{
    g_iRounds = GetConVarInt(g_hCvar[0]);
    g_iCooldown = GetConVarInt(g_hCvar[1]);
    g_iPercent = GetConVarInt(g_hCvar[2]);
    GetConVarString(g_hCvar[3], g_sPrefix, sizeof(g_sPrefix));
}

public void OnMapStart()
{
    g_iTarget = g_iCooldown;
}

public void OnClientDisconnect(int client)
{
    if(g_bVoted[client])
    {
        g_bVoted[client] = false;
        --g_iVotes;
    }   
}

public Action OnPlayerSpawn(Event hEvent, const char[] sName, bool bDontBroadcast)
{
    if(g_bKR)
    {
    int iClient = GetClientOfUserId(hEvent.GetInt("userid"));
    int Weapon_Slot;
    for (int i = 0; i < 5; i++)
    {   
        if ((Weapon_Slot = GetPlayerWeaponSlot(iClient, i)) > 0 && RemovePlayerItem(iClient, Weapon_Slot))
        {
            AcceptEntityInput(Weapon_Slot, "Kill");
        }

    }
    GivePlayerItem(iClient, "weapon_knife");
    }
    return Plugin_Continue;
}
    
public Action OnVoteCmd(int client, int args)
{
    if(client)
    {
        if(!g_bKR)
        {
            int need = RoundToCeil(float(GetClientCount(true)) * (float(g_iPercent) / 100.0));
            
            if(g_iVotes < need)
            {
                int rounds = GameRules_GetProp("m_totalRoundsPlayed");
                
                if(g_iTarget <= rounds)
                {
                    if(!g_bVoted[client])
                    {
                        ++g_iVotes;
                        g_bVoted[client] = true;
                        CGOPrintToChatAll("%s{default} %t", g_sPrefix, "vote msg", client, g_iVotes, need);
                    }
                    else CGOPrintToChat(client, "%s{default} %t", g_sPrefix, "already voted");
                    
                    if(g_iVotes >= need) CGOPrintToChatAll("%s{default} %t", g_sPrefix, "next round alert");
                }
                else CGOPrintToChat(client, "%s{default} %t", g_sPrefix, "cooldown alert", g_iTarget - rounds);
            }
            else CGOPrintToChat(client, "%s{default} %t", g_sPrefix, "enough votes");
        }
        else CGOPrintToChat(client, "%s{default} %t", g_sPrefix, "already happening");
    }
    return Plugin_Handled;
}

public void OnRoundStart(Event hEvent, const char[] name, bool dontBroadcast)
{
    if(!g_bKR)
    {
        if(g_iVotes >= RoundToCeil(float(GetClientCount(true)) * (float(g_iPercent) / 100.0)))
        {
            g_bKR = true;
        }
        
        int rounds = GameRules_GetProp("m_totalRoundsPlayed");
        
        if(g_iTarget - g_iCooldown > rounds)
            g_iTarget = g_iCooldown;
    }
    
    if(g_iKRounds >= g_iRounds)
    {
        g_bKR = false;
        g_iKRounds = g_iVotes = 0;

        for (int i = 1; i <= MaxClients; ++i)   
            if (IsClientInGame(i))
                g_bVoted[i] = false;
        
        if(g_iCooldown)
            g_iTarget = GameRules_GetProp("m_totalRoundsPlayed") + g_iCooldown;
        
        CGOPrintToChatAll("%s{default} %t", g_sPrefix, "battle end");
    }
    
    if(g_bKR)
    {
        ++g_iKRounds;
        CGOPrintToChatAll("%s{default} %t", g_sPrefix, "round start alert");
    }
}
 

DarkerZ

Участник
Сообщения
394
Реакции
175
Предположу, что событие спавна игрока срабатывает до старта раунда. round_end...
 

MrEvgen

Участник
Сообщения
117
Реакции
38
Решил написать плагин для ножевых раундов на основе NoZoom Rounds Voting, но есть баг из-за которого ножевые раунды начинаются и заканчиваются на 1 раунд позже. Как это можно исправить?

krv.sp:
#pragma semicolon 1

#include <sourcemod>
#include <sdkhooks>
#include <sdktools>
#include <csgo_colors>

#undef REQUIRE_PLUGIN

#pragma newdecls required

int g_iRounds, g_iCooldown, g_iPercent;

bool g_bKR, g_bVoted[MAXPLAYERS+1];
int g_iKRounds, g_iVotes, g_iTarget;
char g_sPrefix[32];

ConVar g_hCvar[4];

public Plugin myinfo =
{
    name    = "Knife Rounds Voting",
    author    = "Besais",
    version = "1.0",
    url = ""
};

public void OnPluginStart()
{
    RegConsoleCmd("sm_kr", OnVoteCmd);
   
    HookEvent("round_start", OnRoundStart);
    HookEvent("player_spawn", OnPlayerSpawn);
   

    g_hCvar[0] = CreateConVar("sm_krv_rounds", "4", "Количество ножевых раундов после успешного голосования.");
    g_hCvar[1] = CreateConVar("sm_krv_cooldown_rounds", "4", "Количество раундов между голосованиями.");
    g_hCvar[2] = CreateConVar("sm_krv_voting_percent", "50", "Процент от всех игроков, требуемый для начала ножевых раундов.");
    g_hCvar[3] = CreateConVar("sm_krv_chat_prefix", "{green}[KRV]{default}", "Префикс плагина в чате.");

    AutoExecConfig(true, "krv");
    LoadTranslations("krv.phrases");
}

public void OnConfigsExecuted()
{
    g_iRounds = GetConVarInt(g_hCvar[0]);
    g_iCooldown = GetConVarInt(g_hCvar[1]);
    g_iPercent = GetConVarInt(g_hCvar[2]);
    GetConVarString(g_hCvar[3], g_sPrefix, sizeof(g_sPrefix));
}

public void OnMapStart()
{
    g_iTarget = g_iCooldown;
}

public void OnClientDisconnect(int client)
{
    if(g_bVoted[client])
    {
        g_bVoted[client] = false;
        --g_iVotes;
    }  
}

public Action OnPlayerSpawn(Event hEvent, const char[] sName, bool bDontBroadcast)
{
    if(g_bKR)
    {
    int iClient = GetClientOfUserId(hEvent.GetInt("userid"));
    int Weapon_Slot;
    for (int i = 0; i < 5; i++)
    {  
        if ((Weapon_Slot = GetPlayerWeaponSlot(iClient, i)) > 0 && RemovePlayerItem(iClient, Weapon_Slot))
        {
            AcceptEntityInput(Weapon_Slot, "Kill");
        }

    }
    GivePlayerItem(iClient, "weapon_knife");
    }
    return Plugin_Continue;
}
   
public Action OnVoteCmd(int client, int args)
{
    if(client)
    {
        if(!g_bKR)
        {
            int need = RoundToCeil(float(GetClientCount(true)) * (float(g_iPercent) / 100.0));
           
            if(g_iVotes < need)
            {
                int rounds = GameRules_GetProp("m_totalRoundsPlayed");
               
                if(g_iTarget <= rounds)
                {
                    if(!g_bVoted[client])
                    {
                        ++g_iVotes;
                        g_bVoted[client] = true;
                        CGOPrintToChatAll("%s{default} %t", g_sPrefix, "vote msg", client, g_iVotes, need);
                    }
                    else CGOPrintToChat(client, "%s{default} %t", g_sPrefix, "already voted");
                   
                    if(g_iVotes >= need) CGOPrintToChatAll("%s{default} %t", g_sPrefix, "next round alert");
                }
                else CGOPrintToChat(client, "%s{default} %t", g_sPrefix, "cooldown alert", g_iTarget - rounds);
            }
            else CGOPrintToChat(client, "%s{default} %t", g_sPrefix, "enough votes");
        }
        else CGOPrintToChat(client, "%s{default} %t", g_sPrefix, "already happening");
    }
    return Plugin_Handled;
}

public void OnRoundStart(Event hEvent, const char[] name, bool dontBroadcast)
{
    if(!g_bKR)
    {
        if(g_iVotes >= RoundToCeil(float(GetClientCount(true)) * (float(g_iPercent) / 100.0)))
        {
            g_bKR = true;
        }
       
        int rounds = GameRules_GetProp("m_totalRoundsPlayed");
       
        if(g_iTarget - g_iCooldown > rounds)
            g_iTarget = g_iCooldown;
    }
   
    if(g_iKRounds >= g_iRounds)
    {
        g_bKR = false;
        g_iKRounds = g_iVotes = 0;

        for (int i = 1; i <= MaxClients; ++i)  
            if (IsClientInGame(i))
                g_bVoted[i] = false;
       
        if(g_iCooldown)
            g_iTarget = GameRules_GetProp("m_totalRoundsPlayed") + g_iCooldown;
       
        CGOPrintToChatAll("%s{default} %t", g_sPrefix, "battle end");
    }
   
    if(g_bKR)
    {
        ++g_iKRounds;
        CGOPrintToChatAll("%s{default} %t", g_sPrefix, "round start alert");
    }
}
OnPlayerSpawn срабатывает раньше чем у игрока появляется оружие, я бы добавил таймер
 

Grey83

не пишу плагины с весны 2022
Сообщения
8,519
Реакции
4,979
емнип, событие спавна игрока происходит до события начала раунда, как выше написали (в некоторых играх событие спавна вообще 2 раза происходило в начале раунда и мне в плагинах это приходилось учитывать)

сделай тестовый плагин, который будет писать в консоль сервера какое событие происходит (из необходимых тебе) и будешь знать какое лучше отлавливать и как их учитывать
Сообщения автоматически склеены:

@MrEvgen, таймера достаточно на 0.1 секунды, емнип
ещё можно просто с помощью SDKHooks отловить получение оружия игроком (ну и переключение м/у ними)
 

Besais

Участник
Сообщения
26
Реакции
0
емнип, событие спавна игрока происходит до события начала раунда, как выше написали (в некоторых играх событие спавна вообще 2 раза происходило в начале раунда и мне в плагинах это приходилось учитывать)

сделай тестовый плагин, который будет писать в консоль сервера какое событие происходит (из необходимых тебе) и будешь знать какое лучше отлавливать и как их учитывать
Сообщения автоматически склеены:

@MrEvgen, таймера достаточно на 0.1 секунды, емнип
ещё можно просто с помощью SDKHooks отловить получение оружия игроком (ну и переключение м/у ними)
Попробовал сделать таймер
C-подобный:
public Action OnPlayerSpawn(Event hEvent, const char[] sName, bool bDontBroadcast)
{
    if(g_bKR)
    {
        CreateTimer(0.1, RemoveWeapons);
    }
    return Plugin_Continue;
}

public Action RemoveWeapons(Handle timer, int userid)
{
    int iClient = GetClientOfUserId(userid);
    int Weapon_Slot;
    for (int i = 0; i < 5; i++)
    {   
        if ((Weapon_Slot = GetPlayerWeaponSlot(iClient, i)) > 0 && RemovePlayerItem(iClient, Weapon_Slot))
        {
            AcceptEntityInput(Weapon_Slot, "Kill");
        }
    }
    GivePlayerItem(iClient, "weapon_knife");
    return Plugin_Continue;
}
теперь в консоли спамит этим
L 12/10/2022 - 12:05:36: [SM] Exception reported: Entity index 0 is not a valid client
L 12/10/2022 - 12:05:36: [SM] Blaming: krv.smx
L 12/10/2022 - 12:05:36: [SM] Call stack trace:
L 12/10/2022 - 12:05:36: [SM] [0] GetPlayerWeaponSlot
L 12/10/2022 - 12:05:36: [SM] [1] Line 153, D:\Games\csgo server\csgo\addons\sourcemod\scripting\krv.sp::RemoveWeapons
 

Palonez

бб братки
Сообщения
3,035
Реакции
1,837
Попробовал сделать таймер
C-подобный:
public Action OnPlayerSpawn(Event hEvent, const char[] sName, bool bDontBroadcast)
{
    if(g_bKR)
    {
        CreateTimer(0.1, RemoveWeapons);
    }
    return Plugin_Continue;
}

public Action RemoveWeapons(Handle timer, int userid)
{
    int iClient = GetClientOfUserId(userid);
    int Weapon_Slot;
    for (int i = 0; i < 5; i++)
    {
        if ((Weapon_Slot = GetPlayerWeaponSlot(iClient, i)) > 0 && RemovePlayerItem(iClient, Weapon_Slot))
        {
            AcceptEntityInput(Weapon_Slot, "Kill");
        }
    }
    GivePlayerItem(iClient, "weapon_knife");
    return Plugin_Continue;
}
теперь в консоли спамит этим
L 12/10/2022 - 12:05:36: [SM] Exception reported: Entity index 0 is not a valid client
L 12/10/2022 - 12:05:36: [SM] Blaming: krv.smx
L 12/10/2022 - 12:05:36: [SM] Call stack trace:
L 12/10/2022 - 12:05:36: [SM] [0] GetPlayerWeaponSlot
L 12/10/2022 - 12:05:36: [SM] [1] Line 153, D:\Games\csgo server\csgo\addons\sourcemod\scripting\krv.sp::RemoveWeapons
C-подобный:
public void OnPlayerSpawn(Event hEvent, const char[] sName, bool bDontBroadcast)
{
    int client = GetClientOfUserId(hEvent.GetInt("userid"));
    if(0 < client <= MaxClients) if(g_bKR) CreateTimer(0.1, RemoveWeapons, client);
}

public Action RemoveWeapons(Handle hTimer, int client)
{
    for (int i = 0; i < 5; i++)
    {
        int Weapon_Slot = GetPlayerWeaponSlot(client, i);
        if(Weapon_Slot != -1 && IsValidEntity(Weapon_Slot))
        {
            RemovePlayerItem(client, Weapon_Slot);
            AcceptEntityInput(Weapon_Slot, "Kill");
        }
    }
    GivePlayerItem(client, "weapon_knife");
    return Plugin_Continue;
}
 
Последнее редактирование:

Besais

Участник
Сообщения
26
Реакции
0
C-подобный:
public void OnPlayerSpawn(Event hEvent, const char[] sName, bool bDontBroadcast)
{
    int client = GetClientOfUserId(hEvent.GetInt("userid"));
    if(0 < client <= MaxClients) if(g_bKR) CreateTimer(0.1, RemoveWeapons, client);
}

public Action RemoveWeapons(Handle hTimer, int client)
{
    for (int i = 0; i < 5; i++)
    {
        int Weapon_Slot = GetPlayerWeaponSlot(client, i);
        if(Weapon_Slot != -1 && IsValidEntity(Weapon_Slot))
        {
            RemovePlayerItem(client, Weapon_Slot);
            AcceptEntityInput(Weapon_Slot, "Kill");
        }
    }
    GivePlayerItem(client, "weapon_knife");
    return Plugin_Continue;
}
Не забирает оружие
 

Svyatoy

Участник
Сообщения
335
Реакции
137
Не забирает оружие
Вырезал части кода, которые использую лично - попробуй так
Sourcepawn:
// Глобальная переменная
int m_hMyWeapons;

// OnPluginStart()
m_hMyWeapons = FindSendPropInfo("CBasePlayer", "m_hMyWeapons");
HookEvent("player_spawn", OnPlayerSpawn, EventHookMode_Post);

// Функции
stock void OnPlayerSpawn(Event hEvent, const char[] sEvName, bool bDontBroadcast)
{
    if(g_bKR)
    {
        CreateTimer(0.1, Timer_ClearWeapons, hEvent.GetInt("userid"), TIMER_FLAG_NO_MAPCHANGE);
    }
}

stock Action Timer_ClearWeapons(Handle hTimer, int iUserID)
{
    ClearPlayerWeapons(GetClientOfUserId(iUserID));

    return Plugin_Handled;
}

stock bool ClearPlayerWeapons(int iClient)
{
    if(!IsValidClient(iClient, true))
        return false;

    for(new i = 0, iWeaponIndex = -1; i < 188; i += 4)
    {
        iWeaponIndex = GetEntDataEnt2(iClient, m_hMyWeapons + i);
        if(iWeaponIndex < 1)
             continue;

        RemovePlayerItem(iClient, iWeaponIndex);
        AcceptEntityInput(iWeaponIndex, "KillHierarchy");
    }

    GivePlayerItem(iClient, "weapon_knife");

    return true;
}

stock bool IsValidClient(int iClient, bool bClientAlive = false)
{
    bool bReturnValue = false;

    if(iClient > 0 && iClient < MaxClients+1 && IsClientInGame(iClient) && !IsFakeClient(iClient))
        bReturnValue = true;

    if(bReturnValue && bClientAlive)
        bReturnValue = IsPlayerAlive(iClient) ? true : false;

    return bReturnValue;
}
UPD: Понял, что напрасно вырезал проверку "живости" игрока и вернул её в IsValidClient. Ну а вдруг он умрёт за 0.1 сек :) И добавил return в таймер...
 
Последнее редактирование:

Grey83

не пишу плагины с весны 2022
Сообщения
8,519
Реакции
4,979
теперь в консоли спамит этим
L 12/10/2022 - 12:05:36: [SM] Exception reported: Entity index 0 is not a valid client
Ты забыл передавать таймеру UserID игрока.
5-я строка: CreateTimer(0.1, RemoveWeapons); ==> CreateTimer(0.1, RemoveWeapons, hEvent.GetInt("userid"));
Сообщения автоматически склеены:

@Palonez, у тебя так гранаты не будет забирать, если их больше одной. =)
Сообщения автоматически склеены:

C-подобный:
stock bool IsValidClient(int iClient)
{
    if(iClient > 0 && iClient <= MaxClients && IsClientInGame(iClient))
        return true;
    return false;
}
это выглядит как
C-подобный:
stock bool IsSomething(int value)
{
    if(true)
        return true;
    return false;
}
Сообщения автоматически склеены:

@Besais, вот код с пофикшеным таймером (начало ножевого раунда вроде не фиксилось).
 

Вложения

  • knife_rounds_voting 1.0_fix.sp
    4.1 КБ · Просмотры: 12
Последнее редактирование:

Grey83

не пишу плагины с весны 2022
Сообщения
8,519
Реакции
4,979
@Svyatoy, если true, то вернуть true, иначе вернуть false.
Какие тут нужны аргументы? 🤔

Если не понял, то продолжай говнокодить и не задумывайся. 😏
 

Svyatoy

Участник
Сообщения
335
Реакции
137
@Svyatoy, если true, то вернуть true, иначе вернуть false.
Какие тут нужны аргументы? 🤔

Если не понял, то продолжай говнокодить и не задумывайся. 😏
Человек явно новичок в этом деле и, наверняка, он будет использовать данные ему функции в других плагинах. В чём именно проблема проверки валидности клиента? Она не заточена только на проверку после получения из UserID, как в вашем случае. Это универсальная функция, которая подходит даже для банального цикла перебора.
 

Besais

Участник
Сообщения
26
Реакции
0
Ты забыл передавать таймеру UserID игрока.
5-я строка: CreateTimer(0.1, RemoveWeapons); ==> CreateTimer(0.1, RemoveWeapons, hEvent.GetInt("userid"));
Сообщения автоматически склеены:

@Palonez, у тебя так гранаты не будет забирать, если их больше одной. =)
Сообщения автоматически склеены:

это выглядит как
C-подобный:
stock bool IsSomething(int value)
{
    if(true)
        return true;
    return false;
}
Сообщения автоматически склеены:

@Besais, вот код с пофикшеным таймером (начало ножевого раунда вроде не фиксилось).
В чём ещё может быть проблема?
 

Grey83

не пишу плагины с весны 2022
Сообщения
8,519
Реакции
4,979
@Besais, моя версия работает нормально?
Если да, то ни в чём.
Если ножевой раунд начинается всё так же как и был, то можно пофиксить.
Я вообще фиксил главным образом отбирание оружия у игроков.
Сообщения автоматически склеены:

@Svyatoy, в том, что проверка if() не нужна. Достаточно сразу возвращать то, чо прописано в условиях этой проверки.
Я же говорил: если не понял, то не заморачивайся и продолжай говнокодить дальше.
 

Besais

Участник
Сообщения
26
Реакции
0
@Besais, моя версия работает нормально?
Если да, то ни в чём.
Если ножевой раунд начинается всё так же как и был, то можно пофиксить.
Я вообще фиксил главным образом отбирание оружия у игроков.
Сообщения автоматически склеены:

@Svyatoy, в том, что проверка if() не нужна. Достаточно сразу возвращать то, чо прописано в условиях этой проверки.
Я же говорил: если не понял, то не заморачивайся и продолжай говнокодить дальше.
оружие не забирается
 

Svyatoy

Участник
Сообщения
335
Реакции
137
@Svyatoy, в том, что проверка if() не нужна. Достаточно сразу возвращать то, чо прописано в условиях этой проверки.
Я же говорил: если не понял, то не заморачивайся и продолжай говнокодить дальше.
В этом есть определённый смысл, спасибо за подсказку.
Если это имеет для Вас значение - то совет на будущее. Попробуйте сначала улыбнуться незнакомому человеку, чтобы не пришлось потом его обвинять в том, что он повернулся спиной...
 
Сверху Снизу