This repository has been archived on 2022-08-08. You can view files and clone it, but cannot push or open issues or pull requests.
Acedia/sources/Packages.uc
Anton Tarasenko 6a13c509a2 Remove selfReference from Packages mutator
This variable didn't serve any really useful purpose, but has led to
game crashes. While adding proper cleanup could also solve these
crashes, there is no real point to keeping it at all.

NOTE: It's only purpose was to make sure only one instance of
corresponding mutator exists, but duplicates shouldn't happen in the
first place.
2022-08-08 04:54:52 +07:00

266 lines
8.7 KiB
Ucode

/**
* Main and only Acedia mutator used for loading Acedia packages
* and providing access to mutator events' calls.
* Name is chosen to make config files more readable.
* Copyright 2020-2022 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 Packages extends Mutator
config(Acedia);
// Acedia's reference to a `Global` object.
var private Global _;
var private ServerGlobal _server;
var private ClientGlobal _client;
// Load Acedia on the client as well?
var private config bool clientside;
// Array of predefined services that must be started along with Acedia mutator.
var private config array<string> package;
// Set to `true` to activate Acedia's game modes system
var private config bool useGameModes;
// Responsible for setting up Acedia's game modes in current voting system
var VotingHandlerAdapter votingAdapter;
var Mutator_OnMutate_Signal onMutateSignal;
var Mutator_OnModifyLogin_Signal onModifyLoginSignal;
var Mutator_OnCheckReplacement_Signal onCheckReplacementSignal;
var private LoggerAPI.Definition infoFeatureEnabled;
var private LoggerAPI.Definition errNoServerLevelCore, errorCannotRunTests;
struct FeatureConfigPair
{
var public class<Feature> featureClass;
var public Text configName;
};
// "Constructor"
simulated function PreBeginPlay()
{
if (level.netMode == NM_DedicatedServer) {
InitializeServer();
}
else {
InitializeClient();
}
}
private simulated function InitializeClient()
{
_ = class'Global'.static.GetInstance();
class'ClientLevelCore'.static.CreateLevelCore(self);
}
private function InitializeServer()
{
local int i;
local LevelCore serverCore;
local GameMode currentGameMode;
local array<FeatureConfigPair> availableFeatures;
if (clientside) {
AddToPackageMap("Acedia");
}
CheckForGarbage();
// Launch and setup core Acedia
_ = class'Global'.static.GetInstance();
_server = class'ServerGlobal'.static.GetInstance();
_client = class'ClientGlobal'.static.GetInstance();
serverCore = class'ServerLevelCore'.static.CreateLevelCore(self);
for (i = 0; i < package.length; i += 1) {
_.environment.RegisterPackage_S(package[i]);
}
if (serverCore != none) {
_server.ConnectServerLevelCore();
}
else
{
_.logger.Auto(errNoServerLevelCore);
return;
}
if (class'TestingService'.default.runTestsOnStartUp) {
RunStartUpTests();
}
SetupMutatorSignals();
// Determine required features and launch them
availableFeatures = GetAutoConfigurationInfo();
if (useGameModes)
{
votingAdapter = VotingHandlerAdapter(
_.memory.Allocate(class'VotingHandlerAdapter'));
votingAdapter.InjectIntoVotingHandler();
currentGameMode = votingAdapter.SetupGameModeAfterTravel();
if (currentGameMode != none) {
currentGameMode.UpdateFeatureArray(availableFeatures);
}
}
EnableFeatures(availableFeatures);
}
// "Finalizer"
function ServerTraveling(string URL, bool bItems)
{
if (votingAdapter != none)
{
votingAdapter.PrepareForServerTravel();
votingAdapter.RestoreVotingHandlerConfigBackup();
_.memory.Free(votingAdapter);
votingAdapter = none;
}
_.environment.ShutDown();
if (nextMutator != none) {
nextMutator.ServerTraveling(URL, bItems);
}
Destroy();
}
// Checks whether Acedia has left garbage after the previous map.
// This can lead to serious problems, so such diagnostic check is warranted.
private function CheckForGarbage()
{
local int leftoverObjectAmount, leftoverActorAmount, leftoverDBRAmount;
local AcediaObject nextObject;
local AcediaActor nextActor;
local DBRecord nextRecord;
foreach AllObjects(class'AcediaObject', nextObject) {
leftoverObjectAmount += 1;
}
foreach AllActors(class'AcediaActor', nextActor) {
leftoverActorAmount += 1;
}
foreach AllObjects(class'DBRecord', nextRecord) {
leftoverDBRAmount += 1;
}
if ( leftoverObjectAmount == 0 && leftoverActorAmount == 0
&& leftoverDBRAmount == 0)
{
Log("Acedia garbage check: nothing was found.");
}
else
{
Log("Acedia garbage check: garbage was found." @
"This can cause problems, report it.");
Log("Leftover object:" @ leftoverObjectAmount);
Log("Leftover actors:" @ leftoverActorAmount);
Log("Leftover database records:" @ leftoverDBRAmount);
}
}
public final function array<FeatureConfigPair> GetAutoConfigurationInfo()
{
local int i;
local array< class<Feature> > availableFeatures;
local FeatureConfigPair nextPair;
local array<FeatureConfigPair> result;
availableFeatures = _.environment.GetAvailableFeatures();
for (i = 0; i < availableFeatures.length; i += 1)
{
nextPair.featureClass = availableFeatures[i];
nextPair.configName = availableFeatures[i].static
.GetAutoEnabledConfig();
result[result.length] = nextPair;
}
return result;
}
private function EnableFeatures(array<FeatureConfigPair> features)
{
local int i;
for (i = 0; i < features.length; i += 1)
{
if (features[i].featureClass == none) continue;
if (features[i].configName == none) continue;
features[i].featureClass.static.EnableMe(features[i].configName);
_.logger.Auto(infoFeatureEnabled)
.Arg(_.text.FromString(string(features[i].featureClass)))
.Arg(features[i].configName); // consumes `configName`
}
}
// Fetches and sets up signals that `Mutator` needs to provide
private function SetupMutatorSignals()
{
local ServerUnrealService service;
service = ServerUnrealService(class'ServerUnrealService'.static.Require());
onMutateSignal = Mutator_OnMutate_Signal(
service.GetSignal(class'Mutator_OnMutate_Signal'));
onModifyLoginSignal = Mutator_OnModifyLogin_Signal(
service.GetSignal(class'Mutator_OnModifyLogin_Signal'));
onCheckReplacementSignal = Mutator_OnCheckReplacement_Signal(
service.GetSignal(class'Mutator_OnCheckReplacement_Signal'));
}
private final function RunStartUpTests()
{
local TestingService testService;
testService = TestingService(class'TestingService'.static.Require());
testService.PrepareTests();
if (testService.filterTestsByName) {
testService.FilterByName(testService.requiredName);
}
if (testService.filterTestsByGroup) {
testService.FilterByGroup(testService.requiredGroup);
}
if (!testService.Run()) {
_.logger.Auto(errorCannotRunTests);
}
}
/**
* Below `Mutator` events are redirected into appropriate signals.
*/
function bool CheckReplacement(Actor other, out byte isSuperRelevant)
{
if (onCheckReplacementSignal != none) {
return onCheckReplacementSignal.Emit(other, isSuperRelevant);
}
return true;
}
function Mutate(string command, PlayerController sendingController)
{
if (onMutateSignal != none) {
onMutateSignal.Emit(command, sendingController);
}
super.Mutate(command, sendingController);
}
function ModifyLogin(out string portal, out string options)
{
if (onModifyLoginSignal != none) {
onModifyLoginSignal.Emit(portal, options);
}
super.ModifyLogin(portal, options);
}
defaultproperties
{
clientside = false
useGameModes = false
// This is a server-only mutator
remoteRole = ROLE_SimulatedProxy
bAlwaysRelevant = true
// Mutator description
GroupName = "Package loader"
FriendlyName = "Acedia loader"
Description = "Launcher for Acedia packages"
infoFeatureEnabled = (l=LOG_Info,m="Feature `%1` enabled with config \"%2\".")
errNoServerLevelCore = (l=LOG_Error,m="Cannot create `ServerLevelCore`!")
errorCannotRunTests = (l=LOG_Error,m="Could not perform Acedia's tests.")
}