* Adds save flag support (see `ElvenGlasses` for an example)
* Updates AOSAttributes so they are code genned
* Fixes embedded object support by adding an `IRawSerializable`
* Fixes various inconsistencies in serializing with codegen
* Adds code genning for embedded objects. See `AquariumState` as an example.
* Adds code genning for fields that are `Timer`. See `Aquarium` as an example.
* Codegens aquariums
* Fixes missing option for most primitive field types.
### THIS IS A BREAKING CHANGE IF YOU ARE ALREADY USING CODEGEN. IF YOUR WORLD HAS ERRORS LOADING PLEASE CONTACT ME ON DISCORD. ORE MIGHT FAIL TO LOAD.
### Changes
* Fixes Components from addons not marking dirty
* Code gens BaseAddonContainer
* Code gens Ingots
* Fixes code gen deserialization for Ore
* Code gens dyetubs
* Code gens reagents
* Code gens tailor commodities
* Code gens fish
* Fixes pooled timer leaking
* Fixes `[dumptimers` command so it outputs properly, adds spacing, and stacktraces
* Adds `[Tidy]` for serializing Lists. This will remove deleted entities during world save before serializing the list.
* Adds helpers for managing Lists/Sets/Dictionaries
### New API
```cs
// Creates the list if it is null, then adds
Utility.Add(ref list, value);
Utility.Add(ref set, value);
Utility.Add(ref dict, key, value);
// Nulls the variable if the count is zero
Utility.Remove(ref list, value);
Utility.Remove(ref set, value);
Utility.Remove(ref dict, key);
// Marks entity as dirty in addition to doing the action
entity.Add(list, value);
// Marks entity as dirty, and will create list if it doesn't exist
entity.Add(ref list, value);
// Marks entity as dirty in addition to doing the action
entity.Remove(list, value);
// Marks entity as dirty, and will null the list count is zero
entity.Remove(ref list, value);
```
### Updates to [dumptimers
<img width="825" alt="Screen Shot 2021-08-14 at 2 55 10 AM" src="https://user-images.githubusercontent.com/3953314/129442449-ccf7fe14-29d6-4f3f-9366-c8eb7b9828a7.png">
### Changes/Fixes:
* Adds timer pooling.
* Allows pool to be configurable in ModernUO.json
* Pool replenishes itself asynchronously if depleted.
* Fixes an issue with barkeeps and town criers
* Fixes an issue with incognito buff icons not being removed
* Fixes an issue with polymorph name mod not being removed
* Fixes several places where timers go on forever even after an object is deleted, keeping a reference (memory leak)
* Eliminates the timer for MiningCart altogether.
* Deletes `AcidSlime` since it is a duplicate of `PoolOfAcid`
* Fixes HonorableExecution and standardizes the code for other Bushido moves.
## Changes to the Timer API:
```cs
public class Timer
{
// Creates a timer that will be returned to the pool once execution stops.
public static void StartTimer(Action callback);
public static void StartTimer(TimeSpan delay, Action callback);
public static void StartTimer(TimeSpan delay, TimeSpan interval, Action callback);
public static void StartTimer(TimeSpan interval, int count, Action callback);
public static void StartTimer(TimeSpan delay, TimeSpan interval, int count, Action callback);
// Creates a timer and returns a token for more control. Requires manual cancellation in order for the timer to be returned to the pool.
// If the token is dereferenced, the timer will be dereferenced too. While not returning a timer to the pool is not considered hazardous, it does defeat the purpose of pooled timers.
public static void StartTimer(Action callback, out TimerExecutionToken token);
public static void StartTimer(TimeSpan delay, Action callback, out TimerExecutionToken token);
public static void StartTimer(TimeSpan delay, TimeSpan interval, Action callback, out TimerExecutionToken token);
public static void StartTimer(TimeSpan interval, int count, Action callback, out TimerExecutionToken token);
public static void StartTimer(TimeSpan delay, TimeSpan interval, int count, Action callback, out TimerExecutionToken token);
// If you aren't sure how to use the API above, or you don't care about performance, then you can use the old RunUO Timer.DelayCall
public static DelayCallTimer DelayCall(Action callback);
public static DelayCallTimer DelayCall(TimeSpan delay, Action callback);
public static DelayCallTimer DelayCall(TimeSpan delay, TimeSpan interval, Action callback);
public static DelayCallTimer DelayCall(TimeSpan interval, int count, Action callback);
public static DelayCallTimer DelayCall(TimeSpan delay, TimeSpan interval, int count, Action callback);
}
public struct TimerExecutionToken
{
public bool Running { get; }
public int Index { get; }
public int RemainingCount { get; }
public DateTime Next { get; }
}
```
## When to use `TimerExecutionToken`?
Use tokens when you want to gain the performance benefit of using a pooled timer, but you need one of the following:
* Access to the next time the timer will tick:`token.Next`
* Access to which interval, how many intervals there are, or how many are remaining: `token.Index`, `token.Count`, and `token.RemainingCount`
* Stop a timer manually.
* Determine if the timer is running: `timer.Running`
* See notes below about requirements for using tokens!
## Notes about using the TimerExecutionToken:
When you opt-in to receive a token, you must call `Cancel()` to return the timer. This can be done inside of the callback, or outside of the callback at any time.
If this is not called and your timer is an infinite interval, then you will create a potential memory leak, or null pointer exception in your callback.
If the timer ends and is stopped, but cancel is not called, then the timer will never return to the pool and stay referenced until the token is deleted or cancel is called. (Memory leak)
## Is this thread safe?
No. The ModernUO timer system is not thread safe at all. If you require a thread safe timer system, contact me and I'll help adapt this system. Keep in mind that there is a massive performance hit to make this thread safe when there are literally no use cases for it.
If you need to synchronize execution, meaning you want to execute code from another thread on the core thread. Let's say you have a discord bot that is pushing commands to the game server. Then use `EventLoopContext.Post(SendOrPostCallback callback, object state);`.
- [X] Adds a property to `CommandProperty` to allow modifying `PropertyObject` where there is no property setter that is accessible.
- [X] Updates AosAttributes and friends
Example of how to make this work:
```cs
[CommandProperty(AccessLevel.GameMaster, canModify: true)]
public AosWeaponAttributes WeaponAttributes { get; private set; }
```
This fix is necessary because in release mode the optimizer will sometimes _entirely remove the setter_ because it knows it can do something that is more efficient _when the property setter is private_. RunUO got around this by declaring a public setter explicitly that _was empty_.
### Screenshot
<img width="313" alt="Screen Shot 2021-05-15 at 11 34 01 PM" src="https://user-images.githubusercontent.com/3953314/118387955-49293c00-b5d6-11eb-8f31-a3b5e31bd18b.png">
- [X] Adds question about expansion at start of server
- [X] Adds question about client version to determine old have and map diffs
- [X] Adds config setting "maps.enablePre6000Trammel"
- [X] Rearranges some of the loading order.
- [X] Added support for deserializing nullable enums from json
TODO:
Expand the nullable enums deserialization factory to work with any type by pulling the factory and creating an instance of the converter.
- [X] Caches DateTime.NowUtc on the game loop (not other threads)
- [X] Replaces all locations where it makes sense
- [X] Adds Min/Max for `IComparable` (TimeSpan, DateTimes, etc)
Closes#261
- [X] Removes network pause/resume
- [X] Adds back packet profiler
- [X] Adds state machine to keep track and trace netstates
- [X] Changes NetState.Running back to using an interlock exchange
- [X] Adds preliminary packet throttling support
### Packet Throttling
- `[GetThrottle <packetId>` to get the delay in milliseconds for that packet
- `[SetThrottle <packetId> <delay>` to set the delay in milliseconds for that packet
The settings are saved to `Configuration/throttles.json`
- [X] Exposes Index/Count on the timer.
- [X] Cleans up abilities
- [X] Combines some spell context/info objects with their timers to reduce allocations
- [X] Fixes a bug where immolating weapon both finishes effect or stops in the wrong order due to a race condition.
- [X] Fixes some issues with the type caching
- [X] Changes type check default to ignore case
- [X] Splits out type caching of insensitive and sensitive lists. This means less stuff to iterate through when checking a type against the string.
- [X] Adds an ArrayEnumerator, mostly for reference purposes (copy/paste as needed)
- [X] Converts boat packets
- [X] Makes a packet container builder for packet 0xF7
- [X] Generalizes world item packet so it works for mobiles too
Notes:
- This PR doesn't address proper smooth movement for boats.
- [X] Adds a stop music packet
- [X] Converts chat packets
- [X] Breaks out chat code a little bit more
- [X] Converts character statue animation packet
- [X] Renames some folders to have spaces
- [X] Organizes and consolidates incoming/outgoing packets for other content
- [X] Fixes virtual checks
- [X] Removes 6017 handler since it is only used in one place
- [X] Exposes a ref int to modify the packet length. This is acceptable since we technically have access to the entire reader/buffer.
- [X] Fixes an issue with OPL packets using the wrong endianness and not updating the position properly.
- [X] Fixes an issue with SpanWriter not updating bytes written when it is used adhoc.
- [X] Moves packet creation for OPL inside the SendInfoTo function.
Bumps release version