Commit graph

39 commits

Author SHA1 Message Date
Kamron Batman
360143478a
feat: Adds tidy option for serialization. Codegens ballotbox. Fixes pooled timer leaking (#681)
* 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">
2021-08-14 03:02:53 -07:00
Kamron Batman
9b554f69b0
feat(timers): Adds timer pooling, fixes timer related bugs, and changes timer api (#667)
### 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);`.
2021-08-07 14:33:35 -07:00
Kamron Batman
a0893b68c0
fix(core): Updates slice with range selectors (#583)
- [X] Replaces Span slicing with range selection
- [X] Replaces string slicing with range selection
2021-04-23 20:57:24 -07:00
Kamron Batman
6c4308bce6
fix(core): Caches DateTime.NowUtc (#548)
- [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
2021-03-13 01:32:04 -08:00
Kamron Batman
8903028b5f
fix(core): Tightens the network stack (#479)
- [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`
2021-02-07 23:30:56 -08:00
Kamron Batman
76035f6bd1
fix(recipes): Fixes NPE with recipes on PlayerMobile (#476) 2021-02-06 21:07:59 -08:00
Kamron Batman
67625ad249
fix(core): Removes disposable netstates. (#467)
- [X] Removes IDisposable from NetState
- [X] Swaps Disconnect and Dispose methods
2021-02-05 14:33:35 -08:00
Kamron Batman
b921c38879
fix(core): Removes some uses of Linq (#421)
- [X] Removes some uses of linq
- [X] Creates struct based enumerator for Skills
- [X] Creates a struct based enumerator for TypeCache
- [X] Changes HarvestDefinition to an init array instead of List
- [X] Changes HeritageTokenGump Response from List to Array
2021-01-18 21:05:11 -08:00
Kamron Batman
c58aad733d
fix(core): Converts BB packets (#406)
- [X] Organizes and splits up bulletin boards
- [X] Converts packets
2021-01-13 22:28:31 -08:00
Kamron Batman
8763be8a21
fix(core): Cleans up uninitialized packets (#397)
- [X] Encapsulates/abstracts buffer cache checking
- [X] Changes mobile moving cache to use Span2D
2021-01-09 14:10:29 -08:00
Kamron Batman
03bdff2293
fix(content): Converts buff icon packets (#389)
- [X] Converts buff icon packets, and avoids string formatting.
2021-01-06 01:01:21 -08:00
Kamron Batman
1e2242bb1a
chore(content): Updates to C# 9 syntax (#373) 2020-12-30 12:50:10 -08:00
Kamron Batman
03d0a4664e
fix(core): Adds SkipLocalsInitAttribute support, optimizes broadcasted packets (#363)
- [X] Adds support for `SkipLocalsInitAttribute`. SkipLocalsInitAttribute skips initializing stack variables including `stackalloc`. I don't think it is wired/working yet but should be implemented soon.
- [X] Optimizes broadcasted packets by checking if the first byte (packet ID) is non-zero. If it is already set, it reuses the buffer.
- [X] Removes unnecessary refs to Spans. I don't think the Span struct itself is mutable, so a ref is not helpful.
2020-12-26 12:46:06 -08:00
Kamron Batman
10a6e17640
fix(core): Converts mobile moving packet (#357)
- [X] Converts mobile moving packet
2020-12-24 17:13:55 -08:00
Kamron Batman
4ddb3de026
fix(core): Fixes several serialization issues (#355)
- [X] Fixes an issue where a buffer smaller than 8 bytes would not double with enough space in some cases.
- [X] Fixes an issue with dupe copying the savebuffer reference (ugh).
- [X] Streamlines the IGenericWriter API to use better generics.
- [X] Streamlines the IGenericReader API to use better generics.
- [X] Forces `tidying` of a List/HashSet to be done externally since Writers/Readers should not have side effects.
- [X] Fixes an issue where Tidying a list didn't TrimExcess, causing memory leaks.
- [X] Reverted the meaning of `World.Running` to specifically refer to any world state post world loading.
  - NOTE: Do not use this if you want to block on world saves. Instead use checks against `WorldState.Saving` states.
- [X] Fixes an issue with serializing negative DateTime deltas.
- [X] Fixes a potential issue with serializing non-UTC DateTime.

Bumps release version
2020-12-23 07:11:41 -08:00
Kamron Batman
d71856ddbe
fix(net): Clean up for mobile packets (#338)
### Breaking Change
- [X] `Mobile.GetOldPacketFlags()` no longer exists. Instead there is a flag for `Mobile.GetPacketFlags()`.

### Non-Breaking Changes
- [X] Consolidates move to world for mobiles
- [X] Consolidates mobile packets between stygian abyss and older

This PR supersedes changes in #337. That PR will need to be redone and broken out anyway.
2020-12-10 17:46:58 -08:00
Kamron Batman
75c1b32513
fix(core): NPE in Cycles per second (#331)
- [X] Fixes an edge case where the cycle index goes negative and crashes
- [X] Fixes average CPS calculation
- [X] Fixes issue with logout delay
- [X] Bumps release version
2020-11-30 23:12:16 -08:00
Kamron Batman
77f665502b
Converts Item & Entity Packets (#326)
- [X] Converts World Item packets
- [X] Converter Remove Entity packets
- [X] Updates `LOSBlocker` and `Blocker`
- [X] Fixes a few bugs
- [X] Converts container packets

Bumps release version
2020-11-29 03:24:51 -08:00
Kamron Batman
351611a23a
Updates movement packets & Fastwalk (#324)
- [X] Updates Movement packets
- [X] Adds OSI fastwalk packets. These aren't used on OSi anymore.
- [X] Adds new movement handling, but looks like the client doesn't use it. (Also leaving the 0x4000 Character List Flag off)
- [X] Adds time sync request handler, but also looks like the client doesn't use it.
- [X] Adds time sync response for time sync, just in case, but it isn't used, so not sure about the arguments.
- [X] Reimplements RunUO's fastwalk to use a circular array on the netstate instead of every mobile
- [X] Removes ClearFastwalkStack from RunUO implementation. This shouldn't be needed anymore

Changed fastwalk settings:
```cs
        public static int WalkFootDelay { get; set; } = 440;
        public static int RunFootDelay { get; set; } = 220;
        public static int WalkMountDelay { get; set; } = 220;
        public static int RunMountDelay { get; set; } = 110;

        public static bool EnableFastwalkPrevention { get; set; } = true;
        public static AccessLevel FastwalkExemptionLevel { get; set; } = AccessLevel.Counselor;

        // If this is changed during runtime, then the steps array needs resizing.
        public static int MaxSteps { get; private set; } = 4;
```

modernuo.json
```json
{
  "settings": {
    "movement.delay.runFoot": "220",
    "movement.delay.runMount": "110",
    "movement.delay.walkFoot": "440",
    "movement.delay.walkMount": "220",
    "movement.enableFastWalkPrevention": "True",
    "movement.fastwalkExemptionLevel": "Counselor",
    "movement.maxSteps": "4"
  }
}
```

Notes about OSI fastwalk:
While it does work, I can't find a benefit in using it because of the variable speeds. If players moved at a single speed then we could refill the stack every X milliseconds with 6 keys and use a naive token bucket implementation.
Unfortunately variable speeds mount/run/walk/etc means we would have to use a leaky bucket algorithm.
If we are using a leaky bucket algorithm with a variable leak, then we don't need to send tokens because we are already tracking it on the server side.

ModernUO vs OSI Fastwalk:
When the fastwalk was implemented on OSI, it used up to 6 tokens. These tokens were probably distributed every 600-750 milliseconds. To get the same effect, the new fastwalk settings might need to be adjusted. I would tweak them and feel free to let me know what worked for you!

Bumps release version
2020-11-26 23:53:47 -08:00
Kamron Batman
b6cd408623
Updates Message Packets (#321)
### API Breaking Change
Combined `AsciiMessage` and `UnicodeMessage` into a single function that takes two arguments, `bool ascii` and `string lang`. Lang can be null (or anything) if ascii is true. 

- [X] Changes message packets
- [X] Cleans up some code
- [X] Uses benchmarks to determine if the spanwriter + copyfrom
2020-11-20 21:50:13 -08:00
Kamron Batman
d2cfeb06ab
Updates Light Packets & World Loading (#316)
- [X] Changes light packets
- [X] Updates world loading

Bumps release version
2020-11-17 00:46:06 -08:00
Kamron Batman
525cda5413
Cleanup & Fixes for .NET 5 (#309)
- [X] Fixes several bugs
- [X] Updates more ordinal issues
- [X] Cleans up the code a bit
- [X] Turns classes static that should have been
- [X] Changes TcpServer.Instances to a HashSet

Bumps release version
2020-11-15 10:03:50 -08:00
Kamron Batman
c3289a20ab
Changes damage packets (#299)
- [X] Changes damage packets

Bumps release version
2020-11-01 22:44:23 -08:00
Kamron Batman
6f5cb00cdd
Updates Combat Packets & Moves Tracking to Content (#298)
- [X] Changes outgoing combat packets
- [X] Moves quest arrow to PlayerMobile and moves quest arrow packets to content.

Bumps release version
2020-11-01 21:33:01 -08:00
Kamron Batman
daf48ebdf2
Splits up mobile (#296) 2020-10-31 23:30:51 -07:00
Kamron Batman
a8d486a969
Rearranges packet code (#295) 2020-10-30 22:49:00 -07:00
Kamron Batman
13e2693b59
Cleans up comments for localization (#260) 2020-09-20 12:48:10 -07:00
Kamron Batman
fd9ec089f7
Fixes BuffIcon is NPE (#259)
- [X] Fixes BuffIconTable accessed while null
2020-09-19 15:56:22 -07:00
Kamron Batman
e9c1e4cbba
Fixes dupe exception (#258)
- [X] Cleans up ActivatorUtil
- [X] Fixes dupe exception
- [X] Fixes a bug in BasePotion
- [X] Fixes a few possible memory leaks

Bumps release version
2020-09-19 15:46:07 -07:00
Kamron Batman
a236617ad9
Some cleanup of contains keys and try get values (#246) 2020-09-13 20:20:44 -07:00
Kamron Batman
741e8d8300
Cleanup/Housekeeping (#242) 2020-09-12 15:31:21 -07:00
Kamron Batman
ad3775c4d7
Formats UO Content (#201) 2020-08-27 18:30:38 -07:00
Kamron Batman
1f651992d7
Updates formatting rules (#199) 2020-08-25 18:00:51 -07:00
Kamron Batman
b476bcfd24
Fixes for Last Moved (#194) 2020-08-16 06:58:16 -07:00
Kamron Batman
38568fb5e7
Fixes unequip macro crash (#190) 2020-08-10 20:58:17 -07:00
Kamron Batman
010fd9402a
Code cleanup (#188) 2020-08-01 08:40:06 -07:00
Kamron Batman
24b1a579f4
Creates more tests for outgoing packets (#165) 2020-06-26 12:04:29 -07:00
Kamron Batman
390f30e706
Convert Regions/Spawns to JSON (#138) 2020-05-26 00:34:29 -07:00
Kamron Batman
8ec166bcd0
Adds assemblies config, fixes crash bugs. (#134) 2020-05-09 12:55:56 -07:00
Renamed from Projects/Scripts/Mobiles/PlayerMobile.cs (Browse further)