Доброго времени суток. Есть мутатор и его исходный код для рандомного респауна оружия на карте. Исходный код получен не при декомпиляции мутатора, а от самого автора. Вот его исходник:
тут
//========================================= // Copyright(c) Nolan Richert, RuneStorm. All Rights Reserved. // **RuneStorm Ballistic Weapons Class** // // Ballistic Mutator // Started: 09/05/2009. // Updated: 11/05/2009. // Coder: Nolan Richert. // Coder: Logan Richert. // // Switches default weapons with any number of other weapons. // // Objectives: // -Implement standard Multi-Switching mutator. //=============================== class UTMutator_BallisticWeapons extends UTMutator config(Game); struct WeaponChange { var float NextChangeTime; // Time when next a change should occur var UTWeaponPickupFactory Factory; // The Factory that will change }; struct AmmoChange { var float NextChangeTime; // Time when next a change should occur var UTAmmoPickupFactory Factory; // The Factory that will change }; struct LockerChange { var float NextChangeTime; // Time when next a change should occur var UTWeaponLocker Locker; // The Locker that will change }; struct ItemSwitch { var name OldWeaponName; // Name of old weapon class to replace. var name OldAmmoName; // Name of old anmmo class to replace. var() array<string> NewWeaponNames; // Possible Names of New Weapon classes to replace the old one with. var() array<string> NewAmmoNames; // Possible Names of New Ammo classes to replace the old one with. var int CurrentIndex; // Current random index in NewWeaponNames var array<WeaponChange> WeaponFactories; // All WeapFactories affected by this swap var array<AmmoChange> AmmoFactories; // All AmmoFactories affected by this swap }; var array<LockerChange> Lockers; // FIXME: Config??? var() array<ItemSwitch> WeaponSwaps; // List of weapons and their corresponding ammo, and what weapons and ammos to replace each one with. var config float SwapInterval; // Time(in seconds) between weapons switching with others in the same swap list. var float LastReplaceTime; // Time when the ChechReplacement() function last ran. var bool bInitializedAmmo; // Has the ammo been set up at start. var() array<int> DefaultInventorySwaps; function InitMutator(string Options, out string ErrorMessage) { InitSwaps(); MakeDefaultInventoryList(); SetTimer(5.0, true,'WeaponChangeTimer'); Super.InitMutator(Options, ErrorMessage); } function InitSwaps() { local int i; for (i = 0; i < WeaponSwaps.length; i++) { if (WeaponSwaps[i].NewWeaponNames.length < 1) WeaponSwaps[i].CurrentIndex = -1; else WeaponSwaps[i].CurrentIndex = Rand( WeaponSwaps[i].NewWeaponNames.length ); } } /** * This is going to go through the game's default inventory and make a list * of which of our own swappers should be used to replace the game's definv */ function MakeDefaultInventoryList() { local UTGame Game; local int i, Index; Game = UTGame(WorldInfo.Game); if (Game == None) { `log("Error: MakeDefaultInventoryList: No Game!"); return; } // go through Games definv for (i = 0; i < Game.DefaultInventory.length; i++) { if ( Game.DefaultInventory[i] != None) { // Find replacement Index = WeaponSwaps.Find( 'OldWeaponName', Game.DefaultInventory[i].Name); if (Index != INDEX_NONE) { // If there is one, DefaultInventorySwaps[DefaultInventorySwaps.length] = Index; Game.DefaultInventory.Remove(i, 1); i--; } } } } // EventPath: // Game::RestartPlayer->Game::AddDefaultInventory // Game::SetPlayerDefaults->Mut::ModifyPlayer function ModifyPlayer(Pawn Other) { local class<UTWeapon> NewWeaponClass; local int i, RandIndex; super.ModifyPlayer( Other ); // If the mutator initialized properly, the game should have no (or ones that can be replaced cut out) // defaultinventory and this mut should have a list of what to give the player instead // Add a weapon from each of the DefaultInventorySwaps for (i=0; i<DefaultInventorySwaps.length; i++) { if (WeaponSwaps[ DefaultInventorySwaps[i] ].NewWeaponNames.length < 1) continue; // Get random index into NewWeaponNames list of this swapper RandIndex = Rand( WeaponSwaps[ DefaultInventorySwaps[i] ].NewWeaponNames.length ); // Load the class NewWeaponClass = class<UTWeapon>(DynamicLoadObject(WeaponSwaps[DefaultInventorySwaps[i]].NewWeaponNames[RandIndex], class'Class')); // Hand it over Other.CreateInventory(NewWeaponClass, i > 0); } } function ReplaceWeaponPickup (UTWeaponPickupFactory WeaponPickup, int SwapIndex) { if (WeaponSwaps[SwapIndex].CurrentIndex > -1 && WeaponSwaps[SwapIndex].NewWeaponNames.length > WeaponSwaps[SwapIndex].CurrentIndex && WeaponSwaps[SwapIndex].NewWeaponNames[WeaponSwaps[SwapIndex].CurrentIndex]!="") { WeaponPickup.WeaponPickupClass = class<UTWeapon>(DynamicLoadObject(WeaponSwaps[SwapIndex].NewWeaponNames[WeaponSwaps[SwapIndex].CurrentIndex], class'Class')); WeaponPickup.InitializePickup(); WeaponPickup.Customers.length = 0; } } function ReplaceAmmoPickup (UTAmmoPickupFactory AmmoPickup, int SwapIndex) { local class <UTAmmoPickupFactory> NewAmmoClass; // Change it now if (WeaponSwaps[SwapIndex].CurrentIndex > -1 && WeaponSwaps[SwapIndex].NewAmmoNames.length > WeaponSwaps[SwapIndex].CurrentIndex && WeaponSwaps[SwapIndex].NewAmmoNames[WeaponSwaps[SwapIndex].CurrentIndex]!="") { NewAmmoClass = class<UTAmmoPickupFactory>(DynamicLoadObject(WeaponSwaps[SwapIndex].NewAmmoNames[WeaponSwaps[SwapIndex].CurrentIndex], class'Class')); if (NewAmmoClass != None) { // transform the current ammo into the desired class AmmoPickup.TransformAmmoType(NewAmmoClass); } } } /** * Randomly swap all factories to different weapons */ function WeaponChangeTimer() { local int i, j, r, Index; // Run through all swaps for (i=0; i<WeaponSwaps.length; i++) { // Only bother if it has more than 1 new possibility if (WeaponSwaps[i].NewWeaponNames.length > 1) { // Try pick a new random index r = Rand(WeaponSwaps[i].NewWeaponNames.length); if (r == WeaponSwaps[i].CurrentIndex) { r++; if (r >= WeaponSwaps[i].NewWeaponNames.length) r=0; } WeaponSwaps[i].CurrentIndex = r; // Replace all weapon pickups for (j=0; j<WeaponSwaps[i].WeaponFactories.length; j++) { if (WeaponSwaps[i].WeaponFactories[j].Factory != None && WorldInfo.TimeSeconds >= WeaponSwaps[i].WeaponFactories[j].NextChangeTime && (WeaponSwaps[i].WeaponFactories[j].Factory.bPickupHidden || !WeaponSwaps[i].WeaponFactories[j].Factory.PlayerCanSeeMe())) { ReplaceWeaponPickup(WeaponSwaps[i].WeaponFactories[j].Factory, i); WeaponSwaps[i].WeaponFactories[j].NextChangeTime = WorldInfo.TimeSeconds + SwapInterval; } } // Replace all ammo pickups for (j=0; j<WeaponSwaps[i].AmmoFactories.length; j++) { if (WeaponSwaps[i].AmmoFactories[j].Factory != None && WorldInfo.TimeSeconds >= WeaponSwaps[i].AmmoFactories[j].NextChangeTime && (WeaponSwaps[i].AmmoFactories[j].Factory.bPickupHidden || !WeaponSwaps[i].AmmoFactories[j].Factory.PlayerCanSeeMe())) { ReplaceAmmoPickup(WeaponSwaps[i].AmmoFactories[j].Factory, i); WeaponSwaps[i].AmmoFactories[j].NextChangeTime = WorldInfo.TimeSeconds + SwapInterval; } } } } for (i=0; i<Lockers.length; i++) { if ( Lockers[i].Locker != None && WorldInfo.TimeSeconds >= WeaponSwaps[i].AmmoFactories[j].NextChangeTime && !Lockers[i].Locker.PlayerCanSeeMe() ) { for (j = 0; j < Lockers[i].Locker.Weapons.length; j++) { if (Lockers[i].Locker.Weapons[j].WeaponClass != None) { Index = WeaponSwaps.Find( 'OldWeaponName', Lockers[i].Locker.Weapons[j].WeaponClass.Name); if (Index != INDEX_NONE && WeaponSwaps[Index].CurrentIndex > -1 && WeaponSwaps[Index].NewWeaponNames.length > WeaponSwaps[Index].CurrentIndex && WeaponSwaps[Index].NewWeaponNames[WeaponSwaps[Index].CurrentIndex]!="") { Lockers[i].Locker.ReplaceWeapon(j, class<UTWeapon>(DynamicLoadObject(WeaponSwaps[Index].NewWeaponNames[WeaponSwaps[Index].CurrentIndex], class'Class'))); } } // else // break; } } } } function ReplaceBotFavorites(UTBot Bot) { local int Index, RandPick; if (Bot != None && Bot.FavoriteWeapon != None) { Index = WeaponSwaps.Find('OldWeaponName', Bot.FavoriteWeapon.name); RandPick = Rand(WeaponSwaps[Index].NewWeaponNames.Length); if (Index != INDEX_NONE && WeaponSwaps[Index].NewWeaponNames[RandPick] != "") Bot.FavoriteWeapon = class<UTWeapon>(DynamicLoadObject(WeaponSwaps[Index].NewWeaponNames[RandPick], class'Class')); } } // Check for item replacement. function bool CheckReplacement(Actor Other) { local UTAmmoPickupFactory AmmoPickup; local UTWeaponPickupFactory WeaponPickup; // local class <UTAmmoPickupFactory> NewAmmoClass; local UTWeaponLocker Locker; local int i, Index; // Got a weapon pickup factory WeaponPickup = UTWeaponPickupFactory(Other); if (WeaponPickup != None) { if (WeaponPickup.WeaponPickupClass != None) { // Check if this WPF is to be replaced Index = WeaponSwaps.Find( 'OldWeaponName', WeaponPickup.WeaponPickupClass.Name); if (Index != INDEX_NONE) { // Remember this WPF. We will need to mess with it later WeaponSwaps[Index].WeaponFactories.length = WeaponSwaps[Index].WeaponFactories.length + 1; WeaponSwaps[Index].WeaponFactories[WeaponSwaps[Index].WeaponFactories.length-1].Factory = WeaponPickup; // Change it now ReplaceWeaponPickup(WeaponPickup, Index); WeaponSwaps[Index].WeaponFactories[WeaponSwaps[Index].WeaponFactories.length-1].NextChangeTime = WorldInfo.TimeSeconds + SwapInterval; } } } // Got a locker else { Locker = UTWeaponLocker(Other); if (Locker != None) { // Bookmark the locker so we can easily mess with it later! Lockers.length = Lockers.length + 1; Lockers[Lockers.length-1].Locker = Locker; Lockers[Lockers.length-1].NextChangeTime = WorldInfo.TimeSeconds + SwapInterval; for (i = 0; i < Locker.Weapons.length; i++) { if (Locker.Weapons[i].WeaponClass != None) { Index = WeaponSwaps.Find( 'OldWeaponName', Locker.Weapons[i].WeaponClass.Name); if (Index != INDEX_NONE && WeaponSwaps[Index].CurrentIndex > -1 && WeaponSwaps[Index].NewWeaponNames.length > WeaponSwaps[Index].CurrentIndex && WeaponSwaps[Index].NewWeaponNames[WeaponSwaps[Index].CurrentIndex]!="") { Locker.ReplaceWeapon(i, class<UTWeapon>(DynamicLoadObject(WeaponSwaps[Index].NewWeaponNames[WeaponSwaps[Index].CurrentIndex], class'Class'))); } } // else // break; } } // Got ammo else { AmmoPickup = UTAmmoPickupFactory(Other); if (AmmoPickup != None) { // Check if this APF is to be replaced Index = WeaponSwaps.Find( 'OldAmmoName', AmmoPickup.class.Name); if (Index != INDEX_NONE) { // Remember this APF. We will need to mess with it later WeaponSwaps[Index].AmmoFactories.length = WeaponSwaps[Index].AmmoFactories.length + 1; WeaponSwaps[Index].AmmoFactories[WeaponSwaps[Index].AmmoFactories.length-1].Factory = AmmoPickup; // Change it now ReplaceAmmoPickup(AmmoPickup, Index); WeaponSwaps[Index].AmmoFactories[WeaponSwaps[Index].AmmoFactories.length-1].NextChangeTime = WorldInfo.TimeSeconds + SwapInterval; } } } } LastReplaceTime = WorldInfo.TimeSeconds; return true; } defaultproperties { // This can be compatible with Titan mutator? // GroupNames[0]="WEAPONMOD" WeaponSwaps(0)=(OldWeaponName="UTWeap_ImpactHammer",NewWeaponNames=("UT3_BallisticWeapons.RSBWWeap_EKS43Katana","UT3_BallisticWeapons.RSBWWeap_X4Knife","CxGame.CxWeap_Melee","CxGame.CxWeap_Sword")) WeaponSwaps(1)=(OldWeaponName="UTWeap_Enforcer",OldAmmoName="UTAmmo_Enforcer",NewWeaponNames=("BallisticWeapons.BWWeap_M806Pistol","BallisticWeapons.BWWeap_GRS9Pistol","BallisticWeapons.BWWeap_WilsonRevolver","BallisticWeapons.BWWeap_RS8Pistol","BallisticWeapons.BWWeap_OAPistol","BallisticWeapons.BWWeap_D49Magnum","BallisticWeapons.BWWeap_AM67Pistol","UT3Crucible.Weap_Pistol"),NewAmmoNames=("BallisticWeapons.Ammo_M806Pistol","BallisticWeapons.Ammo_GRS9Pistol","BallisticWeapons.Ammo_WilsonRevolver","BallisticWeapons.Ammo_RS8Pistol","BallisticWeapons.Ammo_OAPistol","BallisticWeapons.Ammo_D49Magnum","BallisticWeapons.Ammo_AM67Pistol","UT3Crucible.Ammo_Pistol")) WeaponSwaps(2)=(OldWeaponName="UTWeap_BioRifle_Content",OldAmmoName="UTAmmo_BioRifle_Content",NewWeaponNames=("BallisticWeapons.BWWeap_NRP57Grenade","UT3Crucible.Weap_Grenade"),NewAmmoNames=("BallisticWeapons.Ammo_NRP57Grenade","UT3Crucible.Ammo_Grenade")) WeaponSwaps(3)=(OldWeaponName="UTWeap_ShockRifle",OldAmmoName="UTAmmo_ShockRifle",NewWeaponNames=("BallisticWeapons.BWWeap_M50Assault","BallisticWeapons.BWWeap_SARAssault","UT3Crucible.Weap_AssaultRifle"),NewAmmoNames=("BallisticWeapons.Ammo_M50Assault","BallisticWeapons.Ammo_SAR","UT3Crucible.Ammo_AssaultRifle")) WeaponSwaps(4)=(OldWeaponName="UTWeap_LinkGun",OldAmmoName="UTAmmo_LinkGun",NewWeaponNames=("MutCustomizableUT.UTWeap_CustomizableLinkGun","BallisticWeapons.BWWeap_Fifty9SMG","BallisticWeapons.BWWeap_XRS10SMG","BallisticWeapons.BWWeap_OASMG","BallisticWeapons.BWWeap_XK2SMG","UT3Crucible.Weap_Lightninggun"),NewAmmoNames=("MutCustomizableUT.UTAmmo_CustomizableLinkGun","BallisticWeapons.Ammo_Fifty9SMG","BallisticWeapons.Ammo_XRS10SMG","BallisticWeapons.Ammo_OASMG","BallisticWeapons.Ammo_XK2SMG","UT3Crucible.Ammo_Lightninggun")) WeaponSwaps(5)=(OldWeaponName="UTWeap_Stinger",OldAmmoName="UTAmmo_Stinger",NewWeaponNames=("BallisticWeapons.BWWeap_M353Machinegun","BallisticWeapons.BWWeap_M925Machinegun","UT3Crucible.Weap_Machinegun"),NewAmmoNames=("BallisticWeapons.Ammo_M353Machinegun","BallisticWeapons.Ammo_M925Machinegun","UT3Crucible.Ammo_Machinegun")) WeaponSwaps(6)=(OldWeaponName="UTWeap_FlakCannon",OldAmmoName="UTAmmo_FlakCannon",NewWeaponNames=("BallisticWeapons.BWWeap_M290Shotgun","BallisticWeapons.BWWeap_MRS38Shotgun","UT3Crucible.Weap_Shotgun"),NewAmmoNames=("BallisticWeapons.Ammo_M290Shotgun","BallisticWeapons.Ammo_MRS38Shotgun","UT3Crucible.Ammo_Shotgun")) WeaponSwaps(7)=(OldWeaponName="UTWeap_RocketLauncher",OldAmmoName="UTAmmo_RocketLauncher",NewWeaponNames=("BallisticWeapons.BWWeap_G5Bazooka","UT3Crucible.Weap_RocketLauncher"),NewAmmoNames=("BallisticWeapons.Ammo_G5Bazooka","UT3Crucible.Ammo_RocketLauncher")) WeaponSwaps(8)=(OldWeaponName="UTWeap_SniperRifle",OldAmmoName="UTAmmo_SniperRifle",NewWeaponNames=("BallisticWeapons.BWWeap_R78SniperRifle","BallisticWeapons.BWWeap_R9Rifle","BallisticWeapons.BWWeap_SRS900AutoRifle","BallisticWeapons.BWWeap_MarlinRifle","UT3Crucible.Weap_SniperRifle"),NewAmmoNames=("BallisticWeapons.Ammo_R78SniperRifle","BallisticWeapons.Ammo_R9Rifle","BallisticWeapons.Ammo_SRS","BallisticWeapons.Ammo_MarlinRifle","UT3Crucible.Ammo_SniperRifle")) WeaponSwaps(9)=(OldWeaponName="UTWeap_Avril_Content",OldAmmoName="UTAmmo_Avril_Content",NewWeaponNames=("MutCustomizableUT.UTWeap_CustomizableAvril"),NewAmmoNames=("MutCustomizableUT.UTAmmo_CustomizableAVRiL")) WeaponSwaps(10)=(OldWeaponName="UTWeap_Redeemer_Content",NewWeaponNames=("MutCustomizableUT.UTWeap_CustomizableRedeemer","BallisticWeapons.BWWeap_XMV850Minigun")) SwapInterval=60.0 // bNetTemporary=True // bAlwaysRelevant=True // RemoteRole=ROLE_SimulatedProxy }
Собственно проблема в том, что любой клиент подключаемый к серверу с этим мутатором получает вылет из игры через 5-10 минут (иногда раньше, иногда позже). Log:
При этом сам сервер работает отлично, без вылетов и т.п., и без разницы выделенный это или просто хост.
1. Возможно в коде допущена семантическая ошибка и у клиента спаунятся дубликаты.
2. Возможно ошибка в десинхроне респауна оружия между клиентом и сервером.