Фиксируем ники игроков

Тема в разделе "Кодинг", создана пользователем Flame, 7 июл 2015.

  1. Flame

    Flame -Заслуженый кодер форума-

    Upd. Под спойлером информация для тех у кого удалённая база данных.
    Владельцы серваков с удалённой базой данных, ServerPerksHost.exe не терпит кириллицу, поэтому всё вне этого спойлера для вас не очень хорошо.
    Ибо любой зафиксированный ник на кириллице превратиться в крякозябру при следующем заходе игрока.

    Вот я накидал мутатор, который фиксирует ники игроков в файле на сервере

    RestoreFixedNameMut + FixSteamRusNameMut должны дать нужный эффект: Ник будет поправлен и сохранён.
    RestoreFixedNameMut фиксирует (в RestoreFixedNameBase.ini) ники всех тех, кто остался до конца карты.

    За последние полгода не первый раз меня пинают по поводу фиксации ника у игроков.
    Ибо задирают они админчиков - фиг запомнишь кто есть кто.

    Данная небольшая правка позволит раз и навсегда зафиксировать ник игрока.
    Изменить может только админ руками в базе данных (ну или можно команду в админке прописать при желании).
    В данной реализации ник игрока фиксируется только после окончания карты (победа или поражение) и если его в этот момент уже нет на сервере - ник не фиксируется.

    Можно в принципе не трогать SP и сделать в виде отдельного мутатора, но тогда будет беда на тех серваках, где удалённая база данных. Ибо мне лень делать удалённую версию мутатора))
    Поэтому будем тупо править SP - благо там почти и править то ничего не надо.

    Будем править последний на данный момент ServerPerks 7.50
    Нам понадобятся классы ServerPerksMut.StatsObject и ServerPerksMut.ServerStStats

    1. Класс StatsObject
    Собственно, тот объект, который и сохраняется в базе данных
    Для того, чтобы работала версия с базой данных в ServerPerksStat.ini достаточно добавить переменную
    var config string uname;

    Тем, кто работает с удалённой базой данных необходимо так же поправить функции сохранения кача в строку и извлечения кача из строки.
    Код:
    final function string GetSaveData()
    {
        local string Result;
    
        Result = SelectedVeterancy$":"$PerkIndex$","$DamageHealedStat$","$WeldingPointsStat$","$ShotgunDamageStat$","$HeadshotKillsStat$","$StalkerKillsStat;
        Result = Result$","$BullpupDamageStat$","$MeleeDamageStat$","$FlameThrowerDamageStat$","$SelfHealsStat$","$SoleSurvivorWavesStat;
        Result = Result$","$CashDonatedStat$","$FeedingKillsStat$","$BurningCrossbowKillsStat$","$GibbedFleshpoundsStat$","$StalkersKilledWithExplosivesStat;
        Result = Result$","$GibbedEnemiesStat$","$BloatKillsStat$","$SirenKillsStat$","$KillsStat$","$ExplosivesDamageStat;
        Result = Result$","$int(TotalZedTimeStat)$","$TotalPlayTime$","$WinsCount$","$LostsCount$",'"$SelectedChar$"'";
        //Flame
        Result = Result$",'"$uname$"'";
        //
        Result = Result$","$GetPropertyText("CC");
        return Result;
    }
    
    final function SetSaveData( string S )
    {
        local int i;
    
        i = InStr(S,",");
        if( i==-1 )
            return;
        SelectedVeterancy = Left(S,i);
        S = Mid(S,i+1);
        i = InStr(SelectedVeterancy,":");
        if( i==-1 )
            PerkIndex = 255;
        else
        {
            PerkIndex = int(Mid(SelectedVeterancy,i+1));
            SelectedVeterancy = Left(SelectedVeterancy,i);
        }
    
        DamageHealedStat = GetNextValue(S);
        WeldingPointsStat = GetNextValue(S);
        ShotgunDamageStat = GetNextValue(S);
        HeadshotKillsStat = GetNextValue(S);
        StalkerKillsStat = GetNextValue(S);
        BullpupDamageStat = GetNextValue(S);
        MeleeDamageStat = GetNextValue(S);
        FlameThrowerDamageStat = GetNextValue(S);
        SelfHealsStat = GetNextValue(S);
        SoleSurvivorWavesStat = GetNextValue(S);
        CashDonatedStat = GetNextValue(S);
        FeedingKillsStat = GetNextValue(S);
        BurningCrossbowKillsStat = GetNextValue(S);
        GibbedFleshpoundsStat = GetNextValue(S);
        StalkersKilledWithExplosivesStat = GetNextValue(S);
        GibbedEnemiesStat = GetNextValue(S);
        BloatKillsStat = GetNextValue(S);
        SirenKillsStat = GetNextValue(S);
        KillsStat = GetNextValue(S);
        ExplosivesDamageStat = GetNextValue(S);
        TotalZedTimeStat = GetNextValue(S);
        TotalPlayTime = GetNextValue(S);
        WinsCount = GetNextValue(S);
        LostsCount = GetNextValue(S);
        SelectedChar = GetNextStrValue(S);
        //Flame
        uname = GetNextStrValue(S);
        //
        CC.Length = 0;
        if( Len(S)>0 )
            SetPropertyText("CC",S);
    }
    
    Добавленный мной код выделен вначале //Flame и в конце //
    2. Класс ServerStStats
    Тут нам надо сделать 2 вещи
    а) Сохранить ник с которым играет игрок в определённый момент.
    Я буду сохранять в момент, когда закончена карта. Если карта так или иначе завершилась - текущий ник сохраняется в переменную uname, но только если она пуста. То есть новичок приходит на сервер, карта заканчивается и его ник зафиксирован. Больше он программно меняться не будет
    б) Заменить ник.
    При старте игры мы должны будем проверить текущий ник и ник сохранённый в uname. Если текущий ник отличается - заменяем его на тот, что в uname

    Итак,
    а) Сохраняем ник
    В классе ServerStStats есть функция WonLostGame, которая вызывается в случае, если карта закончена
    Туда и добавим вызов функции, фиксирующий ник:
    Код:
    function WonLostGame( bool bDidWin )
    {
        //Flame.UName
        FixUName();
        //
        if( bDidWin )
        {
            ++Rep.WinsCount;
            if( MyStatsObject!=None )
                ++MyStatsObject.WinsCount;
        }
        else
        {
            ++Rep.LostsCount;
            if( MyStatsObject!=None )
                ++MyStatsObject.LostsCount;
        }
        bHasChanged = true;
        DelayedStatCheck();
        GoToState('');
    }
    //Flame.UName Этой функцией и фиксируем
    function FixUName()
    {
        if(MyStatsObject.uname=="")
        {
            Log("Name"@PlayerOwner.PlayerReplicationInfo.PlayerName@" is fixed now");
            PlayerOwner.ClientMessage("You Name is fixed now");
            MyStatsObject.uname=PlayerOwner.PlayerReplicationInfo.PlayerName;
        }
    }
    

    б) Заменяем ник
    Тут надо учесть, что данные из удалённой базы подкачиваются не сразу
    Поэтому если мы поставим вызов функции проверки и замены ника, например, в PostBeginPlay, то для локальной базы всё будет отлично, а вот для удалённой нет.
    Мы сделаем замену ника сразу в двух местах:
    в PostBeginPlay для тех, кто не использует удалённую базу данных,
    в Timer`е для тех кто использует.
    А чтобы не получилось так, что мы дважды пытаемся фиксировать ник - мы введём переменную bNameChanged, которая позволит нам запретить больше 1 смены ника. Для чистой фиксации это не так важно, но вот если мы используем версию SetPlayerUName с конвертацией русских букв ника (см. конец статьи), то нам важно чтобы ник был сконвертирован ровно 1 раз.
    Код:
    Class ServerStStats extends SRStatsBase;
    ...
    var bool bNameChanged;
    ...
    
    function PostBeginPlay( string D )
    {
        ...
        SetTimer(0.1,false);
        //Flame
        if(!bNameChanged)
        {
            SetPlayerUName();
            bNameChanged=true;
        }
        //
    }
    
    function Timer()
    {
        ...
        if( bStatsChecking )
        {
            bStatsChecking = false;
            CheckPerks(false);
        }
        //Flame. Фиксация ника
        if(!bNameChanged)
        {
            SetPlayerUName();
            bNameChanged=true;
        }
        //
    }
    
    //Flame.UName Данная функция проверяет есть ли у нас зафиксированный ник
    //Если есть зафиксированный ник (uname не пусто), то мы заменяем текущий ник на фиксированный
    function SetPlayerUName()
    {
        if(MyStatsObject.uname!="")
        {
            if(PlayerOwner.PlayerReplicationInfo.PlayerName!=MyStatsObject.uname)
            {
                Log("Forcing change: Name"@PlayerOwner.PlayerReplicationInfo.PlayerName@"into"@MyStatsObject.uname);
                PlayerOwner.PlayerReplicationInfo.PlayerName = MyStatsObject.uname;
            }
        }
    }
    
    Всё

    Ссылка 1 или Ссылка 2

    Замечание: Те кто используют удалённую базу данных - не советую фиксировать ник таким образом. Кириллица превращается в крякозябру. Либо пишите свой клиент с удалённой базой. Марковский ServerPerksHost.exe вам не подойдёт.
    Мутатор фиксирующий ник в отдельный файл для каждого из серверов представлен в самом начале статьи.

    Upd.
    Написанное ниже относится только к тем, кто не использует удалённую базу данных!
    Кстати, если хотите можете объединить этот код с заменой крякозябренных ников, написанных в кириллице, на читаемый вариант (см. эту тему)
    Можно использовать такой вариант функции SetPlayerUName
    Код:
    //Flame.UName Данная функция проверяет есть ли у нас зафиксированный ник
    //Если есть зафиксированный ник (uname не пусто), то мы заменяем текущий ник на фиксированный
    //Если пока нет зафиксированного ника, то мы применяем конвертацию ника для исправления кириллицы стима
    function SetPlayerUName()
    {
        if(MyStatsObject.uname!="")
        {
            if(PlayerOwner.PlayerReplicationInfo.PlayerName!=MyStatsObject.uname)
            {
                Log("Forcing change: Name"@PlayerOwner.PlayerReplicationInfo.PlayerName@"into"@MyStatsObject.uname);
                PlayerOwner.PlayerReplicationInfo.PlayerName = MyStatsObject.uname;
            }
        }
        else
            PlayerOwner.PlayerReplicationInfo.PlayerName = ConvertSteamString(PlayerOwner.PlayerReplicationInfo.PlayerName);
    }
    //
    //Flame Набор функций для правки кириллицы стима
    //Подробнее тут: http://killingfloor.ru/forum/index.php?/topic/4023-ispravlenie-russkikh-imen/
    function string ConvertSteamString(string msg)
    {
        local int i;
        local string tmp;
        local string result;
        local int code;
        tmp=msg;
        for(i=0; i<Len(msg); i++)
        {
            code=Asc(tmp);
            if(code==1056 || code==1057)
            {
                tmp=Mid(tmp,1);
                continue;
            }
            code=FixCode(code);
            if(code>167)
                code+=848;
            if(i==0) result=Chr(code);
            else result=result$Chr(code);
            tmp=Mid(tmp,1);
        }
        return result;
    }
    
    function int FixCode(int code)
    {
        switch(code)
        {
            case 176:    return 224;
            case 177:    return 225;
            case 1030:    return 226;
            case 1110:    return 227;
            case 1169:    return 228;
            case 181:    return 229;
            case 8216:    return 184;
            case 182:    return 230;
            case 183:    return 231;
            case 1105:    return 232;
            case 8470:    return 233;
            case 1108:    return 234;
            case 187:    return 235;
            case 1112:    return 236;
            case 1029:    return 237;
            case 1109:    return 238;
            case 1111:    return 239;
            case 1026:    return 240;
            case 1027:    return 241;
            case 8218:    return 242;
            case 1107:    return 243;
            case 8222:    return 244;
            case 8230:    return 245;
            case 8224:    return 246;
            case 8225:    return 247;
            case 8364:    return 248;
            case 8240:    return 249;
            case 1033:    return 250;
            case 8249:    return 251;
            case 1034:    return 252;
            case 1036:    return 253;
            case 1035:    return 254;
            case 1039:    return 255;
            case 1106:    return 192;
            case 8216:    return 193;
            case 8217:    return 194;
            case 8220:    return 195;
            case 8221:    return 196;
            case 8226:    return 197;
            case 1027:    return 168;
            case 8211:    return 198;
            case 8212:    return 199;
            case 152:    return 200;
            case 8482:    return 201;
            case 1113:    return 202;
            case 8250:    return 203;
            case 1114:    return 204;
            case 1116:    return 205;
            case 1115:    return 206;
            case 1119:    return 207;
            case 160:    return 208;
            case 1038:    return 209;
            case 1118:    return 210;
            case 1032:    return 211;
            case 164:    return 212;
            case 1168:    return 213;
            case 166:    return 214;
            case 167:    return 215;
            case 1025:    return 216;
            case 169:    return 217;
            case 1028:    return 218;
            case 171:    return 219;
            case 172:    return 220;
            case 173:    return 221;
            case 174:    return 222;
            case 1031:    return 223;
        }
        return code;
    }
    //
    
    Тогда при первом заходе новичка на сервер его ник правится на читаемый вариант и фиксируется. Профит. Ибо иначе зафиксируется крякозябра и даже если он у себя поменяет ник - его это не спасёт.
     
    Последнее редактирование: 17 ноя 2016
    HATAXA, SNapx, kok-s и 2 другим нравится это.
  2. HATAXA

    HATAXA Солдат

    Ник фиксируется при первом заходе?
    А если зашел со стандартным ником, его кикнуло, нужно поменять...
     
  3. Flame

    Flame -Заслуженый кодер форума-

    Не выспалась, ведьма? ))
    Писал же - фиксируется после окончания карты (победы или поражения всех)
     
  4. HATAXA

    HATAXA Солдат

    Видимо не выспалась до сих пор) Не вижу :turned:
    Делать или не делать... вот в чём вопрос :unsure2:
     
  5. Flame

    Flame -Заслуженый кодер форума-

    Ну воот же )

    Ну может ты и права - может стоит это вынести в начальное описание
    И может действительно не ясно, что если он уйдёт до окончания карты (например, будет кикнут), то его ник не зафиксируется
     
  6. kok-s

    kok-s Консильери

    Отлично! Спасибо огромное!
     
  7. Flame

    Flame -Заслуженый кодер форума-

    Обновление кода и дополнение для владельцев серверов с удалённой базой данных
    Следствие этого поста

    В ближайшее время мутатор RestoreFixedNameMut будет доработан и возможно объединён с FixSteamRusNameMut
     
  8. kok-s

    kok-s Консильери

    Да было бы наверно вообще шикарно объединить KickNickMut + RestoreFixedNameMut + FixSteamRusNameMut в один мутатор. Сделать функционал каждого мутатора вкл/выкл в настройках. Будет бомба))) Просто и так мутаторов куча и не хочется ещё плодить их.
     
  9. idpro2

    idpro2 Соучастник

    Ребят, на последнем клиенте 1065 конвертация русских ников с этим мутатором не работает(
    Любые русские символы конвертирует в тильды "~". Пытался это исправить но все безрезультатно.
    Может кто нибудь знает в чем проблема?

    Также хотел спросить по сабжу - можно ли как-то пришить Regex к данному плагину по которому будет проверка валидности ника? Есть ли вообще такое в US?
     
    Последнее редактирование: 9 ноя 2016
  10. Flame

    Flame -Заслуженый кодер форума-

    Пджди) У меня ж всё работает. И не только у меня
    У тебя удалённая база данных?
    Если да, то для тебя сообщение сверху шапки под спойлером

    Насчёт регулярных выражений, ну теоретически ты можешь вывести информацию из игры, обработать своим софтом, вернуть информацию в игру. Но по-моему сомнительное это всё удовольствие. Если хочешь - порассуждаю об этом побольше.
     
    idpro2 нравится это.
  11. idpro2

    idpro2 Соучастник

    Спасибо! Понял

    Да, база удаленная. Если для удаленной конвертировать никак, то можно ли как-то определять что ник игрока содержит русские символы вообще и в таком случае принудительно менять ник на "стандартный"?
     
  12. Flame

    Flame -Заслуженый кодер форума-

    Можно, конечно - поглядеть коды символов в нике. Взять максимальный по значению, поглядеть лежит ли в области относящейся к кириллице

    И ещё разок - для удалённой базы конвертировать не проблема
    Проблема в том, что нельзя фиксировать ник в удалённой базе (кириллица не сохранится)
    Каждый раз можно при заходе игрока менять ему ник
    А фиксировать ник отдельным мутатором, который хранит базу на сервере, либо получает данные с помощью своего канала связи (не ServerPerksHost)

    В принципе я так подумал - можно ведь шифровать ник игрока латиницей, а потом дешифровать при получении. Так что в принципе можно и наладить сохранение ников в удалённой базе, но размер базы увеличится
    Надо попробовать сделать, кстати. Либо создать уже свой аналог ServerPerksHost для винды и линукса
     
    Последнее редактирование: 15 ноя 2016
  13. idpro2

    idpro2 Соучастник

    Суть проблемы в том, что русские ники конвертируются в тильды еще в игре, до того как они сохраняются/достаются из удаленной базы.
    По этому сейчас основная проблема заключается именно в этом)
     
  14. Flame

    Flame -Заслуженый кодер форума-

    Конвертируются в тильды они в том случае, когда конвертация идёт более 1 раза
    Вроде я сейчас выкладывал версию, где это поправлено, когда правил 1 пост
    Кинь чтоль под спойлер то, чем пользуешься ты (содержимое ServerStStats)
    Или у тебя точно как в текущей версии описанной в 1 соообщении темы?
     
  15. Flame

    Flame -Заслуженый кодер форума-

    Накидал независимый от SP и от типа базы данных мутатор для фиксации ников
    Ищите ошибки, предлагайте улучшения
     
    idpro2 нравится это.
  16. Flame

    Flame -Заслуженый кодер форума-

    Шершень пользовался, говорит карты долго меняются
    У кого такая же фигня - пишите
     
  17. kok-s

    kok-s Консильери

    Флейм. Есть такая проблемка. Опишу ситуацию: Человек зашёл с русским ником - модератор меняет ему ник на англ. (используем AdminControlv2), но этот ник не сохраняется в базе. Есть решения?
     
  18. HATAXA

    HATAXA Солдат

    Есть решение установить фиксацию ников. А AdminControlv2 никак не фиксирует.
     
  19. Flame

    Flame -Заслуженый кодер форума-

    Я потестирую, ты только скажи, как именно вы фиксируете ник)
    В этой теме я кучу вариантов расписал. У вас удалённая база и мутатор RestoreFixedNameMut или вы правите ServerStStats?
     
  20. kok-s

    kok-s Консильери

    Удалёнка и правки ServerStStats.