New Years post

Happy New Year from PaperMC!​

Wishing you all a super happy New Year!
It's been a big year at Paper! We've grown a lot and have some big changes on the horizon. Our team has yet again increased in size and become even more motivated to work towards our goal of hard forking. PaperMC is powered by the contributions from everyone, and we have made it our priority that new contributions are getting out there as soon as possible. And through that, we have seen some new faces pop up and contribute more often.

This year, we merged over 475 Pull Requests from over 120 unique contributors!
Going through each one of these PRs wouldn't be possible without you, so we are so grateful for all the bugs reported, testing done, and all the new contributors who decided to give it a shot.

This year was a big team effort, and we want to thank each and every person who's been a part of it. Your ideas and hard work made PaperMC even better, and we're so excited to keep growing and improving together.

The Future​

The future is bright, we have a lot of work being done behind the scenes that we hope to be able to get out into your hands in 2024.

Lifecycle API​

With our new Paper Plugins introduced this year, we introduced ways of running code much earlier before the server has started.
Using this new Lifecycle API, we will now allow plugins to start running code on an event-based system much earlier in server initialization as well.
    public void onEnable() {
        final LifecycleEventManager<Plugin> lifecycles = this.getLifecycleManager();
        lifecycles.registerEventHandler(LifecycleEvents.DUMMY_STATIC.newHandler(event -> {
            final DummyResourceRegistrar registrar = event.registrar();
            System.out.println("dummy_static hook FIRST");
        lifecycles.registerEventHandler(LifecycleEvents.DUMMY_STATIC.newHandler(event -> {
            final DummyResourceRegistrar registrar = event.registrar();
            System.out.println("dummy_static hook FOURTH (monitor)");
        lifecycles.registerEventHandler(LifecycleEvents.DUMMY_STATIC.newHandler(event -> {
            final DummyResourceRegistrar registrar = event.registrar();
            System.out.println("dummy_static hook THIRD");

See more information here

Brigadier API​

Using the Lifecycle API mentioned above, we will also support command registration through this system through brigadier. This will allow these commands to be usable in things like datapack functions.
This API will also support adding custom serverside arguments and more, allowing a more powerful approach compared to the current Bukkit command API.
CommandBuilder.of(plugin, "admin")
                    RequiredArgumentBuilder.argument("msg", VanillaArguments.signedMessage()).executes((context) -> {
                        MessageArgumentResponse argumentResponse = context.
                        getArgument("msg", MessageArgumentResponse.class); // Gets the raw argument.

                        // This is a better way of getting signed messages,
                        // includes the concept of "disguised" messages.
                        argumentResponse.resolveSignedMessage("msg", context)
                            .thenAccept((signedMsg) -> {
                                Component comp = Component.text("STATIC");
                                            .sendMessage(signedMsg, ChatType.SAY_COMMAND.bind(comp));

                        return 1;
            .description("Cool command showcasing what you can do!")
            .aliases("alias_for_admin_that_you_shouldnt_use", "a")
See more information here

Registry Manipulation API​

We've recently introduced autogenerated API keys in our API, and in general are closing the gap allowing us to properly implement custom type registration.

In this API, we finally allow custom types to be registered and we allow the modification of pre-existing entries, allowing you to safely make modifications to registered vanilla types.

static final TypedKey<GameEvent> NEW_EVENT = GameEventKeys.create(Key.key("machine_maker", "best_event"));

public void bootstrap(@NotNull BootstrapContext context) {
    final LifecycleEventManager<BootstrapContext> lifecycles = context.getLifecycleManager();

    // registers a new handler for the prefreeze event for the game event registry
    lifecycles.registerEventHandler(RegistryEvents.GAME_EVENT.preFreeze().newHandler(event -> {
        // the RegistryView provided here is writable so you can register new objects
        event.registry().register(NEW_EVENT, builder -> {
    // registers a handler for the addition event
    lifecycles.registerEventHandler(RegistryEvents.GAME_EVENT.newAdditionHandler(event -> {
        // checks if the object being registered is the block open game event
        if (event.key().equals(GameEventKeys.BLOCK_OPEN)) {
            // multiplies the range by 2
            event.builder().range(event.builder().range() * 2);
See more information here

Mache and Codebook​

Although not directly related to Paper's API, we also have been hard at work building a stable platform for working on the server in the future. Through Mache and Codebook, we have been able to create a stable way of deobfuscating the game in a way more friendly than before.

More work than ever is being put into our tech for hard forking, and we are excited to be able to work off of some of the best tech developed for deobfuscation.

Here's to a fantastic 2024!​

Last edited by a moderator:
Happy New Year everyone! Cheers to the Paper team for all their hard work in 2023, excited to see what 2024 brings (hopefully some cutlery)!
Thanks to the members of the paper team for their hard work to make plugin development more enjoyable!