Browse Source

Add `FixLogSpam` feature

master
Anton Tarasenko 4 years ago
parent
commit
5a118a5b23
  1. 62
      sources/FixLogSpam/FixLogSpam.uc
  2. 213
      sources/FixLogSpam/SpamPickup/HelperPickup.uc
  3. 40
      sources/FixLogSpam/SpamPickup/MutatorListener_FixLogSpam_Pickup.uc
  4. 38
      sources/FixLogSpam/SpamPickup/PickupSpamRule.uc
  5. 21
      sources/Manifest.uc

62
sources/FixLogSpam/FixLogSpam.uc

@ -0,0 +1,62 @@
/**
* This feature fixes different instances of log spam by the killing floor
* with various warnings and errors. Some of them have actual underlying bugs
* that need to be fixed, but a lot seem to be just a byproduct of dead and
* abandoned features or simple negligence.
* Whatever the case, now that TWI will no longer make any new changes to
* the game a lot of them do not serve any purpose and simply pollute
* log files. We try to get rid of at least some of them.
* Since changes we make do not actually have gameplay effect and
* are more aimed at convenience of server owners, our philosophy with the
* changes will be to avoid solutions that are way too "hacky" and prefer some
* message spam getting through to the possibility of some unexpected gameplay
* effects as far as vanilla game is concerned.
* Copyright 2021 Anton Tarasenko
*------------------------------------------------------------------------------
* This file is part of Acedia.
*
* Acedia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License, or
* (at your option) any later version.
*
* Acedia is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Acedia. If not, see <https://www.gnu.org/licenses/>.
*/
class FixLogSpam extends Feature
config(AcediaFixes);
// This is responsible for fixing log spam due to picking up dropped
// weapons without set `inventory` variable.
var private const bool fixPickupSpam;
var private HelperPickup helperPickupSpam;
protected function OnEnabled()
{
if (fixPickupSpam) {
helperPickupSpam = HelperPickup(_.memory.Allocate(class'HelperPickup'));
}
}
protected function OnDisabled()
{
_.memory.Free(helperPickupSpam);
helperPickupSpam = none;
}
public function Tick(float delta)
{
if (helperPickupSpam != none) {
helperPickupSpam.Tick();
}
}
defaultproperties
{
fixPickupSpam = true
}

213
sources/FixLogSpam/SpamPickup/HelperPickup.uc

@ -0,0 +1,213 @@
/**
* Helper object for `FixLogSpam` fix, responsible for fixing log spam
* due to picking up dropped weapons without set `inventory` variable.
* Copyright 2021 Anton Tarasenko
*------------------------------------------------------------------------------
* This file is part of Acedia.
*
* Acedia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License, or
* (at your option) any later version.
*
* Acedia is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Acedia. If not, see <https://www.gnu.org/licenses/>.
*/
class HelperPickup extends AcediaObject
config(AcediaFixes);
/**
* `KFWeaponPickup` class is responsible for spamming log with
* error messages about missing `inventory` actor: "Accessed None 'Inventory'".
* This is caused by `Destroyed()` event that tries to call `KFGameType`'s
* `WeaponDestroyed()` on pickup's `inventory.class`, but it fails because
* `inventory` is essentially guaranteed to be `none` for pickups dropped
* by players. Since no `inventory != none` check is made, this leads to
* log message spam.
* To fix it we simply disable `Destroyed()` event altogether, since all
* it does is:
* 1. Fails as we have described;
* 2. In `super(Pickup).Destroyed()` sets `myMarker.markedItem` to `none`,
* which does nothig for pickups dropped by players, since they do not
* have any `myMarker` in the first place: they are usually defined to
* refer to `InventorySpot`s, generated for placed pickups when
* navigation paths are built.
*
* The are two issues that need resolving for this solution to work:
* 1. Distinguish between pickups dropped by the player versus pickups
* placed on the map;
* 2. Even if one disables `Destroyed()` event, it can get re-enabled again
* (possibly by a state change).
* One way to accomplish the first goal is to check `instigator` during
* `CheckReplacement()` event: it should be `none` for map pickups and point
* to the player's pawn for dropped pickups. If, for some reason, instigator
* would end up being equal to `none` for a dropped pickup, we also record all
* the other pickups and give them some time to initialize
* (`CheckReplacement()` is called at the moment they are spawned and
* before initialization logic is completed) and check their `bDropped` flag,
* since it is what decides whether log message about accessing `none`-value
* will be output: `if ( bDropped && class<Weapon>(Inventory.Class) != none )`.
* Then we also try to fix all the weapons with `bDropped == true`.
* To resolve issue with `Destroyed()` event being re-enabled we use
* brute force approach of disabling it every tick:
* 1. Amount of dropped pickups is small enough for it to not cause
* performance issues;
* 2. Checking change in state or trying to determine other causes for
* re-enabling the event would likely just lead to more complicated
* logic with around the same or even worse performance.
* We also enforce additional update when we catch player trying to pickup some
* `KFWeaponPickup` with `GameRules`'s `OverridePickupQuery()`, which is
* called soon before pickup's destruction. Note that this update cannot
* replace update inside the `Tick()`, since pickup can be destroyed without
* being picked up, i.e. at the start of each wave.
*
* Described method does not 100% guarantee removal of the related spam
* messages, but should make them virtually impossible. At least on
* vanilla servers.
*/
// For easy access in relevant `GameRules` and mutator event listener.
var private HelperPickup singletonInstance;
// Already fixed pickups that we periodically "refix".
var private array<KFWeaponPickup> recordedPickups;
// Pickups that will get `bDropped` flag checked the next tick to
// determine if we need to fix them.
var private array<KFWeaponPickup> pendingPickups;
protected function Constructor()
{
local LevelInfo level;
local KFWeaponPickup nextPickup;
if (default.singletonInstance == none) {
default.singletonInstance = self;
}
// To detect when player tries to pick something up
// (and force additional pickup fix update)
_.unreal.AddGameRules(class'PickupSpamRule');
// To detect newly spawned pickups
class'MutatorListener_FixLogSpam_Pickup'.static.SetActive(true);
// Find all `KFWeaponPickup`s laying around on the map,
// so that we can fix preexisting ones too.
// But add them to pending list in a freaky case this `HealperPickup`
// was created during one's initialization. This will give it time to
// set up variables that distinguish dropped pickup from another
// kind of pickup.
level = _.unreal.GetLevel();
foreach level.DynamicActors(class'KFMod.KFWeaponPickup', nextPickup) {
pendingPickups[pendingPickups.length] = nextPickup;
}
}
protected function Finalizer()
{
local int i;
for (i = 0; i < recordedPickups.length; i += 1)
{
if (recordedPickups[i] != none && !recordedPickups[i].bPendingDelete) {
recordedPickups[i].Enable('Destroyed');
}
}
recordedPickups.length = 0;
pendingPickups.length = 0;
_.unreal.RemoveGameRules(class'PickupSpamRule');
class'MutatorListener_FixLogSpam_Pickup'.static.SetActive(false);
}
public final static function HelperPickup GetInstance()
{
return default.singletonInstance;
}
// Checks whether given pickup is recorded in any of our records,
// including pending pickups.
// `none` is never recorded.
private final function bool IsPickupRecorded(KFWeaponPickup pickupToCheck)
{
local int i;
if (pickupToCheck == none) {
return false;
}
for (i = 0; i < recordedPickups.length; i += 1)
{
if (recordedPickups[i] == pickupToCheck) {
return true;
}
}
for (i = 0; i < pendingPickups.length; i += 1)
{
if (pendingPickups[i] == pickupToCheck) {
return true;
}
}
return false;
}
// Gets rid of pickups that got destroyed at some point and now are set
// to `none`.
private final function CleanRecordedPickups()
{
local int i;
while (i < recordedPickups.length)
{
if (recordedPickups[i] == none) {
recordedPickups.Remove(i, 1);
}
else {
i += 1;
}
}
}
// Makes helper handle given pickup `newPickup` by either fixing it or
// delaying to check whether it is dropped.
public final function HandlePickup(KFWeaponPickup newPickup)
{
if (newPickup == none) return;
if (IsPickupRecorded(newPickup)) return;
if (newPickup.instigator != none)
{
newPickup.Disable('Destroyed');
recordedPickups[recordedPickups.length] = newPickup;
}
else {
pendingPickups[pendingPickups.length] = newPickup;
}
}
// Re-disables `Destroyed()` event for all recorded (confirmed) dropped pickups
// and processes all pending (for the check if they are dropped) pickups.
public final function UpdatePickups()
{
local int i;
for (i = 0; i < recordedPickups.length; i += 1)
{
if (recordedPickups[i] != none) {
recordedPickups[i].Disable('Destroyed');
}
}
for (i = 0; i < pendingPickups.length; i += 1)
{
if (pendingPickups[i].bDropped)
{
pendingPickups[i].Disable('Destroyed');
recordedPickups[recordedPickups.length] = pendingPickups[i];
}
}
pendingPickups.length = 0;
}
public final function Tick()
{
CleanRecordedPickups();
UpdatePickups();
}
defaultproperties
{
}

40
sources/FixLogSpam/SpamPickup/MutatorListener_FixLogSpam_Pickup.uc

@ -0,0 +1,40 @@
/**
* Overloaded mutator events listener to catch and, possibly,
* prevent spawning `KFWeaponPickup` for fixing log spam related to them.
* Copyright 2021 Anton Tarasenko
*------------------------------------------------------------------------------
* This file is part of Acedia.
*
* Acedia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License, or
* (at your option) any later version.
*
* Acedia is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Acedia. If not, see <https://www.gnu.org/licenses/>.
*/
class MutatorListener_FixLogSpam_Pickup extends MutatorListenerBase
abstract;
static function bool CheckReplacement(Actor other, out byte isSuperRelevant)
{
local HelperPickup helper;
local KFWeaponPickup otherPickup;
otherPickup = KFWeaponPickup(other);
if (otherPickup == none) return true;
helper = class'HelperPickup'.static.GetInstance();
if (helper == none) return true;
helper.HandlePickup(otherPickup);
return true;
}
defaultproperties
{
relatedEvents = class'MutatorEvents'
}

38
sources/FixLogSpam/SpamPickup/PickupSpamRule.uc

@ -0,0 +1,38 @@
/**
* This rule detects when someone is trying to... pick up a pickup and
* forces additional fixing update on all the ones, dropped by players.
* Copyright 2021 Anton Tarasenko
*------------------------------------------------------------------------------
* This file is part of Acedia.
*
* Acedia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License, or
* (at your option) any later version.
*
* Acedia is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Acedia. If not, see <https://www.gnu.org/licenses/>.
*/
class PickupSpamRule extends GameRules;
function bool OverridePickupQuery(
Pawn toucher,
Pickup touchedPickup,
out byte allowPickup)
{
local HelperPickup helper;
helper = class'HelperPickup'.static.GetInstance();
if (helper != none) {
helper.UpdatePickups();
}
return super.OverridePickupQuery(toucher, touchedPickup, allowPickup);
}
defaultproperties
{
}

21
sources/Manifest.uc

@ -22,14 +22,15 @@
defaultproperties
{
features(0) = class'FixZedTimeLags'
features(1) = class'FixDoshSpam'
features(2) = class'FixFFHack'
features(3) = class'FixInfiniteNades'
features(4) = class'FixAmmoSelling'
features(5) = class'FixSpectatorCrash'
features(6) = class'FixDualiesCost'
features(7) = class'FixInventoryAbuse'
features(8) = class'FixProjectileFF'
features(9) = class'FixPipes'
features(0) = class'FixZedTimeLags'
features(1) = class'FixDoshSpam'
features(2) = class'FixFFHack'
features(3) = class'FixInfiniteNades'
features(4) = class'FixAmmoSelling'
features(5) = class'FixSpectatorCrash'
features(6) = class'FixDualiesCost'
features(7) = class'FixInventoryAbuse'
features(8) = class'FixProjectileFF'
features(9) = class'FixPipes'
features(10) = class'FixLogSpam'
}
Loading…
Cancel
Save