Initial commit
This commit is contained in:
		
						commit
						4624668be3
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					book
 | 
				
			||||||
							
								
								
									
										6
									
								
								book.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								book.toml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					[book]
 | 
				
			||||||
 | 
					authors = ["Anton Tarasenko"]
 | 
				
			||||||
 | 
					language = "en"
 | 
				
			||||||
 | 
					multilingual = false
 | 
				
			||||||
 | 
					src = "src"
 | 
				
			||||||
 | 
					title = "Lazy cookbook"
 | 
				
			||||||
							
								
								
									
										17
									
								
								src/SUMMARY.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/SUMMARY.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					# Summary
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- [Collections recipes](./collections/index.md)
 | 
				
			||||||
 | 
					  - [Storing built-in values](./collections/storing_builtin.md)
 | 
				
			||||||
 | 
					  - [Using iterators](./collections/iterators.md)
 | 
				
			||||||
 | 
					  - [Using JSON data](./collections/using_json.md)
 | 
				
			||||||
 | 
					- [Acedia events system](./events/index.md)
 | 
				
			||||||
 | 
					  - [Connecting to signal](./events/connecting.md)
 | 
				
			||||||
 | 
					  - [Disconnecting from signal](./events/disconnecting.md)
 | 
				
			||||||
 | 
					  - [Custom signals](./events/custom.md)
 | 
				
			||||||
 | 
					- [Feature recipes](./feature/index.md)
 | 
				
			||||||
 | 
					  - [Creating a `Feature`](./feature/creating_feature.md)
 | 
				
			||||||
 | 
					  - [Packaging a `Feature`](./feature/packaging_feature.md)
 | 
				
			||||||
 | 
					- [AcediaObject recipes](./object/index.md)
 | 
				
			||||||
 | 
					  - [Allocating object](./object/allocate.md)
 | 
				
			||||||
 | 
					  - [Detect object reallocation](./object/detect_reallocation.md)
 | 
				
			||||||
 | 
					  - [Force object deallocation](./object/force_deallocation.md)
 | 
				
			||||||
							
								
								
									
										4
									
								
								src/collections/index.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/collections/index.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					# Collections recipes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A collection of `how-to`s for working with Acedia's collections:
 | 
				
			||||||
 | 
					`ArrayList` and `HashTable` classes.
 | 
				
			||||||
							
								
								
									
										74
									
								
								src/collections/iterators.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								src/collections/iterators.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,74 @@
 | 
				
			|||||||
 | 
					# Using iterators
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Simple iteration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For both `ArrayList` and `HashTable`:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					function ListKeyValue(Collection data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    local AcediaObject          key, value;
 | 
				
			||||||
 | 
					    local CollectionIterator    iter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (iter = data.Iterate(); !iter.HasFinished(); iter.Next())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        key     = iter.GetKey();
 | 
				
			||||||
 | 
					        value   = iter.Get();
 | 
				
			||||||
 | 
					        //  Do what you want here
 | 
				
			||||||
 | 
					        _.memory.Free(key);
 | 
				
			||||||
 | 
					        _.memory.Free(value);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    iter.FreeSelf();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Skipping `none` values
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					function ListKeyValue(Collection data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    local AcediaObject          key, value;
 | 
				
			||||||
 | 
					    local CollectionIterator    iter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    iter = data.Iterate().LeaveOnlyNotNone();
 | 
				
			||||||
 | 
					    while (!iter.HasFinished())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        key     = iter.GetKey();
 | 
				
			||||||
 | 
					        value   = iter.Get();
 | 
				
			||||||
 | 
					        //  Do what you want here
 | 
				
			||||||
 | 
					        _.memory.Free(key);
 | 
				
			||||||
 | 
					        _.memory.Free(value);
 | 
				
			||||||
 | 
					        iter.Next();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    iter.FreeSelf();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Iteration over `Text` keys only
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Text keys are only relevant for `HashTable`s:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					function ListKeyValue(HashTable data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    local AcediaObject          key, value;
 | 
				
			||||||
 | 
					    local Text                  textKey;
 | 
				
			||||||
 | 
					    local CollectionIterator    iter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (iter = data.Iterate(); !iter.HasFinished(); iter.Next())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        key     = iter.GetKey();
 | 
				
			||||||
 | 
					        value   = iter.Get();
 | 
				
			||||||
 | 
					        textKey = Text(key);
 | 
				
			||||||
 | 
					        if (textKey != none)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Log(textKey.ToString() $ ":"
 | 
				
			||||||
 | 
					                @ _.text.IntoString(_.json.Print(value)));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        _.memory.Free(key);
 | 
				
			||||||
 | 
					        _.memory.Free(value);
 | 
				
			||||||
 | 
					        //  `textKey` is the same reference as `key`!
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    iter.FreeSelf();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
							
								
								
									
										53
									
								
								src/collections/storing_builtin.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/collections/storing_builtin.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					# Storing built-in values
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Storing in the array
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`ArrayList` serves the role of the regular array and storing built-in value data
 | 
				
			||||||
 | 
					inside it is simple:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					local ArrayList data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					data = _.collections.EmptyArrayList();
 | 
				
			||||||
 | 
					//  Add as the last element
 | 
				
			||||||
 | 
					data.AddFloat(-2.5);
 | 
				
			||||||
 | 
					//  Set at a particular index (length will be auto-adjusted)
 | 
				
			||||||
 | 
					data.Set(2, "just a string");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Log("data[0] =" @ data.GetFloat(0));    //  data[0] = -2.5
 | 
				
			||||||
 | 
					Log("data[1] =" @ data.IsNone(1));      //  data[1] = true
 | 
				
			||||||
 | 
					Log("data[2] =" @ data.GetString(2));   //  data[2] = just a string
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Getting `string` as a `Text`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					By default Acedia's collections use `Text` to store `string`s, so we can also
 | 
				
			||||||
 | 
					get their values as `Text`:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					local Text textInstance;
 | 
				
			||||||
 | 
					local ArrayList data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					data = _.collections.EmptyArrayList();
 | 
				
			||||||
 | 
					data.SetString(0, "Hello, world!");
 | 
				
			||||||
 | 
					textInstance = data.GetText(0);
 | 
				
			||||||
 | 
					Log("data[0] =" @ textInstance.ToString());
 | 
				
			||||||
 | 
					//  Same as any object returned by a function, `textInstance` must be released
 | 
				
			||||||
 | 
					textInstance.FreeSelf();
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Storing values by keys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For storing values using keys instead of numeric indices, the Acedia's way is to
 | 
				
			||||||
 | 
					use `HashTable`:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					local HashTable data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					data = _.collections.EmptyHashTable();
 | 
				
			||||||
 | 
					data.SetBool(P("Deal damage?"), true);
 | 
				
			||||||
 | 
					data.SetInt(P("Damage amount"), 9001);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Log("Deal damage?" @ data.GetFloat(P("Deal damage?"))); //  Deal damage? true
 | 
				
			||||||
 | 
					Log("Damage amount:" @ data.IsNone(1));                 //  Damage amount: 9001
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
							
								
								
									
										123
									
								
								src/collections/using_json.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								src/collections/using_json.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,123 @@
 | 
				
			|||||||
 | 
					# Using JSON data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					JSON data can be stored inside Acedia's collections using only built-in values
 | 
				
			||||||
 | 
					types and `ArrayList`/`HashTable` collections:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* JSON's *null* can be stored as `none`;
 | 
				
			||||||
 | 
					* JSON's *true*/*false* can be stored as `bool`'
 | 
				
			||||||
 | 
					* JSON's *number* can be stored as either `int` or `float` (actually Acedia also
 | 
				
			||||||
 | 
					  contains `BigInt` type for storing arbitrarily large integer values, but it
 | 
				
			||||||
 | 
					  isn't yet implemented into JSON parsing);
 | 
				
			||||||
 | 
					* JSON's *string* can be stored as `string`/`Text`/`MutableText`;
 | 
				
			||||||
 | 
					* JSON's *array* can be stored as an `ArrayList`;
 | 
				
			||||||
 | 
					* JSON's *object* can be stored as `HashTable` with `Text` keys.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> **NOTE:** JSON *does not* have a separate undefined type and Acedia uses
 | 
				
			||||||
 | 
					> `none` instead of the missing values.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Converting JSON into Acedia collections
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Parsing JSON input
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To get an Acedia collection from a JSON object like this one:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```json
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    "innerObject": {
 | 
				
			||||||
 | 
					        "my_bool": true,
 | 
				
			||||||
 | 
					        "array": [
 | 
				
			||||||
 | 
					            "Engine.Actor",
 | 
				
			||||||
 | 
					            false,
 | 
				
			||||||
 | 
					            null,
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					            "something \"here\"": "yes",
 | 
				
			||||||
 | 
					            "maybe": 0.003
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            56.6
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "one more": {
 | 
				
			||||||
 | 
					            "nope": 324532,
 | 
				
			||||||
 | 
					            "whatever": false,
 | 
				
			||||||
 | 
					            "o rly?": "ya rly"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "my_int": -9823452
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "some_var": -7.32,
 | 
				
			||||||
 | 
					    "another_var": "aye!"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					recorded in the `string` named `jsonData` you can do the following:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					local Parser parser;
 | 
				
			||||||
 | 
					local HashTable jsonObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					parser = _.text.ParseString(jsonData);
 | 
				
			||||||
 | 
					jsonObject = HashTable(_.json.ParseWith(parser));
 | 
				
			||||||
 | 
					if (!parser.Ok()) {
 | 
				
			||||||
 | 
					    // Handle errors
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					else if (!parser.Skip().HasFinished()) {
 | 
				
			||||||
 | 
					    // There is more input left after parsing JSON value - is this a problem?
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					// '/innerObject/array/3/maybe' is  0.003
 | 
				
			||||||
 | 
					Log("'/innerObject/array/3/maybe' is"
 | 
				
			||||||
 | 
					    @ jsonObject.GetFloatBy(P("/innerObject/array/3/maybe")));
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Constructing by hand
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Example of constructing the same object by hand:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					local HashTable jsonObject;
 | 
				
			||||||
 | 
					local HashTable innerObject, oneMore, anonymousObject;
 | 
				
			||||||
 | 
					local ArrayList jsonArray;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					anonymousObject = _.collections.EmptyHashTable();
 | 
				
			||||||
 | 
					anonymousObject.SetString(P("something \"here\""), "yes");
 | 
				
			||||||
 | 
					anonymousObject.SetFloat(P("maybe"), 0.003);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					jsonArray = _.collections.EmptyArrayList()
 | 
				
			||||||
 | 
					    .AddString("Engine.Actor")
 | 
				
			||||||
 | 
					    .jsonArray.AddBool(false)
 | 
				
			||||||
 | 
					    .jsonArray.AddItem(none)
 | 
				
			||||||
 | 
					    .jsonArray.AddItem(anonymousObject)
 | 
				
			||||||
 | 
					    .jsonArray.AddFloat(56.6);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					oneMore = _.collections.EmptyHashTable()
 | 
				
			||||||
 | 
					    .SetString(P("o rly?"), "ya rly")
 | 
				
			||||||
 | 
					    .SetFloat(P("nope"), 324532)
 | 
				
			||||||
 | 
					    .SetBool(P("whatever"), false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					innerObject = _.collections.EmptyHashTable()
 | 
				
			||||||
 | 
					    .SetItem(P("array"), jsonArray)
 | 
				
			||||||
 | 
					    .SetItem(P("one more"), oneMore)
 | 
				
			||||||
 | 
					    .SetBool(P("my_bool"), true)
 | 
				
			||||||
 | 
					    .SetInt(P("my_int"), -9823452);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//  Put it all together!
 | 
				
			||||||
 | 
					jsonObject = _.collections.EmptyHashTable()
 | 
				
			||||||
 | 
					    .SetItem(P("innerObject"), innerObject)
 | 
				
			||||||
 | 
					    .SetFloat(P("some_var"), -7.32)
 | 
				
			||||||
 | 
					    .SetString(P("another_var"), "aye!");
 | 
				
			||||||
 | 
					//  If you only want to keep `jsonObject`, release other references -
 | 
				
			||||||
 | 
					//  they won't disappear
 | 
				
			||||||
 | 
					anonymousObject.FreeSelf();
 | 
				
			||||||
 | 
					jsonArray.FreeSelf();
 | 
				
			||||||
 | 
					oneMore.FreeSelf();
 | 
				
			||||||
 | 
					innerObject.FreeSelf();
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Converting Acedia collections into JSON
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Use `_.json.Print()` to get a compact JSON representation:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					//  {"innerObject":{"my_bool":true,"array":["Engine.Actor",false,null,{"something \"here\"":"yes","maybe":0.003},56.6],"one more":{"nope":324532,"whatever":false,"o rly?":"ya rly"},"my_int":-9823452},"some_var":-7.32,"another_var":"aye!"}
 | 
				
			||||||
 | 
					Log(_.text.IntoString(_.json.Print(jsonObject)));
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					or `_.json.PrettyPrint()` for a nice-looking (multiline, indented and colored)
 | 
				
			||||||
 | 
					result.
 | 
				
			||||||
							
								
								
									
										43
									
								
								src/events/connecting.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/events/connecting.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					# Connecting to signal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## From inside `AcediaObject` (or its child class)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Supposing you want to connect to a signal function
 | 
				
			||||||
 | 
					`_server.unreal.gameRules.OnNetDamage()`:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					_server.unreal.gameRules.OnNetDamage(self).connect = handler;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					where `handler()` can be any function with appropriate signature:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					function int Handler(
 | 
				
			||||||
 | 
					    int                 originalDamage,
 | 
				
			||||||
 | 
					    int                 damage,
 | 
				
			||||||
 | 
					    Pawn                injured,
 | 
				
			||||||
 | 
					    Pawn                instigator,
 | 
				
			||||||
 | 
					    Vector              hitLocation,
 | 
				
			||||||
 | 
					    out Vector          momentum,
 | 
				
			||||||
 | 
					    class<DamageType>   damageType)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    //  Do whatever
 | 
				
			||||||
 | 
					    return damage;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## From inside non-`AcediaObject`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Pass any other `AcediaObject` object as an argument to your signal function.
 | 
				
			||||||
 | 
					For example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					local ServiceAnchor receiver;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					receiver = ServiceAnchor(_.memory.Allocate(class'ServiceAnchor'));
 | 
				
			||||||
 | 
					_server.unreal.gameRules.OnNetDamage(receiver).connect = handler;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> **NOTE:** Signal *does not* keep the reference to passed argument and once
 | 
				
			||||||
 | 
					> `receiver` gets deallocated - signal will stop notifying handlers connected
 | 
				
			||||||
 | 
					> through it.
 | 
				
			||||||
							
								
								
									
										163
									
								
								src/events/custom.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								src/events/custom.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,163 @@
 | 
				
			|||||||
 | 
					# Custom signals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Simple notification events
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you need to add an event with handlers that don't take any parameters and
 | 
				
			||||||
 | 
					don't return anything, then easiest way it to use `SimpleSignal` / `SingleSlot`
 | 
				
			||||||
 | 
					classes:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					class MyEventClass extends AcediaObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var private SimpleSignal onMyEventSignal;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected function Constructor()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    onMyEventSignal = SimpleSignal(_.memory.Allocate(class'SimpleSignal'));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected function Finalizer()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    _.memory.Free(onMyEventSignal);
 | 
				
			||||||
 | 
					    onMyEventSignal = none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public function SimpleSlot OnMyEvent(AcediaObject receiver)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return SimpleSlot(onMyEventSignal.NewSlot(receiver));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//  Suppose you want to emit the `signal` when this function is called...
 | 
				
			||||||
 | 
					public function SimpleSlot FireOffMyEvent(AcediaObject receiver)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    //  ...simply call this and all the slots will have their handlers called
 | 
				
			||||||
 | 
					    onMyEventSignal.Emit();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Then you can use `OnMyEvent()` as a *signal function*:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					//  To add handlers
 | 
				
			||||||
 | 
					myEventClassInstance.OnMyEvent(self).connect = handler;
 | 
				
			||||||
 | 
					//  To remove handlers
 | 
				
			||||||
 | 
					myEventClassInstance.OnMyEvent(self).Disconnect();
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Events with parameters
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Some of the events, like `OnNetDamage()`, can take
 | 
				
			||||||
 | 
					parameters.
 | 
				
			||||||
 | 
					To create signals like that, follow the template and define new classes like so:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					class MySignal extends Signal;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public final function Emit(<PARAMETERS>)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    local Slot nextSlot;
 | 
				
			||||||
 | 
					    StartIterating();
 | 
				
			||||||
 | 
					    nextSlot = GetNextSlot();
 | 
				
			||||||
 | 
					    while (nextSlot != none)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        MySlot(nextSlot).connect(<PARAMETERS>);
 | 
				
			||||||
 | 
					        nextSlot = GetNextSlot();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    CleanEmptySlots();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defaultproperties
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    relatedSlotClass = class'MySlot'
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					class MySlot extends Slot;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					delegate connect(<PARAMETERS>)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    DummyCall(); // This allows Acedia to cleanup slots without set handlers
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected function Constructor()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    connect = none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected function Finalizer()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    super.Finalizer();
 | 
				
			||||||
 | 
					    connect = none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defaultproperties
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Here you can use any set of parameters instead of `<PARAMETERS>`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Events with return values
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Sometimes you want your handlers to respond in some way to the event.
 | 
				
			||||||
 | 
					You can either allow them to modify input parameters (e.g. by declaring them as
 | 
				
			||||||
 | 
					`out`) or allow them to have return value.
 | 
				
			||||||
 | 
					`OnNetDamage()`, for example, is allowed to modify incoming damage by returning
 | 
				
			||||||
 | 
					a new value.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To add `signal`s / `slot`s that handle return value use following templates:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					class MySignal extends Signal;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public final function <RETURN_TYPE> Emit(<PARAMETERS>)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    local <RETURN_TYPE> newValue;
 | 
				
			||||||
 | 
					    local Slot          nextSlot;
 | 
				
			||||||
 | 
					    StartIterating();
 | 
				
			||||||
 | 
					    nextSlot = GetNextSlot();
 | 
				
			||||||
 | 
					    while (nextSlot != none)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        newValue = <SLOT_CLASS>(nextSlot).connect(<PARAMETERS>);
 | 
				
			||||||
 | 
					        //  This check is necessary before using returned value
 | 
				
			||||||
 | 
					        if (!nextSlot.IsEmpty())
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            //  Now handle `newValue` however you see fit
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        nextSlot = GetNextSlot();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    CleanEmptySlots();
 | 
				
			||||||
 | 
					    //  Return whatever you see fit after handling all the slots
 | 
				
			||||||
 | 
					    return <END_RETURN_VALUE>;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defaultproperties
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    relatedSlotClass = class'MySlot'
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					class MySlot extends Slot;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					delegate <RETURN_TYPE> connect(<PARAMETERS>)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    DummyCall();
 | 
				
			||||||
 | 
					    //  Return anything you want:
 | 
				
			||||||
 | 
					    //  this value will be filtered inside corresponding `Signal`
 | 
				
			||||||
 | 
					    //  if no handler is set to the associated slot
 | 
				
			||||||
 | 
					    return <???>;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected function Constructor()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    connect = none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected function Finalizer()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    super.Finalizer();
 | 
				
			||||||
 | 
					    connect = none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
							
								
								
									
										20
									
								
								src/events/disconnecting.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/events/disconnecting.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					# Disconnecting from signal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## From inside `AcediaObject` (or its child class)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Supposing you want to disconnect from a signal function
 | 
				
			||||||
 | 
					`_server.unreal.gameRules.OnNetDamage()`:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					_server.unreal.gameRules.OnNetDamage(self).Disconnect();
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## From inside non-`AcediaObject`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To do that you must have passed another `AcediaObject` as an argument to
 | 
				
			||||||
 | 
					`OnNetDamage()` (or any other signal).
 | 
				
			||||||
 | 
					Supposing that object was called `receiver`:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					_server.unreal.gameRules.OnNetDamage(receiver).Disconnect();
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
							
								
								
									
										4
									
								
								src/events/index.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/events/index.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					# Acedia events system
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A collection of `how-to`s for working with Acedia's event system: `Signal`s and
 | 
				
			||||||
 | 
					`Slot`s.
 | 
				
			||||||
							
								
								
									
										155
									
								
								src/feature/creating_feature.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								src/feature/creating_feature.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,155 @@
 | 
				
			|||||||
 | 
					# Creating a Feature
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Prepare classes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When creating a `Mutator` you must create a child `Mutator` class, but
 | 
				
			||||||
 | 
					when creating a `Feature` you must create two classes: one for the `Feature`
 | 
				
			||||||
 | 
					itself and one for its config.
 | 
				
			||||||
 | 
					Name your config class something human-readable and your `Feature` class should
 | 
				
			||||||
 | 
					have the same name, but with '_Feature' suffix.
 | 
				
			||||||
 | 
					For example, if you want your configs to be stored inside 'MyFeatureConfig.ini',
 | 
				
			||||||
 | 
					bare minimum class skeletons are:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					//  MyFeature.uc
 | 
				
			||||||
 | 
					class MyFeature extends FeatureConfig
 | 
				
			||||||
 | 
					    perobjectconfig
 | 
				
			||||||
 | 
					    config(MyFeatureConfig);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defaultproperties
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    configName = "MyFeatureConfig"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					//  MyFeature_Feature.uc
 | 
				
			||||||
 | 
					class MyFeature_Feature extends Feature;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defaultproperties
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    configClass = class'MyFeature'
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Setup config variables in config file
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Config variables are meant to be added into your `FeatureConfig` class.
 | 
				
			||||||
 | 
					Assuming you want to add `bool` and `int` settings, simply add two public config
 | 
				
			||||||
 | 
					variables:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					//  MyFeature.uc
 | 
				
			||||||
 | 
					class MyFeature extends FeatureConfig
 | 
				
			||||||
 | 
					    perobjectconfig
 | 
				
			||||||
 | 
					    config(MyFeatureConfig);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var public config int   levelOfAwesome;
 | 
				
			||||||
 | 
					var public config bool  enableTrollEngine;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defaultproperties
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    configName = "MyFeatureConfig"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To setup their default values, instead of `defaultproperties`
 | 
				
			||||||
 | 
					define `DefaultIt()` method:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					//  MyFeature.uc
 | 
				
			||||||
 | 
					protected function DefaultIt()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    levelOfAwesome      = 11;
 | 
				
			||||||
 | 
					    enableTrollEngine   = true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Conversion to/from `HashTable`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To make full use out of your `Feature`, Acedia also requires that you provide
 | 
				
			||||||
 | 
					methods to convert to and from its collection.
 | 
				
			||||||
 | 
					For our example simply add two more methods:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					//  MyFeature.uc
 | 
				
			||||||
 | 
					protected function HashTable ToData()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    local HashTable data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    data = __().collections.EmptyHashTable();
 | 
				
			||||||
 | 
					    data.SetInt(P("levelOfAwesome"), levelOfAwesome);
 | 
				
			||||||
 | 
					    data.SetBool(P("enableTrollEngine"), enableTrollEngine);
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected function FromData(HashTable source)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (source == none) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    //  Second parameters should are fallback - use values from `DefaultIt()`
 | 
				
			||||||
 | 
					    levelOfAwesome      = source.GetInt(P("levelOfAwesome"), 11);
 | 
				
			||||||
 | 
					    enableTrollEngine   = source.GetBool(P("enableTrollEngine"), true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Setup your feature to use your config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Recommended way to do it is to duplicate your config variables in your
 | 
				
			||||||
 | 
					`Feature` class:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					//  MyFeature_Feature.uc
 | 
				
			||||||
 | 
					class MyFeature_Feature extends Feature;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//  Not actually config variables
 | 
				
			||||||
 | 
					var public /*config*/ int   levelOfAwesome;
 | 
				
			||||||
 | 
					var public /*config*/ bool  enableTrollEngine;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defaultproperties
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    configClass = class'MyFeature'
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Then add code that will handle setting config data for your `Feature`:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					//  MyFeature_Feature.uc
 | 
				
			||||||
 | 
					protected function SwapConfig(FeatureConfig config)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    local MyFeature newConfig;
 | 
				
			||||||
 | 
					    newConfig = MyFeature(config);
 | 
				
			||||||
 | 
					    if (newConfig == none) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    levelOfAwesome      = newConfig.levelOfAwesome;
 | 
				
			||||||
 | 
					    enableTrollEngine   = enableTrollEngine.disableTick;
 | 
				
			||||||
 | 
					    //      Here you can also add any logic that needs to be performed when
 | 
				
			||||||
 | 
					    //  values of the config variables were swapped mid-game, if you care to
 | 
				
			||||||
 | 
					    //  support it.
 | 
				
			||||||
 | 
					    //      Just beware that this method can be called when you `Feature` is
 | 
				
			||||||
 | 
					    //  both enabled and not (can be checked with `IsEnabled()`).
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Run initialization / shutdown logic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Instead of normal Acedia's `Constructor()` or `Finalizer()`, for `Featuire`s
 | 
				
			||||||
 | 
					one should use:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					protected function OnEnabled()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected function OnDisabled()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					These methods are called when feature gets enabled or disabled, which can,
 | 
				
			||||||
 | 
					in theory, happen several times per game.
 | 
				
			||||||
 | 
					They aren't called when `Feature`'s config is changed mid-game, so sometimes
 | 
				
			||||||
 | 
					it is convenient to move part of the initialization logic into `SwapConfig()`.
 | 
				
			||||||
							
								
								
									
										18
									
								
								src/feature/index.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/feature/index.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					# Feature recipes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A collection of `how-to`s for working with `Feature` class.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This class is Acedia's replacement for `Mutators`: a certain subset of
 | 
				
			||||||
 | 
					functionality that can be enabled or disabled, according to server owner's
 | 
				
			||||||
 | 
					wishes.
 | 
				
			||||||
 | 
					Unlike `Mutator`s:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* There is no limit for the amount of `Feature`s that can be active
 | 
				
			||||||
 | 
					    at the same time;
 | 
				
			||||||
 | 
					* They also provide built-in ability to have several different configs
 | 
				
			||||||
 | 
					    that can be swapped during the runtime;
 | 
				
			||||||
 | 
					* They can be enabled / disabled during the runtime.
 | 
				
			||||||
 | 
					    Achieving these points currently comes at the cost of developer having to
 | 
				
			||||||
 | 
					    perform additional work;
 | 
				
			||||||
 | 
					* They are server-side and for now are not supposed to be created for
 | 
				
			||||||
 | 
					  the clients.
 | 
				
			||||||
							
								
								
									
										42
									
								
								src/feature/packaging_feature.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/feature/packaging_feature.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,42 @@
 | 
				
			|||||||
 | 
					# Packaging a Feature
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Suppose you've created your own `Feature` class and want to compile it to be
 | 
				
			||||||
 | 
					usable with Acedia.
 | 
				
			||||||
 | 
					In this how-to we will assume that your class is named `MyFeature_Feature`
 | 
				
			||||||
 | 
					(same as [here](./creating_feature.md)).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Create regular UnrealScript mod
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					First step is still to prepare compilation of `*.u` file, like one would do for
 | 
				
			||||||
 | 
					any regular UnrealScript mod and put your `*.uc` script files inside.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Create manifest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To know what is available in each package, Acedia reads its manifest.
 | 
				
			||||||
 | 
					To add a manifest create a file named exactly 'Manifest.uc' in your package:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					//  Manifest.uc
 | 
				
			||||||
 | 
					class Manifest extends _manifest
 | 
				
			||||||
 | 
					    abstract;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defaultproperties
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Register feature in the manifest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To add your `Feature` into manifest, simply fill it inside `features` array:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					//  Manifest.uc
 | 
				
			||||||
 | 
					 class Manifest extends _manifest
 | 
				
			||||||
 | 
					    abstract;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defaultproperties
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    //  You can add any amount of features from a single package here
 | 
				
			||||||
 | 
					    features(0) = class'MyFeature_Feature'
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
							
								
								
									
										11
									
								
								src/object/allocate.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/object/allocate.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					# Allocating object
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you've created a new child class (say, `MyCoolObject`) of `AcediaObject` and
 | 
				
			||||||
 | 
					want to allocate it, simply do:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					local MyCoolObject instance;
 | 
				
			||||||
 | 
					instance = MyCoolObject(_.memory.Allocate(class'MyCoolObject'));
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It is guaranteed to succeed for non-abstract classes.
 | 
				
			||||||
							
								
								
									
										50
									
								
								src/object/detect_reallocation.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								src/object/detect_reallocation.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,50 @@
 | 
				
			|||||||
 | 
					# Detect object reallocation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Sometimes you want to keep track of an object without declaring that you own its
 | 
				
			||||||
 | 
					reference with `NewRef()`, thus allowing it to get deallocated even while you
 | 
				
			||||||
 | 
					are keeping a reference to it.
 | 
				
			||||||
 | 
					How to do it in a safe way and detect that it was deallocated/reallocated?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## What to do when you start storing a reference
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When you first get an instance of `AcediaObject` you'd like to store in such
 | 
				
			||||||
 | 
					a way, check if it's allocated and remember its life version:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					var int             storedReferenceLifeVersion;
 | 
				
			||||||
 | 
					var AcediaObject    storedReference;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function Store(AcediaObject newReference)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (newReference == none)           return;
 | 
				
			||||||
 | 
					    if (!newReference.IsAllocated())    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    storedReference             = newReference;
 | 
				
			||||||
 | 
					    storedReferenceLifeVersion  = newReference.GetLifeVersion();
 | 
				
			||||||
 | 
					    //  Not calling `newReference.NewRef()`, so `newReference` can get
 | 
				
			||||||
 | 
					    //  deallocated at any time!
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## What to do when you want to check if stored reference was deallocated
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Before using such reference again you simply need to check if life version has
 | 
				
			||||||
 | 
					changed.
 | 
				
			||||||
 | 
					If it did, then this instance was reallocated and repurposed and you shouldn't
 | 
				
			||||||
 | 
					use it anymore.
 | 
				
			||||||
 | 
					Othewrwise it is still the same object.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```unrealscript
 | 
				
			||||||
 | 
					function AcediaObject Get()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (storedReference == none) {
 | 
				
			||||||
 | 
					        return none;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (storedReference.GetLifeVersion() != storedReferenceLifeVersion)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        //  This object was reallocated! Time to forget about it.
 | 
				
			||||||
 | 
					        storedReference = none;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return storedReference;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
							
								
								
									
										10
									
								
								src/object/force_deallocation.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/object/force_deallocation.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					# Forcing object deallocation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`self.FreeSelf()` and `_.memory.Free()` only reduce reference counter of
 | 
				
			||||||
 | 
					the object.
 | 
				
			||||||
 | 
					But how to forcefully deallocate it?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Just do not do that you fucking idiot**.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you need to somehow dispose of what that object represents, simply add
 | 
				
			||||||
 | 
					a flag that marks that object as disposed.
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/object/index.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/object/index.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					# AcediaObject recipes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A collection of `how-to`s for working with `AcediaObject` class and related
 | 
				
			||||||
 | 
					topics.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Base object class to be used in Acedia instead of an `Object`.
 | 
				
			||||||
 | 
					`AcediaObject` provides access to Acedia's APIs through an accessor to
 | 
				
			||||||
 | 
					a `Global` object, built-in mechanism for storing unneeded references in
 | 
				
			||||||
 | 
					an object pool and constructor/finalizer.
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user