Browse Source

Add `SideEffect`s class

pull/8/head
Anton Tarasenko 2 years ago
parent
commit
71248cb1c4
  1. 8
      sources/ClientRealm/ClientGlobal.uc
  2. 164
      sources/CoreRealm/API/SideEffects/SideEffect.uc
  3. 155
      sources/CoreRealm/API/SideEffects/SideEffectAPI.uc
  4. 36
      sources/CoreRealm/CoreGlobal.uc
  5. 3
      sources/ServerRealm/ServerGlobal.uc

8
sources/ClientRealm/ClientGlobal.uc

@ -19,8 +19,9 @@
* You should have received a copy of the GNU General Public License
* along with Acedia. If not, see <https://www.gnu.org/licenses/>.
*/
class ClientGlobal extends Object;
class ClientGlobal extends CoreGlobal;
var protected bool initialized;
// `Global` is expected to behave like a singleton and will store it's
// main instance in this variable's default value.
var protected ClientGlobal myself;
@ -38,6 +39,11 @@ public final static function ClientGlobal GetInstance()
protected function Initialize()
{
if (initialized) {
return;
}
super.Initialize();
initialized = true;
}
defaultproperties

164
sources/CoreRealm/API/SideEffects/SideEffect.uc

@ -0,0 +1,164 @@
/**
* Object representing a side effect introduced into the game/server.
* Side effects in Acedia refer to changes that aren't a part of mod's main
* functionality, but rather something necessary to make that functionality
* possible that might also affect how other mods work.
* This is a simple data container that is meant to describe relevant
* changes to the human user.
* 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 SideEffect extends AcediaObject
abstract;
/**
* # Side effects
*
* In Acedia "side effect" refers to changes that aren't a part of mod's
* main functionality, but rather something necessary to make that
* functionality possible that might also affect how other mods work. Their
* purpose is to help developers and server admins figure out what changes were
* performed by Acedia or mods based on it.
* What needs to be considered a side effect is loosely defined and they
* are simply a tool to inform others that something they might not have
* expected has happened, that can possibly break other (their) mods.
* AcediaCore, for example, tried to leave a minimal footpring, avoiding
* making any changes to the game classes unless requested, but it still has to
* do some changes (adding `GameRules`, replacing damage types for some zeds,
* etc.) and `SideEffect`s can be used to document these changes. They can be
* used in a similar way for AcediaFixes - a package that is only meant for
* fixing bugs, but inevitably has to make a lot of under the hood changes to
* achieve that.
* On the other hand gameplay mods like Futility can make a lot of changes,
* but they can all be just expected part of its direct functionality: we
* expect feature that shares dosh of leavers to alter players' dosh values, so
* this is not a side effect. Such mods are likely not going to have to specify
* any side effects whatsoever.
*
* ## Implemention your own `SideEffect`s
*
* Simply make a non-abstract child class based on `SideEffect`, create its
* instance filled with necessary data and register it in `SideEffectAPI` once
* side effect is introduced. If you revert introduced side effect, you should
* remove registered object through the same API.
* Each class of the `SideEffect` is supposed to represent a particular
* side effect introduced into the game engine. Whether side effect is active
* is decided by whether it is currently registered in `SideEffectAPI`.
*
* NOTE: `SideEffect` should not have any logic and should serve as
* an immutable data container.
*/
var protected Text sideEffectName;
var protected Text sideEffectDescription;
var protected Text sideEffectPackage;
var protected Text sideEffectSource;
var protected Text sideEffectStatus;
/**
* Returns name (short description) of the caller `SideEffect`. User need to
* be able to tell what this `SideEffect` is generally about from the glance at
* this name.
*
* Guideline is for this value to not exceed `80` cahracters, but this is not
* enforced.
*
* Must not be `none`.
*
* @return Name (short description) of the caller `SideEffect`.
* Guaranteed to not be `none`.
*/
public function Text GetName()
{
if (sideEffectName != none) {
return sideEffectName.Copy();
}
return none;
}
/**
* Returns description of the caller `SideEffect`. This should describe what
* was done and why relevant change was necessary.
*
* Must not be `none`.
*
* @return Description of the caller `SideEffect`.
* Guaranteed to not be `none`.
*/
public function Text GetDescription()
{
if (sideEffectDescription != none) {
return sideEffectDescription.Copy();
}
return none;
}
/**
* Returns name of the package ("*.u" file) that introduced this change.
*
* Note that if package "A" actually performed the change because another
* package "B" requested certain functionality, it is still package "A" that is
* responsible for the side effect.
*
* Must not be `none`.
*
* @return Name of the package ("*.u" file) that introduced this change.
* Guaranteed to not be `none`.
*/
public function Text GetPackage()
{
if (sideEffectPackage != none) {
return sideEffectPackage.Copy();
}
return none;
}
/**
* What part of package caused this change. For huge packages can be used to
* further specify what introduced the change.
*
* Returned value can be `none` (e.g. when it is unnecessary for small
* packages).
*
* @return Name (short description) of the part of the package that caused
* caller `SideEffect`.
*/
public function Text GetSource()
{
if (sideEffectSource != none) {
return sideEffectSource.Copy();
}
return none;
}
/**
* Status of the caller `SideEffect`. Some side effects can be introduced in
* several different ways - this value needs to help distinguish between them.
*
* @return Status of the caller `SideEffect`.
*/
public function Text GetStatus()
{
if (sideEffectStatus != none) {
return sideEffectStatus.Copy();
}
return none;
}
defaultproperties
{
}

155
sources/CoreRealm/API/SideEffects/SideEffectAPI.uc

@ -0,0 +1,155 @@
/**
* Simple API for managing a list of `SideEffect` info objects: can add,
* remove, return all and by package.
* 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 SideEffectAPI extends AcediaObject;
var private array<SideEffect> activeSideEffects;
/**
* Returns all so far registered `SideEffect`s.
*
* @return Array of all registered `SideEffect`s.
*/
public final function array<SideEffect> GetAll()
{
local int i;
for (i = 0; i < activeSideEffects.length; i += 1) {
activeSideEffects[i].NewRef();
}
return activeSideEffects;
}
/**
* Returns active `SideEffect` instance of the specified class
* `sideEffectClass`.
*
* @param sideEffectClass Class of side effect to return active instance of.
* @return Active `SideEffect` instance of the specified class
* `sideEffectClass`.
* `none` if either `sideEffectClass` is `none` or side effect of such
* class is not currently active.
*/
public final function SideEffect GetClass(class<SideEffect> sideEffectClass)
{
local int i;
if (sideEffectClass == none) {
return none;
}
for (i = 0; i < activeSideEffects.length; i += 1)
{
if (activeSideEffects[i].class == sideEffectClass)
{
activeSideEffects[i].NewRef();
return activeSideEffects[i];
}
}
return none;
}
/**
* Returns all so far registered `SideEffect`s from a package `packageName`
* (case insensitive).
*
* @param packageName Name opf the package, in `SideEffect`s from which we are
* interested. Must be not `none`.
* @return Array of all registered `SideEffect`s from a package `packageName`.
* If `none`, returns an empty array.
*/
public final function array<SideEffect> GetFromPackage(BaseText packageName)
{
local int i;
local Text nextPackage;
local array<SideEffect> result;
if (packageName == none) {
return result;
}
for (i = 0; i < activeSideEffects.length; i += 1)
{
nextPackage = activeSideEffects[i].GetPackage();
if (nextPackage.Compare(packageName, SCASE_INSENSITIVE))
{
activeSideEffects[i].NewRef();
result[result.length] = activeSideEffects[i];
}
_.memory.Free(nextPackage);
}
return result;
}
/**
* Registers a new `SideEffect` object as active.
*
* @param newSideEffect Instance of some `SideEffect` class to register as
* active side effect. Must not be `none`.
* @return `true` if new side effect was added and `false` otherwise.
*/
public final function bool AddSideEffect(SideEffect newSideEffect)
{
local int i;
if (newSideEffect == none) {
return false;
}
for (i = 0; i < activeSideEffects.length; i += 1)
{
if (activeSideEffects[i].class == newSideEffect.class) {
return false;
}
}
newSideEffect.NewRef();
activeSideEffects[activeSideEffects.length] = newSideEffect;
return true;
}
/**
* Removes `SideEffect` of the specified sub-class from the list of active
* side effects.
*
* @param sideEffectClass Class of the side effect to remove.
* @return `true` if some side effect was removed as a result of this operation
* and `false` otherise (even if there was no side effect of specified
* class to begin with).
*/
public final function bool RemoveSideEffectClass(
class<SideEffect> sideEffectClass)
{
local int i;
if (sideEffectClass == none) {
return false;
}
for (i = 0; i < activeSideEffects.length; i += 1)
{
if (activeSideEffects[i].class == sideEffectClass)
{
_.memory.Free(activeSideEffects[i]);
activeSideEffects.Remove(i, 1);
return true;
}
}
return false;
}
defaultproperties
{
}

36
sources/CoreRealm/CoreGlobal.uc

@ -0,0 +1,36 @@
/**
* Base class for objects that will provide an access to a Acedia's client- and
* server-specific functionality by giving a reference to this object to all
* Acedia's objects and actors, emulating a global API namespace.
* 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 CoreGlobal extends Object;
var public SideEffectAPI sideEffects;
protected function Initialize()
{
local MemoryAPI api;
api = class'Global'.static.GetInstance().memory;
sideEffects = SideEffectAPI(api.Allocate(class'SideEffectAPI'));
}
defaultproperties
{
}

3
sources/ServerRealm/ServerGlobal.uc

@ -19,7 +19,7 @@
* You should have received a copy of the GNU General Public License
* along with Acedia. If not, see <https://www.gnu.org/licenses/>.
*/
class ServerGlobal extends Object;
class ServerGlobal extends CoreGlobal;
var protected bool initialized;
// `Global` is expected to behave like a singleton and will store it's
@ -46,6 +46,7 @@ protected function Initialize()
if (initialized) {
return;
}
super.Initialize();
_ = class'Global'.static.GetInstance();
kf = KFFrontend(_.memory.Allocate(class'KF1_Frontend'));
// TODO: this is hack, needs to be redone later

Loading…
Cancel
Save