Config file
This commit is contained in:
parent
c751342ad8
commit
e2c49f35e6
|
|
@ -19,9 +19,8 @@ dependencies {
|
|||
compileOnly("com.velocitypowered:velocity-api")
|
||||
compileOnly("com.velocitypowered:velocity-proxy")
|
||||
annotationProcessor("com.velocitypowered:velocity-api")
|
||||
implementation("com.electronwill.night-config:toml:3.6.6")
|
||||
compileOnly("com.electronwill.night-config:toml:3.6.6")
|
||||
implementation("org.bstats:bstats-velocity:3.0.0")
|
||||
implementation("org.apache.commons:commons-collections4:4.4")
|
||||
compileOnly("io.netty:netty-buffer:4.1.86.Final")
|
||||
compileOnly("io.netty:netty-transport:4.1.86.Final")
|
||||
compileOnly("io.netty:netty-codec:4.1.86.Final")
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import com.google.inject.Inject;
|
|||
import com.velocitypowered.api.event.PostOrder;
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
|
||||
import com.velocitypowered.api.event.proxy.ProxyReloadEvent;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.api.plugin.Plugin;
|
||||
import com.velocitypowered.api.plugin.annotation.DataDirectory;
|
||||
|
|
@ -11,12 +12,13 @@ import com.velocitypowered.api.proxy.ProxyServer;
|
|||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.nio.file.Files;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import com.velocitypowered.proxy.VelocityServer;
|
||||
import com.velocitypowered.proxy.network.BackendChannelInitializer;
|
||||
import com.velocitypowered.proxy.network.ConnectionManager;
|
||||
import com.velocitypowered.proxy.network.ServerChannelInitializer;
|
||||
import com.velocitypowered.proxy.protocol.packet.brigadier.ArgumentIdentifier;
|
||||
import com.velocitypowered.proxy.protocol.packet.brigadier.ArgumentPropertyRegistry;
|
||||
import com.velocitypowered.proxy.protocol.packet.brigadier.ArgumentPropertySerializer;
|
||||
|
|
@ -28,11 +30,11 @@ import org.adde0109.ambassador.velocity.VelocityEventHandler;
|
|||
import org.adde0109.ambassador.velocity.protocol.EnumArgumentProperty;
|
||||
import org.adde0109.ambassador.velocity.protocol.EnumArgumentPropertySerializer;
|
||||
import org.adde0109.ambassador.velocity.protocol.ModIdArgumentProperty;
|
||||
import org.bstats.charts.SingleLineChart;
|
||||
import org.bstats.velocity.Metrics;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_19;
|
||||
import static com.velocitypowered.proxy.protocol.packet.brigadier.ArgumentIdentifier.mapSet;
|
||||
|
|
@ -45,6 +47,10 @@ public class Ambassador {
|
|||
private final Metrics.Factory metricsFactory;
|
||||
private final Path dataDirectory;
|
||||
|
||||
public AmbassadorConfig config;
|
||||
|
||||
private static final MapWithExpiration<String, RegisteredServer> TEMPORARY_FORCED = new MapWithExpiration<>();
|
||||
|
||||
private static Ambassador instance;
|
||||
public static Ambassador getInstance() {
|
||||
return instance;
|
||||
|
|
@ -61,12 +67,36 @@ public class Ambassador {
|
|||
}
|
||||
|
||||
@Subscribe(order = PostOrder.LAST)
|
||||
public void onProxyInitialization(ProxyInitializeEvent event) throws ReflectiveOperationException {
|
||||
public void onProxyInitialization(ProxyInitializeEvent event) {
|
||||
initMetrics();
|
||||
|
||||
server.getEventManager().register(this, new VelocityEventHandler(this));
|
||||
try {
|
||||
Files.createDirectories(dataDirectory);
|
||||
|
||||
inject();
|
||||
Path configPath = dataDirectory.resolve("Ambassador.toml");
|
||||
config = AmbassadorConfig.read(configPath);
|
||||
config.validate();
|
||||
|
||||
inject();
|
||||
|
||||
server.getEventManager().register(this, new VelocityEventHandler(this));
|
||||
} catch (Exception e) {
|
||||
logger.error(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onProxyReload(ProxyReloadEvent event) {
|
||||
try {
|
||||
Path configPath = dataDirectory.resolve("Ambassador.toml");
|
||||
final AmbassadorConfig newconfig = AmbassadorConfig.read(configPath);
|
||||
newconfig.validate();
|
||||
|
||||
config = newconfig;
|
||||
} catch (Exception e) {
|
||||
logger.error(e.toString());
|
||||
logger.warn("Reload unsuccessful, old config will be used.");
|
||||
}
|
||||
}
|
||||
|
||||
private void inject() throws ReflectiveOperationException {
|
||||
|
|
@ -97,7 +127,35 @@ public class Ambassador {
|
|||
|
||||
}
|
||||
|
||||
public static MapWithExpiration<String, RegisteredServer> getTemporaryForced() {
|
||||
return TEMPORARY_FORCED;
|
||||
}
|
||||
|
||||
private void initMetrics() {
|
||||
Metrics metrics = metricsFactory.make(this, 15655);
|
||||
}
|
||||
|
||||
public static class MapWithExpiration<K, V> {
|
||||
|
||||
private final Map<K, ExpiringValue<V, Long>> expirationMap = new HashMap<>();
|
||||
|
||||
|
||||
public V remove(K key) {
|
||||
ExpiringValue<V, Long> expiringValue = expirationMap.remove(key);
|
||||
if (expiringValue != null && expiringValue.value > System.currentTimeMillis()) {
|
||||
return expiringValue.key;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void put(K key, V value, int expirationTime, TimeUnit unit) {
|
||||
expirationMap.values().removeIf((v) -> v.value <= System.currentTimeMillis());
|
||||
expirationMap.put(key, new ExpiringValue<>(value,System.currentTimeMillis() + unit.toMillis(expirationTime)));
|
||||
}
|
||||
|
||||
private record ExpiringValue<K, V>(K key, V value) {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
67
src/main/java/org/adde0109/ambassador/AmbassadorConfig.java
Normal file
67
src/main/java/org/adde0109/ambassador/AmbassadorConfig.java
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
package org.adde0109.ambassador;
|
||||
|
||||
import com.electronwill.nightconfig.core.conversion.InvalidValueException;
|
||||
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class AmbassadorConfig {
|
||||
|
||||
@Expose
|
||||
private int resetTimeout = 1000;
|
||||
|
||||
@Expose
|
||||
private String disconnectResetMessage = "Please reconnect";
|
||||
|
||||
@Expose
|
||||
private int serverSwitchCancellationTime = 120;
|
||||
|
||||
private AmbassadorConfig(int resetTimeout, String kickResetMessage, int serverSwitchCancellationTime) {
|
||||
this.resetTimeout = resetTimeout;
|
||||
this.disconnectResetMessage = kickResetMessage;
|
||||
this.serverSwitchCancellationTime = serverSwitchCancellationTime;
|
||||
};
|
||||
|
||||
public void validate() {
|
||||
final int connectionTimeout = Ambassador.getInstance().server.getConfiguration().getConnectTimeout();
|
||||
if (resetTimeout >= connectionTimeout) {
|
||||
throw new InvalidValueException("'reset-timeout' can't be larger than nor equal to 'connection-timeout': reset-timeout=" + resetTimeout + " connection-timeout=" + connectionTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
public static AmbassadorConfig read(Path path) {
|
||||
URL defaultConfigLocation = AmbassadorConfig.class.getClassLoader()
|
||||
.getResource("default-ambassador.toml");
|
||||
if (defaultConfigLocation == null) {
|
||||
throw new RuntimeException("Default configuration file does not exist.");
|
||||
}
|
||||
|
||||
CommentedFileConfig config = CommentedFileConfig.builder(path)
|
||||
.defaultData(defaultConfigLocation)
|
||||
.autosave()
|
||||
.preserveInsertionOrder()
|
||||
.sync()
|
||||
.build();
|
||||
config.load();
|
||||
|
||||
int resetTimeout = config.getIntOrElse("reset-timeout", 3000);
|
||||
String kickResetMessage = config.getOrElse("disconnect-reset-message", "Please reconnect");
|
||||
int serverSwitchCancellationTime = config.getIntOrElse("server-switch-cancellation-time", 120000);
|
||||
|
||||
return new AmbassadorConfig(resetTimeout, kickResetMessage, serverSwitchCancellationTime);
|
||||
}
|
||||
|
||||
public int getResetTimeout() {
|
||||
return resetTimeout;
|
||||
}
|
||||
|
||||
public String getDisconnectResetMessage() {
|
||||
return disconnectResetMessage;
|
||||
}
|
||||
|
||||
public int getServerSwitchCancellationTime() {
|
||||
return serverSwitchCancellationTime;
|
||||
}
|
||||
}
|
||||
|
|
@ -7,7 +7,6 @@ import com.velocitypowered.proxy.VelocityServer;
|
|||
import com.velocitypowered.proxy.config.PlayerInfoForwarding;
|
||||
import com.velocitypowered.proxy.config.VelocityConfiguration;
|
||||
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
||||
import com.velocitypowered.proxy.connection.backend.VelocityServerConnection;
|
||||
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
||||
import com.velocitypowered.proxy.network.Connections;
|
||||
import com.velocitypowered.proxy.protocol.StateRegistry;
|
||||
|
|
@ -51,7 +50,7 @@ public class FML2CRPMClientConnectionPhase extends VelocityForgeClientConnection
|
|||
ScheduledFuture<?> scheduledFuture = connection.eventLoop().schedule(()-> {
|
||||
connection.getChannel().pipeline().remove(ForgeConstants.RESET_LISTENER);
|
||||
future.complete(false);
|
||||
},5, TimeUnit.SECONDS);
|
||||
}, Ambassador.getInstance().config.getResetTimeout(), TimeUnit.MILLISECONDS);
|
||||
connection.getChannel().pipeline().addBefore(Connections.MINECRAFT_DECODER, ForgeConstants.RESET_LISTENER,new FML2CRPMResetCompleteDecoder());
|
||||
getPayloadManager().listenFor(98).thenAccept(ignore -> {
|
||||
if (scheduledFuture.cancel(false)) {
|
||||
|
|
|
|||
|
|
@ -9,10 +9,9 @@ import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
|||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.adde0109.ambassador.Ambassador;
|
||||
import org.adde0109.ambassador.velocity.VelocityForgeClientConnectionPhase;
|
||||
import org.apache.commons.collections4.map.PassiveExpiringMap;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
|
@ -21,10 +20,6 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
public class FML2ClientConnectionPhase extends VelocityForgeClientConnectionPhase {
|
||||
|
||||
private static String OUTBOUND_CATCHER_NAME = "ambassador-catcher";
|
||||
|
||||
private static final PassiveExpiringMap<String,RegisteredServer> TEMPORARY_FORCED = new PassiveExpiringMap<>(120, TimeUnit.SECONDS);
|
||||
|
||||
private Throwable throwable;
|
||||
private RegisteredServer triedServer;
|
||||
private Continuation continuation;
|
||||
|
|
@ -56,7 +51,7 @@ public class FML2ClientConnectionPhase extends VelocityForgeClientConnectionPhas
|
|||
this.continuation = continuation;
|
||||
final MinecraftConnection connection = player.getConnection();
|
||||
|
||||
forced = TEMPORARY_FORCED.remove(player.getUsername());
|
||||
forced = Ambassador.getTemporaryForced().remove(player.getUsername());
|
||||
if (forced != null) {
|
||||
player.createConnectionRequest(forced).fireAndForget();
|
||||
} else {
|
||||
|
|
@ -75,8 +70,8 @@ public class FML2ClientConnectionPhase extends VelocityForgeClientConnectionPhas
|
|||
CompletableFuture<Boolean> future = newPhase.reset(server,player);
|
||||
future.thenAccept(success -> {
|
||||
if (!success) {
|
||||
TEMPORARY_FORCED.put(player.getUsername(),server);
|
||||
player.disconnect(Component.text("Please reconnect"));
|
||||
Ambassador.getTemporaryForced().put(player.getUsername(),server, Ambassador.getInstance().config.getServerSwitchCancellationTime(), TimeUnit.SECONDS);
|
||||
player.disconnect(Component.text(Ambassador.getInstance().config.getDisconnectResetMessage()));
|
||||
}
|
||||
});
|
||||
return future;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ public class ForgeFMLConnectionType implements ConnectionType {
|
|||
|
||||
@Override
|
||||
public GameProfile addGameProfileTokensIfRequired(GameProfile original, PlayerInfoForwarding forwardingType) {
|
||||
//This is meant for Arc light to parse
|
||||
if (forwardingType == PlayerInfoForwarding.LEGACY) {
|
||||
return original.addProperties(Collections.singleton(new GameProfile.Property("extraData", "\1FML" + netVersion + "\1", "")));
|
||||
} else {
|
||||
|
|
|
|||
9
src/main/resources/default-ambassador.toml
Normal file
9
src/main/resources/default-ambassador.toml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# Do not change this
|
||||
config-version = "1.0"
|
||||
|
||||
# How long to wait for the client to reset before disconnecting (In milliseconds)
|
||||
reset-timeout = 1000
|
||||
# Message displayed to the player when disconnected from proxy during server switch.
|
||||
disconnect-reset-message = "Please reconnect"
|
||||
# How long the player has to reconnect before canceling the server switch. (In seconds)
|
||||
server-switch-cancellation-time = 120
|
||||
Loading…
Reference in New Issue
Block a user