Introduction

This "book" describes AcediaCore from the mod maker's perspective and is meant to give broad picture about AcediaCore's design and innerworkings, while also providing reasoning and motivations for why things are the way they are.

This document is not:

  • A tutorial that provides quick and simple introduction into how to start using AcediaCore to create new mods;
  • A collection of recipes for how to do certain specific things;
  • A reference documentation that lists and describes every single class and method. The closest substitute for that would be AcediaCore's source code - most of the methods and classes are given brief descriptions in the comments. They might somewhat lack in quality, since having a peer review for them would not have been viable so far, but that is all we can offer. Any corrections to them are always welcome.

We assume that our audience is at least familiar with UnrealScript and right now we cannot recommend using AcediaCore to people new to the modding anyway: AcediaCore's API is not stable enough and has certain quirks that are unusual for a scripting language and can lead to some nasty, hard-to-catch bugs.

What the hell is Acedia Framework?

Acedia Framework is a set of packages that aims to augment what Killing Floor is from both gameplay and modding perspective. The ideal vision we're striving for is to create a framework that will be able to provide an ultimate Killing Floor experience, while doing only what server's admin wants: anything from a purely vanilla gameplay with some optional bug fixes to configuring the gameplay to the point of total conversion.

Acedia 0.1 was a small mutator that fixed game-breaking bugs and what Acedia is now might seem like a huge departure from that, but Acedia 0.1 was simply the first step in what we want to achieve. Still, we will take great care to ensure that people who only want critical vanilla bug fixes on top of otherwise untouched vanilla can still get exactly that with Acedia.

What Acedia was before is now broken into three different packages:

  • AcediaCore - package can provides base Acedia classes and functionality, usable as a standalone library for other mods;
  • AcediaLauncher - launcher that is supposed to load both native Mutators and Acedia's Features. This is a soft dependency for using AcediaCore - highly recommended, but not absolutely necessary. It can also potentially be replaced by a custom launcher of your own making.
  • AcediaFixes - all the bug fixing Features were moved here.
  • Futility - package that provides rich set of server commands and Features to help with server administration. Actually direct gameplay changes will go into a separate package.

The topic of this document is only AcediaCore - a base class library, but other packages might be referenced as examples.

Object problem

When working with UnrealScript one can distinguish between following types of variables:

  1. Value types: bool, byte, int, float, string and any struct;
  2. Actors: objects that have Actor as their parent;
  3. Non-actor Objects: object of any class not derived derived from the Actor.

Most of the mods mainly use first and second type, but we make heavy use of the third one. This allows Acedia to provide convenient interfaces for its functionality and simplify implementation of its features. However it also creates several new problems, normally not encountered by other mods.

What are the problems?

Storing Actor references inside Objects is dangerous

Storing actors in non-actor objects is a bad idea and can lead to game/server crashes. If you are interested in the explanation of why, you can read discussion here. This isn't really a problem in most mutators, since they store references to actors (KFMonster, KFPlayerController, ...) inside other actors (Mutator, GameType, ...). However, in Acedia almost everything is a non-actor object, so simply having actor variables can be volatile: even a simple check myActor != none can lead to a crash under some circumstances if myActor was destroyed recently enough.

Acedia's end goal is to provide you with enough object-based API and wrappers, that you don't have to reference actors directly. We are a long way away from that, so for whenever our API is not enough, we also provide a safer way to work with actors inside objects (see boxing for more info).

Objects are effectively indestructible

We'll illustrate this point with Text - Acedia's own type that is used as a replacement for string. Consider following simple code:

function MyFunction()
{
    local string message;
    message = "My log message";
    Log(message);
}

For Acedia's Text an equivalent code would be:

function MyFunction()
{
    local Text message;
    message = _.text.FromString("My log message");
    _.logger.Info(message); //  Just Acedia's logging, kind of like `Log()`
}

There is an additional action of calling FromString() to create a new Text object, but otherwise logic is the same. But there is one crucial difference: unlike string value, Text is an object that will continue to exists in memory even after we exit MyFunction()'s body: every single call to MyFunction() will keep creating new objects that won't ever be used anywhere else.

Supposed way to deal with this is garbage collection, but it is a very expensive operation in Unreal Engines before their 3rd version. For example, the lag at the start of each wave in Killing Floor is caused by a garbage collection call. Many players hate it and several mods were made to disable it, since there is usually not much to actually clean up.

NOTE: One can wonder, is there really that much objects to clean up with Acedia? Answer is that there is way more than without Acedia and, while you might be fine even without any cleanup, ignoring it completely isn't scalable and can blow up in our face in the future.

This means that Acedia needed to find another way of dealing with issue of creating useless objects. That solution is releasing objects:

function MyFunction()
{
    local Text message;
    message = _.text.FromString("My log message");
    _.logger.Info(message);
    message.FreeSelf(); //  `_.memory.Free(message)` would also work
}

Here FreeSelf() call marks message as an unneeded object, making it available to be reused. In fact, if you call new MyFunction() several times in a row:

MyFunction()
MyFunction()
//  Paste a couple thousand more calls here
MyFunction()

and all of the calls will use only one Text object - the exactly same as the one first call has created. This concerns not only Text, but almost every single Acedia's object. To efficiently use Acedia, you must learn to deallocate objects that are not going to be used anymore.

And then it got worse

The serious problem here is that after calling message.FreeSelf() one really should not use message reference anymore. If Text variable from above wasn't local, but class variable, then we'd have to add one more instruction message = none:

var Text message;

function MyFunction()
{
    message = _.text.FromString("My log message");
    _.logger.Info(message);
    message.FreeSelf();
    message = none; // Forget about `message`!
}

Deallocating a message does not make an actual object go away and, without setting message variable to none, you risk continuing to use it; however, some other piece of code might re-allocate that object and use it for something completely different. This means unpredictable and undefined behavior for everybody. To avoid creating this problem everyone must always make sure to forget about objects they released by setting their references to none.

Just the possibility of that happening is a huge problem, since messing this up will create bugs that are extremely hard to catch. Possibility of such bugs is the biggest downside of using Acedia.

IMPORTANT: If you did encounter a situation where certain object exhibits an unpredictable behavior and you suspect that it is due to someone else messing up and using released objects - you can attempt to identify the culprit via GetReferencers() method defined inside Object class.

Why risk that new problem?

Why risk new problems if other mods already do completely fine job? To put it simply: because it allowed us to create a more powerful and, overall, easier to use library. To our knowledge, no other Killing Floor mod attempted to produce a library of the Acedia's scale. This isn't to say that there wasn't any huge mods, but their changes, for the most part, didn't deviate too much from what could've been directly achieved by already provided functionality of UnrealScript.

Acedia, on the other hand, introduces collections, databases, richer text support (including parsing and JSON functionality), Signal/Slot event system, custom loggers, aliases, etc.. A lot of those couldn't even be implemented without using Objects, while others would be awkward to use. Short term any of the existing Acedia functionality can be reimplemented in a simpler way, without abuse of Objects. However having AcediaCore the way it is now simplifies making future functionality and makes possible certain future plans we aren't yet ready to talk about.

Why Objects and not Actors?

Using Actor instead of Objects seems to resolve all of the above problems. So why not use them instead? This is a completely legitimate question and for all we know using Actors is a viable alternative. We've made decision to use Objects because:

  1. They are more lightweight than Actors;
  2. Actors are linked to a certain level, but Objects are not: you needs an instance of another Actor to start spawning ones of your own, while you can simply use a large chunk of Acedia's functionality anywhere;
  3. There are ways to completely solve all the above-mentioned problem in the future. Secret ways for now.

AcediaObject

AcediaObject is a base class for all objects in Acedia and it is meant to enable: easy access to Acedia's API through globals, object allocation and release, constructors and finalizers. We'll go over each of these in detail.

Globals and Acedia's API

Globals (clases Global, ServerGlobal and ClientGlobal) is our way of solving the problem of adding an easy access to our new global functions. Examples of global functions are Log(), Caps(), Abs(), VSize() and a multitude of others that you can call from anywhere in UnrealScript. They can be accessed from anywhere because they are all declared as static methods inside Object - a base class for any other class. Problem is, since we cannot add our own methods to the Object, then we also can't add new global functions. The best we can do is declare new static methods in our own classes, but calling them would be cumbersome: class'glb'.static.DoIt().

Idea that we've used to solve this problem for Acedia is to provide every single AcediaObject with an instance of a class that would contain all our global functions. We can then save an instance of this class in a local variable _, which would allow us to simply write _.DoIt().

In actuality we don't just dump all of Acedia's global functions into one variable, but instead group them into a kind of namespaces:

_.text.FromString("I am here!");        // Text API
_.alias.ResolveColor_S("blue");         // Alias API
_.collections.EmptyArrayList();         // Collections API
_.memory.Allocate(class'SimpleSignal'); // Memory API

_ can't be accessed in static methods, since only default values are available inside them. Since writing default._ would also be bulky, AcediaObject provides a static method public static final function Global __() that is always available:

__().text.FromString("I am here!");
__().alias.ResolveColor_S("blue");
__().collections.EmptyArrayList();
__().memory.Allocate(class'SimpleSignal');

Allocation and deallocation

The majority, if not all, of the Acedia's objects you will be using are going to be created by specialized methods like _.text.FromString(), _.collections.EmptyArrayList() or _.time.StartTimer() and can be deallocated with self.FreeSelf() method. However, if you want to allocate instances of your own classes, you'll need the help of MemoryAPI's methods: _.memory.Allocate() and _.memory.Free().

Ultimately, all Acedia's objects must be created with _.memory.Allocate() and destroyed with _.memory.Free(). For example, here is how new Parser is created with _.text.NewParser():

public final function Parser NewParser()
{
    return Parser(_.memory.Allocate(class'Parser'));
}

and self.FreeSelf() is actually defined in AcediaObject as follows (ignore parts about life versions for now, they will be explained in sections below):

public final function FreeSelf(optional int lifeVersion)
{
    if (lifeVersion <= 0 || lifeVersion == GetLifeVersion()) {
        _.memory.Free(self);
    }
}

What is it exactly that Allocate() and Free() methods do?

Reference counting

Lets start with Free(). In earlier versions of Acedia, _.memory.Free() / self.FreeSelf() methods immediately deallocated provided AcediaObject. However that appeared to be a bad design decision, making it harder to understand who was supposed to deallocate what objects and when.

Now calling _.memory.Free() or self.FreeSelf() does not necessarily deallocate AcediaObject, but simply tells it that you no longer store its reference, reducing its internal reference count. AcediaObject is only deallocated once its reference count reaches zero.

Most objects are only used by whatever class allocated them and have reference count of 1 throughout their lifetime. However they become necessary when AcediaObjects are stored somewhere else, most common example being a collection:

local ArrayList myArray;
local Text      myText;

myText = _.text.FromString("hello, world!");
//  ^ here `myText` has reference count of 1
myArray = _.collections.EmptyArrayList().AddItem(myText)'
//  ^ we've just put `myText` into collection,
//  which increased its reference count to 2
myText.FreeSelf();
myText = none;
//  ^ we no longer have a direct reference to that `Text`, but object lives on
//  inside `myArray` collection with reference count of 1
myArray.RemoveIndex(0);
//  ^ now we've also removed it from the collection, once again decreasing its
//  reference count and causing it to get deallocated

Reference count isn't magically tracked by itself. Just as we have to manually reduce it with _.memory.Free() / self.FreeSelf() methods, to increase reference count we have to call self.NewRef() method whenever we want to store AcediaObject instance in some place else. In particular, Acedia's collections are doing it automatically when you add objects inside them.

Who is responsible for releasing references?

For both historical reasons and what seemed like a good idea in practice, two main rules for managing AcediaObjects' references arose:

  • If function returns an object (as a return value or as an out argument) - then whoever called that function is responsible for releasing its reference. If you've called _.text.Empty(), then you must release the MutableText object it has returned. Conversely, if you are implementing function that returns an object, then you lose the reference you've had: you need to either forget a reference to that object after returning it or, if you want to retain your reference, create a new reference with self.NewRef() method first.
  • Functions do not release their arguments. If you pass an object as an argument to a function - you can expect that said object won't be release during function's execution. When implementing your own function - you should not release objects passed as its arguments.

However, these guidelines should be treated as default assumptions and not hard rules. First guideline can be sometimes broken for convenience. For example, EPlayer class has method BorrowConsole() that returns ConsoleWriter for a quick access to player's console. If we had to release returned object, then we'd have to do something like:

local ConsoleWriter writer;

writer = player.BorrowConsole();
writer.UseColorOnce(_.text.Green).WriteLine_S("All is fine!");
writer.FreeSelf();

However this particular method does not return you a new reference and expects you to not release returned ConsoleWriter object, making following code not leak any memory:

player.BorrowConsole().WriteLine_S("All is fine!");

Moreover, another common scenario in which returned object should not be released is when a method returns the caller object itself to allow for method chaining:

player.BorrowConsole().UseColorOnce(_.text.Green).WriteLine_S("All is fine!");

Another example:

local int a, b, c;
local Parser parser;
parser = _.text.Parse_S("78 23 -34");
//  Each call returns `parser`, but...
parser.MInteger(a).Skip().MInteger(b).Skip().MInteger(c);
//  ...`parser` only needs to be released at the very end
parser.FreeSelf();

Such methods always specify that they return objects for method chaining.

Second guideline also has certain exceptions. Obvious one is _.memory.Free() that releases reference one passes to it. Other notable ones are _.text.IntoString() that releases BaseText reference passed to it, returning string instead and Arg() method in Logger class that always releases passed BaseText reference for convenience's sake.

Such exceptions are relatively rare and always documented in the method's description. Methods that break first guideline also usually start with Borrow... prefix and, whenever possible, are made to be error-tolerant if you do release returned reference.

Object pools

To reuse deallocated objects we need to store them somewhere, until they are required again. This idea isn't new and UnrealScript already tried to tackle issue of reusing once created objects: class ObjectPool stores unused objects (mostly resources such as textures) inside dynamic array until they are needed. Unfortunately, using a single ObjectPool for a large volume of objects is impractical from performance perspective, since it stores objects of all classes together and each object allocation from the pool can potentially require going through the whole array:

//  FILE: Engine/ObjectPool.uc
simulated function Object AllocateObject(class ObjectClass)
{
    local Object    Result;
    local int        ObjectIndex;

    for(ObjectIndex = 0;ObjectIndex < Objects.Length;ObjectIndex++)
    {
        if(Objects[ObjectIndex].Class == ObjectClass)
        {
            Result = Objects[ObjectIndex];
            Objects.Remove(ObjectIndex,1);
            break;
        }
    }

    if(Result == None)
        Result = new(Outer) ObjectClass;

    return Result;
}

For that reason Acedia uses a separate object pool (implemented by AcediaObjectPool) for every single class, making object reallocation as trivial as grabbing the last stored object from AcediaObjectPool's internal dynamic array:

//  From `AcediaObjectPool` sources
public final function AcediaObject Fetch()
{
    local AcediaObject result;
    if (storedClass == none)    return none;
    if (objectPool.length <= 0) return none;

    result = objectPool[objectPool.length - 1];
    objectPool.length = objectPool.length - 1;
    return result;
}

New pool is automatically prepared for every class you create, as long as it is inherited from AcediaObject. AcediaActors do not use object pools and are to be simply Destroy()ed.

Constructors and finalizers

Both AcediaObject and AcediaActor support constructors and finalizers. Constructor is a method that's called on object after it was created, preparing it for use. Finalizer is a method that's called when object is deallocated and can be used to clean up any used resources.

NOTE: Technically, right now destructor might be a better terminology for Acedia's finalizers.

A good and simple example is from the ATradingComponent that allocates necessary objects inside its constructor and deallocates them in its finalizer:

protected function Constructor()
{
    onStartSignal   = SimpleSignal(_.memory.Allocate(class'SimpleSignal'));
    onEndSignal     = SimpleSignal(_.memory.Allocate(class'SimpleSignal'));
    onTraderSelectSignal = Trading_OnSelect_Signal(
        _.memory.Allocate(class'Trading_OnSelect_Signal'));
}

protected function Finalizer()
{
    _.memory.Free(onStartSignal);
    _.memory.Free(onEndSignal);
    _.memory.Free(onTraderSelectSignal);
    onStartSignal           = none;
    onEndSignal             = none;
    onTraderSelectSignal    = none;
}

Acedia's constructors do not take parameters and because of that some classes also define Initialize() method that is required to be used right after an object was allocated.

Boxing

Boxing is a process of turning value types such as bool, byte, int or float into objects. The concept is very simple: to store a value as a reference type, we create a box - an object that stores a single primitive value. It could be implemented like that:

class MyBox extends Object;
var float value;

Since Acedia's boxes are immutable (their value cannot change once the box was created), they store their value in the private field and provide access to it through the appropriate getter method.

Boxes were introduced because they allowed creation of general collections: Acedia's collections can only store AcediaObject, but, thanks to boxing, any value can be turned into an AcediaObject and stored in the collection. For native primitive types boxes can be created with either BoxAPI or manually:

local IntBox    box1;
local FloatBox  box2;
//  Created with `BoxAPI`
box1 = _.box.int(7);
//  Allocated and initialized manually
box2 = FloatBox(_.memory.Allocate(class'FloatBox'));
box2.Initialize(-2.48); // Must be done immediately after allocation!
//  Works the same
Log("Int value:" @ box1.Get());     // Int value: 7
Log("Float value:" @ box2.Get());   // Float value: -2.48

Immutable boxes also have a counterpart - mutable references that also provide Set() method:

local IntRef    ref1;
local FloatRef  ref2;
//  Created with `BoxAPI`
ref1 = _.ref.int(7);
//  Allocated and initialized manually
ref2 = FloatRef(_.memory.Allocate(class'FloatRef'));
ref2.Initialize(-2.48); // Must be done immediately after allocation!
//  Change values
ref1.Set(-89);
ref2.Set(0.56);
Log("Int value:" @ ref1.Get());     // Int value: -89
Log("Float value:" @ ref2.Get());   // Float value: 0.56

This makes it sound like reference are just more functional boxes! But the guarantee of unchanged value has its own perks and the most important difference between boxes and references concerns implementation of their IsEqual() and GetHash() methods. Let's talk about them a bit more.

Object equality and object hash

Comparing object variables with == operator checks reference equality: whether variables refer to the exact same object. But sometimes we want to implement value equality check - a comparison for the contents of two objects, e.g. checking that two different Texts store the exact same data. Acedia provides an alternative way to compare two objects - IsEqual() method. Its default implementation corresponds to that of == operator:

public function bool IsEqual(Object other)
{
    return (self == other);
}

But it can be redefined, as long as it obeys following rules:

  • a.IsEqual(a) == true;
  • a.IsEqual(b) if and only if b.IsEqual(a);
  • none is only equal to none;
  • Result of a.IsEqual(b) does not change unless one of the objects gets deallocated.

Because of the last rule, IsEqual() cannot compare two MutableTexts based on their contents, since they can change without deallocation (unlike contents of an immutable Text).

Reimplementing IsEqual() method also requires you to reimplement how object's hash value is calculated. Hash value is a an int value associated with an object. Equal objects must have the same hash value, but, while two different objects are also allowed to share the same hash, such a collision should be highly unlikely. Essentially, object hash value should be 100% determined by that object's contents, but behave as if it was a uniformly randomly generated int. This latter quality is necessary for hash tables to efficiently function.

By default, Acedia's objects simply use randomly generated value, determined at the moment of their allocation, as their hash (this means their hash value fully depends on their reference). This can be changed by reimplementing CalculateHashCode() method. Every object will only call it once to cache it for GetHashCode():

public final function int GetHashCode()
{
    if (_hashCodeWasCached) {
        return _cachedHashCode;
    }
    _hashCodeWasCached = true;
    _cachedHashCode = CalculateHashCode();
    return _cachedHashCode;
}

Important requirement placed on hash value is that it should never change for an allocated object. Unlike mutable objects, immutable ones, such as Text, can benefit from redefining their hash calculation to be fully dependent on their contents instead of their reference:

protected function int CalculateHashCode()
{
    local int i;
    local int hash;
    hash = 5381;
    for (i = 0; i < codePoints.length; i += 1)
    {
        //  hash * 33 + codePoints[i]
        hash = ((hash << 5) + hash) + codePoints[i];
    }
    return hash;
}

This makes sure that two Texts with equal contents have the same hash value and that is what makes them usable as keys inside the HashTable collection.

Equality and hashing for boxes and references

  • Boxes redefine IsEqual() and GetHash() to depend on the stored value. Since value inside the box cannot change, then there is no problem to base equality and hash on it.
  • References do not redefine IsEqual() / GetHash() and behave like any other object - their hash is random and they are only equal to themselves.
local ByteBox box1, box2;
local ByteRef ref1, ref2;
box1 = _.box.byte(56);
box2 = _.box.byte(56);
ref1 = _.ref.byte(247);
ref2 = _.ref.byte(247);
// Boxes equality: true
Log("Boxes equality:" @ (box1.IsEqual(box2)));
// Boxes hash equality: true
Log("Boxes hash equality:" @ (box1.GetHash() == box2.GetHash()));
// Refs equality: false
Log("Refs equality:" @ (ref1.IsEqual(ref2)));
// Refs hash equality: false
// (that's the most likely result, but it can actually be `true` by pure chance)
Log("Refs hash equality:" @ (ref1.GetHash() == ref2.GetHash()));

NOTE: For strings the role of boxes and references is performed by Text and MutableText classes that are discussed elsewhere.

Actor references with NativeActorRef

As was explained in object problem, storing actor references directly inside objects is a bad idea. The safe way to do it are special actor reference objects: ActorRef for Acedia's actors and NativeActorRef for any kind of actors. They themselves are not actors, but Actor returned by their Get() method is guaranteed to be safe to use:

class MyObject extends AcediaObject;

var NativeActorRef pawnReference;
// ...

protected function Finalizer()
{
    _.memory.Free(pawnReference); // This does not destroy stored pawn!
    pawnReference = none;
}

function Pawn GetMyPawn()
{
    if (pawnReference == none) {
        return none;
    }
    return Pawn(pawnReference.Get());
}

function SetMyPawn(Pawn newPawn)
{
    if (pawnReference == none)
    {
        //  `UnrealAPI` deals with storing non-Acedia actors such as `Pawn`.
        //  For `AcediaActor`s you can also use `_.ref.Actor()`.
        pawnReference = _.unreal.ActorRef(newPawn);
    }
    else {
        pawnReference.Set(newPawn);
    }
}

function DoWork()
{
    local Pawn myPawn;
    myPawn = GetMyPawn();
    if (myPawn == none) {
        return;
    }
    // <Some code that might `Destroy()` our pawn>
    // ^ After destroying a pawn,
    //  `myPawn` local variable might go "bad" and cause crashes,
    //  so it's a good idea to "update" it from the safe `pawnReference`:
    myPawn = GetMyPawn();
    if (myPawn != none) {
        myPawn.health += 10;
    }
}

NOTE: Actor boxes do not exist, since we cannot guarantee that value inside them will never change - destroying stored actor will always reset it to none.

Array boxes and references

If necessary, box and reference classes can be manually created for any type of value, including array<...>s and structs. Acedia provides such classes for arrays of primitive value types out of the box. They can be useful for passing huge arrays between objects and functions by reference, without copying their entire data every time. They also provide several convenience methods - here is a list for FloatArrayRef's methods as an example:

MethodDescription
Get()Returns the whole stored array as array<float>.
Set(array<float>)Sets the whole array value.
GetItem(int, optional float)Returns item at specified index. If index is invalid, returns passed default value.
SetItem(int, float)Changes array's value at specified index.
GetLength()Returns length of the array. ref.GetLength() is faster than ref.Get().length, since latter will make a copy of the whole array first
SetLength(int)Resizes stored array, doing nothing on negative input.
Empty()Empties stored array.
Add(int)Increases length of the array by adding specified amount of new elements at the end.
Insert(int index, int count)Inserts count zeroes into the array at specified position. The indices of the following elements are increased by count in order to make room for the new elements.
Remove(int index, int count)Removes number elements from the array, starting at index. All elements before position and from index + count on are not changed, but the element indices change, - they shift to close the gap, created by removed elements.
RemoveIndex(int)Removes value at a given index, shifting all the elements that come after one place backwards.
AddItem(float)Adds given float at the end of the array, expanding it by 1 element.
InsertItem(int, float)Inserts given item at index of the array, shifting all the elements starting from index one position to the right.
AddArray(array<float>) / AddArrayRef(FloatArrayRef)Adds given array of items at the end of the array, expanding it by inserted amount.
InsertArray(array<float>) / InsertArrayRef(FloatArrayRef)Inserts items array at specified index of the array, shifting all the elements starting from index by inserted amount to the right.
RemoveItem(float, bool)Returns all occurrences of item in the caller float (optionally only first one).
Find(float)Finds first occurrence of specified item in caller FloatArrayRef and returns its index.
Replace(float search, float replacement)Replaces any occurrence of search with replacement.
Sort(optional bool descending)Sorts array in either ascending or descending order.