Skip to content

[FEATURE] Custom renderer interface for the IMenuAPI #305

Description

@2oaJ

Problem Description

The current SwiftlyS2 menu API provides a complete menu construction and lifecycle model through IMenuManagerAPI / IMenuAPI, but the actual rendering layer appears to be tied to the default CenterHTML implementation.

This makes the menu system difficult to extend when a plugin wants to keep using the framework-managed menu behavior, but render the menu through a different UI surface.

For example, I may want to implement a custom menu renderer using world text instead of CenterHTML. In that case, I still want SwiftlyS2 to manage the core menu responsibilities:

  • Opening and closing menus for players.
  • Tracking the current active menu.
  • Handling menu key input.
  • Managing selection movement and option activation.
  • Handling menu lifecycle callbacks.
  • Supporting parent / child menu navigation.
  • Reusing existing IMenuAPI and IMenuOption data.

However, without a renderer abstraction or takeover point, the only practical option is to reimplement the whole menu system outside the framework. That means duplicating keybind handling, menu state management, lifecycle behavior, and option interaction logic, even though those are already framework-level responsibilities.

A menu system built into the main framework should ideally separate these concerns:

  • Menu state and lifecycle management.
  • Player input handling.
  • Option selection and activation.
  • Default UI rendering.

CenterHTML can remain the default built-in renderer, but plugin authors should be able to replace or extend the rendering layer when they need a different presentation model.

Proposed Solution

public interface IMenuRenderer
{
    void Open(IPlayer player, IMenuAPI menu);
    void Render(IPlayer player, IMenuAPI menu);
    void Close(IPlayer player, IMenuAPI menu);
}

Or alternatively, expose renderer registration through the menu manager:

Core.Menus.RegisterRenderer("worldtext", new WorldTextMenuRenderer());

Then menus could opt into a renderer:

var menu = Core.Menus.CreateBuilder()
    .Design.SetMenuTitle("Custom Menu")
    .SetRenderer("worldtext")
    .Build();

Alternative Solutions

1

Use Case

1

Implementation Ideas

  • The existing CenterHTML menu rendering remains the default behavior.
  • Existing plugins keep working without changes.
  • Custom renderers can take over only the drawing/output layer.
  • The framework still owns menu input, current menu tracking, selection state, close behavior, and callbacks.
  • Renderers can be implemented by plugins using world text, HUD text, entities, or other display mechanisms.

This would make the menu system more extensible without forcing plugin authors to rebuild the entire menu lifecycle from scratch.

Priority

Low

Contribution

  • I'm willing to implement this feature myself
  • I can help with testing
  • I can help with documentation
  • I can provide feedback during development

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions