Настройка слота и приоритета оружия игроком

Тема в разделе "Общего назначения", создана пользователем Flame, 13 апр 2015.

  1. Flame

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

    Мысль мне пришла ночью - а ведь и не обязательно править ServerPerks.
    (Далее нюансы кода для тех, кому это интересно. Частично кусок будущей статьи про LinkedReplicationInfo)
    Ведь мне зачем нужен был SP?
    1. Ради репликации на сервер информации о новых группах (ниже я так же использую слово "слот") и приоритетах
    2. И ради вмешательства в функцию SRHumanPawn.AddInventory. Мы хотим поменять приоритет до того, как пушка добавлена в
    Inventory. После этого менять уже поздно.

    В чём первая проблема:
    У нас есть на клиенте информация о пушках-приоритетах-слотах, но все основные действия происходят на сервере. Нам надо как-то перекинуть всю эту информацию, полученную из ini файла на сервер. Причём игроков много, а сервер один.

    Значит либо надо на сервере в мутаторе создавать массив пар "Игрок-ИнформацияОПушках", либо надо эту информацию перекидывать
    на какой-то объект, принадлежащий игроку.

    В принципе можно прицепить к игроку любой класс унаследованный от Actor, либо что-то вручить ему в инвентарь и внутри этого объекта перекидывать информацию с клиента на сервер.
    А я в прошлой реализации использовал для этого SRPlayerReplicationInfo. Объект этого класса присутствует и на сервере и на клиенте. Кроме того есть явная принадлежность к игроку.

    Но можно и не трогать SRPlayerReplicationInfo и при этом не мучиться с прикреплением непонятных объектов.

    Есть такая штука, как LinkedReplicationInfo. Я о ней давно знал, но только этой ночью похоже в полной мере понял какие от неё
    преимущества.

    LinkedReplicationInfo - объект так же, как и PlayerReplicationInfo унаследованный от ReplicationInfo. Но что самое приятное - в нём есть встроенный механизм, позволяющий прикреплять этот класс к PlayerReplicationInfo.

    Собственно, весь механизм это переменная в PlayerReplicationInfo - CustomReplicationInfo.
    А в классе LinkedReplicationInfo есть переменная NextReplicationInfo.
    То есть мы можем выстроить цепочку:
    Код:
     PlayerReplicationInfo->PlayerReplicationInfo.CustomReplicationInfo->PlayerReplicationInfo.CustomReplicationInfo.NextReplicationInfo->...
    
    Более того у всех у вас, кто использует SP уже есть такая цепочка. ClientPerkRepLink как раз яркий представитель LinkedReplicationInfo.

    Единственное - нет никаких изначально написанных механизмов прикрепления и поиска LinkedReplicationInfo.
    Можно взять механизм из ClientPerkRepLink, либо из этой статьи

    Итак, необходимость в SRPlayerReplicationInfo отпадает - всё нужное (перекидывание информации из ini файла клиента на сервер) мы делаем в нашем LinkedReplicationInfo. А он уже в свою очередь прикреплён к PlayerReplicationInfo игрока (либо в конец существующей цепочки, если есть уже цепочка).

    Ну а вторая проблема решается совсем просто. Мы перехватываем создание новой пушки в CheckReplacement (оно будет выполнено до AddInventory).

    Тут должно волновать только вот что - заполнены ли в пушке нужные нам поля: Владелец, приоритет и группа.
    Приоритет и группа вообще прописаны в defaultproperties - можем не волноваться по их поводу.
    Как оказывается Instigator так же уже есть, а значит мы знаем владельца пушки и знаем чей LinkedReplicationInfo нам нужно получить, чтобы вытащить оттуда данные.

    Мутатор работает так:
    Игрок заходит
    На сервере:
    - Отлавливаем PlayerReplicationInfo нового игрока. Создаём LinkedReplicationInfo и цепляем его в конец цепочки.

    На клиенте:
    - Ищем новый LinkedReplicationInfo игрока и передаём туда информацию о пушках из ini файла

    На сервере:
    - В LinkedReplicationInfo получаем данные с клиента и перекидываем их на сервер

    Далее игрок заходит в игру и у него появляется пушка
    На сервере:
    - Отлавливаем новую пушку. Узнаём её владельца. Ищем у этого владельца его LinkedReplicationInfo.
    - Зная LinkedReplicationInfo мы знаем данные из ini файла этого игрока, значит мы можем поправить приоритет и слот пушки
    - Передаём данные (пара оружие-слот) с сервера на клиент для установки InventoryGroup у пушек

    На клиенте:
    - Меняем InventoryGroup у пушек из ini файла

    Как-то так)
    Upd. Чуток усложнил мутатор. Теперь на LinkedReplicationInfo ещё и клиентские заморочки с установкой слота.
    Раньше я менял сразу у класса значение. Но доп. функционал с идентификацией перка наложил отпечаток на стройность идеи)
    Ниже полностью автономная версия мутатора

    Кратко о мутаторе и его возможностях:
    Мутатор меняет приоритет и группу пушки. Пользователь у себя в ini файле Killing Floor\System\SlotsAndPrioritiesMut.ini может это настроить при желании.
    Хочется, чтобы беретта была на 5 слоте после шприца? Не вопрос.

    Кроме того, я добавил возможность указывать перк - вдруг мы хотим один набор приоритетов и слотов для снайпера,
    а другой для берсеркера. Можно перк не указывать, тогда изменения будут касаться всех перков.
    Править старые свои ini файлы не надо - для них автоматически Perk будет считаться пустым.

    Так же добавил в мутатор возможность вывести себе на экран список своих пушек, их приоритетов и слотов, чтобы не надо было вам
    мучиться и декомпилировать пакеты с пушками для получения этой информации.

    Список вызывается командой
    Код:
    mutate lpr
    

    Настройки:
    Ну вроде как всё просто. Указываем оружие, новый слот, новый приоритет и при желании перк для которого это выполняется
    Код:
    [SlotsAndPrioritiesMut.SlotsAndPrioritiesMut]
    SlotsAndPrioritiesList=(Weapon="KFMod.Crossbow",Perk="SRVetBerserker",Slot=2,Priority=200)
    SlotsAndPrioritiesList=(Weapon="KFMod.Crossbow",Perk="SRVetSharpshooter",Slot=3,Priority=150)
    SlotsAndPrioritiesList=(Weapon="KFMod.Welder",Slot=1,Priority=1)
    
    В данном примере у берсеркера арбалет будет на 2 слоте с достаточно высоким приоритетом, у снайпера на 3 слоте, у остальных перков Crossbow будет на обычном 4 слоте. Сварка независимо от перка будет на 1 слоте после ножа.

    При этом, если вы ещё добавите после этого настройку для пустого перка,
    Код:
    SlotsAndPrioritiesList=(Weapon="KFMod.Crossbow",Perk="",Slot=1,Priority=150)
    
    то арбалет для всех остальных перков будет на 1 слоте. Но тут важен порядок.
    Настройку с пустым перком надо добавлять после настроек с прописанными перками. Иначе для всех перков арбалет будет на 1 слоте

    Важно!
    Чтобы в примере выше арбалет поменял свой слот для другого перка - нам надо либо выбросить и подобрать его, либо продать и купить.
    Оружие должно быть создано заново!

    Кстати, Priority это число типа byte, а значит максимальный приоритет может быть 255.
    Впрочем, можете писать и больше - мутатор просто обрубит число до 255.

    Но при этом учтите, что пушка с приоритетом 500 может оказаться ниже пушки с приоритетом 300, так как обе они будут с приоритетом 255.

    Код:
    Код:
    Class SlotsAndPrioritiesMut extends Mutator config(SlotsAndPrioritiesMut);
    
    struct SlotsAndPrioritiesStruct
    {
        var config string Weapon;
        var config string Perk;
        var config int Slot;
        var config int Priority;
    };
    var config array<SlotsAndPrioritiesStruct> SlotsAndPrioritiesList;
    
    var array<PlayerReplicationInfo> PendingPRI;
    
    simulated function PostBeginPlay()
    {
        if(Role<ROLE_Authority)
        {
            SetTimer(0.5,true);
            SaveConfig();
        }
    }
    
    function bool CheckReplacement(Actor Other, out byte bSuperRelevant)
    {
        local MyLinkedReplicationInfo MLRI;
        local Weapon W;
        local PlayerReplicationInfo PRI;
        if(Weapon(Other)!=None)
        {
            W=Weapon(Other);
            if(Other.Instigator!=none)
            {
                PRI=Other.Instigator.PlayerReplicationInfo;
                MLRI=class'MyLinkedReplicationInfo'.static.FindFor(PRI);
                ChangeSlotAndPriority(MLRI,W,PRI);
            }
        }
        if(PlayerReplicationInfo(Other)!=None)
        {
            //class'MyLinkedReplicationInfo'.static.SpawnFor(PlayerReplicationInfo(Other));
            PendingPRI[PendingPRI.Length]=PlayerReplicationInfo(Other);
            SetTimer(1.0,false);
        }
        return true;
    }
    
    simulated function Timer()
    {
        local PlayerController PC;
        local MyLinkedReplicationInfo MLRI;
        local int i;
    
        if(Role==ROLE_Authority)
        {
            for( i=(PendingPRI.Length-1); i>=0; --i )
            {
                if(PendingPRI[i].PlayerID>0)
                    class'MyLinkedReplicationInfo'.static.SpawnFor(PendingPRI[i]);
            }
            PendingPRI.Length = 0;
        }
    
        PC=Level.GetLocalPlayerController();
        if(PC==none) return;
        MLRI=class'MyLinkedReplicationInfo'.static.FindFor(PC.PlayerReplicationInfo);
        if(MLRI==none) return;
        for(i=0;i<SlotsAndPrioritiesList.Length;i++)
        {
            MLRI.AddSlotsAndPrioritiesOnServer(SlotsAndPrioritiesList[i].Weapon,SlotsAndPrioritiesList[i].Perk,SlotsAndPrioritiesList[i].Slot,Min(255,SlotsAndPrioritiesList[i].Priority));
        }
        SetTimer(0,false);
    }
    
    function Mutate(string MutateString, PlayerController Sender)
    {
        local Inventory Inv;
        if(MutateString~="lpr")
        {
            if(Sender==none || Sender.Pawn==none)
                return;
            for( Inv=Sender.Pawn.Inventory; Inv!=None; Inv=Inv.Inventory )
            {
                if(Weapon(Inv)!=none)
                    Sender.ClientMessage(Inv.Name@Weapon(Inv).Priority);
            }
        }
        if ( NextMutator != None )
            NextMutator.Mutate(MutateString, Sender);
    }
    
    function ChangeSlotAndPriority(MyLinkedReplicationInfo MLRI, Weapon W, PlayerReplicationInfo PRI)
    {
        local int i;
        for(i=0;i<MLRI.SlotsAndPrioritiesList.Length;i++)
        {
            if(MLRI.SlotsAndPrioritiesList[i].Weapon~=string(W.Class))
            {
                //Меняем приоритет и слот, если поле Perk пусто, либо текущий перк совпадает с тем что в поле Perk
                if    (
                        Len(MLRI.SlotsAndPrioritiesList[i].Perk)==0
                        ||
                        (
                            Len(MLRI.SlotsAndPrioritiesList[i].Perk)>0
                            &&    InStr(Caps(string(KFPlayerReplicationInfo(PRI).ClientVeteranSkill.Name)),Caps(MLRI.SlotsAndPrioritiesList[i].Perk))>=0
                        )
                    )
                {
                    W.Priority=MLRI.SlotsAndPrioritiesList[i].Priority;
                    W.InventoryGroup=MLRI.SlotsAndPrioritiesList[i].Slot;
                    MLRI.AddWeaponToClientArray(W.Name,W.InventoryGroup);
                }
            }
        }
    }
    
    defaultproperties
    {
        //SlotsAndPrioritiesList(0)=(Weapon="KFMod.Chainsaw",Perk="SRVetBerserker",Slot=5,Priority=200)
        //SlotsAndPrioritiesList(1)=(Weapon="KFMod.Syringe",Slot=1,Priority=1)
        GroupName="KF-SlotsAndPriorities"
        FriendlyName="SlotsAndPrioritiesMut"
        Description="Clientside mutator. User can change weapon priority and inventory group"
        RemoteRole=ROLE_SimulatedProxy
        bAlwaysRelevant=true
        bAddToServerPackages=True
    }
    
    Код:
    Class MyLinkedReplicationInfo extends LinkedReplicationInfo;
    
    struct SlotsAndPrioritiesStruct
    {
        var config string Weapon;
        var config string Perk;
        var config int Slot;
        var config int Priority;
    };
    var array<SlotsAndPrioritiesStruct> SlotsAndPrioritiesList;
    var PlayerController ControllerOwner;
    
    struct WeaponAndSlotStruct
    {
        var config Name Weapon;
        var config int Slot;
    };
    var array<WeaponAndSlotStruct> WeaponAndSlotList;
    
    replication
    {
        reliable if ( Role < Role_Authority )
            AddSlotsAndPrioritiesOnServer;
        reliable if ( Role == Role_Authority )
            AddWeaponToClientArray;
        reliable if ( Role == Role_Authority )
            ControllerOwner;
    }
    
    function PostBeginPlay()
    {
        ControllerOwner=PlayerController(Owner);
        Super.PostBeginPlay();
    }
    
    simulated function AddWeaponToClientArray(Name WName, int Slot)
    {
        local WeaponAndSlotStruct wass;
        wass.Weapon=WName;
        wass.Slot=Slot;
        if(!WeaponAlreadyAdded(WName))
            WeaponAndSlotList[WeaponAndSlotList.Length]=wass;
        SetTimer(0.1,true);
    }
    
    simulated function bool WeaponAlreadyAdded(Name WName)
    {
        local int i;
        for(i=0;i<WeaponAndSlotList.Length;i++)
        {
            if(WeaponAndSlotList[i].Weapon==WName)
                return true;
        }
        return false;
    }
    
    simulated function Timer()
    {
        local int i;
        local bool success;
        for(i=WeaponAndSlotList.Length-1;i>=0;i--)
        {
            success=ChangeInventoryGroupOnClient(WeaponAndSlotList[i]);
            if(success)
                WeaponAndSlotList.Remove(i,1);
        }
        if(WeaponAndSlotList.Length==0)
            SetTimer(0,false);
    }
    
    simulated function bool ChangeInventoryGroupOnClient(WeaponAndSlotStruct wass)
    {
        local Inventory Inv;
        if(ControllerOwner==none || ControllerOwner.Pawn==none || ControllerOwner.Pawn.Inventory==none)
            return false;
        for(Inv=ControllerOwner.Pawn.Inventory;Inv!=None;Inv=Inv.Inventory)
        {
            if(Inv.Name==wass.Weapon)
            {
                Inv.InventoryGroup=wass.Slot;
                return true;
            }
        }
        return false;
    }
    
    function AddSlotsAndPrioritiesOnServer(string Weapon, string Perk, int Slot, int Priority)
    {
        local SlotsAndPrioritiesStruct sap;
        sap.Weapon=Weapon;
        sap.Perk=Perk;
        sap.Slot=Slot;
        sap.Priority=Priority;
        SlotsAndPrioritiesList[SlotsAndPrioritiesList.Length]=sap;
    }
    
    static function MyLinkedReplicationInfo SpawnFor(PlayerReplicationInfo OwnerPRI)
    {
        local LinkedReplicationInfo LinkedRI;
        LinkedRI = FindFor(OwnerPRI);
        if(LinkedRI != None)
            return MyLinkedReplicationInfo(LinkedRI);
    
        if(OwnerPRI != None && OwnerPRI.Owner != None)
        {
            LinkedRI = OwnerPRI.Spawn(default.Class, OwnerPRI.Owner);
            LinkedRI.NextReplicationInfo = OwnerPRI.CustomReplicationInfo;
            OwnerPRI.CustomReplicationInfo = LinkedRI;
        }
        return MyLinkedReplicationInfo(LinkedRI);
    }
    
    static function MyLinkedReplicationInfo FindFor(PlayerReplicationInfo OwnerPRI)
    {
        local LinkedReplicationInfo LinkedRI;
        if ( OwnerPRI == None )
            return None;
        for(LinkedRI = OwnerPRI.CustomReplicationInfo; LinkedRI != None; LinkedRI = LinkedRI.NextReplicationInfo)
        {
            if(MyLinkedReplicationInfo(LinkedRI) != None)
                return MyLinkedReplicationInfo(LinkedRI);
        }
        return None;
    }
    
    defaultproperties
    {
        bOnlyRelevantToOwner=True
        bAlwaysRelevant=False
    }
    

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

    Проверяйте и я на свой сервер поставлю. Вполне возможны косяки.

    Список стандартных пушек, их слотов и приоритетов:
    Код:
    [SlotsAndPrioritiesMut.SlotsAndPrioritiesMut]
    SlotsAndPrioritiesList=(Weapon="KFMod.AA12AutoShotgun",Slot=4,Priority=200)
    SlotsAndPrioritiesList=(Weapon="KFMod.AK47AssaultRifle",Slot=3,Priority=95)
    SlotsAndPrioritiesList=(Weapon="KFMod.Axe",Slot=1,Priority=55)
    SlotsAndPrioritiesList=(Weapon="KFMod.BenelliShotgun",Slot=3,Priority=170)
    SlotsAndPrioritiesList=(Weapon="KFMod.BlowerThrower",Slot=3,Priority=103)
    SlotsAndPrioritiesList=(Weapon="KFMod.BoomStick",Slot=4,Priority=160)
    SlotsAndPrioritiesList=(Weapon="KFMod.Bullpup",Slot=3,Priority=70)
    SlotsAndPrioritiesList=(Weapon="KFMod.CamoM32GrenadeLauncher",Slot=4,Priority=210)
    SlotsAndPrioritiesList=(Weapon="KFMod.CamoM4AssaultRifle",Slot=3,Priority=130)
    SlotsAndPrioritiesList=(Weapon="KFMod.CamoMP5MMedicGun",Slot=3,Priority=80)
    SlotsAndPrioritiesList=(Weapon="KFMod.CamoShotgun",Slot=3,Priority=135)
    SlotsAndPrioritiesList=(Weapon="KFMod.Chainsaw",Slot=4,Priority=150)
    SlotsAndPrioritiesList=(Weapon="KFMod.ClaymoreSword",Slot=1,Priority=115)
    SlotsAndPrioritiesList=(Weapon="KFMod.Crossbow",Slot=4,Priority=140)
    SlotsAndPrioritiesList=(Weapon="KFMod.Crossbuzzsaw",Slot=4,Priority=175)
    SlotsAndPrioritiesList=(Weapon="KFMod.Deagle",Slot=2,Priority=100)
    SlotsAndPrioritiesList=(Weapon="KFMod.Dual44Magnum",Slot=2,Priority=120)
    SlotsAndPrioritiesList=(Weapon="KFMod.DualDeagle",Slot=2,Priority=125)
    SlotsAndPrioritiesList=(Weapon="KFMod.DualFlareRevolver",Slot=2,Priority=120)
    SlotsAndPrioritiesList=(Weapon="KFMod.DualFlareRevolver",Slot=2,Priority=65)
    SlotsAndPrioritiesList=(Weapon="KFMod.DualMK23Pistol",Slot=2,Priority=90)
    SlotsAndPrioritiesList=(Weapon="KFMod.DwarfAxe",Slot=1,Priority=75)
    SlotsAndPrioritiesList=(Weapon="KFMod.FlameThrower",Slot=3,Priority=145)
    SlotsAndPrioritiesList=(Weapon="KFMod.FlareRevolver",Slot=2,Priority=105)
    SlotsAndPrioritiesList=(Weapon="KFMod.FNFAL_ACOG_AssaultRifle",Slot=4,Priority=180)
    SlotsAndPrioritiesList=(Weapon="KFMod.GoldenAA12AutoShotgun",Slot=4,Priority=200)
    SlotsAndPrioritiesList=(Weapon="KFMod.GoldenAK47AssaultRifle",Slot=3,Priority=95)
    SlotsAndPrioritiesList=(Weapon="KFMod.GoldenBenelliShotgun",Slot=3,Priority=170)
    SlotsAndPrioritiesList=(Weapon="KFMod.GoldenChainsaw",Slot=4,Priority=150)
    SlotsAndPrioritiesList=(Weapon="KFMod.GoldenDeagle",Slot=2,Priority=100)
    SlotsAndPrioritiesList=(Weapon="KFMod.GoldenDualDeagle",Slot=2,Priority=125)
    SlotsAndPrioritiesList=(Weapon="KFMod.GoldenFlamethrower",Slot=3,Priority=145)
    SlotsAndPrioritiesList=(Weapon="KFMod.GoldenKatana",Slot=1,Priority=110)
    SlotsAndPrioritiesList=(Weapon="KFMod.GoldenM79GrenadeLauncher",Slot=3,Priority=162)
    SlotsAndPrioritiesList=(Weapon="KFMod.HuskGun",Slot=4,Priority=180)
    SlotsAndPrioritiesList=(Weapon="KFMod.Katana",Slot=1,Priority=110)
    SlotsAndPrioritiesList=(Weapon="KFMod.Knife",Slot=1,Priority=45)
    SlotsAndPrioritiesList=(Weapon="KFMod.KrissMMedicGun",Slot=3,Priority=120)
    SlotsAndPrioritiesList=(Weapon="KFMod.KSGShotgun",Slot=3,Priority=100)
    SlotsAndPrioritiesList=(Weapon="KFMod.LAW",Slot=4,Priority=195)
    SlotsAndPrioritiesList=(Weapon="KFMod.M14EBRBattleRifle",Slot=4,Priority=165)
    SlotsAndPrioritiesList=(Weapon="KFMod.M32GrenadeLauncher",Slot=4,Priority=210)
    SlotsAndPrioritiesList=(Weapon="KFMod.M4203AssaultRifle",Slot=4,Priority=190)
    SlotsAndPrioritiesList=(Weapon="KFMod.M4AssaultRifle",Slot=3,Priority=130)
    SlotsAndPrioritiesList=(Weapon="KFMod.M79GrenadeLauncher",Slot=3,Priority=162)
    SlotsAndPrioritiesList=(Weapon="KFMod.M7A3MMedicGun",Slot=4,Priority=100)
    SlotsAndPrioritiesList=(Weapon="KFMod.M99SniperRifle",Slot=4,Priority=190)
    SlotsAndPrioritiesList=(Weapon="KFMod.MAC10MP",Slot=3,Priority=75)
    SlotsAndPrioritiesList=(Weapon="KFMod.Machete",Slot=1,Priority=50)
    SlotsAndPrioritiesList=(Weapon="KFMod.Magnum44Pistol",Slot=2,Priority=105)
    SlotsAndPrioritiesList=(Weapon="KFMod.MK23Pistol",Slot=2,Priority=65)
    SlotsAndPrioritiesList=(Weapon="KFMod.MKb42AssaultRifle",Slot=3,Priority=115)
    SlotsAndPrioritiesList=(Weapon="KFMod.MP5MMedicGun",Slot=3,Priority=80)
    SlotsAndPrioritiesList=(Weapon="KFMod.MP7MMedicGun",Slot=3,Priority=90)
    SlotsAndPrioritiesList=(Weapon="KFMod.NailGun",Slot=3,Priority=150)
    SlotsAndPrioritiesList=(Weapon="KFMod.NeonAK47AssaultRifle",Slot=3,Priority=95)
    SlotsAndPrioritiesList=(Weapon="KFMod.NeonKrissMMedicGun",Slot=3,Priority=120)
    SlotsAndPrioritiesList=(Weapon="KFMod.NeonKSGShotgun",Slot=3,Priority=100)
    SlotsAndPrioritiesList=(Weapon="KFMod.NeonSCARMK17AssaultRifle",Slot=4,Priority=175)
    SlotsAndPrioritiesList=(Weapon="KFMod.PipeBombExplosive",Slot=4,Priority=1)
    SlotsAndPrioritiesList=(Weapon="KFMod.SCARMK17AssaultRifle",Slot=4,Priority=175)
    SlotsAndPrioritiesList=(Weapon="KFMod.Scythe",Slot=1,Priority=125)
    SlotsAndPrioritiesList=(Weapon="KFMod.SealSquealHarpoonBomber",Slot=4,Priority=171)
    SlotsAndPrioritiesList=(Weapon="KFMod.SeekerSixRocketLauncher",Slot=4,Priority=182)
    SlotsAndPrioritiesList=(Weapon="KFMod.Shotgun",Slot=3,Priority=135)
    SlotsAndPrioritiesList=(Weapon="KFMod.Single",Slot=2,Priority=60)
    SlotsAndPrioritiesList=(Weapon="KFMod.SPAutoShotgun",Slot=4,Priority=167)
    SlotsAndPrioritiesList=(Weapon="KFMod.SPGrenadeLauncher",Slot=3,Priority=164)
    SlotsAndPrioritiesList=(Weapon="KFMod.SPSniperRifle",Slot=3,Priority=155)
    SlotsAndPrioritiesList=(Weapon="KFMod.SPThompsonSMG",Slot=3,Priority=123)
    SlotsAndPrioritiesList=(Weapon="KFMod.Syringe",Slot=5,Priority=6)
    SlotsAndPrioritiesList=(Weapon="KFMod.ThompsonDrumSMG",Slot=3,Priority=124)
    SlotsAndPrioritiesList=(Weapon="KFMod.ThompsonSMG",Slot=3,Priority=120)
    SlotsAndPrioritiesList=(Weapon="KFMod.Trenchgun",Slot=3,Priority=142)
    SlotsAndPrioritiesList=(Weapon="KFMod.Welder",Slot=5,Priority=5)
    SlotsAndPrioritiesList=(Weapon="KFMod.Winchester",Slot=3,Priority=85)
    

    Старая версия мутатора:
    Обновил версию мутатора

    Теперь работает как надо, но надо править ServerPerks.SRHumanPawn
    Иначе работает только назначение слота. В конце поста будет ссылка на версию которая правит только слот для тех, кто
    категорически не хочет вмешиваться в SP или для тех, кому достаточно мутатора меняющего слот.
    В принципе можно сделать полностью независимый мутатор, но я пока не готов столько времени на это потратить ))

    Итак ещё разок:
    Задрали меня игроки на сервере
    Вечно им не угодишь с приоритетами и слотами
    Накидал мутатор - пусть сами настраивают
    Лень было делать GUI интерфейс - сделал просто в виде iniшника

    Настройки мутатора просты:
    Клиент лезет в папку Killing Floor\System, ищет файл SlotsAndPrioritiesMut.ini и правит его
    Например, чтобы поправить приоритет и слот пилы и шприца пишем так
    Код:
    [SlotsAndPrioritiesMut.SlotsAndPrioritiesMut]
    SlotsAndPrioritiesList=(Weapon="KFMod.Chainsaw",Slot=5,Priority=200)
    SlotsAndPrioritiesList=(Weapon="KFMod.Syringe",Slot=1,Priority=1)
    
    Теперь пила у нас на 5 слоте, а шприц на 1. Приоритет у шприца минимальный. Впрочем там и так стоит небольшое число (6),
    так что в этом примере ценности от смены приоритета не видно

    Допустим мы хотим бегать с катаной и мечом, но хотим чтобы при переключении на 1 слот первой доставалась катана
    Правим тогда как-нть так
    Код:
    [SlotsAndPrioritiesMut.SlotsAndPrioritiesMut]
    SlotsAndPrioritiesList=(Weapon="KFMod.ClaymoreSword",Slot=1,Priority=115)
    SlotsAndPrioritiesList=(Weapon="KFMod.Katana",Slot=1,Priority=120) ;был приоритет 110 по умолчанию
    
    Ну и так далее

    Код мутатора:
    Код:
    class SlotsAndPrioritiesMut extends Mutator config(SlotsAndPrioritiesMut);
    
    struct SlotsAndPrioritiesStruct
    {
        var config string Weapon;
        var config int Slot;
        var config int Priority;
    };
    var config array<SlotsAndPrioritiesStruct> SlotsAndPrioritiesList;
    
    simulated function PostBeginPlay()
    {
        local int i;
        local class<Weapon> WeaponClass;
        if(Role==ROLE_Authority) return;
    
        for(i=0;i<SlotsAndPrioritiesList.Length;i++)
        {
            WeaponClass = class<Weapon>(DynamicLoadObject(SlotsAndPrioritiesList[I].Weapon, class'Class'));
            WeaponClass.default.InventoryGroup=SlotsAndPrioritiesList[I].Slot;
        }
        SetTimer(1.0,false);
        SaveConfig();
    }
    
    simulated function Timer()
    {
        local PlayerController PC;
        local int i;
        PC=Level.GetLocalPlayerController();
        if(PC==none) return;
        for(i=0;i<SlotsAndPrioritiesList.Length;i++)
            SRPlayerReplicationInfo(PC.PlayerReplicationInfo).AddSlotsAndPrioritiesOnServer(SlotsAndPrioritiesList[I].Weapon,SlotsAndPrioritiesList[I].Slot,SlotsAndPrioritiesList[I].Priority);
    }
    
    defaultproperties
    {
        RemoteRole=ROLE_SimulatedProxy
        bAlwaysRelevant=true
        bAddToServerPackages=True
        GroupName="KF-SlotsAndPriorities"
        FriendlyName="SlotsAndPrioritiesMut"
        Description="SlotsAndPrioritiesMut"
    }
    

    Теперь меняем ServerPerks:
    1а. Создаём класс SRPlayerReplicationInfo (если уже есть, то просто дополняем) в пакете ServerPerks
    Код:
    class SRPlayerReplicationInfo extends KFPlayerReplicationInfo;
    
    struct SlotsAndPrioritiesStruct
    {
        var config string Weapon;
        var config int Slot;
        var config int Priority;
    };
    var array<SlotsAndPrioritiesStruct> SlotsAndPrioritiesList;
    
    replication
    {
        reliable if ( Role < Role_Authority )
            AddSlotsAndPrioritiesOnServer;
    }
    function AddSlotsAndPrioritiesOnServer(string Weapon,int Slot,int Priority)
    {
        local SlotsAndPrioritiesStruct sap;
        sap.Weapon=Weapon;
        sap.Slot=Slot;
        sap.Priority=Priority;
        SlotsAndPrioritiesList[SlotsAndPrioritiesList.Length]=sap;
    }
    
    1б. Правим ServerPerksMut.ServerPerksMut, чтобы SRPlayerReplicationInfo стал классом репликации для контроллера игрока
    Код:
    function bool CheckReplacement(Actor Other, out byte bSuperRelevant)
    {
        //Flame 2015_04_14
        if( Controller(Other) !=None )
            Controller(Other).PlayerReplicationInfoClass = Class'SRPlayerReplicationInfo';
        //
        ...
    }
    
    2. Правим ServerPerks.SRHumanPawn. Добавляем 3 функции.
    Код:
    class SRHumanPawn extends KFHumanPawn_Story;
    ...
    //Flame 2015_04_14. Используется для смены слота и приоритета пользователем
    function bool AddInventory( inventory NewItem )
    {
        if(!AddInventoryFromPawn(NewItem))
            return false;
        if( KFWeapon(NewItem) != none )
            CurrentWeight += KFWeapon(NewItem).Weight;
        return true;
    }
    function bool AddInventoryFromPawn(inventory NewItem)
    {
        local inventory Inv;
        local actor Last, Prev;
        local bool bAddedInOrder;
    
        //Flame Именно тут правится приоритет и слот
        ChangeSlotAndPriority(NewItem);
        //
    
        Last = self;
        if (NewItem ==None )
            log("tried to add none inventory to "$self);
        NewItem.SetOwner(Self);
        NewItem.NetUpdateTime = Level.TimeSeconds - 1;
        if ( Weapon(NewItem) != None )
        {
            Prev = self;
            for(Inv=Inventory; Inv!=None; Inv=Inv.Inventory)
            {
                if(Inv.InventoryGroup == NewItem.InventoryGroup && Weapon(Inv) != None)
                {
                    if(Weapon(Inv).Priority < Weapon(NewItem).Priority)
                    {
                        bAddedInOrder = true;
                        break;
                    }
                }
                else if ( (Weapon(Prev) != None) && (Weapon(Prev).InventoryGroup == NewItem.InventoryGroup) )
                {
                    bAddedInOrder = true;
                    break;
                }
                if ( !bAddedInOrder )
                    Prev = Inv;
            }
            if ( bAddedInOrder )
            {
                NewItem.Inventory = Prev.Inventory;
                Prev.Inventory = NewItem;
                Prev.NetUpdateTime = Level.TimeSeconds - 1;
            }
        }
        if ( !bAddedInOrder )
        {
            for( Inv=Inventory; Inv!=None; Inv=Inv.Inventory )
            {
                if( Inv == NewItem )
                    return false;
                Last = Inv;
            }
            NewItem.Inventory = None;
            Last.Inventory = NewItem;
            Last.NetUpdateTime = Level.TimeSeconds - 1;
        }
        if ( Controller != None )
            Controller.NotifyAddInventory(NewItem);
        return true;
    }
    
    function ChangeSlotAndPriority(inventory W)
    {
        local int i;
        local SRPlayerReplicationInfo SRPRI;
        SRPRI=SRPlayerReplicationInfo(PlayerReplicationInfo);
        if(Weapon(W)==none) return;
        for(i=0;i<SRPRI.SlotsAndPrioritiesList.Length;i++)
        {
            if(SRPRI.SlotsAndPrioritiesList[I].Weapon~=string(W.Class))
            {
                Weapon(W).Priority=SRPRI.SlotsAndPrioritiesList[I].Priority;
                Weapon(W).InventoryGroup=SRPRI.SlotsAndPrioritiesList[I].Slot;
            }
        }
    }
    ...
    
    Обладатели старой версии SP создают класс с нуля и не забывают прописывать его в KFPCServ
    Код:
    class KFPCServ extends KFPlayerController_Story;
    ...
    defaultproperties
    {
        ...
        PawnClass=Class'SRHumanPawn'
    }
    

    Итак, если у вас чистый SP версии 7.50, то тупо заменяем файлы из System по ссылкам ниже
    Если вы ранее модифицировали что-то - правьте классы вручную согласно инструкции выше.
    Из архива берёте только мутатор SlotsAndPrioritiesMut

    Ссылка 1 или Ссылка 2
    На сервак подключаем мутатор:
    SlotsAndPrioritiesMut.SlotsAndPrioritiesMut
    А клиенту сгенерируется SlotsAndPrioritiesMut.ini после 1 захода на сервер
    Далее он выходит из игры и модифицирует ini файл. После этого заходит и радуется

    И для тех, кому достаточно мутатора меняющего слот:
    Код:
    Код:
    class WeaponSlotsMut extends Mutator config(WeaponSlotsMut);
    
    struct WeaponSlotsStruct
    {
        var config class<KFWeapon> Weapon;
        var config int Slot;
    };
    var config array<WeaponSlotsStruct> WeaponSlotsList;
    
    simulated function PostBeginPlay()
    {
        local int i;
        if(Role==ROLE_Authority) return;
        for(i=0;i<WeaponSlotsList.Length;i++)
            WeaponSlotsList[I].Weapon.default.InventoryGroup=WeaponSlotsList[I].Slot;
        SaveConfig();
    }
    
    defaultproperties
    {
        RemoteRole=ROLE_SimulatedProxy
        bAlwaysRelevant=true
        bAddToServerPackages=True
        WeaponSlotsList(0)=(Weapon=Class'KFMod.AA12AutoShotgun',Slot=4)
        WeaponSlotsList(1)=(Weapon=Class'KFMod.AK47AssaultRifle',Slot=3)
        WeaponSlotsList(2)=(Weapon=Class'KFMod.Axe',Slot=1)
        WeaponSlotsList(3)=(Weapon=Class'KFMod.BenelliShotgun',Slot=3)
        WeaponSlotsList(4)=(Weapon=Class'KFMod.BlowerThrower',Slot=3)
        WeaponSlotsList(5)=(Weapon=Class'KFMod.BoomStick',Slot=4)
        WeaponSlotsList(6)=(Weapon=Class'KFMod.Bullpup',Slot=3)
        WeaponSlotsList(7)=(Weapon=Class'KFMod.CamoM32GrenadeLauncher',Slot=4)
        WeaponSlotsList(8)=(Weapon=Class'KFMod.CamoM4AssaultRifle',Slot=3)
        WeaponSlotsList(9)=(Weapon=Class'KFMod.CamoMP5MMedicGun',Slot=3)
        WeaponSlotsList(10)=(Weapon=Class'KFMod.CamoShotgun',Slot=3)
        WeaponSlotsList(11)=(Weapon=Class'KFMod.Chainsaw',Slot=4)
        WeaponSlotsList(12)=(Weapon=Class'KFMod.ClaymoreSword',Slot=1)
        WeaponSlotsList(13)=(Weapon=Class'KFMod.Crossbow',Slot=4)
        WeaponSlotsList(14)=(Weapon=Class'KFMod.Crossbuzzsaw',Slot=4)
        WeaponSlotsList(15)=(Weapon=Class'KFMod.Deagle',Slot=2)
        WeaponSlotsList(16)=(Weapon=Class'KFMod.Dual44Magnum',Slot=2)
        WeaponSlotsList(17)=(Weapon=Class'KFMod.DualDeagle',Slot=2)
        WeaponSlotsList(18)=(Weapon=Class'KFMod.DualFlareRevolver',Slot=2)
        WeaponSlotsList(19)=(Weapon=Class'KFMod.DualFlareRevolver',Slot=2)
        WeaponSlotsList(20)=(Weapon=Class'KFMod.DualMK23Pistol',Slot=2)
        WeaponSlotsList(21)=(Weapon=Class'KFMod.DwarfAxe',Slot=1)
        WeaponSlotsList(22)=(Weapon=Class'KFMod.FlameThrower',Slot=3)
        WeaponSlotsList(23)=(Weapon=Class'KFMod.FlareRevolver',Slot=2)
        WeaponSlotsList(24)=(Weapon=Class'KFMod.FNFAL_ACOG_AssaultRifle',Slot=4)
        WeaponSlotsList(25)=(Weapon=Class'KFMod.GoldenAA12AutoShotgun',Slot=4)
        WeaponSlotsList(26)=(Weapon=Class'KFMod.GoldenAK47AssaultRifle',Slot=3)
        WeaponSlotsList(27)=(Weapon=Class'KFMod.GoldenBenelliShotgun',Slot=3)
        WeaponSlotsList(28)=(Weapon=Class'KFMod.GoldenChainsaw',Slot=4)
        WeaponSlotsList(29)=(Weapon=Class'KFMod.GoldenDeagle',Slot=2)
        WeaponSlotsList(30)=(Weapon=Class'KFMod.GoldenDualDeagle',Slot=2)
        WeaponSlotsList(31)=(Weapon=Class'KFMod.GoldenFlamethrower',Slot=3)
        WeaponSlotsList(32)=(Weapon=Class'KFMod.GoldenKatana',Slot=1)
        WeaponSlotsList(33)=(Weapon=Class'KFMod.GoldenM79GrenadeLauncher',Slot=3)
        WeaponSlotsList(34)=(Weapon=Class'KFMod.HuskGun',Slot=4)
        WeaponSlotsList(35)=(Weapon=Class'KFMod.Katana',Slot=1)
        WeaponSlotsList(36)=(Weapon=Class'KFMod.Knife',Slot=1)
        WeaponSlotsList(37)=(Weapon=Class'KFMod.KrissMMedicGun',Slot=3)
        WeaponSlotsList(38)=(Weapon=Class'KFMod.KSGShotgun',Slot=3)
        WeaponSlotsList(39)=(Weapon=Class'KFMod.LAW',Slot=4)
        WeaponSlotsList(40)=(Weapon=Class'KFMod.M14EBRBattleRifle',Slot=4)
        WeaponSlotsList(41)=(Weapon=Class'KFMod.M32GrenadeLauncher',Slot=4)
        WeaponSlotsList(42)=(Weapon=Class'KFMod.M4203AssaultRifle',Slot=4)
        WeaponSlotsList(43)=(Weapon=Class'KFMod.M4AssaultRifle',Slot=3)
        WeaponSlotsList(44)=(Weapon=Class'KFMod.M79GrenadeLauncher',Slot=3)
        WeaponSlotsList(45)=(Weapon=Class'KFMod.M7A3MMedicGun',Slot=4)
        WeaponSlotsList(46)=(Weapon=Class'KFMod.M99SniperRifle',Slot=4)
        WeaponSlotsList(47)=(Weapon=Class'KFMod.MAC10MP',Slot=3)
        WeaponSlotsList(48)=(Weapon=Class'KFMod.Machete',Slot=1)
        WeaponSlotsList(49)=(Weapon=Class'KFMod.Magnum44Pistol',Slot=2)
        WeaponSlotsList(50)=(Weapon=Class'KFMod.MK23Pistol',Slot=2)
        WeaponSlotsList(51)=(Weapon=Class'KFMod.MKb42AssaultRifle',Slot=3)
        WeaponSlotsList(52)=(Weapon=Class'KFMod.MP5MMedicGun',Slot=3)
        WeaponSlotsList(53)=(Weapon=Class'KFMod.MP7MMedicGun',Slot=3)
        WeaponSlotsList(54)=(Weapon=Class'KFMod.NailGun',Slot=3)
        WeaponSlotsList(55)=(Weapon=Class'KFMod.NeonAK47AssaultRifle',Slot=3)
        WeaponSlotsList(56)=(Weapon=Class'KFMod.NeonKrissMMedicGun',Slot=3)
        WeaponSlotsList(57)=(Weapon=Class'KFMod.NeonKSGShotgun',Slot=3)
        WeaponSlotsList(58)=(Weapon=Class'KFMod.NeonSCARMK17AssaultRifle',Slot=4)
        WeaponSlotsList(59)=(Weapon=Class'KFMod.PipeBombExplosive',Slot=4)
        WeaponSlotsList(60)=(Weapon=Class'KFMod.SCARMK17AssaultRifle',Slot=4)
        WeaponSlotsList(61)=(Weapon=Class'KFMod.Scythe',Slot=1)
        WeaponSlotsList(62)=(Weapon=Class'KFMod.SealSquealHarpoonBomber',Slot=4)
        WeaponSlotsList(63)=(Weapon=Class'KFMod.SeekerSixRocketLauncher',Slot=4)
        WeaponSlotsList(64)=(Weapon=Class'KFMod.Shotgun',Slot=3)
        WeaponSlotsList(65)=(Weapon=Class'KFMod.Single',Slot=2)
        WeaponSlotsList(66)=(Weapon=Class'KFMod.SPAutoShotgun',Slot=4)
        WeaponSlotsList(67)=(Weapon=Class'KFMod.SPGrenadeLauncher',Slot=3)
        WeaponSlotsList(68)=(Weapon=Class'KFMod.SPSniperRifle',Slot=3)
        WeaponSlotsList(69)=(Weapon=Class'KFMod.SPThompsonSMG',Slot=3)
        WeaponSlotsList(70)=(Weapon=Class'KFMod.Syringe',Slot=5)
        WeaponSlotsList(71)=(Weapon=Class'KFMod.ThompsonDrumSMG',Slot=3)
        WeaponSlotsList(72)=(Weapon=Class'KFMod.ThompsonSMG',Slot=3)
        WeaponSlotsList(73)=(Weapon=Class'KFMod.Trenchgun',Slot=3)
        WeaponSlotsList(74)=(Weapon=Class'KFMod.Welder',Slot=5)
        WeaponSlotsList(75)=(Weapon=Class'KFMod.Winchester',Slot=3)
        GroupName="KF-WeaponSlots"
        FriendlyName="WeaponSlotsMut"
        Description="WeaponSlotsMut"
    }
    

    Ссылка 1 или Ссылка 2
    WeaponSlotsMut.WeaponSlotsMut
     
    Последнее редактирование: 14 окт 2016
    siriushard, Denkul999, ЛОХМАТЫЙ и 6 другим нравится это.
  2. Flame

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

    Обновил мутатор. Теперь что заявлено, то и делает)
     
    siriushard, ЛОХМАТЫЙ и AitherKill нравится это.
  3. Flame

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

    Мутатор обновлён. Теперь он не зависит от ServerPerks и у него добавилось чуток настроек и функций
    Пользуйтесь на свой страх и риск и сообщайте об ошибках)