diff --git a/.gitignore b/.gitignore index fd8f6bff5..aa52285df 100644 --- a/.gitignore +++ b/.gitignore @@ -135,3 +135,4 @@ logs/ server-icon.png /bin/ run/ +plugins/ \ No newline at end of file diff --git a/api/src/main/java/com/velocitypowered/api/proxy/messages/MinecraftChannelIdentifier.java b/api/src/main/java/com/velocitypowered/api/proxy/messages/MinecraftChannelIdentifier.java index b8f689324..1355ed239 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/messages/MinecraftChannelIdentifier.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/messages/MinecraftChannelIdentifier.java @@ -10,7 +10,7 @@ import java.util.regex.Pattern; * Represents a Minecraft 1.13+ channel identifier. This class is immutable and safe for multi-threaded use. */ public final class MinecraftChannelIdentifier implements ChannelIdentifier { - private static final Pattern VALID_IDENTIFIER_REGEX = Pattern.compile("[a-z0-9\\-_]+", Pattern.CASE_INSENSITIVE); + private static final Pattern VALID_IDENTIFIER_REGEX = Pattern.compile("[a-z0-9\\-_]+"); private final String namespace; private final String name; diff --git a/api/src/main/java/com/velocitypowered/api/proxy/server/ServerPing.java b/api/src/main/java/com/velocitypowered/api/proxy/server/ServerPing.java index 252ad77c3..069a5f7e8 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/server/ServerPing.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/server/ServerPing.java @@ -74,6 +74,7 @@ public class ServerPing { builder.favicon = favicon; builder.nullOutModinfo = modinfo == null; if (modinfo != null) { + builder.modType = modinfo.type; builder.mods.addAll(modinfo.modList); } return builder; @@ -91,6 +92,7 @@ public class ServerPing { private int onlinePlayers; private int maximumPlayers; private final List samplePlayers = new ArrayList<>(); + private String modType; private final List mods = new ArrayList<>(); private Component description; private Favicon favicon; @@ -121,6 +123,11 @@ public class ServerPing { return this; } + public Builder modType(String modType) { + this.modType = Preconditions.checkNotNull(modType, "modType"); + return this; + } + public Builder mods(Mod... mods) { this.mods.addAll(Arrays.asList(mods)); return this; @@ -158,7 +165,7 @@ public class ServerPing { public ServerPing build() { return new ServerPing(version, nullOutPlayers ? null : new Players(onlinePlayers, maximumPlayers, samplePlayers), description, favicon, - nullOutModinfo ? null : new Modinfo(mods)); + nullOutModinfo ? null : new Modinfo(modType, mods)); } public Version getVersion() { @@ -185,6 +192,10 @@ public class ServerPing { return favicon; } + public String getModType() { + return modType; + } + public List getMods() { return mods; } @@ -196,6 +207,7 @@ public class ServerPing { ", onlinePlayers=" + onlinePlayers + ", maximumPlayers=" + maximumPlayers + ", samplePlayers=" + samplePlayers + + ", modType=" + modType + ", mods=" + mods + ", description=" + description + ", favicon=" + favicon + @@ -291,12 +303,13 @@ public class ServerPing { } public static class Modinfo { - public static final Modinfo DEFAULT = new Modinfo(ImmutableList.of()); + public static final Modinfo DEFAULT = new Modinfo("FML", ImmutableList.of()); - private final String type = "FML"; + private final String type; private final List modList; - public Modinfo(List modList) { + public Modinfo(String type, List modList) { + this.type = Preconditions.checkNotNull(type, "type"); this.modList = ImmutableList.copyOf(modList); } } diff --git a/native/src/main/java/com/velocitypowered/natives/util/NativeCodeLoader.java b/native/src/main/java/com/velocitypowered/natives/util/NativeCodeLoader.java index 2f07378c8..4b84516da 100644 --- a/native/src/main/java/com/velocitypowered/natives/util/NativeCodeLoader.java +++ b/native/src/main/java/com/velocitypowered/natives/util/NativeCodeLoader.java @@ -8,7 +8,7 @@ import java.util.function.Supplier; public class NativeCodeLoader implements Supplier { private final List> variants; - private Variant selected; + private volatile Variant selected; public NativeCodeLoader(List> variants) { this.variants = ImmutableList.copyOf(variants); @@ -16,36 +16,41 @@ public class NativeCodeLoader implements Supplier { @Override public T get() { - if (selected == null) { - selected = select(); - } - return selected.object; + return tryLoad().object; } - private Variant select() { - for (Variant variant : variants) { - T got = variant.get(); - if (got == null) { - continue; - } - return variant; + private Variant tryLoad() { + if (selected != null) { + return selected; + } + + synchronized (this) { + if (selected != null) { + return selected; + } + + for (Variant variant : variants) { + T got = variant.get(); + if (got == null) { + continue; + } + selected = variant; + return selected; + } + throw new IllegalArgumentException("Can't find any suitable variants"); } - throw new IllegalArgumentException("Can't find any suitable variants"); } public String getLoadedVariant() { - if (selected == null) { - selected = select(); - } - return selected.name; + return tryLoad().name; } static class Variant { - private boolean available; + private volatile boolean available; private final Runnable setup; private final String name; private final T object; - private boolean hasBeenSetup = false; + private volatile boolean hasBeenSetup = false; Variant(BooleanSupplier available, Runnable setup, String name, T object) { this.available = available.getAsBoolean(); @@ -54,27 +59,34 @@ public class NativeCodeLoader implements Supplier { this.object = object; } - private void setup() { - if (available && !hasBeenSetup) { - try { - setup.run(); - hasBeenSetup = true; - } catch (Exception e) { - available = false; + public T get() { + if (!available) { + return null; + } + + // Make sure setup happens only once + if (!hasBeenSetup) { + synchronized (this) { + // We change availability if need be below, may as well check it again here for sanity. + if (!available) { + return null; + } + + // Okay, now try the setup if we haven't done so yet. + if (!hasBeenSetup) { + try { + setup.run(); + hasBeenSetup = true; + return object; + } catch (Exception e) { + available = false; + return null; + } + } } } - } - public T get() { - if (!hasBeenSetup) { - setup(); - } - - if (available) { - return object; - } - - return null; + return object; } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java index 91fab4eb4..f343adae4 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java @@ -23,7 +23,7 @@ public enum StateRegistry { }, STATUS { { - SERVERBOUND.register(StatusRequest.class, StatusRequest::new, + SERVERBOUND.register(StatusRequest.class, () -> StatusRequest.INSTANCE, genericMappings(0x00)); SERVERBOUND.register(StatusPing.class, StatusPing::new, genericMappings(0x01)); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusRequest.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusRequest.java index c53276e5a..ff9897c69 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusRequest.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusRequest.java @@ -5,6 +5,12 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import io.netty.buffer.ByteBuf; public class StatusRequest implements MinecraftPacket { + public static final StatusRequest INSTANCE = new StatusRequest(); + + private StatusRequest() { + + } + @Override public void decode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { @@ -14,4 +20,9 @@ public class StatusRequest implements MinecraftPacket { public void encode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { } + + @Override + public String toString() { + return "StatusRequest"; + } }