Compare commits

...
24 Commits
Author SHA1 Message Date
Andrew Steinborn a34b07f2d1 NuVotifier 2.7.0 2020-06-24 22:27:51 -04:00
Andrew Steinborn 1d90a59d5a Add more ArgsToVote tests. 2020-06-23 23:45:30 -04:00
Andrew Steinborn 2734836e58 Add a Sponge server to the testbed and fix one Sponge-related problem 2020-06-23 19:46:26 -04:00
Andrew Steinborn 768daf099f Make Velocity NuVotifier reload command consistent 2020-06-23 19:12:03 -04:00
Andrew Steinborn b6292667b8 Add Velocity testbed and fix some bugs in the Velocity port 2020-06-23 19:05:14 -04:00
Andrew Steinborn 8519535566 Do some test modernization, add some basic ArgsToVote tests 2020-06-23 18:46:58 -04:00
Andrew Steinborn 08e907678f Add additional debug output for pluginMessage forwarding 2020-06-23 18:25:27 -04:00
Andrew Steinborn 27b93ac045 Update dev environment to 1.15 2020-06-16 08:44:50 -04:00
Andrew Steinborn 97f4c91c24 Integrate SpotBugs and fix all errors. 2020-06-06 02:13:29 -04:00
Andrew Steinborn e919c845f7 Attempt to fix vote cache TTL
Instead of trying to expose this data by API, it is now internal to the vote caches.

The only substantial API change was the introduction of a copy constructor to the Vote object.
2020-06-04 00:06:09 -04:00
Andrew Steinborn 1fb35276f7 Support native reloading on BungeeCord, Sponge, and Velocity
/nvreload will remain supported to provide a consistent reload command for documentation, but it is now mostly only relevant for BungeeCord only.
2020-06-03 23:49:02 -04:00
Andrew Steinborn f5f596f21c Document that the Sponge event is fired sync now. 2020-06-03 23:37:41 -04:00
Andrew Steinborn 88523db213 Update issue templates 2020-05-30 23:53:06 -04:00
Andrew Steinborn 3599b0fa1b Restore compatibility with plugins that create Vote objects manually 2020-05-30 18:09:49 -04:00
Andrew Steinborn 950b543e98 Allow using up to 3 worker threads for NuVotifier 2020-05-14 01:38:24 -04:00
Andrew Steinborn e66927dd1a Add epoll transport support 2020-05-14 01:36:40 -04:00
Andrew Steinborn 98d4f69ffb Throttle errors and do general Netty optimizations
Closes #170
2020-05-14 00:58:18 -04:00
Andrew Steinborn ad44c76309 Fix build issues on Windows by just copying the file and not using a symbolic link 2020-05-11 14:24:39 -04:00
Andrew Steinborn 58de66699e Upgrade to Gradle 6.4 and resolve all deprecation issues. 2020-05-11 14:07:25 -04:00
Andrew Steinborn b81052327d Remove almost all use of Guava, closes #187
Guava has proven problematic on a number of occasions - it has caused issues with the Sponge port and there are incompatibilities with certain Forge-Bukkit hybrids. As we desire maximum compatibility, it is better simply to drop Guava altogether. Java 8+ already implements much of what was the bread-and-butter of Guava, or makes rolling our own implementation simpler.

The one place where Guava has been retained is in some configuration-loading code specific to Sponge, which can't be changed to use a non-Guava alternative.
2020-05-11 13:28:43 -04:00
Andrew Steinborn 59a3eff421 Clean up a little Netty code. 2020-05-08 16:50:13 -04:00
Andrew Steinborn 411a529e18 Notify users if they don't have plugins available to listen for votifier events on Bukkit. 2020-05-08 16:39:03 -04:00
Andrew Steinborn 4d6946ab2c Fix a typo 2020-05-08 16:29:20 -04:00
Andrew Steinborn d5ae57b28e Bump Netty to 4.1.49.Final
This could resolve (or greatly ameliorate) #170 but unverified.
2020-04-22 11:47:12 -04:00
100 changed files with 2059 additions and 775 deletions

No files matched your search

+73
View File
@@ -0,0 +1,73 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
<!--
Thank you for submitting an issue for NuVotifier. We appreciate
any and all bug reports.
Before you continue, please ensure you are reporting
a real bug and are not suffering from a configuration issue
or a plugin problem. Once NuVotifier has received and
called your vote listeners, it's not our issue any more.
If you are having difficulty setting up NuVotifier to receive
votes, you are in the wrong place. Please view our wiki
at https://github.com/NuVotifier/NuVotifier/wiki for a
comprehensive set of instructions for configuring and
diagnosing common problems with NuVotifier.
If you are certain that there is a problem with
NuVotifier, please continue filling the form below.
Make sure to follow these instructions:
1. Tell the exact NuVotifier version you're using.
If you just say "latest" your issue will get closed.
2. Please include all relevant logs and configuration
files. Make sure to redact any tokens in the config
file.
3. Don't write anything between these arrows.
We won't see it otherwise.
4. Before you create your issue, delete this block of
text and the code block at the very bottom. -->
### Information
**Platform on which you run NuVotifier**: <!-- Either Bukkit, Sponge, BungeeCord, or Velocity. -->
**Version of NuVotifier**:
```
<!--
Getting this depends on your platform:
Bukkit: Use /version Votifier
Sponge: Use /sponge plugins and find NuVotifier
BungeeCord: No such command exists.
Velocity: Use /velocity plugins from in-game and hover over "nuvotifier"
-->
```
**Relevant log**: <!-- Paste the log on https://gist.github.com/, replace this with link -->
### Details
**Description**
<!-- Replace this with a brief summary of the bug. -->
**Steps to reproduce**
<!-- Replace this with exactly what you did to cause the bug. -->
**Expected behavior**
<!-- Replace this with what you expected to happen. -->
```
Please make sure to delete this line of text and the three ``` characters surrounding it, or your issue will be closed.
```
+1 -3
View File
@@ -1,5 +1,3 @@
dependencies {
compile 'com.google.code.gson:gson:2.8.0'
testCompile "junit:junit:4.11"
testCompile "org.mockito:mockito-core:2.+"
implementation 'com.google.code.gson:gson:2.8.0'
}
@@ -53,6 +53,10 @@ public class Vote {
private byte[] additionalData;
@Deprecated
public Vote() {
}
public Vote(String serviceName, String username, String address, String timeStamp) {
this.serviceName = serviceName;
this.username = username;
@@ -66,7 +70,12 @@ public class Vote {
this.username = username;
this.address = address;
this.timeStamp = timeStamp;
this.additionalData = additionalData;
this.additionalData = additionalData == null ? null : additionalData.clone();
}
public Vote(Vote vote) {
this(vote.getServiceName(), vote.getUsername(), vote.getAddress(), vote.getTimeStamp(),
vote.getAdditionalData() == null ? null : vote.getAdditionalData().clone());
}
private static String getTimestamp(JsonElement object) {
@@ -181,7 +190,7 @@ public class Vote {
* @return Additional data sent with the vote
*/
public byte[] getAdditionalData() {
return additionalData;
return additionalData == null ? null : additionalData.clone();
}
public JsonObject serialize() {
@@ -198,7 +207,7 @@ public class Vote {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!(o instanceof Vote)) return false;
Vote vote = (Vote) o;
@@ -1,7 +1,7 @@
package com.vexsoftware.votifier.model;
import com.google.gson.JsonObject;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
+19 -3
View File
@@ -1,13 +1,18 @@
import org.apache.tools.ant.filters.ReplaceTokens
plugins {
id "com.github.spotbugs" version "4.2.4" apply false
}
allprojects {
group 'com.vexsoftware'
version '3.0.0-SNAPSHOT'
version '2.7.0'
}
subprojects {
apply plugin: 'java'
apply plugin: "com.github.spotbugs"
sourceCompatibility = 1.8
@@ -29,8 +34,9 @@ subprojects {
dependencies {
testImplementation "org.junit.jupiter:junit-jupiter-api:5.4.2"
testRuntime "org.junit.jupiter:junit-jupiter-engine:5.4.2"
testCompile "org.mockito:mockito-core:2.+"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.4.2"
testImplementation "org.junit.jupiter:junit-jupiter-params:5.4.2"
testImplementation "org.mockito:mockito-core:2.+"
}
processResources {
@@ -40,4 +46,14 @@ subprojects {
test {
useJUnitPlatform()
}
tasks.withType(com.github.spotbugs.snom.SpotBugsTask) {
reports {
html {
enabled = true
destination = file("$buildDir/reports/spotbugs/main/spotbugs.html")
stylesheet = 'fancy-hist.xsl'
}
}
}
}
+2 -1
View File
@@ -1,5 +1,6 @@
dependencies {
compileOnly group: "org.spigotmc", name: "spigot-api", version: "1.8.8-R0.1-SNAPSHOT"
compile project(":nuvotifier-common")
implementation project(":nuvotifier-api")
implementation project(":nuvotifier-common")
}
@@ -18,8 +18,6 @@
package com.vexsoftware.votifier;
import com.google.common.io.ByteStreams;
import com.google.common.io.Files;
import com.vexsoftware.votifier.cmd.NVReloadCmd;
import com.vexsoftware.votifier.cmd.TestVoteCmd;
import com.vexsoftware.votifier.forwarding.BukkitPluginMessagingForwardingSink;
@@ -35,25 +33,24 @@ import com.vexsoftware.votifier.platform.JavaUtilLogger;
import com.vexsoftware.votifier.platform.LoggingAdapter;
import com.vexsoftware.votifier.platform.VotifierPlugin;
import com.vexsoftware.votifier.platform.scheduler.VotifierScheduler;
import com.vexsoftware.votifier.util.IOUtil;
import com.vexsoftware.votifier.util.KeyCreator;
import com.vexsoftware.votifier.util.TokenUtil;
import io.netty.channel.Channel;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.security.Key;
import java.security.KeyPair;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.logging.Level;
/**
@@ -64,16 +61,6 @@ import java.util.logging.Level;
*/
public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, VotifierPlugin, ForwardedVoteListener {
/**
* The Votifier instance.
*/
private static NuVotifierBukkit instance;
/**
* The current Votifier version.
*/
private String version;
/**
* The server bootstrap.
*/
@@ -102,7 +89,9 @@ public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, Votifie
scheduler = new BukkitScheduler(this);
pluginLogger = new JavaUtilLogger(getLogger());
if (!getDataFolder().exists()) {
getDataFolder().mkdir();
if (!getDataFolder().mkdir()) {
throw new RuntimeException("Unable to create the plugin data folder " + getDataFolder());
}
}
// Handle configuration.
@@ -127,13 +116,15 @@ public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, Votifie
getLogger().info("Configuring Votifier for the first time...");
// Initialize the configuration file.
config.createNewFile();
if (!config.createNewFile()) {
throw new IOException("Unable to create the config file at " + config);
}
// Load and manually replace variables in the configuration.
String cfgStr = new String(ByteStreams.toByteArray(getResource("bukkitConfig.yml")), StandardCharsets.UTF_8);
String cfgStr = new String(IOUtil.readAllBytes(getResource("bukkitConfig.yml")), StandardCharsets.UTF_8);
String token = TokenUtil.newToken();
cfgStr = cfgStr.replace("%default_token%", token).replace("%ip%", hostAddr);
Files.asCharSink(config, StandardCharsets.UTF_8).write(cfgStr);
Files.copy(new ByteArrayInputStream(cfgStr.getBytes(StandardCharsets.UTF_8)), config.toPath(), StandardCopyOption.REPLACE_EXISTING);
/*
* Remind hosted server admins to be sure they have the right
@@ -167,7 +158,9 @@ public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, Votifie
*/
try {
if (!rsaDirectory.exists()) {
rsaDirectory.mkdir();
if (!rsaDirectory.mkdir()) {
throw new RuntimeException("Unable to create the RSA key folder " + rsaDirectory);
}
keyPair = RSAKeygen.generate(2048);
RSAIO.save(rsaDirectory, keyPair);
} else {
@@ -276,11 +269,6 @@ public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, Votifie
@Override
public void onEnable() {
NuVotifierBukkit.instance = this;
// Set the plugin version.
version = getDescription().getVersion();
getCommand("nvreload").setExecutor(new NVReloadCmd(this));
getCommand("testvote").setExecutor(new TestVoteCmd(this));
@@ -321,15 +309,6 @@ public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, Votifie
getLogger().log(Level.SEVERE, "Votifier did not initialize properly!");
}
/**
* Gets the instance.
*
* @return The instance
*/
public static NuVotifierBukkit getInstance() {
return instance;
}
@Override
public LoggingAdapter getPluginLogger() {
return pluginLogger;
@@ -359,7 +338,7 @@ public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, Votifie
if (debug) {
getLogger().info("Got a " + protocolVersion.humanReadable + " vote record from " + remoteAddress + " -> " + vote);
}
Bukkit.getScheduler().runTask(this, () -> Bukkit.getPluginManager().callEvent(new VotifierEvent(vote)));
Bukkit.getScheduler().runTask(this, () -> fireVotifierEvent(vote));
}
@Override
@@ -381,6 +360,15 @@ public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, Votifie
if (debug) {
getLogger().info("Got a forwarded vote -> " + v);
}
Bukkit.getScheduler().runTask(this, () -> Bukkit.getPluginManager().callEvent(new VotifierEvent(v)));
Bukkit.getScheduler().runTask(this, () -> fireVotifierEvent(v));
}
private void fireVotifierEvent(Vote vote) {
if (VotifierEvent.getHandlerList().getRegisteredListeners().length == 0) {
getLogger().log(Level.SEVERE, "A vote was received, but you don't have any listeners available to listen for it.");
getLogger().log(Level.SEVERE, "See https://github.com/NuVotifier/NuVotifier/wiki/Setup-Guide#vote-listeners for");
getLogger().log(Level.SEVERE, "a list of listeners you can configure.");
}
Bukkit.getPluginManager().callEvent(new VotifierEvent(vote));
}
}
+2 -1
View File
@@ -1,4 +1,5 @@
dependencies {
compileOnly group: "net.md-5", name: "bungeecord-api", version: "1.8-SNAPSHOT"
compile project(":nuvotifier-common")
implementation project(":nuvotifier-api")
implementation project(":nuvotifier-common")
}
@@ -1,14 +1,15 @@
package com.vexsoftware.votifier.bungee;
import com.google.common.base.Preconditions;
import com.vexsoftware.votifier.platform.BackendServer;
import net.md_5.bungee.api.config.ServerInfo;
import java.util.Objects;
public class BungeeBackendServer implements BackendServer {
private final ServerInfo info;
public BungeeBackendServer(ServerInfo info) {
this.info = Preconditions.checkNotNull(info, "info");
this.info = Objects.requireNonNull(info, "info");
}
@Override
@@ -1,8 +1,6 @@
package com.vexsoftware.votifier.bungee;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.ByteStreams;
import com.google.common.io.Files;
import com.google.common.collect.ImmutableList;
import com.vexsoftware.votifier.VoteHandler;
import com.vexsoftware.votifier.bungee.cmd.NVReloadCmd;
import com.vexsoftware.votifier.bungee.cmd.TestVoteCmd;
@@ -23,28 +21,26 @@ import com.vexsoftware.votifier.model.Vote;
import com.vexsoftware.votifier.net.VotifierSession;
import com.vexsoftware.votifier.net.protocol.v1crypto.RSAIO;
import com.vexsoftware.votifier.net.protocol.v1crypto.RSAKeygen;
import com.vexsoftware.votifier.util.IOUtil;
import com.vexsoftware.votifier.util.KeyCreator;
import com.vexsoftware.votifier.util.TokenUtil;
import io.netty.channel.Channel;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.api.plugin.PluginManager;
import net.md_5.bungee.config.Configuration;
import net.md_5.bungee.config.ConfigurationProvider;
import net.md_5.bungee.config.YamlConfiguration;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.security.Key;
import java.security.KeyPair;
import java.util.*;
@@ -86,7 +82,9 @@ public class NuVotifier extends Plugin implements VoteHandler, ProxyVotifierPlug
private void loadAndBind() {
if (!getDataFolder().exists()) {
getDataFolder().mkdir();
if (!getDataFolder().mkdir()) {
throw new RuntimeException("Unable to create the plugin data folder " + getDataFolder());
}
}
// Handle configuration.
@@ -100,12 +98,14 @@ public class NuVotifier extends Plugin implements VoteHandler, ProxyVotifierPlug
getLogger().info("Configuring Votifier for the first time...");
// Initialize the configuration file.
config.createNewFile();
if (!config.createNewFile()) {
throw new IOException("Unable to create the config file at " + config);
}
String cfgStr = new String(ByteStreams.toByteArray(getResourceAsStream("bungeeConfig.yml")), StandardCharsets.UTF_8);
String cfgStr = new String(IOUtil.readAllBytes(getResourceAsStream("bungeeConfig.yml")), StandardCharsets.UTF_8);
String token = TokenUtil.newToken();
cfgStr = cfgStr.replace("%default_token%", token);
Files.asCharSink(config, StandardCharsets.UTF_8).write(cfgStr);
Files.copy(new ByteArrayInputStream(cfgStr.getBytes(StandardCharsets.UTF_8)), config.toPath(), StandardCopyOption.REPLACE_EXISTING);
/*
* Remind hosted server admins to be sure they have the right
@@ -143,7 +143,9 @@ public class NuVotifier extends Plugin implements VoteHandler, ProxyVotifierPlug
*/
try {
if (!rsaDirectory.exists()) {
rsaDirectory.mkdir();
if (!rsaDirectory.mkdir()) {
throw new RuntimeException("Unable to create the RSA key folder " + rsaDirectory);
}
keyPair = RSAKeygen.generate(2048);
RSAIO.save(rsaDirectory, keyPair);
} else {
@@ -163,7 +165,7 @@ public class NuVotifier extends Plugin implements VoteHandler, ProxyVotifierPlug
}
} else {
String token = TokenUtil.newToken();
configuration.set("tokens", ImmutableMap.of("default", token));
configuration.set("tokens", Collections.singletonMap("default", token));
tokens.put("default", KeyCreator.createKeyFrom(token));
try {
ConfigurationProvider.getProvider(YamlConfiguration.class).save(configuration, config);
@@ -222,13 +224,13 @@ public class NuVotifier extends Plugin implements VoteHandler, ProxyVotifierPlug
getLogger().info("Vote cache none selected for caching: votes that cannot be immediately delivered will be lost.");
} else if ("memory".equals(cacheMethod)) {
voteCache = new MemoryVoteCache(
ProxyServer.getInstance().getServers().size(), this,
this,
fwdCfg.getInt("pluginMessaging.memory.cacheTime", -1));
getLogger().info("Using in-memory cache for votes that are not able to be delivered.");
} else if ("file".equals(cacheMethod)) {
try {
voteCache = new FileVoteCache(
ProxyServer.getInstance().getServers().size(), this,
this,
new File(getDataFolder(), fwdCfg.getString("pluginMessaging.file.name")),
fwdCfg.getInt("pluginMessaging.file.cacheTime", -1));
} catch (IOException e) {
@@ -289,7 +291,7 @@ public class NuVotifier extends Plugin implements VoteHandler, ProxyVotifierPlug
}
}
forwardingMethod = new ProxyForwardingVoteSource(this, bootstrap::client, serverList, null);
forwardingMethod = bootstrap.createForwardingSource(serverList, null);
getLogger().info("Forwarding votes from this NuVotifier instance to another NuVotifier server.");
} else {
getLogger().severe("No vote forwarding method '" + fwdMethod + "' known. Defaulting to noop implementation.");
@@ -304,6 +306,7 @@ public class NuVotifier extends Plugin implements VoteHandler, ProxyVotifierPlug
PluginManager pm = ProxyServer.getInstance().getPluginManager();
pm.registerCommand(this, new NVReloadCmd(this));
pm.registerCommand(this, new TestVoteCmd(this));
pm.registerListener(this, new ReloadListener(this));
loadAndBind();
}
@@ -33,6 +33,9 @@ public final class OnlineForwardPluginMessagingForwardingSource extends Abstract
if (p != null && p.getServer() != null &&
serverFilter.isAllowed(p.getServer().getInfo().getName())) {
if (forwardSpecific(new BungeeBackendServer(p.getServer().getInfo()), v)) {
if (plugin.isDebug()) {
plugin.getPluginLogger().info("Successfully forwarded vote " + v + " to server " + p.getServer().getInfo().getName());
}
return;
}
}
@@ -0,0 +1,18 @@
package com.vexsoftware.votifier.bungee;
import net.md_5.bungee.api.event.ProxyReloadEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
public class ReloadListener implements Listener {
private final NuVotifier nuVotifier;
public ReloadListener(NuVotifier nuVotifier) {
this.nuVotifier = nuVotifier;
}
@EventHandler
public void onProxyReload(ProxyReloadEvent event) {
this.nuVotifier.reload();
}
}
+6 -5
View File
@@ -1,7 +1,8 @@
dependencies {
compile project(":nuvotifier-api")
compile group: "io.netty", name: "netty-handler", version: "4.1.32.Final"
compile 'com.google.code.gson:gson:2.8.0'
compile 'com.google.guava:guava:24.1-jre'
testCompile group: "org.json", name: "json", version: "20180130" // retain this for testing reasons
implementation project(":nuvotifier-api")
implementation group: "io.netty", name: "netty-handler", version: "4.1.49.Final"
implementation group: "io.netty", name: "netty-transport-native-epoll", version: "4.1.49.Final", classifier: "linux-x86_64"
implementation 'com.google.code.gson:gson:2.8.0'
testImplementation group: "org.json", name: "json", version: "20180130" // retain this for testing reasons
testImplementation 'com.google.guava:guava:28.1-jre'
}
@@ -1,29 +1,41 @@
package com.vexsoftware.votifier.net;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.vexsoftware.votifier.net.protocol.VoteInboundHandler;
import com.vexsoftware.votifier.net.protocol.VotifierGreetingHandler;
import com.vexsoftware.votifier.net.protocol.VotifierProtocolDifferentiator;
import com.vexsoftware.votifier.platform.VotifierPlugin;
import com.vexsoftware.votifier.support.forwarding.cache.VoteCache;
import com.vexsoftware.votifier.support.forwarding.proxy.ProxyForwardingVoteSource;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.epoll.EpollSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.concurrent.FastThreadLocalThread;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ThreadFactory;
import java.util.function.Consumer;
public class VotifierServerBootstrap {
private static final boolean USE_EPOLL = Epoll.isAvailable();
private final String host;
private final int port;
private final NioEventLoopGroup bossLoopGroup;
private final NioEventLoopGroup eventLoopGroup;
private final EventLoopGroup bossLoopGroup;
private final EventLoopGroup eventLoopGroup;
private final VotifierPlugin plugin;
private final boolean v1Disable;
@@ -34,23 +46,41 @@ public class VotifierServerBootstrap {
this.port = port;
this.plugin = plugin;
this.v1Disable = v1Disable;
this.bossLoopGroup = new NioEventLoopGroup(1, new ThreadFactoryBuilder().setDaemon(true).setNameFormat("Votifier NIO boss").build());
this.eventLoopGroup = new NioEventLoopGroup(1, new ThreadFactoryBuilder().setDaemon(true).setNameFormat("Votifier NIO worker").build());
if (USE_EPOLL) {
this.bossLoopGroup = new EpollEventLoopGroup(1, createThreadFactory("Votifier epoll boss"));
this.eventLoopGroup = new EpollEventLoopGroup(3, createThreadFactory("Votifier epoll worker"));
plugin.getPluginLogger().info("Using epoll transport to accept votes.");
} else {
this.bossLoopGroup = new NioEventLoopGroup(1, createThreadFactory("Votifier NIO boss"));
this.eventLoopGroup = new NioEventLoopGroup(3, createThreadFactory("Votifier NIO worker"));
plugin.getPluginLogger().info("Using NIO transport to accept votes.");
}
}
private static ThreadFactory createThreadFactory(String name) {
return runnable -> {
FastThreadLocalThread thread = new FastThreadLocalThread(runnable, name);
thread.setDaemon(true);
return thread;
};
}
public void start(Consumer<Throwable> error) {
Objects.requireNonNull(error, "error");
VoteInboundHandler voteInboundHandler = new VoteInboundHandler(plugin);
new ServerBootstrap()
.channel(NioServerSocketChannel.class)
.channel(USE_EPOLL ? EpollServerSocketChannel.class : NioServerSocketChannel.class)
.group(bossLoopGroup, eventLoopGroup)
.childHandler(new ChannelInitializer<NioSocketChannel>() {
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(NioSocketChannel channel) {
protected void initChannel(SocketChannel channel) {
channel.attr(VotifierSession.KEY).set(new VotifierSession());
channel.attr(VotifierPlugin.KEY).set(plugin);
channel.pipeline().addLast("greetingHandler", new VotifierGreetingHandler());
channel.pipeline().addLast("greetingHandler", VotifierGreetingHandler.INSTANCE);
channel.pipeline().addLast("protocolDifferentiator", new VotifierProtocolDifferentiator(false, !v1Disable));
channel.pipeline().addLast("voteHandler", new VoteInboundHandler(plugin));
channel.pipeline().addLast("voteHandler", voteInboundHandler);
}
})
.bind(host, port)
@@ -70,12 +100,17 @@ public class VotifierServerBootstrap {
});
}
public Bootstrap client() {
private Bootstrap client() {
return new Bootstrap()
.channel(NioSocketChannel.class)
.channel(USE_EPOLL ? EpollSocketChannel.class : NioSocketChannel.class)
.group(eventLoopGroup);
}
public ProxyForwardingVoteSource createForwardingSource(List<ProxyForwardingVoteSource.BackendServer> backendServers,
VoteCache voteCache) {
return new ProxyForwardingVoteSource(plugin, this::client, backendServers, voteCache);
}
public void shutdown() {
if (serverChannel != null) {
try {
@@ -6,14 +6,22 @@ import com.vexsoftware.votifier.model.Vote;
import com.vexsoftware.votifier.net.VotifierSession;
import com.vexsoftware.votifier.util.GsonInst;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import java.util.concurrent.atomic.AtomicLong;
@ChannelHandler.Sharable
public class VoteInboundHandler extends SimpleChannelInboundHandler<Vote> {
private final VoteHandler handler;
private final AtomicLong lastError;
private final AtomicLong errorsSent;
public VoteInboundHandler(VoteHandler handler) {
this.handler = handler;
this.lastError = new AtomicLong();
this.errorsSent = new AtomicLong();
}
@Override
@@ -36,7 +44,8 @@ public class VoteInboundHandler extends SimpleChannelInboundHandler<Vote> {
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
VotifierSession session = ctx.channel().attr(VotifierSession.KEY).get();
handler.onError(cause, session.hasCompletedVote(), ctx.channel().remoteAddress().toString());
String remoteAddr = ctx.channel().remoteAddress().toString();
boolean hasCompletedVote = session.hasCompletedVote();
if (session.getVersion() == VotifierSession.ProtocolVersion.TWO) {
JsonObject object = new JsonObject();
@@ -47,5 +56,22 @@ public class VoteInboundHandler extends SimpleChannelInboundHandler<Vote> {
} else {
ctx.close();
}
if (!willThrottleErrorLogging()) {
handler.onError(cause, hasCompletedVote, remoteAddr);
}
}
private boolean willThrottleErrorLogging() {
long lastErrorAt = this.lastError.get();
long now = System.currentTimeMillis();
if (lastErrorAt + 2000 >= now) {
return this.errorsSent.incrementAndGet() >= 5;
} else {
this.lastError.set(now);
this.errorsSent.set(0);
return false;
}
}
}
@@ -3,6 +3,7 @@ package com.vexsoftware.votifier.net.protocol;
import com.vexsoftware.votifier.net.VotifierSession;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
@@ -11,7 +12,12 @@ import java.nio.charset.StandardCharsets;
/**
* Handles the Votifier greeting.
*/
@ChannelHandler.Sharable
public class VotifierGreetingHandler extends ChannelInboundHandlerAdapter {
public static final VotifierGreetingHandler INSTANCE = new VotifierGreetingHandler();
private VotifierGreetingHandler() {}
@Override
public void channelActive(ChannelHandlerContext ctx) {
VotifierSession session = ctx.channel().attr(VotifierSession.KEY).get();
@@ -3,7 +3,9 @@ package com.vexsoftware.votifier.net.protocol;
import com.vexsoftware.votifier.platform.VotifierPlugin;
import com.vexsoftware.votifier.model.Vote;
import com.vexsoftware.votifier.net.protocol.v1crypto.RSA;
import com.vexsoftware.votifier.util.QuietException;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.CorruptedFrameException;
@@ -16,33 +18,46 @@ import java.util.List;
*/
public class VotifierProtocol1Decoder extends ByteToMessageDecoder {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf buf, List<Object> list) {
if (buf.readableBytes() < 256) {
protected void decode(ChannelHandlerContext ctx, ByteBuf buf, List<Object> list) throws Exception {
if (!ctx.channel().isActive()) {
buf.skipBytes(buf.readableBytes());
return;
}
byte[] block = new byte[buf.readableBytes()];
buf.getBytes(0, block);
// "Drain" the whole buffer
buf.readerIndex(buf.readableBytes());
if (buf.readableBytes() < 256) {
// The client might have not sent all the data yet, so don't eject the connection.
return;
}
if (buf.readableBytes() > 256) {
// They sent too much data.
throw new QuietException("Could not decrypt data from " + ctx.channel().remoteAddress() + " as it is too long. Attack?");
}
byte[] block = ByteBufUtil.getBytes(buf);
buf.skipBytes(buf.readableBytes());
VotifierPlugin plugin = ctx.channel().attr(VotifierPlugin.KEY).get();
try {
block = RSA.decrypt(block, plugin.getProtocolV1Key().getPrivate());
} catch (Exception e) {
throw new CorruptedFrameException("Could not decrypt data (is your key correct?)", e);
if (plugin.isDebug()) {
throw new CorruptedFrameException("Could not decrypt data from " + ctx.channel().remoteAddress() + ". Make sure the public key on the list is correct.", e);
} else {
throw new QuietException("Could not decrypt data from " + ctx.channel().remoteAddress() + ". Make sure the public key on the list is correct.");
}
}
// Parse the string we received.
String all = new String(block, StandardCharsets.US_ASCII);
String[] split = all.split("\n");
if (split.length < 5) {
throw new CorruptedFrameException("Not enough fields specified in vote.");
throw new QuietException("Not enough fields specified in vote. This is not a NuVotifier issue. Got " + split.length + " fields, but needed 5.");
}
if (!split[0].equals("VOTE")) {
throw new CorruptedFrameException("VOTE opcode not found");
throw new QuietException("The VOTE opcode was not present. This is not a NuVotifier issue, but a bug with the server list.");
}
// Create the vote.
@@ -1,10 +1,10 @@
package com.vexsoftware.votifier.net.protocol;
import com.vexsoftware.votifier.net.VotifierSession;
import com.vexsoftware.votifier.util.QuietException;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.CorruptedFrameException;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
@@ -16,6 +16,8 @@ import java.util.List;
* Attempts to determine if original protocol or protocol v2 is being used.
*/
public class VotifierProtocolDifferentiator extends ByteToMessageDecoder {
private static final QuietException V2_ONLY = new QuietException("This server only accepts well-formed Votifier v2 packets.");
private static final short PROTOCOL_2_MAGIC = 0x733A;
private final boolean testMode;
private final boolean allowv1;
@@ -26,7 +28,7 @@ public class VotifierProtocolDifferentiator extends ByteToMessageDecoder {
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf buf, List<Object> list) {
protected void decode(ChannelHandlerContext ctx, ByteBuf buf, List<Object> list) throws Exception {
// Determine the number of bytes that are available.
int readable = buf.readableBytes();
@@ -35,11 +37,7 @@ public class VotifierProtocolDifferentiator extends ByteToMessageDecoder {
return;
}
short readMagic = buf.readShort();
// Reset reader index again
buf.readerIndex(0);
short readMagic = buf.getShort(0);
VotifierSession session = ctx.channel().attr(VotifierSession.KEY).get();
if (readMagic == PROTOCOL_2_MAGIC) {
@@ -55,7 +53,7 @@ public class VotifierProtocolDifferentiator extends ByteToMessageDecoder {
}
} else {
if (!allowv1) {
throw new CorruptedFrameException("This server only accepts well-formed Votifier v2 packets.");
throw V2_ONLY;
}
// Probably Protocol v1 Vote Message
session.setVersion(VotifierSession.ProtocolVersion.ONE);
@@ -63,7 +63,7 @@ public class RSAIO {
public static byte[] readB64File(File directory, String name) throws IOException {
File f = new File(directory, name);
byte[] contents = Files.readAllBytes(f.toPath());
String strContents = new String(contents);
String strContents = new String(contents, StandardCharsets.US_ASCII);
strContents = strContents.trim();
try {
return Base64.getDecoder().decode(strContents);
@@ -1,7 +1,5 @@
package com.vexsoftware.votifier.platform;
import com.vexsoftware.votifier.platform.LoggingAdapter;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -1,7 +1,6 @@
package com.vexsoftware.votifier.platform.scheduler;
import com.google.common.base.Preconditions;
import java.util.Objects;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@@ -10,7 +9,7 @@ public class ScheduledExecutorServiceVotifierScheduler implements VotifierSchedu
private final ScheduledExecutorService service;
public ScheduledExecutorServiceVotifierScheduler(ScheduledExecutorService service) {
this.service = Preconditions.checkNotNull(service, "service");
this.service = Objects.requireNonNull(service, "service");
}
@Override
@@ -39,7 +39,11 @@ public abstract class AbstractPluginMessagingForwardingSource implements Forward
byte[] rawData = v.serialize().toString().getBytes(StandardCharsets.UTF_8);
for (BackendServer server : plugin.getAllBackendServers()) {
if (!serverFilter.isAllowed(server.getName())) continue;
if (!forwardSpecific(server, rawData)) attemptToAddToCache(v, server.getName());
if (!forwardSpecific(server, rawData)) {
attemptToAddToCache(v, server.getName());
} else if (plugin.isDebug()) {
plugin.getPluginLogger().info("Successfully forwarded vote " + v + " to server " + server.getName());
}
}
}
@@ -11,7 +11,7 @@ public class ServerFilter {
}
public ServerFilter() {
this(Collections.EMPTY_SET, true);
this(Collections.emptySet(), true);
}
private final Collection<String> names;
@@ -1,10 +1,8 @@
package com.vexsoftware.votifier.support.forwarding.cache;
import com.google.common.io.Files;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.vexsoftware.votifier.model.Vote;
import com.vexsoftware.votifier.platform.LoggingAdapter;
import com.vexsoftware.votifier.platform.VotifierPlugin;
import com.vexsoftware.votifier.platform.scheduler.ScheduledVotifierTask;
@@ -12,6 +10,8 @@ import com.vexsoftware.votifier.util.GsonInst;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.util.*;
import java.util.concurrent.TimeUnit;
@@ -21,8 +21,8 @@ public class FileVoteCache extends MemoryVoteCache {
private final File cacheFile;
private final ScheduledVotifierTask saveTask;
public FileVoteCache(int initialMemorySize, final VotifierPlugin plugin, File cacheFile, long voteTTL) throws IOException {
super(initialMemorySize, plugin, voteTTL);
public FileVoteCache(final VotifierPlugin plugin, File cacheFile, long voteTTL) throws IOException {
super(plugin, voteTTL);
this.cacheFile = cacheFile;
this.l = plugin.getPluginLogger();
@@ -48,12 +48,13 @@ public class FileVoteCache extends MemoryVoteCache {
private void load() throws IOException {
// Load the cache from disk
JsonObject object;
try (BufferedReader reader = Files.newReader(cacheFile, StandardCharsets.UTF_8)) {
try (BufferedReader reader = Files.newBufferedReader(cacheFile.toPath(), StandardCharsets.UTF_8)) {
object = GsonInst.gson.fromJson(reader, JsonObject.class);
if (object == null)
if (object == null) {
// When the input is not malformed but instead empty, this returns null. Simply assume it is empty.
object = new JsonObject();
} catch (FileNotFoundException e) {
}
} catch (NoSuchFileException e) {
object = new JsonObject();
}
@@ -76,11 +77,11 @@ public class FileVoteCache extends MemoryVoteCache {
JsonObject servers = object.getAsJsonObject("servers");
for (String player : keySet(players)) {
playerVoteCache.putAll(player, readVotes(players.getAsJsonArray(player)));
playerVoteCache.put(player, readVotes(players.getAsJsonArray(player)));
}
for (String server : keySet(servers)) {
voteCache.putAll(server, readVotes(servers.getAsJsonArray(server)));
voteCache.put(server, readVotes(servers.getAsJsonArray(server)));
}
if (resave) {
@@ -101,11 +102,11 @@ public class FileVoteCache extends MemoryVoteCache {
}
}
private Collection<Vote> readVotes(JsonArray voteArray) {
List<Vote> votes = new ArrayList<>(voteArray.size());
private Collection<VoteWithRecordedTimestamp> readVotes(JsonArray voteArray) {
Collection<VoteWithRecordedTimestamp> votes = new HashSet<>(voteArray.size());
for (int i = 0; i < voteArray.size(); i++) {
JsonObject voteObject = voteArray.get(i).getAsJsonObject();
Vote v = new Vote(voteObject);
VoteWithRecordedTimestamp v = new VoteWithRecordedTimestamp(voteObject);
if (hasTimedOut(v))
l.warn("Purging out of date vote.", v);
else
@@ -115,31 +116,32 @@ public class FileVoteCache extends MemoryVoteCache {
}
public void save() throws IOException {
cacheLock.lock();
JsonObject votesObject = new JsonObject();
votesObject.addProperty("version", 2);
cacheLock.lock();
try {
votesObject.add("players", serializeMap(playerVoteCache.asMap()));
votesObject.add("servers", serializeMap(voteCache.asMap()));
votesObject.addProperty("version", 2);
votesObject.add("players", serializeMap(playerVoteCache));
votesObject.add("servers", serializeMap(voteCache));
} finally {
cacheLock.unlock();
}
try (BufferedWriter writer = Files.newWriter(cacheFile, StandardCharsets.UTF_8)) {
try (BufferedWriter writer = Files.newBufferedWriter(cacheFile.toPath(), StandardCharsets.UTF_8)) {
GsonInst.gson.toJson(votesObject, writer);
}
}
public JsonObject serializeMap(Map<String, Collection<Vote>> map) {
public JsonObject serializeMap(Map<String, Collection<VoteWithRecordedTimestamp>> map) {
JsonObject o = new JsonObject();
Iterator<Map.Entry<String, Collection<Vote>>> entryItr = map.entrySet().iterator();
Iterator<Map.Entry<String, Collection<VoteWithRecordedTimestamp>>> entryItr = map.entrySet().iterator();
while (entryItr.hasNext()) {
Map.Entry<String, Collection<Vote>> entry = entryItr.next();
Map.Entry<String, Collection<VoteWithRecordedTimestamp>> entry = entryItr.next();
JsonArray array = new JsonArray();
Iterator<Vote> voteItr = entry.getValue().iterator();
Iterator<VoteWithRecordedTimestamp> voteItr = entry.getValue().iterator();
while (voteItr.hasNext()) {
Vote vote = voteItr.next();
VoteWithRecordedTimestamp vote = voteItr.next();
// if the vote is no longer valid, notify and remove
if (hasTimedOut(vote)) {
@@ -1,8 +1,6 @@
package com.vexsoftware.votifier.support.forwarding.cache;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Multimap;
import com.google.gson.JsonObject;
import com.vexsoftware.votifier.model.Vote;
import com.vexsoftware.votifier.platform.LoggingAdapter;
import com.vexsoftware.votifier.platform.VotifierPlugin;
@@ -20,16 +18,16 @@ public class MemoryVoteCache implements VoteCache {
private final LoggingAdapter l;
private final long voteTTL;
protected final Multimap<String, Vote> voteCache;
protected final Multimap<String, Vote> playerVoteCache;
protected final Map<String, Collection<VoteWithRecordedTimestamp>> voteCache;
protected final Map<String, Collection<VoteWithRecordedTimestamp>> playerVoteCache;
protected final ReentrantLock cacheLock = new ReentrantLock();
private final ScheduledVotifierTask sweepTask;
public MemoryVoteCache(int initialSize, VotifierPlugin p, long voteTTL) {
voteCache = HashMultimap.create(initialSize, 10); // 10 is a complete guess. I have no idea .-.
playerVoteCache = HashMultimap.create();
public MemoryVoteCache(VotifierPlugin p, long voteTTL) {
voteCache = new HashMap<>();
playerVoteCache = new HashMap<>();
this.voteTTL = voteTTL;
@@ -41,7 +39,7 @@ public class MemoryVoteCache implements VoteCache {
public Collection<String> getCachedServers() {
cacheLock.lock();
try {
return ImmutableList.copyOf(voteCache.keySet());
return Collections.unmodifiableCollection(new ArrayList<>(voteCache.keySet()));
} finally {
cacheLock.unlock();
}
@@ -52,7 +50,7 @@ public class MemoryVoteCache implements VoteCache {
if (server == null) throw new NullPointerException();
cacheLock.lock();
try {
voteCache.put(server, v);
voteCache.computeIfAbsent(server, k -> new HashSet<>()).add(new VoteWithRecordedTimestamp(v));
} finally {
cacheLock.unlock();
}
@@ -63,7 +61,7 @@ public class MemoryVoteCache implements VoteCache {
if (player == null) throw new NullPointerException();
cacheLock.lock();
try {
playerVoteCache.put(player, v);
playerVoteCache.computeIfAbsent(player, k -> new HashSet<>()).add(new VoteWithRecordedTimestamp(v));
} finally {
cacheLock.unlock();
}
@@ -74,7 +72,12 @@ public class MemoryVoteCache implements VoteCache {
if (player == null) throw new NullPointerException();
cacheLock.lock();
try {
return new HashSet<>(playerVoteCache.removeAll(player));
Collection<VoteWithRecordedTimestamp> playerVotes = playerVoteCache.remove(player);
if (playerVotes != null) {
return new HashSet<>(playerVotes);
} else {
return Collections.emptySet();
}
} finally {
cacheLock.unlock();
}
@@ -85,7 +88,12 @@ public class MemoryVoteCache implements VoteCache {
if (server == null) throw new NullPointerException();
cacheLock.lock();
try {
return new HashSet<>(voteCache.removeAll(server));
Collection<VoteWithRecordedTimestamp> serverVotes = voteCache.remove(server);
if (serverVotes != null) {
return new HashSet<>(serverVotes);
} else {
return Collections.emptySet();
}
} finally {
cacheLock.unlock();
}
@@ -101,22 +109,67 @@ public class MemoryVoteCache implements VoteCache {
}
}
private void sweep(Multimap<?, Vote> m) {
Iterator<Vote> vi = m.values().iterator();
while (vi.hasNext()) {
Vote v = vi.next();
if (hasTimedOut(v)) {
l.warn("Purging out of date vote.", v);
vi.remove();
private void sweep(Map<String, Collection<VoteWithRecordedTimestamp>> m) {
for (Map.Entry<String, Collection<VoteWithRecordedTimestamp>> entry : m.entrySet()) {
Iterator<VoteWithRecordedTimestamp> vi = entry.getValue().iterator();
while (vi.hasNext()) {
VoteWithRecordedTimestamp v = vi.next();
if (hasTimedOut(v)) {
l.warn("Purging out of date vote.", v);
vi.remove();
}
}
}
}
protected boolean hasTimedOut(Vote v) {
protected boolean hasTimedOut(VoteWithRecordedTimestamp v) {
if (voteTTL == -1) return false;
// TODO: FIX FOR 3.0 RELEASE
// scale voteTTL to milliseconds
return false;
//return v.getLocalTimestamp() + voteTTL * 24 * 60 * 60 * 1000 < System.currentTimeMillis();
long daysAsMillis = TimeUnit.DAYS.toMillis(voteTTL);
return v.recorded + daysAsMillis < System.currentTimeMillis();
}
static class VoteWithRecordedTimestamp extends Vote {
private final long recorded;
VoteWithRecordedTimestamp(Vote vote) {
super(vote);
this.recorded = System.currentTimeMillis();
}
VoteWithRecordedTimestamp(JsonObject object) {
super(object);
if (object.has("recorded")) {
this.recorded = object.get("recorded").getAsLong();
} else {
// Assign the current time, in the hope that the stale votes will eventually get purged.
this.recorded = System.currentTimeMillis();
}
}
@Override
public JsonObject serialize() {
JsonObject object = super.serialize();
object.addProperty("recorded", this.recorded);
return object;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
VoteWithRecordedTimestamp that = (VoteWithRecordedTimestamp) o;
return recorded == that.recorded;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (int) (recorded ^ (recorded >>> 32));
return result;
}
}
}
@@ -26,19 +26,25 @@ public class ArgsToVote {
if (m.matches()) {
String key = m.group(1).toLowerCase();
String v = m.group(2);
if (key.equals("servicename")) {
serviceName = v;
} else if (key.equals("username")) {
if (v.length() > 16)
throw new IllegalArgumentException("Illegal username - must be less than 16 characters long.");
username = v;
} else if (key.equals("address")) {
address = v;
} else if (key.equals("timestamp")) {
timestamp = v;
} else {
if (additionalArgs != null)
additionalArgs.put(key, v);
switch (key) {
case "servicename":
serviceName = v;
break;
case "username":
if (v.length() > 16)
throw new IllegalArgumentException("Illegal username - must be less than 16 characters long.");
username = v;
break;
case "address":
address = v;
break;
case "timestamp":
timestamp = v;
break;
default:
if (additionalArgs != null)
additionalArgs.put(key, v);
break;
}
} else {
@@ -0,0 +1,17 @@
package com.vexsoftware.votifier.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class IOUtil {
public static byte[] readAllBytes(InputStream from) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream(8192);
byte[] buf = new byte[8192];
int read;
while ((read = from.read(buf)) != -1) {
out.write(buf, 0, read);
}
return out.toByteArray();
}
}
@@ -0,0 +1,15 @@
package com.vexsoftware.votifier.util;
public class QuietException extends Exception {
public QuietException() {
}
public QuietException(String s) {
super(s);
}
@Override
public synchronized Throwable fillInStackTrace() {
return null;
}
}
@@ -85,6 +85,11 @@ public class TestVotifierPlugin implements VotifierPlugin {
return null;
}
@Override
public boolean isDebug() {
return true;
}
public void specificKeysOnly() {
keyMap.clear();
keyMap.put("Test", KeyCreator.createKeyFrom("test"));
@@ -26,6 +26,6 @@ public class VoteUtil {
builder.append(s).append('\n'); // naive join needed!
}
return RSA.encrypt(builder.toString().getBytes(StandardCharsets.UTF_8), key);
return RSA.encrypt(builder.toString().getBytes(StandardCharsets.US_ASCII), key);
}
}
@@ -4,10 +4,12 @@ import com.vexsoftware.votifier.platform.VotifierPlugin;
import com.vexsoftware.votifier.model.Vote;
import com.vexsoftware.votifier.net.VotifierSession;
import com.vexsoftware.votifier.net.protocol.v1crypto.RSA;
import com.vexsoftware.votifier.util.QuietException;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.CorruptedFrameException;
import io.netty.handler.codec.DecoderException;
import org.junit.jupiter.api.Test;
import java.nio.charset.StandardCharsets;
@@ -50,7 +52,7 @@ public class VotifierProtocol1DecoderTest {
byte[] encrypted = RSA.encrypt(bad.getBytes(StandardCharsets.UTF_8), TestVotifierPlugin.getI().getProtocolV1Key().getPublic());
ByteBuf encryptedByteBuf = Unpooled.wrappedBuffer(encrypted);
assertThrows(CorruptedFrameException.class, () -> channel.writeInbound(encryptedByteBuf));
assertThrows(DecoderException.class, () -> channel.writeInbound(encryptedByteBuf));
channel.close();
}
@@ -77,7 +79,7 @@ public class VotifierProtocol1DecoderTest {
byte[] encrypted = VoteUtil.encodePOJOv1(new Vote("Test", "test", "test", "test"), badPublicKey);
ByteBuf encryptedByteBuf = Unpooled.wrappedBuffer(encrypted);
assertThrows(CorruptedFrameException.class, ()->channel.writeInbound(encryptedByteBuf));
assertThrows(DecoderException.class, ()->channel.writeInbound(encryptedByteBuf));
channel.close();
}
}
@@ -19,7 +19,6 @@ import java.util.Base64;
import static org.junit.jupiter.api.Assertions.*;
public class VotifierProtocol2DecoderTest {
private static final VotifierSession SESSION = new VotifierSession();
@@ -2,6 +2,7 @@ package com.vexsoftware.votifier.net.protocol;
import com.vexsoftware.votifier.model.Vote;
import com.vexsoftware.votifier.net.VotifierSession;
import com.vexsoftware.votifier.util.QuietException;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.embedded.EmbeddedChannel;
@@ -56,7 +57,7 @@ public class VotifierProtocolDifferentiatorTest {
for (int i = 0; i < 256; i++) {
test.writeByte(0);
}
assertThrows(CorruptedFrameException.class, () -> channel.writeInbound(test));
assertThrows(DecoderException.class, () -> channel.writeInbound(test));
channel.close();
}
@@ -1,9 +1,11 @@
package com.vexsoftware.votifier.support.forwarding;
import com.google.common.collect.Lists;
import com.vexsoftware.votifier.model.Vote;
import org.junit.jupiter.api.Test;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -12,13 +14,13 @@ public class PMForwardingSinkTest {
@Test
public void testSuccessfulMultiDecode() throws Exception {
List<Vote> receivedVotes = Lists.newArrayList();
List<Vote> receivedVotes = new ArrayList<>();
ForwardedVoteListener vl = receivedVotes::add;
List<Vote> sentVotes = Lists.newArrayList(
List<Vote> sentVotes = new ArrayList<>(Arrays.asList(
new Vote("serviceA", "usernameA", "1.1.1.1", "1546300800"),
new Vote("serviceB", "usernameBBBBBBB", "1.2.23.4", "1514764800")
);
));
StringBuilder message = new StringBuilder();
@@ -26,7 +28,7 @@ public class PMForwardingSinkTest {
message.append(v.serialize());
}
byte[] messageBytes = message.toString().getBytes();
byte[] messageBytes = message.toString().getBytes(StandardCharsets.UTF_8);
System.out.println(message.toString());
AbstractPluginMessagingForwardingSink sink = new AbstractPluginMessagingForwardingSink(vl) {
@@ -0,0 +1,108 @@
package com.vexsoftware.votifier.util;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.vexsoftware.votifier.model.Vote;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import java.lang.reflect.Method;
import java.util.Locale;
import java.util.Set;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.*;
public class ArgsToVoteTest {
@Test
void handlesInvalidRequest() {
assertThrows(IllegalArgumentException.class, () -> {
ArgsToVote.parse(new String[0]);
});
}
@Test
void handlesSingleUsername() {
Vote vote = ArgsToVote.parse(new String[] { "dummy_user" });
assertEquals("dummy_user", vote.getUsername());
}
@Test
void handlesSingleUsernameTooLong() {
assertThrows(IllegalArgumentException.class, () -> {
ArgsToVote.parse(new String[] { "AVeryVeryVeryLongUsername" });
});
}
@ParameterizedTest
@ValueSource(strings = { "servicename", "address", "timestamp" })
void handlesAdditionalKeywordArguments(String key) throws Exception {
Vote vote = ArgsToVote.parse(new String[] { "username=abc123", key + "=dummy" });
// Find the getter on the Vote object
for (Method method : Vote.class.getDeclaredMethods()) {
if (method.getName().toLowerCase(Locale.ENGLISH).equals("get" + key)) {
assertEquals("dummy", method.invoke(vote));
return;
}
}
fail("Unable to find appropriate getter - this is a bug");
}
@Test
void handlesUsernameKeywordArgument() {
Vote vote = ArgsToVote.parse(new String[] { "username=dummy_user" });
assertEquals("dummy_user", vote.getUsername());
}
@ParameterizedTest
@ValueSource(strings = { "servicename", "address", "timestamp" })
void handlesMixedUsernameAndKeywordArgument(String key) throws Exception {
Vote vote = ArgsToVote.parse(new String[] { "abc123", key + "=dummy" });
assertEquals("abc123", vote.getUsername());
// Find the getter on the Vote object
for (Method method : Vote.class.getDeclaredMethods()) {
if (method.getName().toLowerCase(Locale.ENGLISH).equals("get" + key)) {
assertEquals("dummy", method.invoke(vote));
return;
}
}
fail("Unable to find appropriate getter - this is a bug");
}
@ParameterizedTest
@MethodSource("powerSetArgs")
void handlesMixedKeywordArguments(Set<String> keys) throws Exception {
String[] args = new String[keys.size() + 1];
args[0] = "abc123";
for (int i = 0; i < keys.size(); i++) {
args[i + 1] = ImmutableList.copyOf(keys).get(i) + "=dummy";
}
Vote vote = ArgsToVote.parse(args);
assertEquals("abc123", vote.getUsername());
// Find the getters on the Vote object
outer: for (String key : keys) {
for (Method method : Vote.class.getDeclaredMethods()) {
if (method.getName().toLowerCase(Locale.ENGLISH).equals("get" + key)) {
assertEquals("dummy", method.invoke(vote));
continue outer;
}
}
fail("Unable to find appropriate getter - this is a bug");
}
}
private static Stream<Set<String>> powerSetArgs() {
return Sets.powerSet(ImmutableSet.of("servicename", "address", "timestamp")).stream();
}
}
+13 -6
View File
@@ -1,22 +1,29 @@
.PHONY: clean, all, run
.PHONY: clean all run
all : resources/paper.jar resources/proxy.jar
all : resources/paper.jar resources/waterfall.jar resources/velocity.jar resources/sponge.jar
resources :
mkdir resources
resources/paper.jar : resources
wget -O resources/paper.jar https://papermc.io/ci/job/Paper-1.13/lastSuccessfulBuild/artifact/paperclip.jar
wget -O resources/paper.jar https://papermc.io/api/v1/paper/1.15.2/353/download
resources/proxy.jar : resources
wget -O resources/proxy.jar https://papermc.io/ci/job/Waterfall/lastSuccessfulBuild/artifact/Waterfall-Proxy/bootstrap/target/Waterfall.jar
resources/waterfall.jar : resources
wget -O resources/waterfall.jar https://papermc.io/ci/job/Waterfall/lastSuccessfulBuild/artifact/Waterfall-Proxy/bootstrap/target/Waterfall.jar
resources/velocity.jar : resources
wget -O resources/velocity.jar https://ci.velocitypowered.com/job/velocity-1.1.0/lastSuccessfulBuild/artifact/proxy/build/libs/velocity-proxy-1.1.0-SNAPSHOT-all.jar
resources/sponge.jar : resources
wget -O resources/sponge.jar https://repo.spongepowered.org/maven/org/spongepowered/spongevanilla/1.12.2-7.2.2/spongevanilla-1.12.2-7.2.2.jar
clean :
rm -r resources/
run :
tmux new-session './proxy/run.sh' \; \
tmux new-session './p1/run.sh' \; \
split-window -h './p2/run.sh' \; \
split-window -h './s1/run.sh' \; \
split-window -h './s2/run.sh' \; \
select-layout even-horizontal
+10 -7
View File
@@ -1,7 +1,7 @@
## Using this testbed
This testbed runs one Bungeecord as well as two Paper servers behind it, labeled
s1 and s2. Ports for where everything is bound is listed below.
This testbed runs two proxies, labeled p1 and p2, as well as two servers behind it,
labeled s1 and s2. Ports for where everything is bound is listed below.
First, download required sources using the following command:
@@ -19,8 +19,11 @@ FYI, this only works in Linux afaik because thats what I do my development on.
# Ports
| Server | MC Port | Votifier Port |
| ------ | ------- | ------------- |
| proxy | 25577 | 8192 |
| s1 | 25565 | 8193 |
| s2 | 25566 | 8194 |
| Server | Server Software | MC Port | Votifier Port |
| ------ | ---------------------- | ------- | ------------- |
| p1 | Waterfall/BungeeCord | 25577 | 8192 |
| p2 | Velocity | 25578 | 8193 |
| s1 | Paper (1.15.2) | 25565 | 8194 |
| s2 | SpongeVanilla (1.12.2) | 25566 | 8195 |
For compatibility with 1.15.2, s2 includes ViaVersion.
File renamed without changes.
+18 -14
View File
@@ -1,7 +1,4 @@
forge_support: true
timeout: 30000
online_mode: true
log_commands: false
server_connect_timeout: 5000
listeners:
- query_port: 25577
motd: '&4its a bungee cord surbur'
@@ -17,16 +14,8 @@ listeners:
max_players: 1
tab_size: 60
force_default_server: false
connection_throttle: 1
groups:
md_5:
- admin
log_pings: true
ip_forward: true
prevent_proxy_connections: true
remote_ping_cache: -1
network_compression_threshold: 256
disabled_commands: []
stats: bf8a54ea-2917-4b9e-b463-2c05bd7f1ac6
permissions:
default:
- bungeecord.command.server
@@ -36,6 +25,22 @@ permissions:
- bungeecord.command.end
- bungeecord.command.ip
- bungeecord.command.reload
log_pings: true
connection_throttle_limit: 3
prevent_proxy_connections: true
timeout: 30000
player_limit: -1
ip_forward: true
groups:
md_5:
- admin
remote_ping_timeout: 5000
connection_throttle: 1
log_commands: false
stats: bf8a54ea-2917-4b9e-b463-2c05bd7f1ac6
online_mode: true
forge_support: true
disabled_commands: []
servers:
s1:
motd: SERVER 1
@@ -45,4 +50,3 @@ servers:
motd: SERVER 2
address: localhost:25566
restricted: false
player_limit: -1
File renamed without changes.
+2
View File
@@ -0,0 +1,2 @@
rsa/
cached-votes.json
@@ -7,12 +7,12 @@ port: 8192
# Whether or not to print debug messages. In a production system, this should be set to false.
# This is useful when initially setting up NuVotifier to ensure votes are being delivered.
debug: false
debug: true
# All tokens, labeled by the serviceName of each server list.
tokens:
# Default token for all server lists, if another isn't supplied.
default: jqpli3gnd8l67qsg2d81vje09h
default: proxy1token
# Setting this option to true will disable handling of Protocol v1 packets. While the old protocol is not secure, this
# option is currently not recommended as most voting sites only support the old protocol at present.
@@ -24,7 +24,7 @@ forwarding:
# - none - Does not set up a forwarding method.
# - pluginMessaging - Sets up plugin messaging.
# - proxy - Proxies votes to other NuVotifier servers from this server.
method: none
method: pluginMessaging
pluginMessaging:
channel: nuvotifier:votes
@@ -46,11 +46,11 @@ forwarding:
# most set ups.
cache: file
# Only sends the vote to the server in which the player is currently joined.
onlySendToJoinedServer: false
onlySendToJoinedServer: true
#Sets which server to send the vote in the event the player is not online when the vote is cast
#If you do not want the vote forwarded to a fallback, set this value to empty ('')
#ONLY USED IF onlySendToJoinedServer is true!!
joinedServerFallback: 'Hub'
joinedServerFallback: 's1'
# Defines how quickly to dump votes over a player's connection when offloading a cache in votes per second
dumpRate: 5
# Options for file caching.
File renamed without changes.
+1
View File
@@ -0,0 +1 @@
../resources/waterfall.jar
View File
File renamed without changes.
@@ -1,8 +1,9 @@
use_netty_dns_resolver: true
disable_modern_tab_limiter: true
log_initial_handler_connections: true
allow_empty_packets: false
throttling:
tab_complete: 1000
game_version: ''
disable_modern_tab_limiter: true
use_netty_dns_resolver: true
disable_entity_metadata_rewrite: false
log_initial_handler_connections: true
log_server_list_ping: false
allow_empty_packets: false
+1
View File
@@ -0,0 +1 @@
logs/
File renamed without changes.
+2
View File
@@ -0,0 +1,2 @@
rsa/
cached-votes.json
+79
View File
@@ -0,0 +1,79 @@
# The IP to listen to. Use 0.0.0.0 if you wish to listen to all interfaces on your server. (All IP addresses)
# This defaults to the IP you have configured your server to listen on, or 0.0.0.0 if you have not configured this.
host = "0.0.0.0"
# Port to listen for new votes on
port = 8193
# Setting this option to true will disable handling of Protocol v1 packets. While the old protocol is not secure, this
# option is currently not recommended as most voting sites only support the old protocol at present. However, if you are
# using NuVotifier's proxy forwarding mechanism, enabling this option will increase your server's security.
disable-v1-protocol = false
# All tokens, labeled by the serviceName of each server list.
[tokens]
# Default token for all server lists, if another isn't supplied.
default = "proxy2token"
# Configuration section for all vote forwarding to NuVotifier
[forwarding]
# Sets whether to set up a remote method for fowarding. Supported methods:
# - none - Does not set up a forwarding method.
# - pluginMessaging - Sets up plugin messaging.
# - proxy - Proxies votes to other NuVotifier servers from this server.
method = "pluginMessaging"
[forwarding.pluginMessaging]
channel = "nuvotifier:votes"
# Only send votes to certain servers. If a server is present on excludedServers, then votes will NOT be forwarded
# to them. If excludedServers is not present, votes will be sent to all servers.
# If onlySendToJoinedServer is true and a player is on one of these servers, NuVotifier will process the vote as if the
# player was not on the network at all.
# excludedServers = ["server1", "server2"]
# If uncommented, turns excludedServers into an includedServers, where only servers on the list will be used.
# whitelist = true
# Sets which cache to use if there are no players on the server that the vote is being sent to. Supported caches:
# - none - Votes will simply be lost when no players are present on the server.
# - memory - Votes will be cached in memory when no players are present. When Bungee is restarted, the votes will be lost.
# - file - Votes will be saved to a local file every 3 minutes and on shutdown and reloaded when Bungee is restarted. This is suitable for
# most set ups.
cache = "file"
# Only sends the vote to the server in which the player is currently joined.
onlySendToJoinedServer = true
# Sets which server to send the vote in the event the player is not online when the vote is cast
# If you do not want the vote forwarded to a fallback, set this value to empty ('')
# ONLY USED IF onlySendToJoinedServer is true!!
joinedServerFallback = "s1"
# Defines how quickly to dump votes over a player's connection while offloading a cache in votes per second
dumpRate = 5
[forwarding.file-cache]
# Options for file caching.
name = "cached-votes.json"
# days before a vote is considered 'dead' - removed from cache with a console warning. -1 signifies no cache.
cacheTime = 10
[forwarding.memory-cache]
# Options for file caching.
name = "cached-votes.json"
# days before a vote is considered 'dead' - removed from cache with a console warning. -1 signifies no cache. Votes are
# also removed on restart
cacheTime = 10
[forwarding.proxy]
# Specify servers to proxy votes for.
[forwarding.proxy.Hub]
address = "127.0.0.1"
port = 8193
token = "MyKeyHere"
[forwarding.proxy.Hub2]
address = "127.0.0.1"
port = 8194
token = "MyKeyHere"
+1
View File
@@ -0,0 +1 @@
../resources/velocity.jar
Executable
+6
View File
@@ -0,0 +1,6 @@
#!/bin/sh
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
cd $DIR
java -jar proxy.jar
+135
View File
@@ -0,0 +1,135 @@
# Config version. Do not change this
config-version = "1.0"
# What port should the proxy be bound to? By default, we'll bind to all addresses on port 25577.
bind = "0.0.0.0:25578"
# What should be the MOTD? This gets displayed when the player adds your server to
# their server list. Legacy color codes and JSON are accepted.
motd = "&3doot doot imma velocity serbur"
# What should we display for the maximum number of players? (Velocity does not support a cap
# on the number of players online.)
show-max-players = 500
# Should we authenticate players with Mojang? By default, this is on.
online-mode = true
# If client's ISP/AS sent from this proxy is different from the one from Mojang's
# authentication server, the player is kicked. This disallows some VPN and proxy
# connections but is a weak form of protection.
prevent-client-proxy-connections = false
# Should we forward IP addresses and other data to backend servers?
# Available options:
# - "none": No forwarding will be done. All players will appear to be connecting
# from the proxy and will have offline-mode UUIDs.
# - "legacy": Forward player IPs and UUIDs in a BungeeCord-compatible format. Use this
# if you run servers using Minecraft 1.12 or lower.
# - "bungeeguard": Forward player IPs and UUIDs in a format supported by the BungeeGuard
# plugin. Use this if you run servers using Minecraft 1.12 or lower, and are
# unable to implement network level firewalling (on a shared host).
# - "modern": Forward player IPs and UUIDs as part of the login process using
# Velocity's native forwarding. Only applicable for Minecraft 1.13 or higher.
player-info-forwarding-mode = "LEGACY"
# If you are using modern or BungeeGuard IP forwarding, configure an unique secret here.
forwarding-secret = "not at all secret lolololol"
# Announce whether or not your server supports Forge. If you run a modded server, we
# suggest turning this on.
#
# If your network runs one modpack consistently, consider using ping-passthrough = "mods"
# instead for a nicer display in the server list.
announce-forge = false
# If enabled (default is false) and the proxy is in online mode, Velocity will kick
# any existing player who is online if a duplicate connection attempt is made.
kick-existing-players = false
# Should Velocity pass server list ping requests to a backend server?
# Available options:
# - "disabled": No pass-through will be done. The velocity.toml and server-icon.png
# will determine the initial server list ping response.
# - "mods": Passes only the mod list from your backend server into the response.
# The first server in your try list (or forced host) with a mod list will be
# used. If no backend servers can be contacted, Velocity won't display any
# mod information.
# - "description": Uses the description and mod list from the backend server. The first
# server in the try (or forced host) list that responds is used for the
# description and mod list.
# - "all": Uses the backend server's response as the proxy response. The Velocity
# configuration is used if no servers could be contacted.
ping-passthrough = "DISABLED"
[servers]
# Configure your servers here. Each key represents the server's name, and the value
# represents the IP address of the server to connect to.
s1 = "127.0.0.1:25565"
s2 = "127.0.0.1:25566"
# In what order we should try servers when a player logs in or is kicked from aserver.
try = [
"s1"
]
[forced-hosts]
# Configure your forced hosts here.
[advanced]
# How large a Minecraft packet has to be before we compress it. Setting this to zero will
# compress all packets, and setting it to -1 will disable compression entirely.
compression-threshold = 256
# How much compression should be done (from 0-9). The default is -1, which uses the
# default level of 6.
compression-level = -1
# How fast (in milliseconds) are clients allowed to connect after the last connection? By
# default, this is three seconds. Disable this by setting this to 0.
login-ratelimit = 3000
# Specify a custom timeout for connection timeouts here. The default is five seconds.
connection-timeout = 5000
# Specify a read timeout for connections here. The default is 30 seconds.
read-timeout = 30000
# Enables compatibility with HAProxy.
proxy-protocol = false
# Enables TCP fast open support on the proxy. Requires the proxy to run on Linux.
tcp-fast-open = false
# Enables BungeeCord plugin messaging channel support on Velocity.
bungee-plugin-message-channel = true
# Shows ping requests to the proxy from clients.
show-ping-requests = false
[query]
# Whether to enable responding to GameSpy 4 query responses or not.
enabled = false
# If query is enabled, on what port should the query protocol listen on?
port = 25577
# This is the map name that is reported to the query services.
map = "Velocity"
# Whether plugins should be shown in query response by default or not
show-plugins = false
[metrics]
# Whether metrics will be reported to bStats (https://bstats.org).
# bStats collects some basic information, like how many people use Velocity and their
# player count. We recommend keeping bStats enabled, but if you're not comfortable with
# this, you can turn this setting off. There is no performance penalty associated with
# having metrics enabled, and data sent to bStats can't identify your server.
enabled = true
# A unique, anonymous ID to identify this proxy with.
id = "729fe923-b383-4e5b-b456-5adf554bfe69"
log-failure = false
-1
View File
@@ -1 +0,0 @@
rsa/
-1
View File
@@ -1 +0,0 @@
../resources/proxy.jar
+1 -1
View File
@@ -7,4 +7,4 @@ well as overriding the eula check. If you don't agree to the Mojang EULA
thingie, then uh, smash your computer or something because you totally agreed
to it so just fyi
WARNING
java -DIReallyKnowWhatIAmDoingISwear -Dcom.mojang.eula.agree=true -jar paper.jar
java -DIReallyKnowWhatIAmDoingISwear -Dcom.mojang.eula.agree=true -jar paper.jar nogui
+3
View File
@@ -13,6 +13,7 @@
settings:
minimum-api: none
allow-end: true
warn-on-overload: true
permissions-file: permissions.yml
@@ -31,6 +32,8 @@ chunk-gc:
period-in-ticks: 600
load-threshold: 0
ticks-per:
water-spawns: 1
ambient-spawns: 1
animal-spawns: 400
monster-spawns: 1
autosave: 6000
+41 -6
View File
@@ -10,9 +10,12 @@
# Website: https://papermc.io/
# Docs: https://paper.readthedocs.org/
allow-perm-block-break-exploits: false
verbose: false
config-version: 16
config-version: 20
settings:
console-has-all-permissions: false
chunk-tasks-per-tick: 1000
load-permissions-yml-before-plugins: true
bungee-online-mode: true
use-versioned-world: false
@@ -41,10 +44,10 @@ settings:
max-player-auto-save-per-tick: -1
async-chunks:
enable: true
generation: true
thread-per-world-generation: true
load-threads: -1
threads: -1
use-alternative-luck-formula: false
unsupported-settings:
allow-tnt-duplication: false
messages:
no-permission: '&cI''m sorry, but you do not have permission to perform this command.
Please contact the server administrators if you believe that this is in error.'
@@ -54,6 +57,7 @@ messages:
flying-vehicle: Flying is not enabled on this server
connection-throttle: Connection throttled! Please wait before reconnecting.
timings:
server-name: Unknown Server
enabled: true
verbose: true
server-name-privacy: false
@@ -64,8 +68,23 @@ timings:
history-length: 3600
world-settings:
default:
per-player-mob-spawns: false
phantoms-do-not-spawn-on-creative-players: true
phantoms-only-attack-insomniacs: true
light-queue-size: 20
count-all-mobs-for-spawning: false
seed-based-feature-search: true
nether-ceiling-void-damage-height: 0
fix-zero-tick-instant-grow-farms: true
portal-create-radius: 16
iron-golems-can-spawn-in-air: false
entities-target-with-follow-range: false
zombie-villager-infection-chance: -1.0
portal-search-radius: 128
game-mechanics:
disable-pillager-patrols: false
nerf-pigmen-from-nether-portals: false
disable-relative-projectile-velocity: false
villages-load-chunks: false
scan-for-legacy-ender-dragon: true
disable-chest-cat-detection: false
@@ -74,6 +93,14 @@ world-settings:
disable-sprint-interruption-on-attack: false
shield-blocking-delay: 5
disable-unloaded-chunk-enderpearl-exploit: true
pillager-patrols:
spawn-chance: 0.2
spawn-delay:
per-player: false
ticks: 12000
start:
per-player: false
day: 5
queue-light-updates: false
optimize-explosions: false
disable-teleportation-suffocation-check: false
@@ -141,13 +168,12 @@ world-settings:
- chest
- diamond_ore
- redstone_ore
- lit_redstone_ore
- clay
- emerald_ore
- ender_chest
replacement-blocks:
- stone
- planks
- oak_planks
skip-entity-ticking-in-chunks-scheduled-for-unload: true
armor-stands-do-collision-entity-lookups: true
keep-spawn-loaded-range: 8
@@ -176,3 +202,12 @@ world-settings:
mob-spawner-tick-rate: 1
squid-spawn-height:
maximum: 0.0
alt-item-despawn-rate:
enabled: false
items:
COBBLESTONE: 300
viewdistances:
no-tick-view-distance: -1
generator-settings:
flat-bedrock: false
baby-zombie-movement-modifier: 0.5
+1 -1
View File
@@ -3,7 +3,7 @@
host: 0.0.0.0
# Port to listen for new votes on
port: 8193
port: 8194
# Whether or not to print debug messages. In a production system, this should be set to false.
# This is useful when initially setting up NuVotifier to ensure votes are being delivered.
+1
View File
@@ -0,0 +1 @@
../../../universal/build/libs/nuvotifier.jar
+13 -5
View File
@@ -1,26 +1,33 @@
#Minecraft server properties
#Fri Dec 21 15:15:00 EST 2018
#Tue Jun 23 23:02:31 EDT 2020
spawn-protection=16
max-tick-time=60000
query.port=25565
generator-settings=
force-gamemode=false
allow-nether=true
enforce-whitelist=false
gamemode=0
gamemode=survival
broadcast-console-to-ops=true
enable-query=false
player-idle-timeout=0
difficulty=1
difficulty=easy
spawn-monsters=true
broadcast-rcon-to-ops=true
op-permission-level=4
pvp=true
snooper-enabled=true
level-type=DEFAULT
level-type=default
hardcore=false
enable-command-block=false
max-players=20
network-compression-threshold=256
resource-pack-sha1=
max-world-size=29999984
function-permission-level=2
rcon.port=25575
server-port=25565
debug=false
server-ip=
spawn-npcs=true
allow-flight=false
@@ -29,11 +36,12 @@ view-distance=10
resource-pack=
spawn-animals=true
white-list=false
rcon.password=
generate-structures=true
online-mode=false
max-build-height=256
level-seed=
prevent-proxy-connections=false
use-native-transport=true
motd=A Minecraft Server
enable-rcon=false
motd=A Minecraft Server
+32 -2
View File
@@ -10,8 +10,9 @@
# IRC: #spigot @ irc.spi.gt ( http://www.spigotmc.org/pages/irc/ )
# Forums: http://www.spigotmc.org/
config-version: 11
config-version: 12
settings:
log-villager-deaths: true
debug: false
save-user-cache-on-stop-only: false
sample-count: 12
@@ -60,6 +61,11 @@ advancements:
- minecraft:story/disabled
world-settings:
default:
seed-outpost: 165745296
seed-endcity: 10387313
view-distance: default
trident-despawn-rate: 1200
end-portal-sound-radius: 0
verbose: true
merge-radius:
exp: 3.0
@@ -91,6 +97,12 @@ world-settings:
min: 45.0
mob-spawn-range: 8
growth:
beetroot-modifier: 100
carrot-modifier: 100
potato-modifier: 100
bamboo-modifier: 100
sweetberry-modifier: 100
kelp-modifier: 100
cactus-modifier: 100
cane-modifier: 100
melon-modifier: 100
@@ -102,11 +114,30 @@ world-settings:
vine-modifier: 100
cocoa-modifier: 100
entity-activation-range:
raiders: 48
villagers: 32
flying-monsters: 32
villagers-work-immunity-after: 100
villagers-work-immunity-for: 20
villagers-active-for-panic: true
animals: 32
monsters: 32
misc: 16
water: 16
tick-inactive-villagers: true
wake-up-inactive:
animals-max-per-tick: 4
animals-every: 1200
animals-for: 100
monsters-max-per-tick: 8
monsters-every: 400
monsters-for: 100
villagers-max-per-tick: 4
villagers-every: 600
villagers-for: 100
flying-monsters-max-per-tick: 8
flying-monsters-every: 200
flying-monsters-for: 100
entity-tracking-range:
players: 48
animals: 48
@@ -120,7 +151,6 @@ world-settings:
wither-spawn-sound-radius: 0
enable-zombie-pigmen-portal-spawns: true
item-despawn-rate: 6000
view-distance: 10
arrow-despawn-rate: 1200
hanging-tick-frequency: 100
zombie-aggressive-towards-villager: true
+2 -4
View File
@@ -3,17 +3,15 @@ banned-players.json
cache/
eula.txt
logs/
permissions.yml
ops.json
usercache.json
usernamecache.json
version_history.json
whitelist.json
world/
world_nether/
world_the_end/
.mixin.out
-37
View File
@@ -1,37 +0,0 @@
# This is the main configuration file for Bukkit.
# As you can see, there's actually not that much to configure without any plugins.
# For a reference for any variable inside this file, check out the Bukkit Wiki at
# https://www.spigotmc.org/go/bukkit-yml
#
# If you need help on this file, feel free to join us on irc or leave a message
# on the forums asking for advice.
#
# IRC: #spigot @ irc.spi.gt
# (If this means nothing to you, just go to https://www.spigotmc.org/go/irc )
# Forums: https://www.spigotmc.org/
# Bug tracker: https://www.spigotmc.org/go/bugs
settings:
allow-end: true
warn-on-overload: true
permissions-file: permissions.yml
update-folder: update
plugin-profiling: false
connection-throttle: 4000
query-plugins: true
deprecated-verbose: default
shutdown-message: Server closed
spawn-limits:
monsters: 70
animals: 10
water-animals: 15
ambient: 15
chunk-gc:
period-in-ticks: 600
load-threshold: 0
ticks-per:
animal-spawns: 400
monster-spawns: 1
autosave: 6000
aliases: now-in-commands.yml
-17
View File
@@ -1,17 +0,0 @@
# This is the commands configuration file for Bukkit.
# For documentation on how to make use of this file, check out the Bukkit Wiki at
# https://www.spigotmc.org/go/commands-yml
#
# If you need help on this file, feel free to join us on irc or leave a message
# on the forums asking for advice.
#
# IRC: #spigot @ irc.spi.gt
# (If this means nothing to you, just go to https://www.spigotmc.org/go/irc )
# Forums: https://www.spigotmc.org/
# Bug tracker: https://www.spigotmc.org/go/bugs
command-block-overrides: []
ignore-vanilla-permissions: false
aliases:
icanhasbukkit:
- version $1-
+1
View File
@@ -0,0 +1 @@
rsa/
+8
View File
@@ -0,0 +1,8 @@
host: 127.0.0.1
port: 8195
debug: true
disable-v1-protocol: false
tokens: {default: server2token}
forwarding:
method: pluginMessaging
pluginMessaging: {channel: 'nuvotifier:votes'}
+43
View File
@@ -0,0 +1,43 @@
# 1.0
#
# # If you need help with the configuration or have any questions related to Sponge,
# # join us at the IRC or drop by our forums and leave a post.
#
# # IRC: #sponge @ irc.esper.net ( https://webchat.esper.net/?channel=sponge )
# # Forums: https://forums.spongepowered.org/
#
sponge {
data-registration {
# A configurable list of registration ids that are to be removed
# when discovered for deserialization. This can be controlled by
# commands in sponge. It is adviseable to refer to the lists made
# available through 'failed-data-list', as using any id's from
# 'registered-data' will result in custom data being deleted at
# every load.
data-to-purge=[]
# An auto generated list, by Sponge, to discover and list
# all failed custom data deserializations at runtime due
# to a lack of the registrations being made by a plugin.
# Not to be confused by failed deserialization due to bad data.
# Modifying the list will result in no effect as Sponge auto
# generates this list. This is merely for user configuration.
failed-data-list=[]
# In the cases where there is already previously discovered data
# we don't want to spam the log on each discovery in certain
# contexts. If it is required, we still can emit the log warning
# when necessary.
print-on-discovery=false
# An auto generated list, by Sponge, to provide a list of
# registered custom data manipulators by plugins. Since
# the list is generated AFTER the game starts, modifying
# this list will not affect Sponge's system in any way.
# However, it is advisable to view what registered datas
# exist on a server instance, such that when Sponge completes
# startup, it will be verified that all existing registrations
# are accounted for. A warning will be emitted for any existing
# registrations that were not registered, and moved to the
# 'failed-data-list'.
registered-data=[]
}
}
+641
View File
@@ -0,0 +1,641 @@
# 1.0
#
# # If you need help with the configuration or have any questions related to Sponge,
# # join us at the IRC or drop by our forums and leave a post.
#
# # IRC: #sponge @ irc.esper.net ( https://webchat.esper.net/?channel=sponge )
# # Forums: https://forums.spongepowered.org/
#
sponge {
# Stopgap measures for dealing with broken mods
broken-mods {
# A list of mod ids that have broken network handlers (they interact with the game from a Netty handler thread).
# All network handlers from a forcibly scheduled to run on the main thread.
# Note that this setting should be considered a last resort, and should only be used as a stopgap measure while waiting for a mod to properly fix the issue.
broken-network-handler-mods=[]
}
bungeecord {
# If 'true', allows BungeeCord to forward IP address, UUID, and Game Profile to this server.
ip-forwarding=true
}
cause-tracker {
# A mapping that is semi-auto-populating for TileEntities whose types
# are found to be providing "null" Block sources as neighbor notifications
# that end up causing crashes or spam reports. If the value is set to
# "true", then a "workaround" will be attempted. If not, the
#
# current BlockState at the target source will be queried from the world.
# This map having a specific
# entry of a TileEntity will prevent a log or warning come up to any logs
# when that "null" arises, and Sponge will self-rectify the TileEntity
# by calling the method "getBlockType()". It is advised that if the mod
# id in question is coming up, that the mod author is notified about the
# error-prone usage of the field "blockType". You can refer them to
# the following links for the issue:
# https://gist.github.com/gabizou/ad570dc09dfed259cac9d74284e78e8b
# https://github.com/SpongePowered/SpongeForge/issues/2787
# Also, please provide them with these links for the example PR to
# fix the issue itself, as the fix is very simple:
# https://github.com/TehNut/Soul-Shards-Respawn/pull/24
# https://github.com/Epoxide-Software/Enchanting-Plus/pull/135
#
auto-fix-null-source-block-providing-tile-entities {}
# If set to 'true', when a mod or plugin attempts to spawn an entity
# off the main server thread, Sponge will automatically
# capture said entity to spawn it properly on the main
# server thread. The catch to this is that some mods are
# not considering the consequences of spawning an entity
# off the server thread, and are unaware of potential race
# conditions they may cause. If this is set to false,
# Sponge will politely ignore the entity being spawned,
# and emit a warning about said spawn anyways.
capture-async-spawning-entities=true
# If 'true', more thorough debugging for PhaseStates
# such that a StackTrace is created every time a PhaseState
# switches, allowing for more fine grained troubleshooting
# in the cases of runaway phase states. Note that this is
# not extremely performant and may have some associated costs
# with generating the stack traces constantly.
generate-stacktrace-per-phase=false
# The maximum number of times to recursively process transactions in a single phase.
# Some mods may interact badly with Sponge's block capturing system, causing Sponge to
# end up capturing block transactions every time it tries to process an existing batch.
# Due to the recursive nature of the depth-first processing that Sponge uses to handle block transactions,
# this can result in a stack overflow, which causes us to lose all infomration about the original cause of the issue.
# To prevent a stack overflow, Sponge tracks the current processing depth, and aborts processing when it exceeds
# this threshold.
# The default value should almost always work properly - it's unlikely you'll ever have to change it.
max-block-processing-depth=1000
# If verbose is not enabled, this restricts the amount of
# runaway phase state printouts, usually happens on a server
# where a PhaseState is not completing. Although rare, it should
# never happen, but when it does, sometimes it can continuously print
# more and more. This attempts to placate that while a fix can be worked on
# to resolve the runaway. If verbose is enabled, they will always print.
maximum-printed-runaway-counts=3
# If true, when a mod attempts to perform a neighbor notification
# on a block, some mods do not know to perform a 'null' check
# on the source block of their TileEntity. This usually goes by
# unnoticed by other mods, because they may perform '==' instance
# equality checks instead of calling methods on the potentially
# null Block, but Sponge uses the block to build information to
# help tracking. This has caused issues in the past. Generally,
# this can be useful for leaving "true" so a proper report is
# generated once for your server, and can be reported to the
# offending mod author.
# This is 'false' by default in SpongeVanilla.
# Review the following links for more info:
# https://gist.github.com/gabizou/ad570dc09dfed259cac9d74284e78e8b
# https://github.com/SpongePowered/SpongeForge/issues/2787
#
report-null-source-blocks-on-neighbor-notifications=true
# If set to 'true', when a mod or plugin attempts to submit a command
# asynchronously, Sponge will automatically capture said command
# and submit it for processing on the server thread. The catch to
# this is that some mods are performing these commands in vanilla
# without considering the possible consequences of such commands
# affecting any thread-unsafe parts of Minecraft, such as worlds,
# block edits, entity spawns, etc. If this is set to false, Sponge
# will politely ignore the command being executed, and emit a warning
# about said command anyways.
resync-commands-from-async=true
# If 'true', the phase tracker will print out when there are too many phases
# being entered, usually considered as an issue of phase re-entrance and
# indicates an unexpected issue of tracking phases not to complete.
# If this is not reported yet, please report to Sponge. If it has been
# reported, you may disable this.
verbose=true
# If 'true', the phase tracker will dump extra information about the current phases
# when certain non-PhaseTracker related exceptions occur. This is usually not necessary, as the information
# in the exception itself can normally be used to determine the cause of the issue
verbose-errors=false
}
commands {
# Command aliases will resolve conflicts when multiple plugins request a specific command,
# Correct syntax is <unqualified command>=<plugin name> e.g. "sethome=homeplugin"
aliases {}
# Defines how Sponge should act when a user tries to access a command they do not have
# permission for
command-hiding {
# If this is true, when a user tries to tab complete a command, or use "/sponge which" or
# "/sponge:help" this prevents commands a user does not have permission for from being completed.
#
# Note that some commands may not show up during tab complete if a user does not have permission
# regardless of this setting.
hide-on-discovery-attempt=true
# If this is true, when a user tries to use a command they don't have permission for, Sponge
# will act as if the command doesn't exist, rather than showing a no permissions message.
hide-on-execution-attempt=false
}
# Some mods may not trigger a permission check when running their command. Setting this to
# true will enforce a check of the Sponge provided permission ("<modid>.command.<commandname>").
# Note that setting this to true may cause some commands that are generally accessible to all to
# require a permission to run.
#
# Setting this to true will enable greater control over whether a command will appear in
# tab completion and Sponge's help command.
#
# If you are not using a permissions plugin, it is highly recommended that this is set to false
# (as it is by default).
enforce-permission-checks-on-non-sponge-commands=false
# Patches the specified commands to respect the world of the sender instead of applying the
# changes on the all worlds.
multi-world-patches {
defaultgamemode=true
difficulty=true
gamerule=true
seed=true
setdefaultspawnpoint=true
time=true
toggledownfall=true
weather=true
worldborder=true
}
}
debug {
# Detect and prevent parts of PlayerChunkMap being called off the main thread.
# This may decrease sever preformance, so you should only enable it when debugging a specific issue.
concurrent-chunk-map-checks=false
# Detect and prevent certain attempts to use entities concurrently.
# WARNING: May drastically decrease server performance. Only set this to 'true' to debug a pre-existing issue.
concurrent-entity-checks=false
# If 'true', Java's thread contention monitoring for thread dumps is enabled.
thread-contention-monitoring=false
}
entity {
# Number of colliding entities in one spot before logging a warning. Set to 0 to disable
collision-warn-size=200
# Number of ticks before a painting is respawned on clients when their art is changed
entity-painting-respawn-delay=2
# Number of ticks before the fake player entry of a human is removed from the tab list (range of 0 to 100 ticks).
human-player-list-remove-delay=10
# Controls the time in ticks for when an item despawns.
item-despawn-rate=6000
# The upper bounded range where living entities farther from a player will likely despawn
living-hard-despawn-range=128
# The amount of seconds before a living entity between the soft and hard despawn ranges from a player to be considered for despawning
living-soft-despawn-minimum-life=30
# The lower bounded range where living entities near a player may potentially despawn
living-soft-despawn-range=32
# Maximum size of an entity's bounding box before removing it. Set to 0 to disable
max-bounding-box-size=1000
# Square of the maximum speed of an entity before removing it. Set to 0 to disable
max-speed=100
}
entity-activation-range {
# If 'true', newly discovered entities will be added to this config with a default value.
auto-populate=false
# Default activation ranges used for all entities unless overridden.
defaults {
ambient=32
aquatic=32
creature=32
misc=16
monster=32
}
# Per-mod overrides. Refer to the minecraft default mod for example.
mods {}
}
entity-collisions {
# If 'true', newly discovered entities/blocks will be added to this config with a default value.
auto-populate=false
# Maximum amount of entities any given entity or block can collide with. This improves
# performance when there are more than 8 entities on top of each other such as a 1x1
# spawn pen. Set to 0 to disable.
max-entities-within-aabb=8
# Per-mod overrides. Refer to the minecraft default mod for example.
mods {
minecraft {
# Default maximum collisions used for all entities unless overridden.
defaults {}
# If 'false', entity collision rules for this mod will be ignored.
enabled=true
entities {}
}
}
}
exploits {
# If limit-book-size is enabled, controls the multiplier applied to each book page size
book-size-total-multiplier=0.98
# Enables filtering invalid entities when a chunk is being saved
# such that the entity that does not "belong" in the saving
# chunk will not be saved, and forced an update to the world's
# tracked entity lists for chunks.
# See https://github.com/PaperMC/Paper/blob/fd1bd5223a461b6d98280bb8f2d67280a30dd24a/Spigot-Server-Patches/0311-Prevent-Saving-Bad-entities-to-chunks.patch
filter-invalid-entities-on-chunk-save=true
# Limits the size of a book that can be sent by the client.
# See https://github.com/PaperMC/Paper/blob/f8058a8187da9f6185d95bb786783e12c79c8b18/Spigot-Server-Patches/0403-Book-Size-Limits.patch
# (Only affects SpongeVanilla)
limit-book-size=true
# Enables focing a chunk load when an entity position
# is set. Usually due to teleportation, vehicle movement
# etc. can a position lead an entity to no longer exist
# within it's currently marked and tracked chunk. This will
# enable that chunk for the position is loaded. Part of several
# exploits.See https://github.com/PaperMC/Paper/blob/fd1bd5223a461b6d98280bb8f2d67280a30dd24a/Spigot-Server-Patches/0335-Ensure-chunks-are-always-loaded-on-hard-position-set.patch
# (Only affects SpongeVanilla)
load-chunk-on-position-set=true
# Enables forcing chunks to save when an entity is added
# or removed from said chunk. This is a partial fix for
# some exploits using vehicles.See https://github.com/PaperMC/Paper/blob/fd1bd5223a461b6d98280bb8f2d67280a30dd24a/Spigot-Server-Patches/0306-Mark-chunk-dirty-anytime-entities-change-to-guarante.patch
# (Only affects SpongeVanilla)
mark-chunks-as-dirty-on-entity-list-modification=true
# If limit-book-size is enabled, controls the maximum size of a book page
max-book-page-size=2560
# Prevents an exploit in which the client sends a packet with the
# itemstack name exceeding the string limit.
prevent-creative-itemstack-name-exploit=true
# Enables forcing updates to the player's location on vehicle movement.
# This is partially required to update the server's understanding of
# where the player exists, and allows chunk loading issues to be avoided
# with laggy connections and/or hack clients.See https://github.com/PaperMC/Paper/blob/fd1bd5223a461b6d98280bb8f2d67280a30dd24a/Spigot-Server-Patches/0378-Sync-Player-Position-to-Vehicles.patch
# (Only affects SpongeVanilla)
sync-player-positions-for-vehicle-movement=true
# Enables forcing a chunk-tracking refresh on entity movement.
# This enables a guarantee that the entity is tracked in the
# proper chunk when moving.https://github.com/PaperMC/Paper/blob/fd1bd5223a461b6d98280bb8f2d67280a30dd24a/Spigot-Server-Patches/0315-Always-process-chunk-registration-after-moving.patch
# (Only affects SpongeVanilla)
update-tracked-chunk-on-entity-move=true
}
general {
# If 'true', Sponge will try to ensure that its data is on
# disk when saving the 'level_sponge.dat' file, but this
# may cause a slight performance hit.
#
# Setting this to 'false' will mean Sponge does not
# perform any consistency checks, but you may end up
# with corrupt data if an unexpected failure occurs
# on your server, requiring restoring this file from
# backup.
check-file-when-saving-sponge-data-file=true
# The directory for Sponge plugin configurations, relative to the
# execution root or specified as an absolute path.
# Note that the default: "${CANONICAL_GAME_DIR}/config"
# is going to use the "config" directory in the root game directory.
# If you wish for plugin configs to reside within a child of the configuration
# directory, change the value to, for example, "${CANONICAL_CONFIG_DIR}/sponge/plugins".
# Note: It is not recommended to set this to "${CANONICAL_CONFIG_DIR}/sponge", as there is
# a possibility that plugin configurations can conflict the Sponge core configurations.
#
config-dir="${CANONICAL_GAME_DIR}/config"
# If 'true', sleeping between chunk saves will be enabled, beware of memory issues.
file-io-thread-sleep=false
# Additional directory to search for plugins, relative to the
# execution root or specified as an absolute path.
# Note that the default: "${CANONICAL_MODS_DIR}/plugins"
# is going to search for a plugins folder in the mods directory.
# If you wish for the plugins folder to reside in the root game
# directory, change the value to "${CANONICAL_GAME_DIR}/plugins".
plugins-dir="${CANONICAL_MODS_DIR}/plugins"
}
ip-sets {}
logging {
# Log when blocks are broken
block-break=false
# Log when blocks are modified
block-modify=false
# Log when blocks are placed
block-place=false
# Log when blocks are populated in a chunk
block-populate=false
# Log when blocks are placed by players and tracked
block-tracking=false
# Log when chunks are queued to be unloaded by the chunk garbage collector.
chunk-gc-queue-unload=false
# Log when chunks are loaded
chunk-load=false
# Log when chunks are unloaded
chunk-unload=false
# Whether to log entity collision/count checks
entity-collision-checks=false
# Log when living entities are destroyed
entity-death=false
# Log when living entities are despawned
entity-despawn=false
# Log when living entities are spawned
entity-spawn=false
# Whether to log entity removals due to speed
entity-speed-removal=false
# Log when server receives exploited packet with itemstack name exceeding string limit.
exploit-itemstack-name-overflow=false
# Log when player attempts to respawn invisible to surrounding players.
exploit-respawn-invisibility=false
# Log when server receives exploited packet to update a sign containing commands from player with no permission.
exploit-sign-command-updates=false
# Add stack traces to dev logging
log-stacktraces=false
# Log when a world auto-saves its chunk data. Note: This may be spammy depending on the auto-save-interval configured for world.
world-auto-save=false
}
metrics {
# The global collection state that should be respected by all plugins that have no specified collection state. If undefined then it is treated as disabled.
global-state=UNDEFINED
# Plugin-specific collection states that override the global collection state.
plugin-states {}
}
modules {
# Enables experimental fixes for broken mods
broken-mod=false
bungeecord=true
entity-activation-range=true
entity-collisions=true
# Controls whether any exploit patches are applied.
# If there are issues with any specific exploits, please
# test in the exploit category first, before disabling all
# exploits with this toggle.
exploits=true
# Allows configuring Vanilla movement and speed checks
movement-checks=false
optimizations=true
# Use real (wall) time instead of ticks as much as possible
realtime=false
# Controls block range and tick rate of tileentities.
# Use with caution as this can break intended functionality.
tileentity-activation=false
timings=true
tracking=true
}
movement-checks {
# Controls whether the 'player/entity moved wrongly!' check will be enforced
moved-wrongly=true
# Controls whether the 'player moved too quickly!' check will be enforced
player-moved-too-quickly=true
# Controls whether the 'vehicle of player moved too quickly!' check will be enforced
player-vehicle-moved-too-quickly=true
}
optimizations {
# Runs lighting updates asynchronously.
async-lighting {
# If 'true', lighting updates are run asynchronously.
enabled=true
# The amount of threads to dedicate for asynchronous lighting updates. (Default: 2)
num-threads=2
}
# Caches tameable entities owners to avoid constant lookups against data watchers. If mods
# cause issues, disable this.
cache-tameable-owners=true
# Occasionally, some built in advancements,
# recipes, etc. can fail to deserialize properly
# which ends up potentially spamming the server log
# and the original provider of the failing content
# is not able to fix. This provides an option to
# suppress the exceptions printing out in the log.
disable-failing-deserialization-log-spam=true
# If 'true', block item drops are pre-processed to avoid
# having to spawn extra entities that will be merged post spawning.
# Usually, Sponge is smart enough to determine when to attempt an item pre-merge
# and when not to, however, in certain cases, some mods rely on items not being
# pre-merged and actually spawned, in which case, the items will flow right through
# without being merged.
drops-pre-merge=true
# Uses theosib's redstone algorithms to completely overhaul the way redstone works.
eigen-redstone {
# If 'true', uses theosib's redstone implementation which improves performance.
# See https://bugs.mojang.com/browse/MC-11193 and
# https://bugs.mojang.com/browse/MC-81098 for more information.
# Note: We cannot guarantee compatibility with mods. Use at your discretion.
enabled=false
# If 'true', restores the vanilla algorithm for computing wire power levels when powering off.
vanilla-decrement=false
# If 'true', restores the vanilla algorithm for propagating redstone wire changes.
vanilla-search=false
}
# If 'true', provides a fix for possible leaks through
# Minecraft's enchantment helper code that can leak
# entity and world references without much interaction
# Forge native (so when running SpongeForge implementation)
# has a similar patch, but Sponge's patch works a little harder
# at it, but Vanilla (SpongeVanilla implementation) does NOT
# have any of the patch, leading to the recommendation that this
# patch is enabled "for sure" when using SpongeVanilla implementation.
# See https://bugs.mojang.com/browse/MC-128547 for more information.
#
enchantment-helper-leak-fix=true
# If 'true', allows for Sponge to make better assumptinos on single threaded
# operations with relation to various checks for server threaded operations.
# This is default to true due to Sponge being able to precisely inject when
# the server thread is available. This should make an already fast operation
# much faster for better thread checks to ensure stability of sponge's systems.
faster-thread-checks=true
# If 'true', re-writes the incredibly inefficient Vanilla Map code.
# This yields enormous performance enhancements when using many maps, but has a tiny chance of breaking mods that invasively modify Vanilla.It is strongly reccomended to keep this on, unless explicitly advised otherwise by a Sponge developer
map-optimization=true
# Based on Aikar's optimizationo of Hoppers, setting this to 'true'
# will allow for hoppers to save performing server -> client updates
# when transferring items. Because hoppers can transfer items multiple
# times per tick, these updates can get costly on the server, with
# little to no benefit to the client. Because of the nature of the
# change, the default will be 'false' due to the inability to pre-emptively
# foretell whether mod compatibility will fail with these changes or not.
# Refer to: https://github.com/PaperMC/Paper/blob/8175ec916f31dcd130fe0884fe46bdc187d829aa/Spigot-Server-Patches/0269-Optimize-Hoppers.patch
# for more details.
optimize-hoppers=false
# If 'true', uses Panda4494's redstone implementation which improves performance.
# See https://bugs.mojang.com/browse/MC-11193 for more information.
# Note: This optimization has a few issues which are explained in the bug report.
# We strongly recommend using eigen redstone over this implementation as this will
# be removed in a future release.
panda-redstone=false
# Handles structures that are saved to disk. Certain structures can take up large amounts
# of disk space for very large maps and the data for these structures is only needed while the
# world around them is generating. Disabling saving of these structures can save disk space and
# time during saves if your world is already fully generated.
# Warning: disabling structure saving will break the vanilla locate command.
structure-saving {
# If 'true', newly discovered structures will be added to this config
# with a default value of 'true'. This is useful for finding out
# potentially what structures are being saved from various mods, and
# allowing those structures to be selectively disabled.
auto-populate=false
# If 'false', disables the modification to prevent certain structures
# from saving to the world's data folder. If you wish to prevent certain
# structures from saving, leave this "enabled=true". When 'true', the
# modification allows for specific 'named' structures to NOT be saved to
# disk. Examples of some structures that are costly and somewhat irrelivent
# is 'mineshaft's, as they build several structures and save, even after
# finished generating.
enabled=false
# Per-mod overrides. Refer to the minecraft default mod for example.
mods {
minecraft {
# If 'false', this mod will never save its structures. This may
# break some mod functionalities when requesting to locate their
# structures in a World. If true, allows structures not overridden
# in the section below to be saved by default. If you wish to find
# a structure to prevent it being saved, enable 'auto-populate' and
# restart the server/world instance.
enabled=true
# Per structure override. Having the value of 'false' will prevent
# that specific named structure from saving.
structures {
mineshaft=false
}
}
}
}
# Vanilla performs a lot of is area loaded checks during
# entity collision calculations with blocks, and because
# these calculations require fetching the chunks to see
# if they are loaded, before getting the block states
# from those chunks, there can be some small performance
# increase by checking the entity's owned active chunk
# it may currently reside in. Essentially, instead of
# asking the world if those chunks are loaded, the entity
# would know whether it's chunks are loaded and that neighbor's
# chunks are loaded.
use-active-chunks-for-collisions=false
}
permission {
# If 'true', Sponge plugins will be used to handle permissions rather than any Forge mod
forge-permissions-handler=false
}
player-block-tracker {
# Block IDs that will be blacklisted for player block placement tracking.
block-blacklist=[]
# If 'true', adds player tracking support for block positions.
# Note: This should only be disabled if you do not care who caused a block to change.
enabled=true
}
# Used to control spawn limits around players.
# Note: The radius uses the lower value of mob spawn range and server's view distance.
spawner {
# The number of ambients the spawner can potentially spawn around a player.
spawn-limit-ambient=15
# The number of animals the spawner can potentially spawn around a player.
spawn-limit-animal=15
# The number of aquatics the spawner can potentially spawn around a player.
spawn-limit-aquatic=5
# The number of monsters the spawner can potentially spawn around a player.
spawn-limit-monster=70
# The ambient spawning tick rate. Default: 400
tick-rate-ambient=400
# The animal spawning tick rate. Default: 400
tick-rate-animal=400
# The aquatic spawning tick rate. Default: 1
tick-rate-aquatic=1
# The monster spawning tick rate. Default: 1
tick-rate-monster=1
}
# Configuration options related to the Sql service, including connection aliases etc
sql {
# Aliases for SQL connections, in the format jdbc:protocol://[username[:password]@]host/database
aliases {}
}
# Blocks to blacklist for safe teleportation.
teleport-helper {
# If 'true', this blacklist will always be respected, otherwise, plugins can choose whether
# or not to respect it.
force-blacklist=false
# Block IDs that are listed here will not be selected by Sponge's safe teleport routine as
# a safe block for players to warp into.
# You should only list blocks here that are incorrectly selected, solid blocks that prevent
# movement are automatically excluded.
unsafe-body-block-ids=[]
# Block IDs that are listed here will not be selected by Sponge's safe
# teleport routine as a safe floor block.
unsafe-floor-block-ids=[]
}
tileentity-activation {
# If 'true', newly discovered tileentities will be added to this config with default settings.
auto-populate=false
# Default activation block range used for all tileentities unless overridden.
default-block-range=64
# Default tick rate used for all tileentities unless overridden.
default-tick-rate=1
# Per-mod overrides. Refer to the minecraft default mod for example.
mods {}
}
timings {
enabled=true
hidden-config-entries=[
"sponge.sql"
]
history-interval=300
history-length=3600
server-name-privacy=false
verbose=false
}
world {
# The auto-save tick interval used when saving global player data. (Default: 900)
# Note: 20 ticks is equivalent to 1 second. Set to 0 to disable.
auto-player-save-interval=900
# The auto-save tick interval used to save all loaded chunks in a world.
# Set to 0 to disable. (Default: 900)
# Note: 20 ticks is equivalent to 1 second.
auto-save-interval=900
# The number of newly loaded chunks before triggering a forced cleanup.
# Note: When triggered, the loaded chunk threshold will reset and start incrementing.
# Disabled by default.
chunk-gc-load-threshold=0
# The tick interval used to cleanup all inactive chunks that have leaked in a world.
# Set to 0 to disable which restores vanilla handling. (Default: 600)
chunk-gc-tick-interval=600
# The number of seconds to delay a chunk unload once marked inactive. (Default: 15)
# Note: This gets reset if the chunk becomes active again.
chunk-unload-delay=15
# If 'true', any request for a chunk not currently loaded will be denied (exceptions apply
# for things like world gen and player movement).
# Warning: As this is an experimental setting for performance gain, if you encounter any issues
# then we recommend disabling it.
deny-chunk-requests=true
# The interval, in seconds, used by the GameProfileQueryTask to process queued GameProfile requests. (Default: 4)
# Note: This setting should be raised if you experience the following error:
# "The client has sent too many requests within a certain amount of time".
# Finally, if set to 0 or less, the default interval will be used.
gameprofile-lookup-task-interval=4
# If 'true', this world will generate its spawn the moment its loaded.
generate-spawn-on-load=false
# The list of uuid's that should never perform a lookup against Mojang's session server.
# Note: If you are using SpongeForge, make sure to enter any mod fake player's UUID to this list.
invalid-lookup-uuids=[
"00000000-0000-0000-0000-000000000000",
"0d0c4ca0-4ff1-11e4-916c-0800200c9a66",
"41c82c87-7afb-4024-ba57-13d2c99cae77"
]
# The defined merge radius for Item entities such that when two items are
# within the defined radius of each other, they will attempt to merge. Usually,
# the default radius is set to 0.5 in Vanilla, however, for performance reasons
# 2.5 is generally acceptable.
# Note: Increasing the radius higher will likely cause performance degradation
# with larger amount of items as they attempt to merge and search nearby
# areas for more items. Setting to a negative value is not supported!
item-merge-radius=2.5
# If 'true', this worlds spawn will remain loaded with no players.
keep-spawn-loaded=true
# If 'true', natural leaf decay is allowed.
leaf-decay=true
# If 'true', this world will load on startup.
load-on-startup=false
# The maximum number of queued unloaded chunks that will be unloaded in a single tick.
# Note: With the chunk gc enabled, this setting only applies to the ticks
# where the gc runs (controlled by 'chunk-gc-tick-interval')
# Note: If the maximum unloads is too low, too many chunks may remain
# loaded on the world and increases the chance for a drop in tps. (Default: 100)
max-chunk-unloads-per-tick=100
# Specifies the radius (in chunks) of where creatures will spawn.
# This value is capped to the current view distance setting in server.properties
mob-spawn-range=4
# A list of all detected portal agents used in this world.
# In order to override, change the target world name to any other valid world.
# Note: If world is not found, it will fallback to default.
portal-agents {
"minecraft:default_the_end"=DIM1
"minecraft:default_the_nether"=DIM-1
}
# If 'true', this world will allow PVP combat.
pvp-enabled=true
# Override world distance per world/dimension
# The value must be greater than or equal to 3 and less than or equal to 32
# The server-wide view distance will be used when the value is -1.
view-distance=-1
# If 'true', natural formation of ice and snow in supported biomes will be allowed.
weather-ice-and-snow=true
# If 'true', thunderstorms will be initiated in supported biomes.
weather-thunder=true
# If 'true', this world will be registered.
world-enabled=true
}
# World Generation Modifiers to apply to the world
world-generation-modifiers=[]
}
+76
View File
@@ -0,0 +1,76 @@
# 1.0
#
# # If you need help with the configuration or have any questions related to Sponge,
# # join us at the IRC or drop by our forums and leave a post.
#
# # IRC: #sponge @ irc.esper.net ( https://webchat.esper.net/?channel=sponge )
# # Forums: https://forums.spongepowered.org/
#
sponge {
block {
# If 'true', newly discovered blocks will be added to this config with default settings.
auto-populate=false
# Per-mod block id mappings for controlling tracking behavior
mods {
extrautils2 {
# Set to true to perform block bulk capturing during block ticks. (Default: true)
block-bulk-capture {
redstoneclock=false
}
# Set to true to create and fire block events during block ticks. (Default: true)
block-event-creation {}
# If 'false', all tracking for this mod will be ignored.
enabled=true
# Set to true to create and fire entity events during block ticks. (Default: true)
entity-block-creation {}
# Set to true to perform entity bulk capturing during block ticks. (Default: true)
entity-bulk-capture {}
}
minecraft {
# Set to true to perform block bulk capturing during block ticks. (Default: true)
block-bulk-capture {}
# Set to true to create and fire block events during block ticks. (Default: true)
block-event-creation {}
# If 'false', all tracking for this mod will be ignored.
enabled=true
# Set to true to create and fire entity events during block ticks. (Default: true)
entity-block-creation {}
# Set to true to perform entity bulk capturing during block ticks. (Default: true)
entity-bulk-capture {}
}
}
}
entity {
# If 'true', newly discovered entities will be added to this config with default settings.
auto-populate=false
# Per-mod entity id mappings for controlling tracking behavior
mods {
minecraft {
# Set to true to perform block bulk capturing during entity ticks. (Default: true)
block-bulk-capture {
"armor_stand"=false
"experience_orb"=false
item=false
"leash_hitch"=false
"llama_spit"=false
painting=false
}
# Set to true to create and fire block events during entity ticks. (Default: true)
block-event-creation {}
# If 'false', all tracking for this mod will be ignored.
enabled=true
# Set to true to create and fire entity events during entity ticks. (Default: true)
entity-block-creation {}
# Set to true to perform entity bulk capturing during entity ticks. (Default: true)
entity-bulk-capture {}
}
}
}
tileentity {
# If 'true', newly discovered tileentities will be added to this config with default settings.
auto-populate=false
# Per-mod tileentity id mappings for controlling tracking behavior
mods {}
}
}
@@ -0,0 +1,15 @@
# 1.0
#
# # If you need help with the configuration or have any questions related to Sponge,
# # join us at the IRC or drop by our forums and leave a post.
#
# # IRC: #sponge @ irc.esper.net ( https://webchat.esper.net/?channel=sponge )
# # Forums: https://forums.spongepowered.org/
#
sponge {
world {
# If 'true', this world will load on startup.
load-on-startup=true
}
}
@@ -0,0 +1,10 @@
# 1.0
#
# # If you need help with the configuration or have any questions related to Sponge,
# # join us at the IRC or drop by our forums and leave a post.
#
# # IRC: #sponge @ irc.esper.net ( https://webchat.esper.net/?channel=sponge )
# # Forums: https://forums.spongepowered.org/
#
@@ -0,0 +1,10 @@
# 1.0
#
# # If you need help with the configuration or have any questions related to Sponge,
# # join us at the IRC or drop by our forums and leave a post.
#
# # IRC: #sponge @ irc.esper.net ( https://webchat.esper.net/?channel=sponge )
# # Forums: https://forums.spongepowered.org/
#
@@ -0,0 +1,15 @@
# 1.0
#
# # If you need help with the configuration or have any questions related to Sponge,
# # join us at the IRC or drop by our forums and leave a post.
#
# # IRC: #sponge @ irc.esper.net ( https://webchat.esper.net/?channel=sponge )
# # Forums: https://forums.spongepowered.org/
#
sponge {
world {
# If 'true', this world will load on startup.
load-on-startup=true
}
}
@@ -0,0 +1,10 @@
# 1.0
#
# # If you need help with the configuration or have any questions related to Sponge,
# # join us at the IRC or drop by our forums and leave a post.
#
# # IRC: #sponge @ irc.esper.net ( https://webchat.esper.net/?channel=sponge )
# # Forums: https://forums.spongepowered.org/
#
+132
View File
@@ -0,0 +1,132 @@
# Thanks for downloading ViaVersion
# Ensure you look through all these options
# If you need help:
# Discord - https://viaversion.com/discord
# viaversion.com - Discussion tab
# Docs - https://docs.viaversion.com/display/VIAVERSION/Configuration
#
# ----------------------------------------------------------#
# GLOBAL OPTIONS #
# ----------------------------------------------------------#
#
# Should ViaVersion check for updates?
checkforupdates: true
# Send the supported versions with the Status (Ping) response packet
send-supported-versions: false
# Block specific Minecraft protocols that ViaVersion allows
# List of all Minecraft protocol versions: http://wiki.vg/Protocol_version_numbers or use a generator: https://via.krusic22.com
block-protocols: []
# Change the blocked disconnect message
block-disconnect-msg: You are using an unsupported Minecraft version!
# If you use ProtocolLib, we can't reload without kicking the players.
# (We don't suggest using reload either, use a plugin manager)
# You can customise the message we kick people with if you use ProtocolLib here.
reload-disconnect-msg: Server reload, please rejoin!
# We warn when there's a error converting item and block data over versions, should we suppress these? (Only suggested if spamming)
suppress-conversion-warnings: false
#
# ----------------------------------------------------------#
# GLOBAL PACKET LIMITER #
# ----------------------------------------------------------#
#
#
# Packets Per Second (PPS) limiter (Use -1 on max-pps and tracking-period to disable)
# Clients by default send around 20-90 packets per second.
#
# What is the maximum per second a client can send (Use %pps to display their pps)
# Use -1 to disable.
max-pps: 800
max-pps-kick-msg: You are sending too many packets!
#
# We can also kick them if over a period they send over a threshold a certain amount of times.
#
# Period to track (in seconds)
# Use -1 to disable.
tracking-period: 6
# How many packets per second counts as a warning
tracking-warning-pps: 120
# How many warnings over the interval can we have
# This can never be higher than "tracking-period"
tracking-max-warnings: 4
tracking-max-kick-msg: You are sending too many packets, :(
#
# ----------------------------------------------------------#
# MULTIPLE VERSIONS OPTIONS #
# ----------------------------------------------------------#
#
# Should we enable our hologram patch?
# If they're in the wrong place enable this
hologram-patch: false
# This is the offset, should work as default when enabled.
hologram-y: -0.96
# Should we disable piston animation for 1.11/1.11.1 clients?
# In some cases when firing lots of pistons it crashes them.
piston-animation-patch: false
# Should we fix nbt for 1.12 and above clients in chat messages (causes invalid item)
chat-nbt-fix: true
# Should we use prefix for team colour on 1.13 and above clients
team-colour-fix: true
# 1.13 introduced new auto complete which can trigger "Kicked for spamming" for servers older than 1.13, the following option will disable it completely.
disable-1_13-auto-complete: false
# The following option will delay the tab complete request in x ticks if greater than 0, if other tab-complete is received, the previous is cancelled
1_13-tab-complete-delay: 0
# For 1.13 clients the smallest (1 layer) snow doesn't have collision, this will send these as 2 snowlayers for 1.13+ clients to prevent them bugging through them
fix-low-snow-collision: false
# Infested blocks are instantly breakable for 1.13+ clients, resulting in them being unable to break them on sub 1.13 servers. This remaps them to their normal stone variants
fix-infested-block-breaking: true
# In 1.14 the client page limit has been upped to 100 (from 50). Some anti-exploit plugins ban when clients go higher than 50. This option cuts edited books to 50 pages.
truncate-1_14-books: false
# Fixes 1.14+ clients on sub 1.14 servers having a light value of 0 for non full blocks.
fix-non-full-blocklight: true
# Fixes walk animation not shown when health is set to Float.NaN
fix-1_14-health-nan: true
# Should 1.15+ clients respawn instantly / without showing a death screen?
use-1_15-instant-respawn: false
#
# Enable serverside block-connections for 1.13+ clients - all of the options in this section are built around this option
serverside-blockconnections: true
# When activated, only the most important blocks are stored in the blockstorage. (fences, glass panes etc. won't connect to solid blocks)
reduce-blockstorage-memory: false
# When activated with serverside-blockconnections, flower parts with blocks above will be sent as stems
# Useful for lobbyservers where users can't build and those stems are used decoratively
flowerstem-when-block-above: false
# Vines that are not connected to blocks will be mapped to air, else 1.13+ would still be able to climb up on them.
vine-climb-fix: false
#
# ----------------------------------------------------------#
# 1.9+ CLIENTS ON 1.8 SERVERS OPTIONS #
# ----------------------------------------------------------#
#
# No collide options, these allow you to configure how collision works.
# Do you want us to prevent collision?
prevent-collision: true
# If the above is true, should we automatically team players until you do?
auto-team: true
# When enabled if certain metadata can't be read we won't tell you about it
suppress-metadata-errors: false
# When enabled 1.9+ will be able to block by using shields
shield-blocking: true
# Enable player tick simulation, this fixes eating, drinking, nether portals.
simulate-pt: true
# Should we use nms player to simulate packets, (may fix anti-cheat issues)
nms-player-ticking: true
# Should we patch boss bars so they work? (Default: true, disable if you're having issues)
bossbar-patch: true
# If your boss bar flickers on 1.9+, set this to 'true'. It will keep all boss bars on 100% (not recommended)
bossbar-anti-flicker: false
# This will show the new effect indicator in the top-right corner for 1.9+ players.
use-new-effect-indicator: true
# Show the new death messages for 1.9+ on the death screen
use-new-deathmessages: true
# Should we cache our items, this will prevent server from being lagged out, however the cost is a constant task caching items
item-cache: true
# Should we replace extended pistons to fix 1.10.1 (Only on chunk load)
replace-pistons: false
# What id should we replace with, default is air. (careful of players getting stuck standing on them)
replacement-piston-id: 0
# Force the string -> json transform
force-json-transform: false
# Minimize the cooldown animation in 1.8 servers
minimize-cooldown: true
# Left handed handling on 1.8 servers
left-handed-handling: true
+4
View File
@@ -0,0 +1,4 @@
#By changing the setting below to TRUE you are indicating your agreement to our EULA (https://account.mojang.com/documents/minecraft_eula).
#You also agree that tacos are tasty, and the best food in the world.
#Tue Jun 16 08:43:06 EDT 2020
eula=true
-56
View File
@@ -1,56 +0,0 @@
# This is the help configuration file for Bukkit.
#
# By default you do not need to modify this file. Help topics for all plugin commands are automatically provided by
# or extracted from your installed plugins. You only need to modify this file if you wish to add new help pages to
# your server or override the help pages of existing plugin commands.
#
# This file is divided up into the following parts:
# -- general-topics: lists admin defined help topics
# -- index-topics: lists admin defined index topics
# -- amend-topics: lists topic amendments to apply to existing help topics
# -- ignore-plugins: lists any plugins that should be excluded from help
#
# Examples are given below. When amending command topic, the string <text> will be replaced with the existing value
# in the help topic. Color codes can be used in topic text. The color code character is & followed by 0-F.
# ================================================================
#
# Set this to true to list the individual command help topics in the master help.
# command-topics-in-master-index: true
#
# Each general topic will show up as a separate topic in the help index along with all the plugin command topics.
# general-topics:
# Rules:
# shortText: Rules of the server
# fullText: |
# &61. Be kind to your fellow players.
# &B2. No griefing.
# &D3. No swearing.
# permission: topics.rules
#
# Each index topic will show up as a separate sub-index in the help index along with all the plugin command topics.
# To override the default help index (displayed when the user executes /help), name the index topic "Default".
# index-topics:
# Ban Commands:
# shortText: Player banning commands
# preamble: Moderator - do not abuse these commands
# permission: op
# commands:
# - /ban
# - /ban-ip
# - /banlist
#
# Topic amendments are used to change the content of automatically generated plugin command topics.
# amended-topics:
# /stop:
# shortText: Stops the server cold....in its tracks!
# fullText: <text> - This kills the server.
# permission: you.dont.have
#
# Any plugin in the ignored plugins list will be excluded from help. The name must match the name displayed by
# the /plugins command. Ignore "Bukkit" to remove the standard bukkit commands from the index. Ignore "All"
# to completely disable automatic help topic generation.
# ignore-plugins:
# - PluginNameOne
# - PluginNameTwo
# - PluginNameThree
Binary file not shown.
File renamed without changes.
+1
View File
@@ -0,0 +1 @@
../../../universal/build/libs/nuvotifier.jar
+1 -1
View File
@@ -1 +1 @@
../resources/paper.jar
../resources/sponge.jar
-178
View File
@@ -1,178 +0,0 @@
# This is the main configuration file for Paper.
# As you can see, there's tons to configure. Some options may impact gameplay, so use
# with caution, and make sure you know what each option does before configuring.
#
# If you need help with the configuration or have any questions related to Paper,
# join us in our Discord or IRC channel.
#
# Discord: https://paperdiscord.emc.gs
# IRC: #paper @ irc.spi.gt ( http://irc.spi.gt/iris/?channels=paper )
# Website: https://papermc.io/
# Docs: https://paper.readthedocs.org/
verbose: false
config-version: 16
settings:
load-permissions-yml-before-plugins: true
bungee-online-mode: true
incoming-packet-spam-threshold: 300
use-versioned-world: false
velocity-support:
enabled: false
online-mode: false
secret: ''
queue-light-updates-max-loss: 10
suggest-player-names-when-null-tab-completions: true
watchdog:
early-warning-every: 5000
early-warning-delay: 10000
spam-limiter:
tab-spam-increment: 1
tab-spam-limit: 500
save-player-data: true
sleep-between-chunk-saves: false
region-file-cache-size: 256
save-empty-scoreboard-teams: false
book-size:
page-max: 2560
total-multiplier: 0.98
enable-player-collisions: true
player-auto-save-rate: -1
max-player-auto-save-per-tick: -1
async-chunks:
enable: true
generation: true
thread-per-world-generation: true
load-threads: -1
use-alternative-luck-formula: false
messages:
no-permission: '&cI''m sorry, but you do not have permission to perform this command.
Please contact the server administrators if you believe that this is in error.'
kick:
authentication-servers-down: ''
connection-throttle: Connection throttled! Please wait before reconnecting.
flying-player: Flying is not enabled on this server
flying-vehicle: Flying is not enabled on this server
timings:
enabled: true
verbose: true
server-name-privacy: false
hidden-config-entries:
- database
- settings.bungeecord-addresses
history-interval: 300
history-length: 3600
world-settings:
default:
portal-search-radius: 128
game-mechanics:
villages-load-chunks: false
scan-for-legacy-ender-dragon: true
disable-chest-cat-detection: false
disable-end-credits: false
disable-player-crits: false
disable-sprint-interruption-on-attack: false
shield-blocking-delay: 5
disable-unloaded-chunk-enderpearl-exploit: true
queue-light-updates: false
optimize-explosions: false
disable-teleportation-suffocation-check: false
fixed-chunk-inhabited-time: -1
use-vanilla-world-scoreboard-name-coloring: false
delay-chunk-unloads-by: 10s
max-auto-save-chunks-per-tick: 24
save-queue-limit-for-auto-save: 50
enable-treasure-maps: true
treasure-maps-return-already-discovered: false
experience-merge-max-value: -1
max-chunk-sends-per-tick: 81
max-chunk-gens-per-tick: 10
prevent-moving-into-unloaded-chunks: false
max-growth-height:
cactus: 3
reeds: 3
fishing-time-range:
MinimumTicks: 100
MaximumTicks: 600
despawn-ranges:
soft: 32
hard: 128
falling-block-height-nerf: 0
tnt-entity-height-nerf: 0
remove-corrupt-tile-entities: false
lightning-strike-distance-limit:
sound: -1
impact-sound: -1
flash: -1
frosted-ice:
enabled: true
delay:
min: 20
max: 40
lootables:
auto-replenish: false
restrict-player-reloot: true
reset-seed-on-fill: true
max-refills: -1
refresh-min: 12h
refresh-max: 2d
filter-nbt-data-from-spawn-eggs-and-related: true
max-entity-collisions: 8
disable-creeper-lingering-effect: false
hopper:
cooldown-when-full: true
disable-move-event: false
duplicate-uuid-resolver: saferegen
duplicate-uuid-saferegen-delete-range: 32
keep-spawn-loaded: true
anti-xray:
enabled: false
engine-mode: 1
chunk-edge-mode: 1
max-chunk-section-index: 3
update-radius: 2
hidden-blocks:
- gold_ore
- iron_ore
- coal_ore
- lapis_ore
- mossy_cobblestone
- obsidian
- chest
- diamond_ore
- redstone_ore
- lit_redstone_ore
- clay
- emerald_ore
- ender_chest
replacement-blocks:
- stone
- planks
skip-entity-ticking-in-chunks-scheduled-for-unload: true
armor-stands-do-collision-entity-lookups: true
keep-spawn-loaded-range: 8
auto-save-interval: -1
disable-thunder: false
skeleton-horse-thunder-spawn-chance: 0.01
disable-ice-and-snow: false
fire-physics-event-for-redstone: false
grass-spread-tick-rate: 1
water-over-lava-flow-speed: 5
bed-search-radius: 1
use-faster-eigencraft-redstone: false
nether-ceiling-void-damage: false
allow-non-player-entities-on-scoreboards: false
container-update-tick-rate: 1
parrots-are-unaffected-by-player-movement: false
prevent-tnt-from-moving-in-water: false
non-player-arrow-despawn-rate: -1
creative-arrow-despawn-rate: -1
disable-explosion-knockback: false
armor-stands-tick: true
spawner-nerfed-mobs-should-jump: false
allow-leashing-undead-horse: false
baby-zombie-movement-speed: 0.5
all-chunks-are-slime-chunks: false
mob-spawner-tick-rate: 1
squid-spawn-height:
maximum: 0.0
-1
View File
@@ -1 +0,0 @@
rsa/
-29
View File
@@ -1,29 +0,0 @@
# The IP to listen to. Use 0.0.0.0 if you wish to listen to all interfaces on your server. (All IP addresses)
# This defaults to the IP you have configured your server to listen on, or 0.0.0.0 if you have not configured this.
host: 0.0.0.0
# Port to listen for new votes on
port: 8194
# Whether or not to print debug messages. In a production system, this should be set to false.
# This is useful when initially setting up NuVotifier to ensure votes are being delivered.
debug: true
# Setting this option to true will disable handling of Protocol v1 packets. While the old protocol is not secure, this
# option is currently not recommended as most voting sites only support the old protocol at present. However, if you are
# using NuVotifier's proxy forwarding mechanism, enabling this option will increase your server's security.
disable-v1-protocol: false
# All tokens, labeled by the serviceName of each server list.
tokens:
# Default token for all server lists, if another isn't supplied.
default: server2token
# Configuration section for all vote forwarding to NuVotifier
forwarding:
# Sets whether to set up a remote method for fowarding. Supported methods:
# - none - Does not set up a forwarding method.
# - pluginMessaging - Sets up plugin messaging
method: pluginMessaging
pluginMessaging:
channel: nuvotifier:votes
+13 -5
View File
@@ -1,5 +1,8 @@
#Minecraft server properties
#Fri Dec 21 15:15:00 EST 2018
#Tue Jun 23 23:02:40 EDT 2020
spawn-protection=16
max-tick-time=60000
query.port=25565
generator-settings=
force-gamemode=false
allow-nether=true
@@ -8,19 +11,23 @@ gamemode=0
broadcast-console-to-ops=true
enable-query=false
player-idle-timeout=0
difficulty=1
difficulty=2
spawn-monsters=true
broadcast-rcon-to-ops=true
op-permission-level=4
pvp=true
snooper-enabled=true
level-type=DEFAULT
level-type=default
hardcore=false
enable-command-block=false
max-players=20
network-compression-threshold=256
resource-pack-sha1=
max-world-size=29999984
function-permission-level=2
rcon.port=25575
server-port=25566
debug=false
server-ip=
spawn-npcs=true
allow-flight=false
@@ -29,11 +36,12 @@ view-distance=10
resource-pack=
spawn-animals=true
white-list=false
rcon.password=
generate-structures=true
online-mode=false
max-build-height=256
online-mode=false
level-seed=
prevent-proxy-connections=false
use-native-transport=true
prevent-proxy-connections=false
motd=A Minecraft Server
enable-rcon=false
-128
View File
@@ -1,128 +0,0 @@
# This is the main configuration file for Spigot.
# As you can see, there's tons to configure. Some options may impact gameplay, so use
# with caution, and make sure you know what each option does before configuring.
# For a reference for any variable inside this file, check out the Spigot wiki at
# http://www.spigotmc.org/wiki/spigot-configuration/
#
# If you need help with the configuration or have any questions related to Spigot,
# join us at the IRC or drop by our forums and leave a post.
#
# IRC: #spigot @ irc.spi.gt ( http://www.spigotmc.org/pages/irc/ )
# Forums: http://www.spigotmc.org/
config-version: 11
settings:
debug: false
save-user-cache-on-stop-only: false
sample-count: 12
timeout-time: 60
restart-on-crash: true
restart-script: ./start.sh
netty-threads: 4
attribute:
maxHealth:
max: 2048.0
movementSpeed:
max: 2048.0
attackDamage:
max: 2048.0
bungeecord: true
late-bind: false
player-shuffle: 0
user-cache-size: 1000
moved-wrongly-threshold: 0.0625
moved-too-quickly-multiplier: 10.0
messages:
whitelist: You are not whitelisted on this server!
unknown-command: Unknown command. Type "/help" for help.
server-full: The server is full!
outdated-client: Outdated client! Please use {0}
outdated-server: Outdated server! I'm still on {0}
restart: Server is restarting
stats:
disable-saving: false
forced-stats: {}
commands:
tab-complete: 0
send-namespaced: true
log: true
spam-exclusions:
- /skill
silent-commandblock-console: false
replace-commands:
- setblock
- summon
- testforblock
- tellraw
advancements:
disable-saving: false
disabled:
- minecraft:story/disabled
world-settings:
default:
verbose: true
random-light-updates: false
dragon-death-sound-radius: 0
seed-village: 10387312
seed-desert: 14357617
seed-igloo: 14357618
seed-jungle: 14357619
seed-swamp: 14357620
seed-monument: 10387313
seed-shipwreck: 165745295
seed-ocean: 14357621
seed-slime: 987234911
hunger:
jump-walk-exhaustion: 0.05
jump-sprint-exhaustion: 0.2
combat-exhaustion: 0.1
regen-exhaustion: 6.0
swim-multiplier: 0.01
sprint-multiplier: 0.1
other-multiplier: 0.0
max-tnt-per-tick: 100
max-tick-time:
tile: 50
entity: 50
squid-spawn-range:
min: 45.0
merge-radius:
exp: 3.0
item: 2.5
mob-spawn-range: 8
growth:
cactus-modifier: 100
cane-modifier: 100
melon-modifier: 100
mushroom-modifier: 100
pumpkin-modifier: 100
sapling-modifier: 100
wheat-modifier: 100
netherwart-modifier: 100
vine-modifier: 100
cocoa-modifier: 100
entity-activation-range:
animals: 32
monsters: 32
misc: 16
water: 16
tick-inactive-villagers: true
entity-tracking-range:
players: 48
animals: 48
monsters: 48
misc: 32
other: 64
ticks-per:
hopper-transfer: 8
hopper-check: 1
hopper-amount: 1
wither-spawn-sound-radius: 0
enable-zombie-pigmen-portal-spawns: true
item-despawn-rate: 6000
view-distance: 10
arrow-despawn-rate: 1200
zombie-aggressive-towards-villager: true
hanging-tick-frequency: 100
nerf-spawner-mobs: false
max-entity-collisions: 8
+1 -1
View File
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.4-all.zip
+2 -1
View File
@@ -1,5 +1,6 @@
dependencies {
compileOnly group: "org.spongepowered", name: "spongeapi", version: "7.1.0"
annotationProcessor group: "org.spongepowered", name: "spongeapi", version: "7.1.0"
compile project(":nuvotifier-common")
implementation project(":nuvotifier-api")
implementation project(":nuvotifier-common")
}
@@ -8,6 +8,7 @@ import com.vexsoftware.votifier.net.VotifierSession;
import com.vexsoftware.votifier.net.protocol.v1crypto.RSAIO;
import com.vexsoftware.votifier.net.protocol.v1crypto.RSAKeygen;
import com.vexsoftware.votifier.platform.LoggingAdapter;
import com.vexsoftware.votifier.platform.VotifierPlugin;
import com.vexsoftware.votifier.platform.scheduler.VotifierScheduler;
import com.vexsoftware.votifier.sponge.cmd.NVReloadCmd;
import com.vexsoftware.votifier.sponge.cmd.TestVoteCmd;
@@ -23,6 +24,7 @@ import org.spongepowered.api.command.args.GenericArguments;
import org.spongepowered.api.command.spec.CommandSpec;
import org.spongepowered.api.config.ConfigDir;
import org.spongepowered.api.event.Listener;
import org.spongepowered.api.event.game.GameReloadEvent;
import org.spongepowered.api.event.game.state.GameStartedServerEvent;
import org.spongepowered.api.event.game.state.GameStoppingServerEvent;
import org.spongepowered.api.plugin.Plugin;
@@ -34,9 +36,9 @@ import java.security.KeyPair;
import java.util.HashMap;
import java.util.Map;
@Plugin(id = "nuvotifier", name = "NuVotifier", version = "3.0.0-SNAPSHOT", authors = "Ichbinjoe",
@Plugin(id = "nuvotifier", name = "NuVotifier", version = "2.7.0", authors = "Ichbinjoe",
description = "Safe, smart, and secure Votifier server plugin")
public class VotifierPlugin implements VoteHandler, com.vexsoftware.votifier.platform.VotifierPlugin, ForwardedVoteListener {
public class NuVotifier implements VoteHandler, VotifierPlugin, ForwardedVoteListener {
@Inject
public Logger logger;
@@ -60,7 +62,9 @@ public class VotifierPlugin implements VoteHandler, com.vexsoftware.votifier.pla
File rsaDirectory = new File(configDir, "rsa");
try {
if (!rsaDirectory.exists()) {
rsaDirectory.mkdir();
if (!rsaDirectory.mkdir()) {
throw new RuntimeException("Unable to create the RSA key folder " + rsaDirectory);
}
keyPair = RSAKeygen.generate(2048);
RSAIO.save(rsaDirectory, keyPair);
} else {
@@ -184,6 +188,11 @@ public class VotifierPlugin implements VoteHandler, com.vexsoftware.votifier.pla
}
}
@Listener
public void onGameReload(GameReloadEvent event) {
this.reload();
}
@Listener
public void onServerStop(GameStoppingServerEvent event) {
halt();
@@ -194,11 +203,6 @@ public class VotifierPlugin implements VoteHandler, com.vexsoftware.votifier.pla
return logger;
}
/**
* The current Votifier version.
*/
private String version;
/**
* The server bootstrap.
*/
@@ -262,12 +266,7 @@ public class VotifierPlugin implements VoteHandler, com.vexsoftware.votifier.pla
logger.info("Got a protocol v2 vote record from " + remoteAddress + " -> " + vote);
}
}
Sponge.getScheduler().createTaskBuilder()
.execute(() -> {
VotifierEvent event = new VotifierEvent(vote, Sponge.getCauseStackManager().getCurrentCause());
Sponge.getEventManager().post(event);
})
.submit(this);
this.fireVoteEvent(vote);
}
@Override
@@ -289,9 +288,13 @@ public class VotifierPlugin implements VoteHandler, com.vexsoftware.votifier.pla
if (debug) {
logger.info("Got a forwarded vote -> " + v);
}
fireVoteEvent(v);
}
private void fireVoteEvent(final Vote vote) {
Sponge.getScheduler().createTaskBuilder()
.execute(() -> {
VotifierEvent event = new VotifierEvent(v, Sponge.getCauseStackManager().getCurrentCause());
VotifierEvent event = new VotifierEvent(vote, Sponge.getCauseStackManager().getCurrentCause());
Sponge.getEventManager().post(event);
})
.submit(this);
@@ -8,9 +8,9 @@ import org.spongepowered.api.scheduler.Task;
import java.util.concurrent.TimeUnit;
class SpongeScheduler implements VotifierScheduler {
private final VotifierPlugin plugin;
private final NuVotifier plugin;
SpongeScheduler(VotifierPlugin plugin) {
SpongeScheduler(NuVotifier plugin) {
this.plugin = plugin;
}
@@ -1,6 +1,6 @@
package com.vexsoftware.votifier.sponge.cmd;
import com.vexsoftware.votifier.sponge.VotifierPlugin;
import com.vexsoftware.votifier.sponge.NuVotifier;
import org.spongepowered.api.command.CommandException;
import org.spongepowered.api.command.CommandResult;
import org.spongepowered.api.command.CommandSource;
@@ -11,9 +11,9 @@ import org.spongepowered.api.text.format.TextColors;
public class NVReloadCmd implements CommandExecutor {
private final VotifierPlugin plugin;
private final NuVotifier plugin;
public NVReloadCmd(VotifierPlugin plugin) {
public NVReloadCmd(NuVotifier plugin) {
this.plugin = plugin;
}
@@ -2,7 +2,7 @@ package com.vexsoftware.votifier.sponge.cmd;
import com.vexsoftware.votifier.model.Vote;
import com.vexsoftware.votifier.net.VotifierSession;
import com.vexsoftware.votifier.sponge.VotifierPlugin;
import com.vexsoftware.votifier.sponge.NuVotifier;
import com.vexsoftware.votifier.util.ArgsToVote;
import org.spongepowered.api.command.CommandException;
import org.spongepowered.api.command.CommandResult;
@@ -16,9 +16,9 @@ import java.util.Collection;
public class TestVoteCmd implements CommandExecutor {
private final VotifierPlugin plugin;
private final NuVotifier plugin;
public TestVoteCmd(VotifierPlugin plugin) {
public TestVoteCmd(NuVotifier plugin) {
this.plugin = plugin;
}
@@ -26,9 +26,8 @@ public class TestVoteCmd implements CommandExecutor {
public CommandResult execute(CommandSource sender, CommandContext args) throws CommandException {
Vote v;
try {
// well, this is a super nice feature of sponge. unfortunately, no one else has these features. Therefore, GET RID OF IT
Collection<String> a = args.getAll("args");
v = ArgsToVote.parse((String[]) a.toArray());
v = ArgsToVote.parse(a.toArray(new String[0]));
} catch (IllegalArgumentException e) {
sender.sendMessage(Text.builder("Error while parsing arguments to create test vote: " + e.getMessage()).color(TextColors.DARK_RED).build());
sender.sendMessage(Text.builder("Usage hint: /testvote [username] [serviceName=?] [username=?] [address=?] [localTimestamp=?] [timestamp=?]").color(TextColors.GRAY).build());
@@ -1,35 +1,36 @@
package com.vexsoftware.votifier.sponge.config;
import com.google.common.reflect.TypeToken;
import com.vexsoftware.votifier.sponge.VotifierPlugin;
import com.vexsoftware.votifier.sponge.NuVotifier;
import ninja.leaping.configurate.ConfigurationNode;
import ninja.leaping.configurate.ConfigurationOptions;
import ninja.leaping.configurate.loader.ConfigurationLoader;
import ninja.leaping.configurate.yaml.YAMLConfigurationLoader;
import java.io.File;
import java.io.IOException;
public class ConfigLoader {
private static VotifierPlugin plugin;
private static SpongeConfig spongeConfig;
public static void loadConfig(VotifierPlugin pl) {
plugin = pl;
if (!plugin.getConfigDir().exists()) {
plugin.getConfigDir().mkdirs();
public static void loadConfig(NuVotifier pl) {
if (!pl.getConfigDir().exists()) {
if (!pl.getConfigDir().mkdirs()) {
throw new RuntimeException("Unable to create the plugin data folder " + pl.getConfigDir());
}
}
try {
File file = new File(plugin.getConfigDir(), "config.yml");
if (!file.exists()) {
file.createNewFile();
File config = new File(pl.getConfigDir(), "config.yml");
if (!config.exists() && !config.createNewFile()) {
throw new IOException("Unable to create the config file at " + config);
}
ConfigurationLoader loader = YAMLConfigurationLoader.builder().setFile(file).build();
ConfigurationNode config = loader.load(ConfigurationOptions.defaults().setShouldCopyDefaults(true));
spongeConfig = config.getValue(TypeToken.of(SpongeConfig.class), new SpongeConfig());
loader.save(config);
ConfigurationLoader loader = YAMLConfigurationLoader.builder().setFile(config).build();
ConfigurationNode configNode = loader.load(ConfigurationOptions.defaults().setShouldCopyDefaults(true));
spongeConfig = configNode.getValue(TypeToken.of(SpongeConfig.class), new SpongeConfig());
loader.save(configNode);
} catch (Exception e) {
plugin.getLogger().error("Could not load config.", e);
pl.getLogger().error("Could not load config.", e);
}
}
@@ -6,7 +6,7 @@ import org.spongepowered.api.event.impl.AbstractEvent;
/**
* This event is posted whenever a vote is received and processed by NuVotifier. Note that NuVotifier posts this event
* asynchronously, so you can only use limited portions of the Sponge API.
* synchronously.
*/
public class VotifierEvent extends AbstractEvent {
private final Vote vote;
@@ -1,6 +1,6 @@
package com.vexsoftware.votifier.sponge.forwarding;
import com.vexsoftware.votifier.sponge.VotifierPlugin;
import com.vexsoftware.votifier.sponge.NuVotifier;
import com.vexsoftware.votifier.support.forwarding.AbstractPluginMessagingForwardingSink;
import com.vexsoftware.votifier.support.forwarding.ForwardedVoteListener;
import org.spongepowered.api.Platform;
@@ -12,14 +12,14 @@ import org.spongepowered.api.network.RemoteConnection;
public class SpongePluginMessagingForwardingSink extends AbstractPluginMessagingForwardingSink implements RawDataListener {
public SpongePluginMessagingForwardingSink(VotifierPlugin p, String channel, ForwardedVoteListener listener) {
public SpongePluginMessagingForwardingSink(NuVotifier p, String channel, ForwardedVoteListener listener) {
super(listener);
this.channelBinding = Sponge.getChannelRegistrar().createRawChannel(p, channel);
this.channelBinding.addListener(Platform.Type.SERVER, this);
this.p = p;
}
private final VotifierPlugin p;
private final NuVotifier p;
private final ChannelBinding.RawDataChannel channelBinding;
@Override
+41 -19
View File
@@ -1,42 +1,66 @@
import com.github.jengelman.gradle.plugins.shadow.relocation.SimpleRelocator
import java.nio.file.FileAlreadyExistsException
import java.nio.file.Files
import java.nio.file.Paths
import java.nio.file.StandardCopyOption
import java.util.regex.Pattern
import com.github.jengelman.gradle.plugins.shadow.transformers.Transformer
import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext
import shadow.org.apache.tools.zip.ZipEntry
import shadow.org.apache.tools.zip.ZipOutputStream
import org.gradle.api.file.FileTreeElement
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4'
classpath 'com.github.jengelman.gradle.plugins:shadow:4.0.4'
}
}
class NettyEpollTransformer implements Transformer {
private java.nio.file.Path extractedNettyNative
boolean canTransformResource(FileTreeElement element) {
return element.name.endsWith("libnetty_transport_native_epoll_x86_64.so")
}
void transform(TransformerContext context) {
this.extractedNettyNative = Files.createTempFile("nuvotifer_build", ".so")
Files.copy(context.is, this.extractedNettyNative, StandardCopyOption.REPLACE_EXISTING)
}
boolean hasTransformedResource() { this.extractedNettyNative != null }
void modifyOutputStream(ZipOutputStream jos, boolean preserveFileTimestamps) {
ZipEntry entry = new ZipEntry("META-INF/native/libcom_vexsoftware_votifier_netty_transport_native_epoll_x86_64.so")
entry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, entry.time)
jos.putNextEntry(entry)
Files.copy(this.extractedNettyNative, jos)
Files.delete(this.extractedNettyNative)
}
}
apply plugin: 'com.github.johnrengelman.shadow'
dependencies {
compile project(":nuvotifier-bukkit")
compile project(":nuvotifier-bungeecord")
compile project(":nuvotifier-sponge")
compile project(":nuvotifier-velocity")
implementation project(":nuvotifier-api")
implementation project(":nuvotifier-common")
implementation project(":nuvotifier-bukkit")
implementation project(":nuvotifier-bungeecord")
implementation project(":nuvotifier-sponge")
implementation project(":nuvotifier-velocity")
}
shadowJar {
dependencies {
// All current implementations include Google Guava already, and explicitly shading in Guava causes the plugin
// to fail to initialize on Sponge.
exclude(dependency('com.google.guava:guava:24.1-jre'))
}
baseName = 'nuvotifier'
classifier = null
relocate "io.netty", "com.vexsoftware.votifier.netty"
archiveBaseName = 'nuvotifier'
relocate "io.netty", "com.vexsoftware.votifier.io.netty"
relocate "org.json", "com.vexsoftware.votifier.json"
relocate new SimpleRelocator("com.google.code", "com.vexsoftware.votifier.google.code", new ArrayList<String>(), Collections.singletonList("com.vexsoftware.votifier.sponge"))
relocate "com.google.guava", "com.vexsoftware.votifier.google.guava"
relocate "org.apache.commons.io", "com.vexsoftware.votifier.commons.io"
transform(NettyEpollTransformer.class)
}
artifacts {
@@ -60,9 +84,7 @@ task('linkLatest') {
def noVer = Paths.get(noVerMatcher.group(1) + ".jar")
def versnd = it.toPath()
try {
Files.createSymbolicLink(noVer, versnd)
} catch (FileAlreadyExistsException ignored) {}
Files.copy(versnd, noVer, StandardCopyOption.REPLACE_EXISTING)
}
}
}
+4 -3
View File
@@ -1,5 +1,6 @@
dependencies {
compileOnly group: "com.velocitypowered", name: "velocity-api", version: "1.0-SNAPSHOT"
annotationProcessor group: "com.velocitypowered", name: "velocity-api", version: "1.0-SNAPSHOT"
compile project(":nuvotifier-common")
compileOnly "com.velocitypowered:velocity-api:1.0.0-SNAPSHOT"
annotationProcessor "com.velocitypowered:velocity-api:1.0.0-SNAPSHOT"
implementation project(":nuvotifier-api")
implementation project(":nuvotifier-common")
}
@@ -38,6 +38,9 @@ public final class OnlineForwardPluginMessagingForwardingSource extends Abstract
serverFilter.isAllowed(sc.get().getServerInfo().getName())
) {
if (forwardSpecific(new VelocityBackendServer(plugin.getServer(), sc.get().getServer()), v)) {
if (plugin.isDebug()) {
plugin.getPluginLogger().info("Successfully forwarded vote " + v + " to server " + sc.get().getServerInfo().getName());
}
return;
}
}
@@ -1,10 +1,10 @@
package com.vexsoftware.votifier.velocity;
import com.google.common.io.ByteStreams;
import com.google.inject.Inject;
import com.moandjiezana.toml.Toml;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.event.proxy.ProxyReloadEvent;
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
import com.velocitypowered.api.plugin.Plugin;
import com.velocitypowered.api.plugin.annotation.DataDirectory;
@@ -25,12 +25,12 @@ import com.vexsoftware.votifier.support.forwarding.cache.FileVoteCache;
import com.vexsoftware.votifier.support.forwarding.cache.MemoryVoteCache;
import com.vexsoftware.votifier.support.forwarding.cache.VoteCache;
import com.vexsoftware.votifier.support.forwarding.proxy.ProxyForwardingVoteSource;
import com.vexsoftware.votifier.util.IOUtil;
import com.vexsoftware.votifier.util.KeyCreator;
import com.vexsoftware.votifier.util.TokenUtil;
import com.vexsoftware.votifier.velocity.cmd.NVReloadCmd;
import com.vexsoftware.votifier.velocity.cmd.TestVoteCmd;
import com.vexsoftware.votifier.velocity.event.VotifierEvent;
import io.netty.channel.Channel;
import org.slf4j.Logger;
import java.io.ByteArrayInputStream;
@@ -44,13 +44,13 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.security.Key;
import java.security.KeyPair;
import java.util.*;
import java.util.logging.Level;
import java.util.stream.Collectors;
@Plugin(id = "nuvotifier", name = "NuVotifier", version = "3.0.0-SNAPSHOT", authors = "Ichbinjoe",
@Plugin(id = "nuvotifier", name = "NuVotifier", version = "2.7.0", authors = "Ichbinjoe",
description = "Safe, smart, and secure Votifier server plugin")
public class VotifierPlugin implements VoteHandler, ProxyVotifierPlugin {
@@ -83,7 +83,9 @@ public class VotifierPlugin implements VoteHandler, ProxyVotifierPlugin {
File rsaDirectory = new File(configDir.toFile(), "rsa");
try {
if (!rsaDirectory.exists()) {
rsaDirectory.mkdir();
if (!rsaDirectory.mkdir()) {
throw new RuntimeException("Unable to create the RSA key folder " + rsaDirectory);
}
keyPair = RSAKeygen.generate(2048);
RSAIO.save(rsaDirectory, keyPair);
} else {
@@ -138,13 +140,13 @@ public class VotifierPlugin implements VoteHandler, ProxyVotifierPlugin {
getLogger().info("Vote cache none selected for caching: votes that cannot be immediately delivered will be lost.");
} else if ("memory".equals(cacheMethod)) {
voteCache = new MemoryVoteCache(
server.getAllServers().size(), this,
this,
fwdCfg.getTable("memory-cache").getLong("cacheTime", -1L));
getLogger().info("Using in-memory cache for votes that are not able to be delivered.");
} else if ("file".equals(cacheMethod)) {
try {
voteCache = new FileVoteCache(
server.getAllServers().size(), this,
this,
configDir.resolve(fwdCfg.getTable("file-cache").getString("name")).toFile(),
fwdCfg.getTable("file-cache").getLong("cacheTime", -1L));
} catch (IOException e) {
@@ -154,7 +156,7 @@ public class VotifierPlugin implements VoteHandler, ProxyVotifierPlugin {
int dumpRate = pmCfg.getLong("dumpRate", 5L).intValue();
ServerFilter filter = new ServerFilter(
pmCfg.getList("excludedServers"),
pmCfg.getList("excludedServers", Collections.emptyList()),
pmCfg.getBoolean("whitelist", false)
);
@@ -204,7 +206,7 @@ public class VotifierPlugin implements VoteHandler, ProxyVotifierPlugin {
}
}
forwardingMethod = new ProxyForwardingVoteSource(this, bootstrap::client, serverList, null);
forwardingMethod = bootstrap.createForwardingSource(serverList, null);
getLogger().info("Forwarding votes from this NuVotifier instance to another NuVotifier server.");
} else {
getLogger().error("No vote forwarding method '" + fwdMethod + "' known. Defaulting to noop implementation.");
@@ -251,7 +253,7 @@ public class VotifierPlugin implements VoteHandler, ProxyVotifierPlugin {
this.scheduler = new VelocityScheduler(server, this);
this.loggingAdapter = new SLF4JLogger(logger);
this.getServer().getCommandManager().register(new NVReloadCmd(this), "nvpreload");
this.getServer().getCommandManager().register(new NVReloadCmd(this), "pnvreload");
this.getServer().getCommandManager().register(new TestVoteCmd(this), "ptestvote");
if (!loadAndBind())
@@ -260,10 +262,15 @@ public class VotifierPlugin implements VoteHandler, ProxyVotifierPlugin {
@Subscribe
public void onServerStop(ProxyShutdownEvent event) {
this.halt();
logger.info("Votifier disabled.");
}
@Subscribe
public void onProxyReload(ProxyReloadEvent event) {
this.reload();
}
public ProxyServer getServer() {
return server;
}
@@ -281,7 +288,8 @@ public class VotifierPlugin implements VoteHandler, ProxyVotifierPlugin {
getLogger().info("Configuring Votifier for the first time...");
// Initialize the configuration file.
String cfgStr = new String(ByteStreams.toByteArray(VotifierPlugin.class.getResourceAsStream("/config.toml")), StandardCharsets.UTF_8);
String cfgStr = new String(IOUtil.readAllBytes(VotifierPlugin.class.getResourceAsStream("/config.toml")), StandardCharsets.UTF_8);
String token = TokenUtil.newToken();
cfgStr = cfgStr.replace("%ip%", server.getBoundAddress().getAddress().getHostAddress());
cfgStr = cfgStr.replace("%default_token%", token);
@@ -294,18 +302,18 @@ public class VotifierPlugin implements VoteHandler, ProxyVotifierPlugin {
getLogger().info("Assigning NuVotifier to listen on port 8192. If you are hosting BungeeCord on a");
getLogger().info("shared server please check with your hosting provider to verify that this port");
getLogger().info("is available for your use. Chances are that your hosting provider will assign");
getLogger().info("a different port, which you need to specify in config.yml");
getLogger().info("a different port, which you need to specify in config.toml.");
getLogger().info("------------------------------------------------------------------------------");
getLogger().info("Assigning NuVotifier to listen to interface 0.0.0.0. This is usually alright,");
getLogger().info("however, if you want NuVotifier to only listen to one interface for security ");
getLogger().info("reasons (or you use a shared host), you may change this in the config.yml.");
getLogger().info("reasons (or you use a shared host), you may change this in the config.toml.");
getLogger().info("------------------------------------------------------------------------------");
getLogger().info("Your default Votifier token is " + token + ".");
getLogger().info("You will need to provide this token when you submit your server to a voting");
getLogger().info("list.");
getLogger().info("------------------------------------------------------------------------------");
Files.copy(new ByteArrayInputStream(cfgStr.getBytes(StandardCharsets.UTF_8)), configPath);
Files.copy(new ByteArrayInputStream(cfgStr.getBytes(StandardCharsets.UTF_8)), configPath, StandardCopyOption.REPLACE_EXISTING);
return new Toml().read(cfgStr);
}
}