Anton Tarasenko
2 years ago
13 changed files with 295 additions and 355 deletions
@ -0,0 +1,209 @@ |
|||||||
|
/** |
||||||
|
* Container for the information about available resources from other packages. |
||||||
|
* Copyright 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 AcediaEnvironment extends AcediaObject; |
||||||
|
|
||||||
|
/** |
||||||
|
* # `AcediaEnvironment` |
||||||
|
* |
||||||
|
* Instance of this class will be used by Acedia to manage resources available |
||||||
|
* from different packages like `Feature`s, aliases, etc.. |
||||||
|
* This is mostly necessary to implement Acedia loader (and, possibly, |
||||||
|
* its alternatives) that would load available packages and enable `Feature`s |
||||||
|
* admin wants to be enabled. |
||||||
|
* |
||||||
|
* ## Packages |
||||||
|
* |
||||||
|
* Any package to be used in Acedia should first be *registered* with |
||||||
|
* `RegisterPackage()` method. Then a manifest class from it will be read and |
||||||
|
* Acedia will become aware of all the resources that package contains. |
||||||
|
* Once any of those resources is used, package gets marked as *loaded* and its |
||||||
|
* *entry object* (if specified) will be created. |
||||||
|
*/ |
||||||
|
|
||||||
|
var private array< class<_manifest> > availablePackages; |
||||||
|
var private array< class<_manifest> > loadedPackages; |
||||||
|
|
||||||
|
var private array< class<Feature> > availableFeatures; |
||||||
|
var private array<Feature> enabledFeatures; |
||||||
|
|
||||||
|
var private string manifestSuffix; |
||||||
|
|
||||||
|
var private LoggerAPI.Definition infoRegisteringPackage, infoAlreadyRegistered; |
||||||
|
var private LoggerAPI.Definition errNotRegistered; |
||||||
|
|
||||||
|
protected function Constructor() |
||||||
|
{ |
||||||
|
// Always register our core package |
||||||
|
RegisterPackage_S("AcediaCore.Manifest"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Registers an Acedia package with name given by `packageName`. |
||||||
|
* |
||||||
|
* @param packageName Name of the package to register. Must not be `none`. |
||||||
|
* This package must exist and not have yet been registered in this |
||||||
|
* environment. |
||||||
|
* @return `true` if package was successfully registered, `false` if it |
||||||
|
* either does not exist, was already registered or `packageName` is |
||||||
|
* `none`. |
||||||
|
*/ |
||||||
|
public final function bool RegisterPackage(BaseText packageName) |
||||||
|
{ |
||||||
|
local class<_manifest> manifestClass; |
||||||
|
|
||||||
|
if (packageName == none) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
_.logger.Auto(infoRegisteringPackage).Arg(packageName.Copy()); |
||||||
|
manifestClass = class<_manifest>(DynamicLoadObject( |
||||||
|
packageName $ manifestSuffix, class'Class', true)); |
||||||
|
if (manifestClass == none) |
||||||
|
{ |
||||||
|
_.logger.Auto(errNotRegistered).Arg(packageName.Copy()); |
||||||
|
return false; |
||||||
|
} |
||||||
|
if (IsManifestRegistered(manifestClass)) |
||||||
|
{ |
||||||
|
_.logger.Auto(infoAlreadyRegistered).Arg(packageName.Copy()); |
||||||
|
return false; |
||||||
|
} |
||||||
|
availablePackages[availablePackages.length] = manifestClass; |
||||||
|
ReadManifest(manifestClass); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Registers an Acedia package with name given by `packageName`. |
||||||
|
* |
||||||
|
* @param packageName Name of the package to register. |
||||||
|
* This package must exist and not have yet been registered in this |
||||||
|
* environment. |
||||||
|
* @return `true` if package was successfully registered, `false` if it |
||||||
|
* either does not exist or was already registered. |
||||||
|
*/ |
||||||
|
public final function RegisterPackage_S(string packageName) |
||||||
|
{ |
||||||
|
local Text wrapper; |
||||||
|
|
||||||
|
wrapper = _.text.FromString(packageName); |
||||||
|
RegisterPackage(wrapper); |
||||||
|
_.memory.Free(wrapper); |
||||||
|
} |
||||||
|
|
||||||
|
private final function bool IsManifestRegistered(class<_manifest> manifestClass) |
||||||
|
{ |
||||||
|
local int i; |
||||||
|
|
||||||
|
for (i = 0; i < availablePackages.length; i += 1) |
||||||
|
{ |
||||||
|
if (manifestClass == availablePackages[i]) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
private final function ReadManifest(class<_manifest> manifestClass) |
||||||
|
{ |
||||||
|
local int i; |
||||||
|
|
||||||
|
|
||||||
|
for (i = 0; i < manifestClass.default.aliasSources.length; i += 1) |
||||||
|
{ |
||||||
|
if (manifestClass.default.aliasSources[i] == none) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
_.memory.Allocate(manifestClass.default.aliasSources[i]); |
||||||
|
} |
||||||
|
for (i = 0; i < manifestClass.default.features.length; i += 1) |
||||||
|
{ |
||||||
|
if (manifestClass.default.features[i] == none) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
manifestClass.default.features[i].static.LoadConfigs(); |
||||||
|
availableFeatures[availableFeatures.length] = |
||||||
|
manifestClass.default.features[i]; |
||||||
|
} |
||||||
|
for (i = 0; i < manifestClass.default.testCases.length; i += 1) |
||||||
|
{ |
||||||
|
class'TestingService'.static |
||||||
|
.RegisterTestCase(manifestClass.default.testCases[i]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns all packages registered in the caller `AcediaEnvironment`. |
||||||
|
* |
||||||
|
* NOTE: package being registered doesn't mean it's actually loaded. |
||||||
|
* Package must either be explicitly loaded or automatically when one of its |
||||||
|
* resources is being used. |
||||||
|
* |
||||||
|
* @return All packages registered in caller `AcediaEnvironment`. |
||||||
|
*/ |
||||||
|
public final function array< class<_manifest> > GetAvailablePackages() |
||||||
|
{ |
||||||
|
return availablePackages; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns all packages loaded in the caller `AcediaEnvironment`. |
||||||
|
* |
||||||
|
* NOTE: package being registered doesn't mean it's actually loaded. |
||||||
|
* Package must either be explicitly loaded or automatically when one of its |
||||||
|
* resources is being used. |
||||||
|
* |
||||||
|
* @return All packages loaded in caller `AcediaEnvironment`. |
||||||
|
*/ |
||||||
|
public final function array< class<_manifest> > GetLoadedPackages() |
||||||
|
{ |
||||||
|
return loadedPackages; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns all `Feature`s available in the caller `AcediaEnvironment`. |
||||||
|
* |
||||||
|
* @return All `Feature`s available in the caller `AcediaEnvironment`. |
||||||
|
*/ |
||||||
|
public final function array< class<Feature> > GetAvailableFeatures() |
||||||
|
{ |
||||||
|
return availableFeatures; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns all `Feature` instances enabled in the caller `AcediaEnvironment`. |
||||||
|
* |
||||||
|
* @return All `Feature`s enabled in the caller `AcediaEnvironment`. |
||||||
|
*/ |
||||||
|
public final function array<Feature> GetEnabledFeatures() |
||||||
|
{ |
||||||
|
local int i; |
||||||
|
for (i = 0; i < enabledFeatures.length; i += 1) { |
||||||
|
enabledFeatures[i].NewRef(); |
||||||
|
} |
||||||
|
return enabledFeatures; |
||||||
|
} |
||||||
|
|
||||||
|
defaultproperties |
||||||
|
{ |
||||||
|
manifestSuffix = ".Manifest" |
||||||
|
infoRegisteringPackage = (l=LOG_Info,m="Registering package \"%1\".") |
||||||
|
infoAlreadyRegistered = (l=LOG_Info,m="Package \"%1\" is already registered.") |
||||||
|
errNotRegistered = (l=LOG_Error,m="Package \"%2\" has failed to be registered.") |
||||||
|
} |
@ -1,307 +0,0 @@ |
|||||||
/** |
|
||||||
* Core service that is always running alongside Acedia framework, must be |
|
||||||
* created by a launcher. |
|
||||||
* Used for booting up and shutting down Acedia. |
|
||||||
* Also used for spawning `Actor`s as the only must-have `Service`. |
|
||||||
* Copyright 2020 - 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 CoreService extends Service |
|
||||||
dependson(BroadcastEventsObserver); |
|
||||||
|
|
||||||
// Package's manifest is supposed to always have a name of |
|
||||||
// "<package_name>.Manifest", this variable stores the ".Manifest" part |
|
||||||
var private const string manifestSuffix; |
|
||||||
// Classes that will need to do some cleaning before Acedia shuts down |
|
||||||
var private array< class<AcediaObject> > usedObjectClasses; |
|
||||||
var private array< class<AcediaActor> > usedActorClasses; |
|
||||||
// `Singleton`s are handled as a special case and cleaned up after |
|
||||||
// the rest of the classes. |
|
||||||
var private array< class<Singleton> > usedSingletonClasses; |
|
||||||
|
|
||||||
var private array< class<_manifest> > availableManifests; |
|
||||||
|
|
||||||
var private array<string> packagesToLoad; |
|
||||||
|
|
||||||
struct FeatureConfigPair |
|
||||||
{ |
|
||||||
var public class<Feature> featureClass; |
|
||||||
var public Text configName; |
|
||||||
}; |
|
||||||
var private array<FeatureConfigPair> automaticConfigs; |
|
||||||
var private array< class<Feature> > availableFeatures; |
|
||||||
|
|
||||||
var private LoggerAPI.Definition infoLoadingPackage; |
|
||||||
var private LoggerAPI.Definition infoBootingUp, infoBootingUpFinished; |
|
||||||
var private LoggerAPI.Definition infoShuttingDown; |
|
||||||
var private LoggerAPI.Definition errorNoManifest, errorCannotRunTests; |
|
||||||
|
|
||||||
// We do not implement `OnShutdown()`, because total Acedia's clean up |
|
||||||
// is supposed to happen before that event. |
|
||||||
protected function OnLaunch() |
|
||||||
{ |
|
||||||
BootUp(); |
|
||||||
default.packagesToLoad.length = 0; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Static method that starts everything needed by Acedia framework to function. |
|
||||||
* Must be called before attempting to use any of the Acedia's functionality. |
|
||||||
* |
|
||||||
* Acedia needs to be able to spawn actors and for that it first needs to |
|
||||||
* spawn `CoreService`. To make that possible you need to provide |
|
||||||
* an `Actor` instance from current level. It can be any valid actor. |
|
||||||
* |
|
||||||
* @param source Valid actor instance that Acedia will use to |
|
||||||
* spawn `CoreService` |
|
||||||
* @param packages List of acedia packages to load. |
|
||||||
* Using array of `string`s since Acedia's `Text` wouldn't yet |
|
||||||
* be available. |
|
||||||
*/ |
|
||||||
public final static function LaunchAcedia( |
|
||||||
Actor source, |
|
||||||
optional array<string> packages) |
|
||||||
{ |
|
||||||
default.packagesToLoad = packages; |
|
||||||
default.blockSpawning = false; |
|
||||||
// Actual work will be done inside `BootUp()` private method that will be |
|
||||||
// called from `OnCreated()` event. |
|
||||||
source.Spawn(class'CoreService'); |
|
||||||
default.blockSpawning = true; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Shuts down Acedia, cleaning up created actors, default values, |
|
||||||
* changes made to the standard game classes, etc.. |
|
||||||
* |
|
||||||
* This method must be called before the level change (map change), otherwise |
|
||||||
* Acedia is not guaranteed to work on the next map and you might |
|
||||||
* even experience game crashes. |
|
||||||
*/ |
|
||||||
public final function ShutdownAcedia() |
|
||||||
{ |
|
||||||
local int i; |
|
||||||
local AcediaActor nextActor; |
|
||||||
local MemoryService memoryService; |
|
||||||
_.logger.Auto(infoShuttingDown); |
|
||||||
memoryService = MemoryService(class'MemoryService'.static.GetInstance()); |
|
||||||
// Turn off gameplay-related stuff first |
|
||||||
class'Global'.static.GetInstance().DropGameplayAPI(); |
|
||||||
// Get rid of actors |
|
||||||
foreach AllActors(class'AcediaActor', nextActor) |
|
||||||
{ |
|
||||||
if (nextActor == self) continue; |
|
||||||
if (nextActor == memoryService) continue; |
|
||||||
nextActor.Destroy(); |
|
||||||
} |
|
||||||
// Clean all used classes, except for singletons |
|
||||||
for (i = 0; i < usedObjectClasses.length; i += 1) { |
|
||||||
usedObjectClasses[i].static._cleanup(); |
|
||||||
} |
|
||||||
for (i = 0; i < usedActorClasses.length; i += 1) { |
|
||||||
usedActorClasses[i].static._cleanup(); |
|
||||||
} |
|
||||||
// Remove remaining objects |
|
||||||
_.unreal.broadcasts.Remove(class'BroadcastEventsObserver'); |
|
||||||
memoryService.ClearAll(); |
|
||||||
// Finally clean up singletons |
|
||||||
for (i = 0; i < usedSingletonClasses.length; i += 1) { |
|
||||||
usedSingletonClasses[i].static._cleanup(); |
|
||||||
} |
|
||||||
// Clean API |
|
||||||
class'Global'.static.GetInstance().DropCoreAPI(); |
|
||||||
_ = none; |
|
||||||
// Get rid of the `MemoryService` and `CoreService` last |
|
||||||
memoryService.Destroy(); |
|
||||||
Destroy(); |
|
||||||
Log("Acedia has shut down."); |
|
||||||
} |
|
||||||
|
|
||||||
// Loads packages, injects broadcast handler and optionally runs tests |
|
||||||
private final function BootUp() |
|
||||||
{ |
|
||||||
local int i; |
|
||||||
local Text nextPackageName; |
|
||||||
local class<_manifest> nextManifest; |
|
||||||
_.logger.Auto(infoBootingUp); |
|
||||||
LoadManifest(class'AcediaCore.Manifest'); |
|
||||||
// Load packages |
|
||||||
for (i = 0; i < packagesToLoad.length; i += 1) |
|
||||||
{ |
|
||||||
nextPackageName = _.text.FromString(packagesToLoad[i]); |
|
||||||
_.logger.Auto(infoLoadingPackage).Arg(nextPackageName.Copy()); |
|
||||||
nextManifest = LoadManifestClass(packagesToLoad[i]); |
|
||||||
if (nextManifest == none) |
|
||||||
{ |
|
||||||
_.logger.Auto(errorNoManifest).Arg(nextPackageName.Copy()); |
|
||||||
continue; |
|
||||||
} |
|
||||||
availableManifests[availableManifests.length] = nextManifest; |
|
||||||
LoadManifest(nextManifest); |
|
||||||
_.memory.Free(nextPackageName); |
|
||||||
} |
|
||||||
nextPackageName = none; |
|
||||||
_.logger.Auto(infoBootingUpFinished); |
|
||||||
// Other initialization |
|
||||||
class'UnrealService'.static.Require(); |
|
||||||
if (class'TestingService'.default.runTestsOnStartUp) { |
|
||||||
RunStartUpTests(); |
|
||||||
} |
|
||||||
class'InfoQueryHandler'.static.StaticConstructor(); |
|
||||||
_.unreal.mutator.OnMutate(_self).connect = EnableCommandsFeature; |
|
||||||
} |
|
||||||
|
|
||||||
private final function LoadManifest(class<_manifest> manifestClass) |
|
||||||
{ |
|
||||||
local int i; |
|
||||||
local FeatureConfigPair nextPair; |
|
||||||
for (i = 0; i < manifestClass.default.aliasSources.length; i += 1) |
|
||||||
{ |
|
||||||
if (manifestClass.default.aliasSources[i] == none) continue; |
|
||||||
_.memory.Allocate(manifestClass.default.aliasSources[i]); |
|
||||||
} |
|
||||||
LaunchManifestServices(manifestClass); |
|
||||||
for (i = 0; i < manifestClass.default.features.length; i += 1) |
|
||||||
{ |
|
||||||
if (manifestClass.default.features[i] == none) continue; |
|
||||||
manifestClass.default.features[i].static.LoadConfigs(); |
|
||||||
nextPair.featureClass = manifestClass.default.features[i]; |
|
||||||
nextPair.configName = manifestClass.default.features[i].static |
|
||||||
.GetAutoEnabledConfig(); |
|
||||||
automaticConfigs[automaticConfigs.length] = nextPair; |
|
||||||
availableFeatures[availableFeatures.length] = |
|
||||||
manifestClass.default.features[i]; |
|
||||||
} |
|
||||||
for (i = 0; i < manifestClass.default.testCases.length; i += 1) |
|
||||||
{ |
|
||||||
class'TestingService'.static |
|
||||||
.RegisterTestCase(manifestClass.default.testCases[i]); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public final function array<FeatureConfigPair> GetAutoConfigurationInfo() |
|
||||||
{ |
|
||||||
local int i; |
|
||||||
local array<FeatureConfigPair> result; |
|
||||||
for (i = 0; i < automaticConfigs.length; i += 1) |
|
||||||
{ |
|
||||||
result[i] = automaticConfigs[i]; |
|
||||||
if (result[i].configName != none) { |
|
||||||
result[i].configName = result[i].configName.Copy(); |
|
||||||
} |
|
||||||
} |
|
||||||
return result; |
|
||||||
} |
|
||||||
|
|
||||||
public final function array< class<Feature> > GetAvailableFeatures() |
|
||||||
{ |
|
||||||
return availableFeatures; |
|
||||||
} |
|
||||||
|
|
||||||
private final function class<_manifest> LoadManifestClass(string packageName) |
|
||||||
{ |
|
||||||
return class<_manifest>(DynamicLoadObject( packageName $ manifestSuffix, |
|
||||||
class'Class', true)); |
|
||||||
} |
|
||||||
|
|
||||||
private final function LaunchManifestServices(class<_manifest> manifestClass) |
|
||||||
{ |
|
||||||
local int i; |
|
||||||
for (i = 0; i < manifestClass.default.services.length; i += 1) |
|
||||||
{ |
|
||||||
if (manifestClass.default.services[i] != none) { |
|
||||||
manifestClass.default.services[i].static.Require(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
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); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private final function EnableCommandsFeature( |
|
||||||
string command, |
|
||||||
PlayerController sendingPlayer) |
|
||||||
{ |
|
||||||
if (command ~= "acediacommands") { |
|
||||||
class'Commands_Feature'.static.EmergencyEnable(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Registers class derived from `AcediaObject` for clean up when |
|
||||||
* Acedia shuts down. |
|
||||||
* |
|
||||||
* Does not check for duplicates. |
|
||||||
* |
|
||||||
* This is an internal function and should not be used outside of |
|
||||||
* AcediaCore package. |
|
||||||
*/ |
|
||||||
public final function _registerObjectClass(class<AcediaObject> classToClean) |
|
||||||
{ |
|
||||||
if (classToClean != none) { |
|
||||||
usedObjectClasses[usedObjectClasses.length] = classToClean; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Registers class derived from `AcediaActor` for clean up when |
|
||||||
* Acedia shuts down. |
|
||||||
* |
|
||||||
* Does not check for duplicates. |
|
||||||
* |
|
||||||
* This is an internal function and should not be used outside of |
|
||||||
* AcediaCore package. |
|
||||||
*/ |
|
||||||
public final function _registerActorClass(class<AcediaActor> classToClean) |
|
||||||
{ |
|
||||||
local class<Singleton> singletonClass; |
|
||||||
if (classToClean == none) { |
|
||||||
return; |
|
||||||
} |
|
||||||
singletonClass = class<Singleton>(classToClean); |
|
||||||
if (singletonClass != none) { |
|
||||||
usedSingletonClasses[usedSingletonClasses.length] = singletonClass; |
|
||||||
} |
|
||||||
else { |
|
||||||
usedActorClasses[usedActorClasses.length] = classToClean; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
defaultproperties |
|
||||||
{ |
|
||||||
manifestSuffix = ".Manifest" |
|
||||||
|
|
||||||
infoBootingUp = (l=LOG_Info,m="Initializing Acedia.") |
|
||||||
infoBootingUpFinished = (l=LOG_Info,m="Acedia initialized.") |
|
||||||
infoShuttingDown = (l=LOG_Info,m="Shutting down Acedia.") |
|
||||||
infoLoadingPackage = (l=LOG_Info,m="Loading package \"%1\".") |
|
||||||
errorNoManifest = (l=LOG_Error,m="Cannot load `Manifest` for package \"%1\". Check if it's missing or if its name is spelled incorrectly.") |
|
||||||
errorCannotRunTests = (l=LOG_Error,m="Could not perform Acedia's tests.") |
|
||||||
} |
|
@ -0,0 +1,31 @@ |
|||||||
|
/** |
||||||
|
* Copyright 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 ServerLevelCore extends LevelCore; |
||||||
|
|
||||||
|
public static function LevelCore CreateLevelCore(Actor source) |
||||||
|
{ |
||||||
|
if (source == none) return none; |
||||||
|
if (source.level.netMode != NM_DedicatedServer) return none; |
||||||
|
|
||||||
|
return super.CreateLevelCore(source); |
||||||
|
} |
||||||
|
|
||||||
|
defaultproperties |
||||||
|
{ |
||||||
|
} |
Loading…
Reference in new issue