Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d22f4cd58b | ||
|
|
8ba7e87067 | ||
|
|
5776acaf34 | ||
|
|
90f6ed8b55 | ||
|
|
616bd4ad01 | ||
|
|
448baf0329 | ||
|
|
13fe852bcd | ||
|
|
c996e36b97 | ||
|
|
ad9e6f5fe8 | ||
|
|
53eb9c8fec | ||
|
|
6dbda167d3 | ||
|
|
be9f92d5cd | ||
|
|
96bf715fbc | ||
|
|
628273413b | ||
|
|
bbfa9e4aa9 | ||
|
|
a34b07f2d1 | ||
|
|
1d90a59d5a | ||
|
|
2734836e58 | ||
|
|
768daf099f | ||
|
|
b6292667b8 | ||
|
|
8519535566 | ||
|
|
08e907678f | ||
|
|
27b93ac045 | ||
|
|
97f4c91c24 | ||
|
|
e919c845f7 | ||
|
|
1fb35276f7 | ||
|
|
f5f596f21c | ||
|
|
88523db213 | ||
|
|
3599b0fa1b | ||
|
|
950b543e98 | ||
|
|
e66927dd1a | ||
|
|
98d4f69ffb | ||
|
|
ad44c76309 | ||
|
|
58de66699e | ||
|
|
b81052327d | ||
|
|
59a3eff421 | ||
|
|
411a529e18 | ||
|
|
4d6946ab2c | ||
|
|
d5ae57b28e | ||
|
|
aa1d9b3d71 | ||
|
|
c250048bf7 | ||
|
|
1db78a5bea | ||
|
|
2ad0fa118f | ||
|
|
38afe59db0 | ||
|
|
b173930c14 | ||
|
|
61c4529df6 | ||
|
|
dd48af5b50 | ||
|
|
bc3c667d2a | ||
|
|
1041bdb6b7 | ||
|
|
fc7a04547c | ||
|
|
dd2a1c4ed5 | ||
|
|
c7667abf24 | ||
|
|
df484523c2 | ||
|
|
81fca5b218 | ||
|
|
c520fd6650 |
No files matched your search
@@ -0,0 +1 @@
|
||||
custom: https://www.paypal.me/ibj
|
||||
@@ -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,35 +1,25 @@
|
||||
# NuVotifier
|
||||
|
||||
NuVotifier is a Bukkit plugin whose purpose is to be notified (aka *votified*)
|
||||
when a vote is made on a Minecraft server top list for the server. NuVotifier
|
||||
creates a *lightweight* server that waits for connections by Minecraft server
|
||||
lists and uses a simple protocol to get the required information. NuVotifier is
|
||||
*secure*, and makes sure that all vote notifications are delivered by authentic
|
||||
top lists.
|
||||
NuVotifier is a secure alternative to using the original Votifier project.
|
||||
NuVotifier will work in place of Votifier - any vote listener that supports
|
||||
Votifier will also support NuVotifier.
|
||||
|
||||
## Why fork Votifier?
|
||||
NuVotifier supports many different platforms using the same universal JAR:
|
||||
|
||||
Votifier has lagged in activity, has severe security flaws in its protocol, and
|
||||
is vulnerable to denial of service attacks.
|
||||
+ Bukkit / Spigot / Paper >=1.7.10
|
||||
+ Sponge 7
|
||||
+ BungeeCord / Waterfall
|
||||
+ Velocity
|
||||
|
||||
## Is NuVotifier a drop-in replacement for Votifier?
|
||||
NuVotifier also adds forwarding and listener test commands not present in the
|
||||
original version.
|
||||
|
||||
Yes! Except for some minor non-breaking changes (look into the [technical qa
|
||||
docs](docs/technical_qa.md) for more info), NuVotifier is 100% compatible with
|
||||
the old Votifier with many more features.
|
||||
[Setup Guide](https://github.com/NuVotifier/NuVotifier/wiki/Setup-Guide)
|
||||
|
||||
# Documentation / Configuration Guide
|
||||
[Troubleshooting Guide](https://github.com/NuVotifier/NuVotifier/wiki/Troubleshooting-Guide)
|
||||
|
||||
All documentation is located under the [docs](docs/) directory. A server admin
|
||||
configuration guide is available [here](docs/usage.md).
|
||||
|
||||
# Support
|
||||
|
||||
Feel free to join the MOSS Discord server using the below link:
|
||||
|
||||
[](https://discord.gg/anUtuAC)
|
||||
[Developer Information](https://github.com/NuVotifier/NuVotifier/wiki/Developer-Documentation)
|
||||
|
||||
# License
|
||||
|
||||
NuVotifier is GNU GPLv3 licensed. This project's license can be viewed
|
||||
[here](LICENSE).
|
||||
NuVotifier is GNU GPLv3 licensed. This project's license can be viewed [here](LICENSE).
|
||||
@@ -0,0 +1,4 @@
|
||||
# nuvotifier-api
|
||||
|
||||
Files in this directory have a strong API promise - they really shouldn't
|
||||
change over time. Feel free to depend against it!
|
||||
@@ -0,0 +1,3 @@
|
||||
dependencies {
|
||||
implementation 'com.google.code.gson:gson:2.8.0'
|
||||
}
|
||||
+37
-21
@@ -21,6 +21,9 @@ package com.vexsoftware.votifier.model;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* A model for a vote.
|
||||
*
|
||||
@@ -48,26 +51,31 @@ public class Vote {
|
||||
*/
|
||||
private String timeStamp;
|
||||
|
||||
/**
|
||||
* Timestamp (unix-millis) normalized and taken from a known source
|
||||
*/
|
||||
private final long localTimestamp;
|
||||
private byte[] additionalData;
|
||||
|
||||
@Deprecated
|
||||
public Vote() {
|
||||
localTimestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public Vote(String serviceName, String username, String address, String timeStamp) {
|
||||
this(serviceName, username, address, timeStamp, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public Vote(String serviceName, String username, String address, String timeStamp, long localTimestamp) {
|
||||
this.serviceName = serviceName;
|
||||
this.username = username;
|
||||
this.address = address;
|
||||
this.timeStamp = timeStamp;
|
||||
this.localTimestamp = localTimestamp;
|
||||
this.additionalData = null;
|
||||
}
|
||||
|
||||
public Vote(String serviceName, String username, String address, String timeStamp, byte[] additionalData) {
|
||||
this.serviceName = serviceName;
|
||||
this.username = username;
|
||||
this.address = address;
|
||||
this.timeStamp = timeStamp;
|
||||
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) {
|
||||
@@ -82,16 +90,22 @@ public class Vote {
|
||||
this(jsonObject.get("serviceName").getAsString(),
|
||||
jsonObject.get("username").getAsString(),
|
||||
jsonObject.get("address").getAsString(),
|
||||
getTimestamp(jsonObject.get("timestamp")),
|
||||
// maintained for backwards compatibility with <2.3.6 peers
|
||||
(jsonObject.has("localTimestamp") ? jsonObject.get("localTimestamp").getAsLong() : System.currentTimeMillis()));
|
||||
getTimestamp(jsonObject.get("timestamp")));
|
||||
if (jsonObject.has("additionalData"))
|
||||
additionalData = Base64.getDecoder().decode(jsonObject.get("additionalData").getAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String data;
|
||||
if (additionalData == null)
|
||||
data = "null";
|
||||
else
|
||||
data = Base64.getEncoder().encodeToString(additionalData);
|
||||
|
||||
return "Vote (from:" + serviceName + " username:" + username
|
||||
+ " address:" + address + " timeStamp:" + timeStamp
|
||||
+ " localTimestamp:" + localTimestamp + ")";
|
||||
+ " additionalData:" + data + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -171,12 +185,12 @@ public class Vote {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the local timestamp, in unix-millis. Calculated locally by a NuVotifier instance
|
||||
* Returns additional data sent with the vote, if it exists.
|
||||
*
|
||||
* @return The local timestamp
|
||||
* @return Additional data sent with the vote
|
||||
*/
|
||||
public long getLocalTimestamp() {
|
||||
return localTimestamp;
|
||||
public byte[] getAdditionalData() {
|
||||
return additionalData == null ? null : additionalData.clone();
|
||||
}
|
||||
|
||||
public JsonObject serialize() {
|
||||
@@ -185,21 +199,23 @@ public class Vote {
|
||||
ret.addProperty("username", username);
|
||||
ret.addProperty("address", address);
|
||||
ret.addProperty("timestamp", timeStamp);
|
||||
ret.addProperty("localTimestamp", localTimestamp);
|
||||
if (additionalData != null)
|
||||
ret.addProperty("additionalData", Base64.getEncoder().encodeToString(additionalData));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@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;
|
||||
|
||||
if (!serviceName.equals(vote.serviceName)) return false;
|
||||
if (!username.equals(vote.username)) return false;
|
||||
if (!address.equals(vote.address)) return false;
|
||||
return timeStamp.equals(vote.timeStamp);
|
||||
if (!timeStamp.equals(vote.timeStamp)) return false;
|
||||
return Arrays.equals(additionalData, vote.additionalData);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.vexsoftware.votifier.model;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class VoteTest {
|
||||
@Test
|
||||
public void testVoteConstructFromJsonObject() {
|
||||
|
||||
String serviceName = "serviceNameA";
|
||||
String username = "usernameA";
|
||||
String address = "home";
|
||||
String timestamp = "1234";
|
||||
|
||||
JsonObject o = new JsonObject();
|
||||
o.addProperty("serviceName", serviceName);
|
||||
o.addProperty("username", username);
|
||||
o.addProperty("address", address);
|
||||
o.addProperty("timestamp", timestamp);
|
||||
|
||||
Vote v = new Vote(o);
|
||||
|
||||
assertEquals(serviceName, v.getServiceName());
|
||||
assertEquals(username, v.getUsername());
|
||||
assertEquals(address, v.getAddress());
|
||||
assertEquals(timestamp, v.getTimeStamp());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVoteConstructFromJsonObjectLongTS() {
|
||||
|
||||
String serviceName = "serviceNameA";
|
||||
String username = "usernameA";
|
||||
String address = "home";
|
||||
|
||||
JsonObject o = new JsonObject();
|
||||
o.addProperty("serviceName", serviceName);
|
||||
o.addProperty("username", username);
|
||||
o.addProperty("address", address);
|
||||
o.addProperty("timestamp", 1234);
|
||||
|
||||
Vote v = new Vote(o);
|
||||
|
||||
assertEquals(serviceName, v.getServiceName());
|
||||
assertEquals(username, v.getUsername());
|
||||
assertEquals(address, v.getAddress());
|
||||
assertEquals("1234", v.getTimeStamp());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVoteSerialize() {
|
||||
Vote v = new Vote("service", "username", "address", "1234");
|
||||
JsonObject o = v.serialize();
|
||||
|
||||
assertEquals(4, o.size());
|
||||
assertEquals("service", o.get("serviceName").getAsString());
|
||||
assertEquals("username", o.get("username").getAsString());
|
||||
assertEquals("address", o.get("address").getAsString());
|
||||
assertEquals("1234", o.get("timestamp").getAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVoteEquals() {
|
||||
Vote v1 = new Vote("service", "username", "address", "1234");
|
||||
assertEquals(v1, v1);
|
||||
assertEquals(v1.hashCode(), new Vote("service", "username", "address", "1234").hashCode());
|
||||
assertEquals(v1, new Vote("service", "username", "address", "1234"));
|
||||
assertNotEquals(v1, new Object());
|
||||
assertNotEquals(v1, null);
|
||||
assertNotEquals(v1, new Vote("service2", "username", "address", "1234"));
|
||||
assertNotEquals(v1, new Vote("service", "username1", "address", "1234"));
|
||||
assertNotEquals(v1, new Vote("service", "username", "address1", "1234"));
|
||||
assertNotEquals(v1, new Vote("service", "username", "address", "12345"));
|
||||
}
|
||||
}
|
||||
+37
-5
@@ -1,28 +1,60 @@
|
||||
|
||||
import org.apache.tools.ant.filters.ReplaceTokens
|
||||
|
||||
plugins {
|
||||
id "com.github.spotbugs" version "4.2.4" apply false
|
||||
id "net.kyori.blossom" version "1.1.0" apply false
|
||||
}
|
||||
|
||||
allprojects {
|
||||
group 'com.vexsoftware'
|
||||
version '3.0.0-SNAPSHOT'
|
||||
version '2.7.2'
|
||||
}
|
||||
|
||||
subprojects {
|
||||
apply plugin: 'java'
|
||||
apply plugin: "com.github.spotbugs"
|
||||
|
||||
sourceCompatibility = 1.8
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven {
|
||||
url 'https://nexus.ibj.io/repository/maven-public/'
|
||||
url "https://hub.spigotmc.org/nexus/content/repositories/snapshots"
|
||||
}
|
||||
maven {
|
||||
url "https://oss.sonatype.org/content/repositories/snapshots"
|
||||
}
|
||||
maven {
|
||||
url "https://repo.spongepowered.org/maven"
|
||||
}
|
||||
maven {
|
||||
url "https://repo.velocitypowered.com/snapshots/"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-api:5.4.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 {
|
||||
filter(ReplaceTokens, tokens: ["app.version": this.project.version])
|
||||
}
|
||||
}
|
||||
|
||||
if (System.env.PUBLISH) {
|
||||
apply from: 'publish.gradle'
|
||||
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
@@ -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,8 @@
|
||||
|
||||
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;
|
||||
import com.vexsoftware.votifier.support.forwarding.ForwardedVoteListener;
|
||||
import com.vexsoftware.votifier.support.forwarding.ForwardingVoteSink;
|
||||
@@ -33,20 +33,20 @@ 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;
|
||||
@@ -61,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.
|
||||
*/
|
||||
@@ -99,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.
|
||||
@@ -124,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
|
||||
@@ -164,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 {
|
||||
@@ -273,10 +269,8 @@ 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));
|
||||
|
||||
if (!loadAndBind()) {
|
||||
gracefulExit();
|
||||
@@ -290,17 +284,7 @@ public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, Votifie
|
||||
getLogger().info("Votifier disabled.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (sender instanceof ConsoleCommandSender) {
|
||||
reload();
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.RED + "For security and stability, only console may run this command!");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void reload() {
|
||||
public boolean reload() {
|
||||
try {
|
||||
halt();
|
||||
} catch (Exception ex) {
|
||||
@@ -309,6 +293,7 @@ public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, Votifie
|
||||
|
||||
if (loadAndBind()) {
|
||||
getLogger().info("Reload was successful.");
|
||||
return true;
|
||||
} else {
|
||||
try {
|
||||
halt();
|
||||
@@ -316,6 +301,7 @@ public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, Votifie
|
||||
} catch (Exception ex) {
|
||||
getLogger().log(Level.SEVERE, "On reload, there was a problem loading, and we could not re-halt the server. Votifier is in an unstable state!", ex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,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;
|
||||
@@ -357,28 +334,24 @@ public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, Votifie
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVoteReceived(Channel channel, final Vote vote, VotifierSession.ProtocolVersion protocolVersion) {
|
||||
public void onVoteReceived(final Vote vote, VotifierSession.ProtocolVersion protocolVersion, String remoteAddress) {
|
||||
if (debug) {
|
||||
if (protocolVersion == VotifierSession.ProtocolVersion.ONE) {
|
||||
getLogger().info("Got a protocol v1 vote record from " + channel.remoteAddress() + " -> " + vote);
|
||||
} else {
|
||||
getLogger().info("Got a protocol v2 vote record from " + channel.remoteAddress() + " -> " + vote);
|
||||
}
|
||||
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
|
||||
public void onError(Channel channel, boolean alreadyHandledVote, Throwable throwable) {
|
||||
public void onError(Throwable throwable, boolean alreadyHandledVote, String remoteAddress) {
|
||||
if (debug) {
|
||||
if (alreadyHandledVote) {
|
||||
getLogger().log(Level.SEVERE, "Vote processed, however an exception " +
|
||||
"occurred with a vote from " + channel.remoteAddress(), throwable);
|
||||
"occurred with a vote from " + remoteAddress, throwable);
|
||||
} else {
|
||||
getLogger().log(Level.SEVERE, "Unable to process vote from " + channel.remoteAddress(), throwable);
|
||||
getLogger().log(Level.SEVERE, "Unable to process vote from " + remoteAddress, throwable);
|
||||
}
|
||||
} else if (!alreadyHandledVote) {
|
||||
getLogger().log(Level.SEVERE, "Unable to process vote from " + channel.remoteAddress());
|
||||
getLogger().log(Level.SEVERE, "Unable to process vote from " + remoteAddress);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -387,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));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.vexsoftware.votifier.cmd;
|
||||
|
||||
import com.vexsoftware.votifier.NuVotifierBukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public class NVReloadCmd implements CommandExecutor {
|
||||
|
||||
private final NuVotifierBukkit plugin;
|
||||
|
||||
public NVReloadCmd(NuVotifierBukkit plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (sender.hasPermission("nuvotifier.reload")) {
|
||||
sender.sendMessage(ChatColor.GRAY + "Reloading NuVotifier...");
|
||||
if (plugin.reload()) {
|
||||
sender.sendMessage(ChatColor.DARK_GREEN + "NuVotifier has been reloaded!");
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.DARK_RED + "Looks like there was a problem reloading NuVotifier, check the console!");
|
||||
}
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.DARK_RED + "You do not have permission to do this!");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.vexsoftware.votifier.cmd;
|
||||
|
||||
import com.vexsoftware.votifier.NuVotifierBukkit;
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
import com.vexsoftware.votifier.net.VotifierSession;
|
||||
import com.vexsoftware.votifier.util.ArgsToVote;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public class TestVoteCmd implements CommandExecutor {
|
||||
|
||||
private final NuVotifierBukkit plugin;
|
||||
|
||||
public TestVoteCmd(NuVotifierBukkit plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (sender.hasPermission("nuvotifier.testvote")) {
|
||||
Vote v;
|
||||
try {
|
||||
v = ArgsToVote.parse(args);
|
||||
} catch (IllegalArgumentException e) {
|
||||
sender.sendMessage(ChatColor.DARK_RED + "Error while parsing arguments to create test vote: " + e.getMessage());
|
||||
sender.sendMessage(ChatColor.GRAY + "Usage hint: /testvote [username] [serviceName=?] [username=?] [address=?] [localTimestamp=?] [timestamp=?]");
|
||||
return true;
|
||||
}
|
||||
|
||||
plugin.onVoteReceived(v, VotifierSession.ProtocolVersion.TEST, "localhost.test");
|
||||
sender.sendMessage(ChatColor.GREEN + "Test vote executed: " + v.toString());
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.DARK_RED + "You do not have permission to do this!");
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -37,7 +37,7 @@ public class BukkitPluginMessagingForwardingSink extends AbstractPluginMessaging
|
||||
try {
|
||||
this.handlePluginMessage(bytes);
|
||||
} catch (Exception e) {
|
||||
NuVotifierBukkit.getInstance().getLogger().log(Level.SEVERE, "There was an unknown error when processing a forwarded vote.", e);
|
||||
p.getLogger().log(Level.SEVERE, "There was an unknown error when processing a forwarded vote.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,19 @@ api-version: 1.13
|
||||
commands:
|
||||
nvreload:
|
||||
description: Reloads the NuVotifier configuration
|
||||
permission: nuvotifier.console
|
||||
permission: nuvotifier.reload
|
||||
permission-message: "You do not have permission to run this command."
|
||||
usage: "/nvreload"
|
||||
usage: "/nvreload"
|
||||
testvote:
|
||||
description: Sends a test vote to the server
|
||||
permission: nuvotifier.testvote
|
||||
permission-message: "You do not have permission to run this command."
|
||||
usage: "/testvote [username] [serviceName=?] [username=?] [address=?] [localTimestamp=?] [timestamp=?]"
|
||||
|
||||
permissions:
|
||||
nuvotifier.reload:
|
||||
description: Allows you to reload the NuVotifier plugin
|
||||
default: op
|
||||
nuvotifier.testvote:
|
||||
description: Allows you to send a test vote
|
||||
default: op
|
||||
@@ -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,9 +1,9 @@
|
||||
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;
|
||||
import com.vexsoftware.votifier.net.VotifierServerBootstrap;
|
||||
import com.vexsoftware.votifier.platform.BackendServer;
|
||||
import com.vexsoftware.votifier.platform.JavaUtilLogger;
|
||||
@@ -21,26 +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.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.*;
|
||||
@@ -81,10 +81,10 @@ public class NuVotifier extends Plugin implements VoteHandler, ProxyVotifierPlug
|
||||
private LoggingAdapter pluginLogger;
|
||||
|
||||
private void loadAndBind() {
|
||||
scheduler = new BungeeScheduler(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.
|
||||
@@ -98,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
|
||||
@@ -141,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 {
|
||||
@@ -161,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);
|
||||
@@ -220,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) {
|
||||
@@ -253,6 +257,7 @@ public class NuVotifier extends Plugin implements VoteHandler, ProxyVotifierPlug
|
||||
String fallbackServer = fwdCfg.getString("pluginMessaging.joinedServerFallback", null);
|
||||
if (fallbackServer != null && fallbackServer.isEmpty()) fallbackServer = null;
|
||||
forwardingMethod = new OnlineForwardPluginMessagingForwardingSource(channel, this, filter, voteCache, fallbackServer, dumpRate);
|
||||
getLogger().info("Forwarding votes over PluginMessaging channel '" + channel + "' for vote forwarding for online players!");
|
||||
} catch (RuntimeException e) {
|
||||
getLogger().log(Level.SEVERE, "NuVotifier could not set up PluginMessaging for vote forwarding!", e);
|
||||
}
|
||||
@@ -287,7 +292,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.");
|
||||
@@ -296,17 +301,15 @@ public class NuVotifier extends Plugin implements VoteHandler, ProxyVotifierPlug
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
loadAndBind();
|
||||
scheduler = new BungeeScheduler(this);
|
||||
pluginLogger = new JavaUtilLogger(getLogger());
|
||||
|
||||
getProxy().getPluginManager().registerCommand(this, new Command("nvreload") {
|
||||
@Override
|
||||
public void execute(CommandSender sender, String[] args) {
|
||||
if (sender instanceof ProxiedPlayer)
|
||||
sender.sendMessage(ChatColor.RED + "For security and stability, only console may run this command!");
|
||||
else
|
||||
reload();
|
||||
}
|
||||
});
|
||||
PluginManager pm = ProxyServer.getInstance().getPluginManager();
|
||||
pm.registerCommand(this, new NVReloadCmd(this));
|
||||
pm.registerCommand(this, new TestVoteCmd(this));
|
||||
pm.registerListener(this, new ReloadListener(this));
|
||||
|
||||
loadAndBind();
|
||||
}
|
||||
|
||||
private void halt() {
|
||||
@@ -322,7 +325,7 @@ public class NuVotifier extends Plugin implements VoteHandler, ProxyVotifierPlug
|
||||
}
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
public boolean reload() {
|
||||
try {
|
||||
halt();
|
||||
} catch (Exception ex) {
|
||||
@@ -332,6 +335,7 @@ public class NuVotifier extends Plugin implements VoteHandler, ProxyVotifierPlug
|
||||
try {
|
||||
loadAndBind();
|
||||
getLogger().info("Reload was successful.");
|
||||
return true;
|
||||
} catch (Exception ex) {
|
||||
try {
|
||||
halt();
|
||||
@@ -340,6 +344,7 @@ public class NuVotifier extends Plugin implements VoteHandler, ProxyVotifierPlug
|
||||
getLogger().log(Level.SEVERE, "On reload, there was a problem loading, and we could not re-halt the server. Votifier is in an unstable state!", ex);
|
||||
getLogger().log(Level.SEVERE, "(halt exception)", ex2);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,12 +355,12 @@ public class NuVotifier extends Plugin implements VoteHandler, ProxyVotifierPlug
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVoteReceived(Channel channel, final Vote vote, VotifierSession.ProtocolVersion protocolVersion) {
|
||||
public void onVoteReceived(final Vote vote, VotifierSession.ProtocolVersion protocolVersion, String remoteAddress) {
|
||||
if (debug) {
|
||||
if (protocolVersion == VotifierSession.ProtocolVersion.ONE) {
|
||||
getLogger().info("Got a protocol v1 vote record from " + channel.remoteAddress() + " -> " + vote);
|
||||
getLogger().info("Got a protocol v1 vote record from " + remoteAddress + " -> " + vote);
|
||||
} else {
|
||||
getLogger().info("Got a protocol v2 vote record from " + channel.remoteAddress() + " -> " + vote);
|
||||
getLogger().info("Got a protocol v2 vote record from " + remoteAddress + " -> " + vote);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,16 +372,16 @@ public class NuVotifier extends Plugin implements VoteHandler, ProxyVotifierPlug
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Channel channel, boolean alreadyHandledVote, Throwable throwable) {
|
||||
public void onError(Throwable throwable, boolean alreadyHandledVote, String remoteAddress) {
|
||||
if (debug) {
|
||||
if (alreadyHandledVote) {
|
||||
getLogger().log(Level.SEVERE, "Vote processed, however an exception " +
|
||||
"occurred with a vote from " + channel.remoteAddress(), throwable);
|
||||
"occurred with a vote from " + remoteAddress, throwable);
|
||||
} else {
|
||||
getLogger().log(Level.SEVERE, "Unable to process vote from " + channel.remoteAddress(), throwable);
|
||||
getLogger().log(Level.SEVERE, "Unable to process vote from " + remoteAddress, throwable);
|
||||
}
|
||||
} else if (!alreadyHandledVote) {
|
||||
getLogger().log(Level.SEVERE, "Unable to process vote from " + channel.remoteAddress());
|
||||
getLogger().log(Level.SEVERE, "Unable to process vote from " + remoteAddress);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.vexsoftware.votifier.bungee.cmd;
|
||||
|
||||
import com.vexsoftware.votifier.bungee.NuVotifier;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
|
||||
public class NVReloadCmd extends Command {
|
||||
|
||||
private final NuVotifier plugin;
|
||||
|
||||
private static final BaseComponent reloadingNuVotifier = new TextComponent("Reloading NuVotifier...");
|
||||
private static final BaseComponent nuvotifierHasBeenReloaded = new TextComponent("NuVotifier has been reloaded!");
|
||||
private static final BaseComponent problem = new TextComponent("Looks like there was a problem reloading NuVotifier, check the console!");
|
||||
private static final BaseComponent permission = new TextComponent("You do not have permission to do this!");
|
||||
|
||||
static {
|
||||
reloadingNuVotifier.setColor(ChatColor.GRAY);
|
||||
nuvotifierHasBeenReloaded.setColor(ChatColor.DARK_GREEN);
|
||||
problem.setColor(ChatColor.DARK_RED);
|
||||
permission.setColor(ChatColor.DARK_RED);
|
||||
}
|
||||
|
||||
public NVReloadCmd(NuVotifier plugin) {
|
||||
super("pnvreload", "nuvotifier.reload");
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender, String[] args) {
|
||||
if (sender.hasPermission("nuvotifier.reload")) {
|
||||
sender.sendMessage(reloadingNuVotifier);
|
||||
if (plugin.reload()) {
|
||||
sender.sendMessage(nuvotifierHasBeenReloaded);
|
||||
} else {
|
||||
sender.sendMessage(problem);
|
||||
}
|
||||
} else {
|
||||
sender.sendMessage(permission);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.vexsoftware.votifier.bungee.cmd;
|
||||
|
||||
import com.vexsoftware.votifier.bungee.NuVotifier;
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
import com.vexsoftware.votifier.net.VotifierSession;
|
||||
import com.vexsoftware.votifier.util.ArgsToVote;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
|
||||
public class TestVoteCmd extends Command {
|
||||
|
||||
private final NuVotifier plugin;
|
||||
|
||||
private static final BaseComponent permission = new TextComponent("You do not have permission to do this!");
|
||||
private static final BaseComponent usage = new TextComponent("Usage hint: /ptestvote [username] [serviceName=?] [username=?] [address=?] [localTimestamp=?] [timestamp=?]");
|
||||
|
||||
static {
|
||||
usage.setColor(ChatColor.GRAY);
|
||||
}
|
||||
|
||||
public TestVoteCmd(NuVotifier plugin) {
|
||||
super("ptestvote", "nuvotifier.testvote");
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender, String[] args) {
|
||||
if (sender.hasPermission("nuvotifier.testvote")) {
|
||||
Vote v;
|
||||
try {
|
||||
v = ArgsToVote.parse(args);
|
||||
} catch (IllegalArgumentException e) {
|
||||
TextComponent c = new TextComponent("Error while parsing arguments to create test vote: " + e.getMessage());
|
||||
c.setColor(ChatColor.DARK_RED);
|
||||
sender.sendMessage(c);
|
||||
sender.sendMessage(usage);
|
||||
return;
|
||||
}
|
||||
|
||||
plugin.onVoteReceived(v, VotifierSession.ProtocolVersion.TEST, "localhost.test");
|
||||
TextComponent c = new TextComponent("Test vote executed: " + v.toString());
|
||||
c.setColor(ChatColor.GREEN);
|
||||
sender.sendMessage(c);
|
||||
} else {
|
||||
sender.sendMessage(permission);
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-5
@@ -1,7 +1,8 @@
|
||||
dependencies {
|
||||
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: "junit", name: "junit", version: "4.12"
|
||||
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'
|
||||
}
|
||||
@@ -5,16 +5,11 @@ import com.vexsoftware.votifier.net.VotifierSession;
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
public interface VoteHandler {
|
||||
void onVoteReceived(Channel channel, Vote vote, VotifierSession.ProtocolVersion protocolVersion) throws Exception;
|
||||
|
||||
// these default members are kept for compatibility sake - there probably isn't anyone out there implementing these
|
||||
// on their own, but we still deprecate them before removing them because we are nice!
|
||||
default void onError(Channel channel, boolean voteAlreadyCompleted, Throwable throwable) {
|
||||
onError(channel, throwable);
|
||||
}
|
||||
void onVoteReceived(Vote vote, VotifierSession.ProtocolVersion protocolVersion, String remoteAddress) throws Exception;
|
||||
|
||||
@Deprecated
|
||||
default void onError(Channel channel, Throwable throwable) {
|
||||
default void onError(Throwable throwable, boolean voteAlreadyCompleted, String remoteAddress) {
|
||||
throw new RuntimeException("Unimplemented onError handler");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -40,8 +40,14 @@ public class VotifierSession {
|
||||
}
|
||||
|
||||
public enum ProtocolVersion {
|
||||
UNKNOWN,
|
||||
ONE,
|
||||
TWO
|
||||
UNKNOWN("unknown"),
|
||||
ONE("protocol v1"),
|
||||
TWO("protocol v2"),
|
||||
TEST("test");
|
||||
|
||||
public final String humanReadable;
|
||||
ProtocolVersion(String hr) {
|
||||
this.humanReadable = hr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,21 +6,29 @@ 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
|
||||
protected void channelRead0(ChannelHandlerContext ctx, final Vote vote) throws Exception {
|
||||
VotifierSession session = ctx.channel().attr(VotifierSession.KEY).get();
|
||||
|
||||
handler.onVoteReceived(ctx.channel(), vote, session.getVersion());
|
||||
handler.onVoteReceived(vote, session.getVersion(), ctx.channel().remoteAddress().toString());
|
||||
session.completeVote();
|
||||
|
||||
if (session.getVersion() == VotifierSession.ProtocolVersion.ONE) {
|
||||
@@ -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(ctx.channel(), session.hasCompletedVote(), cause);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
@@ -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();
|
||||
|
||||
+24
-9
@@ -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.
|
||||
|
||||
+6
-8
@@ -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;
|
||||
|
||||
|
||||
+2
-3
@@ -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
|
||||
|
||||
+5
-1
@@ -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;
|
||||
|
||||
+26
-21
@@ -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,9 +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);
|
||||
} catch (FileNotFoundException e) {
|
||||
if (object == null) {
|
||||
// When the input is not malformed but instead empty, this returns null. Simply assume it is empty.
|
||||
object = new JsonObject();
|
||||
}
|
||||
} catch (NoSuchFileException e) {
|
||||
object = new JsonObject();
|
||||
}
|
||||
|
||||
@@ -73,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) {
|
||||
@@ -98,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
|
||||
@@ -112,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)) {
|
||||
|
||||
Vendored
+78
-23
@@ -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,20 +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;
|
||||
// scale voteTTL to milliseconds
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -10,7 +10,7 @@ import com.vexsoftware.votifier.model.Vote;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
|
||||
import io.netty.handler.codec.Delimiters;
|
||||
import io.netty.handler.codec.string.StringDecoder;
|
||||
@@ -53,9 +53,9 @@ public class ProxyForwardingVoteSource implements ForwardingVoteSource {
|
||||
|
||||
private void forwardVote(final BackendServer server, final Vote v, final int tries) {
|
||||
nettyBootstrap.get()
|
||||
.handler(new ChannelInitializer<NioSocketChannel>() {
|
||||
.handler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
protected void initChannel(NioSocketChannel channel) {
|
||||
protected void initChannel(SocketChannel channel) {
|
||||
channel.pipeline().addLast(new DelimiterBasedFrameDecoder(256, true, Delimiters.lineDelimiter()));
|
||||
channel.pipeline().addLast(new ReadTimeoutHandler(5, TimeUnit.SECONDS));
|
||||
channel.pipeline().addLast(STRING_DECODER);
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.vexsoftware.votifier.util;
|
||||
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ArgsToVote {
|
||||
|
||||
private static final Pattern argumentPattern = Pattern.compile("([a-zA-Z]+)=(\\S*)");
|
||||
|
||||
public static Vote parse(String[] arguments) {
|
||||
return parse(arguments, null);
|
||||
}
|
||||
|
||||
public static Vote parse(String[] arguments, Map<String, String> additionalArgs) {
|
||||
String serviceName = "TestVote";
|
||||
String username = null;
|
||||
String address = "127.0.0.1";
|
||||
long localTimestamp = System.currentTimeMillis();
|
||||
String timestamp = Long.toString(localTimestamp, 10);
|
||||
|
||||
for (String s : arguments) {
|
||||
Matcher m = argumentPattern.matcher(s);
|
||||
if (m.matches()) {
|
||||
String key = m.group(1).toLowerCase();
|
||||
String v = m.group(2);
|
||||
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 {
|
||||
if (s.length() > 16)
|
||||
throw new IllegalArgumentException("Illegal username - must be less than 16 characters long.");
|
||||
username = s; // ezpz
|
||||
}
|
||||
}
|
||||
|
||||
if (username == null)
|
||||
throw new IllegalArgumentException("Username not specified!");
|
||||
|
||||
return new Vote(serviceName, username, address, timestamp);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
+4
-5
@@ -1,14 +1,13 @@
|
||||
package com.vexsoftware.votifier.util.standalone;
|
||||
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
import com.vexsoftware.votifier.net.VotifierServerBootstrap;
|
||||
import com.vexsoftware.votifier.net.VotifierSession;
|
||||
import com.vexsoftware.votifier.platform.JavaUtilLogger;
|
||||
import com.vexsoftware.votifier.platform.LoggingAdapter;
|
||||
import com.vexsoftware.votifier.platform.VotifierPlugin;
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
import com.vexsoftware.votifier.net.VotifierSession;
|
||||
import com.vexsoftware.votifier.platform.scheduler.ScheduledExecutorServiceVotifierScheduler;
|
||||
import com.vexsoftware.votifier.platform.scheduler.VotifierScheduler;
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.security.Key;
|
||||
@@ -69,12 +68,12 @@ public class StandaloneVotifierPlugin implements VotifierPlugin {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVoteReceived(Channel channel, Vote vote, VotifierSession.ProtocolVersion protocolVersion) throws Exception {
|
||||
public void onVoteReceived(Vote vote, VotifierSession.ProtocolVersion protocolVersion, String remoteAddress) throws Exception {
|
||||
receiver.onVote(vote);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Channel channel, boolean alreadyHandledVote, Throwable throwable) {
|
||||
public void onError(Throwable throwable, boolean alreadyHandledVote, String remoteAddress) {
|
||||
receiver.onException(throwable);
|
||||
}
|
||||
}
|
||||
@@ -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"));
|
||||
@@ -96,7 +101,7 @@ public class TestVotifierPlugin implements VotifierPlugin {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVoteReceived(Channel channel, Vote vote, VotifierSession.ProtocolVersion protocolVersion) throws Exception {
|
||||
public void onVoteReceived(Vote vote, VotifierSession.ProtocolVersion protocolVersion, String remoteAddress) throws Exception {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
+11
-15
@@ -4,18 +4,20 @@ 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 org.junit.Test;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.PublicKey;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class VotifierProtocol1DecoderTest {
|
||||
private static final VotifierSession SESSION = new VotifierSession();
|
||||
@@ -50,24 +52,21 @@ public class VotifierProtocol1DecoderTest {
|
||||
byte[] encrypted = RSA.encrypt(bad.getBytes(StandardCharsets.UTF_8), TestVotifierPlugin.getI().getProtocolV1Key().getPublic());
|
||||
ByteBuf encryptedByteBuf = Unpooled.wrappedBuffer(encrypted);
|
||||
|
||||
try {
|
||||
channel.writeInbound(encryptedByteBuf);
|
||||
} finally {
|
||||
channel.close();
|
||||
}
|
||||
assertThrows(DecoderException.class, () -> channel.writeInbound(encryptedByteBuf));
|
||||
channel.close();
|
||||
}
|
||||
|
||||
@Test(expected = CorruptedFrameException.class)
|
||||
@Test
|
||||
public void testFailureDecodeMissingField() throws Exception {
|
||||
verifyFailure("VOTE\nTest\ntest\ntest"); // missing field
|
||||
}
|
||||
|
||||
@Test(expected = CorruptedFrameException.class)
|
||||
@Test
|
||||
public void testFailureDecodeBadOpcode() throws Exception {
|
||||
verifyFailure("TEST\nTest\ntest\ntest\ntest\n");
|
||||
}
|
||||
|
||||
@Test(expected = CorruptedFrameException.class)
|
||||
@Test
|
||||
public void testFailureDecodeBadRsa() throws Exception {
|
||||
// Decode our bad RSA key
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
@@ -80,10 +79,7 @@ public class VotifierProtocol1DecoderTest {
|
||||
byte[] encrypted = VoteUtil.encodePOJOv1(new Vote("Test", "test", "test", "test"), badPublicKey);
|
||||
ByteBuf encryptedByteBuf = Unpooled.wrappedBuffer(encrypted);
|
||||
|
||||
try {
|
||||
channel.writeInbound(encryptedByteBuf);
|
||||
} finally {
|
||||
channel.close();
|
||||
}
|
||||
assertThrows(DecoderException.class, ()->channel.writeInbound(encryptedByteBuf));
|
||||
channel.close();
|
||||
}
|
||||
}
|
||||
+18
-29
@@ -10,14 +10,14 @@ import io.netty.channel.embedded.EmbeddedChannel;
|
||||
import io.netty.handler.codec.CorruptedFrameException;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.Key;
|
||||
import java.util.Base64;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class VotifierProtocol2DecoderTest {
|
||||
private static final VotifierSession SESSION = new VotifierSession();
|
||||
@@ -61,7 +61,7 @@ public class VotifierProtocol2DecoderTest {
|
||||
sendVote(new Vote("Test", "test", "test", "0"), TestVotifierPlugin.getI().getTokens().get("default"), true);
|
||||
}
|
||||
|
||||
@Test(expected = DecoderException.class)
|
||||
@Test
|
||||
public void testFailureDecodeBadPacket() {
|
||||
// Create a well-formed request
|
||||
EmbeddedChannel channel = createChannel();
|
||||
@@ -73,14 +73,11 @@ public class VotifierProtocol2DecoderTest {
|
||||
object.put("payload", GsonInst.gson.toJson(payload));
|
||||
// We "forget" the signature.
|
||||
|
||||
try {
|
||||
channel.writeInbound(object.toString());
|
||||
} finally {
|
||||
channel.close();
|
||||
}
|
||||
assertThrows(DecoderException.class, () -> channel.writeInbound(object.toString()));
|
||||
channel.close();
|
||||
}
|
||||
|
||||
@Test(expected = DecoderException.class)
|
||||
@Test
|
||||
public void testFailureDecodeBadVoteField() throws Exception {
|
||||
// Create a well-formed request
|
||||
EmbeddedChannel channel = createChannel();
|
||||
@@ -96,14 +93,11 @@ public class VotifierProtocol2DecoderTest {
|
||||
object.put("signature",
|
||||
Base64.getEncoder().encodeToString(mac.doFinal(payloadEncoded.getBytes(StandardCharsets.UTF_8))));
|
||||
|
||||
try {
|
||||
channel.writeInbound(object.toString());
|
||||
} finally {
|
||||
channel.close();
|
||||
}
|
||||
assertThrows(DecoderException.class, () -> channel.writeInbound(object.toString()));
|
||||
channel.close();
|
||||
}
|
||||
|
||||
@Test(expected = DecoderException.class)
|
||||
@Test
|
||||
public void testFailureDecodeBadChallenge() throws Exception {
|
||||
// Create a well-formed request
|
||||
EmbeddedChannel channel = createChannel();
|
||||
@@ -120,29 +114,24 @@ public class VotifierProtocol2DecoderTest {
|
||||
object.put("signature",
|
||||
Base64.getEncoder().encode(mac.doFinal(payloadEncoded.getBytes(StandardCharsets.UTF_8))));
|
||||
|
||||
try {
|
||||
channel.writeInbound(object.toString());
|
||||
} finally {
|
||||
channel.close();
|
||||
}
|
||||
assertThrows(DecoderException.class, () -> channel.writeInbound(object.toString()));
|
||||
channel.close();
|
||||
}
|
||||
|
||||
@Test(expected = DecoderException.class)
|
||||
@Test
|
||||
public void testFailureDecodeNonExistentKey() throws Exception {
|
||||
TestVotifierPlugin.getI().specificKeysOnly();
|
||||
|
||||
Vote vote = new Vote("Bad Service", "test", "test", "0");
|
||||
|
||||
try {
|
||||
sendVote(vote, TestVotifierPlugin.getI().getTokens().get("Test"), false);
|
||||
} finally {
|
||||
TestVotifierPlugin.getI().restoreDefault();
|
||||
}
|
||||
assertThrows(DecoderException.class, () -> sendVote(vote, TestVotifierPlugin.getI().getTokens().get("Test"), false));
|
||||
|
||||
TestVotifierPlugin.getI().restoreDefault();
|
||||
}
|
||||
|
||||
@Test(expected = CorruptedFrameException.class)
|
||||
public void testFailureDecodeBadSignature() throws Exception {
|
||||
@Test
|
||||
public void testFailureDecodeBadSignature() {
|
||||
Vote vote = new Vote("Bad Service", "test", "test", "0");
|
||||
sendVote(vote, KeyCreator.createKeyFrom("BadKey"), false);
|
||||
assertThrows(CorruptedFrameException.class, () -> sendVote(vote, KeyCreator.createKeyFrom("BadKey"), false));
|
||||
}
|
||||
}
|
||||
+10
-12
@@ -2,13 +2,16 @@ 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;
|
||||
import io.netty.handler.codec.CorruptedFrameException;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
public class VotifierProtocolDifferentiatorTest {
|
||||
@Test
|
||||
@@ -43,7 +46,7 @@ public class VotifierProtocolDifferentiatorTest {
|
||||
channel.close();
|
||||
}
|
||||
|
||||
@Test(expected = DecoderException.class)
|
||||
@Test
|
||||
public void failIfv1NotSupported() {
|
||||
EmbeddedChannel channel = new EmbeddedChannel(new VotifierProtocolDifferentiator(true, false));
|
||||
|
||||
@@ -54,13 +57,11 @@ public class VotifierProtocolDifferentiatorTest {
|
||||
for (int i = 0; i < 256; i++) {
|
||||
test.writeByte(0);
|
||||
}
|
||||
channel.writeInbound(test);
|
||||
|
||||
assertEquals(VotifierSession.ProtocolVersion.ONE, session.getVersion());
|
||||
assertThrows(DecoderException.class, () -> channel.writeInbound(test));
|
||||
channel.close();
|
||||
}
|
||||
|
||||
@Test(expected = DecoderException.class)
|
||||
@Test
|
||||
public void failOnBadPacketTest() {
|
||||
EmbeddedChannel channel = new EmbeddedChannel(new VotifierProtocolDifferentiator(true, false));
|
||||
|
||||
@@ -69,11 +70,8 @@ public class VotifierProtocolDifferentiatorTest {
|
||||
buf.writeByte(0);
|
||||
}
|
||||
|
||||
try {
|
||||
channel.writeInbound(buf);
|
||||
} finally {
|
||||
channel.close();
|
||||
}
|
||||
assertThrows(DecoderException.class, () -> channel.writeInbound(buf));
|
||||
channel.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+10
-10
@@ -1,26 +1,26 @@
|
||||
package com.vexsoftware.votifier.support.forwarding;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
import com.vexsoftware.votifier.support.forwarding.ForwardedVoteListener;
|
||||
import org.junit.Test;
|
||||
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.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
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", System.currentTimeMillis())
|
||||
);
|
||||
new Vote("serviceB", "usernameBBBBBBB", "1.2.23.4", "1514764800")
|
||||
));
|
||||
|
||||
StringBuilder message = new StringBuilder();
|
||||
|
||||
@@ -28,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();
|
||||
}
|
||||
}
|
||||
+16
-6
@@ -1,22 +1,32 @@
|
||||
|
||||
.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/viaversion.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.16.2/182/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.3.0/spongevanilla-1.12.2-7.3.0.jar
|
||||
|
||||
resources/viaversion.jar : resources
|
||||
wget -O resources/viaversion.jar https://ci.viaversion.com/job/ViaVersion/459/artifact/jar/target/ViaVersion-3.1.1-SNAPSHOT.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
@@ -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.16.1) | 25565 | 8194 |
|
||||
| s2 | SpongeVanilla (1.12.2) | 25566 | 8195 |
|
||||
|
||||
For compatibility with 1.16.1, s2 includes ViaVersion.
|
||||
File renamed without changes.
@@ -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.
@@ -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.
|
||||
@@ -66,9 +66,9 @@ forwarding:
|
||||
proxy:
|
||||
Hub:
|
||||
address: 127.0.0.1
|
||||
port: 8193
|
||||
token: MyKeyHere
|
||||
port: 8194
|
||||
token: server1token
|
||||
Hub2:
|
||||
address: 127.0.0.1
|
||||
port: 8194
|
||||
token: AnotherKeyHere
|
||||
port: 8195
|
||||
token: server2token
|
||||
File renamed without changes.
Symlink
+1
@@ -0,0 +1 @@
|
||||
../resources/waterfall.jar
|
||||
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
|
||||
@@ -0,0 +1 @@
|
||||
logs/
|
||||
File renamed without changes.
@@ -0,0 +1,2 @@
|
||||
rsa/
|
||||
cached-votes.json
|
||||
@@ -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 = false
|
||||
|
||||
# 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 = 8194
|
||||
token = "server1token"
|
||||
|
||||
[forwarding.proxy.Hub2]
|
||||
address = "127.0.0.1"
|
||||
port = 8195
|
||||
token = "server2token"
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../resources/velocity.jar
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
|
||||
cd $DIR
|
||||
|
||||
java -jar proxy.jar
|
||||
@@ -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 +0,0 @@
|
||||
rsa/
|
||||
@@ -1 +0,0 @@
|
||||
../resources/proxy.jar
|
||||
+1
-1
@@ -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
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
|
||||
settings:
|
||||
minimum-api: none
|
||||
allow-end: true
|
||||
warn-on-overload: true
|
||||
permissions-file: permissions.yml
|
||||
@@ -23,6 +24,7 @@ settings:
|
||||
deprecated-verbose: default
|
||||
shutdown-message: Server closed
|
||||
spawn-limits:
|
||||
water-ambient: 20
|
||||
monsters: 70
|
||||
animals: 10
|
||||
water-animals: 15
|
||||
@@ -31,6 +33,9 @@ chunk-gc:
|
||||
period-in-ticks: 600
|
||||
load-threshold: 0
|
||||
ticks-per:
|
||||
water-ambient-spawns: 1
|
||||
water-spawns: 1
|
||||
ambient-spawns: 1
|
||||
animal-spawns: 400
|
||||
monster-spawns: 1
|
||||
autosave: 6000
|
||||
|
||||
+52
-6
@@ -11,8 +11,11 @@
|
||||
# Docs: https://paper.readthedocs.org/
|
||||
|
||||
verbose: false
|
||||
config-version: 16
|
||||
config-version: 20
|
||||
settings:
|
||||
max-joins-per-tick: 3
|
||||
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,20 @@ 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-headless-pistons: false
|
||||
allow-permanent-block-break-exploits: false
|
||||
allow-piston-duplication: false
|
||||
allow-permanent-block-break-exploits-readme: This setting controls if players
|
||||
should be able to break bedrock, end portals and other intended to be permanent
|
||||
blocks.
|
||||
allow-piston-duplication-readme: This setting controls if player should be able
|
||||
to use TNT duplication, but this also allows duplicating carpet, rails and potentially
|
||||
other items
|
||||
allow-headless-pistons-readme: This setting controls if players should be able
|
||||
to create headless pistons.
|
||||
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 +67,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 +78,24 @@ timings:
|
||||
history-length: 3600
|
||||
world-settings:
|
||||
default:
|
||||
zombies-target-turtle-eggs: true
|
||||
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 +104,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 +179,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 +213,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
|
||||
@@ -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.
|
||||
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../../universal/build/libs/nuvotifier.jar
|
||||
@@ -1,26 +1,36 @@
|
||||
#Minecraft server properties
|
||||
#Fri Dec 21 15:15:00 EST 2018
|
||||
#Thu Sep 03 15:49:51 EDT 2020
|
||||
spawn-protection=16
|
||||
max-tick-time=60000
|
||||
query.port=25565
|
||||
generator-settings=
|
||||
sync-chunk-writes=true
|
||||
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
|
||||
entity-broadcast-range-percentage=100
|
||||
snooper-enabled=true
|
||||
level-type=DEFAULT
|
||||
level-type=default
|
||||
hardcore=false
|
||||
enable-status=true
|
||||
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 +39,14 @@ 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
|
||||
motd=A Minecraft Server
|
||||
enable-jmx-monitoring=false
|
||||
rate-limit=0
|
||||
enable-rcon=false
|
||||
motd=A Minecraft Server
|
||||
+37
-2
@@ -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,16 @@ advancements:
|
||||
- minecraft:story/disabled
|
||||
world-settings:
|
||||
default:
|
||||
seed-bastion: 30084232
|
||||
seed-fortress: 30084232
|
||||
seed-mansion: 10387319
|
||||
seed-fossil: 14357921
|
||||
seed-portal: 34222645
|
||||
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 +102,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 +119,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 +156,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
@@ -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
|
||||
@@ -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
|
||||
@@ -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-
|
||||
@@ -0,0 +1 @@
|
||||
rsa/
|
||||
@@ -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'}
|
||||
@@ -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=[]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,697 @@
|
||||
# 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=[]
|
||||
}
|
||||
# Controls how Sponge interacts with server proxies, such as BungeeCord and Velocity.
|
||||
# Requires that the 'bungeecord' module is enabled.
|
||||
bungeecord {
|
||||
# If 'true', allows BungeeCord to forward IP address, UUID, and Game Profile to this server.
|
||||
ip-forwarding=true
|
||||
}
|
||||
# Configuration options related to Sponge's cause tracking system
|
||||
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
|
||||
}
|
||||
# Configuration options related to commands, including command aliases and hidden commands.
|
||||
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
|
||||
}
|
||||
}
|
||||
# Configuratiom options related to debugging features that are disabled by default.
|
||||
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
|
||||
}
|
||||
# Configuration options related to entities and their performance impact.
|
||||
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
|
||||
# (ranges from '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
|
||||
}
|
||||
# Allows the configuration of the default entity activation ranges.
|
||||
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 {}
|
||||
}
|
||||
# Configuration options related to entity collision checks.
|
||||
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 {}
|
||||
}
|
||||
}
|
||||
}
|
||||
# Configuration option related to sponge provided exploit patches
|
||||
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.
|
||||
# See 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
|
||||
}
|
||||
# Contains general configuration options for Sponge that don't fit into a specific classification
|
||||
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"
|
||||
}
|
||||
# Automatically assigns (permission) contexts to users that use any of the given ips.
|
||||
# This can be used to restrict/grant permissions, based on the player's source or target ip.
|
||||
ip-sets {}
|
||||
# Configuration option related to logging certain action such as chunk loading.
|
||||
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 two conflicting changes are merged into one. (This number specifies the maximum number of
|
||||
# messages to log. Set to 0 to show all messages.)
|
||||
transaction-merge-fail=25
|
||||
# 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
|
||||
}
|
||||
# Configuration options related to metric collection.
|
||||
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 {}
|
||||
}
|
||||
# Sponge provides a number of modules that allow for enabling or disabling
|
||||
# certain specific features. These may be enabled or disabled below.
|
||||
#
|
||||
# Any changes here require a server restart as modules are applied at startup.
|
||||
modules {
|
||||
# Enables experimental fixes for broken mods
|
||||
broken-mod=false
|
||||
# The BungeeCord Module, allows Sponge to be used with a Proxy like Bungeecord or Velocity.
|
||||
# Usually you want to also enable 'bungeecord.ip-forwarding' with this.
|
||||
bungeecord=true
|
||||
# The entity activation module, allows you to tweak entity activation ranges,
|
||||
# similarly to "Entity Distance" in the latest 1.16 snapshots but per mob.
|
||||
# Essentially, it changes how far an entity can be away from a player, until it stops being updated (e.g. moving).
|
||||
entity-activation-range=true
|
||||
# Module that allows you to configure the maximum amount of entities a specific entity or block can collide with.
|
||||
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
|
||||
# Module to run Aikar's Timings, profile your server performance and get a sharable web result.
|
||||
# https://github.com/aikar/timings#aikars-minecraft-timings-viewer-v2
|
||||
timings=true
|
||||
# Can be used to disable some parts of the tracking.
|
||||
tracking=true
|
||||
}
|
||||
# Configuration options related to minecraft's movement checks, that can be enabled or disabled.
|
||||
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
|
||||
}
|
||||
# Configuration options related to sponge provided performance optimizations.
|
||||
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 them. This provides an option to suppress the exceptions printing out in the log.
|
||||
disable-failing-deserialization-log-spam=true
|
||||
# In vanilla, pathfinding may result in loading chunks.
|
||||
# You can disable that here, which may result in a
|
||||
# performance improvement. This may not work well
|
||||
# with mods.
|
||||
disable-pathfinding-chunk-loads=false
|
||||
# In vanilla, ray tracing may result in loading chunks.
|
||||
# You can disable that here, which may result in a
|
||||
# performance improvement. This may not work well
|
||||
# with mods.
|
||||
disable-raytracing-chunk-loads=false
|
||||
# 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 optimizations 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
|
||||
# Global switch to enable sponge's changes to the structure saving mechansim.
|
||||
# By default, this option is disabled, i.e. saving structures is not affected.
|
||||
# If you want to prevent that a certain "named" structure is saved to the world's folder,
|
||||
# you have to enable this module/setting and disable the structure in the further settings.
|
||||
# An example of a structure that is costly and somewhat irrelevant is 'mineshaft',
|
||||
# as they build and save several structures even after the mine shafts have been completely generated.
|
||||
# However, this has the disadvantage that these structures may no longer be locatable by some mods.
|
||||
enabled=false
|
||||
# Per-mod overrides. Refer to the minecraft default mod for example.
|
||||
mods {
|
||||
minecraft {
|
||||
# Global flag, whether this mod's structures will be saved.
|
||||
# If 'false', this mod will never save its structures.
|
||||
# If 'true', it will check the 'structureList' for disabled structures.
|
||||
enabled=true
|
||||
# The configuration for each struture.
|
||||
# A value of 'false' prevents that struture from being saved.
|
||||
# Entries that are either missing in this list or have the value 'true' will still be saved,
|
||||
# unless the structure saving of the mod is globally disabled.
|
||||
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
|
||||
}
|
||||
# Configuration options related to permissions and permission handling
|
||||
permission {
|
||||
# If 'true', Sponge plugins will be used to handle permissions rather than any Forge mod
|
||||
forge-permissions-handler=false
|
||||
}
|
||||
# Configuration options related to tracking player interactions with blocks
|
||||
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=[]
|
||||
}
|
||||
# Configuration options related to activation ranges of tile entities.
|
||||
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 {}
|
||||
}
|
||||
# Module to run Aikar's Timings, profile your server performance and get a sharable web result.
|
||||
# https://github.com/aikar/timings#aikars-minecraft-timings-viewer-v2
|
||||
timings {
|
||||
# Enables the timing module
|
||||
enabled=true
|
||||
# These configuration entries/paths/sections are removed before the report is sent.
|
||||
# This is to prevent credentials from being leaked unintentionally.
|
||||
# Note: The 'sponge.sql' section is always ignored
|
||||
# and thus is never sent to the webviewer regardless of this config.
|
||||
hidden-config-entries=[
|
||||
"sponge.sql"
|
||||
]
|
||||
# Modulo value how often a tick should be pushed to the timings history
|
||||
history-interval=300
|
||||
# How long the list of said history can get
|
||||
history-length=3600
|
||||
# Hides the server name in the Aikar webviewer to no leak the l33t server you are running
|
||||
server-name-privacy=false
|
||||
# Enables the verbose mode for the timings module.
|
||||
verbose=false
|
||||
}
|
||||
# Configuration options that will affect all worlds.
|
||||
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
|
||||
# If 'true', any neighbour notification for a chunk not currently loaded will be denied
|
||||
# Warning: As this is an experimental setting for performance gain,
|
||||
# if you encounter any issues then we recommend disabling it.
|
||||
deny-neighbor-notification-chunk-requests=false
|
||||
# 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=[]
|
||||
}
|
||||
@@ -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,16 @@
|
||||
# 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 {
|
||||
# Configuration options that will affect all worlds.
|
||||
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,16 @@
|
||||
# 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 {
|
||||
# Configuration options that will affect all worlds.
|
||||
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,136 @@
|
||||
# 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
|
||||
#
|
||||
# Ignores incoming plugin channel messages of 1.16+ clients with channel names longer than 32 characters.
|
||||
# CraftBukkit had this limit hardcoded until 1.16, so we have to assume any server/proxy might have this arbitrary check present.
|
||||
ignore-long-1_16-channel-names: true
|
||||
#
|
||||
# ----------------------------------------------------------#
|
||||
# 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
File renamed without changes.
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../../universal/build/libs/nuvotifier.jar
|
||||
+1
-1
@@ -1 +1 @@
|
||||
../resources/paper.jar
|
||||
../resources/sponge.jar
|
||||
@@ -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 +0,0 @@
|
||||
rsa/
|
||||
@@ -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
|
||||
@@ -1,5 +1,8 @@
|
||||
#Minecraft server properties
|
||||
#Fri Dec 21 15:15:00 EST 2018
|
||||
#Thu Sep 03 15:49:48 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
|
||||
@@ -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,10 +0,0 @@
|
||||
# Changing the version of NuVotifier
|
||||
|
||||
So since I keep forgetting, here are the places which need to have their version
|
||||
numbers changed:
|
||||
|
||||
+ build.gradle
|
||||
+ com.vexsoftware.votifier.sponge.VotifierPlugin @Plugin
|
||||
+ com.vexsoftware.votifier.velocity.VotifierPlugin @Plugin
|
||||
|
||||
This is really annoying.
|
||||
Loaded 100 of 121 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user