Kamron Batman
8d88ef70fd
fix: Eliminates double lookup with Contains->Remove ( #2539 )
2026-07-19 09:26:27 -07:00
Kamron Batman
e1e1a7c640
fix: Bumps deps. Updates copyrights ( #2353 )
2026-03-05 19:36:54 -08:00
Kamron Batman
b191498569
feat: Adds Feature Flag System ( #2328 )
...
## Feature Flag System
A runtime feature flag system for dynamically enabling/disabling game systems and blocking specific game elements
without server restarts.
### Overview
Two types of controls:
1. Feature Flags - Named boolean flags that gate entire systems (trading, PvP, vendors, housing, etc.)
2. Dynamic Blocks - Block specific gumps, items, skills, or spells by type
All changes are persisted to JSON, broadcast to online staff, and bypass-able by administrators.
### Predefined Flags
```
┌─────────────────┬──────────┬─────────────────────────────────────┐
│ Flag │ Category │ Description │
├─────────────────┼──────────┼─────────────────────────────────────┤
│ player_trading │ Economy │ Allow secure trades between players │
├─────────────────┼──────────┼─────────────────────────────────────┤
│ vendor_purchase │ Economy │ Allow purchasing from NPC vendors │
├─────────────────┼──────────┼─────────────────────────────────────┤
│ vendor_sell │ Economy │ Allow selling to NPC vendors │
├─────────────────┼──────────┼─────────────────────────────────────┤
│ player_vendors │ Economy │ Allow player vendor interactions │
├─────────────────┼──────────┼─────────────────────────────────────┤
│ bank_access │ Economy │ Allow bank box access │
├─────────────────┼──────────┼─────────────────────────────────────┤
│ house_placement │ Housing │ Allow new house placements │
├─────────────────┼──────────┼─────────────────────────────────────┤
│ boat_placement │ Housing │ Allow new boat placements │
├─────────────────┼──────────┼─────────────────────────────────────┤
│ bulk_orders │ Crafting │ Allow bulk order deeds │
├─────────────────┼──────────┼─────────────────────────────────────┤
│ pvp_combat │ Combat │ Allow player vs player combat │
└─────────────────┴──────────┴─────────────────────────────────────┘
```
### Commands
#### Feature Flags
```
┌────────────────────────────────────────────────────┬───────────────────────┐
│ Command │ Description │
├────────────────────────────────────────────────────┼───────────────────────┤
│ [FeatureFlag <key> on|off|toggle|info │ Manage a feature flag │
├────────────────────────────────────────────────────┼───────────────────────┤
│ [FF <key> on|off │ Shorthand alias │
├────────────────────────────────────────────────────┼───────────────────────┤
│ [FeatureFlag <key> create <category> <desc> │ Create a custom flag │
├────────────────────────────────────────────────────┼───────────────────────┤
│ [FeatureFlag <key> delete │ Delete a custom flag │
├────────────────────────────────────────────────────┼───────────────────────┤
│ [FeatureList [flags|gumps|items|skills|spells|all] │ List all flags/blocks │
├────────────────────────────────────────────────────┼───────────────────────┤
│ [FeatureAdmin │ Open the admin gump │
└────────────────────────────────────────────────────┴───────────────────────┘
```
#### Gump Blocks
```
┌────────────────────────────────┬──────────────────────────────────────────────────────┐
│ Command │ Description │
├────────────────────────────────┼──────────────────────────────────────────────────────┤
│ [BlockGump <typeName> [reason] │ Block a gump type from displaying │
├────────────────────────────────┼──────────────────────────────────────────────────────┤
│ [UnblockGump <typeName> │ Remove a gump block │
├────────────────────────────────┼──────────────────────────────────────────────────────┤
│ [ListGumps [self] │ List open gumps on a player (for finding type names) │
└────────────────────────────────┴──────────────────────────────────────────────────────┘
```
#### Item Blocks
```
┌────────────────────────────────────────────────┬───────────────────────────────┐
│ Command │ Description │
├────────────────────────────────────────────────┼───────────────────────────────┤
│ [BlockItemUse <typeName|target> [reason] │ Block item use │
├────────────────────────────────────────────────┼───────────────────────────────┤
│ [BlockItemEquip <typeName|target> [reason] │ Block item equipping │
├────────────────────────────────────────────────┼───────────────────────────────┤
│ [BlockItemContainer <typeName|target> [reason] │ Block container access │
├────────────────────────────────────────────────┼───────────────────────────────┤
│ [UnblockItemUse <typeName> │ Remove use block │
├────────────────────────────────────────────────┼───────────────────────────────┤
│ [UnblockItemEquip <typeName> │ Remove equip block │
├────────────────────────────────────────────────┼───────────────────────────────┤
│ [UnblockItemContainer <typeName> │ Remove container access block │
└────────────────────────────────────────────────┴───────────────────────────────┘
```
Item block commands create an entry if one doesn't exist, or flip the relevant flag on an existing entry. Unblock
commands only clear their specific flag -- the entry is removed when all flags (use/equip/container) are off.
#### Skill & Spell Blocks
```
┌──────────────────────────────────────┬──────────────────────┐
│ Command │ Description │
├──────────────────────────────────────┼──────────────────────┤
│ [BlockSkill <SkillName> [reason] │ Block a skill │
├──────────────────────────────────────┼──────────────────────┤
│ [UnblockSkill <SkillName> │ Remove a skill block │
├──────────────────────────────────────┼──────────────────────┤
│ [BlockSpell <SpellTypeName> [reason] │ Block a spell │
├──────────────────────────────────────┼──────────────────────┤
│ [UnblockSpell <SpellTypeName> │ Remove a spell block │
└──────────────────────────────────────┴──────────────────────┘
```
### Architecture
- Static bool classes for hot-path checks (no dictionary lookups): ServerFeatureFlags (Server project) and
ContentFeatureFlags (UOContent)
- Synced automatically by FeatureFlagManager.SyncStaticFlag() when flags change
- Predefined flags loaded from Distribution/Configuration/FeatureFlags/default-flags.json
- Runtime state persisted to Configuration/FeatureFlags/*.json (flags, gump-blocks, item-blocks, skill-blocks,
spell-blocks)
- Admin gump with tabbed UI for managing all block types, per-entry PropertiesGump editing, and pagination
- All staff at AccessLevel.GameMaster+ bypass dynamic blocks; AccessLevel.Administrator+ bypass feature flags
### Hook Points
Hook: Player trading
Location: Mobile.OpenTrade
Mechanism: ServerFeatureFlags.PlayerTrading
────────────────────────────────────────
Hook: PvP combat
Location: Mobile.CanBeHarmful
Mechanism: ServerFeatureFlags.PvPCombat
────────────────────────────────────────
Hook: Bank access
Location: BankBox.Open()
Mechanism: ServerFeatureFlags.BankAccess
────────────────────────────────────────
Hook: Vendor buy/sell
Location: BaseVendor
Mechanism: ContentFeatureFlags.VendorPurchase/Sell
────────────────────────────────────────
Hook: Player vendors
Location: PlayerVendor
Mechanism: ContentFeatureFlags.PlayerVendors
────────────────────────────────────────
Hook: House placement
Location: HousePlacement.Check()
Mechanism: ContentFeatureFlags.HousePlacement (returns BadRegionTemp)
────────────────────────────────────────
Hook: Boat placement
Location: BaseBoatDeed.OnDoubleClick/OnPlacement
Mechanism: ContentFeatureFlags.BoatPlacement
────────────────────────────────────────
Hook: Bulk orders
Location: SmallBOD/LargeBOD
Mechanism: ContentFeatureFlags.BulkOrders
────────────────────────────────────────
Hook: Gump display
Location: GumpSystem.SendGump
Mechanism: FeatureFlagManager.IsGumpBlocked
────────────────────────────────────────
Hook: Item use
Location: PlayerMobile.AllowItemUse
Mechanism: FeatureFlagManager.IsItemUseBlocked
────────────────────────────────────────
Hook: Item equip
Location: PlayerMobile.CheckEquip
Mechanism: FeatureFlagManager.IsItemEquipBlocked
────────────────────────────────────────
Hook: Container access
Location: BaseContainer.DisplayTo
Mechanism: FeatureFlagManager.IsContainerAccessBlocked
────────────────────────────────────────
Hook: Skill use
Location: PlayerMobile.AllowSkillUse
Mechanism: FeatureFlagManager.IsSkillBlocked
────────────────────────────────────────
Hook: Spell casting
Location: Spell.Cast / Spellbook.CastSpellRequest
Mechanism: FeatureFlagManager.IsSpellBlocked
2026-02-07 12:02:57 -08:00
Kamron Batman
0404251638
feat: Adds Latin1 text support ( #2317 )
...
## Summary
- Adds proper Latin1 encoding support, replacing CP1252 usage throughout the codebase
- Adds specialized, optimized string decoding methods with safe string filtering for each encoding type
- Filters invalid Unicode characters (C0/C1 control codes, non-characters) by removal rather than replacement since
the UO client renders nothing for these characters
- Fixes UTF-16 null terminator position handling to correctly advance by 2 bytes
## Changes
TextEncoding.cs
- Added SearchValues-based invalid byte/char detection for efficient filtering
- Added encoding-specific GetString methods: GetStringAscii, GetStringLatin1, GetStringUtf8, GetStringBigUni,
GetStringLittleUni
- Each method supports a safeString parameter for filtering invalid characters
- Little-endian UTF-16 uses direct memory cast for zero-copy decoding on LE systems
- Invalid characters are removed (not replaced with U+FFFD) since the client renders nothing for them
SpanReader.cs
- Added ReadLatin1() and ReadLatin1Safe() methods
- Rewrote encoding-specific read methods to use optimized TextEncoding.GetString* methods
- Fixed UTF-16 null terminator handling: position now correctly advances by byteLength (2) instead of 1
SpanWriter.cs
- Added WriteLatin1 and WriteLatin1Null methods
## Packet Updates
- Updated all packet code to use Latin1 encoding instead of CP1252
- Affected: account packets, equipment packets, menu packets, message packets, mobile packets, player packets, secure
trade packets, vendor packets, gump packets, book packets, mahjong packets
## Filtering Behavior
Invalid characters filtered in safe mode:
```
┌───────────────┬────────────────────────┐
│ Range │ Description │
├───────────────┼────────────────────────┤
│ 0x00-0x1F │ C0 control codes │
├───────────────┼────────────────────────┤
│ 0x7F │ DEL │
├───────────────┼────────────────────────┤
│ 0x80-0x9F │ C1 control codes │
├───────────────┼────────────────────────┤
│ 0xFFFE-0xFFFF │ Unicode non-characters │
└───────────────┴────────────────────────┘
```
Note: Surrogate pairs (0xD800-0xDFFF) are not filtered because proper validation requires context checking for paired
vs unpaired surrogates. The UO client renders nothing for these anyway.
## Test Plan
- All 631 Server.Tests pass
- Verified client rendering behavior using TestUnicodeGump command (pages 1-5)
- Confirmed U+FFFD, unpaired surrogates, and non-characters all render as blank in client
- Verified Latin1 characters (0xA0-0xFF) display correctly
- Verified C1 control codes (0x80-0x9F) are filtered and don't display
2026-01-22 15:51:00 -08:00
Kamron Batman
bc6735bd23
feat: Adds grid support for the DynamicGump system ( #2306 )
...
### Summary
- Adds a new grid layout system for DynamicGump with zero heap allocations
- Migrates SpawnerControllerGump from legacy GumpGrid to DynamicGump
- Migrates CommandListGump from BaseGridGump to DynamicGump
- Removes legacy GumpGrid (no longer needed)
### New Grid Layout Components
| Component | Purpose |
|-----------|---------|
| `GridCell` | Value type for cell bounds (x, y, width, height) |
| `GridSizeSpec` | Parses CSS-like sizing specs ("10*", "*", "100") |
| `GridCalculator` | Computes track positions using stackalloc |
| `ListViewLayout` | Pagination + column layout for list views |
| `GridBuilderExtensions` | Extension methods accepting `GridCell` |
| `GridEntryStyle` | Styling properties for BaseGridGump migration |
| `GridEntryExtensions` | Entry methods matching BaseGridGump patterns |
### Memory Impact
| Component | Legacy | New |
|-----------|--------|-----|
| Grid storage | ~200 bytes heap | 0 bytes (stackalloc) |
| Column/Row lists | ~400 bytes heap | ~128 bytes stack |
| ListView | ~300 bytes heap | ~64 bytes stack |
| **Total per render** | **~900 bytes heap** | **0 bytes heap** |
### Test plan
- [x] All 21 gump tests pass
- [x] Build succeeds with no warnings
- [ ] In-game verification of SpawnerControllerGump
- [ ] In-game verification of CommandListGump (HelpInfo command)
2026-01-03 10:12:22 -08:00
Kamron Batman
ebaf104935
chore: Use var everywhere ( #2294 )
2025-12-27 16:47:28 -08:00
Kamron Batman
7bd5a853a3
feat: Adds size/style support to gump builders, optimizes EscapeHtml ( #2257 )
...
> [!IMPORTANT]
> **Developer Note**
> THIS IS A BREAKING CHANGE TO THE NEW API GUMP.
> Please give us feedback in [discord ](https://muo.gg/discord ) if you have issues, need help, or have ideas for a better API change!
### Summary
* Adds support for size/style to dynamic/static builder.
* Drastically simplifies the dynamic/static builder api for AddHtml.
* Cleans up some legacy gump files.
2025-11-23 11:35:31 -08:00
Kamron Batman
90059c5e74
feat: Adds convenience methods to GumpStringsBuilder ( #2124 )
2025-02-13 19:58:46 -08:00
Kamron Batman
6d7b1b8bee
fix: Adds missing string interpolation handler for SetStringSlot ( #2123 )
2025-02-13 19:30:47 -08:00
Kamron Batman
899146dcb7
fix: Fixes static gumps sending too much data. ( #2122 )
2025-02-13 19:12:28 -08:00
Kamron Batman
3cf1bd0f7d
fix: Fixes AddLabelPlaceholder on StaticGump ( #2121 )
2025-02-13 18:53:24 -08:00
Kamron Batman
2d0957119e
feat: Adds BaseGump.GetGumpOffsetForItemGraphic ( #2116 )
2025-02-10 19:53:47 -08:00
Kamron Batman
40479c946a
feat: Adds item graphic size to Bounds.bin and makes item graphic offset available to gumps ( #2115 )
2025-02-10 19:31:39 -08:00
Kamron Batman
2e6ddcd31a
fix: Removes profiling. Streamlines core tick count. ( #1948 )
...
### Summary
- Removes `Profiling` - Recommend using Visual Studio Performance Profiler, [dotnet-trace](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-trace ) or [JetBrains dotTrace](https://www.jetbrains.com/profiler/ )
- Cleans up the core tick count, sampling, etc.
2024-09-11 00:55:18 -07:00
Stefano Merotta
aa68d96807
fix: Removes redundant code in GumpSystem ( #1921 )
2024-08-10 10:20:34 -07:00
Stefano Merotta
6fe01488ef
fix: Fix NetStateGumps and other Gumps cleanup ( #1919 )
2024-08-10 09:57:28 -07:00
Kamron Batman
8282b00ca2
feat: Moves gumps out of the core ( #1916 )
...
> [!Important]
> **Developer Note**
> This code change will **completely move gumps out of the core**
### Summary
- Adds `GetGumps()` convenience which exposes methods to Find/Close/Send multiple gumps. This helper is a performance improvement by eliminating the Dictionary<Player, List> lookup for gumps.
2024-08-09 19:07:32 -07:00