Author SHA1 Message Date
onebeastchris a02d0af349 Start on new troubleshooting pages 2024-12-16 11:04:04 +08:00
onebeastchris 06f12d2248 changes 2024-12-04 00:26:20 +08:00
rtm516 5641161aa8 Add markdown step support 2024-09-26 13:59:58 +01:00
rtm516 5277c30f68 Add initial troubleshooting tree framework 2024-09-26 12:48:42 +01:00
121 changed files with 12403 additions and 22209 deletions

No files matched your search

+5 -12
View File
@@ -30,29 +30,22 @@ jobs:
name: Deploy to GitHub Pages
runs-on: ubuntu-latest
steps:
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af
with:
node-version: 22
- name: Enable Corepack
run: corepack enable
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
with:
fetch-depth: 0
- name: Setup Pages
uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af
- uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b
with:
node-version: 22
node-version: 18
cache: yarn
- name: Install dependencies
run: yarn install --frozen-lockfile
- uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57
- uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9
with:
path: |
${{ github.workspace }}/.docusaurus
@@ -78,4 +71,4 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e
uses: actions/deploy-pages@decdde0ac072f6dcbe43649d82d9c635fff5b4e4
+4 -11
View File
@@ -8,26 +8,19 @@ jobs:
name: Build PR
runs-on: ubuntu-latest
steps:
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af
with:
node-version: 22
- name: Enable Corepack
run: corepack enable
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
with:
fetch-depth: 0
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af
- uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b
with:
node-version: 22
node-version: 18
cache: yarn
- name: Install dependencies
run: yarn install --frozen-lockfile
- uses: actions/cache/restore@1bd1e32a3bdc45362d1e726936510720a7c30a57
- uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9
with:
path: |
${{ github.workspace }}/.docusaurus
+1 -6
View File
@@ -26,9 +26,4 @@ vendor
npm-debug.log*
yarn-debug.log*
yarn-error.log*
package-lock.json
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/versions
package-lock.json
-1
View File
@@ -1 +0,0 @@
nodeLinker: node-modules
@@ -224,12 +224,12 @@ Geyser initially rolled out a fix that forced these defaults, but has since been
These defaults may present an issue to those running a reverse proxy in front of their Geyser instance, particularly those utilizing DDoS mitigation services like TCPShield and CosmicGuard, as to Network it will appear that all connections are originating from the same IP. To make configuration on these services easier, Geyser will disable these rate limits provided proxy protocol is enabled for the bedrock connection, and the Geyser instance is properly configured to only accept connections from the IPs of the proxy. To simplify this configuration, Geyser’s config can now accept a URL to specify proxy server IP ranges. Many DDoS mitigation providers have a static link to an always up to date text file of these.
```yaml
advanced.bedrock:
bedrock:
# ...
use-haproxy-protocol: true
haproxy-protocol-whitelisted-ips: [ "https://cosmic.global/ips/", "https://tcpshield.com/v4/" ]
enable-proxy-protocol: true
proxy-protocol-whitelisted-ips: [ "https://cosmic.global/ips/", "https://tcpshield.com/v4/" ]
```
*Geyser configuration using a URL pointing a new-line separated text file containing allowed IPs for haproxy-protocol usage.*
*Geyser configuration using a URL pointing a new-line separated text file containing allowed IPs for proxy-protocol usage.*
## Long Term Impact
@@ -1,472 +0,0 @@
---
title: "Bedrock Early Packet Handling DoS Attack Summary and Response"
slug: "early-packet-handling-attack"
authors: Kas-tle
hide_table_of_contents: false
description: "A summary of how we addressed a series of exploits targeting Geyser's early handling of Bedrock game packets"
---
Back in July, we received reports of multiple Geyser instances experiencing targeted Denial of Service (DoS) attacks exhibiting similar characteristics. Out of an abundance of caution, we delayed making this post to ensure that users had adequate time to upgrade. The bugs that allowed for this string of attacks were patched on Geyser builds numbered 897 and later. In the unlikely event you are still running an outdated build of Geyser from many months ago, you should update immediately by downloading the latest build from [https://geysermc.org/download](https://geysermc.org/download). The original [security advisory](https://github.com/GeyserMC/Geyser/security/advisories/GHSA-m2q6-2hwr-643w) for this vulnerability was published on the [GeyserMC/Geyser](https://github.com/GeyserMC/Geyser) repository. This response will detail the timeline, attack vectors, how they were patched, and additional measures we took to prevent future attacks.
<!-- truncate -->
## Timeline (UTC)
- **July 29th, 9:40PM:** Server being attacked privately reports the issue to Geyser and shares logs
- **July 29th, 11:45PM:** Preemptive patch is released to limit the number of authenticated connections per address
- **July 30th, 5:36PM:** Large servers continue to report attacks with newer builds of Geyser
- **July 30th, 6:20PM:** A server being attacked provides us with packet logs, illustrating what Bedrock packets malicious clients are using to carry out the attack
- **July 30th, 6:52PM:** Second patch is released to ensure the Bedrock client can only signal complete of resource pack sending once per session
- **July 30th, 7:45PM:** Issue regarding connections failing to close out is reported to upstream Bedrock protocol library
- **July 30th, 9:35PM:** Upstream Bedrock protocol library publishes patch to ensure connections are properly closed when Bedrock users are disconnected
- **July 30th, 10:45PM:** Third patch is released updating the upstream Bedrock protocol library and ensuring Bedrock connections that cause exceptions are closed immediately
- **July 31st, 11:24PM:** An @everyone ping is made in the Geyser Discord advising users to update their Geyser instances, and the initial security advisory is published to GitHub.
## Initial Disclosure
Use of this attack was first privately reported to us by multiple larger servers using Geyser. We were provided server logs showing a single user appearing to be authenticated multiple times. The logs generally took a form of:
```log
[17:26:09.183 GeyserServerChild-4-1/INFO] Player connected with username BedrockPleyer
[17:26:09.183 GeyserServerChild-4-1/INFO] Player connected with username BedrockPleyer
[17:26:09.183 GeyserServerChild-4-1/INFO] Player connected with username BedrockPleyer
[17:26:09.183 GeyserServerChild-4-1/ERROR] BedrockPleyer is already logged in!
[17:26:09.183 GeyserServerChild-4-1/INFO] Player connected with username BedrockPlayer
[17:26:09.183 clientNetworkSession-6-3/INFO] BedrockPlayer (logged in as: BedrockPlayer) has connected to remote java server on address 127.0.0.1
[17:26:09.183 clientNetworkSession-6-1/INFO] BedrockPlayer (logged in as: BedrockPlayer) has connected to remote java server on address 127.0.0.1
[17:26:09.183 clientNetworkSession-6-2/INFO] BedrockPlayer (logged in as: BedrockPlayer) has connected to remote java server on address 127.0.0.1
[17:26:09.184 GeyserServerChild-4-1/ERROR] BedrockPlayer is already logged in!
[17:26:09.184 clientNetworkSession-6-4/INFO] BedrockPlayer (logged in as: BedrockPlayer) has connected to remote java server on address 127.0.0.1
[17:26:09.184 GeyserServerChild-4-1/INFO] Player connected with username BedrockPlayer
[17:26:09.184 GeyserServerChild-4-1/ERROR] BedrockPlayer is already logged in!
[17:26:09.184 GeyserServerChild-4-1/INFO] Player connected with username BedrockPlayer
[17:26:09.184 GeyserServerChild-4-1/ERROR] BedrockPlayer is already logged in!
[17:26:09.184 GeyserServerChild-4-1/INFO] Player connected with username BedrockPlayer
[17:26:09.184 GeyserServerChild-4-1/ERROR] BedrockPlayer is already logged in!
[17:26:09.185 GeyserServerChild-4-1/INFO] Player connected with username BedrockPlayer
[17:26:09.185 GeyserServerChild-4-1/ERROR] BedrockPlayer is already logged in!
```
Based on the content of these logs, we initially suspected that packets in the early phase of the Bedrock connection were being exploited. However, we were not yet sure of what specific packets the attacker was sending. Based on these logs, we released a preemptive patch to ensure that the number of authenticated users from a single IP address at any given time was limited. This alone, however, would prove to be insufficient to mitigate the attack.
## Game Packet and Code Analysis of the First Attack Vector
Understanding this attack requires a basic understanding of the general Bedrock login process. This is detailed below:
![chart_04 Bedrock Login Process](/img/blog/2025-11-30-early-packet-handling-attack/chart_04.svg#gh-light-mode-only)![chart_04 Bedrock Login Process](/img/blog/2025-11-30-early-packet-handling-attack/chart_04_dark.svg#gh-dark-mode-only)
In order to fully mitigate this attack, we required packet capture samples from a server being actively exploited. This is somewhat challenging to achieve, as traffic at the Bedrock protocol level is generally encrypted after the player has logged into the server. As a result, a modified build of Geyser is required to capture this traffic. We were fortunate to have the cooperation of a server being targeted with this attack, who installed a build of Geyser we provided to log packets. This was the resulting log, with IP addresses and usernames redacted:
```log
[18:16:37.767 GeyserServerChild-4-1/INFO] null /XXX.XXX.XXX.XXX ClientToServerHandshakePacket
[18:16:37.795 GeyserServerChild-4-1/INFO] null /XXX.XXX.XXX.XXX ResourcePackClientResponsePacket(packIds=[], status=COMPLETED)
[18:16:37.808 GeyserServerChild-4-1/INFO] Player connected with username BedrockPlayer
[18:16:37.808 GeyserServerChild-4-1/INFO] null /XXX.XXX.XXX.XXX ResourcePackClientResponsePacket(packIds=[], status=COMPLETED)
[18:16:37.809 GeyserServerChild-4-1/INFO] Player connected with username BedrockPlayer
[18:16:37.809 GeyserServerChild-4-1/INFO] null /XXX.XXX.XXX.XXX ResourcePackClientResponsePacket(packIds=[], status=COMPLETED)
[18:16:37.809 GeyserServerChild-4-1/INFO] Player connected with username BedrockPlayer
[18:16:37.809 GeyserServerChild-4-1/INFO] null /XXX.XXX.XXX.XXX ResourcePackClientResponsePacket(packIds=[], status=COMPLETED)
[18:16:37.810 GeyserServerChild-4-1/INFO] Player connected with username BedrockPlayer
[18:16:37.810 GeyserServerChild-4-1/INFO] null /XXX.XXX.XXX.XXX ResourcePackClientResponsePacket(packIds=[], status=COMPLETED)
[18:16:37.810 GeyserServerChild-4-1/INFO] Player connected with username BedrockPlayer
[18:16:37.810 GeyserServerChild-4-1/INFO] null /XXX.XXX.XXX.XXX ResourcePackClientResponsePacket(packIds=[], status=COMPLETED)
[18:16:37.810 GeyserServerChild-4-1/INFO] Player connected with username BedrockPlayer
[18:16:37.810 GeyserServerChild-4-1/INFO] null /XXX.XXX.XXX.XXX ResourcePackClientResponsePacket(packIds=[], status=COMPLETED)
[18:16:37.811 GeyserServerChild-4-1/INFO] Player connected with username BedrockPlayer
[18:16:37.811 GeyserServerChild-4-1/INFO] null /XXX.XXX.XXX.XXX ResourcePackClientResponsePacket(packIds=[], status=COMPLETED)
[18:16:37.811 GeyserServerChild-4-1/INFO] Player connected with username BedrockPlayer
[18:16:37.811 GeyserServerChild-4-1/INFO] null /XXX.XXX.XXX.XXX ResourcePackClientResponsePacket(packIds=[], status=COMPLETED)
[18:16:37.811 GeyserServerChild-4-1/INFO] Player connected with username BedrockPlayer
[18:16:37.811 GeyserServerChild-4-1/INFO] null /XXX.XXX.XXX.XXX ResourcePackClientResponsePacket(packIds=[], status=COMPLETED)
[18:16:37.812 GeyserServerChild-4-1/INFO] Player connected with username BedrockPlayer
[18:16:37.812 GeyserServerChild-4-1/INFO] null /XXX.XXX.XXX.XXX ResourcePackClientResponsePacket(packIds=[], status=COMPLETED)
[18:16:37.820 clientNetworkSession-6-2/INFO] BedrockPlayer (logged in as: BedrockPlayer) has connected to remote java server on address 127.0.0.1
[18:16:37.820 clientNetworkSession-6-1/INFO] BedrockPlayer (logged in as: BedrockPlayer) has connected to remote java server on address 127.0.0.1
[18:16:37.820 clientNetworkSession-6-4/INFO] BedrockPlayer (logged in as: BedrockPlayer) has connected to remote java server on address 127.0.0.1
[18:16:37.820 clientNetworkSession-6-3/INFO] BedrockPlayer (logged in as: BedrockPlayer) has connected to remote java server on address 127.0.0.1
[18:16:37.848 GeyserServerChild-4-1/INFO] Player connected with username BedrockPlayer
[18:16:37.849 GeyserServerChild-4-1/INFO] BedrockPlayer /XXX.XXX.XXX.XXX ResourcePackClientResponsePacket(packIds=[], status=COMPLETED)
[18:16:37.849 GeyserServerChild-4-1/ERROR] BedrockPlayer is already logged in!
[18:16:37.849 GeyserServerChild-4-1/INFO] Player connected with username BedrockPlayer
[18:16:37.849 GeyserServerChild-4-1/INFO] BedrockPlayer /XXX.XXX.XXX.XXX ResourcePackClientResponsePacket(packIds=[], status=COMPLETED)
[18:16:37.850 GeyserServerChild-4-1/ERROR] BedrockPlayer is already logged in!
[18:16:37.850 GeyserServerChild-4-1/INFO] Player connected with username BedrockPlayer
[18:16:37.850 GeyserServerChild-4-1/INFO] BedrockPlayer /XXX.XXX.XXX.XXX ResourcePackClientResponsePacket(packIds=[], status=COMPLETED)
[18:16:37.850 GeyserServerChild-4-1/ERROR] BedrockPlayer is already logged in!
[18:16:37.850 GeyserServerChild-4-1/INFO] Player connected with username BedrockPlayer
```
The above log clearly indicates that the packet being exploited is the [ResourcePackClientResponsePacket](https://mojang.github.io/bedrock-protocol-docs/html/ResourcePackClientResponsePacket.html). This leads to code paths in Geyser being called multiple times a way that is not intended, ultimately leading to increased resource consumption. We can essentially summarize the attack as follows:
![chart_02 Attack Summary](/img/blog/2025-11-30-early-packet-handling-attack/chart_02.svg#gh-light-mode-only)![chart_02 Attack Summary](/img/blog/2025-11-30-early-packet-handling-attack/chart_02_dark.svg#gh-dark-mode-only)
The initial response to the ResourcePackClientResponsePacket is handled by `UpstreamPacketHandler`:
```java
package org.geysermc.geyser.network;
// ...
public class UpstreamPacketHandler extends LoggingPacketHandler {
// ...
public PacketSignal handle(ResourcePackClientResponsePacket packet) {
// ...
switch (packet.getStatus()) {
case COMPLETED -> {
if (geyser.getConfig().getRemote().authType() != AuthType.ONLINE) {
session.authenticate(session.getAuthData().name());
} else if (!couldLoginUserByName(session.getAuthData().name())) {
// We must spawn the white world
session.connect();
}
geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.network.connect", session.getAuthData().name()));
}
// ...
}
return PacketSignal.HANDLED;
}
// ...
}
```
We see in the code above that this will lead to the invocation of `GeyserSession#authenticate` for most connections, as most Geyser instances use `AuthType.FLOODGATE`:
```java
package org.geysermc.geyser.session;
// ...
public class GeyserSession implements GeyserConnection, GeyserCommandSource {
// ...
public void authenticate(String username) {
if (loggedIn) {
geyser.getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.auth.already_loggedin", username));
return;
}
loggingIn = true;
// Always replace spaces with underscores to avoid illegal nicknames, e.g. with GeyserConnect
protocol = new MinecraftProtocol(username.replace(' ', '_'));
try {
connectDownstream();
} catch (Throwable t) {
t.printStackTrace();
}
}
// ...
}
```
This leads to the calling of `GeyserSession#connectDownstream`, which triggers a variety of logic to open a connection to the Java server:
```java
package org.geysermc.geyser.session;
// ...
public class GeyserSession implements GeyserConnection, GeyserCommandSource {
// ...
private void connectDownstream() {
SessionLoginEvent loginEvent = new SessionLoginEvent(this, remoteServer, new Object2ObjectOpenHashMap<>());
GeyserImpl.getInstance().eventBus().fire(loginEvent);
if (loginEvent.isCancelled()) {
String disconnectReason = loginEvent.disconnectReason() == null ?
BedrockDisconnectReasons.DISCONNECTED : loginEvent.disconnectReason();
disconnect(disconnectReason);
return;
}
this.cookies = loginEvent.cookies();
// Don't allow changing the remote server when it's not up to us
// Just imagine the chaos of using an integrated world manager for an external server :)
this.remoteServer = this.geyser.platformType() == PlatformType.STANDALONE ? loginEvent.remoteServer() : remoteServer;
// Start ticking
tickThread = tickEventLoop.scheduleAtFixedRate(this::tick, nanosecondsPerTick, nanosecondsPerTick, TimeUnit.NANOSECONDS);
ClientSession downstream;
if (geyser.getBootstrap().getSocketAddress() != null) {
// We're going to connect through the JVM and not through TCP
downstream = new LocalSession(geyser.getBootstrap().getSocketAddress(),
upstream.getAddress().getAddress().getHostAddress(),
this.protocol, this.tickEventLoop);
downstream.setFlag(MinecraftConstants.CLIENT_HOST, this.remoteServer.address());
downstream.setFlag(MinecraftConstants.CLIENT_PORT, this.remoteServer.port());
this.downstream = new DownstreamSession(downstream);
} else {
downstream = new ClientNetworkSession(new InetSocketAddress(this.remoteServer.address(), this.remoteServer.port()), this.protocol, tickEventLoop, null, null);
this.downstream = new DownstreamSession(downstream);
boolean resolveSrv = false;
try {
resolveSrv = this.remoteServer.resolveSrv();
} catch (AbstractMethodError | NoSuchMethodError ignored) {
// Ignore if the method doesn't exist
// This will happen with extensions using old APIs
}
this.downstream.getSession().setFlag(BuiltinFlags.ATTEMPT_SRV_RESOLVE, resolveSrv);
}
// Disable automatic creation of a new TcpClientSession when transferring - we don't use that functionality.
this.downstream.getSession().setFlag(MinecraftConstants.FOLLOW_TRANSFERS, false);
if (geyser.getConfig().getRemote().isUseProxyProtocol()) {
downstream.setFlag(BuiltinFlags.CLIENT_PROXIED_ADDRESS, upstream.getAddress());
}
if (geyser.getConfig().isForwardPlayerPing()) {
// Let Geyser handle sending the keep alive
downstream.setFlag(MinecraftConstants.AUTOMATIC_KEEP_ALIVE_MANAGEMENT, false);
}
// We'll handle this since we have the registry data on hand
downstream.setFlag(MinecraftConstants.SEND_BLANK_KNOWN_PACKS_RESPONSE, false);
// We manually add the default listener to ensure the order of listeners.
protocol.setUseDefaultListeners(false);
// MCPL listener comes first to handle protocol state switching before Geyser translates packets
downstream.addListener(new ClientListener(HandshakeIntent.LOGIN));
// Geyser adapter second to ensure translating packets in the correct states
downstream.addListener(new GeyserSessionAdapter(this));
downstream.setFlag(BuiltinFlags.CLIENT_TRANSFERRING, loginEvent.transferring());
downstream.connect(false);
if (!daylightCycle) {
setDaylightCycle(true);
}
}
// ...
}
```
Notably, this allows for multiple downstream sessions (representing Geyser's connection to the Java server per player) to be created for a single Bedrock session. This is not intended behavior, as it leads to significantly increased resource consumption. This is especially true on Geyser Standalone, which, as seen in the code above, must open a TCP session to the Java server. The window of time for an attacker to pull this off is relatively short, as once Geyser completes the Java login process on behalf of the Bedrock client, `GeyserSession.loggedIn` is set to true, preventing further calls to `GeyserSession#connectDownstream`. However, this is still enough time for an attacker to create numerous downstream sessions, leading to a DoS attack. We attempted to mitigate this by disconnecting clients that send multiple ResourcePackClientResponsePacket in a single session. The following class diagram summarizes this:
![chart_05 Multiple Sessions Class Diagram](/img/blog/2025-11-30-early-packet-handling-attack/chart_05.svg#gh-light-mode-only)![chart_05 Multiple Sessions Class Diagram](/img/blog/2025-11-30-early-packet-handling-attack/chart_05_dark.svg#gh-dark-mode-only)
## Code Analysis of the Second Attack Vector
While we thought we had addressed the root issue and provided the affected users with a patch for testing, we quickly received logs that indicated otherwise:
```log
[18:54:29.235 GeyserServerChild-4-3/INFO] Player connected with username BedrockPlayer
[18:54:29.237 clientNetworkSession-6-2/INFO] BedrockPlayer (logged in as: BedrockPlayer) has connected to remote java server on address 127.0.0.1
[18:54:49.257 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:54:49.259 GeyserServerChild-4-3/INFO] BedrockPlayer has disconnected from remote Java server on address 127.0.0.1 because of An internal error occurred!
[18:54:52.836 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:54:55.620 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:54:56.186 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:54:56.872 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:54:59.508 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:55:02.551 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:55:03.025 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:55:03.619 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:55:04.254 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:55:04.922 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:55:05.435 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:55:07.662 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:55:08.139 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:55:08.650 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:55:11.066 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:55:13.498 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:55:14.023 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:55:14.466 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:55:15.057 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:55:15.712 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:55:16.211 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:55:18.431 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:55:18.966 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:55:19.443 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:55:21.599 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:55:23.904 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:55:24.409 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:55:24.971 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:55:25.539 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
[18:55:26.225 GeyserServerChild-4-3/WARN] Exception caught in session of BedrockPlayer: index: 13, length: 25710 (expected: range(0, 27))
```
These exceptions are thrown by Geyser's InvalidPacketHandler, which is designed to quickly disconnect players that send malformed packets or packets that exceed the expected size limits. This is a security measure to prevent potential exploits or crashes caused by invalid data.
```java
package org.geysermc.geyser.network;
// ...
public class InvalidPacketHandler extends ChannelInboundHandlerAdapter {
public static final String NAME = "rak-error-handler";
private final GeyserSession session;
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
Throwable rootCause = Stream.iterate(cause, Throwable::getCause)
.filter(element -> element.getCause() == null)
.findFirst()
.orElse(cause);
GeyserLogger logger = GeyserImpl.getInstance().getLogger();
if (!(rootCause instanceof IllegalArgumentException)) {
// Kick users that cause exceptions
logger.warning("Exception caught in session of " + session.bedrockUsername() + ": " + rootCause.getMessage());
session.disconnect("An internal error occurred!");
return;
}
// Kick users that try to send illegal packets
logger.warning("Illegal packet from " + session.bedrockUsername() + ": " + rootCause.getMessage());
if (logger.isDebug()) {
cause.printStackTrace();
}
session.disconnect("Invalid packet received!");
}
}
```
This makes the aforementioned logs of particular concern, as it should not be possible for any exceptions to be triggered from this handler multiple times. The first exception should be logged and trigger an immediate disconnect, preventing further exceptions from being thrown. Despite this, the log clearly indicates that multiple exceptions are being thrown in quick succession, suggesting that the disconnect is not being handled as intended. This is summarized below:
![chart_03 Exception Handler](/img/blog/2025-11-30-early-packet-handling-attack/chart_03.svg#gh-light-mode-only)![chart_03 Exception Handler](/img/blog/2025-11-30-early-packet-handling-attack/chart_03_dark.svg#gh-dark-mode-only)
We first followed the chain of `GeyserSession#disconnect`. This invokes Geyser's `UpstreamSession#disconnect`, which contains `BedrockServerSession` and invokes `BedrockServerSession#disconnect`. Beyond this, the disconnect logic is handled by the upstream Bedrock protocol library used by Geyser, [CloudburstMC/Protocol](https://github.com/CloudburstMC/Protocol). The overall logic is summarized below:
![chart_01 GeyserSession Disconnect Chain](/img/blog/2025-11-30-early-packet-handling-attack/chart_01.svg#gh-light-mode-only)![chart_01 GeyserSession Disconnect Chain](/img/blog/2025-11-30-early-packet-handling-attack/chart_01_dark.svg#gh-dark-mode-only)
Upon further investigation, we found that the Bedrock protocol library did not actually close the underlying Netty channel when a disconnect was triggered:
```java
package org.cloudburstmc.protocol.bedrock;
// ...
public class BedrockServerSession extends BedrockSession {
// ...
public void disconnect(@Nullable String reason, boolean hideReason) {
this.checkForClosed();
DisconnectPacket packet = new DisconnectPacket();
if (reason == null || hideReason) {
packet.setMessageSkipped(true);
reason = BedrockDisconnectReasons.DISCONNECTED;
}
packet.setKickMessage(reason);
this.sendPacketImmediately(packet);
}
}
```
This allows an attacker that should have been disconnected to continue to send malicous packets that lead to expensive deserialization logic. The result is another potential denial of service (DoS) attack vector.
## Patch and Mitigation
We mitigated the first attack vector by ensuring that the Bedrock client can only signal completion of resource pack sending once per session. This was done by modifying the `UpstreamPacketHandler` to check if the `finishedResourcePackSending` flag is already set before proceeding with authentication logic:
```java
package org.geysermc.geyser.network;
// ...
public class UpstreamPacketHandler extends LoggingPacketHandler {
// ...
public PacketSignal handle(ResourcePackClientResponsePacket packet) {
// ...
// highlight-start
if (finishedResourcePackSending) {
session.disconnect("Illegal duplicate resource pack response packet received!");
return PacketSignal.HANDLED;
}
// highlight-end
// ...
switch (packet.getStatus()) {
case COMPLETED -> {
// highlight-start
finishedResourcePackSending = true;
// highlight-end
if (geyser.getConfig().getRemote().authType() != AuthType.ONLINE) {
session.authenticate(session.getAuthData().name());
} else if (!couldLoginUserByName(session.getAuthData().name())) {
// We must spawn the white world
session.connect();
}
geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.network.connect", session.getAuthData().name()));
}
// ...
}
return PacketSignal.HANDLED;
}
// ...
}
```
This ensures that any further attempts to send a `ResourcePackClientResponsePacket` after the first one will result in an immediate disconnect, preventing the creation of multiple downstream sessions.
The second attack vector was mitigated by ensuring that the disconnect logic in the Bedrock protocol library properly closes the underlying Netty channel. This was achieved by modifying the `BedrockServerSession#disconnect` method to schedule a task that closes the session after a timeout, ensuring that the channel is closed after the disconnect packet is sent. Packet serialzation is also stopped immediately for disconnected clients:
```java
package org.cloudburstmc.protocol.bedrock;
// ...
public class BedrockServerSession extends BedrockSession {
private static final int TIMEOUT_SECONDS = SystemPropertyUtil.getInt("org.cloudburstmc.protocol.bedrock.disconnectTimeout", 10);
// ...
public void disconnect(@Nullable String reason, boolean hideReason) {
this.checkForClosed();
DisconnectPacket packet = new DisconnectPacket();
String finalReason;
if (reason == null || hideReason) {
packet.setMessageSkipped(true);
finalReason = BedrockDisconnectReasons.DISCONNECTED;
} else {
finalReason = reason;
}
packet.setKickMessage(finalReason);
this.sendPacketImmediately(packet);
// highlight-start
if (!this.isSubClient()) {
this.getPeer().blackholeInboundPackets();
}
this.getPeer().channel.eventLoop().schedule(() -> {
if (this.isConnected()) {
this.close(finalReason);
}
}, TIMEOUT_SECONDS, TimeUnit.SECONDS);
// highlight-end
}
}
```
Logic was also added to Geyser's `InvalidPacketHandler` to ensure that invalid packets result in an immediate closing of the underlying Netty channel:
```java
package org.geysermc.geyser.network;
// ...
public class InvalidPacketHandler extends ChannelInboundHandlerAdapter {
public static final String NAME = "rak-error-handler";
private final GeyserSession session;
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
Throwable rootCause = Stream.iterate(cause, Throwable::getCause)
.filter(element -> element.getCause() == null)
.findFirst()
.orElse(cause);
GeyserLogger logger = GeyserImpl.getInstance().getLogger();
if (!(rootCause instanceof IllegalArgumentException)) {
// Kick users that cause exceptions
logger.error("Exception caught in session of " + session.bedrockUsername(), cause);
session.disconnect("An internal error occurred!");
// highlight-start
session.forciblyCloseUpstream();
// highlight-end
return;
}
// Kick users that try to send illegal packets
logger.error("Illegal packet from " + session.bedrockUsername(), cause);
session.disconnect("Invalid packet received!");
// highlight-start
session.forciblyCloseUpstream();
// highlight-end
}
}
```
## Long Term Impact
All users of Geyser running outdated builds should update as soon as possible to ensure they are not vulnerable to the attacks described in this post. During the process of investigating this attack, we were made aware of multiple servers being exploited, meaning this is being exploited in the wild. Unlike the previous RakNet amplification attack, this attack is limited in scope to the selected Geyser instance. We expect the number of unpatched instances to decrease over time as Bedrock updates require server owners to update their Geyser instances. As of November 2025, we have not received any recent reports of Geyser instances being targeted by this attack vector, indicating that most instances have been patched.
## Acknowledgements
We thank the community for their patience as we addressed this issue, the server owners who responsibly disclosed this issue to us, the developers at Cloudburst and Geyser that worked to mitigate the issue, all donors for their financial support of Geyser, and Cubecraft and Open Collaboration for their continued financial and operational support of the project.
+8 -4
View File
@@ -134,6 +134,11 @@ const config: Config = {
className: 'header-utilities-link',
position: 'left',
items: [
{
to: 'utilities/config-editor',
label: 'Config Editor',
},
{
to: 'utilities/dump-viewer',
@@ -147,12 +152,12 @@ const config: Config = {
position: 'left',
className: 'header-download-link'
},
{ // Name on mobile sidebar specified in custom.scss
{
href: 'https://github.com/GeyserMC/Geyser',
position: 'right',
className: 'header-github-link'
},
{ // Name on mobile sidebar specified in custom.scss
{
href: 'https://discord.gg/geysermc',
position: 'right',
className: 'header-discord-link'
@@ -170,7 +175,6 @@ const config: Config = {
href: '/',
width: 430,
},
copyright: `Copyright © ${new Date().getFullYear()} GeyserMC. Built with Docusaurus.<br>This website is not an official Minecraft website and is not associated with Mojang Studios or Microsoft. All product and company names are trademarks or registered trademarks of their respective holders. Use of these names does not imply any affiliation or endorsement by them.`,
links: [
{
title: 'Wiki',
@@ -189,7 +193,7 @@ const config: Config = {
},
{
label: 'Other',
to: 'wiki/other/geyserintegratedpack',
to: 'wiki/other/geyseroptionalpack',
},
],
},
+36 -131
View File
@@ -9,13 +9,13 @@
"message": "Enable `clone-remote-port` (or manually set `bedrock port` to the Java port), and connect with the Java IP and port."
},
"providers.templates.ip_and_port": {
"message": "Enable `clone-remote-port` (or manually set `bedrock port` to the Java port) and change `bedrock address` from `0.0.0.0` to your Java server's IP. Connect with the Java IP and port."
"message": "Enable `clone-remote-port` (or manually set `bedrock port` to the Java port), uncomment `bedrock address`, and change `0.0.0.0` to your Java server's IP. Connect with the Java IP and port."
},
"providers.templates.forwarding_option": {
"message": "Offers a working port forwarding option."
},
"providers.templates.java_ip": {
"message": "Change `bedrock address` from `0.0.0.0` to your Java server's IP."
"message": "Make sure your remote address is 'auto', uncomment `bedrock address`, and change `0.0.0.0` to your Java server's IP."
},
"providers.provider.apex_hosting.description": {
"message": "Full auto installation. Go to the Customizations tab in the panel and select 'Enabled' under the 'Geyser Auto Installer' option. Then, restart and connect to your server with your Java IP and port. See [Apex's article](https://apexminecrafthosting.com/geysermc/) for more details."
@@ -53,14 +53,11 @@
"providers.provider.minehut.description": {
"message": "Connect via `bedrock.minehut.com` and do `/join [servername]`, or connect directly via `[servername].bedrock.minehut.gg`."
},
"providers.provider.omgserv.description": {
"message": "Select Geyser in the [Install Menu](https://i.imgur.com/Gewpsrq.png), it will be automatically installed. You can enable floodgate in the [server properties on the dashboard](https://i.imgur.com/jg5mzNj.png)."
},
"providers.provider.piglinhost.description": {
"message": "Order from the [cross-platform servers page](https://piglinhost.com/minecraft-java-hosting.html). Alternatively, contact their support by creating a [support ticket](https://billing.piglinhost.com/submitticket.php?step=2&deptid=5) or via discord for installation and configuration help."
},
"providers.provider.playhosting.description": {
"message": "Tick the 'Enable Bedrock crossplay?' option when changing your server software to automatically install and configure Geyser + Floodgate. For more details, navigate to [help.play.hosting/minecraft/crossplay](https://help.play.hosting/minecraft/crossplay)."
"providers.provider.omgserv.description": {
"message": "Select Geyser in the [Install Menu](https://i.imgur.com/Gewpsrq.png), it will be automatically installed. You can enable floodgate in the [server properties on the dashboard](https://i.imgur.com/jg5mzNj.png)."
},
"providers.provider.pufferfish_host.description": {
"message": "Geyser is installed and configured on all servers by default."
@@ -68,9 +65,6 @@
"providers.provider.server.pro.description": {
"message": "Different instructions for different plans: On VPS, select Geyser in the [Service Type Menu](https://i.imgur.com/loSNmvu.png), Floodgate can be enabled on the dashboard configuration. For manual installation: Using a Premium or Free plan, use the same port as your Java server for the Bedrock port in the configuration file and connect that; for the Free plan, also enable the `clone-remote-port` option. If you are using a PRO or a VPS plan, you can use any port, which can be opened on the Firewall tab."
},
"providers.provider.serverprism.description": {
"message": "Order a [Minecraft server](https://serverprism.com/minecraft-server-hosting) on any plugin-compatible runtime (Paper, Spigot, Purpur, etc.), then install Geyser from the panel's plugin installer. Connect with the same IP and port as your Java server."
},
"providers.provider.snakecraft_hosting.description": {
"message": "Select 'Paper + Geyser with Floodgate' under the Jar Type at checkout to install the Geyser plugin. Players will Connect with the same IP and port as you would on Java."
},
@@ -81,7 +75,7 @@
"message": "Find the plugin in the control panel under the 'VG Recommended' category and restart your server. IP and port are the same as Java."
},
"providers.provider.wisehosting.description": {
"message": "Both auto and manual installation available. Find the GeyserMC presets from the `Addons` tab in the Game Panel. There, click `Install` and restart your server. See [Crossplay FAQ](https://wisehosting.com/help/how-to-install-geysermc-to-your-minecraft-server) for additional details."
"message": "Both auto and manual installation available. Find the GeyserMC presets from the `Properties` tab in the Game Panel. There, click `Install` and restart your server. See [Crossplay FAQ](https://help.wisehosting.com/en/articles/13-how-to-install-geysermc-java-bedrock-crossplay-to-your-server) for additional details."
},
"providers.provider.zaphosting.description": {
"message": "Find the plugin in the control panel and restart your server. IP and port are the same as Java."
@@ -93,7 +87,7 @@
"message": "Need to open a support ticket to get a UDP port, then use that as the `bedrock port`."
},
"providers.provider.bisecthosting.description": {
"message": "Go to the Network tab and copy an available port not in use by other mods. In Geyser's config, under the bedrock section, on the port: line, edit the value to the port you copied. See Bisect's [article](https://www.bisecthosting.com/clients/index.php?rp=/knowledgebase/193/How-to-install-Geyser-and-Floodgate-on-a-Minecraft-Java-server.html) for full instructions. If you still cannot connect after following these instructions, contact Bisect Support, as they reportedly have UDP disabled on some nodes."
"message": "You must have a plan with a dedicated IP. In Geyser's config, uncomment the `bedrock address` and set it to the public IP of your server (e.g. `address: 51.79.129.18`). Leave the port as `19132`. Under the home tab, select 'Enable UDP Network' and restart the server. See Bisect's [article](https://www.bisecthosting.com/clients/index.php?rp=/knowledgebase/193/How-to-install-Geyser-and-Floodgate-on-a-Minecraft-Java-server.html) for full instructions. If you still cannot connect after following these instructions, contact Bisect Support as they reportedly have UDP disabled on some nodes."
},
"providers.provider.bloomhost.description": {
"message": "See [Bloom's documentation](https://docs.bloom.host/plugins/geysermc/) for setup instructions."
@@ -143,9 +137,6 @@
"providers.provider.humbleservers.description": {
"message": "Set the Bedrock port to the Java server's port, or to one of the two extra ports, and connect with that port. If the subdomain doesn't work, use your regular numbered IP address."
},
"providers.provider.kaashosting.description": {
"message": "Automatic and manual installation supported. Go to the `Plugin Installer` tab, search for Geyser and click `Install Automatically`. Connect with the Java IP and port. See [KaasHosting's article](https://www.kaashosting.nl/help/nl/minecraft/hoe-maak-ik-mijn-minecraft-server-crossplay-met-geysermc) for more details."
},
"providers.provider.kekshost.description": {
"message": "Use the default bedrock port (19132) and the server ip to connect on Bedrock edition. No changes to the Geyser config are needed. You can also ask for a new port and use it instead."
},
@@ -162,7 +153,7 @@
"message": "Install Geyser with the dedicated Plugin installer. Use the same port as your Java server in your config. Connect with the same address and port as your Java server."
},
"providers.provider.nfoservers.description": {
"message": "Set `bedrock address` to the server IP in the Geyser config file. As an alternative, you can run Geyser standalone separately on an Unmanaged VDS."
"message": "Uncomment and set `bedrock address` to the server IP in the Geyser config file. As an alternative, you can run Geyser standalone separately on an Unmanaged VDS."
},
"providers.provider.nitrado.description": {
"message": "Get Geyser as a plugin. Add 4 to the Port of the Java server. See [here](https://wiki.nitrado.net/en/How_to_install_GeyserMC_and_Floodgate) for specific instructions."
@@ -204,7 +195,7 @@
"message": "Set the Bedrock port to the Java server's port and connect with that port. Alternatively, request an additional port, or buy a dedicated IP address."
},
"providers.provider.witherhosting.description": {
"message": "Either use the Java server's port, or create a port in the ports manager on the panel and use that for Bedrock. Refer to the hosts [support article](https://my.witherhosting.com/kb/how-to-install-and-use-geysermc-java) for further info."
"message": "Either use the Java server's port, or create a port in the ports manager on the panel and use that for Bedrock. Refer to the hosts [support article](https://support.witherhosting.com/en/article/how-to-install-and-use-geysermc-1xn5l6v/) for further info."
},
"providers.provider.myarena.description": {
"message": "Does seem to be working, but the Java version is too old in order for Geyser to run properly."
@@ -215,41 +206,20 @@
"providers.provider.feather.description": {
"message": "Their proxy network does not support UDP. Therefore, Geyser is not supported. As an alternative, set up a paper server with e.g. playit.gg instead of port forwarding."
},
"providers.provider.freemcserver_net.description": {
"message": "Install Geyser from the Plugins tab, then connect to your server using your Java IP and port."
},
"providers.provider.ultraservers.description": {
"message": "Select 'Paper + Geyser' under the Change version tab. You can connect to your server using the same IP and port as you would on Java. Existing servers can use the Plugins/Minecraft mods tab to install Geyser. See [Crossplay](https://docs.ultraservers.com/minecraft/plugins-mods/crossplay-on-java-and-bedrock) for more information."
},
"providers.provider.bedrockhost.description": {
"message": "Easiest solution is: Go to hosting panel > install new engine > Ready-made solutions and select Geyser. This will install Paper & Geyser-Spigot - no setup needed, just connect with your Java IP and port. See [BedrockHost's article](https://bedrockhost.pl/w/geyser-czyli-serwer-minecraft-java-i-bedrock-w-jednym) for more details or for custom setup instructions (available in Polish)."
},
"providers.provider.simplegamehosting.description": {
"message": "Contact live chat support to open a port and check out the [help center guide](https://help.simplegamehosting.com/how-to-enable-crossplay-with-geyser-on-your-minecraft-server/) for how to install and configure Geyser on your server."
},
"providers.provider.axenthost.description": {
"message": "For a quick installation, navigate to your server Variants tab and select GeyserMC. The server will be automatically reinstalled with Geyser-Spigot alongside a Paper server. For a manual install using any other variant such as Paper, you will need to upload the GeyserMC jar to your server and set the the clone-remote-port option to true. See AxentHost's [guide](https://axenthost.com/knowledgebase/categories/minecraft/create-a-crossplay-server-with-geyser/) to see all the steps."
},
"pages.main.title": {
"message": "Revolutionize Your Minecraft Server"
},
"pages.main.subtitle": {
"message": "Enable clients from Minecraft Bedrock Edition to join your Minecraft Java server"
},
"components.homepage_features.1.line1": {
"message": "Geyser is a program that allows Minecraft: Bedrock Edition clients to join Minecraft: Java Edition servers, allowing for true crossplay between both editions of the game."
"components.homepage_features.1": {
"message": "Geyser is a program that allows Minecraft: Bedrock Edition clients to join Minecraft: Java Edition servers, allowing for true crossplay between both editions of the game. The ultimate goal of this project is to allow Minecraft: Bedrock Edition users to join Minecraft: Java Edition servers as seamlessly as possible."
},
"components.homepage_features.1.line2": {
"message": "The ultimate goal of this project is to allow Minecraft: Bedrock Edition users to join Minecraft: Java Edition servers as seamlessly as possible."
},
"components.homepage_features.2": {
"components.homepage_features.features.2": {
"message": "Geyser acts as a translator which sits between the Bedrock client and the Java server. It takes data from the Bedrock client and translates it into a format the Java server understands and vice versa. Geyser works with any modern Minecraft version and can be installed either as a plugin or ran as a standalone program."
},
"components.homepage_features.3.line1": {
"message": "Geyser can be joined from Bedrock clients on Windows 10/11, iOS, Android, and even consoles. Geyser works with a wide array of hosting providers, but can also be used as its own standalone proxy to join any Minecraft server!"
},
"components.homepage_features.3.line2": {
"message": "If you are a server owner, you can install our Floodgate plugin which allows Xbox Live authenticated Bedrock users to join without a Java Edition account!"
"components.homepage_features.features.3": {
"message": "Geyser can be joined from Bedrock clients on Windows 10/11, iOS, Android, and even consoles. Geyser works with a wide array of hosting providers, but can also be used as its own standalone proxy to join any Minecraft server! If you are a server owner, you can install our Floodgate plugin which allows Xbox Live authenticated Bedrock users to join without a Java Edition account!"
},
"pages.download.title": {
"message": "Download"
@@ -266,11 +236,32 @@
"pages.download.description.geyserconnect": {
"message": "A plugin to allow for Geyser players to connect to your server without needing to use a proxy."
},
"pages.download.description.geyseroptionalpack": {
"message": "An optional Bedrock resource pack to extend Geyser functionality."
},
"pages.download.description.thirdpartycosmetics": {
"message": "An extension that adds support for loading ears and other third party cosmetics on java players"
},
"pages.download.description.emoteoffhand": {
"message": "An extension that allows Bedrock players to switch their offhand and mainhand item by emoting."
"pages.configeditor.noconfigselected.heading": {
"message": "No config selected."
},
"pages.configeditor.noconfigselected.subheading": {
"message": "Upload a file or get started with the default config!"
},
"pages.configeditor.button.defaultconfig": {
"message": "Default"
},
"pages.configeditor.button.upload": {
"message": "Upload"
},
"pages.configeditor.button.export": {
"message": "Export"
},
"pages.configeditor.title": {
"message": "Config Editor"
},
"pages.configeditor.subheading": {
"message": "Edit your Geyser configuration."
},
"pages.dumpviewer.title": {
"message": "Dump Viewer"
@@ -779,91 +770,5 @@
"theme.unlistedContent.message": {
"message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.",
"description": "The unlisted content banner message"
},
"providers.provider.not_listed.description": {
"message": "If your hosting provider is not listed, try enabling the `clone-remote-port` option in the config. Then, restart the server, and try connecting with the same IP and port as on Java Edition. <br> If this does not work, ask your server hosting provider for a UDP port, and use that. For VPS/KVM servers please follow the self-hosting steps."
},
"providers.provider.wasabihosting.description": {
"message": "Install Geyser with the plugin installer. Use the same port as your Java server in the Geyser config. Connect with the same address and port as your Java server."
},
"pages.download.description.hurricane": {
"message": "A plugin with various workarounds for Geyser players that modify the server in order to achieve their goal."
},
"theme.blog.author.pageTitle": {
"message": "{authorName} - {nPosts}",
"description": "The title of the page for a blog author"
},
"theme.blog.authorsList.pageTitle": {
"message": "Authors",
"description": "The title of the authors page"
},
"theme.blog.authorsList.viewAll": {
"message": "View all authors",
"description": "The label of the link targeting the blog authors page"
},
"theme.blog.author.noPosts": {
"message": "This author has not written any posts yet.",
"description": "The text for authors with 0 blog post"
},
"theme.contentVisibility.unlistedBanner.title": {
"message": "Unlisted page",
"description": "The unlisted content banner title"
},
"theme.contentVisibility.unlistedBanner.message": {
"message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.",
"description": "The unlisted content banner message"
},
"theme.contentVisibility.draftBanner.title": {
"message": "Draft page",
"description": "The draft content banner title"
},
"theme.contentVisibility.draftBanner.message": {
"message": "This page is a draft. It will only be visible in dev and be excluded from the production build.",
"description": "The draft content banner message"
},
"providers.provider.arth_hosting.description": {
"message": "Geyser is installed and configured on all servers by default. You can disable it in the 'Manage Plugins' menu."
},
"providers.provider.mcserverhost.description": {
"message": "Under the server configuration, select 'Crossplay' to automatically install Geyser and Floodgate. Join with the connection address. To update Geyser and Floodgate, replace the plugin jars in the server manager and restart the server."
},
"providers.provider.vemox_hosting.description": {
"message": "Full automatic installation. Go to one of the panel options and select the option to enable GeyserMC. Then, restart and connect to your server using your Java IP and port."
},
"providers.provider.mcforfree.de.description": {
"message": "Create an extra port in the game panel, then change the `port` in the `bedrock` section to the newly created port. To connect on Bedrock edition, use the Java server's IP and the port you've created. It may take a few minutes for the port to become active."
},
"providers.provider.modrinth.description": {
"message": "Check [Modrinth's documentation](https://support.modrinth.com/en/articles/10986613-adding-geyser-to-your-server) for specific instructions."
},
"providers.provider.orionnodes.description": {
"message": "Open a port yourself from the network page in the game panel, use that port in the bedrock section of the Geyser config."
},
"providers.provider.papernodes.description": {
"message": "Enable clone-remote-port (or manually set the Bedrock port to the Java port), and connect with the Java IP and port. Alternatively, you can contact the host to request an additional port or a dedicated IP."
},
"providers.provider.wepwawet.description": {
"message": "Add a new port in the Network tab. Use this new port as the bedrock port."
},
"pages.download.description.offhandextension": {
"message": "An extension that allows Bedrock players to switch their offhand and mainhand item by emoting."
},
"pages.download.description.rainbow": {
"message": "A Minecraft mod to generate Geyser item mappings and bedrock resourcepacks for use with Geyser's custom item API (v2)."
},
"pages.download.description.hydraulic": {
"message": "A companion mod to Geyser which allows for Bedrock players to join modded Minecraft: Java Edition servers."
},
"pages.download.description.thunder": {
"message": "A java application to convert simple Java Edition resource packs to Bedrock Edition ones."
},
"pages.dumpviewer.extensions": {
"message": "Extensions"
},
"pages.dumpviewer.extensions.noextensions": {
"message": "No extensions to show."
},
"pages.dumpviewer.extensions.helptext": {
"message": "Click on an extension to view more information."
}
}
@@ -182,9 +182,5 @@
"sidebar.geyserSidebar.category.Geyser API": {
"message": "Geyser API",
"description": "The label for category Geyser API in sidebar geyserSidebar"
},
"sidebar.geyserSidebar.category.Custom Resource Packs": {
"message": "Custom Resource Packs",
"description": "The label for category Custom Resource Packs in sidebar geyserSidebar"
}
}
+1 -69
View File
@@ -1,74 +1,6 @@
{
"link.title.Wiki": {
"message": "Wiki",
"description": "The title of the footer links column with title=Wiki in the footer"
},
"link.title.Downloads": {
"message": "Downloads",
"description": "The title of the footer links column with title=Downloads in the footer"
},
"link.title.Community": {
"message": "Community",
"description": "The title of the footer links column with title=Community in the footer"
},
"link.title.More": {
"message": "More",
"description": "The title of the footer links column with title=More in the footer"
},
"link.item.label.Geyser": {
"message": "Geyser",
"description": "The label of footer link with label=Geyser linking to download?project=geyser"
},
"link.item.label.Floodgate": {
"message": "Floodgate",
"description": "The label of footer link with label=Floodgate linking to download?project=floodgate"
},
"link.item.label.REST APIs": {
"message": "REST APIs",
"description": "The label of footer link with label=REST APIs linking to wiki/api/api.geysermc.org/global-api"
},
"link.item.label.Other": {
"message": "Other",
"description": "The label of footer link with label=Other linking to download?project=other-projects"
},
"link.item.label.Crowdin": {
"message": "Crowdin",
"description": "The label of footer link with label=Crowdin linking to https://translate.geysermc.org/"
},
"link.item.label.Discord": {
"message": "Discord",
"description": "The label of footer link with label=Discord linking to https://discord.gg/geysermc"
},
"link.item.label.GitHub": {
"message": "GitHub",
"description": "The label of footer link with label=GitHub linking to https://github.com/GeyserMC/Geyser"
},
"link.item.label.Reddit": {
"message": "Reddit",
"description": "The label of footer link with label=Reddit linking to https://www.reddit.com/r/GeyserMC/"
},
"link.item.label.Twitter": {
"message": "Twitter",
"description": "The label of footer link with label=Twitter linking to https://twitter.com/Geyser_MC"
},
"link.item.label.Blog": {
"message": "Blog",
"description": "The label of footer link with label=Blog linking to blog"
},
"link.item.label.Donate": {
"message": "Donate",
"description": "The label of footer link with label=Donate linking to https://opencollective.com/geysermc"
},
"link.item.label.Global Linking": {
"message": "Global Linking",
"description": "The label of footer link with label=Global Linking linking to https://link.geysermc.org/"
},
"logo.alt": {
"message": "GeyserMC logo",
"description": "The alt text of footer logo"
},
"copyright": {
"message": "Copyright © 2026 GeyserMC. Built with Docusaurus.<br>This website is not an official Minecraft website and is not associated with Mojang Studios or Microsoft. All product and company names are trademarks or registered trademarks of their respective holders. Use of these names does not imply any affiliation or endorsement by them.",
"message": "Copyright © 2024 GeyserMC. Built with Docusaurus.",
"description": "The footer copyright"
}
}
@@ -39,6 +39,10 @@
"message": "Other",
"description": "Navbar item with label Other"
},
"item.label.Config Editor": {
"message": "Config Editor",
"description": "Navbar item with label Config Editor"
},
"item.label.Dump Viewer": {
"message": "Dump Viewer",
"description": "Navbar item with label Dump Viewer"
+23 -26
View File
@@ -23,33 +23,31 @@
"typecheck": "tsc"
},
"dependencies": {
"@docusaurus/core": "3.6.3",
"@docusaurus/preset-classic": "3.6.3",
"@fortawesome/fontawesome-svg-core": "6.5.1",
"@fortawesome/free-brands-svg-icons": "6.5.1",
"@fortawesome/free-regular-svg-icons": "6.5.1",
"@fortawesome/free-solid-svg-icons": "6.5.1",
"@fortawesome/react-fontawesome": "0.2.0",
"@docusaurus/core": "^3.4.0",
"@docusaurus/preset-classic": "^3.4.0",
"@fortawesome/fontawesome-svg-core": "^6.5.1",
"@fortawesome/free-brands-svg-icons": "^6.5.1",
"@fortawesome/free-regular-svg-icons": "^6.5.1",
"@fortawesome/free-solid-svg-icons": "^6.5.1",
"@fortawesome/react-fontawesome": "^0.2.0",
"@kas-tle/docusaurus-og": "https://github.com/Kas-tle/docusaurus-og",
"@mdx-js/react": "3.0.0",
"clsx": "1.2.1",
"docusaurus-plugin-openapi-docs": "4.3.0",
"docusaurus-theme-openapi-docs": "4.3.0",
"prism-react-renderer": "2.1.0",
"react": "18.3.1",
"react-dom": "18.3.1",
"@mdx-js/react": "^3.0.0",
"clsx": "^1.2.1",
"docusaurus-plugin-openapi-docs": "^3.0.1",
"docusaurus-theme-openapi-docs": "^3.0.1",
"prism-react-renderer": "^2.1.0",
"react": "^18.0.0",
"react-decision-tree-flow": "^2.1.0",
"react-dom": "^18.0.0",
"react-markdown": "^9.0.0"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^3.6.3",
"@docusaurus/tsconfig": "^3.6.3",
"@docusaurus/types": "^3.6.3",
"docusaurus-plugin-sass": "0.2.5",
"sass": "1.77.8",
"typescript": "5.7.2"
},
"resolutions": {
"postman-code-generators": "1.14.0"
"@docusaurus/module-type-aliases": "^3.4.0",
"@docusaurus/tsconfig": "^3.4.0",
"@docusaurus/types": "^3.4.0",
"docusaurus-plugin-sass": "^0.2.5",
"sass": "^1.77.8",
"typescript": "~5.2.2"
},
"browserslist": {
"production": [
@@ -64,7 +62,6 @@
]
},
"engines": {
"node": ">=22.0"
},
"packageManager": "yarn@4.5.3"
"node": ">=18.0"
}
}
+5 -4
View File
@@ -68,6 +68,10 @@ const sidebars: SidebarsConfig = {
{
type: 'category',
label: 'Configuring Geyser',
link: {
type: 'doc',
id: 'geyser/understanding-the-config',
},
items: [
'geyser/commands',
'geyser/translations',
@@ -95,7 +99,6 @@ const sidebars: SidebarsConfig = {
id: 'geyser/custom-resource-packs'
},
items: [
'geyser/packs',
'geyser/custom-items',
'geyser/custom-blocks',
'geyser/custom-skulls',
@@ -132,12 +135,10 @@ const sidebars: SidebarsConfig = {
'other/index',
'other/geyserconnect',
'other/thirdpartycosmetics',
'other/geyserintegratedpack',
'other/geyseroptionalpack',
'other/community-geyser-projects',
'other/hurricane',
'other/rainbow',
'other/hydraulic',
'other/thunder',
'other/test-server',
'other/developer-guide',
'other/discord-bot-usage'
-25
View File
@@ -1,25 +0,0 @@
import clsx from 'clsx';
import { PropsWithChildren } from 'react';
import styles from "./styles.module.scss";
interface HomepageFeatureProps {
title: string;
image?: string;
flipped?: boolean;
}
export const HomepageFeature: React.FC<PropsWithChildren<HomepageFeatureProps>> = ({ title, image, flipped, children }) => {
return (
<div className={clsx(styles.feature, { [styles.flipped]: flipped })}>
<div className={clsx(styles.content, "text--left padding-horiz--md")}>
<h3 className={styles.title}>{title}</h3>
{children}
</div>
{image && (
<div>
<img src={image} alt={title} />
</div>
)}
</div>
);
}
@@ -1,40 +0,0 @@
.feature {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
}
.feature.flipped > *:first-child {
order: 2;
}
.feature.flipped > *:last-child {
order: 1;
}
.content {
margin-top: auto;
margin-bottom: auto;
}
.title {
font-size: 30px;
}
@media (max-width: 768px) {
.feature {
grid-template-columns: 1fr;
}
.feature > *:first-child {
order: 2;
}
.feature > *:last-child {
order: 1;
}
.title {
margin-top: 15px;
}
}
+78
View File
@@ -0,0 +1,78 @@
import clsx from 'clsx';
import Heading from '@theme/Heading';
import styles from './styles.module.scss';
import Crossplatform0Img from '@site/static/img/site/crossplatform_0.png';
import Crossplatform1Img from '@site/static/img/site/crossplatform_1.png';
import Crossplatform2Img from '@site/static/img/site/crossplatform_2.png';
import Translate from '@docusaurus/Translate';
type FeatureItem = {
title: string;
image?: string;
description: JSX.Element;
index?: number;
};
const FeatureList: FeatureItem[] = [
{
title: 'What is Geyser?',
image: Crossplatform2Img,
description: (
<>
<Translate id="components.homepage_features.1">Geyser is a program that allows Minecraft: Bedrock Edition clients to join Minecraft: Java Edition servers, allowing for true crossplay between both editions of the game. The ultimate goal of this project is to allow Minecraft: Bedrock Edition users to join Minecraft: Java Edition servers as seamlessly as possible.</Translate>
</>
),
},
{
title: 'How does it work?',
image: Crossplatform1Img,
description: (
<>
<Translate id='components.homepage_features.features.2'>Geyser acts as a translator which sits between the Bedrock client and the Java server. It takes data from the Bedrock client and translates it into a format the Java server understands and vice versa. Geyser works with any modern Minecraft version and can be installed either as a plugin or ran as a standalone program.</Translate>
</>
),
},
{
title: 'Join from anywhere',
image: Crossplatform0Img,
description: (
<>
<Translate id='components.homepage_features.features.3'>Geyser can be joined from Bedrock clients on Windows 10/11, iOS, Android, and even consoles. Geyser works with a wide array of hosting providers, but can also be used as its own standalone proxy to join any Minecraft server! If you are a server owner, you can install our Floodgate plugin which allows Xbox Live authenticated Bedrock users to join without a Java Edition account!</Translate>
</>
),
},
];
function Feature({ title, image, description, index }: FeatureItem) {
const Content = () => (
<div className="text--left padding-horiz--md">
<Heading as="h3">{title}</Heading>
<p>{description}</p>
</div>
);
const Image = () => (
image &&
<div className="column text--left">
<img src={image} alt={title} />
</div>
);
return (
<div className={clsx('column')}>
{index % 2 === 0 ? <><Image /><Content /></> : <><Content /><Image /></>}
</div>
);
}
export default function HomepageFeatures(): JSX.Element {
return (
<section className={styles.features}>
<div className="container">
<div className="row">
{FeatureList.map((props, idx) => (
<Feature key={idx} {...props} index={idx} />
))}
</div>
</div>
</section>
);
}
@@ -0,0 +1,11 @@
.features {
display: flex;
align-items: center;
padding: 2rem 0;
width: 100%;
}
.featureSvg {
height: 200px;
width: 200px;
}
+1 -7
View File
@@ -16,10 +16,9 @@ interface ProjectDownloadProps {
[key: string]: { url: string, file: string };
};
gridColumns?: number;
warning?: React.ReactNode;
}
export const ProjectDownload: React.FC<ProjectDownloadProps> = ({ projectId, description, setup, downloadsInfo, additionalDownloads, gridColumns, warning }) => {
export const ProjectDownload: React.FC<ProjectDownloadProps> = ({ projectId, description, setup, downloadsInfo, additionalDownloads, gridColumns }) => {
const [platformInfo, setPlatformInfo] = useState<Downloads.Builds>({
project_id: '',
project_name: '',
@@ -80,11 +79,6 @@ export const ProjectDownload: React.FC<ProjectDownloadProps> = ({ projectId, des
<Column>
<h3>Build #{latestBuild.build} · {new Date(latestBuild.time).toLocaleDateString()}:</h3>
<Grid elementsPerRow={gridColumns || 2} gap="8px">
{ warning &&
<div className='warning-box'>
{ warning }
</div>
}
{ setup &&
<a href={setup} className='no-underline setup-button large-button'>
<b><FontAwesomeIcon icon={faBook}/> Setup Instructions</b>
+14 -26
View File
@@ -14,37 +14,25 @@ export const Provider = ({ type }) => {
const hostingProviders: HostingProvider[] = providersData[type as ProviderType]
return (
<table>
<thead>
<tr>
<th>Provider</th>
<th>Description</th>
</tr>
</thead>
<tbody>
{hostingProviders.map((provider: HostingProvider) => (
<tr>
<td>
<a href={provider.url}>{provider.name}</a>
</td>
<td>
{provider.description != null ? (
<ReactMarkdown children={provider.description} components={{ p: noP }} />
) : (
''
)}
</td>
</tr>
))}
</tbody>
</table>
<div>
<ul>{hostingProviders.map((provider: HostingProvider) => (
<li>
<a href={provider.url}>{provider.name}</a>
{provider.description != null ? (
<ReactMarkdown children={`&nbsp;&hyphen; ${provider.description}`} components={{ p: noP }} />
) : (
''
)}
</li>
))}</ul>
</div>
)
}
export const ProviderSelector = () => {
const providers: HostingProvider[] = [
...Object.values(providersData.built_in),
...Object.values(providersData.support),
...Object.values(providersData.support),
...Object.values(providersData.no_support)
].flat().sort((a, b) => a.name.localeCompare(b.name));
@@ -55,7 +43,7 @@ export const ProviderSelector = () => {
message: "If your hosting provider is not listed, try enabling the `clone-remote-port` option in the config. Then, restart the server, and try connecting with the same IP and port as on Java Edition. <br> If this does not work, ask your server hosting provider for a UDP port, and use that. For VPS/KVM servers please follow the self-hosting steps."
})
} as HostingProvider);
const [selectedProvider, setSelectedProvider] = useState(null);
@@ -0,0 +1,7 @@
export interface StepData {
path: string[];
}
export default interface StepProps {
data: StepData;
}
@@ -0,0 +1,64 @@
import { Controls, Step, useControls, Wizard } from 'react-decision-tree-flow'
import Step1 from './steps/Step1'
import Step2 from './steps/Step2'
import Step3 from './steps/Step3'
import Error from './steps/Error'
import { useEffect, useState } from 'react'
import { StepData } from './StepProps'
import MarkDownStep from './steps/MarkDownStep'
// React components for each step
const stepComponents = [
Step1,
Step2,
Step3,
Error
]
// Build the steps object from the stepComponents array
function formatStepName(name: string): string {
return name.charAt(0).toLowerCase() + name.slice(1)
}
let steps = Object.fromEntries(stepComponents.map((Component) => [formatStepName(Component.name), Component]))
// Add the markdown steps
steps = {
//test: MarkDownStep(Test),
...steps
}
// Make a tree so all steps can go to all others
const tree = Object.fromEntries(Object.keys(steps).map((key, i, arr) => {
return [key, arr]
}))
function TreeInternals(): JSX.Element {
const [data, setData] = useState<StepData>({
path: []
})
const { step } = useControls();
useEffect(() => {
if (step == 'internalStep') {
console.log()
}
setData(data => ({...data, path: [...data.path, step as string]}))
}, [step])
return (
<>
{Object.entries(steps).map(([name, Component]) => <Step key={name} name={name}><Component data={data}/></Step>)}
</>
)
}
export default function TroubleshootingTree(): JSX.Element {
return (
<Wizard tree={tree} first={Object.keys(steps)[0]}>
<TreeInternals />
</Wizard>
)
}
@@ -0,0 +1,16 @@
import { useControls } from "react-decision-tree-flow";
import StepProps from "../StepProps";
export default function Error({ data }: StepProps): JSX.Element {
const { step, tree, destinations, back } = useControls();
return (
<>
I am error
<br />
Path: {data.path.join(' -> ')}
<br />
<button onClick={() => destinations.step1({...data, path: [...data.path, step]})}>Go back to start</button>
</>
)
}
@@ -0,0 +1,10 @@
import { useControls } from "react-decision-tree-flow";
import StepProps from "../StepProps";
export default function MarkDownStep(Component: any): Function {
return function InternalStep({ data }: StepProps): JSX.Element {
const { step, tree, destinations, back } = useControls();
return (<Component step={step} tree={tree} destinations={destinations} back={back} data={data}/>)
}
}
@@ -0,0 +1,27 @@
import { useControls } from "react-decision-tree-flow";
import StepProps from "../StepProps";
export default function OwnerPrerequesites({ data }: StepProps): JSX.Element {
const { step, tree, destinations, back } = useControls();
return (
<>
# Before we start...
Are you hosting a Geyser instance yourself?
You should click "Yes" if you...:
- ...own and operate a Minecraft: Java edition server with the Geyser plugin/mod installed.
- ...have a Geyser-Standalone / Geyser-ViaProxy instance set up to connect to other servers.
- ...use any variant of Geyser on any supported platform.
If you are NOT hosting your own Geyser instance or server - and are intead connecting to someone's server -
then please contact the server administrator for help.
<br />
// TODO add "return" button
<button onClick={() => destinations.step2({...data, path: [...data.path, step]})}>Go to Step 2</button>
</>
)
}
@@ -0,0 +1,14 @@
import { useControls } from "react-decision-tree-flow";
import StepProps from "../StepProps";
export default function Step1({ data }: StepProps): JSX.Element {
const { step, tree, destinations, back } = useControls();
return (
<>
I am step 1
<br />
<button onClick={() => destinations.step2({...data, path: [...data.path, step]})}>Go to Step 2</button>
</>
)
}
@@ -0,0 +1,17 @@
import { useControls } from "react-decision-tree-flow";
import StepProps from "../StepProps";
export default function Step2({ data }: StepProps): JSX.Element {
const { step, tree, destinations, back } = useControls();
return (
<>
I am step 2
<br />
<div>
<button onClick={() => destinations.error({...data, path: [...data.path, step]})}>Go to error</button>
<button onClick={() => destinations.step3({...data, path: [...data.path, step]})}>Go to Step 3</button>
</div>
</>
)
}
@@ -0,0 +1,12 @@
import { useControls } from "react-decision-tree-flow";
import StepProps from "../StepProps";
export default function Step3({ data }: StepProps): JSX.Element {
const { step, tree, destinations, back } = useControls();
return (
<>
I am step 3. No steps after me!
</>
)
}
@@ -0,0 +1,116 @@
steps:
init: u owner?
"""
// TODO figure out steps; simplify language
# Before we start...
Are you hosting a Geyser instance yourself?
You should click "Yes" if you...:
- ...own and operate a Minecraft: Java edition server with the Geyser plugin/mod installed.
- ...have a Geyser-Standalone / Geyser-ViaProxy instance set up to connect to other servers.
- ...use any variant of Geyser on any supported platform.
If you are NOT hosting your own Geyser instance or server - and are intead connecting to someone's server -
then please contact the server administrator for help.
options: y/n -> y: start troubleshooting; n -> show a link to send to administrator
"""
then: u using right guide?
"""
any errors in your log? do you see a connection attempt? conntest command?
"""
1. Toubleshooting start
Self hosting vs minecraft server hosting provider
"""
Hosting provider:
Select this option if you are using a Minecraft server hosting provider that
provides you with a Minecraft server.
Self-Hosted @ home:
Select this option if you are hosting on your own Windows/Linux/MacOS computer,
server located at your location.
Self-Hosted @ nothome:
Applies for KVM/VPS/Bare-Metal servers (and similar) that are not located at your location.
"""
-------------------------------------------------------------------------------
Hosting provider:
1. Select provider (dropdown w. search / not listed)
Non-Listed:
- recommend clone-remote-port, do basic dump checks for bad options/system properties
- pls contact host!
"""
We unfortunately do not have instructions available for the server hosting provider you're using.
However, we recommend trying these configurations:
1. Runnning Geyser on the Java server port
- Open the Geyser configuration, and set `clone-remote-port` to `true`. Then, save the changes, and restart the server.
- Verify connecting works:
-> directly connect with the java server ip and port
or
-> connectiontest command
If none of these options work, please contact your server hosting provider for help on how to set up Geyser.
"""
Listed:
- geyser dump
-> configuration check (match with instructions???)
-> bad options: proxy protocol; remote address
-> check for system properties
- options:
-> re-ask for a geyser dump (verify correct changes)
-> still not working; continue troubleshooting
-> errors in log?
-> else: contact host pls
-> works now -> send to feedback page?
OR: unable to get dump
-> is server running? log???
Options:
-> addr. in use -> show setup steps
-> port in use (-> check for voice plugins/query???)
-> startup errors -> join discord/open github issue
-> ...
IF server running/config correct:
-> ensure connection to proper ip/port
-> contact server hosting provider for help
-> join discord if unclear
-------------------------------------------------------------------------------
Self-Hosted @ home:
First stage: Gather information!
Which OS are you hosting on? Linux/Win/MacOS
-> Windows
-> MacOS
-> Linux
-------------------------------------------------------------------------------
+1 -33
View File
@@ -16,7 +16,6 @@
--ifm-color-primary-light: #33925d;
--ifm-color-primary-lighter: #359962;
--ifm-color-primary-lightest: #3cad6e;
--ifm-color-warning: #e4f126;
--ifm-code-font-size: 95%;
--ifm-footer-color: rgb(238, 249, 253);
--ifm-footer-background-color: #303846;
@@ -75,7 +74,6 @@ html[data-theme='dark'] {
display: inline-block;
background-color: var(--ifm-navbar-link-color);
mask-image: $url;
mask-repeat: no-repeat;
transition: background-color var(--ifm-transition-fast) var(--ifm-transition-timing-default);
}
@@ -89,11 +87,7 @@ html[data-theme='dark'] {
}
.header-discord-link {
@include header-link(24px, 24px, url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M524.5 69.8a1.5 1.5 0 0 0 -.8-.7A485.1 485.1 0 0 0 404.1 32a1.8 1.8 0 0 0 -1.9 .9 337.5 337.5 0 0 0 -14.9 30.6 447.8 447.8 0 0 0 -134.4 0 309.5 309.5 0 0 0 -15.1-30.6 1.9 1.9 0 0 0 -1.9-.9A483.7 483.7 0 0 0 116.1 69.1a1.7 1.7 0 0 0 -.8 .7C39.1 183.7 18.2 294.7 28.4 404.4a2 2 0 0 0 .8 1.4A487.7 487.7 0 0 0 176 479.9a1.9 1.9 0 0 0 2.1-.7A348.2 348.2 0 0 0 208.1 430.4a1.9 1.9 0 0 0 -1-2.6 321.2 321.2 0 0 1 -45.9-21.9 1.9 1.9 0 0 1 -.2-3.1c3.1-2.3 6.2-4.7 9.1-7.1a1.8 1.8 0 0 1 1.9-.3c96.2 43.9 200.4 43.9 295.5 0a1.8 1.8 0 0 1 1.9 .2c2.9 2.4 6 4.9 9.1 7.2a1.9 1.9 0 0 1 -.2 3.1 301.4 301.4 0 0 1 -45.9 21.8 1.9 1.9 0 0 0 -1 2.6 391.1 391.1 0 0 0 30 48.8 1.9 1.9 0 0 0 2.1 .7A486 486 0 0 0 610.7 405.7a1.9 1.9 0 0 0 .8-1.4C623.7 277.6 590.9 167.5 524.5 69.8zM222.5 337.6c-29 0-52.8-26.6-52.8-59.2S193.1 219.1 222.5 219.1c29.7 0 53.3 26.8 52.8 59.2C275.3 311 251.9 337.6 222.5 337.6zm195.4 0c-29 0-52.8-26.6-52.8-59.2S388.4 219.1 417.9 219.1c29.7 0 53.3 26.8 52.8 59.2C470.7 311 447.5 337.6 417.9 337.6z"/></svg>'));
&::before { // Fixes the Discord icon being a little shorter than the others causing an offset
mask-position: 0 2px;
}
@include header-link(32px, 26px, url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M524.5 69.8a1.5 1.5 0 0 0 -.8-.7A485.1 485.1 0 0 0 404.1 32a1.8 1.8 0 0 0 -1.9 .9 337.5 337.5 0 0 0 -14.9 30.6 447.8 447.8 0 0 0 -134.4 0 309.5 309.5 0 0 0 -15.1-30.6 1.9 1.9 0 0 0 -1.9-.9A483.7 483.7 0 0 0 116.1 69.1a1.7 1.7 0 0 0 -.8 .7C39.1 183.7 18.2 294.7 28.4 404.4a2 2 0 0 0 .8 1.4A487.7 487.7 0 0 0 176 479.9a1.9 1.9 0 0 0 2.1-.7A348.2 348.2 0 0 0 208.1 430.4a1.9 1.9 0 0 0 -1-2.6 321.2 321.2 0 0 1 -45.9-21.9 1.9 1.9 0 0 1 -.2-3.1c3.1-2.3 6.2-4.7 9.1-7.1a1.8 1.8 0 0 1 1.9-.3c96.2 43.9 200.4 43.9 295.5 0a1.8 1.8 0 0 1 1.9 .2c2.9 2.4 6 4.9 9.1 7.2a1.9 1.9 0 0 1 -.2 3.1 301.4 301.4 0 0 1 -45.9 21.8 1.9 1.9 0 0 0 -1 2.6 391.1 391.1 0 0 0 30 48.8 1.9 1.9 0 0 0 2.1 .7A486 486 0 0 0 610.7 405.7a1.9 1.9 0 0 0 .8-1.4C623.7 277.6 590.9 167.5 524.5 69.8zM222.5 337.6c-29 0-52.8-26.6-52.8-59.2S193.1 219.1 222.5 219.1c29.7 0 53.3 26.8 52.8 59.2C275.3 311 251.9 337.6 222.5 337.6zm195.4 0c-29 0-52.8-26.6-52.8-59.2S388.4 219.1 417.9 219.1c29.7 0 53.3 26.8 52.8 59.2C470.7 311 447.5 337.6 417.9 337.6z"/></svg>'));
}
.header-utilities-link {
@@ -112,16 +106,6 @@ html[data-theme='dark'] {
@include header-link(22px, 25px, url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M96 0C43 0 0 43 0 96V416c0 53 43 96 96 96H384h32c17.7 0 32-14.3 32-32s-14.3-32-32-32V384c17.7 0 32-14.3 32-32V32c0-17.7-14.3-32-32-32H384 96zm0 384H352v64H96c-17.7 0-32-14.3-32-32s14.3-32 32-32zm32-240c0-8.8 7.2-16 16-16H336c8.8 0 16 7.2 16 16s-7.2 16-16 16H144c-8.8 0-16-7.2-16-16zm16 48H336c8.8 0 16 7.2 16 16s-7.2 16-16 16H144c-8.8 0-16-7.2-16-16s7.2-16 16-16z"/></svg>'));
}
@media screen and (max-width: 996px) { // Magic numbers! This was the value which caused the site to go to mobile navigation
.header-discord-link::after {
content: 'Discord'
}
.header-github-link::after {
content: 'GitHub'
}
}
.api-method>.menu__link {
align-items: center;
justify-content: start;
@@ -174,7 +158,6 @@ html[data-theme='dark'] {
align-items: center;
width: 100%;
position: relative;
cursor: pointer;
h3 {
margin: 0;
@@ -320,16 +303,6 @@ html[data-theme='dark'] {
}
}
.warning-box {
width: 100%;
border-left: 3px solid var(--ifm-color-warning);
text-align: center;
font-size: 18px;
padding-top: 5px;
padding-bottom: 5px;
padding-left: 5px;
}
.tabs {
flex-wrap: wrap;
border-bottom-color: var(--ifm-horizontal-line-color);
@@ -371,9 +344,4 @@ html[data-theme='dark'] {
border-radius: var(--ifm-global-radius);
color: #fff
}
}
[data-theme='light'] img[src$='#gh-dark-mode-only'],
[data-theme='dark'] img[src$='#gh-light-mode-only'] {
display: none;
}
+25 -130
View File
@@ -1,8 +1,6 @@
import { translate } from "@docusaurus/Translate"
import { Providers } from "../types/providers"
// Do not modify the structure of this file without updating the extraction logic in create-providers-json.ts
const descriptionTemplates = {
default: translate({
id: 'providers.templates.default',
@@ -10,7 +8,7 @@ const descriptionTemplates = {
}),
ipAndPort: translate({
id: 'providers.templates.ip_and_port',
message: "Enable `clone-remote-port` (or manually set `bedrock port` to the Java port) and change `bedrock address` from `0.0.0.0` to your Java server's IP. Connect with the Java IP and port."
message: "Enable `clone-remote-port` (or manually set `bedrock port` to the Java port), uncomment `bedrock address`, and change `0.0.0.0` to your Java server's IP. Connect with the Java IP and port."
}),
forwardingOption: translate({
id: 'providers.templates.forwarding_option',
@@ -18,7 +16,7 @@ const descriptionTemplates = {
}),
javaIp: translate({
id: 'providers.templates.java_ip',
message: "Change `bedrock address` from `0.0.0.0` to your Java server's IP."
message: "Make sure your remote address is 'auto', uncomment `bedrock address`, and change `0.0.0.0` to your Java server's IP."
})
}
@@ -35,10 +33,7 @@ export const providersData: Providers = {
{
name: 'Arth Hosting',
url: 'https://arthmc.xyz/',
description: translate({
id: 'providers.provider.arth_hosting.description',
message: "Geyser is installed and configured on all servers by default. You can disable it in the 'Manage Plugins' menu."
})
description: "Geyser is installed and configured on all servers by default. You can disable it in the 'Manage Plugins' menu."
},
{
name: 'Aternos',
@@ -49,23 +44,7 @@ export const providersData: Providers = {
})
},
{
name: 'AxentHost',
url: 'https://axenthost.com/games/minecraft/',
description: translate({
id: 'providers.provider.axenthost.description',
message: "For a quick installation, navigate to your server Variants tab and select GeyserMC. The server will be automatically reinstalled with Geyser-Spigot alongside a Paper server. For a manual install using any other variant such as Paper, you will need to upload the GeyserMC jar to your server and set the the clone-remote-port option to true. See AxentHost's [guide](https://axenthost.com/knowledgebase/categories/minecraft/create-a-crossplay-server-with-geyser/) to see all the steps."
})
},
{
name: 'BedrockHost',
url: 'https://bedrockhost.pl/',
description: translate({
id: 'providers.provider.bedrockhost.description',
message: "Easiest solution is: Go to hosting panel > install new engine > Ready-made solutions and select Geyser. This will install Paper & Geyser-Spigot - no setup needed, just connect with your Java IP and port. See [BedrockHost's article](https://bedrockhost.pl/w/geyser-czyli-serwer-minecraft-java-i-bedrock-w-jednym) for more details or for custom setup instructions (available in Polish)."
})
},
{
name: 'CloudNord',
name: 'Cloud Nord',
url: 'https://cloudnord.net/',
description: translate({
id: 'providers.provider.cloud_nord.description',
@@ -96,14 +75,6 @@ export const providersData: Providers = {
message: "Install Geyser in the exaroton plugin list and connect to your server with your Java IP and port. See [exaroton's article](https://support.exaroton.com/hc/en-us/articles/360019857918-Geyser) for more details."
})
},
{
name: 'FreeMcServer.net',
url: 'https://freemcserver.net',
description: translate({
id: 'providers.provider.freemcserver_net.description',
message: "Install Geyser from the Plugins tab, then connect to your server using your Java IP and port."
})
},
{
name: 'GGServers',
url: 'https://ggservers.com',
@@ -112,14 +83,6 @@ export const providersData: Providers = {
message: "Can be installed to any server from their auto plugin setups. No further configuration needed."
})
},
{
name: 'KaasHosting',
url: 'https://www.kaashosting.nl/minecraft-servers',
description: translate({
id: 'providers.provider.kaashosting.description',
message: "Automatic and manual installation supported. Go to the `Plugin Installer` tab, search for Geyser and click `Install Automatically`. Connect with the Java IP and port. See [KaasHosting's article](https://www.kaashosting.nl/help/nl/minecraft/hoe-maak-ik-mijn-minecraft-server-crossplay-met-geysermc) for more details."
})
},
{
name: 'Lilypad',
url: 'https://lilypad.gg',
@@ -129,11 +92,11 @@ export const providersData: Providers = {
})
},
{
name: 'MCServerHost',
url: 'https://mcserverhost.com/',
name: 'MCProHosting',
url: 'https://mcprohosting.com/',
description: translate({
id: 'providers.provider.mcserverhost.description',
message: "Under the server configuration, select 'Crossplay' to automatically install Geyser and Floodgate. Join with the connection address. To update Geyser and Floodgate, replace the plugin jars in the server manager and restart the server."
id: 'providers.provider.mcprohosting.description',
message: "Click 'Enable Bedrock Support' on the server dashboard and follow the steps. For manual installation: Add 'Destination Port' `19132` with 'Protocol UDP' to the port forward mapping and connect to the given source port."
})
},
{
@@ -152,14 +115,6 @@ export const providersData: Providers = {
message: "Connect via `bedrock.minehut.com` and do `/join [servername]`, or connect directly via `[servername].bedrock.minehut.gg`."
})
},
{
name: 'OMGServ',
url: 'https://www.omgserv.com/en/',
description: translate({
id: 'providers.provider.omgserv.description',
message: "Select Geyser in the [Install Menu](https://i.imgur.com/Gewpsrq.png), it will be automatically installed. You can enable floodgate in the [server properties on the dashboard](https://i.imgur.com/jg5mzNj.png)."
})
},
{
name: 'Physgun',
url: 'https://physgun.com/',
@@ -174,11 +129,11 @@ export const providersData: Providers = {
})
},
{
name: 'Play Hosting',
url: 'https://play.hosting',
name: 'OMGServ',
url: 'https://www.omgserv.com/en/',
description: translate({
id: 'providers.provider.playhosting.description',
message: "Tick the 'Enable Bedrock crossplay?' option when changing your server software to automatically install and configure Geyser + Floodgate. For more details, navigate to [help.play.hosting/minecraft/crossplay](https://help.play.hosting/minecraft/crossplay)."
id: 'providers.provider.omgserv.description',
message: "Select Geyser in the [Install Menu](https://i.imgur.com/Gewpsrq.png), it will be automatically installed. You can enable floodgate in the [server properties on the dashboard](https://i.imgur.com/jg5mzNj.png)."
})
},
{
@@ -197,14 +152,6 @@ export const providersData: Providers = {
message: "Different instructions for different plans: On VPS, select Geyser in the [Service Type Menu](https://i.imgur.com/loSNmvu.png), Floodgate can be enabled on the dashboard configuration. For manual installation: Using a Premium or Free plan, use the same port as your Java server for the Bedrock port in the configuration file and connect that; for the Free plan, also enable the `clone-remote-port` option. If you are using a PRO or a VPS plan, you can use any port, which can be opened on the Firewall tab."
})
},
{
name: 'ServerPrism',
url: 'https://serverprism.com/',
description: translate({
id: 'providers.provider.serverprism.description',
message: "Order a [Minecraft server](https://serverprism.com/minecraft-server-hosting) on any plugin-compatible runtime (Paper, Spigot, Purpur, etc.), then install Geyser from the panel's plugin installer. Connect with the same IP and port as your Java server."
})
},
{
name: 'Snakecraft Hosting',
url: 'https://snakecrafthosting.com/',
@@ -221,22 +168,6 @@ export const providersData: Providers = {
message: "You can enable Geyser on the version changer page. Geyser will run on the given port by the host."
})
},
{
name: 'UltraServers',
url: 'https://ultraservers.com/',
description: translate({
id: 'providers.provider.ultraservers.description',
message: "Select 'Paper + Geyser' under the Change version tab. You can connect to your server using the same IP and port as you would on Java. Existing servers can use the Plugins/Minecraft mods tab to install Geyser. See [Crossplay](https://docs.ultraservers.com/minecraft/plugins-mods/crossplay-on-java-and-bedrock) for more information."
})
},
{
name: 'VemoxHost',
url: 'https://vemoxhost.com/',
description: translate({
id: 'providers.provider.vemox_hosting.description',
message: "Full automatic installation. Go to one of the panel options and select the option to enable GeyserMC. Then, restart and connect to your server using your Java IP and port."
})
},
{
name: 'Virtual Gladiators',
url: 'https://virtualgladiators.com/',
@@ -250,7 +181,7 @@ export const providersData: Providers = {
url: 'https://wisehosting.com',
description: translate({
id: 'providers.provider.wisehosting.description',
message: "Both auto and manual installation available. Find the GeyserMC presets from the `Addons` tab in the Game Panel. There, click `Install` and restart your server. See [Crossplay FAQ](https://wisehosting.com/help/how-to-install-geysermc-to-your-minecraft-server) for additional details."
message: "Both auto and manual installation available. Find the GeyserMC presets from the `Properties` tab in the Game Panel. There, click `Install` and restart your server. See [Crossplay FAQ](https://help.wisehosting.com/en/articles/13-how-to-install-geysermc-java-bedrock-crossplay-to-your-server) for additional details."
})
},
{
@@ -289,7 +220,7 @@ export const providersData: Providers = {
url: 'https://www.bisecthosting.com/',
description: translate({
id: 'providers.provider.bisecthosting.description',
message: "Go to the Network tab and copy an available port not in use by other mods. In Geyser's config, under the bedrock section, on the port: line, edit the value to the port you copied. See Bisect's [article](https://www.bisecthosting.com/clients/index.php?rp=/knowledgebase/193/How-to-install-Geyser-and-Floodgate-on-a-Minecraft-Java-server.html) for full instructions. If you still cannot connect after following these instructions, contact Bisect Support, as they reportedly have UDP disabled on some nodes."
message: "You must have a plan with a dedicated IP. In Geyser's config, uncomment the `bedrock address` and set it to the public IP of your server (e.g. `address: 51.79.129.18`). Leave the port as `19132`. Under the home tab, select 'Enable UDP Network' and restart the server. See Bisect's [article](https://www.bisecthosting.com/clients/index.php?rp=/knowledgebase/193/How-to-install-Geyser-and-Floodgate-on-a-Minecraft-Java-server.html) for full instructions. If you still cannot connect after following these instructions, contact Bisect Support as they reportedly have UDP disabled on some nodes."
})
},
{
@@ -394,6 +325,11 @@ export const providersData: Providers = {
url: 'https://freakhosting.com/',
description: descriptionTemplates.default
},
{
name: 'FreeMcServer.net',
url: 'https://freemcserver.net',
description: descriptionTemplates.default
},
{
name: 'Fusion Hosting',
url: 'https://fusionhostingltd.co.uk',
@@ -497,10 +433,7 @@ export const providersData: Providers = {
{
name: 'MCFORFREE.DE',
url: 'https://mcforfree.de/',
description: translate({
id: 'providers.provider.mcforfree.de.description',
message: 'Create an extra port in the game panel, then change the `port` in the `bedrock` section to the newly created port. To connect on Bedrock edition, use the Java server\'s IP and the port you\'ve created. It may take a few minutes for the port to become active.'
})
description: 'Create an extra port in the game panel, then change the `port` in the `bedrock` section to the newly created port. To connect on Bedrock edition, use the Java server\'s IP and the port you\'ve created. It may take a few minutes for the port to become active.'
},
{
name: 'MCPEhost.ru',
@@ -528,14 +461,6 @@ export const providersData: Providers = {
url: 'https://www.minecraft-hosting.pro/',
description: descriptionTemplates.default
},
{
name: 'Modrinth Hosting',
url: 'https://modrinth.com/hosting',
description: translate({
id: 'providers.provider.modrinth.description',
message: "Check [Modrinth's documentation](https://support.modrinth.com/en/articles/10986613-adding-geyser-to-your-server) for specific instructions."
})
},
{
name: 'Netbela',
url: 'https://netbela.nl/store/minecraft',
@@ -549,7 +474,7 @@ export const providersData: Providers = {
url: 'https://nfoservers.com/',
description: translate({
id: 'providers.provider.nfoservers.description',
message: "Set `bedrock address` to the server IP in the Geyser config file. As an alternative, you can run Geyser standalone separately on an Unmanaged VDS."
message: "Uncomment and set `bedrock address` to the server IP in the Geyser config file. As an alternative, you can run Geyser standalone separately on an Unmanaged VDS."
})
},
{
@@ -568,21 +493,10 @@ export const providersData: Providers = {
message: "Use the default server port and `0.0.0.0` or your server IP as the host address."
})
},
{
name: 'OrionNodes',
url: 'https://orionnodes.com',
description: translate({
id: 'providers.provider.orionnodes.description',
message: "Open a port yourself from the network page in the game panel, use that port in the bedrock section of the Geyser config."
})
},
{
name: 'PaperNodes',
url: 'https://papernodes.com/',
description: translate({
id: 'providers.provider.papernodes.description',
message: 'Enable clone-remote-port (or manually set the Bedrock port to the Java port), and connect with the Java IP and port. Alternatively, you can contact the host to request an additional port or a dedicated IP.'
})
description: 'Enable clone-remote-port (or manually set the Bedrock port to the Java port), and connect with the Java IP and port. Alternatively, you can contact the host to request an additional port or a dedicated IP.'
},
{
name: 'Pebblehost',
@@ -636,14 +550,6 @@ export const providersData: Providers = {
message: "The port will be automatically set after you download Geyser and restart the server. Connect with the same IP and port as on Java. For Geyser Standalone installation instructions, see [here](https://shockbyte.com/billing/knowledgebase/173/Introduction-to-GeyserMCorDragonProxy-How-GeyserMC-Works.html)."
})
},
{
name: 'SimpleGameHosting',
url: 'https://simplegamehosting.com/',
description: translate({
id: 'providers.provider.simplegamehosting.description',
message: "Contact live chat support to open a port and check out the [help center guide](https://help.simplegamehosting.com/how-to-enable-crossplay-with-geyser-on-your-minecraft-server/) for how to install and configure Geyser on your server."
})
},
{
name: 'Skynode.pro',
url: 'https://skynode.pro/',
@@ -719,24 +625,13 @@ export const providersData: Providers = {
url: 'https://vultam.net/',
description: translate({
id: 'providers.provider.vultam.description',
message: "Enable `clone-remote-port` in the Geyser config, and connect with the Java IP and port. Alternatively, allocate an additional port to your server from the Network section of the control panel and set it as the `bedrock port` in the Geyser config. Use that port to connect from Bedrock. Please contact [Vultam support](https://clients.vultam.net/submitticket.php?step=2&deptid=1) if you need assistance."
})
},
{
name: 'Wasabi Hosting',
url: 'https://wasabihosting.com',
description: translate({
id: 'providers.provider.wasabihosting.description',
message: "Install Geyser with the plugin installer. Use the same port as your Java server in the Geyser config. Connect with the same address and port as your Java server."
message: "Enable `clone-remote-port` in the Geyser config, and connect with the Java IP and port. Alternatively, allocate an additional port to your server from the Network section of the control panel and set it as the `bedrock.port` in the Geyser config. Use that port to connect from Bedrock. Please contact [Vultam support](https://clients.vultam.net/submitticket.php?step=2&deptid=1) if you need assistance."
})
},
{
name: "Wepwawet",
url: "https://wepwawet.net/",
description: translate({
id: 'providers.provider.wepwawet.description',
message: "Add a new port in the Network tab. Use this new port as the bedrock port."
})
description: "Add a new port in the Network tab. Use this new port as the bedrock port."
},
{
name: 'WinterNode',
@@ -751,7 +646,7 @@ export const providersData: Providers = {
url: 'https://witherhosting.com/',
description: translate({
id: 'providers.provider.witherhosting.description',
message: "Either use the Java server's port, or create a port in the ports manager on the panel and use that for Bedrock. Refer to the hosts [support article](https://my.witherhosting.com/kb/how-to-install-and-use-geysermc-java) for further info."
message: "Either use the Java server's port, or create a port in the ports manager on the panel and use that for Bedrock. Refer to the hosts [support article](https://support.witherhosting.com/en/article/how-to-install-and-use-geysermc-1xn5l6v/) for further info."
})
}
],
+4 -4
View File
@@ -1,12 +1,12 @@
{
"bedrock": {
"supported": "1.21.130-26.20",
"supported": "1.20.80-1.21.30",
"latest": {
"id": 975,
"name": "26.20"
"id": 729,
"name": "1.21.30"
}
},
"java": {
"supported": "26.1"
"supported": "1.21/1.21.1"
}
}
@@ -69,6 +69,21 @@ const DownloadPage: React.FC = () => (
</TabItem>
<TabItem value="other-projects" label="Other Projects">
<Collapsibles>
<Collapsible
title='GeyserOptionalPack'
subtitle={<Translate id='pages.download.description.geyseroptionalpack'>An optional Bedrock resource pack to extend Geyser functionality.</Translate>}
id='geyseroptionalpack'
inner={
<ProjectDownload
projectId="geyseroptionalpack"
setup='/wiki/other/geyseroptionalpack'
downloadsInfo={{
geyseroptionalpack: <><FontAwesomeIcon icon={faFileZipper} /> GeyserOptionalPack</>,
}}
gridColumns={1}
/>
}
/>
<Collapsible
title='ThirdPartyCosmetics'
subtitle={<Translate id='pages.download.description.thirdpartycosmetics'>An extension that adds support for loading ears and other third party cosmetics on java players</Translate>}
@@ -84,20 +99,6 @@ const DownloadPage: React.FC = () => (
/>
}
/>
<Collapsible
title='EmoteOffhand'
subtitle={<Translate id='pages.download.description.offhandextension'>An extension that allows Bedrock players to switch their offhand and mainhand item by emoting.</Translate>}
id='emoteoffhand'
inner={
<ProjectDownload
projectId="emoteoffhand"
downloadsInfo={{
emoteoffhand: <><FontAwesomeIcon icon={faFileZipper} /> EmoteOffhand</>,
}}
gridColumns={1}
/>
}
/>
<Collapsible
title='Hurricane'
subtitle={<Translate id='pages.download.description.hurricane'>A plugin with various workarounds for Geyser players that modify the server in order to achieve their goal.</Translate>}
@@ -128,21 +129,6 @@ const DownloadPage: React.FC = () => (
/>
}
/>
<Collapsible
title='Rainbow'
subtitle={<Translate id='pages.download.description.rainbow'>A Minecraft mod to generate Geyser item mappings and bedrock resourcepacks for use with Geyser's custom item API (v2). </Translate>}
id='rainbow'
inner={
<ProjectDownload
projectId="rainbow"
setup='/wiki/other/rainbow'
downloadsInfo={{
rainbow: <PlatformIcon img={FabricIcon} text="Fabric" />,
}}
gridColumns={1}
/>
}
/>
<Collapsible
title='Hydraulic'
subtitle={<Translate id='pages.download.description.hydraulic'>A companion mod to Geyser which allows for Bedrock players to join modded Minecraft: Java Edition servers.</Translate>}
@@ -160,22 +146,6 @@ const DownloadPage: React.FC = () => (
/>
}
/>
<Collapsible
title='Thunder'
subtitle={<Translate id='pages.download.description.thunder'>A java application to convert simple Java Edition resource packs to Bedrock Edition ones.</Translate>}
id='thunder'
tags={['Beta']}
inner={
<ProjectDownload
projectId="thunder"
setup='/wiki/other/thunder'
downloadsInfo={{
thunder: <><FontAwesomeIcon icon={faFileZipper} /> Thunder</>,
}}
gridColumns={1}
/>
}
/>
</Collapsibles>
</TabItem>
</Tabs>
-7
View File
@@ -66,11 +66,4 @@
display: flex;
align-items: center;
justify-content: center;
}
.features {
padding: 50px 0;
display: flex;
flex-direction: column;
gap: 40px;
}
+4 -34
View File
@@ -1,21 +1,18 @@
import clsx from 'clsx';
import Layout from '@theme/Layout';
import Crossplatform0Img from '@site/static/img/site/crossplatform_0.png';
import Crossplatform1Img from '@site/static/img/site/crossplatform_1.png';
import Crossplatform2Img from '@site/static/img/site/crossplatform_2.png';
import HomepageFeatures from '@site/src/components/HomepageFeatures';
import Heading from '@theme/Heading';
import HeroImage from '@site/static/img/site/geyser.png';
import styles from './index.module.scss';
import Translate from '@docusaurus/Translate';
import { HomepageFeature } from '../components/HomepageFeature';
function HomepageHeader() {
return (
<header className={clsx('hero hero--primary', styles.heroBanner)}>
<div className={styles.heroContent}>
<img src={HeroImage} alt="Geyser Logo" className={styles.heroImage} />
<img src={HeroImage} alt="Geyser Logo" className={styles.heroImageBackgroundBlur} />
<img src={HeroImage} alt="Geyser Logo" className={styles.heroImage}/>
<img src={HeroImage} alt="Geyser Logo" className={styles.heroImageBackgroundBlur}/>
<div className={styles.textSection}>
<Heading as="h1" className="hero__title">
<Translate id='pages.main.title'>Revolutionize Your Minecraft Server</Translate>
@@ -36,35 +33,8 @@ export default function Home(): JSX.Element {
description="Enable clients from Minecraft Bedrock Edition to join your Minecraft Java server."
>
<HomepageHeader />
<main>
<div className={clsx(styles.features, "container")}>
<HomepageFeature
title="What is Geyser?"
image={Crossplatform2Img}
>
<Translate id="components.homepage_features.1.line1">Geyser is a program that allows Minecraft: Bedrock Edition clients to join Minecraft: Java Edition servers, allowing for true crossplay between both editions of the game.</Translate>
<br /><br />
<Translate id="components.homepage_features.1.line2">The ultimate goal of this project is to allow Minecraft: Bedrock Edition users to join Minecraft: Java Edition servers as seamlessly as possible.</Translate>
</HomepageFeature>
<HomepageFeature
title="How does it work?"
image={Crossplatform1Img}
flipped
>
<Translate id="components.homepage_features.2">Geyser acts as a translator which sits between the Bedrock client and the Java server. It takes data from the Bedrock client and translates it into a format the Java server understands and vice versa. Geyser works with any modern Minecraft version and can be installed either as a plugin or ran as a standalone program.</Translate>
</HomepageFeature>
<HomepageFeature
title="Join from anywhere"
image={Crossplatform0Img}
>
<Translate id="components.homepage_features.3.line1">Geyser can be joined from Bedrock clients on Windows 10/11, iOS, Android, and even consoles. Geyser works with a wide array of hosting providers, but can also be used as its own standalone proxy to join any Minecraft server!</Translate>
<br /><br />
<Translate id="components.homepage_features.3.line2">If you are a server owner, you can install our Floodgate plugin which allows Xbox Live authenticated Bedrock users to join without a Java Edition account!</Translate>
</HomepageFeature>
</div>
<HomepageFeatures />
</main>
</Layout>
);
+323
View File
@@ -0,0 +1,323 @@
import Translate from '@docusaurus/Translate';
import HeroBanner from '@site/src/components/HeroBanner';
import HeroBackground from '@site/static/img/site/split-background.webp';
import Layout from '@theme/Layout';
import styles from './utilities.module.scss';
import { useRef, useState } from 'react';
const ConfigEditorPage: React.FC = () => {
const [config, setConfig] = useState('');
const [parsedConfig, setParsedConfig] = useState<any>({});
// match optional key
const keyReg = /^#? ?[^:\sA-Z]+:(?!\S)/
const editedConfig = useRef<any>({});
const uploadRef = useRef<any>(null);
const loadDefault = async () => {
try {
const response = await fetch('https://raw.githubusercontent.com/GeyserMC/Geyser/master/core/src/main/resources/config.yml');
if (!response.ok) {
throw new Error('Network response was not ok');
}
const text = await response.text();
handleConfigLoad(text);
} catch (error) {
console.error('Failed to fetch default config:', error);
}
}
const handleUpload = async (e) => {
const fileName = e.target.files[0];
// Makse sure the file is a .yml file
if (!fileName.name.endsWith('.yml')) {
alert('Please select a .yml config file!');
return;
}
// Read the file
const fileReader = new FileReader();
fileReader.onload = (e) => {
handleConfigLoad(e.target.result as string);
}
fileReader.readAsText(fileName);
}
const handleConfigLoad = (config: string) => {
setConfig(config);
setParsedConfig(loadConfig(config));
}
const loadConfig = (config: string) => {
const lines = config.split('\n');
let currentSection = '';
let currentComment = '';
const newConfig = {};
// Parse each line of the config
for (let i = 0; i < lines.length; i++) {
let line = lines[i];
// Reset the section if we are no indented
if (!line.startsWith(' ')) {
currentSection = '';
}
// Ignore any empty lines
line = line.trim()
if (line === '') {
currentComment = '';
continue;
}
const commented = line.startsWith('#');
const match = line.match(keyReg)
if (match === null) {
// Check if we are in a comment
if (commented) {
currentComment += line.replace(/^# ?/i, '') + '<br>';
}
continue;
}
// Check if we are in a new section
if (line.endsWith(':')) {
currentSection = line.replace(':', '');
currentComment = '';
continue;
}
// Ignore user auths section
if (currentSection === 'saved-user-logins') {
continue;
}
// Get the key and value
const splitLine = line.split(':');
splitLine[0] = splitLine[0].trim();
let val = '';
for (let j = 1;j<splitLine.length;j++) {
val += splitLine[j];
}
val = val.trim();
if (splitLine[0].includes('proxy-protocol-whitelisted-ips')) {
currentComment = '';
continue;
}
if (commented) {
currentComment += '<strong>Note: This option is commented on, and if you change it, it will be automatically uncommented.</strong>' + '<br>';
}
// Add the config option to the config object
newConfig[currentSection] = newConfig[currentSection] || {};
newConfig[currentSection][splitLine[0]] = {
desc: currentComment,
value: val,
line: i
};
// Reset the comment
currentComment = '';
}
return newConfig;
}
const generateHTML = (config: any) => {
return Object.keys(config).map(configKey => (
<div key={configKey} className={styles.card}>
<div className={styles.cardHeader}>{configKey === '' ? 'Root' : configKey}</div>
<div className={styles.cardBody}>
{Object.keys(config[configKey]).map(configOption => {
const configOptionInfo = config[configKey][configOption];
const configOptionKey = configKey === '' ? configOption : `${configKey}.${configOption}`;
const showOptionName = configOption.replace('#','').trim()
return (
<div key={configOptionKey} className={styles.configOption}>
<h3>{showOptionName}</h3>
<p dangerouslySetInnerHTML={{ __html: configOptionInfo.desc }} />
{getInput(configOptionKey, configOptionInfo.value)}
</div>
)
})}
</div>
</div>
))
}
const handleExport = () => {
let newConfig = config;
const lines = newConfig.split('\n');
Object.entries(editedConfig.current).forEach(([key, value]) => {
const keys = key.split('.');
let currentObj = parsedConfig;
keys.forEach((nestedKey, index) => {
if (currentObj.hasOwnProperty(nestedKey)) {
if (index === keys.length - 1) {
const option = currentObj[nestedKey];
const oldValue = option.value;
const index = option.line;
const newKey = nestedKey.replace('#','').trim();
lines[index] = lines[index].replace(` ${nestedKey}: ${oldValue}`,` ${newKey}: ${value}`);
} else {
currentObj = currentObj[nestedKey];
}
}
});
});
newConfig = lines.join('\n');
// Trigger a download of the final config
downloadString(newConfig, 'text/plain', 'config.yml');
}
function getInput(name, value) {
const handleChange = (event) => {
const { id, value, type, checked } = event.target;
editedConfig.current = {
...editedConfig.current,
[id]: type === 'checkbox' ? checked.toString() : value
};
}
switch (name) {
// Handle all the dropdowns
case 'remote.auth-type':
return (
<select key={name} className={styles.formInput} id={name} defaultValue={value} onChange={handleChange}>
<option value='offline'>offline</option>
<option value='online'>online</option>
<option value='floodgate'>floodgate</option>
</select>
);
case 'show-cooldown':
return (
<select key={name} className={styles.formInput} id={name} defaultValue={value} onChange={handleChange}>
<option value='title'>title</option>
<option value='actionbar'>actionbar</option>
<option value='false'>false</option>
</select>
);
case 'emote-offhand-workaround':
return (
<select key={name} className={styles.formInput} id={name} defaultValue={value} onChange={handleChange}>
<option value='disabled'>disabled</option>
<option value='no-emotes'>no-emotes</option>
<option value='emotes-and-offhand'>emotes-and-offhand</option>
</select>
);
case 'config-version':
return <input key={name} className={styles.formInput} type='text' disabled defaultValue={value.replace(/"/g, '')} />;
case 'metrics.uuid':
return <input key={name} className={styles.formInput} id={name} type='text' disabled defaultValue={value === 'generateduuid' ? crypto.randomUUID() : value} />;
default:
// Handle all the other inputs
if (value.toLowerCase() === 'true' || value.toLowerCase() === 'false') {
// Boolean
return (
<div key={name}>
<input className={styles.checkbox} type='checkbox' id={name}
defaultChecked={value.toLowerCase() === 'true'} onChange={handleChange}/>
<label htmlFor={name} className='switch'></label>
</div>
);
} else if (!isNaN(value)) {
// Number
return <input key={name} className={styles.formInput} type='number' defaultValue={value}
id={name} onChange={handleChange}/>;
} else {
// String
return <input key={name} className={styles.formInput} type='text'
defaultValue={value.replace(/"/g, '')} id={name} onChange={handleChange}/>;
}
}
}
// From https://gist.github.com/danallison/3ec9d5314788b337b682
function downloadString(text, fileType, fileName) {
const blob = new Blob([text], { type: fileType })
const a = document.createElement('a')
a.download = fileName
a.href = URL.createObjectURL(blob)
a.dataset.downloadurl = [fileType, a.download, a.href].join(':')
a.style.display = 'none'
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
setTimeout(() => { URL.revokeObjectURL(a.href) }, 1500)
}
const NoConfigSection = () => (
<>
<h1><Translate id='pages.configeditor.noconfigselected.heading'>No config selected.</Translate></h1>
<h3 className={styles.fontNormal}><Translate id='pages.configeditor.noconfigselected.subheading'>Upload a file or get started with the default config!</Translate></h3>
<div className={styles.buttonsContainer}>
<button className={styles.button} onClick={loadDefault}>
<Translate id='pages.configeditor.button.defaultconfig'>Default</Translate>
</button>
<button className={styles.button} onClick={() => uploadRef.current.click()}>
<input
ref={uploadRef}
type='file'
className={styles.hidden}
accept='.yml'
onChange={handleUpload}
/>
<Translate id='pages.configeditor.button.upload'>Upload</Translate>
</button>
</div>
</>
)
const EditorView = () => (
<>
<div className={styles.buttonsContainer} style={{ marginBottom: '30px' }}>
<button className={styles.button} onClick={handleExport}>
<Translate id='pages.configeditor.button.export'>Export</Translate>
</button>
</div>
{generateHTML(parsedConfig)}
</>
)
return (
<>
<HeroBanner
title={<Translate id='pages.configeditor.title'>Config Editor</Translate>}
subheading={<Translate id='pages.configeditor.subheading'>Edit your Geyser configuration.</Translate>}
backgroundImage={HeroBackground}
/>
<div className='container' style={{ marginTop: '30px' }}>
{Object.keys(parsedConfig).length === 0 ? <NoConfigSection /> : <EditorView />}
</div>
<section id='config-options'></section>
</>
)
}
export default function ConfigEditor(): JSX.Element {
return (
<Layout
title={`Config Editor`}
description='Edit your Geyser configuration.'
>
<main>
<div className='container container--fluid margin-vert--lg'>
<ConfigEditorPage />
</div>
</main>
</Layout>
)
}
+35 -51
View File
@@ -8,10 +8,16 @@ import { Grid } from '@site/src/components/Grid';
import CodeBlock from '@theme/CodeBlock';
import clsx from 'clsx';
const PluginList = ({plugins}, {}) => {
const DumpViewerPage: React.FC = () => {
const [dumpId, setDumpId] = useState('');
const [data, setData] = useState<any>({});
const [statusMessage, setStatusMessage] = useState('');
const [activePlugin, setActivePlugin] = useState<any>({});
const pluginPopoverRef = useRef<any>(null);
const urlReg = /^(https?:\/\/)?dump\.geysermc\.org/;
useEffect(() => {
const handleClickOutside = (event) => setActivePlugin({});
document.addEventListener("mousedown", handleClickOutside);
@@ -21,37 +27,6 @@ const PluginList = ({plugins}, {}) => {
};
}, [pluginPopoverRef]);
return <Grid elementsPerRow={5}>
{plugins.map(plugin => (
<div key={plugin.main}>
<div onClick={() => setActivePlugin(plugin)} className={styles.pluginName}>
<b>{plugin.name}</b> <div className={styles.pluginEnabledIndicator} style={{ backgroundColor: plugin.enabled ? "green" : "red" }} />
</div>
{activePlugin?.main === plugin.main ? (
<div ref={pluginPopoverRef} className={styles.pluginInfoPopover}>
<p className={styles.pluginNamePopover}>{plugin.name}</p>
<p>{plugin.version}</p>
<p className={styles.pluginEnabled} style={{ backgroundColor: plugin.enabled ? "green" : "red" }}>{plugin.enabled ? "Enabled" : "Disabled"}</p>
<p className={styles.pluginAuthorsLabel}>Authors:</p>
<ul>
{plugin.authors.map(author => <li>{author}</li>)}
</ul>
</div>
) : undefined}
</div>
))}
</Grid>
};
const DumpViewerPage: React.FC = () => {
const [dumpId, setDumpId] = useState('');
const [data, setData] = useState<any>({});
const [statusMessage, setStatusMessage] = useState('');
const urlReg = /^(https?:\/\/)?dump\.geysermc\.org/;
useEffect(() => {
// Get the ID from the URL
let id = window.location.href.includes('?') ? window.location.href.split('?').pop() : '';
@@ -101,6 +76,10 @@ const DumpViewerPage: React.FC = () => {
return string.charAt(0).toUpperCase() + string.slice(1)
}
const handlePluginClick = (plugin) => {
setActivePlugin(plugin);
}
return (
<>
<HeroBanner
@@ -180,7 +159,7 @@ const DumpViewerPage: React.FC = () => {
</div>
<div>
<b><Translate id='pages.dumpviewer.platform.name'>Platform Name</Translate></b><br />
<p id='platformName'>{data.bootstrapInfo.platformName ?? capitalizeFirstLetter(data.bootstrapInfo.platform.platformName.toLowerCase())}</p>
<p id='platformName'>{data.bootstrapInfo.platformName ?? capitalizeFirstLetter(data.bootstrapInfo.platform.toLowerCase())}</p>
</div>
<div>
<b><Translate id='pages.dumpviewer.platform.version'>Platform Version</Translate></b><br />
@@ -232,30 +211,35 @@ const DumpViewerPage: React.FC = () => {
</div>
<div className={styles.card}>
<div className={styles.cardHeader}>
<Translate id='pages.dumpviewer.plugins'>Plugins</Translate> ({data.bootstrapInfo.plugins?.length ?? 0})
<Translate id='pages.dumpviewer.plugins'>Plugins</Translate> ({data.bootstrapInfo.plugins.length})
</div>
<div className={styles.cardBody}>
{!data.bootstrapInfo.plugins || data.bootstrapInfo.plugins.length === 0 ? (
<p><Translate id='pages.dumpviewer.plugins.noplugins'>No plugins to show.</Translate></p>) : (
{data.bootstrapInfo.plugins.length === 0 ? <p><Translate id='pages.dumpviewer.plugins.noplugins'>No plugins to show.</Translate></p> : (
<>
<p><Translate id='pages.dumpviewer.plugins.helptext'>Click on a plugin to view more information.</Translate></p>
<PluginList plugins={data.bootstrapInfo.plugins}></PluginList>
</>
)}
</div>
</div>
<div className={styles.card}>
<div className={styles.cardHeader}>
<Translate id='pages.dumpviewer.extensions'>Extensions</Translate> ({data.extensionInfo?.length ?? 0})
</div>
<div className={styles.cardBody}>
{!data.extensionInfo || data.extensionInfo.length === 0 ? (
<p><Translate id='pages.dumpviewer.extensions.noextensions'>No extensions to show.</Translate></p>) : (
<>
<p><Translate id='pages.dumpviewer.extensions.helptext'>Click on an extension to view more information.</Translate></p>
<Grid elementsPerRow={5}>
{data.bootstrapInfo.plugins.map(plugin => (
<div>
<b onClick={() => handlePluginClick(plugin)} className={styles.pluginName}>
{plugin.name} <div className={styles.pluginEnabledIndicator} style={{ backgroundColor: plugin.enabled ? "green" : "red" }} />
</b>
<PluginList plugins={data.extensionInfo}></PluginList>
{activePlugin?.main === plugin.main ? (
<div ref={pluginPopoverRef} className={styles.pluginInfoPopover}>
<p className={styles.pluginNamePopover}>{plugin.name}</p>
<p>{plugin.version}</p>
<p className={styles.pluginEnabled} style={{ backgroundColor: plugin.enabled ? "green" : "red" }}>{plugin.enabled ? "Enabled" : "Disabled"}</p>
<p className={styles.pluginAuthorsLabel}>Authors:</p>
<ul>
{plugin.authors.map(author => <li>{author}</li>)}
</ul>
</div>
) : undefined}
</div>
))}
</Grid>
</>
)}
</div>
+35 -38
View File
@@ -109,6 +109,41 @@
border-radius: 50%;
}
/* https://codepen.io/JAGATHISH1123/pen/PvayMB */
.switch {
position: relative;
display: inline-block;
width: 40px;
height: 20px;
background-color: var(--switch-background-color);
border-radius: 20px;
transition: all 0.3s;
&::after {
content: '';
position: absolute;
width: 18px;
height: 18px;
border-radius: 50%;
background-color: white;
top: 1px;
left: 1px;
transition: all 0.3s;
}
}
.checkbox:checked+.switch::after {
left: 20px;
}
.checkbox:checked+.switch {
background-color: var(--ifm-color-secondary);
}
.checkbox {
display: inline-block;
}
.hidden {
display: none;
}
@@ -164,41 +199,3 @@
min-width: 100%;
}
}
/* Modified from https://danklammer.com/articles/simple-css-toggle-switch */
.checkbox {
appearance: none;
position: relative;
display: inline-block;
box-sizing: content-box;
width: 4.5em;
height: 1.8em;
padding: 0.2em;
border: none;
cursor: pointer;
border-radius: 1.5em;
overflow: hidden;
background-color: #707070;
transition: background ease 0.3s;
&:before {
content: "";
display: block;
position: absolute;
z-index: 2;
width: 1.8em;
height: 1.8em;
background: #fff;
color: #fff;
border-radius: 1.5em;
transition: transform cubic-bezier(0.3, 1.5, 0.7, 1) 0.3s;
}
&:checked {
background-color: var(--ifm-color-secondary);
}
&:checked:before {
transform: translateX(2.5em);
}
}
+28 -123
View File
@@ -2,133 +2,38 @@ import fs from 'fs';
import path from 'path';
import { LoadContext, Plugin, PluginOptions } from '@docusaurus/types';
import logger from '@docusaurus/logger';
import ts from "typescript";
import Module from 'module';
// Welcome to hell
const createProvidersJsonPlugin = (_context: LoadContext, _options: PluginOptions): Plugin => {
return {
name: 'docusaurus-plugin-create-providers-json',
const createProvidersJsonPlugin = (context: LoadContext, options: PluginOptions): Plugin => {
return {
name: 'docusaurus-plugin-create-providers-json',
async postBuild({ outDir }) {
const providersFilePath = path.join(__dirname, '../data/providers.ts');
const providersFileContent = fs.readFileSync(providersFilePath, 'utf-8');
const providersAst = ts.createSourceFile('providers.ts', providersFileContent, ts.ScriptTarget.Latest, true);
async postBuild({ outDir, routes, plugins }) {
const originalResolveFilename = Module._resolveFilename
let providersDataNode: ts.ObjectLiteralExpression | null = null;
let descriptionTemplatesNode: ts.ObjectLiteralExpression | null = null;
for (const statement of providersAst.statements) {
if (ts.isVariableStatement(statement)) {
for (const decl of statement.declarationList.declarations) {
if (
ts.isIdentifier(decl.name) &&
decl.initializer
) {
if (decl.name.text === 'providersData' && ts.isObjectLiteralExpression(decl.initializer)) {
providersDataNode = decl.initializer;
} else if (decl.name.text === 'descriptionTemplates' && ts.isObjectLiteralExpression(decl.initializer)) {
descriptionTemplatesNode = decl.initializer;
}
}
}
}
}
if (!providersDataNode) {
logger.error('Could not find providersData in providers.ts');
return;
}
if (!descriptionTemplatesNode) {
logger.error('Could not find defaultDescriptions in providers.ts');
return;
}
function parseDescriptionTemplates(node: ts.ObjectLiteralExpression): Record<string, string> {
const map: Record<string, string> = {};
for (const prop of node.properties) {
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
const key = prop.name.text;
const val = extractDescription(prop.initializer);
map[key] = val || '';
}
}
return map;
}
let defaultDescriptionsMap = parseDescriptionTemplates(descriptionTemplatesNode);
function extractDescription(node: ts.Expression): string {
if (ts.isCallExpression(node)) {
const expr = node.expression;
if (ts.isIdentifier(expr) && expr.text === 'translate') {
const arg = node.arguments[0];
if (arg && ts.isObjectLiteralExpression(arg)) {
for (const prop of arg.properties) {
if (
ts.isPropertyAssignment(prop) &&
ts.isIdentifier(prop.name) &&
prop.name.text === 'message' &&
ts.isStringLiteral(prop.initializer)
) {
return prop.initializer.text;
}
}
}
}
} else if (ts.isPropertyAccessExpression(node)) {
if (ts.isIdentifier(node.expression) && node.expression.text === 'descriptionTemplates') {
const key = node.name.text;
return defaultDescriptionsMap[key] || '';
}
}
}
function parseProvidersArray(prop: ts.PropertyAssignment): {name: string; url: string; description: string;}[] {
if (ts.isArrayLiteralExpression(prop.initializer)) {
return prop.initializer.elements
.filter(ts.isObjectLiteralExpression)
.map(element => {
let nameVal = '';
let urlVal = '';
let descVal = '';
for (const property of element.properties) {
if (ts.isPropertyAssignment(property) && ts.isIdentifier(property.name)) {
const key = property.name.text;
const val = property.initializer;
if (key === 'name' && ts.isStringLiteral(val)) {
nameVal = val.text;
} else if (key === 'url' && ts.isStringLiteral(val)) {
urlVal = val.text;
} else if (key === 'description') {
descVal = extractDescription(val);
}
}
}
return { name: nameVal, url: urlVal, description: descVal };
});
}
return [];
}
let providersJson = {};
for (const prop of providersDataNode.properties) {
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
providersJson[prop.name.text] = parseProvidersArray(prop);
}
}
const dataDir = path.join(outDir, 'data');
if (!fs.existsSync(dataDir)) {
fs.mkdirSync(dataDir, { recursive: true });
}
const outputFilePath = path.join(dataDir, 'providers.json');
fs.writeFileSync(outputFilePath, JSON.stringify(providersJson, null, 4), 'utf-8');
// This is a hack to allow us to import a custom module instead of the normal translation module
Module._resolveFilename = function (request, parent, isMain, options) {
if (request == '@docusaurus/Translate') {
request = path.resolve(__dirname, 'custom_modules', 'translate.ts');
}
};
return originalResolveFilename.call(this, request, parent, isMain, options);
};
// Import the providers data
const { providersData } = await import('../data/providers');
// Restore the original resolve function
Module._resolveFilename = originalResolveFilename
const providersFilePath = path.join(outDir, 'data/providers.json');
fs.mkdirSync(path.dirname(providersFilePath), { recursive: true });
fs.writeFileSync(providersFilePath, JSON.stringify(providersData, null, 2), 'utf-8');
logger.success(`Created providers.json file at ${providersFilePath}`);
}
};
};
export default createProvidersJsonPlugin;
@@ -1,102 +0,0 @@
<svg id="export-svg" width="100%" xmlns="http://www.w3.org/2000/svg" class="classDiagram" style="max-width: 1267.4666748046875px;" viewBox="0 0 1267.4666748046875 673" role="graphics-document document" aria-roledescription="class"><style xmlns="http://www.w3.org/1999/xhtml">/* Google Inc.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION &amp; CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
*/
@font-face {
font-family: 'Recursive Variable';
font-style: normal;
font-display: swap;
font-weight: 300 1000;
src: url("data:font/woff2;base64,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 truncated
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}</style><style xmlns="http://www.w3.org/1999/xhtml">@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"); p {margin: 0;}</style><style>#export-svg{font-family:"Recursive Variable",arial,sans-serif;font-size:14px;fill:#28253D;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#export-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#export-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#export-svg .error-icon{fill:#ffffff;}#export-svg .error-text{fill:#000000;stroke:#000000;}#export-svg .edge-thickness-normal{stroke-width:2px;}#export-svg .edge-thickness-thick{stroke-width:3.5px;}#export-svg .edge-pattern-solid{stroke-dasharray:0;}#export-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#export-svg .edge-pattern-dashed{stroke-dasharray:3;}#export-svg .edge-pattern-dotted{stroke-dasharray:2;}#export-svg .marker{fill:#000000;stroke:#000000;}#export-svg .marker.cross{stroke:#000000;}#export-svg svg{font-family:"Recursive Variable",arial,sans-serif;font-size:14px;}#export-svg p{margin:0;}#export-svg g.classGroup text{fill:#28253D;stroke:none;font-family:"Recursive Variable",arial,sans-serif;font-size:10px;}#export-svg g.classGroup text .title{font-weight:bolder;}#export-svg .nodeLabel,#export-svg .edgeLabel{color:#28253D;}#export-svg .noteLabel .nodeLabel,#export-svg .noteLabel .edgeLabel{color:#28253D;}#export-svg .edgeLabel .label rect{fill:#ffffff;}#export-svg .label text{fill:#28253D;}#export-svg .labelBkg{background:#ffffff;}#export-svg .edgeLabel .label span{background:#ffffff;}#export-svg .classTitle{font-weight:bolder;}#export-svg .node rect,#export-svg .node circle,#export-svg .node ellipse,#export-svg .node polygon,#export-svg .node path{fill:#ffffff;stroke:#28253D;stroke-width:2;}#export-svg .divider{stroke:#28253D;stroke-width:1;}#export-svg g.clickable{cursor:pointer;}#export-svg g.classGroup rect{fill:#ffffff;stroke:#28253D;}#export-svg g.classGroup line{stroke:#28253D;stroke-width:1;}#export-svg .classLabel .box{stroke:none;stroke-width:0;fill:#ffffff;opacity:0.5;}#export-svg .classLabel .label{fill:#28253D;font-size:10px;}#export-svg .relation{stroke:#000000;stroke-width:2;fill:none;}#export-svg .dashed-line{stroke-dasharray:3;}#export-svg .dotted-line{stroke-dasharray:1 2;}#export-svg #compositionStart,#export-svg .composition{fill:#000000!important;stroke:#000000!important;stroke-width:1;}#export-svg #compositionEnd,#export-svg .composition{fill:#000000!important;stroke:#000000!important;stroke-width:1;}#export-svg #dependencyStart,#export-svg .dependency{fill:#000000!important;stroke:#000000!important;stroke-width:1;}#export-svg #dependencyStart,#export-svg .dependency{fill:#000000!important;stroke:#000000!important;stroke-width:1;}#export-svg #extensionStart,#export-svg .extension{fill:transparent!important;stroke:#000000!important;stroke-width:1;}#export-svg #extensionEnd,#export-svg .extension{fill:transparent!important;stroke:#000000!important;stroke-width:1;}#export-svg #aggregationStart,#export-svg .aggregation{fill:transparent!important;stroke:#000000!important;stroke-width:1;}#export-svg #aggregationEnd,#export-svg .aggregation{fill:transparent!important;stroke:#000000!important;stroke-width:1;}#export-svg #lollipopStart,#export-svg .lollipop{fill:#ffffff!important;stroke:#000000!important;stroke-width:1;}#export-svg #lollipopEnd,#export-svg .lollipop{fill:#ffffff!important;stroke:#000000!important;stroke-width:1;}#export-svg .edgeTerminals{font-size:11px;line-height:initial;}#export-svg .classTitleText{text-anchor:middle;font-size:18px;fill:#28253D;}#export-svg .edgeLabel{background-color:hsl(-120, 0%, 80%);text-align:center;}#export-svg .edgeLabel p{background-color:hsl(-120, 0%, 80%);}#export-svg .edgeLabel rect{opacity:0.5;background-color:hsl(-120, 0%, 80%);fill:hsl(-120, 0%, 80%);}#export-svg .cluster rect{fill:#F9F9FB;stroke:#BDBCCC;stroke-width:2px;}#export-svg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#export-svg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#export-svg .node .neo-node{stroke:#28253D;}#export-svg [data-look="neo"].node rect,#export-svg [data-look="neo"].cluster rect,#export-svg [data-look="neo"].node polygon{stroke:#28253D;filter:url(#drop-shadow);}#export-svg [data-look="neo"].node path{stroke:#28253D;stroke-width:2;}#export-svg [data-look="neo"].node .outer-path{filter:url(#drop-shadow);}#export-svg [data-look="neo"].node .neo-line path{stroke:#28253D;filter:none;}#export-svg [data-look="neo"].node circle{stroke:#28253D;filter:url(#drop-shadow);}#export-svg [data-look="neo"].node circle .state-start{fill:#000000;}#export-svg [data-look="neo"].statediagram-cluster rect{fill:#F9F9FB;stroke:#28253D;stroke-width:2;}#export-svLine truncated

Before

Width:  |  Height:  |  Size: 126 KiB

@@ -1,102 +0,0 @@
<svg id="export-svg" width="100%" xmlns="http://www.w3.org/2000/svg" class="classDiagram" style="max-width: 1267.47px;" viewBox="0 0 1267.4666748046875 673" role="graphics-document document" aria-roledescription="class"><style xmlns="http://www.w3.org/1999/xhtml">/* Google Inc.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION &amp; CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
*/
@font-face {
font-family: 'Recursive Variable';
font-style: normal;
font-display: swap;
font-weight: 300 1000;
src: url("data:font/woff2;base64,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 truncated
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}</style><style xmlns="http://www.w3.org/1999/xhtml">@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"); p {margin: 0;}</style><style>#export-svg{font-family:"Recursive Variable",arial,sans-serif;font-size:14px;fill:#ccc;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#export-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#export-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#export-svg .error-icon{fill:hsl(20, 1.5873015873%, 12.3529411765%);}#export-svg .error-text{fill:rgb(222.9999999999, 223.6666666666, 223.9999999999);stroke:rgb(222.9999999999, 223.6666666666, 223.9999999999);}#export-svg .edge-thickness-normal{stroke-width:2px;}#export-svg .edge-thickness-thick{stroke-width:3.5px;}#export-svg .edge-pattern-solid{stroke-dasharray:0;}#export-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#export-svg .edge-pattern-dashed{stroke-dasharray:3;}#export-svg .edge-pattern-dotted{stroke-dasharray:2;}#export-svg .marker{fill:#cccccc;stroke:#cccccc;}#export-svg .marker.cross{stroke:#cccccc;}#export-svg svg{font-family:"Recursive Variable",arial,sans-serif;font-size:14px;}#export-svg p{margin:0;}#export-svg g.classGroup text{fill:#FFFFFF;stroke:none;font-family:"Recursive Variable",arial,sans-serif;font-size:10px;}#export-svg g.classGroup text .title{font-weight:bolder;}#export-svg .nodeLabel,#export-svg .edgeLabel{color:#ccc;}#export-svg .noteLabel .nodeLabel,#export-svg .noteLabel .edgeLabel{color:#28253D;}#export-svg .edgeLabel .label rect{fill:#111113;}#export-svg .label text{fill:#ccc;}#export-svg .labelBkg{background:#111113;}#export-svg .edgeLabel .label span{background:#111113;}#export-svg .classTitle{font-weight:bolder;}#export-svg .node rect,#export-svg .node circle,#export-svg .node ellipse,#export-svg .node polygon,#export-svg .node path{fill:#111113;stroke:#FFFFFF;stroke-width:2;}#export-svg .divider{stroke:#FFFFFF;stroke-width:1;}#export-svg g.clickable{cursor:pointer;}#export-svg g.classGroup rect{fill:#111113;stroke:#FFFFFF;}#export-svg g.classGroup line{stroke:#FFFFFF;stroke-width:1;}#export-svg .classLabel .box{stroke:none;stroke-width:0;fill:#111113;opacity:0.5;}#export-svg .classLabel .label{fill:#FFFFFF;font-size:10px;}#export-svg .relation{stroke:#cccccc;stroke-width:2;fill:none;}#export-svg .dashed-line{stroke-dasharray:3;}#export-svg .dotted-line{stroke-dasharray:1 2;}#export-svg #compositionStart,#export-svg .composition{fill:#cccccc!important;stroke:#cccccc!important;stroke-width:1;}#export-svg #compositionEnd,#export-svg .composition{fill:#cccccc!important;stroke:#cccccc!important;stroke-width:1;}#export-svg #dependencyStart,#export-svg .dependency{fill:#cccccc!important;stroke:#cccccc!important;stroke-width:1;}#export-svg #dependencyStart,#export-svg .dependency{fill:#cccccc!important;stroke:#cccccc!important;stroke-width:1;}#export-svg #extensionStart,#export-svg .extension{fill:transparent!important;stroke:#cccccc!important;stroke-width:1;}#export-svg #extensionEnd,#export-svg .extension{fill:transparent!important;stroke:#cccccc!important;stroke-width:1;}#export-svg #aggregationStart,#export-svg .aggregation{fill:transparent!important;stroke:#cccccc!important;stroke-width:1;}#export-svg #aggregationEnd,#export-svg .aggregation{fill:transparent!important;stroke:#cccccc!important;stroke-width:1;}#export-svg #lollipopStart,#export-svg .lollipop{fill:#111113!important;stroke:#cccccc!important;stroke-width:1;}#export-svg #lollipopEnd,#export-svg .lollipop{fill:#111113!important;stroke:#cccccc!important;stroke-width:1;}#export-svg .edgeTerminals{font-size:11px;line-height:initial;}#export-svg .classTitleText{text-anchor:middle;font-size:18px;fill:#ccc;}#export-svg .edgeLabel{background-color:hsl(180, 1.5873015873%, 28.3529411765%);text-align:center;}#export-svg .edgeLabel p{background-color:hsl(180, 1.5873015873%, 28.3529411765%);}#export-svg .edgeLabel rect{opacity:0.5;background-color:hsl(180, 1.5873015873%, 28.3529411765%);fill:hsl(180, 1.5873015873%, 28.3529411765%);}#export-svg .cluster rect{fill:#1E1A2E;stroke:#BDBCCC;stroke-width:2px;}#export-svg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#export-svg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#export-svg .node .neo-node{stroke:#FFFFFF;}#export-svg [data-look="neo"].node rect,#export-svg [data-look="neo"].cluster rect,#export-svg [data-look="neo"].node polygon{stroke:#FFFFFF;filter:url(#drop-shadow);}#export-svg [data-look="neo"].node path{stroke:#FFFFFF;stroke-width:2;}#export-svg [data-look="neo"].node .outer-path{filter:url(#drop-shadow);}#export-svg [data-look="neo"].node .neo-line path{stroke:#FFFFFF;filter:none;}#export-svg [data-look="neo"].node circle{stroke:#FFFFFF;filter:url(#drLine truncated

Before

Width:  |  Height:  |  Size: 126 KiB

@@ -1,102 +0,0 @@
<svg id="export-svg" width="100%" xmlns="http://www.w3.org/2000/svg" style="max-width: 1332px;" viewBox="-50 -10 1332 1090" role="graphics-document document" aria-roledescription="sequence"><style xmlns="http://www.w3.org/1999/xhtml">/* Google Inc.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION &amp; CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
*/
@font-face {
font-family: 'Recursive Variable';
font-style: normal;
font-display: swap;
font-weight: 300 1000;
src: url("data:font/woff2;base64,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 truncated
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}</style><style xmlns="http://www.w3.org/1999/xhtml">@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"); p {margin: 0;}</style><rect x="40" y="618" fill="rgb(255, 235, 235)" width="1138" height="249" class="rect"/><rect x="40" y="346" fill="rgb(255, 245, 235)" width="636" height="213" class="rect"/><rect x="40" y="75" fill="rgb(235, 245, 255)" width="636" height="261" class="rect"/><g><rect x="1082" y="974" fill="#eaeaea" stroke="#666" width="150" height="65" name="JavaServer" rx="6" ry="6" class="actor actor-bottom" data-look="neo" style="stroke: rgb(251, 146, 60); fill: rgb(255, 247, 237);" filter="url(#drop-shadow)"/><text x="1157" y="1006.5" style="text-anchor: middle; font-size: 16px; font-weight: 400;" dominant-baseline="central" alignment-baseline="central" class="actor actor-box"><tspan x="1157" dy="0">Java Server</tspan></text></g><g><rect x="566" y="974" fill="#eaeaea" stroke="#666" width="150" height="65" name="Geyser" rx="6" ry="6" class="actor actor-bottom" data-look="neo" style="stroke: rgb(45, 212, 191); fill: rgb(240, 253, 250);" filter="url(#drop-shadow)"/><text x="641" y="1006.5" style="text-anchor: middle; font-size: 16px; font-weight: 400;" dominant-baseline="central" alignment-baseline="central" class="actor actor-box"><tspan x="641" dy="0">Geyser</tspan></text></g><g><rect x="0" y="974" fill="#eaeaea" stroke="#666" width="150" height="65" name="Client" rx="6" ry="6" class="actor actor-bottom" data-look="neo" style="stroke: rgb(232, 121, 249); fill: rgb(253, 244, 255);" filter="url(#drop-shadow)"/><text x="75" y="1006.5" style="text-anchor: middle; font-size: 16px; font-weight: 400;" dominant-baseline="central" alignment-baseline="central" class="actor actor-box"><tspan x="75" dy="0">Client</tspan></text></g><g><line id="actor222" x1="1157" y1="65" x2="1157" y2="974" class="actor-line 200" stroke-width="0.5px" stroke="#999" name="JavaServer" data-et="life-line" data-id="JavaServer"/><g id="root-222" data-look="neo" data-et="participant" data-id="JavaServer"><rect x="1082" y="0" fill="#eaeaea" stroke="#666" width="150" height="65" name="JavaServer" rx="6" ry="6" class="actor actor-top" data-look="neo" style="stroke: rgb(251, 146, 60); fill: rgb(255, 247, 237);" filter="url(#drop-shadow)"/><defs><filter id="drop-shadow" height="130%" width="130%"><feDropShadow dx="4" dy="4" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"/></filter></defs><text x="1157" y="32.5" style="text-anchor: middle; font-size: 16px; font-weight: 400;" dominant-baseline="central" alignment-baseline="central" class="actor actor-box"><tspan x="1157" dy="0">Java Server</tspan></text></g></g><g><line id="actor221" x1="641" y1="65" x2="641" y2="974" class="actor-line 200" stroke-width="0.5px" stroke="#999" name="Geyser" data-et="life-line" data-id="Geyser"/><g id="root-221" data-look="neo" data-et="participant" data-id="Geyser"><rect x="566" y="0" fill="#eaeaea" stroke="#666" width="150" height="65" name="Geyser" rx="6" ry="6" class="actor actor-top" data-look="neo" style="stroke: rgb(45, 212, 191); fill: rgb(240, 253, 250);" filter="url(#drop-shadow)"/><defs><filter id="drop-shadow" height="130%" width="130%"><feDropShadow dx="4" dy="4" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"/></filter></defs><text x="641" y="32.5" style="text-anchor: middle; font-size: 16px; font-weight: 400;" dominant-baseline="central" alignment-baseline="central" class="actor actor-box"><tspan x="641" dy="0">Geyser</tspan></text></g></g><g><line id="actor220" x1="75" y1="65" x2="75" y2="974" class="actor-line 200" stroke-width="0.5px" stroke="#999" name="Client" data-et="life-line" data-id="Client"/><g id="root-220" data-look="neo" data-et="participant" data-id="Client"><rect x="0" y="0" fill="#eaeaea" stroke="#666" width="150" height="65" name="Client" rx="6" ry="6" class="actor actor-top" data-look="neo" style="stroke: rgb(232, 121, 249); fill: rgb(253, 244, 255);" filter="url(#drop-shadow)"/><defs><filter id="drop-shadow" height="130%" width="130%"><feDropShadow dx="4" dy="4" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"/></filter></defs><text x="75" y="32.5" style="text-anchor: middle; font-size: 16px; font-weight: 400;" dominant-baseline="central" alignment-baseline="central" class="actor actor-box"><tspan x="75" dy="0">Client</tspan></text></g></g><style>#export-svg{font-family:"Recursive Variable",arial,sans-serif;font-size:14px;fill:#28253D;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#export-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#export-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#export-svg .error-icon{fill:#ffffff;}#export-svg .error-text{fill:#000000;stroke:#000000;}#export-svg .edge-thickness-normal{stroke-width:2pLine truncated

Before

Width:  |  Height:  |  Size: 117 KiB

@@ -1,102 +0,0 @@
<svg id="export-svg" width="100%" xmlns="http://www.w3.org/2000/svg" style="max-width: 1332px;" viewBox="-50 -10 1332 1090" role="graphics-document document" aria-roledescription="sequence"><style xmlns="http://www.w3.org/1999/xhtml">/* Google Inc.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION &amp; CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
*/
@font-face {
font-family: 'Recursive Variable';
font-style: normal;
font-display: swap;
font-weight: 300 1000;
src: url("data:font/woff2;base64,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 truncated
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}</style><style xmlns="http://www.w3.org/1999/xhtml">@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"); p {margin: 0;}</style><rect x="40" y="618" fill="rgb(1, 50, 50)" width="1138" height="249" class="rect"/><rect x="40" y="346" fill="rgb(1, 25, 50)" width="636" height="213" class="rect"/><rect x="40" y="75" fill="rgb(1, 1, 50)" width="636" height="261" class="rect"/><g><rect x="1082" y="974" fill="#eaeaea" stroke="#666" width="150" height="65" name="JavaServer" rx="6" ry="6" class="actor actor-bottom" data-look="neo" style="stroke: rgb(251, 146, 60);" filter="url(#drop-shadow)"/><text x="1157" y="1006.5" style="text-anchor: middle; font-size: 16px; font-weight: 400;" dominant-baseline="central" alignment-baseline="central" class="actor actor-box"><tspan x="1157" dy="0">Java Server</tspan></text></g><g><rect x="566" y="974" fill="#eaeaea" stroke="#666" width="150" height="65" name="Geyser" rx="6" ry="6" class="actor actor-bottom" data-look="neo" style="stroke: rgb(45, 212, 191);" filter="url(#drop-shadow)"/><text x="641" y="1006.5" style="text-anchor: middle; font-size: 16px; font-weight: 400;" dominant-baseline="central" alignment-baseline="central" class="actor actor-box"><tspan x="641" dy="0">Geyser</tspan></text></g><g><rect x="0" y="974" fill="#eaeaea" stroke="#666" width="150" height="65" name="Client" rx="6" ry="6" class="actor actor-bottom" data-look="neo" style="stroke: rgb(232, 121, 249);" filter="url(#drop-shadow)"/><text x="75" y="1006.5" style="text-anchor: middle; font-size: 16px; font-weight: 400;" dominant-baseline="central" alignment-baseline="central" class="actor actor-box"><tspan x="75" dy="0">Client</tspan></text></g><g><line id="actor5" x1="1157" y1="65" x2="1157" y2="974" class="actor-line 200" stroke-width="0.5px" stroke="#999" name="JavaServer" data-et="life-line" data-id="JavaServer"/><g id="root-5" data-look="neo" data-et="participant" data-id="JavaServer"><rect x="1082" y="0" fill="#eaeaea" stroke="#666" width="150" height="65" name="JavaServer" rx="6" ry="6" class="actor actor-top" data-look="neo" style="stroke: rgb(251, 146, 60);" filter="url(#drop-shadow)"/><defs><filter id="drop-shadow" height="130%" width="130%"><feDropShadow dx="4" dy="4" stdDeviation="0" flood-opacity="0.06" flood-color="#FFFFFF"/></filter></defs><text x="1157" y="32.5" style="text-anchor: middle; font-size: 16px; font-weight: 400;" dominant-baseline="central" alignment-baseline="central" class="actor actor-box"><tspan x="1157" dy="0">Java Server</tspan></text></g></g><g><line id="actor4" x1="641" y1="65" x2="641" y2="974" class="actor-line 200" stroke-width="0.5px" stroke="#999" name="Geyser" data-et="life-line" data-id="Geyser"/><g id="root-4" data-look="neo" data-et="participant" data-id="Geyser"><rect x="566" y="0" fill="#eaeaea" stroke="#666" width="150" height="65" name="Geyser" rx="6" ry="6" class="actor actor-top" data-look="neo" style="stroke: rgb(45, 212, 191);" filter="url(#drop-shadow)"/><defs><filter id="drop-shadow" height="130%" width="130%"><feDropShadow dx="4" dy="4" stdDeviation="0" flood-opacity="0.06" flood-color="#FFFFFF"/></filter></defs><text x="641" y="32.5" style="text-anchor: middle; font-size: 16px; font-weight: 400;" dominant-baseline="central" alignment-baseline="central" class="actor actor-box"><tspan x="641" dy="0">Geyser</tspan></text></g></g><g><line id="actor3" x1="75" y1="65" x2="75" y2="974" class="actor-line 200" stroke-width="0.5px" stroke="#999" name="Client" data-et="life-line" data-id="Client"/><g id="root-3" data-look="neo" data-et="participant" data-id="Client"><rect x="0" y="0" fill="#eaeaea" stroke="#666" width="150" height="65" name="Client" rx="6" ry="6" class="actor actor-top" data-look="neo" style="stroke: rgb(232, 121, 249);" filter="url(#drop-shadow)"/><defs><filter id="drop-shadow" height="130%" width="130%"><feDropShadow dx="4" dy="4" stdDeviation="0" flood-opacity="0.06" flood-color="#FFFFFF"/></filter></defs><text x="75" y="32.5" style="text-anchor: middle; font-size: 16px; font-weight: 400;" dominant-baseline="central" alignment-baseline="central" class="actor actor-box"><tspan x="75" dy="0">Client</tspan></text></g></g><style>#export-svg{font-family:"Recursive Variable",arial,sans-serif;font-size:14px;fill:#ccc;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#export-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#export-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#export-svg .error-icon{fill:hsl(20, 1.5873015873%, 12.3529411765%);}#export-svg .error-text{fill:rgb(222.9999999999, 223.6666666666, 223.9999999999);stroke:rgb(222.9999999999, 223.6666666666, 223.9999999999);}#export-svg .edge-thickness-normal{stroke-width:2px;}#export-svg .edge-thickness-thick{stroke-width:3.5px;}#export-Line truncated

Before

Width:  |  Height:  |  Size: 117 KiB

@@ -1,102 +0,0 @@
<svg id="export-svg" width="100%" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 1814.8438720703125px;" viewBox="308.9886474609375 -207.49822998046875 1814.8438720703125 937.8803100585938" role="graphics-document document" aria-roledescription="flowchart-v2"><style xmlns="http://www.w3.org/1999/xhtml">/* Google Inc.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION &amp; CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
*/
@font-face {
font-family: 'Recursive Variable';
font-style: normal;
font-display: swap;
font-weight: 300 1000;
src: url("data:font/woff2;base64,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 truncated
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}</style><style xmlns="http://www.w3.org/1999/xhtml">@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"); p {margin: 0;}</style><style>#export-svg{font-family:"Recursive Variable",arial,sans-serif;font-size:14px;fill:#28253D;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#export-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#export-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#export-svg .error-icon{fill:#ffffff;}#export-svg .error-text{fill:#000000;stroke:#000000;}#export-svg .edge-thickness-normal{stroke-width:2px;}#export-svg .edge-thickness-thick{stroke-width:3.5px;}#export-svg .edge-pattern-solid{stroke-dasharray:0;}#export-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#export-svg .edge-pattern-dashed{stroke-dasharray:3;}#export-svg .edge-pattern-dotted{stroke-dasharray:2;}#export-svg .marker{fill:#000000;stroke:#000000;}#export-svg .marker.cross{stroke:#000000;}#export-svg svg{font-family:"Recursive Variable",arial,sans-serif;font-size:14px;}#export-svg p{margin:0;}#export-svg .label{font-family:"Recursive Variable",arial,sans-serif;color:#28253D;}#export-svg .cluster-label text{fill:#000000;}#export-svg .cluster-label span{color:#000000;}#export-svg .cluster-label span p{background-color:transparent;}#export-svg .label text,#export-svg span{fill:#28253D;color:#28253D;}#export-svg .node rect,#export-svg .node circle,#export-svg .node ellipse,#export-svg .node polygon,#export-svg .node path{fill:#ffffff;stroke:#28253D;stroke-width:2px;}#export-svg .rough-node .label text,#export-svg .node .label text,#export-svg .image-shape .label,#export-svg .icon-shape .label{text-anchor:middle;}#export-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#export-svg .rough-node .label,#export-svg .node .label,#export-svg .image-shape .label,#export-svg .icon-shape .label{text-align:center;}#export-svg .node.clickable{cursor:pointer;}#export-svg .root .anchor path{fill:#000000!important;stroke-width:0;stroke:#000000;}#export-svg .arrowheadPath{fill:#000000;}#export-svg .edgePath .path{stroke:#000000;stroke-width:2px;}#export-svg .flowchart-link{stroke:#000000;fill:none;}#export-svg .edgeLabel{background-color:hsl(-120, 0%, 80%);text-align:center;}#export-svg .edgeLabel p{background-color:hsl(-120, 0%, 80%);}#export-svg .edgeLabel rect{opacity:0.5;background-color:hsl(-120, 0%, 80%);fill:hsl(-120, 0%, 80%);}#export-svg .labelBkg{background-color:rgba(204, 204, 204, 0.5);}#export-svg .cluster rect{fill:#F9F9FB;stroke:#BDBCCC;stroke-width:2px;}#export-svg .cluster text{fill:#000000;}#export-svg .cluster span{color:#000000;}#export-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"Recursive Variable",arial,sans-serif;font-size:12px;background:#ffffff;border:1px solid hsl(0, 0%, 90%);border-radius:2px;pointer-events:none;z-index:100;}#export-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#28253D;}#export-svg rect.text{fill:none;stroke-width:0;}#export-svg .icon-shape,#export-svg .image-shape{background-color:hsl(-120, 0%, 80%);text-align:center;}#export-svg .icon-shape p,#export-svg .image-shape p{background-color:hsl(-120, 0%, 80%);padding:2px;}#export-svg .icon-shape rect,#export-svg .image-shape rect{opacity:0.5;background-color:hsl(-120, 0%, 80%);fill:hsl(-120, 0%, 80%);}#export-svg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#export-svg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#export-svg .node .neo-node{stroke:#28253D;}#export-svg [data-look="neo"].node rect,#export-svg [data-look="neo"].cluster rect,#export-svg [data-look="neo"].node polygon{stroke:#28253D;filter:url(#drop-shadow);}#export-svg [data-look="neo"].node path{stroke:#28253D;stroke-width:2;}#export-svg [data-look="neo"].node .outer-path{filter:url(#drop-shadow);}#export-svg [data-look="neo"].node .neo-line path{stroke:#28253D;filter:none;}#export-svg [data-look="neo"].node circle{stroke:#28253D;filter:url(#drop-shadow);}#export-svg [data-look="neo"].node circle .state-start{fill:#000000;}#export-svg [data-look="neo"].statediagram-cluster rect{fill:#F9F9FB;stroke:#28253D;stroke-width:2;}#export-svg [data-look="neo"].icon-shape .icon{fill:#28253D;filter:url(#drop-shadow);}#export-svg [data-look="neo"].icon-shape .icon-neo path{stroke:#28253D;filter:url(#drop-shadow);}#export-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><marker id="export-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="7.75" refY="7" markerUnits="userSpaceOnUse" markerWidth="10.5" markerHeight="14" orient="auto"><path d="M 0 0 L 11.5 7 L 0 14 z" class="arrowMarkerPath" style="stroke-width: 0pLine truncated

Before

Width:  |  Height:  |  Size: 115 KiB

@@ -1,102 +0,0 @@
<svg id="export-svg" width="100%" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 1814.84px;" viewBox="308.9886474609375 -207.49822998046875 1814.8438720703125 937.8803100585938" role="graphics-document document" aria-roledescription="flowchart-v2"><style xmlns="http://www.w3.org/1999/xhtml">/* Google Inc.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION &amp; CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
*/
@font-face {
font-family: 'Recursive Variable';
font-style: normal;
font-display: swap;
font-weight: 300 1000;
src: url("data:font/woff2;base64,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 truncated
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}</style><style xmlns="http://www.w3.org/1999/xhtml">@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"); p {margin: 0;}</style><style>#export-svg{font-family:"Recursive Variable",arial,sans-serif;font-size:14px;fill:#ccc;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#export-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#export-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#export-svg .error-icon{fill:hsl(20, 1.5873015873%, 12.3529411765%);}#export-svg .error-text{fill:rgb(222.9999999999, 223.6666666666, 223.9999999999);stroke:rgb(222.9999999999, 223.6666666666, 223.9999999999);}#export-svg .edge-thickness-normal{stroke-width:2px;}#export-svg .edge-thickness-thick{stroke-width:3.5px;}#export-svg .edge-pattern-solid{stroke-dasharray:0;}#export-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#export-svg .edge-pattern-dashed{stroke-dasharray:3;}#export-svg .edge-pattern-dotted{stroke-dasharray:2;}#export-svg .marker{fill:#cccccc;stroke:#cccccc;}#export-svg .marker.cross{stroke:#cccccc;}#export-svg svg{font-family:"Recursive Variable",arial,sans-serif;font-size:14px;}#export-svg p{margin:0;}#export-svg .label{font-family:"Recursive Variable",arial,sans-serif;color:#e0dfdf;}#export-svg .cluster-label text{fill:rgb(222.9999999999, 223.6666666666, 223.9999999999);}#export-svg .cluster-label span{color:rgb(222.9999999999, 223.6666666666, 223.9999999999);}#export-svg .cluster-label span p{background-color:transparent;}#export-svg .label text,#export-svg span{fill:#e0dfdf;color:#e0dfdf;}#export-svg .node rect,#export-svg .node circle,#export-svg .node ellipse,#export-svg .node polygon,#export-svg .node path{fill:#111113;stroke:#FFFFFF;stroke-width:2px;}#export-svg .rough-node .label text,#export-svg .node .label text,#export-svg .image-shape .label,#export-svg .icon-shape .label{text-anchor:middle;}#export-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#export-svg .rough-node .label,#export-svg .node .label,#export-svg .image-shape .label,#export-svg .icon-shape .label{text-align:center;}#export-svg .node.clickable{cursor:pointer;}#export-svg .root .anchor path{fill:#cccccc!important;stroke-width:0;stroke:#cccccc;}#export-svg .arrowheadPath{fill:#cccccc;}#export-svg .edgePath .path{stroke:#cccccc;stroke-width:2px;}#export-svg .flowchart-link{stroke:#cccccc;fill:none;}#export-svg .edgeLabel{background-color:hsl(180, 1.5873015873%, 28.3529411765%);text-align:center;}#export-svg .edgeLabel p{background-color:hsl(180, 1.5873015873%, 28.3529411765%);}#export-svg .edgeLabel rect{opacity:0.5;background-color:hsl(180, 1.5873015873%, 28.3529411765%);fill:hsl(180, 1.5873015873%, 28.3529411765%);}#export-svg .labelBkg{background-color:rgba(71.1523809525, 73.4476190477, 73.4476190477, 0.5);}#export-svg .cluster rect{fill:#1E1A2E;stroke:#BDBCCC;stroke-width:2px;}#export-svg .cluster text{fill:rgb(222.9999999999, 223.6666666666, 223.9999999999);}#export-svg .cluster span{color:rgb(222.9999999999, 223.6666666666, 223.9999999999);}#export-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"Recursive Variable",arial,sans-serif;font-size:12px;background:hsl(20, 1.5873015873%, 12.3529411765%);border:1px solid rgba(255, 255, 255, 0.25);border-radius:2px;pointer-events:none;z-index:100;}#export-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#ccc;}#export-svg rect.text{fill:none;stroke-width:0;}#export-svg .icon-shape,#export-svg .image-shape{background-color:hsl(180, 1.5873015873%, 28.3529411765%);text-align:center;}#export-svg .icon-shape p,#export-svg .image-shape p{background-color:hsl(180, 1.5873015873%, 28.3529411765%);padding:2px;}#export-svg .icon-shape rect,#export-svg .image-shape rect{opacity:0.5;background-color:hsl(180, 1.5873015873%, 28.3529411765%);fill:hsl(180, 1.5873015873%, 28.3529411765%);}#export-svg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#export-svg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#export-svg .node .neo-node{stroke:#FFFFFF;}#export-svg [data-look="neo"].node rect,#export-svg [data-look="neo"].cluster rect,#export-svg [data-look="neo"].node polygon{stroke:#FFFFFF;filter:url(#drop-shadow);}#export-svg [data-look="neo"].node path{stroke:#FFFFFF;stroke-width:2;}#export-svg [data-look="neo"].node .outer-path{filter:url(#drop-shadow);}#export-svg [data-look="neo"].node .neo-line path{stroke:#FFFFFF;filter:none;}#export-svg [data-look="neo"].node circle{stroke:#FFFFFF;filter:url(#drop-shadow);}#export-svg [data-look="neo"].node circle .state-start{fill:#000000;}#export-svg [data-look="neo"].statediagram-cluster rect{fill:#16141F;stroke:#FFFFFF;stroke-width:2;}#export-svg [data-look="nLine truncated

Before

Width:  |  Height:  |  Size: 116 KiB

@@ -1,102 +0,0 @@
<svg id="export-svg" width="100%" xmlns="http://www.w3.org/2000/svg" style="max-width: 816px;" viewBox="-50 -10 816 1062" role="graphics-document document" aria-roledescription="sequence"><style xmlns="http://www.w3.org/1999/xhtml">/* Google Inc.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION &amp; CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
*/
@font-face {
font-family: 'Recursive Variable';
font-style: normal;
font-display: swap;
font-weight: 300 1000;
src: url("data:font/woff2;base64,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 truncated
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}</style><style xmlns="http://www.w3.org/1999/xhtml">@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"); p {margin: 0;}</style><rect x="40" y="617" fill="rgb(255, 235, 235)" width="636" height="309" class="rect"/><rect x="40" y="346" fill="rgb(255, 245, 235)" width="636" height="261" class="rect"/><rect x="40" y="75" fill="rgb(235, 245, 255)" width="636" height="261" class="rect"/><g><rect x="566" y="946" fill="#eaeaea" stroke="#666" width="150" height="65" name="Geyser" rx="6" ry="6" class="actor actor-bottom" data-look="neo" style="stroke: rgb(45, 212, 191); fill: rgb(240, 253, 250);" filter="url(#drop-shadow)"/><text x="641" y="978.5" style="text-anchor: middle; font-size: 16px; font-weight: 400;" dominant-baseline="central" alignment-baseline="central" class="actor actor-box"><tspan x="641" dy="0">Geyser</tspan></text></g><g><rect x="0" y="946" fill="#eaeaea" stroke="#666" width="150" height="65" name="Client" rx="6" ry="6" class="actor actor-bottom" data-look="neo" style="stroke: rgb(232, 121, 249); fill: rgb(253, 244, 255);" filter="url(#drop-shadow)"/><text x="75" y="978.5" style="text-anchor: middle; font-size: 16px; font-weight: 400;" dominant-baseline="central" alignment-baseline="central" class="actor actor-box"><tspan x="75" dy="0">Client</tspan></text></g><g><line id="actor447" x1="641" y1="65" x2="641" y2="946" class="actor-line 200" stroke-width="0.5px" stroke="#999" name="Geyser" data-et="life-line" data-id="Geyser"/><g id="root-447" data-look="neo" data-et="participant" data-id="Geyser"><rect x="566" y="0" fill="#eaeaea" stroke="#666" width="150" height="65" name="Geyser" rx="6" ry="6" class="actor actor-top" data-look="neo" style="stroke: rgb(45, 212, 191); fill: rgb(240, 253, 250);" filter="url(#drop-shadow)"/><defs><filter id="drop-shadow" height="130%" width="130%"><feDropShadow dx="4" dy="4" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"/></filter></defs><text x="641" y="32.5" style="text-anchor: middle; font-size: 16px; font-weight: 400;" dominant-baseline="central" alignment-baseline="central" class="actor actor-box"><tspan x="641" dy="0">Geyser</tspan></text></g></g><g><line id="actor446" x1="75" y1="65" x2="75" y2="946" class="actor-line 200" stroke-width="0.5px" stroke="#999" name="Client" data-et="life-line" data-id="Client"/><g id="root-446" data-look="neo" data-et="participant" data-id="Client"><rect x="0" y="0" fill="#eaeaea" stroke="#666" width="150" height="65" name="Client" rx="6" ry="6" class="actor actor-top" data-look="neo" style="stroke: rgb(232, 121, 249); fill: rgb(253, 244, 255);" filter="url(#drop-shadow)"/><defs><filter id="drop-shadow" height="130%" width="130%"><feDropShadow dx="4" dy="4" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"/></filter></defs><text x="75" y="32.5" style="text-anchor: middle; font-size: 16px; font-weight: 400;" dominant-baseline="central" alignment-baseline="central" class="actor actor-box"><tspan x="75" dy="0">Client</tspan></text></g></g><style>#export-svg{font-family:"Recursive Variable",arial,sans-serif;font-size:14px;fill:#28253D;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#export-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#export-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#export-svg .error-icon{fill:#ffffff;}#export-svg .error-text{fill:#000000;stroke:#000000;}#export-svg .edge-thickness-normal{stroke-width:2px;}#export-svg .edge-thickness-thick{stroke-width:3.5px;}#export-svg .edge-pattern-solid{stroke-dasharray:0;}#export-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#export-svg .edge-pattern-dashed{stroke-dasharray:3;}#export-svg .edge-pattern-dotted{stroke-dasharray:2;}#export-svg .marker{fill:#000000;stroke:#000000;}#export-svg .marker.cross{stroke:#000000;}#export-svg svg{font-family:"Recursive Variable",arial,sans-serif;font-size:14px;}#export-svg p{margin:0;}#export-svg .actor{stroke:#28253D;fill:#ffffff;stroke-width:2;}#export-svg rect.actor.outer-path[data-look="neo"]{filter:url(#drop-shadow);}#export-svg rect.note[data-look="neo"]{stroke:#FACC15;fill:#fff5ad;filter:url(#drop-shadow);stroke-width:2;}#export-svg text.actor&gt;tspan{fill:#28253D;stroke:none;}#export-svg .actor-line{stroke:#28253D;}#export-svg .messageLine0{stroke-width:2;stroke-dasharray:none;stroke:#28253D;}#export-svg .messageLine1{stroke-width:2;stroke-dasharray:2,2;stroke:#28253D;}#export-svg #arrowhead path{fill:#28253D;stroke:#28253D;}#export-svg .sequenceNumber{fill:#ffffff;}#export-svg #sequencenumber{fill:#28253D;}#export-svg #crosshead path{fill:#28253D;stroke:#28253D;}#export-svg .messageText{fill:#28253D;stroke:none;}#export-svg .labelBox{stroke:#28253D;fill:#ffffff;filter:url(#drop-shadow);}#export-svg .labelText,#export-svg .labelTexLine truncated

Before

Width:  |  Height:  |  Size: 116 KiB

@@ -1,102 +0,0 @@
<svg id="export-svg" width="100%" xmlns="http://www.w3.org/2000/svg" style="max-width: 816px;" viewBox="-50 -10 816 1062" role="graphics-document document" aria-roledescription="sequence"><style xmlns="http://www.w3.org/1999/xhtml">/* Google Inc.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION &amp; CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
*/
@font-face {
font-family: 'Recursive Variable';
font-style: normal;
font-display: swap;
font-weight: 300 1000;
src: url("data:font/woff2;base64,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 truncated
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}</style><style xmlns="http://www.w3.org/1999/xhtml">@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"); p {margin: 0;}</style><rect x="40" y="617" fill="rgb(1, 50, 50)" width="636" height="309" class="rect"/><rect x="40" y="346" fill="rgb(1, 25, 50)" width="636" height="261" class="rect"/><rect x="40" y="75" fill="rgb(1, 1, 50)" width="636" height="261" class="rect"/><g><rect x="566" y="946" fill="#eaeaea" stroke="#666" width="150" height="65" name="Geyser" rx="6" ry="6" class="actor actor-bottom" data-look="neo" style="stroke: rgb(45, 212, 191);" filter="url(#drop-shadow)"/><text x="641" y="978.5" style="text-anchor: middle; font-size: 16px; font-weight: 400;" dominant-baseline="central" alignment-baseline="central" class="actor actor-box"><tspan x="641" dy="0">Geyser</tspan></text></g><g><rect x="0" y="946" fill="#eaeaea" stroke="#666" width="150" height="65" name="Client" rx="6" ry="6" class="actor actor-bottom" data-look="neo" style="stroke: rgb(232, 121, 249);" filter="url(#drop-shadow)"/><text x="75" y="978.5" style="text-anchor: middle; font-size: 16px; font-weight: 400;" dominant-baseline="central" alignment-baseline="central" class="actor actor-box"><tspan x="75" dy="0">Client</tspan></text></g><g><line id="actor473" x1="641" y1="65" x2="641" y2="946" class="actor-line 200" stroke-width="0.5px" stroke="#999" name="Geyser" data-et="life-line" data-id="Geyser"/><g id="root-473" data-look="neo" data-et="participant" data-id="Geyser"><rect x="566" y="0" fill="#eaeaea" stroke="#666" width="150" height="65" name="Geyser" rx="6" ry="6" class="actor actor-top" data-look="neo" style="stroke: rgb(45, 212, 191);" filter="url(#drop-shadow)"/><defs><filter id="drop-shadow" height="130%" width="130%"><feDropShadow dx="4" dy="4" stdDeviation="0" flood-opacity="0.06" flood-color="#FFFFFF"/></filter></defs><text x="641" y="32.5" style="text-anchor: middle; font-size: 16px; font-weight: 400;" dominant-baseline="central" alignment-baseline="central" class="actor actor-box"><tspan x="641" dy="0">Geyser</tspan></text></g></g><g><line id="actor472" x1="75" y1="65" x2="75" y2="946" class="actor-line 200" stroke-width="0.5px" stroke="#999" name="Client" data-et="life-line" data-id="Client"/><g id="root-472" data-look="neo" data-et="participant" data-id="Client"><rect x="0" y="0" fill="#eaeaea" stroke="#666" width="150" height="65" name="Client" rx="6" ry="6" class="actor actor-top" data-look="neo" style="stroke: rgb(232, 121, 249);" filter="url(#drop-shadow)"/><defs><filter id="drop-shadow" height="130%" width="130%"><feDropShadow dx="4" dy="4" stdDeviation="0" flood-opacity="0.06" flood-color="#FFFFFF"/></filter></defs><text x="75" y="32.5" style="text-anchor: middle; font-size: 16px; font-weight: 400;" dominant-baseline="central" alignment-baseline="central" class="actor actor-box"><tspan x="75" dy="0">Client</tspan></text></g></g><style>#export-svg{font-family:"Recursive Variable",arial,sans-serif;font-size:14px;fill:#ccc;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#export-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#export-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#export-svg .error-icon{fill:hsl(20, 1.5873015873%, 12.3529411765%);}#export-svg .error-text{fill:rgb(222.9999999999, 223.6666666666, 223.9999999999);stroke:rgb(222.9999999999, 223.6666666666, 223.9999999999);}#export-svg .edge-thickness-normal{stroke-width:2px;}#export-svg .edge-thickness-thick{stroke-width:3.5px;}#export-svg .edge-pattern-solid{stroke-dasharray:0;}#export-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#export-svg .edge-pattern-dashed{stroke-dasharray:3;}#export-svg .edge-pattern-dotted{stroke-dasharray:2;}#export-svg .marker{fill:#cccccc;stroke:#cccccc;}#export-svg .marker.cross{stroke:#cccccc;}#export-svg svg{font-family:"Recursive Variable",arial,sans-serif;font-size:14px;}#export-svg p{margin:0;}#export-svg .actor{stroke:#FFFFFF;fill:#111113;stroke-width:2;}#export-svg rect.actor.outer-path[data-look="neo"]{filter:url(#drop-shadow);}#export-svg rect.note[data-look="neo"]{stroke:#FACC15;fill:#FEF9C3;filter:url(#drop-shadow);stroke-width:2;}#export-svg text.actor&gt;tspan{fill:#e0dfdf;stroke:none;}#export-svg .actor-line{stroke:#FFFFFF;}#export-svg .messageLine0{stroke-width:2;stroke-dasharray:none;stroke:#FFFFFF;}#export-svg .messageLine1{stroke-width:2;stroke-dasharray:2,2;stroke:#FFFFFF;}#export-svg #arrowhead path{fill:#FFFFFF;stroke:#FFFFFF;}#export-svg .sequenceNumber{fill:#333333;}#export-svg #sequencenumber{fill:#FFFFFF;}#export-svg #crosshead path{fill:#FFFFFF;stroke:#FFFFFF;}#export-svg .messageText{fill:#ccc;stroke:none;}#export-svg .labelBox{stroke:#BDBCCC;fill:#111113;filter:url(#drop-shadow);}#export-svg .labelText,#export-svg .labelText&gtLine truncated

Before

Width:  |  Height:  |  Size: 116 KiB

@@ -1,102 +0,0 @@
<svg id="export-svg" width="100%" xmlns="http://www.w3.org/2000/svg" class="classDiagram" style="max-width: 1155.88330078125px;" viewBox="0 0 1155.88330078125 1208" role="graphics-document document" aria-roledescription="class"><style xmlns="http://www.w3.org/1999/xhtml">/* Google Inc.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION &amp; CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
*/
@font-face {
font-family: 'Recursive Variable';
font-style: normal;
font-display: swap;
font-weight: 300 1000;
src: url("data:font/woff2;base64,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 truncated
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}</style><style xmlns="http://www.w3.org/1999/xhtml">@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"); p {margin: 0;}</style><style>#export-svg{font-family:"Recursive Variable",arial,sans-serif;font-size:14px;fill:#28253D;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#export-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#export-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#export-svg .error-icon{fill:#ffffff;}#export-svg .error-text{fill:#000000;stroke:#000000;}#export-svg .edge-thickness-normal{stroke-width:2px;}#export-svg .edge-thickness-thick{stroke-width:3.5px;}#export-svg .edge-pattern-solid{stroke-dasharray:0;}#export-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#export-svg .edge-pattern-dashed{stroke-dasharray:3;}#export-svg .edge-pattern-dotted{stroke-dasharray:2;}#export-svg .marker{fill:#000000;stroke:#000000;}#export-svg .marker.cross{stroke:#000000;}#export-svg svg{font-family:"Recursive Variable",arial,sans-serif;font-size:14px;}#export-svg p{margin:0;}#export-svg g.classGroup text{fill:#28253D;stroke:none;font-family:"Recursive Variable",arial,sans-serif;font-size:10px;}#export-svg g.classGroup text .title{font-weight:bolder;}#export-svg .nodeLabel,#export-svg .edgeLabel{color:#28253D;}#export-svg .noteLabel .nodeLabel,#export-svg .noteLabel .edgeLabel{color:#28253D;}#export-svg .edgeLabel .label rect{fill:#ffffff;}#export-svg .label text{fill:#28253D;}#export-svg .labelBkg{background:#ffffff;}#export-svg .edgeLabel .label span{background:#ffffff;}#export-svg .classTitle{font-weight:bolder;}#export-svg .node rect,#export-svg .node circle,#export-svg .node ellipse,#export-svg .node polygon,#export-svg .node path{fill:#ffffff;stroke:#28253D;stroke-width:2;}#export-svg .divider{stroke:#28253D;stroke-width:1;}#export-svg g.clickable{cursor:pointer;}#export-svg g.classGroup rect{fill:#ffffff;stroke:#28253D;}#export-svg g.classGroup line{stroke:#28253D;stroke-width:1;}#export-svg .classLabel .box{stroke:none;stroke-width:0;fill:#ffffff;opacity:0.5;}#export-svg .classLabel .label{fill:#28253D;font-size:10px;}#export-svg .relation{stroke:#000000;stroke-width:2;fill:none;}#export-svg .dashed-line{stroke-dasharray:3;}#export-svg .dotted-line{stroke-dasharray:1 2;}#export-svg #compositionStart,#export-svg .composition{fill:#000000!important;stroke:#000000!important;stroke-width:1;}#export-svg #compositionEnd,#export-svg .composition{fill:#000000!important;stroke:#000000!important;stroke-width:1;}#export-svg #dependencyStart,#export-svg .dependency{fill:#000000!important;stroke:#000000!important;stroke-width:1;}#export-svg #dependencyStart,#export-svg .dependency{fill:#000000!important;stroke:#000000!important;stroke-width:1;}#export-svg #extensionStart,#export-svg .extension{fill:transparent!important;stroke:#000000!important;stroke-width:1;}#export-svg #extensionEnd,#export-svg .extension{fill:transparent!important;stroke:#000000!important;stroke-width:1;}#export-svg #aggregationStart,#export-svg .aggregation{fill:transparent!important;stroke:#000000!important;stroke-width:1;}#export-svg #aggregationEnd,#export-svg .aggregation{fill:transparent!important;stroke:#000000!important;stroke-width:1;}#export-svg #lollipopStart,#export-svg .lollipop{fill:#ffffff!important;stroke:#000000!important;stroke-width:1;}#export-svg #lollipopEnd,#export-svg .lollipop{fill:#ffffff!important;stroke:#000000!important;stroke-width:1;}#export-svg .edgeTerminals{font-size:11px;line-height:initial;}#export-svg .classTitleText{text-anchor:middle;font-size:18px;fill:#28253D;}#export-svg .edgeLabel{background-color:hsl(-120, 0%, 80%);text-align:center;}#export-svg .edgeLabel p{background-color:hsl(-120, 0%, 80%);}#export-svg .edgeLabel rect{opacity:0.5;background-color:hsl(-120, 0%, 80%);fill:hsl(-120, 0%, 80%);}#export-svg .cluster rect{fill:#F9F9FB;stroke:#BDBCCC;stroke-width:2px;}#export-svg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#export-svg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#export-svg .node .neo-node{stroke:#28253D;}#export-svg [data-look="neo"].node rect,#export-svg [data-look="neo"].cluster rect,#export-svg [data-look="neo"].node polygon{stroke:#28253D;filter:url(#drop-shadow);}#export-svg [data-look="neo"].node path{stroke:#28253D;stroke-width:2;}#export-svg [data-look="neo"].node .outer-path{filter:url(#drop-shadow);}#export-svg [data-look="neo"].node .neo-line path{stroke:#28253D;filter:none;}#export-svg [data-look="neo"].node circle{stroke:#28253D;filter:url(#drop-shadow);}#export-svg [data-look="neo"].node circle .state-start{fill:#000000;}#export-svg [data-look="neo"].statediagram-cluster rect{fill:#F9F9FB;stroke:#28253D;stroke-width:2;}#export-svLine truncated

Before

Width:  |  Height:  |  Size: 135 KiB

@@ -1,102 +0,0 @@
<svg id="export-svg" width="100%" xmlns="http://www.w3.org/2000/svg" class="classDiagram" style="max-width: 1155.88px;" viewBox="0 0 1155.88330078125 1208" role="graphics-document document" aria-roledescription="class"><style xmlns="http://www.w3.org/1999/xhtml">/* Google Inc.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION &amp; CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
*/
@font-face {
font-family: 'Recursive Variable';
font-style: normal;
font-display: swap;
font-weight: 300 1000;
src: url("data:font/woff2;base64,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 truncated
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}</style><style xmlns="http://www.w3.org/1999/xhtml">@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"); p {margin: 0;}</style><style>#export-svg{font-family:"Recursive Variable",arial,sans-serif;font-size:14px;fill:#ccc;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#export-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#export-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#export-svg .error-icon{fill:hsl(20, 1.5873015873%, 12.3529411765%);}#export-svg .error-text{fill:rgb(222.9999999999, 223.6666666666, 223.9999999999);stroke:rgb(222.9999999999, 223.6666666666, 223.9999999999);}#export-svg .edge-thickness-normal{stroke-width:2px;}#export-svg .edge-thickness-thick{stroke-width:3.5px;}#export-svg .edge-pattern-solid{stroke-dasharray:0;}#export-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#export-svg .edge-pattern-dashed{stroke-dasharray:3;}#export-svg .edge-pattern-dotted{stroke-dasharray:2;}#export-svg .marker{fill:#cccccc;stroke:#cccccc;}#export-svg .marker.cross{stroke:#cccccc;}#export-svg svg{font-family:"Recursive Variable",arial,sans-serif;font-size:14px;}#export-svg p{margin:0;}#export-svg g.classGroup text{fill:#FFFFFF;stroke:none;font-family:"Recursive Variable",arial,sans-serif;font-size:10px;}#export-svg g.classGroup text .title{font-weight:bolder;}#export-svg .nodeLabel,#export-svg .edgeLabel{color:#ccc;}#export-svg .noteLabel .nodeLabel,#export-svg .noteLabel .edgeLabel{color:#28253D;}#export-svg .edgeLabel .label rect{fill:#111113;}#export-svg .label text{fill:#ccc;}#export-svg .labelBkg{background:#111113;}#export-svg .edgeLabel .label span{background:#111113;}#export-svg .classTitle{font-weight:bolder;}#export-svg .node rect,#export-svg .node circle,#export-svg .node ellipse,#export-svg .node polygon,#export-svg .node path{fill:#111113;stroke:#FFFFFF;stroke-width:2;}#export-svg .divider{stroke:#FFFFFF;stroke-width:1;}#export-svg g.clickable{cursor:pointer;}#export-svg g.classGroup rect{fill:#111113;stroke:#FFFFFF;}#export-svg g.classGroup line{stroke:#FFFFFF;stroke-width:1;}#export-svg .classLabel .box{stroke:none;stroke-width:0;fill:#111113;opacity:0.5;}#export-svg .classLabel .label{fill:#FFFFFF;font-size:10px;}#export-svg .relation{stroke:#cccccc;stroke-width:2;fill:none;}#export-svg .dashed-line{stroke-dasharray:3;}#export-svg .dotted-line{stroke-dasharray:1 2;}#export-svg #compositionStart,#export-svg .composition{fill:#cccccc!important;stroke:#cccccc!important;stroke-width:1;}#export-svg #compositionEnd,#export-svg .composition{fill:#cccccc!important;stroke:#cccccc!important;stroke-width:1;}#export-svg #dependencyStart,#export-svg .dependency{fill:#cccccc!important;stroke:#cccccc!important;stroke-width:1;}#export-svg #dependencyStart,#export-svg .dependency{fill:#cccccc!important;stroke:#cccccc!important;stroke-width:1;}#export-svg #extensionStart,#export-svg .extension{fill:transparent!important;stroke:#cccccc!important;stroke-width:1;}#export-svg #extensionEnd,#export-svg .extension{fill:transparent!important;stroke:#cccccc!important;stroke-width:1;}#export-svg #aggregationStart,#export-svg .aggregation{fill:transparent!important;stroke:#cccccc!important;stroke-width:1;}#export-svg #aggregationEnd,#export-svg .aggregation{fill:transparent!important;stroke:#cccccc!important;stroke-width:1;}#export-svg #lollipopStart,#export-svg .lollipop{fill:#111113!important;stroke:#cccccc!important;stroke-width:1;}#export-svg #lollipopEnd,#export-svg .lollipop{fill:#111113!important;stroke:#cccccc!important;stroke-width:1;}#export-svg .edgeTerminals{font-size:11px;line-height:initial;}#export-svg .classTitleText{text-anchor:middle;font-size:18px;fill:#ccc;}#export-svg .edgeLabel{background-color:hsl(180, 1.5873015873%, 28.3529411765%);text-align:center;}#export-svg .edgeLabel p{background-color:hsl(180, 1.5873015873%, 28.3529411765%);}#export-svg .edgeLabel rect{opacity:0.5;background-color:hsl(180, 1.5873015873%, 28.3529411765%);fill:hsl(180, 1.5873015873%, 28.3529411765%);}#export-svg .cluster rect{fill:#1E1A2E;stroke:#BDBCCC;stroke-width:2px;}#export-svg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#export-svg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#export-svg .node .neo-node{stroke:#FFFFFF;}#export-svg [data-look="neo"].node rect,#export-svg [data-look="neo"].cluster rect,#export-svg [data-look="neo"].node polygon{stroke:#FFFFFF;filter:url(#drop-shadow);}#export-svg [data-look="neo"].node path{stroke:#FFFFFF;stroke-width:2;}#export-svg [data-look="neo"].node .outer-path{filter:url(#drop-shadow);}#export-svg [data-look="neo"].node .neo-line path{stroke:#FFFFFF;filter:none;}#export-svg [data-look="neo"].node circle{stroke:#FFFFFF;filter:url(#drLine truncated

Before

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 339 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 KiB

+2 -3
View File
@@ -1,13 +1,12 @@
{
// This file is not used in compilation. It is here just for a nice editor experience.
"extends": "@docusaurus/tsconfig",
"esModuleInterop": true,
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"target": "ESNext",
"baseUrl": "."
},
"exclude": [
"**/node_modules",
"build",
"**/node_modules"
]
}
+1 -1
View File
@@ -6,7 +6,7 @@ description: 'These REST APIs provide web endpoints to query different informati
import DocCardList from '@theme/DocCardList'
# Overview of available REST APIs \{#overview-of-available-rest-apis}
# Overview of available REST APIs
Currently, there are two different Rest APIs you can use.
+2 -2
View File
@@ -5,8 +5,8 @@ description: 'Floodgate is a hybrid mode plugin that allows Minecraft: Bedrock A
---
# Overview
Floodgate is a hybrid mode server-plugin. It introduces new features:
- Ability for clients to join Minecraft: Java Edition servers with Minecraft: Bedrock accounts without needing a paid Minecraft: Java Edition account.
Floodgate is a hybrid mode plugin. It introduces new features:
- Ability to join Minecraft: Java Edition servers with Minecraft: Bedrock accounts without needing a paid Minecraft: Java Edition account.
- Ability to [see Bedrock player skins on Java edition](/wiki/floodgate/features#what-is-skin-uploading).
- Ability for plugins to [send Bedrock forms](/wiki/geyser/forms/).
- Ability to query players through the [Global Api](/wiki/api/api.geysermc.org/global-api/),
+1 -1
View File
@@ -45,7 +45,7 @@ Set `allow-invalid-usernames` to `true` in LuckPerms' config.
## Failed to verify username! (with Paper) {#failed-to-verify-username-with-paper}
To completely mitigate this issue, disable `perform-username-validation` in the [unsupported settings of the `config/paper-global.yml` file](https://docs.papermc.io/paper/reference/global-configuration#unsupported_settings) (`paper.yml` in the root server folder on servers below 1.19). Using Floodgate on the backend servers will also mitigate this issue.
To completely mitigate this issue, disable `perform-username-validation` in the [unsupported settings of the `config/paper-global.yml` file](https://paper.readthedocs.io/en/latest/server/configuration.html#unsupported_settings) (`paper.yml` in the root server folder on servers below 1.19). Using Floodgate on the backend servers will also mitigate this issue.
## Error with Forge or Fabric Bukkit Hybrid {#error-with-forge-or-fabric-bukkit-hybrid}
+1 -1
View File
@@ -4,7 +4,7 @@ description: Learn how to set up Floodgate on your Paper or Spigot server.
hide_title: true
---
1. Download Floodgate-Spigot from the [download page](/download/?project=floodgate).
1. Download Floodgate-Spigot from the [download page](https://download.geysermc.org/v2/projects/floodgate/versions/latest/builds/latest/downloads/spigot).
2. Place the Floodgate-Spigot.jar in the `plugins` folder, and restart the server.
3. Change `auth-type` in Geyser's config to `floodgate`.
4. Restart the server.
+2 -2
View File
@@ -9,12 +9,12 @@ You only need to install Floodgate on the BungeeCord or Velocity proxy server, u
Additionally, it will display Bedrock edition skins properly.
:::
1. Download Floodgate for your proxy software from the [download page](/download/?project=floodgate).
1. Download Floodgate for your proxy software from the [download page](https://geysermc.org/download#floodgate).
2. Place the Floodgate jar in the `plugins` folder, and restart the proxy server.
3. Change `auth-type` in Geyser's config to `floodgate`.
4. Restart the server.
### Installing Floodgate on servers behind the proxy \{#installing-floodgate-on-servers-behind-the-proxy}
### Installing Floodgate on servers behind the proxy {#installing-floodgate-on-servers-behind-the-proxy}
This is only needed when you want to use the Floodgate API on your backend server(s) behind a proxy.
+1 -1
View File
@@ -8,7 +8,7 @@ hide_title: true
To be able to use Floodgate authentication, you need to be able to install Floodgate on the Java server you are connecting to.
:::
1. Download and install the platform-specific Floodgate jar (e.g. floodgate-spigot, or floodgate-fabric) [here](/download/?project=floodgate).
1. Download and install the platform-specific Floodgate jar (e.g. floodgate-spigot, or floodgate-fabric) [here](https://geysermc.org/download#floodgate).
See the platform setup instructions for a detailed, platform specific setup guide. Then, continue with the instructions below.
2. Change `auth-type` in Geyser Standalone's config to `floodgate`.
3. Copy the `key.pem` file in the Floodgate config folder to the same directory as Geyser Standalone.
+1 -1
View File
@@ -8,7 +8,7 @@ hide_title: true
To be able to use Floodgate authentication, you need to be able to install Floodgate on the Java server you are connecting to.
:::
1. Download and install the platform-specific Floodgate jar (e.g. floodgate-spigot, or floodgate-fabric) [here](/download/?project=floodgate).
1. Download and install the platform-specific Floodgate jar (e.g. floodgate-spigot, or floodgate-fabric) [here](https://geysermc.org/download#floodgate).
See the platform setup instructions for a detailed, platform specific setup guide. Then, continue with the instructions below.
2. Copy the `key.pem` file in the Floodgate config folder to the `/plugins/Geyser/´ directory.
3. Restart ViaProxy.
+4 -2
View File
@@ -14,12 +14,14 @@ This is a community-compiled list and does not indicate any endorsement from Gey
Full Compatibility (Checks Bedrock Players Accurately)
- [Boar](https://modrinth.com/plugin/boar) - Last checked on 13th March 2026
- [AntiAura](https://www.spigotmc.org/resources/1368/) (Paid) - Last checked on 24th January 2023
- [LightAntiCheat](https://modrinth.com/plugin/lightanticheat) - Last checked on 19rd July 2024
- [Spartan: Bedrock Edition](https://builtbybit.com/resources/12832/) (Paid) - Last checked on 18th July 2024
- [Themis](https://www.spigotmc.org/resources/90766/) - Last checked on 11th July 2024
Partially Compatible (Does not Check/Ignores Bedrock Players)
- [GrimAC](https://github.com/GrimAnticheat/Grim) - Last checked on 8th November 2024
- [GrimAC](https://github.com/MWHunter/Grim) - Last checked on 30th June 2024
- [Intave](https://intave.ac) (Paid) Requires [GeyserMC addon](https://github.com/intave/bedrock) - Last checked on 2nd July 2024
- [Matrix](https://matrix.rip/) (Paid) - Last checked on 23rd July 2024
- [Spartan: Java Edition](https://www.spigotmc.org/resources/25638/) (Paid) - Last checked on 18th July 2024
+1 -1
View File
@@ -97,7 +97,7 @@ The skin package contains some records representing skin data. If you want to ch
#### [Pack](https://github.com/GeyserMC/Geyser/tree/master/api/src/main/java/org/geysermc/geyser/api/pack) {#pack}
The pack package contains classes and interfaces related to resource packs in Geyser. You can create custom resource packs and send them to individual sessions before they log in using the [SessionLoadResourcePacksEvent](https://github.com/GeyserMC/Geyser/blob/master/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionLoadResourcePacksEvent.java).
If you wish to send a resource pack to all sessions, you can use the [GeyserDefineResourcePacksEvent](https://github.com/GeyserMC/Geyser/blob/master/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineResourcePacksEvent.java).
If you wish to send a resource pack to all sessions, you can use the [GeyserLoadResourcePacksEvent](https://github.com/GeyserMC/Geyser/blob/master/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserLoadResourcePacksEvent.java).
Packs can be created using a [PackCodec](https://github.com/GeyserMC/Geyser/blob/master/api/src/main/java/org/geysermc/geyser/api/pack/PackCodec.java), such as the provided [PathPackCodec](https://github.com/GeyserMC/Geyser/blob/master/api/src/main/java/org/geysermc/geyser/api/pack/PathPackCodec.java).
This allows you to load a Bedrock resource pack from a file path:
-3
View File
@@ -31,9 +31,6 @@ on the proxy server to assign permissions to players. Assigning permissions on t
| `geyser version` | `geyser.command.version` | Shows the current Geyser version and checks for updates. |
| `geyser tooltips` | `geyser.command.tooltips` | Toggle showing Advanced Tooltips (F3 + H on Java) |
| `geyser extensions` | `geyser.command.extensions` | Lists all currently loaded extensions. This command is only registered if any extensions are loaded. |
| `geyser ping` | `geyser.command.ping` | Shows the ping between the player and the Geyser instance. |
| `geyser options` | `geyser.command.options` | Opens the "pause screen additions" dialogue, if sent by the Java server |
| `geyser quickactions` | `geyser.command.quickactions` | Opens the "quick actions" dialogue, if sent by the Java server. |
## Permissions for Geyser extensions {#extension-permissions}
+13 -5
View File
@@ -13,7 +13,7 @@ If you still can't make it work, join [our Discord](https://discord.gg/geysermc)
For Floodgate issues see: [Floodgate: Known Issues/Caveats](/wiki/floodgate/issues/).
# I can't connect! (Either the server doesn't show up in the friends list or I get "Unable to connect to world")
* If you don't use a reverse proxy such as TCPShield make sure that `advanced.java.use-haproxy-protocol` is set to false.
* If you don't use a reverse proxy such as TCPShield make sure that `enable-proxy-protocol` is set to false.
To fix "Unable to connect to world" with no console errors, see [here](/wiki/geyser/fixing-unable-to-connect-to-world/).
## If the server doesn't show up in the friends list {#if-the-server-doesnt-show-up-in-the-friends-list}
@@ -37,7 +37,7 @@ This means something (likely another instance of Geyser) is running on the port
### [...]` has been compiled by a more recent version of the Java Runtime (class file version 60.0)` {#-has-been-compiled-by-a-more-recent-version-of-the-java-runtime-class-file-version-600}
See this link for updating to Java 17: https://docs.papermc.io/misc/java-install.
See this link for updating to Java 17: https://paper.readthedocs.io/en/latest/java-update/index.html.
### Hosting provider will not immediately open up UDP. {#hosting-provider-will-not-immediately-open-up-udp}
@@ -51,7 +51,7 @@ One way to get around this (if you're using an online host) is to shut down your
You may need to update your Java version. If so, update at [Adoptium.net](https://adoptium.net/).
Sometimes this happens in poor-network environments. There is an `advanced.bedrock.mtu` option in the Geyser config; lower this number slowly (in batches of 100), restart each time, and re-test joining.
Sometimes this happens in poor-network environments. There is an `mtu` option in the Geyser config; lower this number slowly (in batches of 100), restart each time, and re-test joining.
This option will most likely not help if you are getting "Unable to Connect to World" with no console logs indicating a connection.
@@ -76,6 +76,8 @@ If you have your configuration set up like this, put simply, it won't work. If a
Connection Refused usually means that a Java server could not be found on that port, or the server denied access to the connection on a network level.
The latter can happen with anti-DDOS plugins such as TCPShield, but otherwise ensure that the server you're trying to connect to is spelled correctly in the config, is up and is port forwarded correctly.
If you're updating from an old build of Geyser, set your remote address to `auto` and try again.
### Floodgate Misconfiguration {#floodgate-misconfiguration}
See [this page](/wiki/floodgate/setup/) for more information.
@@ -97,9 +99,9 @@ It has other benefits too. Here's a plugin that can just do that:
[CommandWhitelist](https://www.spigotmc.org/resources/81326/). Alternatively, use the [HideCommands](https://github.com/Redned235/HideCommands) Geyser extension to hide commands just for Bedrock players.
# Failed to load locale asset cache: Unrecognized token 'Cannot'
This or anything else related to failing to download a locale file on startup is usually caused by java trying to connect using IPv6 and Mojang only use IPv4, so start Geyser or the server up with this flag `-Djava.net.preferIPv4Stack=true`, EG: `java -Xms1024M -Djava.net.preferIPv4Stack=true -jar Geyser.jar`
This or anything else related to failing to download a locale file on startup is usually caused by java trying to connect using IPv6 and Mojadng only use IPv4, so start Geyser or the server up with this flag `-Djava.net.preferIPv4Stack=true`, EG: `java -Xms1024M -Djava.net.preferIPv4Stack=true -jar Geyser.jar`
# Outdated client! Please use 1.x.x
# Outdated client! Please use 1.x.x
The server is too new or Geyser is outdated. Make sure you're on the latest Geyser.
@@ -107,6 +109,12 @@ The server is too new or Geyser is outdated. Make sure you're on the latest Geys
Update the server or ask them to install [ViaVersion](https://viaversion.com/). You can also try [VIAaaS](https://github.com/ViaVersion/VIAaaS) (ViaVersion as a Service).
# Query: Incorrect Magic!
See here: https://www.spigotmc.org/threads/query-incorrect-magic-and-high-cpu-usage.159386/#post-2709057
* If you don't use a reverse proxy such as TCPShield make sure that `enable-proxy-protocol` is set to false.
# Only for BungeeCord with floodgate
If you use floodgate ensure that it is installed on all of your Spigot backend servers as following:
+7 -8
View File
@@ -14,15 +14,16 @@ The following things cannot be fixed without changes to Bedrock or the Java prot
- Clickable links in chat
- Glowing effect
- Crafting in the 2x2 menu while in creative mode - with the GeyserOptionalPack, this grid is hidden as it does not exist on Java.
- Distinguishing between left and right clicks in inventories
- Redstone dot blockstates
- Potion colors implemented using the PotionContents data component
- Potion colors implemented using NBT
- Various command arguments for any command that doesn't use the Minecraft Brigadier library
- Anything that relies on tab complete or typing in the chat UI (related to the above) - Bedrock sends no packet that indicates they are in this menu
- Unable to see banner layers past 6
- Movement issues around bamboo due to offset differences between Java and Bedrock. Use [Hurricane](/wiki/other/hurricane) to work around it.
- Custom anvil recipes or custom smithing table ingredients/patterns ([GeyserMC/Geyser#4706](https://github.com/GeyserMC/Geyser/issues/4706))
- Heights lower than -512 or higher than 512 in the overworld (and custom dimensions mapped by Geyser to the overworld), and heights lower than 0 or higher than 256 in other dimensions ([GeyserMC/Geyser#3804](https://github.com/GeyserMC/Geyser/issues/3804))
- Heights lower than -64 or higher than 320 in the overworld with extended height enabled, and heights lower than 0 or higher than 256 in other dimensions ([GeyserMC/Geyser#3804](https://github.com/GeyserMC/Geyser/issues/3804))
- Dolphin's Grace potion effect visuals (effects should still work correctly)
- Invisible item frames - however, there are Bedrock edition resource packs making *all* item frames invisible
- Blocks (excluding jack-o-lantern) on entity heads (E.G. armor stands, players)
@@ -30,16 +31,14 @@ The following things cannot be fixed without changes to Bedrock or the Java prot
- Custom beacon base blocks ([GeyserMC/Geyser#2301](https://github.com/GeyserMC/Geyser/issues/2301)) - these are hardcoded on Bedrock edition.
- Climbable blocks changed by datapacks ([GeyserMC/Geyser#4051](https://github.com/GeyserMC/Geyser/issues/4051))
- Custom enchantments/sweeping edge ([GeyserMC/Geyser#3121](https://github.com/GeyserMC/Geyser/issues/3121))
- "Bordure Indented" pattern shape not appearing on the Bedrock side in the loom ([GeyserMC/Geyser#3183](https://github.com/GeyserMC/Geyser/issues/3183))
- Gliding without elytras/custom elytras (https://github.com/GeyserMC/Geyser/issues/3255, https://github.com/GeyserMC/Geyser/issues/3299)
- Custom furnace cook times ([GeyserMC/Geyser#4104](https://github.com/GeyserMC/Geyser/issues/4104))
- Maximum sign length different on Java/Bedrock edition ([GeyserMC/Geyser#4130](https://github.com/GeyserMC/Geyser/issues/4130))
- Second line on advancement toasts ([GeyserMC/Geyser#3205](https://github.com/GeyserMC/Geyser/issues/3205))
- Showing non-vanilla enchantment levels, such as "Silk Touch 2" ([GeyserMC/Geyser#5252](https://github.com/GeyserMC/Geyser/issues/5252))
- Test instance blocks are not available in Bedrock ([GeyserMC/Geyser#6164](https://github.com/GeyserMC/Geyser/issues/6164))
## Fixed with the included GeyserIntegratedPack {#fixed-with-geyserintegratedpack}
## Fixable With GeyserOptionalPack {#fixable-with-geyseroptionalpack}
The following changes **are supported** with the included GeyserIntegratedPack, which is a Bedrock resource pack to add features Bedrock doesn't natively support:
The following changes **are supported** with the [GeyserOptionalPack](/wiki/other/geyseroptionalpack/), which is a Bedrock resource pack you can install for additional functionality for features Bedrock does not natively support:
- Custom armor stand poses
- Illusioners
- Hit particles and other miscellaneous particles not natively in Bedrock
@@ -53,4 +52,4 @@ The following changes **are supported** with the included GeyserIntegratedPack,
The following issues can be worked around with the [Hurricane](/wiki/other/hurricane) plugin/mod. However, these involve Java server
modifications.
- Movement issues around bamboo due to offset differences between Java and Bedrock.
- Movement issues around bamboo due to offset differences between Java and Bedrock.
+28 -9
View File
@@ -9,7 +9,7 @@ It should be noted that blocks and their associated components are not very stab
## Enabling custom blocks {#enabling-custom-blocks}
Before beginning, ensure that `gameplay.enable-custom-content` is set to `true` in your `config.yml` file.
Before beginning, ensure that `add-non-bedrock-items` is set to `true` in your `config.yml` file.
```yml
# Whether to add any items and blocks which normally does not exist in Bedrock Edition.
@@ -17,7 +17,7 @@ Before beginning, ensure that `gameplay.enable-custom-content` is set to `true`
# If this is disabled, furnace minecart items will be mapped to hopper minecart items.
# Geyser's block, item, and skull mappings systems will also be disabled.
# This option requires a restart of Geyser in order to change its setting.
enable-custom-content: true
add-non-bedrock-items: true
```
## JSON mappings {#json-mappings}
@@ -99,12 +99,12 @@ The following details the schema for the mappings file. Only the `name` field is
- Default: none
- Description: The name of the custom block.
- `collision_box`:
- Type: `object` or array of `object`s for multiple collision boxes
- Type: `object`
- `origin`:
- Type: `array`
- Default: Inferred from overridden block
- Description: An array of x, y, and z origin values
- Range: Must be in range `[-8, 0, -8]` to `[8, 24, 8]`, inclusive
- Range: Must be in range `[-8, 0, -8]` to `[8, 16, 8]`, inclusive
- `items`:
- Type: `float`
- Default: Inferred from overridden block
@@ -113,12 +113,11 @@ The following details the schema for the mappings file. Only the `name` field is
- Type: `array`
- Default: Inferred from overridden block
- Description: An array of x, y, and z size values
- Range: Must be in range `[0, 0, 0]` to `[16, 24, 16]`, inclusive
- `items`:
- Type: `float`
- Default: Inferred from overridden block
- Description: An size value for a single axis
- Range: The sum of `origin` and `size` must be in range `[-8, 0, -8]` to `[8, 24, 8]`, inclusive.
- Range: Addittion of `origin` and `size` must be in range `[-8, 0, -8]` to `[8, 16, 8]`, inclusive.
- `destructible_by_mining`:
- Type: `integer`
- Default: Inferred from overridden block
@@ -127,6 +126,26 @@ The following details the schema for the mappings file. Only the `name` field is
- Type: `string`
- Default: the name of the custom block
- Description: The display name of the block.
- `extended_collision_box`:
- Type: `object`
- `origin`:
- Type: `array`
- Default: Inferred from overridden block
- Description: An array of x, y, and z origin values
- Range: Must be in range `[-8, 0, -8]` to `[8, 16, 8]`, inclusive
- `items`:
- Type: `float`
- Default: Inferred from overridden block
- Description: An origin value for a single axis
- `size`:
- Type: `array`
- Default: Inferred from overridden block
- Description: An array of x, y, and z size values
- `items`:
- Type: `float`
- Default: Inferred from overridden block
- Description: An size value for a single axis
- Range: Addittion of `origin` and `size` must be in range `[-8, 0, -8]` to `[8, 16, 8]`, inclusive.
- `friction`:
- Type: `float`
- Range: `0.0` to `1.0`
@@ -273,12 +292,12 @@ The following details the schema for the mappings file. Only the `name` field is
- Type: `string`
- Default: `building_blocks`
- Description: The creative category to place the block in.
- Range: See [Menu Categories](https://wiki.bedrock.dev/documentation/menu-categories.html#list-of-categories) on the Bedrock Wiki.
- Range: See [Creative Categories](https://wiki.bedrock.dev/documentation/creative-categories.html#list-of-creative-categories) on the Bedrock Wiki.
- `creative_group`:
- Type: `string`
- Default: none
- Description: The creative group to place the block in.
- Range: See [Menu Groups](https://wiki.bedrock.dev/documentation/menu-categories.html#list-of-groups) on the Bedrock Wiki.
- Range: See [Creative Tabs](https://wiki.bedrock.dev/documentation/creative-categories.html#list-of-creative-tabs) on the Bedrock Wiki.
- `included_in_creative_inventory`:
- Type: `boolean`
- Default: `true`
@@ -292,7 +311,7 @@ The following details the schema for the mappings file. Only the `name` field is
- Description: An object containing state overrides for the block.
- `property1=value1,property2=value2,...`:
- Type: `object`
- Description: An override for a specific block state. Possible states are listed in Geyser's [Block Mappings](https://raw.githubusercontent.com/GeyserMC/mappings/6b661f0d517d895aebc1f55a25d2c86f033beb1d/blocks.json)
- Description: An override for a specific block state. Possible states are listed in Geyser's [Block Mappings](https://raw.githubusercontent.com/GeyserMC/mappings/master/blocks.json)
- Accepts all of the same properties as a block definition except `creative_category`, `creative_group`, `included_in_creative_inventory`, `only_override_states`, and `state_overrides`.
</div>
@@ -1,18 +1,11 @@
---
title: Custom Items (v1)
description: Legacy documentation for the first version of the custom item API
title: Custom Items
description: Geyser allows custom Bedrock items to be added for an equivalency to Vanilla Java item predicates or modded items.
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
To setup custom items in geyser, you have to choose how you are going to register your items. The easiest is [using a json file](#json-mappings) but you can also [use a Geyser extension](#geyser-extensions).
### Format version 1 (legacy)
:::warning
`format_version: 1` is no longer receiving updates. New features will only be added to format version 2.
:::
## JSON mappings (v1)
## JSON mappings {#json-mappings}
1. Start your server, and you should have a folder called `custom_mappings` that is created. That would be with the folder of `Geyser.jar` file for standalone and inside your Geyser data folder for a plugin.
2. Create a `.json` file, it can be any name you like and as many files as you like. You don't need to make one file per item. Here is the structure of the file:
@@ -48,7 +41,7 @@ import TabItem from '@theme/TabItem';
* `allow_offhand` (boolean) default: false
* `texture_size` (int) default: 16
* `creative_category` (int) default: not set. This can take values between 1-5, and defines the creative category the item appears in. Note: Adding your item to a creative category is needed if you want recipes that output this custom item to show up in the recipe book! However, including it does NOT mean you can get the custom item from the creative inventory.
* `creative_group` (string) default: not set. Requires a creative category to also be set - allows you to group the custom item in a sub-group. See [here](https://wiki.bedrock.dev/documentation/menu-categories.html#list-of-categories) for all categories.
* `creative_group` (string) default: not set. Requires a creative category to also be set - allows you to group the custom item in a sub-group. See [here](https://wiki.bedrock.dev/documentation/creative-categories.html#list-of-categories) for all categories.
* `render_offsets` (object) It works as follows. Note that all the sub-objects are optional, except x, y and z. You can have for example only a main hand with a position, and noting else. default: no render offset
* `tags` (array) default: no tags. Allows defining tags that can be used in Molang queries. Example value: ["test:tag_one", "test:tag_two"].
```json
@@ -81,9 +74,9 @@ import TabItem from '@theme/TabItem';
}
```
## Geyser extensions (v1)
## Geyser extensions {#geyser-extensions}
### Extending a vanilla item (v1)
### Extending a vanilla item {#extending-a-vanilla-item}
1. Create your custom item options or registrations, to which you can add any of the following. They can be stacked, so that all of the specified types need to match, but you **do NOT need all of them.**
```java
@@ -116,7 +109,7 @@ public void onGeyserPreInitializeEvent(GeyserDefineCustomItemsEvent event) {
}
```
### Non vanilla (modded) items with Geyser extensions (for example to use with Fabric) (v1)
### Non vanilla (modded) items with Geyser extensions (for example to use with Fabric) {#non-vanilla-modded-items-with-geyser-extensions-for-example-to-use-with-fabric}
1. Create your item data:
```java
@@ -134,4 +127,28 @@ public void onGeyserDefineCustomItemsEvent(GeyserDefineCustomItemsEvent event) {
}
```
## Resource pack {#resource-pack}
1. Setup a basic bedrock resource pack. If you need help, you can find it [here](https://wiki.bedrock.dev/guide/project-setup.html#rp-manifest).
2. Make a `textures` folder.
3. Create `item_texture.json` in the `textures`, and put this in it:
```json
{
"resource_pack_name": "MY_PACK_NAME_HERE",
"texture_name": "atlas.items",
"texture_data": {
}
}
```
4. Inside texture data, you can add your items. The texture name and path must match the name that you set in your mappings.
```json
"my_item": {
"textures": [
"textures/items/my_item"
]
}
```
5. Then you need to put your textures inside the `textures/items`. Make sure to have it match the texture path that you specified in `item_texture.json`!
File diff suppressed because it is too large. Load diff
+2 -2
View File
@@ -9,7 +9,7 @@ To setup custom skulls in geyser, you have to choose how you are going to regist
## Enabling custom skulls {#enabling-custom-skulls}
To enable custom skulls, you must set `gameplay.enable-custom-content` to `true` in the `config.yml` file. This will enable the generation of the custom resource pack and the translation of custom skulls to custom blocks. You can then add custom skulls to the `custom-skulls.yml` file.
To enable custom skulls, you must set `add-non-bedrock-items` to `true` in the `config.yml` file. This will enable the generation of the custom resource pack and the translation of custom skulls to custom blocks. You can then add custom skulls to the `custom-skulls.yml` file.
```yaml
# Whether to add any items and blocks which normally does not exist in Bedrock Edition.
@@ -17,7 +17,7 @@ To enable custom skulls, you must set `gameplay.enable-custom-content` to `true`
# If this is disabled, furnace minecart items will be mapped to hopper minecart items.
# Geyser's block, item, and skull mappings systems will also be disabled.
# This option requires a restart of Geyser in order to change its setting.
enable-custom-content: true
add-non-bedrock-items: true
```
## custom-skulls.yml {#custom-skullsyml}
+8 -18
View File
@@ -25,23 +25,20 @@ The underlying Geyser API is steadily expanding, creating more and more opportun
## Which Geyser Extensions exist? {#which-geyser-extensions-exist}
Check out Modrinth's Geyser extensions section under the "plugins" tab!
At the moment, extensions are still a new system, so there is only a small list of known extensions for Geyser.
However, new extensions are always being created!
There is an [official list](https://github.com/GeyserMC/GeyserExtensionList) of available extensions you can check out.
If you have an extension you'd like to see on this list, feel free to open a PR!
## Installing Extensions {#installing-extensions}
To install an extension, simply put the extension .jar file into Geyser's `extensions` folder.
Then, restart Geyser (or the server Geyser runs on).
## Updating Extensions {#updating-extensions}
To update extensions, use the `update` folder within the extensions directory as follows:
1. Copy the updated versions of your extension jars into the `update` folder inside the `extensions` directory.
2. On the next server or application restart, any extensions in the `update` folder will automatically replace the corresponding extensions in the main extensions directory. If an extension is new, it will be added.
3. If an update fails, it will be logged, and the server/application will proceed with loading extensions as usual. You can review the logs to address any issues.
## Creating Geyser Extensions {#creating-geyser-extensions}
The easiest way to create an extension would be utilizing [this official template](https://github.com/GeyserMC/GeyserExtensionTemplate/).
The easiest way to create an extension would be utilizing [this official template](https://github.com/GeyserMC/GeyserExampleExtension/).
Simply create a new repository from the template, customize the `extension.yml` & `settings.gradle` files, and get started making the extension.
Geyser recognizes extensions when they have a file called `extension.yml` in the jars `resources` folder.
@@ -50,15 +47,9 @@ Geyser recognizes extensions when they have a file called `extension.yml` in the
id: exampleid
name: ExampleExtension
main: org.geyser.extension.exampleid.ExampleExtension
api: 2.9.0
api: 2.4.1
version: 1.0.0
authors: [ExampleAuthor]
dependencies: # Optional
exampledependency:
# When this dependency should be loaded (BEFORE or AFTER your extension)
load: BEFORE # Default: BEFORE
# This determines whether or not this dependency is required for this extension to load
required: true # Default: true
```
Explanations for the individual fields:
@@ -67,11 +58,10 @@ Explanations for the individual fields:
- main: The main class of your extension.
- api: The Geyser API version your extension targets.
- authors: The author(s) of the extension. To add more than one entry, separate entries with a comma.
- dependencies: The dependencies of the extension. Each dependency has a load order and required property with defaults of `BEFORE` and `true` respectively.
## Creating the main class {#creating-the-main-class}
The main class, the entrypoint for the extension, needs to [implement the **Extension** interface provided by Geyser](https://github.com/GeyserMC/GeyserExtensionTemplate/blob/master/src/main/java/org/geyser/extension/exampleid/ExampleExtension.java#L15).
The main class, the entrypoint for the extension, needs to [implement the **Extension** interface provided by Geyser](https://github.com/GeyserMC/GeyserExampleExtension/blob/master/src/main/java/org/geyser/extension/exampleid/ExampleExtension.java#L12).
That way, Geyser recognizes the extension, and gives you access to important methods - such as `logger()`, to get your extensions logger.
To see all the methods provided by that interface, see [here](https://github.com/GeyserMC/Geyser/blob/master/api/src/main/java/org/geysermc/geyser/api/extension/Extension.java).
+5 -5
View File
@@ -6,7 +6,7 @@ description: Frequently asked questions about Geyser, including how it works, wh
import { Questions, Q, A } from "@site/src/components/Questions";
import { Versions } from '@site/src/components/Versions'
### General Questions \{#general-questions}
### General Questions {#general-questions}
Here you can find answers to frequently asked questions about Geyser - if you have a question that isn't answered here, feel free to ask in our [Discord](https://discord.gg/GeyserMC)!
@@ -150,7 +150,7 @@ Here you can find answers to frequently asked questions about Geyser - if you ha
<Q>
Sometimes, when I go really far out, the world starts to experience very odd visual bugs...
<A>
This is a Bedrock client issue caused by Bedrock being 32-bit and Java being 64-bit. For more information read [here](https://minecraft.wiki/w/Bedrock_Edition_distance_effects). This can be worked around using an [unofficial Geyser extension](https://github.com/oryxel1/GeyserFloatingPoints) that spoofs the player position.
This is a Bedrock client issue caused by Bedrock being 32-bit and Java being 64-bit. For more information read [here](https://minecraft.wiki/w/Bedrock_Edition_distance_effects).
</A>
</Q>
<Q>
@@ -209,7 +209,7 @@ Here you can find answers to frequently asked questions about Geyser - if you ha
Note: you need to be running DiscordSRV v1.22.0 or newer. Floodgate 2.0 or GeyserSkinRestorer is still required for skins to show up for Java players and for this to work.
Alternatively, if you cannot get the above AvatarUrl to work with DiscordSRV, or you'd like to use it with another plugin that does not support texture ids, you can use the [Starlight Skin API.](https://docs.lunareclipse.studio/)
Alternatively, if you cannot get the above AvatarUrl to work with DiscordSRV, or you'd like to use it with another plugin that does not support texture ids, you can use the [TydiumCraft Skin API.](https://tydiumcraft.net/docs/skinapi)
</A>
</Q>
<Q>
@@ -240,7 +240,7 @@ Here you can find answers to frequently asked questions about Geyser - if you ha
</Q>
</Questions>
### Additional Questions \{#additional-questions}
### Additional Questions {#additional-questions}
These additional frequently asked questions are not related to Geyser gameplay.
@@ -257,4 +257,4 @@ These additional frequently asked questions are not related to Geyser gameplay.
No. They have their own bedrock server tech you can find out more info about [here](https://www.cubecraft.net/threads/behind-the-cube-1-feelin-lucky.264600/).
</A>
</Q>
</Questions>
</Questions>
@@ -3,6 +3,10 @@ title: Fixing 'Unable to Connect to World'
description: Common issues and solutions for the 'Unable to Connect to World' error.
---
import TroubleshootingTree from '@site/src/components/TroubleshootingTree';
<TroubleshootingTree />
## Fixing 'Unable to Connect to World' errors {#fixing-unable-to-connect-to-world-errors}
This is by far the most common error people get when attempting to set up Geyser. Here's some steps on how to solve it.
Usually, this error is caused by improper configuration of Geyser, or issues with your network.
@@ -98,3 +102,22 @@ Your firewall is likely in the way. Try adding an exception to Java, or disable
## As a last resort for troubleshooting... {#as-a-last-resort-for-troubleshooting}
Minecraft offers a vanilla Bedrock server [here](https://www.minecraft.net/download/server/bedrock). Downloading, running, and attempting to connect to it may help isolate if the issue is on Geyser's end, or your computer/network's end.
## Using Geyser on the same computer {#using-geyser-on-the-same-computer}
### Windows 10/11 {#windows-1011}
_This only affects people trying to join Geyser from Windows 10/11 Edition with Geyser hosted on the same computer._
This is an issue caused by Loopback restrictions not being lifted. By default, Microsoft Apps have this restriction on all their apps for local connections. Geyser will attempt to resolve this automatically; however, if you're still having connection problems, you can lift it by typing the following in Windows PowerShell in administrator mode: (it should return `OK.` if it worked)
```powershell
CheckNetIsolation LoopbackExempt -a -n="Microsoft.MinecraftUWP_8wekyb3d8bbwe"
```
Should this not work, you can try this set of steps:
1. Hold down Windows Key + R
2. In the prompt, type `hdwwiz.exe`, then press Enter then Next
3. Install the Hardware Manually
4. Choose Network Adapter > Next > Microsoft > "Microsoft KM-TEST Loopback Adapter" then hit Next until it's done.
+4 -4
View File
@@ -32,7 +32,7 @@ Add Geyser's API codebase as a dependency:
<dependency>
<groupId>org.geysermc.geyser</groupId>
<artifactId>api</artifactId>
<version>2.9.5-SNAPSHOT</version>
<version>2.4.2-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
```
@@ -40,7 +40,7 @@ Add Geyser's API codebase as a dependency:
**Gradle**
```groovy
dependencies {
compileOnly('org.geysermc.geyser:api:2.9.5-SNAPSHOT')
compileOnly('org.geysermc.geyser:api:2.4.2-SNAPSHOT')
}
```
@@ -66,7 +66,7 @@ Add Floodgate's API as a dependency:
<dependency>
<groupId>org.geysermc.floodgate</groupId>
<artifactId>api</artifactId>
<version>2.2.5-SNAPSHOT</version>
<version>2.2.3-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
```
@@ -74,7 +74,7 @@ Add Floodgate's API as a dependency:
**Gradle**
```groovy
dependencies {
compileOnly('org.geysermc.floodgate:api:2.2.5-SNAPSHOT')
compileOnly('org.geysermc.floodgate:api:2.2.3-SNAPSHOT')
}
```
@@ -28,10 +28,6 @@ The Geyser specific properties are prioritized over the plugin properties!
- ```server``` means to match the bind address of the TCP server
- any other string will be used as-is for the bind address.
- ```-DgeyserBroadcastPort=19132```
- This can be used in cases where the port Geyser runs on does not match the port players use to connect to (e.g. due to port forwarding routings).
- When not set or set to 0, it defaults to the same port that Geyser runs on
## Disabling warnings and advanced configuration {#disabling-warnings-and-advanced-configuration}
You may disable some warnings that may be printed to the console by using the following command line arguments. The values shown are the defaults used by Geyser, unless otherwise noted.
@@ -59,9 +55,6 @@ Disabling Geyser warnings from being logged will not fix the real issue! Only di
- `-DGeyser.AddTeamSuggestions=true`
- Allows you to turn off suggestions for teams in the scoreboard command. This is enabled by default, disabling this can help with performance if there are a lot of teams defined.
Setting "command-suggestions" to false in the config will also disable this.
- `-DGeyser.NoPlayerListPS=true`
- Enables a less-than-ideal workaround to resolve client crashing when chatting / typing commands on PlayStation consoles with lots of player online.
Disabled by default, as it is not needed for most setups.
- `-DGeyser.RakPacketLimit=120`
- Sets RakNet's per-ip per-tick (10ms) post-connection packet limit.
- `-DGeyser.RakGlobalPacketLimit=100000`
+3 -3
View File
@@ -5,10 +5,10 @@ description: 'Geyser is a bridge between Minecraft: Bedrock Edition and Minecraf
---
import { Versions } from '@site/src/components/Versions'
import { useDocById } from '@docusaurus/plugin-content-docs/client'
import { useDocById } from '@docusaurus/theme-common/internal'
import DocCardList from '@theme/DocCardList'
# Overview \{#overview}
# Overview
[//]: # ([![License: MIT]&#40;https://img.shields.io/badge/license-MIT-blue.svg?label=License&#41;]&#40;LICENSE&#41;)
[![Build Status](https://github.com/GeyserMC/Geyser/actions/workflows/build.yml/badge.svg)](https://github.com/GeyserMC/Geyser/actions/workflows/build.yml)
@@ -23,7 +23,7 @@ Here are a few selected guides that will help you get started with Geyser!
<DocCardList items={[
'setup',
'supported-versions',
'commands',
'understanding-the-config',
'faq',
'common-issues',
'extensions'
-101
View File
@@ -1,101 +0,0 @@
---
title: Using Resource Packs with Geyser
description: This page explains how to use resource packs with Geyser.
---
# Introduction
Geyser supports sending Bedrock edition resource packs to connecting Bedrock clients.
However, Geyser does not convert resource packs from the Java Edition format into the Bedrock edition format.
Resource packs offer a range of customization options. Just like on Java, they can be used for a wide variety of things:
- Texture Modifications: Resource packs can change the look of blocks, items, and entities, providing a unique visual experience.
- Sound Changes: Custom sound effects or music tracks can be added to create a more immersive atmosphere.
- UI Enhancements: Resource packs can modify the user interface - a popular example would be providing a dark mode UI option.
... and much more!
# Using resource packs
### Sending local packs
The easiest way to send resource packs to Bedrock players is by putting the Bedrock edition resource pack, either as a `.zip` or `.mcpack` file, into Geyser's `packs` folder.
Location of the 'packs' folder:
- Fabric/NeoForge: `/config/Geyser-<platform>/packs/`
- Geyser Standalone: `/packs/` at the root directory
- Other platforms: `/plugins/Geyser-<platform>/packs/`
After restarting the server (or reloading Geyser), players that connect will receive all packs that are in that folder.
### Remote pack urls (accessible using the Geyser API)
As an alternative to sending local packs, you can also send resource packs by sending Bedrock players a link to download the packs from.
This works similarly to Java edition's pack downloading. However, there are a few key limitations:
- The link must be a direct link to the resource pack download (it will follow redirects, but those must result in a file download)
- The Content-Length header must specify the exact file size.
- The Content-Type application header must be set to `application/zip`.
Geyser will download your configured remote resource packs once on boot, and warn you if any of these conditions are not met.
It is unfortunately not possible to bypass these, as these are restrictions imposed by the Bedrock client.
To verify headers manually, curl the website and check the values.
For example:
`curl -I -L https://download.geysermc.org/v2/projects/geyseroptionalpack/versions/1.0.10/builds/11/downloads/geyseroptionalpack` returns the following:
- `-I`: This option tells curl to fetch the HTTP response headers in the output.
- `-L`: Ensures that curl follows redirects
The output for this shows the following:
```shell
HTTP/1.1 200 OK
Date: Wed, 03 Jul 2024 23:03:06 GMT
Content-Type: application/zip
Content-Length: 95400
Connection: keep-alive
access-control-allow-methods: GET
access-control-allow-origin: *
Cache-Control: public, s-maxage=1209600
content-disposition: attachment; filename="=?UTF-8?Q?GeyserOptionalPack.mcpack?="; filename*=UTF-8''GeyserOptionalPack.mcpack
etag: "0258409cde3a2906e1085490fa5b10b77"
last-modified: Wed, 03 Jul 2024 08:42:41 GMT
CF-Cache-Status: HIT
Age: 21500
Accept-Ranges: bytes
Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=DUpNVi9R96y13%2BlJm%2BNTpDLvSt9bw9CFDUh8Qwhpb9SsqjJbuInBGtSM5hiM2dGbSGkUccP4KvSqqD%2FCKrrcQ9ur5at5G0u8FrfooVTKLP%2B4MwGoUl29DwlxeMVg6tX36RjjICmV97M4FlErCZEe%2F3gM%2FA%3D%3D"}],"group":"cf-nel","max_age":604800}
NEL: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
Server: cloudflare
CF-RAY: 89da81ca69c63735-FRA
alt-svc: h3=":443"; ma=86400
```
This shows that the content-length is indeed set correctly, and that the content type indeed is `application/zip`.
Further, Geyser will attempt to read the `ETag` to see if the content has changed. To query that, you can use the following:
`curl -I -L -v https://download.geysermc.org/v2/projects/geyseroptionalpack/versions/1.0.10/builds/11/downloads/geyseroptionalpack 2>&1 | grep ETag`
Alternatively, just using the `-v` header will turn on verbose mode that would also display the etag.
# Common questions
- **Does Geyser support behavior packs/add-ons?** <br />
No. These would require modifications on the Java server side, which isn't possible when Geyser is used on a proxy.
However, many things that are possible with add-ons or behavior packs can be done with Geyser's API - such as [custom items](/wiki/geyser/custom-items)
or [custom blocks](/wiki/geyser/custom-blocks).
- **Does Geyser convert Java edition resource packs?** <br />
Not currently. For now, you need to manually create a Bedrock edition resource pack equivalent.
- **Can I allow players to choose resource packs themselves?** <br />
On most Bedrock platforms (except consoles), players are able to download and install resource packs on the client.
There is also a Geyser extension, [PickPack](https://github.com/onebeastchris/PickPack) that uses the Geyser API to allow all Bedrock players to choose from a set of resource packs.
- **On proxy setups: Are per-backend-server resource packs possible?** <br />
This unfortunately is not possible natively, as Bedrock edition only allows removing and adding packs when connecting initially to the server.
However, with the usage of the transfer packet, it is possible to instruct the Bedrock client to re-connect to the server, and to apply changes then.
For per-server-packs, you can use the unofficial [GeyserPackSync](https://github.com/onebeastchris/GeyserPackSync) plugin.
- **Does Geyser have an API to send resource packs?** <br />
Yes! See the [Geyser API docs](/wiki/geyser/api/) for more info on that. There is a `SessionLoadResourcePacksEvent` to determine which
packs are sent to each connecting player, or the more general `GeyserDefineResourcePacksEvent` that defines the packs all users receive.
- **Can I use subpacks or specify the load order of resource packs**? <br />
You can! However, this feature requires you to use the Geyser API.
+15 -32
View File
@@ -13,42 +13,25 @@ You must be able to connect to your Geyser instance locally!
The playit.gg Minecraft server plugin does not support UDP tunnels. You will need to use the program agent instead!
:::
- If you already have playit.gg running & set up (for e.g. Minecraft Java edition), skip steps 1 and 2 and proceed with step 3.
## Setup {#setup}
1. Head over to [playit.gg's website](https://playit.gg/) - download the program & run it.
2. The program will provide a claiming link. Visit that link, log in.
![img](/img/wiki/playit-gg/playit_claim.png)
3. Confirm your agent.
![img](/img/wiki/playit-gg/playit_claim_confirm.png)
4. Add the agent.
![img](/img/wiki/playit-gg/playit_add_agent.png)
5. After the agent is created, create a tunnel.
![img](/img/wiki/playit-gg/playit_add_tunnel.png)
6. Name your tunnel and click Next.
![img](/img/wiki/playit-gg/playit_name_tunnel.png)
7. Select "Minecraft Bedrock" as the tunnel type and click Next.
![img](/img/wiki/playit-gg/playit_tunnel_type.png)
8. Select the Free Network and click Next.
![img](/img/wiki/playit-gg/playit_select_network.png)
**Do not change your Geyser port in `config.yml` unless you have a reason (for example, hosting another Geyser server on the same machine).** The Bedrock (Geyser) port in `config.yml` and the playit.gg ports are separate. playit.gg will forward its port to the default Geyser port and should work as-is. Changing it can cause errors. If you have changed your config port, set the Bedrock port back to the default `19132` and ensure `clone-remote-port` is `false`.
9. If the playit.gg agent and GeyserMC are running on the same device, leave the IP as `127.0.0.1` and set the port to whatever you configured in GeyserMC's config.
![img](/img/wiki/playit-gg/playit_set_ipandport.png)
10. Select `proxy-protocol-v2` for the Proxy Protocol section and click Next.
11. In the GeyserMC config, under `advanced:` `bedrock:`, set `use-haproxy-protocol` to `true`.
12. Click Create Tunnel and wait for the tunnel to be created.
![img](/img/wiki/playit-gg/playit_create_tunnel.png)
13. Copy your tunnel's port. For example, if your tunnel address is `visiting-phone.gl.at.ply.gg:6695`, then `6695` is the tunnel port.
14. In the GeyserMC config under `advanced:` `bedrock:`, set `broadcast-port` to your tunnel port (`6695` in the example).
15. Save your config. Start your Minecraft server and connect using your tunnel's IP and port.
16. If you join successfully, then you are done! Make sure to leave the playit.gg program running as closing it will close the tunnel. You also may want to ratelimit individual connections - use the "Per Connection Rate Limit" option to do so.
1. Head over to [playit.gg's website](https://playit.gg/) - download the program & run it. It will open the login site in the browser - create an account & sign in. Or, use a guest account.
2. Once logged in, make sure to connect the program + site, until step 4 is reached. This should happen automatically, if it does not, follow the instructions on the website and the playit.gg program console.
![img](/img/wiki/playit-gg/running.png)
3. Click "Create Tunnel" if you see the screen above, or, select the "Tunnels" tab when logged in to your account. There, select "Minecraft Bedrock", leave "Enable Tunnel" ticked, and click "Add tunnel".
![img](/img/wiki/playit-gg/add_tunnel.png)
4. Once "Add tunnel" is clicked, it should create a new tunnel, and you are set! Scroll down until you see this:
![img](/img/wiki/playit-gg/added_tunnel.png)
If you have Geyser running on a port that is not 19132, update the port there. The "Local Address" does not need to be changed unless you are not running playit.gg and Geyser on the same device.
5. Connect to your server - use the IP and Port from the "Allocation" tab. In our example - "180.ip.ply.gg" as the IP, and "17019" as the port. Alternatively, use the Domain it gives you instead of the IP.
6. If you join successfully, then you are done! Make sure to leave the playit.gg program running as closing it will close the tunnel. You also may want to ratelimit individual connections - use the "Per Connection Rate Limit" option to do so.
(If you failed to join, check out the [troubleshooting](#troubleshooting) section of the page.)
## Troubleshooting {#troubleshooting}
### I can't connect to my server! {#i-cant-connect-to-my-server}
* *Try going to the Agents page, set your agent to IPv4 only, and change the region. You may need to switch regions a few times before you can connect.*
* *Are there errors in your minecraft server console?*
* *Unless you manually changed the "Local Port" on the playit.gg website, in Geyser config, ensure that the bedrock port is the default of `19132` and that `clone-remote-port` is `false`.*
* *If you changed the `bedrock-port` or set `clone-remote-port` to `true` and have a reason for doing so (e.g. hosting another Geyser server on the same machine), you'll have to tell playit.gg to use that port instead! See the last paragraph in step 8.*
* *Check that you're joining with playit.gg's IP and port from the "Allocation" tab.*
* *Make sure that you have the program agent open while trying to join.*
* *See [here](/wiki/geyser/fixing-unable-to-connect-to-world/) for general troubleshooting steps.*
* *Make sure to check [here](/wiki/geyser/fixing-unable-to-connect-to-world/) beforehand.*
* *If you changed the port that Geyser would bind to, you'll have to tell playit.gg to use that port instead! See step 5 here.*
* *(Alternatively: You can try setting the* `bedrock` `port` *in the Geyser configuration to* `19132`.)
+4 -5
View File
@@ -183,9 +183,8 @@ sudo firewall-cmd --reload
#### Ubuntu {#ubuntu}
Run the following commands to allow Minecraft and Geyser through the OS firewall:
```bash
sudo ufw allow 25565/tcp
sudo ufw allow 19132/udp
1. Remove/comment out `-A INPUT -j REJECT --reject-with icmp-host-prohibited` in the `/etc/iptables/rules.v4` file.
2. Run the following command to fix `ufw`:
```bash
sudo iptables-restore < /etc/iptables/rules.v4
```
+36
View File
@@ -0,0 +1,36 @@
---
title: Information for server hosting providers
description: Useful information specifically aimed at server hosting providers.
---
# Information for server hosting providers
Hello! If you see this page, it's likely one of your users sent it to you as they wish to use the Geyser plugin/mod. This page aims to explain the configuration needed for Geyser, your options to automatically configure it to make it easier for users, and other noteworthy details.
# What is Geyser/Floodgate?
Geyser is a proxy allowing Minecraft: Bedrock edition users to play on Minecraft: Java edition servers. It can be used as a plugin, a mod, or as a standalone program.
# Requirements
Since Bedrock edition uses UDP (instead of TCP, as Java edition does), Geyser requires a port with UDP traffic allowed on it to properly function. Some setups, such as running Geyser in docker/pterodactyl or some providers such as OVH have specific configuration requirements. See our [portforwarding guide](/wiki/geyser/port-forwarding.md) for further information.
It can be the same port as the Java server, but it cannot be shared with other plugins using UDP traffic, such as voice chat plugins/mods, or Minecraft's query.
Further, see [here](/wiki/geyser/supported-versions/) for which Minecraft versions are currently supported.
# Geyser Download API
Geyser can be automatically downloaded from Geyser's download api. See [our api docs](/wiki/api/downloads.geysermc.org/) for usage instructions. Our current download api is based on Paper's downloads api, so you might be able to re-use existing scripts.
# Auto-Configuring Geyser
For maximum convenience for users, Geyser supports automatic configuration via system properties. See [here](/wiki/geyser/geyser-command-line-arguments-and-system-properties.md) for more information.
# Adding your host to our wiki
You can add usage instructions for your host [here](/src/data/providers.ts). Doing so allows us to direct users to proper instructions.
# Contacting us
Join our discord!
+11 -11
View File
@@ -7,7 +7,7 @@ import { Versions } from '@site/src/components/Versions'
:::caution
Geyser-Fabric and Geyser-NeoForge run **only** on a <Versions platform="java"/> server.
See [this page](/wiki/geyser/supported-versions#fabric-neoforge-servers) for more details.
See [this page](/wiki/geyser/supported-versions#using-geyser-fabric-or-geyser-neoforge-on-servers-that-do-not-run-) for more details.
:::
:::info
@@ -15,23 +15,23 @@ Geyser only works with **server-side** mods. Mods that require a client-side ins
:::
1. Select your server hosting provider in the dropdown above.
2. Download the mod from [the download page](/download).
2. Download the mod from [the download page](https://geysermc.org/download#geyser).
3. Place the Geyser mod jar in the `mods` folder, and restart the server. **For Fabric, you will also need [FabricAPI](https://modrinth.com/mod/fabric-api).**
4. Open your Geyser config, located in `/config/Geyser-Fabric/config.yml` (or `/config/Geyser-NeoForge/config.yml`), and find the following:
```yaml
bedrock:
# The IP address that will listen for connections.
# Generally, you should only change this if you want to limit what IPs can connect to your server.
address: 0.0.0.0
# The IP address that will listen for connections.
# Generally, you should only uncomment and change this if you want to limit what IPs can connect to your server.
#address: 0.0.0.0
# The port that will Geyser will listen on for incoming Bedrock connections.
# Since Minecraft: Bedrock Edition uses UDP, this port must allow UDP traffic.
port: 19132
# The port that will listen for connections. This is the port that Bedrock players will use to connect to your server.
port: 19132
# Some hosting services change your Java port everytime you start the server and require the same port to be used for Bedrock.
# This option makes the Bedrock port the same as the Java port every time you start the server.
clone-remote-port: false
# Some hosting services change your Java port everytime you start the server and require the same port to be used for Bedrock.
# This option makes the Bedrock port the same as the Java port every time you start the server.
# This option is for the plugin version only.
clone-remote-port: false
```
The vital part is the port. This is the port that Bedrock players will use to connect to your server.
Follow the instructions in the provider selector - change the port, and if necessary, `clone-remote-port` & `address`.
+14 -14
View File
@@ -7,29 +7,29 @@ hide_title: true
import { Versions } from '@site/src/components/Versions'
:::info
If your server is running a version older than <Versions platform="java"/>, you will need to install <a href="https://viaversion.com/">ViaVersion</a>.
If your server is not running <Versions platform="java"/>, you will need to install <a href="https://viaversion.com/">ViaVersion</a>.
See also [this page](/wiki/geyser/supported-versions/) on supported versions.
:::
1. Select your server hosting provider in the dropdown above.
2. Download the plugin from [the download page](/download).
2. Download the plugin from [the download page](https://download.geysermc.org/v2/projects/geyser/versions/latest/builds/latest/downloads/spigot).
3. Place the Geyser-Spigot.jar in the `plugins` folder, and restart the server.
4. Open your Geyser config, located in `/plugins/Geyser-Spigot/config.yml`, and find the following:
```yaml
bedrock:
# The IP address that will listen for connections.
# Generally, you should only change this if you want to limit what IPs can connect to your server.
address: 0.0.0.0
```yaml
bedrock:
# The IP address that will listen for connections.
# Generally, you should only uncomment and change this if you want to limit what IPs can connect to your server.
#address: 0.0.0.0
# The port that will Geyser will listen on for incoming Bedrock connections.
# Since Minecraft: Bedrock Edition uses UDP, this port must allow UDP traffic.
port: 19132
# The port that will listen for connections. This is the port that Bedrock players will use to connect to your server.
port: 19132
# Some hosting services change your Java port everytime you start the server and require the same port to be used for Bedrock.
# This option makes the Bedrock port the same as the Java port every time you start the server.
clone-remote-port: false
```
# Some hosting services change your Java port everytime you start the server and require the same port to be used for Bedrock.
# This option makes the Bedrock port the same as the Java port every time you start the server.
# This option is for the plugin version only.
clone-remote-port: false
```
The vital part is the port. This is the port that Bedrock players will use to connect to your server.
Follow the instructions in the provider selector - change the port, and if necessary, `clone-remote-port` & `address`.
If `clone-remote-port` is enabled, the bedrock port will be overwritten with the Java port!
+15 -15
View File
@@ -13,27 +13,27 @@ import { Versions } from '@site/src/components/Versions'
:::
1. Select your server hosting provider in the dropdown above.
2. Download the plugin for your proxy software from [the download page](/download).
2. Download the plugin for your proxy software from [the download page](https://geysermc.org/download).
3. Place the Geyser jar in the `plugins` folder, and restart the server.
4. Open your Geyser config, located in `/plugins/Geyser-xyz/config.yml`, and find the following:
```yaml
bedrock:
# The IP address that will listen for connections.
# Generally, you should only change this if you want to limit what IPs can connect to your server.
address: 0.0.0.0
```yaml
bedrock:
# The IP address that will listen for connections.
# Generally, you should only uncomment and change this if you want to limit what IPs can connect to your server.
#address: 0.0.0.0
# The port that will Geyser will listen on for incoming Bedrock connections.
# Since Minecraft: Bedrock Edition uses UDP, this port must allow UDP traffic.
port: 19132
# The port that will listen for connections. This is the port that Bedrock players will use to connect to your server.
port: 19132
# Some hosting services change your Java port everytime you start the server and require the same port to be used for Bedrock.
# This option makes the Bedrock port the same as the Java port every time you start the server.
clone-remote-port: false
```
The vital part is the port. This is the port that Bedrock players will use to connect to your server.
# Some hosting services change your Java port everytime you start the server and require the same port to be used for Bedrock.
# This option makes the Bedrock port the same as the Java port every time you start the server.
# This option is for the plugin version only.
clone-remote-port: false
```
The vital part is the port. This is the port that Bedrock players will use to connect to your server.
Follow the instructions in the provider selector - change the port, and if necessary, `clone-remote-port` & `address`.
If `clone-remote-port` is enabled, the bedrock port will be overwritten with the Java port!
If `clone-remote-port` is enabled, the bedrock port will be overwritten with the Java port!
**Important**: Other services/plugins that rely on ports with UDP, such as Voice Chats or Query, cannot share the port with Geyser.
5. Verify whether connections are possible by running `geyser connectiontest <ip> <port>` in the console.
+8 -13
View File
@@ -8,30 +8,25 @@ import { Versions } from '@site/src/components/Versions'
:::caution
Geyser-Fabric and Geyser-NeoForge run **only** on a <Versions platform="java"/> server.
See [this page](/wiki/geyser/supported-versions#fabric-neoforge-servers) for more details.
See [this page](/wiki/geyser/supported-versions#using-geyser-fabric-or-geyser-neoforge-on-servers-that-do-not-run-) for more details.
:::
:::info
Geyser only works with **server-side** mods. Mods that require a client-side install will not work!
:::
1. Download the mod from [the download page](/download).
1. Download the mod from [the download page](https://geysermc.org/download#geyser).
2. Place the Geyser mod jar in the `mods` folder, and restart the server. **For Fabric, you will also need [FabricAPI](https://modrinth.com/mod/fabric-api).**
3. Open your Geyser config, located in `/config/Geyser-Fabric/config.yml` (or `/config/Geyser-NeoForge/config.yml`), and find the following:
```yaml
bedrock:
# The IP address that will listen for connections.
# Generally, you should only change this if you want to limit what IPs can connect to your server.
address: 0.0.0.0
bedrock:
# The IP address that will listen for connections.
# Generally, you should only uncomment and change this if you want to limit what IPs can connect to your server.
#address: 0.0.0.0
# The port that will Geyser will listen on for incoming Bedrock connections.
# Since Minecraft: Bedrock Edition uses UDP, this port must allow UDP traffic.
port: 19132
# Some hosting services change your Java port everytime you start the server and require the same port to be used for Bedrock.
# This option makes the Bedrock port the same as the Java port every time you start the server.
clone-remote-port: false
# The port that will listen for connections. This is the port that Bedrock players will use to connect to your server.
port: 19132
```
The vital part is the port. This is the port that Bedrock players will use to connect to your server!
If you enable `clone-remote-port`, the port will be overridden and the Java port is used.
+8 -13
View File
@@ -6,27 +6,22 @@ description: Learn how to set up Geyser on your self-hosted Paper or Spigot serv
import { Versions } from '@site/src/components/Versions'
:::info
If your server is running a version older than <Versions platform="java"/>, you will need to install <a href="https://viaversion.com/">ViaVersion</a>.
If your server is not running <Versions platform="java"/>, you will need to install <a href="https://viaversion.com/">ViaVersion</a>.
See also [this page](/wiki/geyser/supported-versions/) on supported versions.
:::
1. Download the plugin from [the download page](/download).
1. Download the plugin from [the download page](https://download.geysermc.org/v2/projects/geyser/versions/latest/builds/latest/downloads/spigot).
2. Place the Geyser-Spigot.jar in the `plugins` folder, and restart the server.
3. Open your Geyser config, located in `/plugins/Geyser-Spigot/config.yml`, and find the following:
```yaml
bedrock:
# The IP address that will listen for connections.
# Generally, you should only change this if you want to limit what IPs can connect to your server.
address: 0.0.0.0
bedrock:
# The IP address that will listen for connections.
# Generally, you should only uncomment and change this if you want to limit what IPs can connect to your server.
#address: 0.0.0.0
# The port that will Geyser will listen on for incoming Bedrock connections.
# Since Minecraft: Bedrock Edition uses UDP, this port must allow UDP traffic.
port: 19132
# Some hosting services change your Java port everytime you start the server and require the same port to be used for Bedrock.
# This option makes the Bedrock port the same as the Java port every time you start the server.
clone-remote-port: false
# The port that will listen for connections. This is the port that Bedrock players will use to connect to your server.
port: 19132
```
The vital part is the port. This is the port that Bedrock players will use to connect to your server!
If you enable `clone-remote-port`, the port will be overridden and the Java port is used.
+8 -13
View File
@@ -12,23 +12,18 @@ import { Versions } from '@site/src/components/Versions'
- All servers on the network must accept <Versions platform="java"/> Java clients, as Geyser imitates one.
:::
1. Download the plugin for your proxy software from [the download page](/download).
1. Download the plugin for your proxy software from [the download page](https://geysermc.org/download).
2. Place the Geyser jar in the `plugins` folder, and restart the server.
3. Open your Geyser config, located in `/plugins/Geyser-xyz/config.yml`, and find the following:
```yaml
bedrock:
# The IP address that will listen for connections.
# Generally, you should only change this if you want to limit what IPs can connect to your server.
address: 0.0.0.0
```yaml
bedrock:
# The IP address that will listen for connections.
# Generally, you should only uncomment and change this if you want to limit what IPs can connect to your server.
#address: 0.0.0.0
# The port that will Geyser will listen on for incoming Bedrock connections.
# Since Minecraft: Bedrock Edition uses UDP, this port must allow UDP traffic.
port: 19132
# Some hosting services change your Java port everytime you start the server and require the same port to be used for Bedrock.
# This option makes the Bedrock port the same as the Java port every time you start the server.
clone-remote-port: false
# The port that will listen for connections. This is the port that Bedrock players will use to connect to your server.
port: 19132
```
The vital part is the port. This is the port that Bedrock players will use to connect to your server!
If you enable `clone-remote-port`, the port will be overridden and the Java port is used.
+20 -22
View File
@@ -12,9 +12,9 @@ You need to have Java 17 or higher installed to run Geyser. To run Geyser Standa
Geyser-Standalone is NOT a plugin or mod! It is a standalone Java program that you would run separately to your Java Edition server.
:::
#### General Setup & Configuration \{#general-setup--configuration}
### General Setup & Configuration {#general-setup--configuration}
1. Download Geyser Standalone from [here](/download).
1. Download Geyser Standalone from [here](https://download.geysermc.org/v2/projects/geyser/versions/latest/builds/latest/downloads/standalone).
2. Create a new folder for Geyser, and drop the jar in there.
3. Start Geyser Standalone:
- **GUI** (Recommended):
@@ -26,15 +26,13 @@ Geyser-Standalone is NOT a plugin or mod! It is a standalone Java program that y
4. Open your Geyser config (`config.yml`), and find the following:
```yaml
bedrock:
# The IP address that Geyser will bind on to listen for incoming Bedrock connections.
# Generally, you should only change this if you want to limit what IPs can connect to your server.
address: 0.0.0.0
# The port that will Geyser will listen on for incoming Bedrock connections.
# Since Minecraft: Bedrock Edition uses UDP, this port must allow UDP traffic.
port: 19132
bedrock:
# The IP address that will listen for connections.
# Generally, you should only uncomment and change this if you want to limit what IPs can connect to your server.
#address: 0.0.0.0
# The port that will listen for connections. This is the port that Bedrock players will use to connect to your server.
port: 19132
```
The `port` is the port Bedrock players will enter to connect to the server.
Uncommenting and changing `address` here is only needed if you need to limit connections to a specific IP address.
@@ -42,18 +40,18 @@ Geyser-Standalone is NOT a plugin or mod! It is a standalone Java program that y
To configure which Java Edition server Geyser Standalone will send players to, find the remote section:
```yaml
java:
# The IP address of the Java Edition server.
address: 127.0.0.1
remote:
# The IP address of the remote (Java Edition) server
# If it is "auto", for standalone version the remote address will be set to 127.0.0.1.
address: auto
# The port of the Java Edition server.
port: 25565
# What type of authentication Bedrock players will be checked against when logging into the Java server.
# Can be "floodgate" (see https://wiki.geysermc.org/floodgate/), "online", or "offline".
auth-type: online
# The port of the remote (Java Edition) server
port: 25565
# Authentication type. Can be offline, online, or floodgate (see https://github.com/GeyserMC/Geyser/wiki/Floodgate).
auth-type: online
```
Here, change `address` to the Java server's address, or leave it as-is if the server is on the same machine as Geyser-Standalone.
Here, change `address` to the Java server's address, or to `auto` if the server is on the same machine as Geyser-Standalone.
Then, change `port` to the Java server's port. If you have set up Floodgate on the remote Java server, you can set auth-type to "floodgate" - otherwise,
set it to either `online` for an online mode server, or `offline` for an offline mode server. To install and set up Floodgate with a Standalone server, see [here](/wiki/floodgate/setup).
@@ -79,13 +77,13 @@ set it to either `online` for an online mode server, or `offline` for an offline
6. Verify whether connections from other networks are possible by running `geyser connectiontest <ip> <port>` in the console.
#### Running Geyser-Standalone on Android \{#running-geyser-standalone-on-android}
### Running Geyser-Standalone on Android {#running-geyser-standalone-on-android}
:::caution
Applications such as Termux on Android are capable of running Geyser, but this largely depends on how powerful your Android device is. Please do so at your own risk.
:::
##### Termux (Android) \{#termux-android}
#### Termux (Android) {#termux-android}
1. Download and install [Termux](https://termux.com/)
2. Run `pkg install openjdk-17`
3. Run `wget https://download.geysermc.org/v2/projects/geyser/versions/latest/builds/latest/downloads/standalone`
+7 -12
View File
@@ -4,23 +4,18 @@ description: Learn how to set up Geyser with ViaProxy.
---
1. [Setup ViaProxy](https://github.com/ViaVersion/ViaProxy?tab=readme-ov-file#usage-for-players-gui).
2. Download the plugin from [the download page](/download).
2. Download the plugin from [the download page](https://download.geysermc.org/v2/projects/geyser/versions/latest/builds/latest/downloads/viaproxy).
3. Place the Geyser-ViaProxy.jar in the `plugins` folder, and restart ViaProxy.
4. Open your Geyser config, located in `/plugins/Geyser/config.yml`, and find the following:
```yaml
bedrock:
# The IP address that will listen for connections.
# Generally, you should only change this if you want to limit what IPs can connect to your server.
address: 0.0.0.0
bedrock:
# The IP address that will listen for connections.
# Generally, you should only uncomment and change this if you want to limit what IPs can connect to your server.
#address: 0.0.0.0
# The port that will Geyser will listen on for incoming Bedrock connections.
# Since Minecraft: Bedrock Edition uses UDP, this port must allow UDP traffic.
port: 19132
# Some hosting services change your Java port everytime you start the server and require the same port to be used for Bedrock.
# This option makes the Bedrock port the same as the Java port every time you start the server.
clone-remote-port: false
# The port that will listen for connections. This is the port that Bedrock players will use to connect to your server.
port: 19132
```
The vital part is the port. This is the port that Bedrock players will use to connect to your server!
If you enable `clone-remote-port`, the port will be overridden and the ViaProxy port is used.
+9 -11
View File
@@ -7,6 +7,12 @@ import { Provider } from "@site/src/components/Provider";
:::caution
This list is incomplete. Please open a [PR](https://github.com/GeyserMC/GeyserWebsite/pulls) or contact us on [Discord](https://discord.gg/geysermc) if the information is incorrect, or you want to add a new hosting provider!
:::
:::caution
These providers are not verified by the Geyser team, and the server providers below are reported as working by members of the community.
:::
@@ -23,22 +29,14 @@ The below information is for the plugin versions of Geyser unless otherwise spec
:::
<br/>
:::info PLEASE NOTE
This list is incomplete. Please open a [PR](https://github.com/GeyserMC/GeyserWebsite/pulls) or contact us on [Discord](https://discord.gg/geysermc) if the information is incorrect, or you want to add a new hosting provider!
:::
## Built-in Geyser \{#built-in-geyser}
## Built-in Geyser {#built-in-geyser}
<Provider type="built_in" />
## Support for Geyser \{#support-for-geyser}
## Support for Geyser {#support-for-geyser}
<Provider type="support" />
## Does not support Geyser \{#does-not-support-geyser}
## Does not support Geyser {#does-not-support-geyser}
<Provider type="no_support" />
+1 -1
View File
@@ -30,7 +30,7 @@ In order for Bedrock players to chat (1.19.3+) or join (1.19.1/1.19.2), you need
This is unfortunately not possible. You'll need to use a proxy such as Velocity or BungeeCord, or set up Geyser-Standalone separately with the [ViaVersion](https://github.com/ViaVersion/ViaVersion) plugin. Another alternative would be to install [ViaProxy](https://github.com/ViaVersion/ViaProxy), which is a standalone ViaVersion proxy that
translates between different Minecraft: Java edition versions, and to install Geyser-ViaProxy on it.
### Using Geyser on Fabric/NeoForge servers not on the latest Minecraft version {#fabric-neoforge-servers}
### Using Geyser-Fabric or Geyser-NeoForge on servers that do not run <Versions platform="java"/>
Unfortunately, Geyser-Fabric and Geyser-NeoForge only support the latest version of Minecraft: Java edition. The recommended way to still use
Geyser with older versions would be to install [ViaProxy](https://github.com/ViaVersion/ViaProxy), which is a standalone ViaVersion proxy that
translates between different Minecraft: Java edition versions, and to install Geyser-ViaProxy on it. This will also work with Floodgate auth.
+1 -1
View File
@@ -52,7 +52,7 @@ These languages are also supported, and are available in the Bedrock client usin
| Hindi | hi_in |
## How can I help translate Geyser? {#how-can-i-help-translate-geyser}
We use [Crowdin](https://translate.geysermc.org/) to manage our translations.
We use [Crowdin](https://crowdin.com/project/geyser) to manage our translations.
We also can add support for more languages, and please request them in the Discord server if you are willing to translate them.
(Those can be enabled clientside via [https://www.curseforge.com/minecraft-bedrock/addons/translations-for-minecraft](https://www.curseforge.com/minecraft-bedrock/addons/translations-for-minecraft))
@@ -0,0 +1,48 @@
---
title: Resolving Address already in use
description: A small guide on resolving the "Address already in use" error.
---
# Resolving "Address already in use"
This error means that something else using UDP is already running on the address/port that Geyser
is trying to bind to.
## Potential causes
The following section lists potential causes for this issue.
### Incorrect configuration
If you are using a Minecraft server hosting provider, this can also be caused by your Geyser configuration not using
the port assigned to your server. Please make sure you configured Geyser properly by checking our [setup guide](/wiki/geyser/setup).
:::info
If you are using a Minecraft server hosting provider, you may only have one UDP port assigned to you.
In that case, you **cannot** use multiple of the features listed here, and may need to choose one over another.
:::
### Minecraft's Query system
It also utilizes UDP, and some server hosting providers automatically enable it or change the port it is running on.
If you suspect it is conflicting with Geyser, you can disable query entirely, or change the query port.
To *disable* it:
| Platform | Spigot/Paper/Fabric/NeoForge | BungeeCord | Velocity |
|:---------|:-----------------------------|:--------------------------|:-------------------------------------|
| Filename | `server.properties` | BungeeCord's `config.yml` | `velocity.toml` |
| Options | `enable-query=false` | `query_enabled:false` | `[query]` section: `enabled = false` |
To *change the port* it is running on:
| Platform | Spigot/Paper/Fabric/NeoForge | BungeeCord | Velocity |
|:---------|:-----------------------------|:--------------------------|:---------------------------------|
| Filename | `server.properties` | BungeeCord's `config.yml` | `velocity.toml` |
| Options | change `query.port` | change `query_port` | `[query]` section: change `port` |
### Voice Chat plugins/mods
You can remove them, or change the port in their respective configuration. Please consult their documentation to find out how!
### Another application using UDP
If you are self-hosting, it can also mean that something (likely another instance of Geyser) is running on the port you have specified in the config.
Please make sure you close all applications running on this port. If you don't recall opening anything, usually restarting your computer fixes this.
@@ -0,0 +1,32 @@
---
title: Command/Permission issues
description: This page aims to resolve issues about being unable to run or use Geyser commands.
---
# Resolving issues related to commands and command permissions
---------
# Geyser commands not available to players
See [our page on commands](/wiki/geyser/commands/) for information on how to grant permissions to players.
For Floodgate commands, see [here](/wiki/floodgate/commands).
---------
# Bedrock clients freeze when opening up commands for the first time
Disable `command-suggestions` in your Geyser config. This will stop the freezing at the expense of removing command suggestions from Bedrock clients.
If you're a dedicated server admin, you can have a list of commands players should be using. This will remove any unnecessary commands from tab completion as well for Java players.
It has other benefits too. Here's a plugin that can just do that:
[CommandWhitelist](https://www.spigotmc.org/resources/81326/). Alternatively, use the [HideCommands](https://github.com/Redned235/HideCommands) Geyser extension to hide commands just for Bedrock players.
---------
# Unable to whitelist / op Bedrock players
## Whitelist command
To whitelist Bedrock players when using Floodgate, use the [`/fwhitelist` command](/wiki/floodgate/features#whitelist-command) provided by Floodgate.
## For other commands:
In some instances, like if you have the `username-prefix` set to `*`, you may need to wrap the Bedrock player's username in quotes; for example: `/tp "*BedrockPlayer"`. Setting the prefix to `.` should also fix this.
Loaded 100 of 121 files, more files were not shown because too many files have changed in this diff. Show more