Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Adds optimized dynamic/static layout gumps #1652

Merged
merged 7 commits into from
Apr 26, 2024
Merged

Conversation

kamronbatman
Copy link
Contributor

@kamronbatman kamronbatman commented Dec 30, 2023

Important

In the future, gumps that come with ModernUO will be converted to this new API where it makes sense. Please reach out in discord if you have questions or need help!

Note

DEVELOPER NOTE
We will not deprecate the legacy (RunUO) gump API. If you want to continue to use it, go for it!

New Gump API

We are pleased to release a new API that is faster, allocates nearly zero memory, and still feels very similar to the original API. The API is broken into 3 types of gumps, dynamic, static with placeholders, and static without placeholders.

Dynamic Gumps

These gumps will inherit DynamicGump and are meant for gumps that have a dynamic layout. This includes specifying dynamic arguments to HtmlLocalized entries.

Example
public class PetResurrectGump : DynamicGump
{
  private readonly string _petName;

  public PetResurrectGump(string petName) : base(50, 50)
  {
      from.CloseGump<PetResurrectGump>();

      _petName = petName;
  }

  protected override void BuildLayout(ref DynamicGumpBuilder builder)
  {
      builder.AddPage();

      builder.AddBackground(10, 10, 265, 140, 0x242C);

      builder.AddItem(205, 40, 0x4);
      builder.AddItem(227, 40, 0x5);

      builder.AddItem(180, 78, 0xCAE);
      builder.AddItem(195, 90, 0xCAD);
      builder.AddItem(218, 95, 0xCB0);

      // <div align=center>Wilt thou sanctify the resurrection of:</div>
      builder.AddHtmlLocalized(30, 30, 150, 75, 1049665);
      builder.AddHtml(30, 70, 150, 25, _petName, true);

      builder.AddButton(40, 105, 0x81A, 0x81B, 0x1);  // Okay
      builder.AddButton(110, 105, 0x819, 0x818, 0x2); // Cancel
  }

  public override void OnResponse(NetState state, in RelayInfo info)
  {
      // Normal on response code that all gumps have.
  }
}

Static Gumps

Static gumps are those where the function to the build the layout is called only once and cached forever. They can optionally have placeholders. These placeholders allow the developer to specify the string values later, dynamically in a BuildStrings method on the gump. If a gump does not have any placeholders, the string entries will also be cached forever.

Example
public class PetResurrectGump : StaticGump<PetResurrectGump>
{
  private readonly string _petName;

  public PetResurrectGump(string petName) : base(50, 50)
  {
      from.CloseGump<PetResurrectGump>();

      _petName = petName;
  }

  protected override void BuildLayout(ref StaticGumpBuilder builder)
  {
      builder.AddPage();

      builder.AddBackground(10, 10, 265, 140, 0x242C);

      builder.AddItem(205, 40, 0x4);
      builder.AddItem(227, 40, 0x5);

      builder.AddItem(180, 78, 0xCAE);
      builder.AddItem(195, 90, 0xCAD);
      builder.AddItem(218, 95, 0xCB0);

      // <div align=center>Wilt thou sanctify the resurrection of:</div>
      builder.AddHtmlLocalized(30, 30, 150, 75, 1049665);
      builder.AddHtmlPlaceholder(30, 70, 150, 25, "petName", true);

      builder.AddButton(40, 105, 0x81A, 0x81B, 0x1);  // Okay
      builder.AddButton(110, 105, 0x819, 0x818, 0x2); // Cancel
  }

  protected override void BuildStrings(ref GumpStringsBuilder builder)
  {
      builder.SetStringSlot("petName", $"<CENTER>{_pet.Name}</CENTER>");
  }

  public override void OnResponse(NetState state, in RelayInfo info)
  {
      // Normal on response code that all gumps have.
  }
}

Benchmarks

To make sure we were going in the right direction and not wasting time, we took copious benchmarks. Here are the final benchmarks for a really simple gump.

Note:

  • The majority of creating a gump is compressing the layout and the strings. Compressing each section takes ~6,000ns (12us total).
| Method                         | Mean         | Error        | StdDev       | Median       | Ratio | RatioSD | Gen0   | Allocated | Alloc Ratio |
|------------------------------- |-------------:|-------------:|-------------:|-------------:|------:|--------:|-------:|----------:|------------:|
| OldGump                        | 13,308.29 ns | 1,059.695 ns | 1,883.608 ns | 14,330.72 ns | 1.000 |    0.00 | 0.1526 |    2400 B |        1.00 |
| DynamicLayoutGump              | 13,357.86 ns |   129.144 ns |   226.185 ns | 13,323.60 ns | 1.029 |    0.17 |      - |      48 B |        0.02 |
| StaticLayoutDynamicStringsGump |  6,653.10 ns |    81.815 ns |   143.292 ns |  6,617.45 ns | 0.514 |    0.09 |      - |      40 B |        0.02 |
| StaticLayoutGump               |     86.33 ns |     0.760 ns |     1.350 ns |     86.07 ns | 0.007 |    0.00 | 0.0020 |      32 B |        0.01 |

Non-Breaking Changes

  • All gump components in the core have been moved to Gumps/Legacy.
  • All legacy gumps will still inherit Gump, which now inherits BaseGump

Special Thanks

Thank you to @stefanomerotta for considerable contributions/benchmarking/testing to make this effort a reality! We collectively went through over 10 iterations, but it is finally ready.

Closes #1640

@kamronbatman kamronbatman linked an issue Dec 30, 2023 that may be closed by this pull request
@kamronbatman kamronbatman changed the title feat,: Optimized Static Gumps feat: Optimized Static Gumps Dec 30, 2023
@stefanomerotta
Copy link
Contributor

@kamronbatman I've just refactor the StaticGump as discussed yesterday.
I also removed the DynamicStringPlaceholder and added a bunch of extension methods for dynamic string placeholder (they have the suffix "Slot" in the name)

The converted static gump with dynamic strings is "PetResurrectGump"

@kamronbatman kamronbatman force-pushed the smerotta/new-gumps branch 3 times, most recently from a70cd06 to 5fa464d Compare March 8, 2024 05:14
@kamronbatman
Copy link
Contributor Author

Before we can merge this, I think we can simplify the concepts. Our goal is:

  1. Static Layout, Static Strings
  2. Static Layout, Dynamic Strings

The first with static strings can use a dynamic strings builder, but also cache the strings themselves.
The difficult part will be creating a way to specify the strings for an index, I think we decided to use a Dictionary<int, int>.

@kamronbatman kamronbatman force-pushed the smerotta/new-gumps branch 2 times, most recently from d929875 to 2668a7c Compare April 14, 2024 18:13
@kamronbatman kamronbatman marked this pull request as draft April 16, 2024 02:31
@kamronbatman kamronbatman force-pushed the smerotta/new-gumps branch 11 times, most recently from 6b7be72 to e940b09 Compare April 24, 2024 23:58
@kamronbatman kamronbatman force-pushed the smerotta/new-gumps branch 2 times, most recently from a9b4d87 to 38f10d1 Compare April 25, 2024 06:59
@kamronbatman kamronbatman changed the title feat: Optimized Static Gumps feat: Adds optimized dynamic/static layout gumps Apr 25, 2024
@kamronbatman kamronbatman marked this pull request as ready for review April 25, 2024 07:31
@modernuo modernuo deleted a comment from stefanomerotta Apr 26, 2024
@modernuo modernuo deleted a comment from stefanomerotta Apr 26, 2024
@modernuo modernuo deleted a comment from stefanomerotta Apr 26, 2024
@modernuo modernuo deleted a comment from stefanomerotta Apr 26, 2024
@modernuo modernuo deleted a comment from stefanomerotta Apr 26, 2024
@modernuo modernuo deleted a comment from stefanomerotta Apr 26, 2024
@modernuo modernuo deleted a comment from stefanomerotta Apr 26, 2024
@modernuo modernuo deleted a comment from stefanomerotta Apr 26, 2024
@modernuo modernuo deleted a comment from stefanomerotta Apr 26, 2024
@modernuo modernuo deleted a comment from stefanomerotta Apr 26, 2024
@kamronbatman kamronbatman merged commit 65532ea into main Apr 26, 2024
13 checks passed
@kamronbatman kamronbatman deleted the smerotta/new-gumps branch April 26, 2024 05:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Gump refactor for caching and functional generation
2 participants