UWC3X - BACKUP XP - SAFETY CHECK

Started by xReforged,

Previous topic - Next topic

xReforged

UWC3X – BACKUP XP – SAFETY CHECK

Sistem de siguranță conceput pentru a preveni pierderea XP-ului și a levelului jucătorilor în cazul unor probleme sau erori ale bazei de date principale.

Salvează separat, intr-un fisier de backup, numele jucătorului, levelul și XP-ul.
Verifică periodic, la un interval configurabil, valorile actuale ale fiecărui jucător.
Detectează automat dacă levelul sau XP-ul a scăzut ori s-a pierdut în urma unei probleme cu baza de date.
În cazul detectării unei pierderi, sistemul restaurează automat ultima valoare validă salvată.
Backup-ul funcționează independent de baza de date principală, oferind un nivel suplimentar de protecție.

Scop: jucătorii să nu își piardă niciodată progresul, chiar dacă baza de date principală întâmpină probleme.

#include <amxmodx>
#include <hamsandwich>

native get_xp(id);
native set_xp(id, amount);

native get_level(id);
native set_level(id, amount);

#define PLUGIN  "XP Backup System"
#define VERSION "1.0"
#define AUTHOR  "xReforged - Plugin netestat facut rapid"

#define CHECK_DELAY       5.0
#define AUTOSAVE_INTERVAL 120.0

new const BACKUP_FILE[] = "xp_backup.dat";

public plugin_init()
{
    register_plugin(PLUGIN, VERSION, AUTHOR);

    RegisterHam(Ham_Spawn, "player", "PlayerSpawn_Post", 1);

    set_task(AUTOSAVE_INTERVAL, "Task_AutoSave", 0, "", 0, "b");
}

public PlayerSpawn_Post(id)
{
    if (!is_user_alive(id))
        return HAM_IGNORED;

    remove_task(id);

    set_task(CHECK_DELAY, "Task_CheckBackup", id);

    return HAM_IGNORED;
}

public Task_CheckBackup(id)
{
    if (!is_user_connected(id))
        return;

    new currentLevel = get_level(id);
    new currentXP = get_xp(id);

    new backupLevel;
    new backupXP;

    if (LoadBackup(id, backupLevel, backupXP))
    {
     
        if (currentLevel < backupLevel)
        {
            set_level(id, backupLevel);
            set_xp(id, backupXP);

            LogRestore(
                id,
                currentLevel,
                currentXP,
                backupLevel,
                backupXP
            );

            return;
        }

   
        if (currentLevel == backupLevel && currentXP < backupXP)
        {
            set_xp(id, backupXP);

            LogRestore(
                id,
                currentLevel,
                currentXP,
                backupLevel,
                backupXP
            );

            return;
        }


        if (currentLevel > backupLevel)
        {
            SaveBackup(id, currentLevel, currentXP);
        }
        else if (currentLevel == backupLevel && currentXP > backupXP)
        {
            SaveBackup(id, currentLevel, currentXP);
        }
    }
    else
    {

        SaveBackup(id, currentLevel, currentXP);
    }
}

public Task_AutoSave()
{
    new players[32];
    new num;

    get_players(players, num, "ch");

    for (new i = 0; i < num; i++)
    {
        SafeSave(players[i]);
    }
}

stock SafeSave(id)
{
    if (!is_user_connected(id))
        return;

    new currentLevel = get_level(id);
    new currentXP = get_xp(id);

    new backupLevel;
    new backupXP;

    if (LoadBackup(id, backupLevel, backupXP))
    {

        if (currentLevel < backupLevel)
            return;

        if (currentLevel == backupLevel && currentXP < backupXP)
            return;
    }

    SaveBackup(id, currentLevel, currentXP);
}

stock bool:LoadBackup(id, &level, &xp)
{
    new name[32];
    get_user_name(id, name, charsmax(name));

    if (!name[0])
        return false;

    new filePath[128];
    GetBackupPath(filePath, charsmax(filePath));

    if (!file_exists(filePath))
        return false;

    new file = fopen(filePath, "rt");

    if (!file)
        return false;

    new line[256];

    new savedName[32];
    new savedLevel[16];
    new savedXP[32];

    while (!feof(file))
    {
        fgets(file, line, charsmax(line));
        trim(line);

        if (!line[0])
            continue;

        savedName[0] = 0;
        savedLevel[0] = 0;
        savedXP[0] = 0;

        parse(
            line,
            savedName, charsmax(savedName),
            savedLevel, charsmax(savedLevel),
            savedXP, charsmax(savedXP)
        );

        if (equali(savedName, name))
        {
            level = str_to_num(savedLevel);
            xp = str_to_num(savedXP);

            fclose(file);

            return true;
        }
    }

    fclose(file);

    return false;
}

stock SaveBackup(id, level, xp)
{
    new name[32];
    get_user_name(id, name, charsmax(name));

    if (!name[0])
        return;

    new filePath[128];
    GetBackupPath(filePath, charsmax(filePath));

    if (!file_exists(filePath))
    {
        new file = fopen(filePath, "wt");

        if (!file)
            return;

        fprintf(
            file,
            "^"%s^" ^"%d^" ^"%d^"^n",
            name,
            level,
            xp
        );

        fclose(file);

        return;
    }

    new tempPath[128];

    formatex(
        tempPath,
        charsmax(tempPath),
        "%s.tmp",
        filePath
    );

    new file = fopen(filePath, "rt");
    new temp = fopen(tempPath, "wt");

    if (!file || !temp)
    {
        if (file)
            fclose(file);

        if (temp)
            fclose(temp);

        return;
    }

    new line[256];

    new savedName[32];
    new savedLevel[16];
    new savedXP[32];

    new bool:found = false;

    while (!feof(file))
    {
        fgets(file, line, charsmax(line));
        trim(line);

        if (!line[0])
            continue;

        savedName[0] = 0;
        savedLevel[0] = 0;
        savedXP[0] = 0;

        parse(
            line,
            savedName, charsmax(savedName),
            savedLevel, charsmax(savedLevel),
            savedXP, charsmax(savedXP)
        );

        if (equali(savedName, name))
        {
           
            fprintf(
                temp,
                "^"%s^" ^"%d^" ^"%d^"^n",
                name,
                level,
                xp
            );

            found = true;
        }
        else
        {

            fprintf(
                temp,
                "%s^n",
                line
            );
        }
    }

    fclose(file);

    if (!found)
    {
        fprintf(
            temp,
            "^"%s^" ^"%d^" ^"%d^"^n",
            name,
            level,
            xp
        );
    }

    fclose(temp);

    delete_file(filePath);
    rename_file(tempPath, filePath, 1);
}

stock GetBackupPath(path[], len)
{
    get_localinfo(
        "amxx_datadir",
        path,
        len
    );

    add(
        path,
        len,
        "/xp_backup.dat"
    );
}

stock LogRestore(
    id,
    oldLevel,
    oldXP,
    backupLevel,
    backupXP
)
{
    new name[32];
    get_user_name(id, name, charsmax(name));

    log_amx(
        "[XP BACKUP] RESTORE: %s | Actual: Level %d / XP %d | Backup: Level %d / XP %d",
        name,
        oldLevel,
        oldXP,
        backupLevel,
        backupXP
    );
}

 

eMIL


xReforged


eMIL

Mulțumesc frumos,o sa îl pun sa vedem.

Astarasefk

#4
Ideea e chiar buna, dar e facut putin hardcoded, o sa-ti fac o analiza minima:

1. Cand compilezi plugin-ul , primesti un warning ca nu folosesti nicaieri variabila BACKUP_FILE_

//AMXXPC compile.exe
// by the AMX Mod X Dev Team


//// ATB.sma
//
// C:\gamecs\cstrike\addons\amxmodx\scripting\ATB.sma(17) : warning 203: symbol is never used: "BACKUP_FILE"
// Header size:            952 bytes
// Code size:            5996 bytes
// Data size:            1596 bytes
// Stack/heap size:      16384 bytes
// Total requirements:  24928 bytes
//
// 1 Warning.
// Done.
//
// Compilation Time: 1,76 sec
// ----------------------------------------

Press enter to exit ...

in GetBackUpPath() tu scrii direct numele fisierului in loc sa foloesti variabile BACKUP_FILE.


2.  Sa redeschizi un fisier pentru fiecare player odata la 120 de secunde si sa-l rescrii e putin teribil.

Pentru salvari de genul, cred ca Nvault/Nvault Util ar fi mult mai efficient  iar ca idee, eu cred ca BackUpFile ar trebui sa fie exact ce sugereaza numele un fisier de BackUp care nu e deschis niciodata decat daca jucatorii chiar isi pierd xp/level sau se intampla ceva cu serverul, cred ca ar trebui pur si simplu doar sa scrii in datele jucatorilor cu xp/level si sal salvezi fara sa suprascrii xp lor actual si sa faci niste comenzi de gen-ul /xpbackup in care fiecare jucator isi poate reloca singur xp interior in caz de se intampla ceva..


3. In plugin ai inregistratat nativele get/set_xp/level()  , acestea sunt inregistreare in timpul compilarii, dar daca uitilizatorii nu au plugin-ul unde sunt si create aceste native, (gen cu register_native() din pluginu-l original) le va da erroare in timpul folosiri, practic plugin-ul e dependent de un plugin exterior unde sunt inregistrate aceste functi, va trebui ori sa-l postezi pe forum si sa pui link in topicul asta, ori sa postezi si plugin-ul original altfel lumea nu-l poate folosi findca get_xp/set_xp etc... nu sunt functii native din amxx.

4. Cand faci sisteme de XP intodeauna sa iei in considerare deconectarea jucatorului sau daca acesta isi  schimba numele in client_infochanged() ori o sa apara buguri multe.


5. Ca solutie eu as propune urmatoarea: in pluginu-l original, unde ai inregistrat get/set_xp/level() sa inregistrezi si un forward cand jucatorul face level-up, iar apoi faci un plugin separat de backup cu nvault, si doar cat apelezi public Player_level_UP(id, newlevel, currentxp); si in public ii faci un backup cu noul nivel si xp-ul current, si doar cat scrii o comanda in chat gen /restore  unde jucatorii isi pot restaura xp/level in cazul in care chiar e pierdut sau s-a intamplata ceva). Asta ar fi mult mai putin costisitor si ar apela sursa unde e scris xp mult mai lejer.
terra fanclub.

eMIL

Pfff cam complicat o sa vad când am timp

Astarasefk

#6
Quote from: eMIL on Pfff cam complicat o sa vad când am timp

va pot ajuta eu, consider ca xrefo o facut plugin-ul asta findca aveti pe server-ul de Hero pierderi de Xp/level la jucatori.

Plugin-ul asta n-o sa va ajute cu nimic,  daca un jucator isi va pierde levelul,  acest plugin ii va pune in baza de date noul level care nu e congruent cu ce nivel avea el. In cateva cazuri va reusi, dar daca jucatorul se reconecteaza sau alte lucruri se intampla, va scrie un level corrupt care nu e ce avea el inainte.

Problema cu salvarile pe Xp/level sunt foarte complicate, in majoritatea cazuilor nu e bine faci salvari in fisere text sa il scrii sa/l redeschii, ca sa faci salvare pe nume pe non-steam si sa mearga 100% fara erori, trebuie:

1. Sa folosesti Nvault_Util (acest include: https://forums.alliedmods.net/showthread.php?t=139584 ), folosesti Numele jucatorului ca Key si in Data ii pui si level si XP
2. Sa iei in considerare cand jucatorul isi schimba numele(client_infochanged() ).
3. Sa iei in cosniderare cand un jucator se deconecteaza (client_Disconnected() ).


Voi presupun ca deja aveti baza de date cu multi jucatori cu level, ca sa puneti un system solid si bine facut singura solutie e ca toti playerii sa o ia de la level 1 si toti sa faca cerere de level pe forum cu ce nivel aveau inainte. SI il reupladati cu noul system pe nvault util .
terra fanclub.

eMIL


Astarasefk

Quote from: eMIL on E pentru uwc3x nu hero

aceiasi chestie bro, nu conteaza serverul, plugin-ul conteaza.

Posteaza aicia in Asistenta Daeva: https://daeva.ro/forum/index.php?board=227.0

Pune-mi plugin-ul core in care ai salvare Xp si ti-l refac eu sa nu mai ai probleme cu salvarea, dar din nou, va trebui s-o iei de la zero cu toti jucatorii la level, findca vom face o baza de date nou nouta optimizata care nu are scurgeri sau nu e reduntanta. Adica toti vor incepe de la level 1 din nou. Si vor trebui sa faca cerere pe forum sau server ca sa le dai tu level.  Dar macar vor avea permanent, fara probleme de salvare.


Posteaza-mi pluignul complet in care salvezi level-ul , il poti pune pe https://pastebin.com/ ca sa-l copii de acolo, si spune-mi ce schimbari doresti la el.
terra fanclub.

eMIL