Skip to content

Conversation

@Manu585
Copy link
Contributor

@Manu585 Manu585 commented Jul 14, 2025

GUI Framework & Code Modernization

📖 Summary

This PR introduces a brand-new, lightweight GUI framework (no external GUI libraries) and modernizes large swaths of the codebase to leverage recent Java features and cleaner dependency injection.

🆕 New GUI Framework

  • InventoryUI API

    • Single interface with default handleClick(…) and onClose(…)
    • Implemented by BasicInventoryUI
  • Fluent Builder

    • InventoryUIBuilder with
      • withItem(x,y,item) for non-clickable slots
      • withButton(x,y,item,handler) for clickable slots
    • getWidth() / getHeight() helpers replace magic numbers
  • Lifecycle Service

    • InventoryService tracks “which player has which UI open”
    • Auto-closes old GUIs, fires onClose callbacks, and closeAll() on shutdown
  • Event Routing

    • InventoryEventListener listens for Bukkit click/close events
    • Only cancels & dispatches clicks for our UIs (no global interference)

📋 How to Define & Use a Menu

  1. Implement the Menu interface by providing a single buildUI(Player) method:

    public class MainMenu implements Menu {
        private static final int ROWS = 3;
    
        @Override
        public InventoryUI buildUI(Player player) {
            ItemStack fillerPane = ItemUtil.create(Material.GRAY_STAINED_GLASS_PANE, " ");
            ItemStack openSkillIcon = ItemUtil.create(Material.NETHER_STAR, "&bSkillTree");
    
            // Build and return menu
            return InventoryUIBuilder.create(ROWS, "&1Main Menu")
                .withItem(0, 0, fillerPane)
                .withButton(4, 1, openSkillIcon, click -> new SkillTreeMenu().open(player))
                .build();
        }
    }
  2. Open the menu anywhere you have a Player:

    Menu mainMenu = new MainMenu();
    mainMenu.open(player);
  3. Inside a command:

    public class LevelCommand extends RPGCommand {
        private final Menu mainMenu = new MainMenu();
    
        public LevelCommand() {
            super("level", "/bending level", "Opens the leveling menu", new String[]{"level", "l", "le"});
        }
    
        @Override
        public void execute(CommandSender sender, List<String> args) {
            if (!(sender instanceof Player p)) {
                sender.sendMessage("Only players may run this command.");
                return;
            }
            if (args.isEmpty()) {
                mainMenu.open(p);
            } else {
                help(sender, true);
            }
        }
    }

Why this pattern?

  • No service or player in constructors menus remain pure builders
  • Dynamic data each open(player) rebuilds with fresh stats, XP, permissions, etc.
  • Clear navigation buttons simply call new OtherMenu().open(player)

🔄 Code Modernization

  • Dropped I-prefixes on interfaces
  • Replaced marker interfaces with default methods
  • Switched to Map.copyOf(...) for defensive immutability
  • Embraced Java records for simple data carriers (Slot)
  • ItemUtil for DRY item creation
  • Improved Dependency Injection
  • Many "Legacy" Java features replaced with streams and lambda expressions

@CrashCringle12
Copy link
Contributor

I talked to Manu about this in discord but saying in the git thread as well. This PR should have its commits cleaned up before merging because there are a lot of repeat commits in here and many spots where things should be squashed so the git history doesn't become messy or hard to read.

Otherwise if this gets merged it should just get squashed into 1 commit but I think given the number of changes here...for tracking purposes this should just get cleaned up so we arent getting 82 commits in upstream of varying redundancy. Cleaning this up will help people in the future so they are able to follow where certain changes were made (if something needs reverted we could easily locate the commit or two of origin as opposed to it being scattered over 20). Going to try to meet with Manu to help them with this.

@CrashCringle12
Copy link
Contributor

CrashCringle12 commented Jul 21, 2025

I think ideally in the future these changes should be split into multiple PRs as I feel this PR contains a lot. The implementation of the GUI Framework could be 1 PR and the "Code Modernization" I think should have been separate. These in a way are two different featuresets and the modernization in particular involves modifying a lot of files so it's not super clean to track which changes were part of which featureset from a git pov. It's also two different topics to discuss, which I think warrants having 2 different PRs for things like this in the future. We can discuss the framework in 1 thread and the "modernization" efforts in another one. It's not super pressing I think for this but in theory if there was a lot of discussion happening in the PRs it could be messy in the future so figured it was a thought worth sharing. Also if the leveling stuff is being introduced here that might also be worth a diff PR as well.

@CrashCringle12
Copy link
Contributor

CrashCringle12 commented Jul 21, 2025

Can we rebase this branch on the latest in master? Just to get rid of the chunk of commits coming from d61be67

I also see there are a couple duplicate commits in here like 632284c and ac05736. I think we should try to avoid this happening and if worst case scenario it does we squash that into 1 commit. I know that functionally all your changes will get in all the same, but from a git standpoint it's really good practice to clean those up and try to keep a concise tree when you can. I think it's still good practice cause it keeps this repo clean and ensures accuracy when it comes to tracking changes and metrics in general. We should treat upstream master as the "prod" environment so to speak so if we can i think we should try to keep that clean.

Ik either which way this will get squashed into 1 commit there to keep it clean but it's still important cause when that happens it becomes a little more difficult to track when certain changes happened. So ideally it doesn't have to be and we can cleanly follow the tree. (ik you've have in the past already) I'd definitely recommend asking in #git-support if you encounter issues cleaning up your branch or see weird things like duplicate commits. Just so this can get sorted out earlier.

Anyways all in all I think the changes themselves that are happening are great and exciting stuffs. Mainly write all this just to help out so they can be even better haha.

@Manu585
Copy link
Contributor Author

Manu585 commented Jul 26, 2025

I think commit history should now be cleaner and PR should be mergeable, if @CrashCringle12 thinks so too

@CrashCringle12
Copy link
Contributor

@Manu585 thanks for handling that yeah this is MUCH better haha. The last thing is just checking out my reviews on some of the changes, you can comment on each one and mark it as resolved after you've made the suggested change or if whatever I proposed doesn't work/make sense.

It'll also automatically mark my reviews as Outdated if you've made a change related to the highlighted code before you resolve it.

Manu585 added 5 commits July 28, 2025 22:20
…ed` interface for WorldEvents. Introduced new Display interface `ITickingDisplay`, removed redundant WorldEventBossBar since we switch to wrapping the KeyedBossBar into the Display
…player quit / world changes for BossBar display in WorldEvents
WorldEvent class now only is State
Introduced WorldEventManager to handle CRUD and State
Removed past Schedule, needs to be re-done in a better way
Moved classes into different packages for better overlook
Introduced `AttributeRules` and `ScheduleParser` Objects to not use `FileConfiguration` in `WorldEvent` Object
Handled world changes, server quits / joins for BossBar displays (ViewerDisplay)
Re-did Attribute Ruleset and Modification Services
Manu585 added 15 commits August 13, 2025 14:33
…stop.

Fixed passive attribute recalculations
Removed WorldEventRuntime and created ActiveWorldEvent Object
ActiveWorldEvents are being ticked by the newly introduced WorldEventService
Introduced WorldEventRegistry and ActiveWorldEventIndex for storing and retrieving  WorldEvents and ActiveWorldEvents
Some GPT generated content included (toString() Debugging, Parts of Service)
Remove ViewerDisplay and TickingDisplay to introduce new IBossBarDisplay
Introduced ChatDisplay, not yet in use but will be from benefit when players freshly join WorldEvent world with active event running without BossBar
Got rid of universal WorldEventDisplay and introduced interfaces for each possible display method to get rid of unnecessary iterations and instanceof calls and for a more structured approach
implemented new interfaces
updated WorldEventLoader and Builder to provide new interfaces
ActiveWorldEvent now works with each interface instance
Added some more docs
Unregistered ActiveEventIndex
Optimized stream usages
Optimized interface implementation methods
Nullable annotation for Scheduler added
Removed useless debugging
Optimized imports
Players now receive a message when they join a world with an ActiveWorldEvent
New arg 'edit' in WorldEventCommand. In future updates admins will be able to modify attributes with a built-in GUI (idea: cozymc) this is just the basis
Removed recalcPassives Method since it's redundant
Applied changes from CrashCringle's review.
Optimized imports
Optimized comments
Removed redundant ticking calls in Service
OG Avatar Cycle re-implemented
@Manu585 Manu585 changed the title GUI Framework & Code Modernization Reworked WorldEvents, implemented GUI Framework & Code Modernizations Aug 31, 2025
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.

3 participants