Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-11-17 05:20:14 +01:00
Small code cleanups and switch more stuff to adventure
Dieser Commit ist enthalten in:
Ursprung
21ad6a433f
Commit
f9f60e1489
@ -43,7 +43,7 @@ public class Metrics {
|
|||||||
private static boolean logFailedRequests = false;
|
private static boolean logFailedRequests = false;
|
||||||
|
|
||||||
// The logger for the failed requests
|
// The logger for the failed requests
|
||||||
private static Logger logger = LogManager.getLogger(Metrics.class);
|
private static final Logger logger = LogManager.getLogger(Metrics.class);
|
||||||
|
|
||||||
// The name of the server software
|
// The name of the server software
|
||||||
private final String name;
|
private final String name;
|
||||||
|
@ -568,7 +568,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
|||||||
|
|
||||||
if (event.getResult() instanceof DisconnectPlayer) {
|
if (event.getResult() instanceof DisconnectPlayer) {
|
||||||
DisconnectPlayer res = (DisconnectPlayer) event.getResult();
|
DisconnectPlayer res = (DisconnectPlayer) event.getResult();
|
||||||
disconnect(res.getReason());
|
disconnect(res.getReasonComponent());
|
||||||
} else if (event.getResult() instanceof RedirectPlayer) {
|
} else if (event.getResult() instanceof RedirectPlayer) {
|
||||||
RedirectPlayer res = (RedirectPlayer) event.getResult();
|
RedirectPlayer res = (RedirectPlayer) event.getResult();
|
||||||
createConnectionRequest(res.getServer())
|
createConnectionRequest(res.getServer())
|
||||||
@ -587,9 +587,9 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
|||||||
} else if (event.getResult() instanceof Notify) {
|
} else if (event.getResult() instanceof Notify) {
|
||||||
Notify res = (Notify) event.getResult();
|
Notify res = (Notify) event.getResult();
|
||||||
if (event.kickedDuringServerConnect()) {
|
if (event.kickedDuringServerConnect()) {
|
||||||
sendMessage(res.getMessage());
|
sendMessage(res.getMessageComponent());
|
||||||
} else {
|
} else {
|
||||||
disconnect(res.getMessage());
|
disconnect(res.getMessageComponent());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// In case someone gets creative, assume we want to disconnect the player.
|
// In case someone gets creative, assume we want to disconnect the player.
|
||||||
|
@ -43,7 +43,7 @@ import java.util.UUID;
|
|||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import net.kyori.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.asynchttpclient.ListenableFuture;
|
import org.asynchttpclient.ListenableFuture;
|
||||||
@ -167,10 +167,11 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PreLoginComponentResult result = event.getResult();
|
PreLoginComponentResult result = event.getResult();
|
||||||
Optional<Component> disconnectReason = result.getReason();
|
Optional<Component> disconnectReason = result.getReasonComponent();
|
||||||
if (disconnectReason.isPresent()) {
|
if (disconnectReason.isPresent()) {
|
||||||
// The component is guaranteed to be provided if the connection was denied.
|
// The component is guaranteed to be provided if the connection was denied.
|
||||||
mcConnection.closeWith(Disconnect.create(disconnectReason.get()));
|
mcConnection.closeWith(Disconnect.create(disconnectReason.get(),
|
||||||
|
inbound.getProtocolVersion()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,7 +261,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<Component> reason = event.getResult().getReason();
|
Optional<Component> reason = event.getResult().getReasonComponent();
|
||||||
if (reason.isPresent()) {
|
if (reason.isPresent()) {
|
||||||
player.disconnect0(reason.get(), true);
|
player.disconnect0(reason.get(), true);
|
||||||
} else {
|
} else {
|
||||||
|
@ -16,8 +16,6 @@ import io.netty.channel.ChannelOption;
|
|||||||
import io.netty.channel.EventLoopGroup;
|
import io.netty.channel.EventLoopGroup;
|
||||||
import io.netty.channel.WriteBufferWaterMark;
|
import io.netty.channel.WriteBufferWaterMark;
|
||||||
import io.netty.channel.epoll.EpollChannelOption;
|
import io.netty.channel.epoll.EpollChannelOption;
|
||||||
import io.netty.resolver.dns.DnsAddressResolverGroup;
|
|
||||||
import io.netty.resolver.dns.DnsNameResolverBuilder;
|
|
||||||
import io.netty.util.concurrent.GlobalEventExecutor;
|
import io.netty.util.concurrent.GlobalEventExecutor;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.velocitypowered.proxy.network.netty;
|
package com.velocitypowered.proxy.network.netty;
|
||||||
|
|
||||||
|
import com.google.common.cache.Cache;
|
||||||
|
import com.google.common.cache.CacheBuilder;
|
||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
import io.netty.resolver.AddressResolver;
|
import io.netty.resolver.AddressResolver;
|
||||||
import io.netty.resolver.AddressResolverGroup;
|
import io.netty.resolver.AddressResolverGroup;
|
||||||
@ -14,11 +16,13 @@ import java.util.List;
|
|||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.RejectedExecutionException;
|
import java.util.concurrent.RejectedExecutionException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public final class SeparatePoolInetNameResolver extends InetNameResolver {
|
public final class SeparatePoolInetNameResolver extends InetNameResolver {
|
||||||
|
|
||||||
private final ExecutorService resolveExecutor;
|
private final ExecutorService resolveExecutor;
|
||||||
private final InetNameResolver delegate;
|
private final InetNameResolver delegate;
|
||||||
|
private final Cache<String, List<InetAddress>> cache;
|
||||||
private AddressResolverGroup<InetSocketAddress> resolverGroup;
|
private AddressResolverGroup<InetSocketAddress> resolverGroup;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -35,12 +39,28 @@ public final class SeparatePoolInetNameResolver extends InetNameResolver {
|
|||||||
.setDaemon(true)
|
.setDaemon(true)
|
||||||
.build());
|
.build());
|
||||||
this.delegate = new DefaultNameResolver(executor);
|
this.delegate = new DefaultNameResolver(executor);
|
||||||
|
this.cache = CacheBuilder.newBuilder()
|
||||||
|
.expireAfterWrite(30, TimeUnit.SECONDS)
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doResolve(String inetHost, Promise<InetAddress> promise) throws Exception {
|
protected void doResolve(String inetHost, Promise<InetAddress> promise) throws Exception {
|
||||||
|
List<InetAddress> addresses = cache.getIfPresent(inetHost);
|
||||||
|
if (addresses != null) {
|
||||||
|
promise.trySuccess(addresses.get(0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
resolveExecutor.execute(() -> this.delegate.resolve(inetHost, promise));
|
resolveExecutor.execute(() -> {
|
||||||
|
promise.addListener(future -> {
|
||||||
|
if (future.isSuccess()) {
|
||||||
|
cache.put(inetHost, (List<InetAddress>) future.getNow());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.delegate.resolve(inetHost, promise);
|
||||||
|
});
|
||||||
} catch (RejectedExecutionException e) {
|
} catch (RejectedExecutionException e) {
|
||||||
promise.setFailure(e);
|
promise.setFailure(e);
|
||||||
}
|
}
|
||||||
@ -49,7 +69,18 @@ public final class SeparatePoolInetNameResolver extends InetNameResolver {
|
|||||||
@Override
|
@Override
|
||||||
protected void doResolveAll(String inetHost, Promise<List<InetAddress>> promise)
|
protected void doResolveAll(String inetHost, Promise<List<InetAddress>> promise)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
List<InetAddress> addresses = cache.getIfPresent(inetHost);
|
||||||
|
if (addresses != null) {
|
||||||
|
promise.trySuccess(addresses);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
promise.addListener(future -> {
|
||||||
|
if (future.isSuccess()) {
|
||||||
|
cache.put(inetHost, (List<InetAddress>) future.getNow());
|
||||||
|
}
|
||||||
|
});
|
||||||
resolveExecutor.execute(() -> this.delegate.resolveAll(inetHost, promise));
|
resolveExecutor.execute(() -> this.delegate.resolveAll(inetHost, promise));
|
||||||
} catch (RejectedExecutionException e) {
|
} catch (RejectedExecutionException e) {
|
||||||
promise.setFailure(e);
|
promise.setFailure(e);
|
||||||
|
@ -340,7 +340,7 @@ public enum ProtocolUtils {
|
|||||||
// No vanilla packet should give a 3 byte packet
|
// No vanilla packet should give a 3 byte packet
|
||||||
int len = readExtendedForgeShort(buf);
|
int len = readExtendedForgeShort(buf);
|
||||||
|
|
||||||
Preconditions.checkArgument(len <= (FORGE_MAX_ARRAY_LENGTH),
|
checkArgument(len <= FORGE_MAX_ARRAY_LENGTH,
|
||||||
"Cannot receive array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, len);
|
"Cannot receive array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, len);
|
||||||
|
|
||||||
byte[] ret = new byte[len];
|
byte[] ret = new byte[len];
|
||||||
@ -360,7 +360,7 @@ public enum ProtocolUtils {
|
|||||||
// No vanilla packet should give a 3 byte packet
|
// No vanilla packet should give a 3 byte packet
|
||||||
int len = readExtendedForgeShort(buf);
|
int len = readExtendedForgeShort(buf);
|
||||||
|
|
||||||
checkFrame(len <= (FORGE_MAX_ARRAY_LENGTH),
|
checkFrame(len <= FORGE_MAX_ARRAY_LENGTH,
|
||||||
"Cannot receive array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, len);
|
"Cannot receive array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, len);
|
||||||
|
|
||||||
return buf.readRetainedSlice(len);
|
return buf.readRetainedSlice(len);
|
||||||
@ -375,7 +375,7 @@ public enum ProtocolUtils {
|
|||||||
*/
|
*/
|
||||||
public static void writeByteArray17(byte[] b, ByteBuf buf, boolean allowExtended) {
|
public static void writeByteArray17(byte[] b, ByteBuf buf, boolean allowExtended) {
|
||||||
if (allowExtended) {
|
if (allowExtended) {
|
||||||
checkFrame(b.length <= (FORGE_MAX_ARRAY_LENGTH),
|
checkFrame(b.length <= FORGE_MAX_ARRAY_LENGTH,
|
||||||
"Cannot send array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH,
|
"Cannot send array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH,
|
||||||
b.length);
|
b.length);
|
||||||
} else {
|
} else {
|
||||||
@ -399,7 +399,7 @@ public enum ProtocolUtils {
|
|||||||
*/
|
*/
|
||||||
public static void writeByteBuf17(ByteBuf b, ByteBuf buf, boolean allowExtended) {
|
public static void writeByteBuf17(ByteBuf b, ByteBuf buf, boolean allowExtended) {
|
||||||
if (allowExtended) {
|
if (allowExtended) {
|
||||||
checkFrame(b.readableBytes() <= (FORGE_MAX_ARRAY_LENGTH),
|
checkFrame(b.readableBytes() <= FORGE_MAX_ARRAY_LENGTH,
|
||||||
"Cannot send array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH,
|
"Cannot send array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH,
|
||||||
b.readableBytes());
|
b.readableBytes());
|
||||||
} else {
|
} else {
|
||||||
|
@ -11,7 +11,7 @@ import java.util.Queue;
|
|||||||
* A variation on {@link io.netty.handler.flow.FlowControlHandler} that explicitly holds messages
|
* A variation on {@link io.netty.handler.flow.FlowControlHandler} that explicitly holds messages
|
||||||
* on {@code channelRead} and only releases them on an explicit read operation.
|
* on {@code channelRead} and only releases them on an explicit read operation.
|
||||||
*/
|
*/
|
||||||
public class AutoReadHolderHandler extends ChannelDuplexHandler implements ChannelInboundHandler {
|
public class AutoReadHolderHandler extends ChannelDuplexHandler {
|
||||||
|
|
||||||
private final Queue<Object> queuedMessages;
|
private final Queue<Object> queuedMessages;
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ import java.io.IOException;
|
|||||||
* A wrapper around {@link io.netty.buffer.ByteBuf} that implements the exception-free
|
* A wrapper around {@link io.netty.buffer.ByteBuf} that implements the exception-free
|
||||||
* {@link ByteArrayDataInput} interface from Guava.
|
* {@link ByteArrayDataInput} interface from Guava.
|
||||||
*/
|
*/
|
||||||
public class ByteBufDataInput implements ByteArrayDataInput, DataInput {
|
public class ByteBufDataInput implements ByteArrayDataInput {
|
||||||
|
|
||||||
private final ByteBuf in;
|
private final ByteBuf in;
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ import java.nio.charset.StandardCharsets;
|
|||||||
/**
|
/**
|
||||||
* A {@link DataOutput} equivalent to {@link ByteBufDataInput}.
|
* A {@link DataOutput} equivalent to {@link ByteBufDataInput}.
|
||||||
*/
|
*/
|
||||||
public class ByteBufDataOutput extends OutputStream implements DataOutput, ByteArrayDataOutput {
|
public class ByteBufDataOutput extends OutputStream implements ByteArrayDataOutput {
|
||||||
|
|
||||||
private final ByteBuf buf;
|
private final ByteBuf buf;
|
||||||
private final DataOutputStream utf8out;
|
private final DataOutputStream utf8out;
|
||||||
|
@ -9,7 +9,7 @@ import com.google.gson.JsonSerializer;
|
|||||||
import com.velocitypowered.api.util.Favicon;
|
import com.velocitypowered.api.util.Favicon;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
public class FaviconSerializer implements JsonSerializer<Favicon>, JsonDeserializer<Favicon> {
|
public final class FaviconSerializer implements JsonSerializer<Favicon>, JsonDeserializer<Favicon> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Favicon deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) {
|
public Favicon deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) {
|
||||||
|
@ -13,7 +13,7 @@ import com.velocitypowered.api.util.GameProfile.Property;
|
|||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class GameProfileSerializer implements JsonSerializer<GameProfile>,
|
public final class GameProfileSerializer implements JsonSerializer<GameProfile>,
|
||||||
JsonDeserializer<GameProfile> {
|
JsonDeserializer<GameProfile> {
|
||||||
|
|
||||||
private static final Type propertyList = new TypeToken<List<Property>>() {}.getType();
|
private static final Type propertyList = new TypeToken<List<Property>>() {}.getType();
|
||||||
|
@ -8,7 +8,7 @@ import io.netty.handler.codec.CorruptedFrameException;
|
|||||||
/**
|
/**
|
||||||
* Extends {@link com.google.common.base.Preconditions} for Netty's {@link CorruptedFrameException}.
|
* Extends {@link com.google.common.base.Preconditions} for Netty's {@link CorruptedFrameException}.
|
||||||
*/
|
*/
|
||||||
public class NettyPreconditions {
|
public final class NettyPreconditions {
|
||||||
private static final QuietDecoderException BAD = new QuietDecoderException(
|
private static final QuietDecoderException BAD = new QuietDecoderException(
|
||||||
"Invalid packet received. Launch Velocity with -Dvelocity.packet-decode-logging=true "
|
"Invalid packet received. Launch Velocity with -Dvelocity.packet-decode-logging=true "
|
||||||
+ "to see more.");
|
+ "to see more.");
|
||||||
|
@ -17,7 +17,7 @@ import java.util.List;
|
|||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class PluginMessageUtil {
|
public final class PluginMessageUtil {
|
||||||
|
|
||||||
private static final String BRAND_CHANNEL_LEGACY = "MC|Brand";
|
private static final String BRAND_CHANNEL_LEGACY = "MC|Brand";
|
||||||
private static final String BRAND_CHANNEL = "minecraft:brand";
|
private static final String BRAND_CHANNEL = "minecraft:brand";
|
||||||
@ -110,8 +110,8 @@ public class PluginMessageUtil {
|
|||||||
*/
|
*/
|
||||||
public static PluginMessage constructChannelsPacket(ProtocolVersion protocolVersion,
|
public static PluginMessage constructChannelsPacket(ProtocolVersion protocolVersion,
|
||||||
Collection<String> channels) {
|
Collection<String> channels) {
|
||||||
Preconditions.checkNotNull(channels, "channels");
|
checkNotNull(channels, "channels");
|
||||||
Preconditions.checkArgument(channels.size() > 0, "no channels specified");
|
checkArgument(!channels.isEmpty(), "no channels specified");
|
||||||
String channelName = protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_13) >= 0
|
String channelName = protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_13) >= 0
|
||||||
? REGISTER_CHANNEL : REGISTER_CHANNEL_LEGACY;
|
? REGISTER_CHANNEL : REGISTER_CHANNEL_LEGACY;
|
||||||
ByteBuf contents = Unpooled.buffer();
|
ByteBuf contents = Unpooled.buffer();
|
||||||
@ -131,14 +131,14 @@ public class PluginMessageUtil {
|
|||||||
checkNotNull(version, "version");
|
checkNotNull(version, "version");
|
||||||
checkArgument(isMcBrand(message), "message is not a brand plugin message");
|
checkArgument(isMcBrand(message), "message is not a brand plugin message");
|
||||||
|
|
||||||
String toAppend = " (" + version.getName() + ")";
|
|
||||||
String currentBrand = readBrandMessage(message.content());
|
String currentBrand = readBrandMessage(message.content());
|
||||||
|
String rewrittenBrand = String.format("%s (%s)", currentBrand, version.getName());
|
||||||
|
|
||||||
ByteBuf rewrittenBuf = Unpooled.buffer();
|
ByteBuf rewrittenBuf = Unpooled.buffer();
|
||||||
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
|
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
|
||||||
ProtocolUtils.writeString(rewrittenBuf, currentBrand + toAppend);
|
ProtocolUtils.writeString(rewrittenBuf, rewrittenBrand);
|
||||||
} else {
|
} else {
|
||||||
rewrittenBuf.writeBytes((currentBrand + toAppend).getBytes());
|
rewrittenBuf.writeCharSequence(rewrittenBrand, StandardCharsets.UTF_8);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PluginMessage(message.getChannel(), rewrittenBuf);
|
return new PluginMessage(message.getChannel(), rewrittenBuf);
|
||||||
|
@ -6,13 +6,13 @@ import java.net.InetAddress;
|
|||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
|
||||||
public class AddressUtil {
|
public final class AddressUtil {
|
||||||
private AddressUtil() {
|
private AddressUtil() {
|
||||||
throw new AssertionError();
|
throw new AssertionError();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to parse an IP address of the form <code>127.0.0.1:25565</code>. The returned
|
* Attempts to parse an IP address of the form {@code 127.0.0.1:25565}. The returned
|
||||||
* {@link InetSocketAddress} is not resolved.
|
* {@link InetSocketAddress} is not resolved.
|
||||||
*
|
*
|
||||||
* @param ip the IP to parse
|
* @param ip the IP to parse
|
||||||
@ -30,7 +30,7 @@ public class AddressUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to parse an IP address of the form <code>127.0.0.1:25565</code>. The returned
|
* Attempts to parse an IP address of the form {@code 127.0.0.1:25565}. The returned
|
||||||
* {@link InetSocketAddress} is resolved.
|
* {@link InetSocketAddress} is resolved.
|
||||||
*
|
*
|
||||||
* @param ip the IP to parse
|
* @param ip the IP to parse
|
||||||
|
@ -5,7 +5,7 @@ import java.time.Duration;
|
|||||||
/**
|
/**
|
||||||
* Provides utility functions for working with durations.
|
* Provides utility functions for working with durations.
|
||||||
*/
|
*/
|
||||||
public class DurationUtils {
|
public final class DurationUtils {
|
||||||
private static final long ONE_TICK_IN_MILLISECONDS = 50;
|
private static final long ONE_TICK_IN_MILLISECONDS = 50;
|
||||||
|
|
||||||
private DurationUtils() {
|
private DurationUtils() {
|
||||||
|
@ -4,7 +4,7 @@ import net.kyori.adventure.text.Component;
|
|||||||
import net.kyori.adventure.text.TextComponent;
|
import net.kyori.adventure.text.TextComponent;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
|
||||||
public class VelocityMessages {
|
public final class VelocityMessages {
|
||||||
|
|
||||||
public static final Component ONLINE_MODE_ONLY = TextComponent
|
public static final Component ONLINE_MODE_ONLY = TextComponent
|
||||||
.builder("This server only accepts connections from online-mode clients.")
|
.builder("This server only accepts connections from online-mode clients.")
|
||||||
|
@ -57,7 +57,7 @@ public class BossBarManager implements BossBar.Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private BossBarHolder getOrCreateHandler(BossBar bar) {
|
private BossBarHolder getOrCreateHandler(BossBar bar) {
|
||||||
BossBarHolder holder = this.bars.computeIfAbsent(bar, (k) -> new BossBarHolder(bar));
|
BossBarHolder holder = this.bars.computeIfAbsent(bar, k -> new BossBarHolder(bar));
|
||||||
holder.register();
|
holder.register();
|
||||||
return holder;
|
return holder;
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,12 @@
|
|||||||
package com.velocitypowered.proxy.util.concurrent;
|
package com.velocitypowered.proxy.util.concurrent;
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that guarantees that a given initialization shall only happen once. The implementation
|
* A class that guarantees that a given initialization shall only occur once. The implementation
|
||||||
* is (almost) a direct Java port of the Go {@code sync.Once} type (see the
|
* is (almost) a direct Java port of the Go {@code sync.Once} type (see the
|
||||||
* <a href="https://golang.org/pkg/sync/#Once">Go documentation</a>) and thus has similar
|
* <a href="https://golang.org/pkg/sync/#Once">Go documentation</a>) and thus has similar
|
||||||
* semantics.
|
* semantics.
|
||||||
*/
|
*/
|
||||||
public final class Once {
|
public final class Once {
|
||||||
private static final AtomicIntegerFieldUpdater<Once> COMPLETED_UPDATER =
|
|
||||||
AtomicIntegerFieldUpdater.newUpdater(Once.class, "completed");
|
|
||||||
|
|
||||||
private static final int NOT_STARTED = 0;
|
private static final int NOT_STARTED = 0;
|
||||||
private static final int COMPLETED = 1;
|
private static final int COMPLETED = 1;
|
||||||
|
|
||||||
@ -20,25 +15,25 @@ public final class Once {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Calls {@code runnable.run()} exactly once if this instance is being called for the first time,
|
* Calls {@code runnable.run()} exactly once if this instance is being called for the first time,
|
||||||
* otherwise the invocation shall wait until {@code runnable.run()} completes. Future calls to
|
* otherwise the invocation shall wait until {@code runnable.run()} completes. The first runnable
|
||||||
* this method once {@code runnable.run()} completes are no-ops - a new instance should be used
|
* used when this function is called is run. Future calls to this method once the initial
|
||||||
* instead.
|
* runnable completes are no-ops - a new instance should be used instead.
|
||||||
*
|
*
|
||||||
* @param runnable the runnable to run
|
* @param runnable the runnable to run
|
||||||
*/
|
*/
|
||||||
public void run(Runnable runnable) {
|
public void run(Runnable runnable) {
|
||||||
if (COMPLETED_UPDATER.get(this) == NOT_STARTED) {
|
if (completed == NOT_STARTED) {
|
||||||
slowRun(runnable);
|
slowRun(runnable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void slowRun(Runnable runnable) {
|
private void slowRun(Runnable runnable) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
if (this.completed == NOT_STARTED) {
|
if (completed == NOT_STARTED) {
|
||||||
try {
|
try {
|
||||||
runnable.run();
|
runnable.run();
|
||||||
} finally {
|
} finally {
|
||||||
COMPLETED_UPDATER.set(this, COMPLETED);
|
completed = COMPLETED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,11 +21,13 @@ public class OnceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void contendedOnce() throws Exception {
|
void contendedOnce() throws Exception {
|
||||||
ExecutorService service = Executors.newFixedThreadPool(10);
|
int threadsForTest = 25;
|
||||||
|
|
||||||
|
ExecutorService service = Executors.newFixedThreadPool(threadsForTest);
|
||||||
AtomicInteger i = new AtomicInteger();
|
AtomicInteger i = new AtomicInteger();
|
||||||
Once once = new Once();
|
Once once = new Once();
|
||||||
CountDownLatch latch = new CountDownLatch(10);
|
CountDownLatch latch = new CountDownLatch(threadsForTest);
|
||||||
for (int i1 = 0; i1 < 10; i1++) {
|
for (int i1 = 0; i1 < threadsForTest; i1++) {
|
||||||
service.execute(() -> {
|
service.execute(() -> {
|
||||||
once.run(i::incrementAndGet);
|
once.run(i::incrementAndGet);
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren