Files
GeyserWebsite/blog/2021-12-28-1-18-release-and-more.md
T
+16 078446694c Add Crowdin, introduce new provider schema, introduce NetherNet blog post (#51)
* Begin testing i18n

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Add crowdin in-context demo for non-mdx

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Add crowdin-sync system

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Working sync system for translations

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Only build en locale for PRs

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Modify yarn install

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Do not immute cache

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Try with standard yarn install

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Revert to yarn --immutable

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Remove explicit url/file-loader resolutions

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Only log webpack errors

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Added MCServerHost to hosting providers (#47)

* Added MCServerHost to hosting providers

* Update providers.ts

* Correct grammar and make instructions more concise

---------

Co-authored-by: Kas-tle <26531652+Kas-tle@users.noreply.github.com>

* Update supported Bedrock versions

* Remove and Replace "TydiumCraft Skin API" (#53)

* Update community-geyser-projects.md

I no longer will run TydiumCraft Skin API. I have no interest in continuing it at this time (or anything minecraft related). However I have switched out the spot with an API that 100% is always updated and active. Hosted by my good friend Bret06. This works so much better as well. Thanks for everything over the years guys! Tydium out!

* Update wiki/other/community-geyser-projects.md

👍

Co-authored-by: chris <github@onechris.mozmail.com>

---------

Co-authored-by: chris <github@onechris.mozmail.com>

* Update wording for creepernation api

Update wording because it’s bothering me

* Update GeyserExtras description  (#52)

* Update community-geyser-projects.md

* Update wiki/other/community-geyser-projects.md

Co-authored-by: chris <github@onechris.mozmail.com>

---------

Co-authored-by: Luke <32024335+lukeeey@users.noreply.github.com>
Co-authored-by: chris <github@onechris.mozmail.com>

* Try matrix build strategy

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Fix matrix output

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Matrix goes to GITHUB_OUTPUT

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Fix deploy needs to combine

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Ensure correct commit is used if crowdin updates

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Make sure excluded content is respected

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Allow permission for commit action write

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Sync translations with Crowdin

* Update index.md to make clear that this is for servers, not purely for clients (#57)

* Update providers.ts (#58)

* Update providers.ts

VemoxHost added

* Maintain alphabetized list

---------

Co-authored-by: Kas-tle <26531652+Kas-tle@users.noreply.github.com>

* Start on re-writing the providers page to provide more useful details to improve the setup guide

* more work on this

* Rework paper page for setup

* Don't try and build paper setup as a full page

* adjust not listed message

* update mod/proxy pages

* Initial setup i18n

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Add ability to hide proxy setup instructions by provider

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Temporary auto deployment; fix broken links

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Fix heading consistency

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Update language on provider instructions

* Update language on new provider instructions

* Upgrade actions/setup-node due to hang issue

* Both

* Forgot how many times we setup node...

* Documentation for changes in API/2.6.2 (#62)

* Document latest Geyser changes:
- remote resource packs

* Update/Finish pack docs

* small typo fixes

* Update page content

* fix build

* Update supported Bedrock version

* Add Modrinth Servers to providers (#63)

* Update supported versions & api version

* Update versions.json to include 1.21.72 (#64)

* Update bedrock version (#67)

* Add 'we are not mojang' disclaimer to footer

* Stop translations from overriding footer message

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Fix Standalone dump view (#68)

* Add OrionNodes to providers (#69)

* Update supported Bedrock versions in versions.json (1.21.81, 1.21.82) (#70)

* Update faq.mdx to include recommended API (#73)

Tydium skin API is abandoned, please direct users to a working API such as the one recommended by Tydium

Derived from: https://github.com/GeyserMC/GeyserWebsite/commit/19ae50f95ddbfc24ff34a42d278bdc263e0200e6

* Update anticheat-compatibility.md (#74)

* Update versions.json

* Update versions.json (#75)

* Remove LAC because it is no longer being maintained (#76)

* Update versions.json for 1.21.7 (#77)

* Update versions.json for 1.21.93 (#78)

* Update versions.json for 1.21.94 (#79)

* Update versions.json for Java 1.21.8 (#80)

* Update Geyser Api version (#81)

* Readd Hydraulic and add Rainbow, provide Item API V2 warning for Hydraulic (#82)

* Fix incorrect Ubuntu on Oracle Cloud instructions (#84)

* Remove Geyser Android App and Tempest (#83)

* Update version.json for 1.21.100 (#88)

* Update getting-started-with-the-api.md (#89)

* Add and update wiki pages, add Thunder download. (#90)

* Add a Thunder and Rainbow wiki page, touch up some other pages

* Fix mobile sidebar

* Address review 1/2

* Address review 1.5/2 (oops)

* Address review 2/2

Co-authored-by: chris <github@onechris.mozmail.com>

---------

Co-authored-by: chris <github@onechris.mozmail.com>

* Indicate 1.21.101 on the Geyser Website (#93)

* Added GeyserFloatingPoints to FAQ (#92)

* Added GeyserFloatingPoints.

* Update wiki/geyser/faq.mdx

Co-authored-by: chris <github@onechris.mozmail.com>

---------

Co-authored-by: chris <github@onechris.mozmail.com>

* Update versions.json to indicate support for bedrock 1.21.111

* Update versions.json for Java 1.21.9/1.21.10 (#97)

* Update versions.json for Java 1.21.9

* Update versions.json to include 1.21.10

* Update supported Bedrock version

---------

Co-authored-by: Aurorawr <auroranova8756@gmail.com>
Co-authored-by: chris <github@onechris.mozmail.com>

* Update extensions file for new dependency system (#98)

* Update extensions file for new dependency system

* Update version

* Update wiki/geyser/extensions.md

---------

Co-authored-by: chris <github@onechris.mozmail.com>

* Replace the Crowdin link with the current one (#101)

* Replace the Crowdin link with the current one

* Replace the link with the subdomain redirect

* Update versions.json to include 1.21.114 (#102)

* Update rainbow.md to indicate 1.21.9/.10 (#103)

* Revise port forwarding instructions for Ubuntu

Updated instructions for allowing Minecraft and Geyser through the OS firewall on Ubuntu.

* Update providers and deploy action

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Sync translations with Crowdin

* Correct providers syntax

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Use more templates wherever possible

* Add build cache; update docusaurus-og

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Test deploy time with cache hit

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Use read-only cache for matrix build

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Unlikely we will use gh actions on arm...

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* This time cache will hit

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Hopefully correct yarn cache path...

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Maybe npm?

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Surely...

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* This time...

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Include yarn/docusaurus cache for PRs

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Add page IDs to more pages, fix broken pages

* Update i18n pages

* Sync translations with Crowdin

* Add missing support pages and articles on providers, add Discord links

* Add blog post on preparing Geyser servers for NetherNet

Drafted with the help of Claude Opus 5.5.

* Rewrite the hosted setup guide for NetherNet, add hosting page

Provider entries now describe ports, signaling and install steps, grouped
in the order the setup guide shows them. The guide generates the NetherNet
config from them, and the old supported hosting providers list is replaced
by a hosting page for Open Collaboration supporters.

Drafted with the help of Claude Opus 5.5.

* Rewrite the self-hosted setup guides for NetherNet

The self-hosting pages now use the same steps and generated config as the
hosted guide, and point out that the Geyser port needs both TCP and UDP.

Drafted with the help of Claude Opus 5.5.

* Add HTTPS for NetherNet page

Covers serving built-in signaling over HTTPS, with a certificate in the
Geyser config or with a reverse proxy (Caddy, nginx).

Drafted with the help of Claude Opus 5.5.

* Skip Crowdin sync in deploy workflow when no token is set

Forks do not have the Crowdin secrets, so the sync step failed there and
nothing got deployed. Without a token, the workflow now builds and deploys
the pushed commit as is.

Drafted with the help of Claude Opus 5.5.

* Address: rtm's comments

* Improve layout, drop confusing 26.40 note on setup guide

* Cleanup blog post language / line breaks

* Merge proxy server guides for server hosts, adjust exarotron provider entry, adjust setup guides to work with crowdin

* Split the proxy setup guides back into Velocity and BungeeCord

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Update hosting providers to upstream and collapse strings into defaults

Port upstream's provider changes to the new format: add Minehost and
ConsulHosting, update MCServerHost, rename Feather to Dawn and Modrinth
Servers to Modrinth Hosting, merge RamShard into RackGenius, add MyArena,
and drop hosts upstream removed. Restore link fixes the rewrite undid
and install details dropped from the live page.

Replace host-specific strings with templates or the generated steps
where they say the same thing. Hosts that pick the port themselves show
where it comes from instead of the config step.

Hosts without NetherNet details that shared the Java server's port now
ask for a new port, open for both TCP and UDP, and the generated config
turns clone-remote-port off. Hosts that cannot give out a port fall back
to the "Not listed" guide for the Java server's port, which uses Warden.
BisectHosting no longer uses assumed example data. Entries keep the date
of their last edit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Remove Dawn and date Aternos and exaroton today

Dawn now integrates with Aternos, so it no longer needs its own entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Remove unused translation strings and fix the English GeyserConnect text

Drop keys the code no longer uses from every locale: the old EmoteOffhand
description ID, the theme's old unlisted content strings, strings removed
on this branch, and the removed Custom Resource Packs sidebar category.
The English GeyserConnect description had an outdated message that
overrode the current one on the English site.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hide the NetherNet and RakNet option when only the Java port is available

With only the Java server's port there is no second UDP port for RakNet,
so the "Not listed" Java port guide shows the NetherNet config without
transport tabs. Drop the placeholder text that only applied there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Add an HTTPS step to the self-hosted guides and correct external signaling HTTPS claims

Self-hosted guides end with a recommended step to serve signaling over
HTTPS, since Geyser's built-in signaling uses plain HTTP by default and
players get a "Trust on First Use?" prompt. External signaling services
do not all provide HTTPS, so the blog post and HTTPS page now name Warden
as one that does instead of implying all do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Update port forwarding guide, update OVH note

* Sync translations with Crowdin

* Hide entire placeholder strings and correcntly mark chrome json in crowdin

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Update actions and yarn

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Sync translations with Crowdin

* Apply batched suggestions from code review

Co-authored-by: Eclipse <eclipse@eclipseisoffline.xyz>

* Fix NetherNet docs for the final Geyser PR

- Built-in signaling serves HTTPS instead of HTTP once a certificate is configured (blog, system properties)
- "Free port" is now "available port" in the blog
- System properties: drop the removed "none" signaling mode, fix the signaling port default
- playit.gg: note that the guide is for RakNet, and link playit.gg's NetherNet progress

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Build the setup guides from translation strings

The per-platform setup pages are replaced by SetupGuide.tsx, which renders the
hosted and self-hosted guides from shared MDXTranslatable strings, so Crowdin
translates each sentence once instead of every page separately.

Also:
- "Not listed" with only the Java port sets mode: nxs instead of relying on Geyser's fallback
- The playit.gg note links playit.gg's NetherNet progress instead of describing a setup
- "free port" is now "available port"

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Remove the trustedProxies.fetch system property for now

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Fix crowdin sync and don't translate trade names

Signed-off-by: GitHub <noreply@github.com>

* Sync translations with Crowdin

* Fix build

Signed-off-by: GitHub <noreply@github.com>

* Sync translations with Crowdin

* Address more concerns with nethernet https guide

Signed-off-by: GitHub <noreply@github.com>

* Fix signaling-trusted-proxies config in nethernet https article

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>

* Remove port forwarding from the HTTPS guide

Ports are already covered by the setup guide, and HTTPS does not change
which ports need to be opened. Reverse proxies now use
signaling-trusted-proxies, which reads X-Forwarded-For.

* Remove placeholder hosts, hide the hosting page until it launches

- Remove the placeholder hosts and their logos
- Aternos and exaroton are bronze supporters: highlighted with a badge in
  the setup guide, without a "last updated" date, but not listed on the
  hosting page, which only shows gold and silver
- Hide the hosting page and its links for now, and mention in the blog
  post that it is coming soon

* Supporting hosts configure Geyser, they do not install it

* Sync translations with Crowdin

* Move nethernet https guide up on sidebar

* Update to docusaurus 3.10 and fix all type errors

Signed-off-by: GitHub <noreply@github.com>

* HTTP and HTTPS do not both run at once

* Link win-acme's and nginx's own Windows guides in the HTTPS guide

* Fix crowdin key exclusion logic

Signed-off-by: GitHub <noreply@github.com>

* Sync translations with Crowdin

* Address reviews, clear up instructions for users. Adds info on haproxy, NXS and MOTD forwarding

* Note certificate permissions and where to save the Caddyfile

* Sync translations with Crowdin

* Document the geyser nethernet command

* Sync translations with Crowdin

* Support directly linking to the "not listed" or a specific hosts' guide

* Mention warden supporting custom domains

* Add HOSTING_PROVIDERS.md, update existing server host setup entries to reduce translation strings used

* Sync translations with Crowdin

---------

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: Yara Durand <87721861+Roolps@users.noreply.github.com>
Co-authored-by: chris <github@onechris.mozmail.com>
Co-authored-by: Tydium <67938521+Tydium@users.noreply.github.com>
Co-authored-by: Creeperz653 <76449952+Creeperz653@users.noreply.github.com>
Co-authored-by: LetsGoAway <68365423+letsgoawaydev@users.noreply.github.com>
Co-authored-by: Luke <32024335+lukeeey@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Dan <20766261+D4n2021@users.noreply.github.com>
Co-authored-by: santevemox <57247088+santevemox@users.noreply.github.com>
Co-authored-by: rtm516 <ryantmilner@hotmail.co.uk>
Co-authored-by: Emma Alexia <wafflecoffee7@gmail.com>
Co-authored-by: Alex <zomka@fard.ing>
Co-authored-by: Aurorawr <100384210+Novampr@users.noreply.github.com>
Co-authored-by: Jens Collaert <63231928+Jens-Co@users.noreply.github.com>
Co-authored-by: OrionNodes <ethan@orionnodes.com>
Co-authored-by: SylentHuntress <91935048+sylenthuntress@users.noreply.github.com>
Co-authored-by: oryxel <gamingnoob681@gmail.com>
Co-authored-by: Eclipse <eclipse@eclipseisoffline.xyz>
Co-authored-by: Nebojsa Majic <79749977+Onako2@users.noreply.github.com>
Co-authored-by: qscbm187531 <1309635304@qq.com>
Co-authored-by: Eveline Carter <6444703+drakon64@users.noreply.github.com>
Co-authored-by: SleepyPop <81194303+SleepyPopp@users.noreply.github.com>
Co-authored-by: Aurorawr <auroranova8756@gmail.com>
Co-authored-by: rtm516 <rtm516@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 19:42:47 -07:00

18 KiB
Raw Blame History

title, slug, authors, hide_table_of_contents, description, crowdin_page_id
title slug authors hide_table_of_contents description crowdin_page_id
1.18 Release, MCProtocolLib, Refactors & More! 1-18-release-and-more RednedEpic false In this post, we will be covering all the changes that led up to the 1.18 release. cd16bcf9-0de9-4239-946a-4ccdbeb372f6

Hi everyone 👋

Welcome to the new Geyser blog! We’ll be posting new content here periodically about project updates, future plans, project announcements and really just miscellaneous development-related content around the Geyser project(s). These will be linked in our #blog-feed channel on Discord, so if you want to be notified when we make new posts and such, feel free to either follow the channel in your own Discord server, or turn on notifications.

Introduction:

In this post, we will be covering all the changes that led up to the 1.18 release. With 1.18 came a huge set of changes for Geyser which although may not be visible to the end user, were a massive feat internally. This resulted in not only multiple project refactors of Geyser along with surrounding projects (PacketLib, MCProtocolLib, etc.) but many additional optimizations and improvements to how the code operated and ran. For the latter half of 2021 especially, we’ve been putting in a lot more time to ensure Geyser runs more smoothly and to optimize poorly performing parts of the code, so much of these changes were a direct result of that initiative.

Writing a New Java Edition Protocol Library:

To preface, we were not initially planning to do this big refactor all at once, but one thing led to another and here we are. Our initial plans were actually quite a bit different, with us initially planning to deprecate and remove MCProtocolLib from our codebase, and instead implement support for Java Edition inside of Protocol, our Bedrock Edition protocol library. We actually got it to a point where you could join and properly send/receive packets quite well!

Java Edition Lib

This was inline with our plans to continually improve performance and maintainability with Geyser, since using a library where much of the code is the same across both the Java & Bedrock protocol libraries would reduce much of the additional work we need to do in. A good example of this is inside our ItemTranslator class, where we translate NBT objects from that used inside of MCProtocolLib, to that used inside of our Bedrock protocol library. We were intending to have this done with 1.18 since the update itself was not too drastic, meaning we could spend much more time on Geyser itself, rather than trying to update to the protocol.

Taking over MCProtocolLib:

However our plans completely changed when Steveice10, the maintainer of MCProtocolLib at the time, reached out and asked if we wanted to take over the project. At first we were a bit hesitant as we had already put in quite a bit of work to our new library, but as MCProtocolLib was already an integral part of Geyser from the very beginning and we had essentially been maintaining the library for the past year or so, we all came to the consensus that scrapping the library would be a poor idea, both for us as well as the wider community who was also using this library. We decided to take over it.

With us now being in full control of MCProtocolLib, that gave us much more freedom to update and improve the project that we previously were unable to do. Rather than go on with a new library altogether, we felt it would be better to gradually port over much of our work into MCProtocolLib. With the release of 1.18 still lingering, we decided to jump the gun and start on a massive refactor of packets, with us adopting Mojang-mapped packet names. This is something we were doing inside of Protocol for Java Edition and with more and more projects adopting these names and for the sake of unity across the board, we felt now was the best time to make this decision.

Improving Performance in MCProtocolLib:

During the process of renaming packets to use Mojmap names, we found that most of the performance bottlenecks with MCProtocolLib & Geyser did not particularly lie with object translation, since it's relatively cheap in the grand scheme of things, but just the ways in which the library operated itself.

Slow Packets

What we identified is that inside of MinecraftProtocol, the main class inside of MCProtocolLib, that it was re-registering the Minecraft protocol individually for every player individually, any time the protocol state changed. To give a bit more background on this - the Minecraft protocol operates over four individual state. The first is the handshaking state, which is the state set when a client first makes a connection the Minecraft server. Once the handshake has completed, the next state is either the login or the status state. The status state is set when a client pings the server from the server list and never actually joins, while the login state is for when the client is logging into the server. Once the login is complete, the server then goes on to the game state, where you actually recieve packets that let you interact with the world.

Below is an example of what MCProtocolLib was doing previously, any time you switched from the login state to the game state:

private void initGame(BiConsumer<Integer, Class<? extends Packet>> clientboundPackets, BiConsumer<Integer, Class<? extends Packet>> serverboundPackets) {
        clientboundPackets.accept(0x00, ServerSpawnEntityPacket.class);
        clientboundPackets.accept(0x01, ServerSpawnExpOrbPacket.class);
        clientboundPackets.accept(0x02, ServerSpawnLivingEntityPacket.class);
        clientboundPackets.accept(0x03, ServerSpawnPaintingPacket.class);
        clientboundPackets.accept(0x04, ServerSpawnPlayerPacket.class);
        clientboundPackets.accept(0x05, ServerAddVibrationSignalPacket.class);
        clientboundPackets.accept(0x06, ServerEntityAnimationPacket.class);
        clientboundPackets.accept(0x07, ServerStatisticsPacket.class);
        clientboundPackets.accept(0x08, ServerPlayerActionAckPacket.class);
        clientboundPackets.accept(0x09, ServerBlockBreakAnimPacket.class);
        clientboundPackets.accept(0x0A, ServerUpdateTileEntityPacket.class);
        clientboundPackets.accept(0x0B, ServerBlockValuePacket.class);
        clientboundPackets.accept(0x0C, ServerBlockChangePacket.class);
        clientboundPackets.accept(0x0D, ServerBossBarPacket.class);
        clientboundPackets.accept(0x0E, ServerDifficultyPacket.class);
        clientboundPackets.accept(0x0F, ServerChatPacket.class);
        clientboundPackets.accept(0x10, ServerClearTitlesPacket.class);
        clientboundPackets.accept(0x11, ServerTabCompletePacket.class);
        clientboundPackets.accept(0x12, ServerDeclareCommandsPacket.class);
        clientboundPackets.accept(0x13, ServerCloseWindowPacket.class);
        clientboundPackets.accept(0x14, ServerWindowItemsPacket.class);
        clientboundPackets.accept(0x15, ServerWindowPropertyPacket.class);
        clientboundPackets.accept(0x16, ServerSetSlotPacket.class);
        clientboundPackets.accept(0x17, ServerSetCooldownPacket.class);
        clientboundPackets.accept(0x18, ServerPluginMessagePacket.class);
        // this continues for more than 100 more packets

With the above code, every game packet would be registered into a new map. This was a far less than ideal situation, given that hundreds of packets would be registered, and this was something called for every client. We opted to replace this with a static registry which instead holds these values just once. Any time the sub-protocol changes, it instead just pulls from this static codec instead, rather than populating a map every time.

We also identified other areas where code was running poorly - previously, every packet was constructed through reflection, which we realized could easily be replaced with a packet factory. Nowadays, the packet registration code is only constructed once, and the player's protocol state determines which map to pull packets from.

With all these changes consolidated into an individual codec, it also opens the door for multi-version compatibility - something we were initially planning to do with our Java Edition work in Protocol. Although not officially supported yet nor something we have fully committed to, these changes will allow that capability in the future, and implementing projects technically could implement the capability to do so if they please.

Refactoring Geyser:

With the massive changes inside MCProtocolLib already lining up, we already foresaw the changes in Geyser being quite drastic. With plans for extensions and a more streamlined API being in the plans for over a year, we felt that now was the best time to start moving along with that. This initially started with a massive refactor of the packages inside of Geyser. Previously, everything involved with the work Geyser did with packet translation and whatnot lied in the connector module of the project. This name was slightly confusing for many as Geyser does much more than just "connecting you to a server." With that being said, we decided to rename the module to core and update the packaging for it from org.geysermc.connector to org.geysermc.geyser.

Along with the package name changes, we decided to start implementing a new API. At the time of writing, this is still something that is very much a work in progress, however this will make it much easier to write projects that interop with Geyser & Floodgate in a much more streamlined fashion, and allow for extensions to have a solid base to build off of.

Improving Code in Geyser:

As mentioned earlier in this post, one of our plans was to eventually move away from MCProtocolLib due to the additional translation we have to do between MCProtocolLib and Protocol objects. However, as we continued working on both the MCProtocolLib changes and the Geyser refactor, we identified that these translations were not the sources of most performance bottlenecks inside of Geyser itself. This led to us refactoring our entity system inside of Geyser, not solely for the sake of performance, but also for the sake of better usability and understanding.

public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
        switch (entityMetadata.getId()) {
            case 0:
                if (entityMetadata.getType() == MetadataType.BYTE) {
                    byte xd = (byte) entityMetadata.getValue();
                    metadata.getFlags().setFlag(EntityFlag.ON_FIRE, ((xd & 0x01) == 0x01) && !metadata.getFlags().getFlag(EntityFlag.FIRE_IMMUNE)); // Otherwise immune entities sometimes flicker onfire
                    metadata.getFlags().setFlag(EntityFlag.SNEAKING, (xd & 0x02) == 0x02);
                    metadata.getFlags().setFlag(EntityFlag.SPRINTING, (xd & 0x08) == 0x08);
                    // Swimming is ignored here and instead we rely on the pose
                    metadata.getFlags().setFlag(EntityFlag.GLIDING, (xd & 0x80) == 0x80);

                    setInvisible(session, (xd & 0x20) == 0x20);
                }
                break;
            case 1: // Air/bubbles
                setAir((int) entityMetadata.getValue());
                break;
            case 2: // custom name
                if (entityMetadata.getValue() instanceof Component message) {
                    // Always translate even if it's a TextMessage since there could be translatable parameters
                    metadata.put(EntityData.NAMETAG, MessageTranslator.convertMessage(message, session.getLocale()));
                }
                break;
            case 3: // is custom name visible
                if (!this.is(PlayerEntity.class))
                    metadata.put(EntityData.NAMETAG_ALWAYS_SHOW, (byte) ((boolean) entityMetadata.getValue() ? 1 : 0));
                break;
            case 4: // silent
                metadata.getFlags().setFlag(EntityFlag.SILENT, (boolean) entityMetadata.getValue());
                break;
            case 5: // no gravity
                metadata.getFlags().setFlag(EntityFlag.HAS_GRAVITY, !(boolean) entityMetadata.getValue());
                break;
            case 6: // Pose change - typically used for bounding box and not animation
                Pose pose = (Pose) entityMetadata.getValue();

                metadata.getFlags().setFlag(EntityFlag.SLEEPING, pose.equals(Pose.SLEEPING));
                // Triggered when crawling
                metadata.getFlags().setFlag(EntityFlag.SWIMMING, pose.equals(Pose.SWIMMING));
                setDimensions(pose);
                break;
            case 7: // Freezing ticks
                // The value that Java edition gives us is in ticks, but Bedrock uses a float percentage of the strength 0.0 -> 1.0
                // The Java client caps its freezing tick percentage at 140
                int freezingTicks = Math.min((int) entityMetadata.getValue(), 140);
                setFreezing(session, freezingTicks / 140f);
                break;
        }
    }

Looking at the code above, our previous code for translating entity metadata was extremely scattered and utilized many magic “numbers” associated with entity translation. These types of switch statements were all over various entity classes, and were quite messy.

To explain the above code in more detail - the way Minecraft Java sends entity metadata over the protocol is that it associates an id for every entity metadata “type”. Looking at the above code, id 3 for example, is associated with whether an entity’s name is visible above their head. The problem with handling our code like this is that if Mojang decides to add a new entity metadata field at id 2 for example, everything above that will be incremented by 1, so 'custom name visible' would have an id of 4, rather than 3 in future updates. Along with the code being so scattered, it meant that we would need to increment ids inside of every entity class, which was far less than ideal.

What we opted to do to remedy this issue is to instead not use massive if or switch statements on the ids, but to register these values inside of a list, and add them based on the order they should be translated in.

EntityDefinition<Entity> entityBase = EntityDefinition.builder((BaseEntityFactory<Entity>) Entity::new)
        .addTranslator(MetadataType.BYTE, Entity::setFlags)
        .addTranslator(MetadataType.INT, Entity::setAir) // Air/bubbles
        .addTranslator(MetadataType.OPTIONAL_CHAT, Entity::setDisplayName)
        .addTranslator(MetadataType.BOOLEAN, Entity::setDisplayNameVisible)
        .addTranslator(MetadataType.BOOLEAN, (entity, entityMetadata) -> entity.setFlag(EntityFlag.SILENT, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue()))
        .addTranslator(MetadataType.BOOLEAN, Entity::setGravity)
        .addTranslator(MetadataType.POSE, Entity::setPose)
        .addTranslator(MetadataType.INT, Entity::setFreezing)
        .build();

All that code shown earlier has been condensed into the following. Now, if Mojang is to add a new metadata field at id 2 for instance, we can simply just plug it in as the third value, and boom, everything else will automatically be incremented!

In regards to performance, previously all the entity data had been held in an EntityType enum, which was not the best for constructing more complex entity objects. This meant we had to use reflection for constructing entities which as mentioned earlier, was used inside of MCProtocolLib, and was slower than what we wanted. This too was replaced with an entity factory, and can be seen in the above code snippet.

New API, Extensions, and Looking Onward:

As brought up multiple times throughout this post, we have been spending time working up a new API. We eventually want to bring in extensions to Geyser, which act as plugins on their own except they are loaded from Geyser itself. With more and more people and larger servers adopting Geyser, many more unique and niche usecases have popped up which don’t particularly fit inside of Geyser itself, but would still benefit users as a whole. As Geyser is capable of running on 6 platforms at this point in time (Spigot, Sponge, Standalone, Velocity, Fabric and BungeeCord, with Forge likely on the way), as a developer, creating a separate addon capable of running on all these platforms is far less than ideal. We’ve opted to get around this by creating a new extension system, allowing developers to create an extension one time for Geyser, and it being capable of running on any of these platforms.

This extension API has not been created yet however, and plans for the base API inside of Geyser are still being finalized. We also intend to start moving most of Floodgate into Geyser itself, so unless you are running Floodgate independently from Geyser (e.g. you use Geyser Standalone but run Floodgate on the proxy), in the near future you will only need to install Geyser, and Floodgate’s functions will all be handled automatically in Geyser.

With that coming up, we also want to design the base API to be agnostic in the sense that basic functions such as retrieving how many players are online can be done using the same API, whether the server has just Geyser installed or just Floodgate. But at the same time, we also want to make it easy to utilize a more-specific Floodgate and Geyser API.

Anyway, that about wraps up the first post! Thanks for reading and feel free to offer any feedback about the topics covered in our Discord server!