Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-11-19 14:30:17 +01:00
Merge branch 'master' into feature/1.20.5
Dieser Commit ist enthalten in:
Commit
efda13421f
7
.github/workflows/build.yml
vendored
7
.github/workflows/build.yml
vendored
@ -136,14 +136,15 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cat metadata.json
|
cat metadata.json
|
||||||
echo
|
echo
|
||||||
|
mv metadata.json metadata.json.tmp
|
||||||
version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2)
|
version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2)
|
||||||
cat metadata.json | jq --arg project "${PROJECT}" --arg version "${version}" '
|
jq --arg project "${PROJECT}" --arg version "${version}" '
|
||||||
.
|
.
|
||||||
| .changes |= map({"commit", "summary", "message"})
|
| .changes |= map({"commit", "summary", "message"})
|
||||||
| .downloads |= map_values({"name", "sha256"})
|
| .downloads |= map_values({"name", "sha256"})
|
||||||
| {$project, "repo", $version, "number": .build, "changes", "downloads"}
|
| {$project, "repo", $version, "number": .build, "changes", "downloads"}
|
||||||
' | tee metadata.json
|
' metadata.json.tmp > metadata.json
|
||||||
echo
|
cat metadata.json
|
||||||
- name: Publish to Downloads API
|
- name: Publish to Downloads API
|
||||||
if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
|
if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
|
||||||
shell: bash
|
shell: bash
|
||||||
|
6
.github/workflows/preview.yml
vendored
6
.github/workflows/preview.yml
vendored
@ -69,11 +69,13 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cat metadata.json
|
cat metadata.json
|
||||||
echo
|
echo
|
||||||
cat metadata.json | jq --arg project "${PROJECT}" --arg version "${VERSION}" --arg number "${BUILD}" '
|
mv metadata.json metadata.json.tmp
|
||||||
|
jq --arg project "${PROJECT}" --arg version "${VERSION}" --arg number "${BUILD}" '
|
||||||
.
|
.
|
||||||
| .downloads |= map_values({"name", "sha256"})
|
| .downloads |= map_values({"name", "sha256"})
|
||||||
| {$project, "repo", $version, "number": $number | tonumber, "changes": [], "downloads"}
|
| {$project, "repo", $version, "number": $number | tonumber, "changes": [], "downloads"}
|
||||||
' | tee metadata.json
|
' metadata.json.tmp > metadata.json
|
||||||
|
cat metadata.json
|
||||||
- name: Publish to Downloads API
|
- name: Publish to Downloads API
|
||||||
if: success()
|
if: success()
|
||||||
shell: bash
|
shell: bash
|
||||||
|
@ -28,14 +28,15 @@ package org.geysermc.geyser.platform.fabric;
|
|||||||
import me.lucko.fabric.api.permissions.v0.Permissions;
|
import me.lucko.fabric.api.permissions.v0.Permissions;
|
||||||
import net.fabricmc.api.EnvType;
|
import net.fabricmc.api.EnvType;
|
||||||
import net.fabricmc.api.ModInitializer;
|
import net.fabricmc.api.ModInitializer;
|
||||||
|
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
|
||||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
|
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
|
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
|
||||||
import org.geysermc.geyser.platform.mod.GeyserModUpdateListener;
|
import org.geysermc.geyser.platform.mod.GeyserModUpdateListener;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
|
||||||
|
|
||||||
public class GeyserFabricBootstrap extends GeyserModBootstrap implements ModInitializer {
|
public class GeyserFabricBootstrap extends GeyserModBootstrap implements ModInitializer {
|
||||||
|
|
||||||
@ -45,21 +46,37 @@ public class GeyserFabricBootstrap extends GeyserModBootstrap implements ModInit
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInitialize() {
|
public void onInitialize() {
|
||||||
if (FabricLoader.getInstance().getEnvironmentType() == EnvType.SERVER) {
|
if (isServer()) {
|
||||||
// Set as an event, so we can get the proper IP and port if needed
|
// Set as an event, so we can get the proper IP and port if needed
|
||||||
ServerLifecycleEvents.SERVER_STARTED.register((server) -> {
|
ServerLifecycleEvents.SERVER_STARTED.register((server) -> {
|
||||||
this.setServer(server);
|
this.setServer(server);
|
||||||
onGeyserEnable();
|
onGeyserEnable();
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
ClientLifecycleEvents.CLIENT_STOPPING.register(($)-> {
|
||||||
|
onGeyserShutdown();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are only registered once
|
// These are only registered once
|
||||||
ServerLifecycleEvents.SERVER_STOPPING.register((server) -> onGeyserShutdown());
|
ServerLifecycleEvents.SERVER_STOPPING.register((server) -> {
|
||||||
|
if (isServer()) {
|
||||||
|
onGeyserShutdown();
|
||||||
|
} else {
|
||||||
|
onGeyserDisable();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
ServerPlayConnectionEvents.JOIN.register((handler, $, $$) -> GeyserModUpdateListener.onPlayReady(handler.getPlayer()));
|
ServerPlayConnectionEvents.JOIN.register((handler, $, $$) -> GeyserModUpdateListener.onPlayReady(handler.getPlayer()));
|
||||||
|
|
||||||
this.onGeyserInitialize();
|
this.onGeyserInitialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isServer() {
|
||||||
|
return FabricLoader.getInstance().getEnvironmentType().equals(EnvType.SERVER);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasPermission(@NonNull Player source, @NonNull String permissionNode) {
|
public boolean hasPermission(@NonNull Player source, @NonNull String permissionNode) {
|
||||||
return Permissions.check(source, permissionNode);
|
return Permissions.check(source, permissionNode);
|
||||||
|
@ -27,10 +27,10 @@ package org.geysermc.geyser.platform.neoforge;
|
|||||||
|
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.neoforged.api.distmarker.Dist;
|
|
||||||
import net.neoforged.fml.common.Mod;
|
import net.neoforged.fml.common.Mod;
|
||||||
import net.neoforged.fml.loading.FMLLoader;
|
import net.neoforged.fml.loading.FMLLoader;
|
||||||
import net.neoforged.neoforge.common.NeoForge;
|
import net.neoforged.neoforge.common.NeoForge;
|
||||||
|
import net.neoforged.neoforge.event.GameShuttingDownEvent;
|
||||||
import net.neoforged.neoforge.event.entity.player.PlayerEvent;
|
import net.neoforged.neoforge.event.entity.player.PlayerEvent;
|
||||||
import net.neoforged.neoforge.event.server.ServerStartedEvent;
|
import net.neoforged.neoforge.event.server.ServerStartedEvent;
|
||||||
import net.neoforged.neoforge.event.server.ServerStoppingEvent;
|
import net.neoforged.neoforge.event.server.ServerStoppingEvent;
|
||||||
@ -46,9 +46,11 @@ public class GeyserNeoForgeBootstrap extends GeyserModBootstrap {
|
|||||||
public GeyserNeoForgeBootstrap() {
|
public GeyserNeoForgeBootstrap() {
|
||||||
super(new GeyserNeoForgePlatform());
|
super(new GeyserNeoForgePlatform());
|
||||||
|
|
||||||
if (FMLLoader.getDist() == Dist.DEDICATED_SERVER) {
|
if (isServer()) {
|
||||||
// Set as an event so we can get the proper IP and port if needed
|
// Set as an event so we can get the proper IP and port if needed
|
||||||
NeoForge.EVENT_BUS.addListener(this::onServerStarted);
|
NeoForge.EVENT_BUS.addListener(this::onServerStarted);
|
||||||
|
} else {
|
||||||
|
NeoForge.EVENT_BUS.addListener(this::onClientStopping);
|
||||||
}
|
}
|
||||||
|
|
||||||
NeoForge.EVENT_BUS.addListener(this::onServerStopping);
|
NeoForge.EVENT_BUS.addListener(this::onServerStopping);
|
||||||
@ -64,6 +66,14 @@ public class GeyserNeoForgeBootstrap extends GeyserModBootstrap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onServerStopping(ServerStoppingEvent event) {
|
private void onServerStopping(ServerStoppingEvent event) {
|
||||||
|
if (isServer()) {
|
||||||
|
this.onGeyserShutdown();
|
||||||
|
} else {
|
||||||
|
this.onGeyserDisable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onClientStopping(GameShuttingDownEvent ignored) {
|
||||||
this.onGeyserShutdown();
|
this.onGeyserShutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,6 +81,11 @@ public class GeyserNeoForgeBootstrap extends GeyserModBootstrap {
|
|||||||
GeyserModUpdateListener.onPlayReady(event.getEntity());
|
GeyserModUpdateListener.onPlayReady(event.getEntity());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isServer() {
|
||||||
|
return FMLLoader.getDist().isDedicatedServer();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasPermission(@NonNull Player source, @NonNull String permissionNode) {
|
public boolean hasPermission(@NonNull Player source, @NonNull String permissionNode) {
|
||||||
return this.permissionHandler.hasPermission(source, permissionNode);
|
return this.permissionHandler.hasPermission(source, permissionNode);
|
||||||
|
@ -128,7 +128,9 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap {
|
|||||||
// We want to do this late in the server startup process to allow other mods
|
// We want to do this late in the server startup process to allow other mods
|
||||||
// To do their job injecting, then connect into *that*
|
// To do their job injecting, then connect into *that*
|
||||||
this.geyserInjector = new GeyserModInjector(server, this.platform);
|
this.geyserInjector = new GeyserModInjector(server, this.platform);
|
||||||
this.geyserInjector.initializeLocalChannel(this);
|
if (isServer()) {
|
||||||
|
this.geyserInjector.initializeLocalChannel(this);
|
||||||
|
}
|
||||||
|
|
||||||
// Start command building
|
// Start command building
|
||||||
// Set just "geyser" as the help command
|
// Set just "geyser" as the help command
|
||||||
@ -248,7 +250,19 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getServerPort() {
|
public int getServerPort() {
|
||||||
return ((GeyserServerPortGetter) server).geyser$getServerPort();
|
if (isServer()) {
|
||||||
|
return ((GeyserServerPortGetter) server).geyser$getServerPort();
|
||||||
|
} else {
|
||||||
|
// Set in the IntegratedServerMixin
|
||||||
|
return geyserConfig.getRemote().port();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract boolean isServer();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable SocketAddress getSocketAddress() {
|
||||||
|
return this.geyserInjector.getServerSocketAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -54,8 +54,10 @@ public class IntegratedServerMixin implements GeyserServerPortGetter {
|
|||||||
private void onOpenToLan(GameType gameType, boolean cheatsAllowed, int port, CallbackInfoReturnable<Boolean> cir) {
|
private void onOpenToLan(GameType gameType, boolean cheatsAllowed, int port, CallbackInfoReturnable<Boolean> cir) {
|
||||||
if (cir.getReturnValueZ()) {
|
if (cir.getReturnValueZ()) {
|
||||||
// If the LAN is opened, starts Geyser.
|
// If the LAN is opened, starts Geyser.
|
||||||
GeyserModBootstrap.getInstance().setServer((MinecraftServer) (Object) this);
|
GeyserModBootstrap instance = GeyserModBootstrap.getInstance();
|
||||||
GeyserModBootstrap.getInstance().onGeyserEnable();
|
instance.setServer((MinecraftServer) (Object) this);
|
||||||
|
instance.getGeyserConfig().getRemote().setPort(port);
|
||||||
|
instance.onGeyserEnable();
|
||||||
// Ensure player locale has been loaded, in case it's different from Java system language
|
// Ensure player locale has been loaded, in case it's different from Java system language
|
||||||
GeyserLocale.loadGeyserLocale(this.minecraft.options.languageCode);
|
GeyserLocale.loadGeyserLocale(this.minecraft.options.languageCode);
|
||||||
// Give indication that Geyser is loaded
|
// Give indication that Geyser is loaded
|
||||||
|
@ -26,7 +26,7 @@ package org.geysermc.geyser.platform.viaproxy;
|
|||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import net.raphimc.vialegacy.api.LegacyProtocolVersion;
|
import net.raphimc.vialegacy.api.LegacyProtocolVersion;
|
||||||
import net.raphimc.viaproxy.cli.options.Options;
|
import net.raphimc.viaproxy.ViaProxy;
|
||||||
import org.geysermc.geyser.configuration.GeyserJacksonConfiguration;
|
import org.geysermc.geyser.configuration.GeyserJacksonConfiguration;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -43,7 +43,7 @@ public class GeyserViaProxyConfiguration extends GeyserJacksonConfiguration {
|
|||||||
@Override
|
@Override
|
||||||
public int getPingPassthroughInterval() {
|
public int getPingPassthroughInterval() {
|
||||||
int interval = super.getPingPassthroughInterval();
|
int interval = super.getPingPassthroughInterval();
|
||||||
if (interval < 15 && Options.PROTOCOL_VERSION != null && Options.PROTOCOL_VERSION.olderThanOrEqualTo(LegacyProtocolVersion.r1_6_4)) {
|
if (interval < 15 && ViaProxy.getConfig().getTargetVersion() != null && ViaProxy.getConfig().getTargetVersion().olderThanOrEqualTo(LegacyProtocolVersion.r1_6_4)) {
|
||||||
// <= 1.6.4 servers sometimes block incoming connections from an IP address if too many connections are made
|
// <= 1.6.4 servers sometimes block incoming connections from an IP address if too many connections are made
|
||||||
interval = 15;
|
interval = 15;
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,6 @@ package org.geysermc.geyser.platform.viaproxy;
|
|||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import net.raphimc.viaproxy.ViaProxy;
|
import net.raphimc.viaproxy.ViaProxy;
|
||||||
import net.raphimc.viaproxy.cli.options.Options;
|
|
||||||
import net.raphimc.viaproxy.plugins.ViaProxyPlugin;
|
import net.raphimc.viaproxy.plugins.ViaProxyPlugin;
|
||||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
||||||
import org.geysermc.geyser.text.AsteriskSerializer;
|
import org.geysermc.geyser.text.AsteriskSerializer;
|
||||||
@ -49,8 +48,8 @@ public class GeyserViaProxyDumpInfo extends BootstrapDumpInfo {
|
|||||||
|
|
||||||
public GeyserViaProxyDumpInfo() {
|
public GeyserViaProxyDumpInfo() {
|
||||||
this.platformVersion = ViaProxy.VERSION;
|
this.platformVersion = ViaProxy.VERSION;
|
||||||
this.onlineMode = Options.ONLINE_MODE;
|
this.onlineMode = ViaProxy.getConfig().isProxyOnlineMode();
|
||||||
if (Options.BIND_ADDRESS instanceof InetSocketAddress inetSocketAddress) {
|
if (ViaProxy.getConfig().getBindAddress() instanceof InetSocketAddress inetSocketAddress) {
|
||||||
this.serverIP = inetSocketAddress.getHostString();
|
this.serverIP = inetSocketAddress.getHostString();
|
||||||
this.serverPort = inetSocketAddress.getPort();
|
this.serverPort = inetSocketAddress.getPort();
|
||||||
} else {
|
} else {
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.platform.viaproxy;
|
package org.geysermc.geyser.platform.viaproxy;
|
||||||
|
|
||||||
import net.raphimc.viaproxy.plugins.PluginManager;
|
|
||||||
import org.geysermc.geyser.GeyserMain;
|
import org.geysermc.geyser.GeyserMain;
|
||||||
|
|
||||||
public class GeyserViaProxyMain extends GeyserMain {
|
public class GeyserViaProxyMain extends GeyserMain {
|
||||||
@ -39,7 +38,7 @@ public class GeyserViaProxyMain extends GeyserMain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getPluginFolder() {
|
public String getPluginFolder() {
|
||||||
return PluginManager.PLUGINS_DIR.getName();
|
return "plugins";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,6 @@ package org.geysermc.geyser.platform.viaproxy;
|
|||||||
import net.lenni0451.lambdaevents.EventHandler;
|
import net.lenni0451.lambdaevents.EventHandler;
|
||||||
import net.raphimc.vialegacy.api.LegacyProtocolVersion;
|
import net.raphimc.vialegacy.api.LegacyProtocolVersion;
|
||||||
import net.raphimc.viaproxy.ViaProxy;
|
import net.raphimc.viaproxy.ViaProxy;
|
||||||
import net.raphimc.viaproxy.cli.options.Options;
|
|
||||||
import net.raphimc.viaproxy.plugins.PluginManager;
|
import net.raphimc.viaproxy.plugins.PluginManager;
|
||||||
import net.raphimc.viaproxy.plugins.ViaProxyPlugin;
|
import net.raphimc.viaproxy.plugins.ViaProxyPlugin;
|
||||||
import net.raphimc.viaproxy.plugins.events.ConsoleCommandEvent;
|
import net.raphimc.viaproxy.plugins.events.ConsoleCommandEvent;
|
||||||
@ -137,7 +136,7 @@ public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootst
|
|||||||
|
|
||||||
GeyserImpl.start();
|
GeyserImpl.start();
|
||||||
|
|
||||||
if (Options.PROTOCOL_VERSION != null && Options.PROTOCOL_VERSION.newerThanOrEqualTo(LegacyProtocolVersion.b1_8tob1_8_1)) {
|
if (ViaProxy.getConfig().getTargetVersion() != null && ViaProxy.getConfig().getTargetVersion().newerThanOrEqualTo(LegacyProtocolVersion.b1_8tob1_8_1)) {
|
||||||
// Only initialize the ping passthrough if the protocol version is above beta 1.7.3, as that's when the status protocol was added
|
// Only initialize the ping passthrough if the protocol version is above beta 1.7.3, as that's when the status protocol was added
|
||||||
this.pingPassthrough = GeyserLegacyPingPassthrough.init(this.geyser);
|
this.pingPassthrough = GeyserLegacyPingPassthrough.init(this.geyser);
|
||||||
}
|
}
|
||||||
@ -186,19 +185,19 @@ public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootst
|
|||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public String getServerBindAddress() {
|
public String getServerBindAddress() {
|
||||||
if (Options.BIND_ADDRESS instanceof InetSocketAddress socketAddress) {
|
if (ViaProxy.getConfig().getBindAddress() instanceof InetSocketAddress socketAddress) {
|
||||||
return socketAddress.getHostString();
|
return socketAddress.getHostString();
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Unsupported bind address type: " + Options.BIND_ADDRESS.getClass().getName());
|
throw new IllegalStateException("Unsupported bind address type: " + ViaProxy.getConfig().getBindAddress().getClass().getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getServerPort() {
|
public int getServerPort() {
|
||||||
if (Options.BIND_ADDRESS instanceof InetSocketAddress socketAddress) {
|
if (ViaProxy.getConfig().getBindAddress() instanceof InetSocketAddress socketAddress) {
|
||||||
return socketAddress.getPort();
|
return socketAddress.getPort();
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Unsupported bind address type: " + Options.BIND_ADDRESS.getClass().getName());
|
throw new IllegalStateException("Unsupported bind address type: " + ViaProxy.getConfig().getBindAddress().getClass().getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,4 +2,4 @@ name: "${name}-ViaProxy"
|
|||||||
version: "${version}"
|
version: "${version}"
|
||||||
author: "${author}"
|
author: "${author}"
|
||||||
main: "org.geysermc.geyser.platform.viaproxy.GeyserViaProxyPlugin"
|
main: "org.geysermc.geyser.platform.viaproxy.GeyserViaProxyPlugin"
|
||||||
min-version: "3.2.0"
|
min-version: "3.2.1"
|
||||||
|
@ -29,7 +29,7 @@ adapters = "1.12-SNAPSHOT"
|
|||||||
commodore = "2.2"
|
commodore = "2.2"
|
||||||
bungeecord = "a7c6ede"
|
bungeecord = "a7c6ede"
|
||||||
velocity = "3.1.1"
|
velocity = "3.1.1"
|
||||||
viaproxy = "3.2.0-SNAPSHOT"
|
viaproxy = "3.2.1"
|
||||||
fabric-minecraft = "1.20.5"
|
fabric-minecraft = "1.20.5"
|
||||||
fabric-loader = "0.15.10"
|
fabric-loader = "0.15.10"
|
||||||
fabric-api = "0.97.6+1.20.5"
|
fabric-api = "0.97.6+1.20.5"
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren