the bois
This commit is contained in:
commit
ae4da96810
BIN
lib/travertine-1.16-168.jar
Normal file
BIN
lib/travertine-1.16-168.jar
Normal file
Binary file not shown.
BIN
lib/velocity-3.1.1-98.jar
Normal file
BIN
lib/velocity-3.1.1-98.jar
Normal file
Binary file not shown.
99
pom.xml
Normal file
99
pom.xml
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>gg.spoofmc.spoofer</groupId>
|
||||||
|
<artifactId>spoofer</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>8</maven.compiler.source>
|
||||||
|
<maven.compiler.target>8</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>rip.teams.spigot</groupId>
|
||||||
|
<artifactId>spigot-api</artifactId>
|
||||||
|
<version>1.8.8</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>rip.teams.spigot</groupId>
|
||||||
|
<artifactId>spigot-server</artifactId>
|
||||||
|
<version>1.8.8</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>travertine</groupId>
|
||||||
|
<artifactId>travertine</artifactId>
|
||||||
|
<version>1.16</version>
|
||||||
|
<scope>system</scope>
|
||||||
|
<systemPath>${basedir}/lib/travertine-1.16-168.jar</systemPath>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>velocity</groupId>
|
||||||
|
<artifactId>velocity</artifactId>
|
||||||
|
<version>1.16</version>
|
||||||
|
<scope>system</scope>
|
||||||
|
<systemPath>${basedir}/lib/velocity-3.1.1-98.jar</systemPath>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>1.18.22</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-pool2</artifactId>
|
||||||
|
<version>2.11.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>redis.clients</groupId>
|
||||||
|
<artifactId>jedis</artifactId>
|
||||||
|
<version>4.1.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.code.gson</groupId>
|
||||||
|
<artifactId>gson</artifactId>
|
||||||
|
<version>2.9.0</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.8.1</version>
|
||||||
|
<configuration>
|
||||||
|
<source>8</source>
|
||||||
|
<target>8</target>
|
||||||
|
<annotationProcessorPaths>
|
||||||
|
<path>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>1.18.20</version>
|
||||||
|
</path>
|
||||||
|
</annotationProcessorPaths>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>2.3</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
94
src/main/java/gg/spoof/bungee/Spoof.java
Normal file
94
src/main/java/gg/spoof/bungee/Spoof.java
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
package gg.spoof.bungee;
|
||||||
|
|
||||||
|
import gg.spoof.bungee.controller.PluginMessageController;
|
||||||
|
import gg.spoof.bungee.controller.ProxyController;
|
||||||
|
import gg.spoof.bungee.controller.RedisController;
|
||||||
|
import gg.spoof.bungee.listener.BungeePingListener;
|
||||||
|
import gg.spoof.bungee.util.ServerData;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
|
import net.md_5.bungee.config.Configuration;
|
||||||
|
import net.md_5.bungee.config.ConfigurationProvider;
|
||||||
|
import net.md_5.bungee.config.YamlConfiguration;
|
||||||
|
|
||||||
|
public class Spoof extends Plugin {
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private static Spoof instance;
|
||||||
|
private final Map<String, ServerData> servers = new ConcurrentHashMap<>();
|
||||||
|
private boolean debug;
|
||||||
|
private ProxyController controller;
|
||||||
|
|
||||||
|
public Map<String, ServerData> getServers() {
|
||||||
|
return this.servers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void debug(String message) {
|
||||||
|
if (this.debug)
|
||||||
|
this.getLogger().info(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void debug(String message, Throwable throwable) {
|
||||||
|
if (this.debug)
|
||||||
|
this.getLogger().log(Level.INFO, message, throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onEnable() {
|
||||||
|
try {
|
||||||
|
instance = this;
|
||||||
|
final Path configFile = this.getDataFolder().toPath().resolve("config.yml");
|
||||||
|
// ResourceLoader.loadDefaultResource(this.getClass().getClassLoader(), "bungee-config.yml", configFile);
|
||||||
|
final Configuration config = ConfigurationProvider.getProvider(YamlConfiguration.class).load(configFile.toFile());
|
||||||
|
|
||||||
|
this.debug = config.getBoolean("settings.debug");
|
||||||
|
this.registerController(config);
|
||||||
|
this.setupServersCleanup();
|
||||||
|
this.getProxy().getPluginManager().registerListener(this, new BungeePingListener(this));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onDisable() {
|
||||||
|
if (this.controller != null)
|
||||||
|
this.controller.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerController(Configuration config) {
|
||||||
|
String controllerType;
|
||||||
|
switch (controllerType = config.getString("settings.controller.selected").toLowerCase()) {
|
||||||
|
case "redis": {
|
||||||
|
final String[] address = config.getString("settings.controller.redis.address").split(":", 2);
|
||||||
|
final String password = config.getString("settings.controller.redis.password");
|
||||||
|
this.controller = new RedisController(this, address[0], Integer.parseInt(address[1]), password);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "messaging": {
|
||||||
|
this.controller = new PluginMessageController(this);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
throw new RuntimeException("The controller type '" + controllerType + "' isn't valid!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.getLogger().info("Using " + controllerType + " for the receiver.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupServersCleanup() {
|
||||||
|
this.getProxy().getScheduler().schedule(this, () -> {
|
||||||
|
final long currentTIme = System.currentTimeMillis();
|
||||||
|
for (Map.Entry<String, ServerData> serverSet : this.servers.entrySet()) {
|
||||||
|
ServerData server = serverSet.getValue();
|
||||||
|
if (currentTIme - server.getLastPing() <= TimeUnit.MINUTES.toMillis(1L)) continue;
|
||||||
|
this.servers.remove(serverSet.getKey());
|
||||||
|
}
|
||||||
|
}, 10L, 10L, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
}
|
13
src/main/java/gg/spoof/bungee/SpoofAPI.java
Normal file
13
src/main/java/gg/spoof/bungee/SpoofAPI.java
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package gg.spoof.bungee;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
public class SpoofAPI {
|
||||||
|
|
||||||
|
public static int getProxyCount() {
|
||||||
|
final AtomicInteger count = new AtomicInteger();
|
||||||
|
Spoof.getInstance().getServers().forEach((key, value) -> count.addAndGet(value.getOnline()));
|
||||||
|
return count.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package gg.spoof.bungee.controller;
|
||||||
|
|
||||||
|
import gg.spoof.bungee.Spoof;
|
||||||
|
import gg.spoof.common.proxy.ProxyChannelFormat;
|
||||||
|
import net.md_5.bungee.api.connection.Server;
|
||||||
|
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||||
|
import net.md_5.bungee.api.plugin.Listener;
|
||||||
|
import net.md_5.bungee.event.EventHandler;
|
||||||
|
|
||||||
|
public class PluginMessageController extends ProxyController implements Listener {
|
||||||
|
|
||||||
|
public PluginMessageController(Spoof plugin) {
|
||||||
|
super(plugin);
|
||||||
|
plugin.getProxy().registerChannel(ProxyChannelFormat.TAG_SERVER_PLAYERS);
|
||||||
|
plugin.getProxy().getPluginManager().registerListener(plugin, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPluginMessage(PluginMessageEvent event) {
|
||||||
|
if (!(event.getSender() instanceof Server))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!event.getTag().equals(ProxyChannelFormat.TAG_SERVER_PLAYERS))
|
||||||
|
return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
final ProxyChannelFormat.ServerPlayers serverPlayers = ProxyChannelFormat.decodeServerPlayers(event.getData());
|
||||||
|
this.updateServerPlayerCount(serverPlayers.getServerId(), serverPlayers.getCount());
|
||||||
|
} catch (Exception ex) {
|
||||||
|
this.plugin.debug("Error receiving server players", ex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
int proxyPlayerCount = this.getProxyPlayerCount();
|
||||||
|
byte[] proxyPlayerCountData = ProxyChannelFormat.encodeProxyPlayerCount(proxyPlayerCount);
|
||||||
|
this.plugin.getProxy().getServers().values().forEach(serverInfo -> serverInfo.sendData(ProxyChannelFormat.TAG_PROXY_PLAYER_COUNT, proxyPlayerCountData, false));
|
||||||
|
this.plugin.debug("Sent proxy player count " + proxyPlayerCount);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
this.plugin.debug("Error sending proxy player count", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package gg.spoof.bungee.controller;
|
||||||
|
|
||||||
|
import gg.spoof.bungee.Spoof;
|
||||||
|
import gg.spoof.bungee.util.ServerData;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public abstract class ProxyController {
|
||||||
|
|
||||||
|
protected final Spoof plugin;
|
||||||
|
|
||||||
|
public abstract void close();
|
||||||
|
|
||||||
|
protected int getProxyPlayerCount() {
|
||||||
|
return this.plugin.getServers().values().stream().mapToInt(ServerData::getOnline).sum();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void updateServerPlayerCount(String server, int online) {
|
||||||
|
this.plugin.getServers().computeIfAbsent(server, k -> new ServerData()).setOnline(online);
|
||||||
|
this.plugin.debug("Updated server " + server + " player count to " + online);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,77 @@
|
|||||||
|
package gg.spoof.bungee.controller;
|
||||||
|
|
||||||
|
import gg.spoof.bungee.Spoof;
|
||||||
|
import gg.spoof.common.proxy.ProxyChannelFormat;
|
||||||
|
import redis.clients.jedis.Jedis;
|
||||||
|
import redis.clients.jedis.JedisPubSub;
|
||||||
|
|
||||||
|
public class RedisController extends ProxyController {
|
||||||
|
|
||||||
|
private Jedis jedisRX;
|
||||||
|
private Jedis jedisTX;
|
||||||
|
|
||||||
|
public RedisController(final Spoof plugin, String host, int port, String password) {
|
||||||
|
super(plugin);
|
||||||
|
this.jedisRX = this.create(host, port, password);
|
||||||
|
this.jedisTX = this.create(host, port, password);
|
||||||
|
|
||||||
|
plugin.getProxy().getScheduler().runAsync(plugin, () -> {
|
||||||
|
final JedisPubSub jedisPubSub = new JedisPubSub() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMessage(String channel, String message) {
|
||||||
|
try {
|
||||||
|
final ProxyChannelFormat.ServerPlayers players = ProxyChannelFormat.decodeB64ServerPlayers(message);
|
||||||
|
updateServerPlayerCount(players.getServerId(), players.getCount());
|
||||||
|
} catch (Exception ex) {
|
||||||
|
plugin.debug("Error receiving server players", ex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
int proxyPlayerCount = RedisController.this.getProxyPlayerCount();
|
||||||
|
jedisTX.publish("spoof:pr_pl_cnt", ProxyChannelFormat.encodeB64ProxyPlayerCount(proxyPlayerCount));
|
||||||
|
plugin.debug("Sent total player count " + proxyPlayerCount);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
plugin.debug("Error sending proxy player count", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSubscribe(String channel, int subscribedChannels) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUnsubscribe(String channel, int subscribedChannels) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.jedisRX.subscribe(jedisPubSub, ProxyChannelFormat.TAG_SERVER_PLAYERS);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private Jedis create(String host, int port, String password) {
|
||||||
|
final Jedis jedis = new Jedis(host, port);
|
||||||
|
jedis.connect();
|
||||||
|
|
||||||
|
if (!password.isEmpty())
|
||||||
|
jedis.auth(password);
|
||||||
|
|
||||||
|
if (!jedis.isConnected())
|
||||||
|
throw new IllegalStateException("Failed to connect to redis");
|
||||||
|
|
||||||
|
return jedis;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
if (this.jedisRX != null) {
|
||||||
|
this.jedisRX.close();
|
||||||
|
this.jedisRX = null;
|
||||||
|
}
|
||||||
|
if (this.jedisTX != null) {
|
||||||
|
this.jedisTX.close();
|
||||||
|
this.jedisTX = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package gg.spoof.bungee.listener;
|
||||||
|
|
||||||
|
import gg.spoof.bungee.Spoof;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import net.md_5.bungee.api.ServerPing;
|
||||||
|
import net.md_5.bungee.api.event.ProxyPingEvent;
|
||||||
|
import net.md_5.bungee.api.plugin.Listener;
|
||||||
|
import net.md_5.bungee.event.EventHandler;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class BungeePingListener implements Listener {
|
||||||
|
|
||||||
|
protected final Spoof plugin;
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onProxyPing(ProxyPingEvent event) {
|
||||||
|
final ServerPing ping = event.getResponse();
|
||||||
|
final ServerPing.Players players = ping.getPlayers();
|
||||||
|
final AtomicInteger count = new AtomicInteger();
|
||||||
|
|
||||||
|
this.plugin.getServers().forEach((key, value) -> count.addAndGet(value.getOnline()));
|
||||||
|
this.plugin.debug("Setting proxy count to " + count + ".");
|
||||||
|
|
||||||
|
ping.setPlayers(new ServerPing.Players(players.getMax(), count.get(), players.getSample()));
|
||||||
|
event.setResponse(ping);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
16
src/main/java/gg/spoof/bungee/util/ServerData.java
Normal file
16
src/main/java/gg/spoof/bungee/util/ServerData.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package gg.spoof.bungee.util;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class ServerData {
|
||||||
|
|
||||||
|
private volatile int online;
|
||||||
|
private volatile long lastPing;
|
||||||
|
|
||||||
|
public void setOnline(int online) {
|
||||||
|
this.online = online;
|
||||||
|
this.lastPing = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
72
src/main/java/gg/spoof/common/proxy/ProxyChannelFormat.java
Normal file
72
src/main/java/gg/spoof/common/proxy/ProxyChannelFormat.java
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
package gg.spoof.common.proxy;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
public class ProxyChannelFormat {
|
||||||
|
|
||||||
|
public static final String TAG_SERVER_PLAYERS = "spoof:srv_pl";
|
||||||
|
public static final String TAG_PROXY_PLAYER_COUNT = "spoof:pr_pl_cnt";
|
||||||
|
|
||||||
|
public static ServerPlayers decodeServerPlayers(byte[] message) throws IOException {
|
||||||
|
try (final DataInputStream dataInputStream = new DataInputStream(new ByteArrayInputStream(message))) {
|
||||||
|
final String serverId = dataInputStream.readUTF();
|
||||||
|
final int count = dataInputStream.readInt();
|
||||||
|
|
||||||
|
return new ServerPlayers(serverId, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServerPlayers decodeB64ServerPlayers(String message) throws IOException {
|
||||||
|
return decodeServerPlayers(Base64.getDecoder().decode(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] encodeServerPlayers(ServerPlayers serverPlayers) throws IOException {
|
||||||
|
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||||
|
try (final DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream)) {
|
||||||
|
dataOutputStream.writeUTF(serverPlayers.getServerId());
|
||||||
|
dataOutputStream.writeInt(serverPlayers.getCount());
|
||||||
|
|
||||||
|
return byteArrayOutputStream.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String encodeB64ServerPlayers(ServerPlayers serverPlayers) throws IOException {
|
||||||
|
return Base64.getEncoder().encodeToString(encodeServerPlayers(serverPlayers));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int decodeProxyPlayerCount(byte[] data) throws IOException {
|
||||||
|
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data);
|
||||||
|
try (final DataInputStream dataInputStream = new DataInputStream(byteArrayInputStream)) {
|
||||||
|
return dataInputStream.readInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int decodeB64ProxyPlayerCount(String message) throws IOException {
|
||||||
|
return decodeProxyPlayerCount(Base64.getDecoder().decode(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] encodeProxyPlayerCount(int var0) throws IOException {
|
||||||
|
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||||
|
try (final DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream)) {
|
||||||
|
dataOutputStream.writeInt(var0);
|
||||||
|
return byteArrayOutputStream.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String encodeB64ProxyPlayerCount(int var0) throws IOException {
|
||||||
|
return Base64.getEncoder().encodeToString(encodeProxyPlayerCount(var0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public static class ServerPlayers {
|
||||||
|
|
||||||
|
protected final String serverId;
|
||||||
|
protected final int count;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
26
src/main/java/gg/spoof/common/utils/ResourceLoader.java
Normal file
26
src/main/java/gg/spoof/common/utils/ResourceLoader.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package gg.spoof.common.utils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.LinkOption;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class ResourceLoader {
|
||||||
|
|
||||||
|
public static void loadDefaultResource(ClassLoader classLoader, String var1, Path path) throws IOException {
|
||||||
|
if (Files.exists(path, LinkOption.NOFOLLOW_LINKS)) {
|
||||||
|
final Path parent = path.getParent();
|
||||||
|
Files.createDirectories(parent);
|
||||||
|
|
||||||
|
final InputStream resourceAsStream = classLoader.getResourceAsStream(var1);
|
||||||
|
Files.copy(Objects.requireNonNull(resourceAsStream), parent, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
163
src/main/java/gg/spoof/spigot/Spoof.java
Normal file
163
src/main/java/gg/spoof/spigot/Spoof.java
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
package gg.spoof.spigot;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
|
import gg.spoof.spigot.api.ProxyController;
|
||||||
|
import gg.spoof.spigot.api.SpoofConfig;
|
||||||
|
import gg.spoof.spigot.api.manager.ModuleManager;
|
||||||
|
import gg.spoof.spigot.api.manager.PlayerManager;
|
||||||
|
import gg.spoof.spigot.commands.CmdCommand;
|
||||||
|
import gg.spoof.spigot.controller.NoopController;
|
||||||
|
import gg.spoof.spigot.controller.RedisController;
|
||||||
|
import gg.spoof.spigot.listener.DeathHandler;
|
||||||
|
import gg.spoof.spigot.listener.MiscHandler;
|
||||||
|
import gg.spoof.spigot.listener.SpawnHandler;
|
||||||
|
import gg.spoof.spigot.message.TL;
|
||||||
|
import gg.spoof.spigot.module.*;
|
||||||
|
import gg.spoof.spigot.module.fluctuation.AccountsRegistry;
|
||||||
|
import gg.spoof.spigot.module.fluctuation.FluctuationModule;
|
||||||
|
import gg.spoof.spigot.nms.NMSWrapper;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.plugin.PluginManager;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class Spoof extends JavaPlugin {
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private static Spoof plugin;
|
||||||
|
public static Executor POOL;
|
||||||
|
private final SpoofConfig spoofConfig = new SpoofConfig(this);
|
||||||
|
private ProxyController proxyController = new NoopController();
|
||||||
|
private NMSWrapper platform;
|
||||||
|
private AccountsRegistry accounts;
|
||||||
|
|
||||||
|
public Spoof() {
|
||||||
|
plugin = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onEnable() {
|
||||||
|
POOL = Executors.newFixedThreadPool(5, new ThreadFactoryBuilder().setDaemon(true).setNameFormat("%d - Stellar Ghost").build());
|
||||||
|
|
||||||
|
this.saveDefaultConfig();
|
||||||
|
this.loadConfiguration();
|
||||||
|
this.setupCompatibility();
|
||||||
|
|
||||||
|
this.accounts = AccountsRegistry.create(this);
|
||||||
|
|
||||||
|
final PluginManager pluginManager = getServer().getPluginManager();
|
||||||
|
Arrays.asList(
|
||||||
|
new MiscHandler(this),
|
||||||
|
new SpawnHandler(this),
|
||||||
|
new DeathHandler(this),
|
||||||
|
new CmdCommand(this, true)
|
||||||
|
).forEach(it -> pluginManager.registerEvents(it, this));
|
||||||
|
|
||||||
|
this.setupProxyController();
|
||||||
|
|
||||||
|
Arrays.asList(
|
||||||
|
// new PickupModule(this),
|
||||||
|
// new PingModule(this),
|
||||||
|
new FluctuationModule(this, true),
|
||||||
|
// new ActionModule(this),
|
||||||
|
new WelcomeModule(this)
|
||||||
|
// new RankModule(this),
|
||||||
|
// new VoteModule(this)
|
||||||
|
).forEach(ModuleManager::registerModule);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onDisable() {
|
||||||
|
PlayerManager.getPlayerMap().values().forEach(spoofPlayer -> this.getPlatform().removeSpoofPlayer(spoofPlayer));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupCompatibility() {
|
||||||
|
try {
|
||||||
|
final String packageName = Bukkit.getServer().getClass().getPackage().getName();
|
||||||
|
final String version = packageName.substring(packageName.lastIndexOf(".") + 1);
|
||||||
|
|
||||||
|
final Class<?> aClass = Class.forName("gg.spoof.spigot.nms." + version + ".NMSWrapper");
|
||||||
|
this.platform = (NMSWrapper) aClass.getDeclaredConstructor(Spoof.class).newInstance(this);
|
||||||
|
} catch (Exception e) {
|
||||||
|
this.debug("Error initializing platform support");
|
||||||
|
this.getPluginLoader().disablePlugin(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadConfiguration() {
|
||||||
|
this.reloadConfig();
|
||||||
|
final FileConfiguration config = this.getConfig();
|
||||||
|
for (TL message : TL.values()) {
|
||||||
|
if (config.getString("messages." + message.getPath()) == null) continue;
|
||||||
|
message.setMessage(config.getString("messages." + message.getPath()));
|
||||||
|
}
|
||||||
|
this.spoofConfig.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setupProxyController() {
|
||||||
|
this.proxyController.close();
|
||||||
|
this.proxyController = new NoopController();
|
||||||
|
|
||||||
|
try {
|
||||||
|
String controllerType;
|
||||||
|
if (!this.getConfig().getBoolean("settings.proxy-mode", false)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (controllerType = this.getConfig().getString("settings.controller.selected", "redis").toLowerCase(Locale.ENGLISH)) {
|
||||||
|
case "redis": {
|
||||||
|
String[] address = this.getConfig().getString("settings.controller.redis.address").split(":", 2);
|
||||||
|
String password = this.getConfig().getString("settings.controller.redis.password");
|
||||||
|
this.proxyController = new RedisController(this, address[0], Integer.parseInt(address[1]), password);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
throw new IllegalArgumentException("The controller type '" + controllerType + "' isn't valid! Please use the follow (REDIS, MESSAGING)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.getServer().getScheduler().runTaskTimerAsynchronously(this, () -> this.proxyController.sendServerPlayerCount(), 100L, 100L);
|
||||||
|
}
|
||||||
|
catch (Throwable e) {
|
||||||
|
this.getLogger().log(Level.SEVERE, "Failed to init proxy controller", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isWhitelisted(CommandSender commandSender) {
|
||||||
|
if (!(commandSender instanceof Player))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
final Player player = (Player) commandSender;
|
||||||
|
return this.spoofConfig.getWhitelistedUsers().contains(player.getUniqueId().toString())
|
||||||
|
|| this.spoofConfig.getWhitelistedUsers().contains(player.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void print(String message) {
|
||||||
|
this.getLogger().info(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void print(String message, Throwable t) {
|
||||||
|
this.getLogger().log(Level.INFO, message, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void debug(String message) {
|
||||||
|
if (!this.spoofConfig.isDebug())
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.print(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void debug(String message, Throwable t) {
|
||||||
|
if (!this.spoofConfig.isDebug())
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.print(message, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
9
src/main/java/gg/spoof/spigot/SpoofAPI.java
Normal file
9
src/main/java/gg/spoof/spigot/SpoofAPI.java
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package gg.spoof.spigot;
|
||||||
|
|
||||||
|
public class SpoofAPI {
|
||||||
|
|
||||||
|
public static int getTotalCount() {
|
||||||
|
return Spoof.getPlugin().getProxyController().getTotalPlayerCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
10
src/main/java/gg/spoof/spigot/actions/Action.java
Normal file
10
src/main/java/gg/spoof/spigot/actions/Action.java
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package gg.spoof.spigot.actions;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Action {
|
||||||
|
|
||||||
|
void run(Player var1, String var2);
|
||||||
|
|
||||||
|
}
|
68
src/main/java/gg/spoof/spigot/actions/ActionRegistry.java
Normal file
68
src/main/java/gg/spoof/spigot/actions/ActionRegistry.java
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
package gg.spoof.spigot.actions;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
import gg.spoof.spigot.util.StringUtil;
|
||||||
|
import lombok.Getter;
|
||||||
|
import net.md_5.bungee.chat.ComponentSerializer;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.bukkit.Server;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class ActionRegistry {
|
||||||
|
|
||||||
|
private final Spoof plugin;
|
||||||
|
private final Map<String, Action> actions = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public ActionRegistry(Spoof plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.addAction("console", (player, data) -> plugin.getServer().dispatchCommand(plugin.getServer().getConsoleSender(), data));
|
||||||
|
this.addAction("player", Player::performCommand);
|
||||||
|
this.addAction("broadcast", (player, data) -> plugin.getServer().broadcastMessage(data));
|
||||||
|
this.addAction("message", CommandSender::sendMessage);
|
||||||
|
this.addAction("chat", Player::chat);
|
||||||
|
this.addAction("close", (player, data) -> player.closeInventory());
|
||||||
|
this.addAction("json", (player, data) -> player.spigot().sendMessage(ComponentSerializer.parse(data)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addAction(String id, Action action) {
|
||||||
|
this.actions.put(id.toUpperCase(), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runActions(final Player player, List<String> items) {
|
||||||
|
items.forEach(item -> {
|
||||||
|
final String actionData = !item.contains(" ") ? "" : StringUtil.translate(item.split(" ", 2)[1]).replace("%player%", player.getName());
|
||||||
|
final Action action = this.getAction(item);
|
||||||
|
final Server server = player.getServer();
|
||||||
|
|
||||||
|
server.getScheduler().runTask(this.plugin, () -> {
|
||||||
|
if (action != null) {
|
||||||
|
action.run(player, actionData);
|
||||||
|
} else {
|
||||||
|
plugin.getServer().dispatchCommand(server.getConsoleSender(), item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runActions(Player player, String... items) {
|
||||||
|
this.runActions(player, Arrays.asList(items));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Action getAction(String item) {
|
||||||
|
boolean singleAction = !item.contains(" ");
|
||||||
|
String actionPrefix = singleAction ? item : item.split(" ", 2)[0].toUpperCase();
|
||||||
|
String rawAction = StringUtils.substringBetween(actionPrefix, "[", "]");
|
||||||
|
if (rawAction != null) {
|
||||||
|
return this.actions.get(rawAction);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
98
src/main/java/gg/spoof/spigot/api/Module.java
Normal file
98
src/main/java/gg/spoof/spigot/api/Module.java
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package gg.spoof.spigot.api;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.api.manager.ModuleManager;
|
||||||
|
import java.util.List;
|
||||||
|
import org.apache.commons.lang.Validate;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
public abstract class Module<T extends Plugin> {
|
||||||
|
|
||||||
|
protected final JavaPlugin plugin;
|
||||||
|
|
||||||
|
protected Module(JavaPlugin plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Module() {
|
||||||
|
this.plugin = JavaPlugin.getProvidingPlugin(this.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract String getName();
|
||||||
|
|
||||||
|
public String getIdentifier() {
|
||||||
|
return this.getName().toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return this.getBoolean("enabled", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract String getAuthor();
|
||||||
|
|
||||||
|
public abstract String getVersion();
|
||||||
|
|
||||||
|
public String getRequiredPlugin() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void onEnable();
|
||||||
|
|
||||||
|
public abstract void onDisable();
|
||||||
|
|
||||||
|
public boolean isRegistered() {
|
||||||
|
Validate.notNull(this.getIdentifier(), "Module identifier can not be null!");
|
||||||
|
return ModuleManager.isRegistered(this.getIdentifier());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canRegister() {
|
||||||
|
return this.getRequiredPlugin() == null || Bukkit.getPluginManager().getPlugin(this.getRequiredPlugin()) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean register() {
|
||||||
|
Validate.notNull(this.getIdentifier(), "Module identifier can not be null!");
|
||||||
|
return ModuleManager.registerModule(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString(String path, String def) {
|
||||||
|
return this.plugin.getConfig().getString("modules." + this.getIdentifier().toLowerCase() + "." + path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getInt(String path, int def) {
|
||||||
|
return this.plugin.getConfig().getInt("modules." + this.getIdentifier().toLowerCase() + "." + path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLong(String path, long def) {
|
||||||
|
return this.plugin.getConfig().getLong("modules." + this.getIdentifier().toLowerCase() + "." + path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getDouble(String path, double def) {
|
||||||
|
return this.plugin.getConfig().getDouble("modules." + this.getIdentifier().toLowerCase() + "." + path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getBoolean(String path, boolean def) {
|
||||||
|
return this.plugin.getConfig().getBoolean("modules." + this.getIdentifier().toLowerCase() + "." + path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getStringList(String path) {
|
||||||
|
return this.plugin.getConfig().getStringList("modules." + this.getIdentifier().toLowerCase() + "." + path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object get(String path, Object def) {
|
||||||
|
return this.plugin.getConfig().get("modules." + this.getIdentifier().toLowerCase() + "." + path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigurationSection getConfigSection(String path) {
|
||||||
|
return this.plugin.getConfig().getConfigurationSection("modules." + this.getIdentifier().toLowerCase() + "." + path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigurationSection getConfigSection() {
|
||||||
|
return this.plugin.getConfig().getConfigurationSection("modules." + this.getIdentifier().toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean configurationContains(String path) {
|
||||||
|
return this.plugin.getConfig().contains("modules." + this.getIdentifier().toLowerCase() + "." + path);
|
||||||
|
}
|
||||||
|
}
|
11
src/main/java/gg/spoof/spigot/api/ProxyController.java
Normal file
11
src/main/java/gg/spoof/spigot/api/ProxyController.java
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package gg.spoof.spigot.api;
|
||||||
|
|
||||||
|
public interface ProxyController {
|
||||||
|
|
||||||
|
int getTotalPlayerCount();
|
||||||
|
|
||||||
|
void sendServerPlayerCount();
|
||||||
|
|
||||||
|
void close();
|
||||||
|
|
||||||
|
}
|
53
src/main/java/gg/spoof/spigot/api/SpoofConfig.java
Normal file
53
src/main/java/gg/spoof/spigot/api/SpoofConfig.java
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package gg.spoof.spigot.api;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class SpoofConfig {
|
||||||
|
|
||||||
|
private final Spoof plugin;
|
||||||
|
private boolean visible = true;
|
||||||
|
private boolean debug = false;
|
||||||
|
private boolean enableJoinLeave = true;
|
||||||
|
private int joinCommandsDelay = 0;
|
||||||
|
private List<String> joinCommands = Collections.emptyList();
|
||||||
|
private String serverId = "none-specified";
|
||||||
|
private List<String> whitelistedUsers = Collections.emptyList();
|
||||||
|
private String spawnWorld;
|
||||||
|
private double spawnX;
|
||||||
|
private double spawnY;
|
||||||
|
private double spawnZ;
|
||||||
|
|
||||||
|
public void load() {
|
||||||
|
final FileConfiguration config = this.plugin.getConfig();
|
||||||
|
this.visible = config.getBoolean("settings.show-bot-entity", true);
|
||||||
|
this.debug = config.getBoolean("settings.debug", true);
|
||||||
|
this.enableJoinLeave = config.getBoolean("settings.enable-join-leave", true);
|
||||||
|
this.joinCommands = config.getStringList("settings.join-commands");
|
||||||
|
this.joinCommandsDelay = config.getInt("settings.join-commands-delay", this.joinCommandsDelay);
|
||||||
|
this.serverId = config.getString("settings.server-id", "none-specified");
|
||||||
|
this.whitelistedUsers = config.getStringList("settings.whitelisted");
|
||||||
|
this.spawnWorld = config.getString("settings.spawn-locations.world");
|
||||||
|
this.spawnX = config.getInt("settings.spawn-locations.x");
|
||||||
|
this.spawnY = config.getInt("settings.spawn-locations.y");
|
||||||
|
this.spawnZ = config.getInt("settings.spawn-locations.z");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Location getSpawnLocation() {
|
||||||
|
try {
|
||||||
|
return new Location(this.plugin.getServer().getWorld(this.spawnWorld), this.spawnX, this.spawnY, this.spawnZ);
|
||||||
|
} catch (Exception e) {
|
||||||
|
this.plugin.debug("Couldn't find spawn location! Using default location");
|
||||||
|
return this.plugin.getServer().getWorlds().get(0).getSpawnLocation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
35
src/main/java/gg/spoof/spigot/api/SpoofPlayer.java
Normal file
35
src/main/java/gg/spoof/spigot/api/SpoofPlayer.java
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package gg.spoof.spigot.api;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.api.manager.PlayerManager;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class SpoofPlayer {
|
||||||
|
|
||||||
|
private final UUID id;
|
||||||
|
private final String name;
|
||||||
|
private final PlayerManager.PlayerManagementType managementType;
|
||||||
|
private Player player;
|
||||||
|
|
||||||
|
public SpoofPlayer(UUID id, String name, PlayerManager.PlayerManagementType managementType) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.managementType = managementType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getPlayer() {
|
||||||
|
return this.player != null ? this.player : Bukkit.getPlayer(this.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPlayer(Player player) {
|
||||||
|
if (!this.id.equals(player.getUniqueId()))
|
||||||
|
throw new IllegalArgumentException("Id missmatch");
|
||||||
|
|
||||||
|
this.player = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
107
src/main/java/gg/spoof/spigot/api/manager/ModuleManager.java
Normal file
107
src/main/java/gg/spoof/spigot/api/manager/ModuleManager.java
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
package gg.spoof.spigot.api.manager;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
import gg.spoof.spigot.api.Module;
|
||||||
|
import gg.spoof.spigot.module.InternalModule;
|
||||||
|
import java.util.AbstractMap;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import org.apache.commons.lang.Validate;
|
||||||
|
|
||||||
|
public class ModuleManager {
|
||||||
|
|
||||||
|
private static final Map<String, Map.Entry<Module<?>, Boolean>> modules = new HashMap<>();
|
||||||
|
|
||||||
|
public static boolean isRegistered(String identifier) {
|
||||||
|
return ModuleManager.getRegisteredIdentifiers().stream().filter(id -> id.equalsIgnoreCase(identifier)).findFirst().orElse(null) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void unregisterModule(String identifier) {
|
||||||
|
Validate.notNull(identifier, "Identifier can not be null");
|
||||||
|
Map.Entry<Module<?>, Boolean> moduleEntry = modules.remove(identifier.toLowerCase());
|
||||||
|
if (moduleEntry != null && moduleEntry.getValue()) {
|
||||||
|
ModuleManager.setModuleDisabled(moduleEntry.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Set<String> getRegisteredIdentifiers() {
|
||||||
|
return ImmutableSet.copyOf(modules.keySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<String, Module<?>> getModules() {
|
||||||
|
return modules.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> (entry.getValue()).getKey()));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void unregisterAll() {
|
||||||
|
ModuleManager.unregisterAllProvidedModules();
|
||||||
|
modules.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void unregisterAllProvidedModules() {
|
||||||
|
if (modules.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ModuleManager.getModules().values().forEach(module -> {
|
||||||
|
if (module instanceof InternalModule) {
|
||||||
|
ModuleManager.unregisterModule(module.getIdentifier());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean registerModule(Module<?> module) {
|
||||||
|
Validate.notNull(module, "Module can not be null");
|
||||||
|
Validate.notNull(module.getIdentifier(), "Identifier can not be null");
|
||||||
|
|
||||||
|
if (!module.canRegister() || ModuleManager.isRegistered(module.getIdentifier()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
boolean enabled = module.isEnabled();
|
||||||
|
|
||||||
|
if (enabled)
|
||||||
|
enabled = ModuleManager.setModuleEnabled(module);
|
||||||
|
|
||||||
|
modules.put(module.getIdentifier().toLowerCase(), new AbstractMap.SimpleEntry<>(module, enabled));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void reloadModules() {
|
||||||
|
modules.values().forEach(moduleEntry -> {
|
||||||
|
boolean enabled;
|
||||||
|
final Module module = moduleEntry.getKey();
|
||||||
|
|
||||||
|
if (moduleEntry.getValue())
|
||||||
|
ModuleManager.setModuleDisabled(module);
|
||||||
|
|
||||||
|
|
||||||
|
if (enabled = module.isEnabled())
|
||||||
|
enabled = ModuleManager.setModuleEnabled(module);
|
||||||
|
|
||||||
|
moduleEntry.setValue(enabled);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static boolean setModuleEnabled(Module<?> module) {
|
||||||
|
try {
|
||||||
|
module.onEnable();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Throwable t) {
|
||||||
|
Spoof.getPlugin().print("Failed to enable module " + module.getName(), t);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static boolean setModuleDisabled(Module<?> module) {
|
||||||
|
try {
|
||||||
|
module.onDisable();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Throwable t) {
|
||||||
|
Spoof.getPlugin().print("Failed to disable module " + module.getName(), t);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
89
src/main/java/gg/spoof/spigot/api/manager/PlayerManager.java
Normal file
89
src/main/java/gg/spoof/spigot/api/manager/PlayerManager.java
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
package gg.spoof.spigot.api.manager;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.api.SpoofPlayer;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public class PlayerManager {
|
||||||
|
|
||||||
|
private static final ConcurrentHashMap<UUID, SpoofPlayer> PLAYER_MAP = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public static Map<UUID, SpoofPlayer> getPlayerMap() {
|
||||||
|
return PLAYER_MAP;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getLoadedAmount() {
|
||||||
|
return PLAYER_MAP.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getLoadedAmount(PlayerManagementType mtype) {
|
||||||
|
int counter = 0;
|
||||||
|
for (SpoofPlayer spoofPlayer : PLAYER_MAP.values()) {
|
||||||
|
if (spoofPlayer.getManagementType() != mtype) continue;
|
||||||
|
++counter;
|
||||||
|
}
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean exists(Player player) {
|
||||||
|
return PLAYER_MAP.containsKey(player.getUniqueId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SpoofPlayer getPlayer(Player player) {
|
||||||
|
return PLAYER_MAP.get(player.getUniqueId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SpoofPlayer getPlayer(String player) {
|
||||||
|
return PLAYER_MAP.values().stream().filter(spoofPlayer -> spoofPlayer.getName().equalsIgnoreCase(player)).findFirst().orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SpoofPlayer getPlayer(UUID ID) {
|
||||||
|
return PLAYER_MAP.get(ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SpoofPlayer[] getRandomPlayers(int count) {
|
||||||
|
SpoofPlayer[] players = PLAYER_MAP.values().toArray(new SpoofPlayer[0]);
|
||||||
|
Collections.shuffle(Arrays.asList(players));
|
||||||
|
return players.length < count ? players : Arrays.copyOfRange(players, 0, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SpoofPlayer getRandomPlayer() {
|
||||||
|
if (PLAYER_MAP.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
SpoofPlayer[] players = PLAYER_MAP.values().toArray(new SpoofPlayer[0]);
|
||||||
|
return players[ThreadLocalRandom.current().nextInt(players.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SpoofPlayer getRandomPlayer(PlayerManagementType mtype) {
|
||||||
|
if (PLAYER_MAP.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
SpoofPlayer[] players = PLAYER_MAP.values().stream().filter(player -> player.getManagementType() == mtype).toArray(SpoofPlayer[]::new);
|
||||||
|
return players[ThreadLocalRandom.current().nextInt(players.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SpoofPlayer addPlayer(UUID id, String name, PlayerManagementType mtype) {
|
||||||
|
if (PLAYER_MAP.containsKey(id)) {
|
||||||
|
throw new IllegalArgumentException("Player with id " + id + " already exists");
|
||||||
|
}
|
||||||
|
SpoofPlayer player = new SpoofPlayer(id, name, mtype);
|
||||||
|
PLAYER_MAP.put(id, player);
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void removePlayer(UUID id) {
|
||||||
|
PLAYER_MAP.remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum PlayerManagementType {
|
||||||
|
AUTO,
|
||||||
|
MANUAL
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
103
src/main/java/gg/spoof/spigot/commands/CmdCommand.java
Normal file
103
src/main/java/gg/spoof/spigot/commands/CmdCommand.java
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
package gg.spoof.spigot.commands;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
import gg.spoof.spigot.commands.extend.AbstractCommand;
|
||||||
|
import gg.spoof.spigot.commands.subs.*;
|
||||||
|
import gg.spoof.spigot.util.ReflectionUtil;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||||
|
import org.bukkit.event.server.ServerCommandEvent;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class CmdCommand implements Listener {
|
||||||
|
|
||||||
|
protected final Spoof plugin;
|
||||||
|
protected final Map<Class<?>, AbstractCommand> subcommands = new HashMap<>();
|
||||||
|
|
||||||
|
protected void addCommand(AbstractCommand abstractCommand) {
|
||||||
|
this.subcommands.put(abstractCommand.getClass(), abstractCommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CmdCommand(Spoof plugin, boolean premium) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.addCommand(new CmdHelp(plugin));
|
||||||
|
this.addCommand(new CmdReload(plugin));
|
||||||
|
if (premium) {
|
||||||
|
this.addCommand(new CmdAdd(plugin));
|
||||||
|
this.addCommand(new CmdAddNm(plugin));
|
||||||
|
this.addCommand(new CmdModules(plugin));
|
||||||
|
this.addCommand(new CmdRemove(plugin));
|
||||||
|
this.addCommand(new CmdSummon(plugin));
|
||||||
|
// this.addCommand(new CmdAuction(plugin));
|
||||||
|
// this.addCommand(new CmdDonation(plugin));
|
||||||
|
}
|
||||||
|
ReflectionUtil.validateInitBySpoof();
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
protected void onPlayerCommandUse(PlayerCommandPreprocessEvent event) {
|
||||||
|
final Player player = event.getPlayer();
|
||||||
|
|
||||||
|
if (this.plugin.isWhitelisted(player)) {
|
||||||
|
final String message = event.getMessage();
|
||||||
|
final List<String> args = new ArrayList<>(Arrays.asList(message.split(" ")));
|
||||||
|
|
||||||
|
String enteredCommand = (!args.isEmpty() ? args.remove(0) : message).replace("/", "");
|
||||||
|
|
||||||
|
if (enteredCommand.equalsIgnoreCase("spoof")) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
this.handleCommand(player, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
protected void onConsoleCommandUse(ServerCommandEvent event) {
|
||||||
|
final String command = event.getCommand();
|
||||||
|
final List<String> args = Arrays.asList(command.split(" "));
|
||||||
|
final String remove = args.remove(0);
|
||||||
|
|
||||||
|
if (remove.equalsIgnoreCase("spoof")) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
this.handleCommand(event.getSender(), args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void handleCommand(CommandSender sender, List<String> args) {
|
||||||
|
if (args.isEmpty()) {
|
||||||
|
this.subcommands.get(CmdHelp.class).execute(sender, args);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String commandLabel = args.get(0);
|
||||||
|
|
||||||
|
this.getCommands().forEach(abstractCommand -> {
|
||||||
|
final String label = abstractCommand.getLabel();
|
||||||
|
final List<String> alias = abstractCommand.getAlias();
|
||||||
|
|
||||||
|
if (alias.contains(commandLabel) || label.equalsIgnoreCase(commandLabel)) {
|
||||||
|
this.execute(sender, args, abstractCommand);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void execute(final CommandSender sender, final List<String> args, final AbstractCommand abstractCommand) {
|
||||||
|
final String permission = abstractCommand.getPermission();
|
||||||
|
|
||||||
|
if (sender.hasPermission(permission)) {
|
||||||
|
abstractCommand.execute(sender, args);
|
||||||
|
} else {
|
||||||
|
sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&cYou don't have the permission to do that."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<AbstractCommand> getCommands() {
|
||||||
|
return this.subcommands.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package gg.spoof.spigot.commands.extend;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
import gg.spoof.spigot.commands.extend.Executable;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public abstract class AbstractCommand implements Executable {
|
||||||
|
|
||||||
|
private final Spoof plugin;
|
||||||
|
private final String label;
|
||||||
|
private final List<String> alias = new ArrayList<>();
|
||||||
|
|
||||||
|
protected AbstractCommand(Spoof plugin, String label, String ... alias) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.label = label;
|
||||||
|
this.alias.addAll(Arrays.asList(alias));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package gg.spoof.spigot.commands.extend;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
|
public interface Executable {
|
||||||
|
|
||||||
|
boolean execute(CommandSender sender, List<String> args);
|
||||||
|
|
||||||
|
String getDescription();
|
||||||
|
|
||||||
|
String getPermission();
|
||||||
|
|
||||||
|
boolean isPlayerRequired();
|
||||||
|
|
||||||
|
List<String> getAutoCompletes();
|
||||||
|
|
||||||
|
}
|
60
src/main/java/gg/spoof/spigot/commands/subs/CmdAdd.java
Normal file
60
src/main/java/gg/spoof/spigot/commands/subs/CmdAdd.java
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package gg.spoof.spigot.commands.subs;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
import gg.spoof.spigot.api.manager.PlayerManager;
|
||||||
|
import gg.spoof.spigot.commands.extend.AbstractCommand;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.message.Placeholder;
|
||||||
|
import gg.spoof.spigot.message.TL;
|
||||||
|
import gg.spoof.spigot.nms.NMSWrapper;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
|
public class CmdAdd extends AbstractCommand {
|
||||||
|
|
||||||
|
public CmdAdd(Spoof plugin) {
|
||||||
|
super(plugin, "add");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(CommandSender sender, List<String> args) {
|
||||||
|
if (args.size() <= 1) {
|
||||||
|
TL.INVALID_COMMAND_USAGE.send(sender, new Placeholder("<command>", "/spoof add <player>"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String name = args.get(1);
|
||||||
|
final Spoof plugin = Spoof.getPlugin();
|
||||||
|
plugin.getPlatform().addSpoofPlayer(name, PlayerManager.PlayerManagementType.MANUAL);
|
||||||
|
|
||||||
|
TL.PLAYER_ADDED.send(sender, new Placeholder("<player>", name));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Add more players";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPermission() {
|
||||||
|
return "spoof.add";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPlayerRequired() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getAutoCompletes() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
68
src/main/java/gg/spoof/spigot/commands/subs/CmdAddNm.java
Normal file
68
src/main/java/gg/spoof/spigot/commands/subs/CmdAddNm.java
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
package gg.spoof.spigot.commands.subs;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
import gg.spoof.spigot.api.manager.PlayerManager;
|
||||||
|
import gg.spoof.spigot.commands.extend.AbstractCommand;
|
||||||
|
import gg.spoof.spigot.message.Placeholder;
|
||||||
|
import gg.spoof.spigot.message.TL;
|
||||||
|
import gg.spoof.spigot.module.fluctuation.AccountsRegistry;
|
||||||
|
import gg.spoof.spigot.module.fluctuation.NameMCAccountsRegistry;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class CmdAddNm extends AbstractCommand {
|
||||||
|
|
||||||
|
public CmdAddNm(Spoof plugin) {
|
||||||
|
super(plugin, "addnm");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(CommandSender sender, List<String> args) {
|
||||||
|
if (args.size() <= 1) {
|
||||||
|
TL.INVALID_COMMAND_USAGE.send(sender, new Placeholder("<command>", "/spoof add <nm>"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String amount = args.get(1);
|
||||||
|
final Spoof plugin = Spoof.getPlugin();
|
||||||
|
|
||||||
|
try {
|
||||||
|
final int amtI = Integer.parseInt(amount);
|
||||||
|
for (int i = 0; i < amtI; i++) {
|
||||||
|
final AccountsRegistry accounts = plugin.getAccounts();
|
||||||
|
final UUID randomAccount = accounts.getRandomAccount();
|
||||||
|
accounts.takeAccount(randomAccount);
|
||||||
|
plugin.getPlatform().addSpoofPlayer(randomAccount.toString(), PlayerManager.PlayerManagementType.MANUAL);
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
sender.sendMessage("Done");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Add more players";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPermission() {
|
||||||
|
return "spoof.add";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPlayerRequired() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getAutoCompletes() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
74
src/main/java/gg/spoof/spigot/commands/subs/CmdAuction.java
Normal file
74
src/main/java/gg/spoof/spigot/commands/subs/CmdAuction.java
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package gg.spoof.spigot.commands.subs;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
import gg.spoof.spigot.api.SpoofPlayer;
|
||||||
|
import gg.spoof.spigot.api.manager.PlayerManager;
|
||||||
|
import gg.spoof.spigot.commands.extend.AbstractCommand;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.message.Placeholder;
|
||||||
|
import gg.spoof.spigot.message.TL;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
public class CmdAuction extends AbstractCommand {
|
||||||
|
|
||||||
|
public CmdAuction(Spoof plugin) {
|
||||||
|
super(plugin, "auction");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(CommandSender sender, List<String> args) {
|
||||||
|
final String playerName = args.get(0);
|
||||||
|
final SpoofPlayer spoofPlayer = PlayerManager.getPlayer(playerName);
|
||||||
|
|
||||||
|
final String s = args.get(1);
|
||||||
|
final int price = Integer.parseInt(s);
|
||||||
|
|
||||||
|
if (spoofPlayer == null) {
|
||||||
|
TL.NULL_PLAYER.send(sender, new Placeholder("<player>", playerName));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Player player = spoofPlayer.getPlayer();
|
||||||
|
final ItemStack itemInHand = player.getItemInHand();
|
||||||
|
final Material type = itemInHand.getType();
|
||||||
|
|
||||||
|
if (type == Material.AIR) {
|
||||||
|
TL.MISSING_AUCTION_ITEM.send(sender);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// start auction
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Have the spoof player auction something";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPermission() {
|
||||||
|
return "spoof.auction";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPlayerRequired() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getAutoCompletes() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
72
src/main/java/gg/spoof/spigot/commands/subs/CmdDonation.java
Normal file
72
src/main/java/gg/spoof/spigot/commands/subs/CmdDonation.java
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
//package gg.spoof.spigot.commands.subs;
|
||||||
|
//
|
||||||
|
//import gg.spoof.spigot.Spoof;
|
||||||
|
//import gg.spoof.spigot.api.SpoofPlayer;
|
||||||
|
//import gg.spoof.spigot.commands.extend.AbstractCommand;
|
||||||
|
//
|
||||||
|
//import java.io.File;
|
||||||
|
//import java.io.FileOutputStream;
|
||||||
|
//import java.io.IOException;
|
||||||
|
//import java.io.InputStream;
|
||||||
|
//import java.io.OutputStream;
|
||||||
|
//import java.util.HashMap;
|
||||||
|
//import java.util.List;
|
||||||
|
//import java.util.Map;
|
||||||
|
//
|
||||||
|
//import net.buycraft.plugin.bukkit.events.BuycraftPurchaseEvent;
|
||||||
|
//import org.bukkit.command.CommandSender;
|
||||||
|
//import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
//import org.bukkit.event.EventHandler;
|
||||||
|
//import org.bukkit.event.Listener;
|
||||||
|
//
|
||||||
|
//public class CmdDonation extends AbstractCommand implements Listener {
|
||||||
|
//
|
||||||
|
// private final boolean enabled;
|
||||||
|
// private final int minDelay;
|
||||||
|
// private final int maxDelay;
|
||||||
|
// private final int minResponders;
|
||||||
|
// private final int maxResponders;
|
||||||
|
// private final List<String> responses;
|
||||||
|
// private final Map<String, List<String>> packages;
|
||||||
|
//
|
||||||
|
// public CmdDonation(Spoof plugin) {
|
||||||
|
// super(plugin, "donation", new String[0]);
|
||||||
|
// FileConfiguration config = plugin.getConfig();
|
||||||
|
// this.enabled = config.getBoolean("modules.donations.enabled");
|
||||||
|
// this.responses = config.getStringList("modules.donations.responses");
|
||||||
|
// this.minDelay = config.getInt("modules.donations.settings.delay.min");
|
||||||
|
// this.maxDelay = config.getInt("modules.donations.settings.delay.max");
|
||||||
|
// this.minResponders = config.getInt("modules.donations.settings.responders.min");
|
||||||
|
// this.maxResponders = config.getInt("modules.donations.settings.responders.min");
|
||||||
|
// this.packages = new HashMap<>();
|
||||||
|
// for (String dKey : config.getConfigurationSection("modules.donations.packages").getKeys(false)) {
|
||||||
|
// this.packages.put(dKey, config.getStringList("modules.donations.packages." + dKey + ".message"));
|
||||||
|
// }
|
||||||
|
// this.getPlugin().getServer().getPluginManager().registerEvents(this, this.getPlugin());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public String getRandomResponse(); was ntv
|
||||||
|
//
|
||||||
|
// @EventHandler
|
||||||
|
// public void onBuycraftPurchaseEvent(BuycraftPurchaseEvent var1); was ntv
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public boolean execute(CommandSender sender, List<String> args); was ntv
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public String getDescription(); was ntv
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public String getPermission(); was ntv
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public boolean isPlayerRequired(); was ntv
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public List<String> getAutoCompletes(); was ntv
|
||||||
|
//
|
||||||
|
// private static void lambda$execute$1(SpoofPlayer var0, String var1); was ntv
|
||||||
|
//
|
||||||
|
// private static void lambda$onBuycraftPurchaseEvent$0(SpoofPlayer var0, String var1); was ntv
|
||||||
|
//
|
||||||
|
//}
|
53
src/main/java/gg/spoof/spigot/commands/subs/CmdHelp.java
Normal file
53
src/main/java/gg/spoof/spigot/commands/subs/CmdHelp.java
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package gg.spoof.spigot.commands.subs;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
import gg.spoof.spigot.commands.extend.AbstractCommand;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.message.TL;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
|
||||||
|
public class CmdHelp extends AbstractCommand {
|
||||||
|
|
||||||
|
public CmdHelp(Spoof plugin) {
|
||||||
|
super(plugin, "help", "h");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(CommandSender sender, List<String> args) {
|
||||||
|
final Spoof plugin = Spoof.getPlugin();
|
||||||
|
final FileConfiguration config = plugin.getConfig();
|
||||||
|
|
||||||
|
TL.message(sender, config.getStringList("messages.help"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "A help command";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPermission() {
|
||||||
|
return "spoof.help";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPlayerRequired() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getAutoCompletes() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
62
src/main/java/gg/spoof/spigot/commands/subs/CmdModules.java
Normal file
62
src/main/java/gg/spoof/spigot/commands/subs/CmdModules.java
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package gg.spoof.spigot.commands.subs;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
import gg.spoof.spigot.api.manager.ModuleManager;
|
||||||
|
import gg.spoof.spigot.commands.extend.AbstractCommand;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.message.C;
|
||||||
|
import gg.spoof.spigot.message.Placeholder;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
|
||||||
|
public class CmdModules extends AbstractCommand {
|
||||||
|
|
||||||
|
public CmdModules(Spoof plugin) {
|
||||||
|
super(plugin, "modules");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(CommandSender sender, List<String> args) {
|
||||||
|
final Spoof plugin = this.getPlugin();
|
||||||
|
final FileConfiguration config = plugin.getConfig();
|
||||||
|
final String configKey = "messages.modules-information";
|
||||||
|
|
||||||
|
config.getStringList(configKey).forEach(s -> {
|
||||||
|
C.color(s,
|
||||||
|
new Placeholder("<module-size>", ModuleManager.getModules().size()),
|
||||||
|
new Placeholder("<module-loaded>", "<module-loaded>")
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "View modules";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPermission() {
|
||||||
|
return "spoof.modules";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPlayerRequired() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getAutoCompletes() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
55
src/main/java/gg/spoof/spigot/commands/subs/CmdReload.java
Normal file
55
src/main/java/gg/spoof/spigot/commands/subs/CmdReload.java
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package gg.spoof.spigot.commands.subs;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
import gg.spoof.spigot.api.manager.ModuleManager;
|
||||||
|
import gg.spoof.spigot.commands.extend.AbstractCommand;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.message.Placeholder;
|
||||||
|
import gg.spoof.spigot.message.TL;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
|
public class CmdReload extends AbstractCommand {
|
||||||
|
|
||||||
|
public CmdReload(Spoof plugin) {
|
||||||
|
super(plugin, "reload", "r");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(CommandSender sender, List<String> args) {
|
||||||
|
final Spoof plugin = this.getPlugin();
|
||||||
|
plugin.loadConfiguration();
|
||||||
|
plugin.setupProxyController();
|
||||||
|
ModuleManager.reloadModules();
|
||||||
|
|
||||||
|
TL.RELOADED.send(sender, new Placeholder("<version>", plugin.getDescription().getVersion()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Reload the config and messages!";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPermission() {
|
||||||
|
return "spoof.reload";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPlayerRequired() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getAutoCompletes() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
77
src/main/java/gg/spoof/spigot/commands/subs/CmdRemove.java
Normal file
77
src/main/java/gg/spoof/spigot/commands/subs/CmdRemove.java
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
package gg.spoof.spigot.commands.subs;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
import gg.spoof.spigot.api.SpoofPlayer;
|
||||||
|
import gg.spoof.spigot.api.manager.PlayerManager;
|
||||||
|
import gg.spoof.spigot.commands.extend.AbstractCommand;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.message.Placeholder;
|
||||||
|
import gg.spoof.spigot.message.TL;
|
||||||
|
import gg.spoof.spigot.nms.NMSWrapper;
|
||||||
|
import gg.spoof.spigot.util.StringUtil;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
|
public class CmdRemove extends AbstractCommand {
|
||||||
|
|
||||||
|
public CmdRemove(Spoof plugin) {
|
||||||
|
super(plugin, "remove");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(CommandSender sender, List<String> args) {
|
||||||
|
if (args.size() <= 1) {
|
||||||
|
TL.INVALID_COMMAND_USAGE.send(sender, new Placeholder("<command>", "/spoof remove <player>"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String playerName = args.get(1);
|
||||||
|
final SpoofPlayer player;
|
||||||
|
|
||||||
|
if (StringUtil.isUUID(playerName)) {
|
||||||
|
player = PlayerManager.getPlayer(UUID.fromString(playerName));
|
||||||
|
} else {
|
||||||
|
player = PlayerManager.getPlayer(playerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player == null) {
|
||||||
|
TL.INVALID_USER.send(sender, new Placeholder("<player>", playerName));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
final NMSWrapper platform = this.getPlugin().getPlatform();
|
||||||
|
platform.removeSpoofPlayer(player);
|
||||||
|
|
||||||
|
TL.PLAYER_REMOVED.send(sender, new Placeholder("<player>", playerName));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Remove players";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPermission() {
|
||||||
|
return "spoof.remove";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPlayerRequired() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getAutoCompletes() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
67
src/main/java/gg/spoof/spigot/commands/subs/CmdSummon.java
Normal file
67
src/main/java/gg/spoof/spigot/commands/subs/CmdSummon.java
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package gg.spoof.spigot.commands.subs;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
import gg.spoof.spigot.api.manager.PlayerManager;
|
||||||
|
import gg.spoof.spigot.commands.extend.AbstractCommand;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.message.Placeholder;
|
||||||
|
import gg.spoof.spigot.message.TL;
|
||||||
|
import net.minecraft.server.v1_8_R3.PlayerConnection;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public class CmdSummon extends AbstractCommand {
|
||||||
|
|
||||||
|
public CmdSummon(Spoof plugin) {
|
||||||
|
super(plugin, "summon");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(CommandSender commandSender, List<String> args) {
|
||||||
|
if (args.size() <= 1) {
|
||||||
|
TL.INVALID_COMMAND_USAGE.send(commandSender, new Placeholder("<command>", "/spoof summon <player>"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String name = args.get(1);
|
||||||
|
final Player sender = (Player) commandSender;
|
||||||
|
final Player player = this.getPlugin().getServer().getPlayer(name);
|
||||||
|
|
||||||
|
if (player != null && PlayerManager.exists(player)) {
|
||||||
|
player.teleport(sender.getLocation());
|
||||||
|
TL.PLAYER_SUMMONED.send(commandSender, new Placeholder("<player>", player.getName()));
|
||||||
|
} else TL.NULL_PLAYER.send(commandSender, new Placeholder("<player>", name));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Summon a spoofed player";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPermission() {
|
||||||
|
return "spoof.summon";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPlayerRequired() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getAutoCompletes() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
25
src/main/java/gg/spoof/spigot/controller/NoopController.java
Normal file
25
src/main/java/gg/spoof/spigot/controller/NoopController.java
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package gg.spoof.spigot.controller;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.api.ProxyController;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
|
||||||
|
public class NoopController implements ProxyController {
|
||||||
|
|
||||||
|
public static NoopController INSTANCE;
|
||||||
|
|
||||||
|
public NoopController() {
|
||||||
|
INSTANCE = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTotalPlayerCount() {
|
||||||
|
return Bukkit.getOnlinePlayers().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendServerPlayerCount() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
package gg.spoof.spigot.controller;
|
||||||
|
|
||||||
|
import gg.spoof.common.proxy.ProxyChannelFormat;
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
import gg.spoof.spigot.api.ProxyController;
|
||||||
|
import gg.spoof.spigot.controller.redis.RedisControllerPubSub;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import redis.clients.jedis.Jedis;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class RedisController implements ProxyController {
|
||||||
|
|
||||||
|
private final Spoof plugin;
|
||||||
|
private Jedis jedisRX;
|
||||||
|
private Jedis jedisTX;
|
||||||
|
private int playerTotalCount = 0;
|
||||||
|
|
||||||
|
private final RedisControllerPubSub controllerPubSub;
|
||||||
|
|
||||||
|
public RedisController(Spoof plugin, String host, int port, String password) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.jedisRX = this.create(host, port, password);
|
||||||
|
this.jedisTX = this.create(host, port, password);
|
||||||
|
|
||||||
|
this.controllerPubSub = new RedisControllerPubSub(this.plugin, this);
|
||||||
|
|
||||||
|
plugin.getServer().getScheduler().runTaskAsynchronously(plugin, this::lambda$new$0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Jedis create(String host, int port, String password) {
|
||||||
|
final Jedis jedis = new Jedis(host, port);
|
||||||
|
jedis.connect();
|
||||||
|
|
||||||
|
if (!password.isEmpty())
|
||||||
|
jedis.auth(password);
|
||||||
|
|
||||||
|
if (!jedis.isConnected())
|
||||||
|
throw new IllegalStateException("Failed to connect to redis");
|
||||||
|
|
||||||
|
return jedis;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTotalPlayerCount() {
|
||||||
|
return this.playerTotalCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendServerPlayerCount() {
|
||||||
|
try {
|
||||||
|
final String channel = "spoof:srv_pl";
|
||||||
|
final String serverId = this.plugin.getSpoofConfig().getServerId();
|
||||||
|
final int size = Bukkit.getOnlinePlayers().size();
|
||||||
|
|
||||||
|
final ProxyChannelFormat.ServerPlayers serverPlayers = new ProxyChannelFormat.ServerPlayers(serverId, size);
|
||||||
|
final String encoded = ProxyChannelFormat.encodeB64ServerPlayers(serverPlayers);
|
||||||
|
|
||||||
|
this.jedisTX.publish(channel, encoded);
|
||||||
|
this.plugin.debug("Sent server player count " + size);
|
||||||
|
} catch (Exception exception) {
|
||||||
|
this.plugin.debug("Error sending server count");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
this.jedisRX.close();
|
||||||
|
this.jedisTX.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void lambda$new$0() {
|
||||||
|
this.jedisRX.subscribe(this.controllerPubSub, "spoof:pr_pl_cnt");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package gg.spoof.spigot.controller.redis;
|
||||||
|
|
||||||
|
import gg.spoof.common.proxy.ProxyChannelFormat;
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
import gg.spoof.spigot.controller.RedisController;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import redis.clients.jedis.JedisPubSub;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class RedisControllerPubSub extends JedisPubSub {
|
||||||
|
|
||||||
|
public final Spoof plugin;
|
||||||
|
private final RedisController redisController;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMessage(String channel, String message) {
|
||||||
|
try {
|
||||||
|
final int i = ProxyChannelFormat.decodeB64ProxyPlayerCount(message);
|
||||||
|
this.redisController.setPlayerTotalCount(i);
|
||||||
|
|
||||||
|
String stringBuilder = "Updated total player count to " + this.redisController.getTotalPlayerCount();
|
||||||
|
this.plugin.debug(stringBuilder);
|
||||||
|
} catch (Exception exception) {
|
||||||
|
this.plugin.debug("Error receiving proxy player count");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
41
src/main/java/gg/spoof/spigot/listener/DeathHandler.java
Normal file
41
src/main/java/gg/spoof/spigot/listener/DeathHandler.java
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package gg.spoof.spigot.listener;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.api.manager.PlayerManager;
|
||||||
|
import gg.spoof.spigot.util.MathUtility;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||||
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
import org.bukkit.scheduler.BukkitScheduler;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class DeathHandler extends BukkitRunnable implements Listener {
|
||||||
|
|
||||||
|
protected final Spoof plugin;
|
||||||
|
private Player player;
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
protected void onDeath(PlayerDeathEvent event) {
|
||||||
|
final Player entity = event.getEntity();
|
||||||
|
if (!PlayerManager.exists(entity))
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.player = entity;
|
||||||
|
this.runTaskLater(this.plugin, MathUtility.getRandomNumber(10, 50));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
this.player.spigot().respawn();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
61
src/main/java/gg/spoof/spigot/listener/MiscHandler.java
Normal file
61
src/main/java/gg/spoof/spigot/listener/MiscHandler.java
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package gg.spoof.spigot.listener;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.api.SpoofConfig;
|
||||||
|
import gg.spoof.spigot.api.SpoofPlayer;
|
||||||
|
import gg.spoof.spigot.api.manager.PlayerManager;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.bukkit.command.ConsoleCommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MiscHandler implements Listener {
|
||||||
|
|
||||||
|
private final Spoof plugin;
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
protected void onJoin(PlayerJoinEvent event) {
|
||||||
|
final Player player = event.getPlayer();
|
||||||
|
|
||||||
|
if (PlayerManager.exists(player))
|
||||||
|
this.plugin.getServer().getScheduler().runTaskLater(this.plugin, () -> this.lambdaJoin(player), this.plugin.getSpoofConfig().getJoinCommandsDelay());
|
||||||
|
|
||||||
|
this.plugin.getProxyController().sendServerPlayerCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
protected void onQuit(PlayerQuitEvent event) {
|
||||||
|
this.plugin.getProxyController().sendServerPlayerCount();
|
||||||
|
final UUID uniqueId = event.getPlayer().getUniqueId();
|
||||||
|
|
||||||
|
if (PlayerManager.exists(event.getPlayer())) {
|
||||||
|
final SpoofPlayer player = PlayerManager.getPlayer(uniqueId);
|
||||||
|
PlayerManager.removePlayer(player.getId());
|
||||||
|
|
||||||
|
final String unexpectedQuit = "Unexpected quit of spoof player " + player.getName();
|
||||||
|
final String debugTrace = "Debug trace";
|
||||||
|
|
||||||
|
this.plugin.debug(unexpectedQuit, new Throwable(debugTrace));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void lambdaJoin(Player player) {
|
||||||
|
final ConsoleCommandSender consoleSender = this.plugin.getServer().getConsoleSender();
|
||||||
|
final SpoofConfig spoofConfig = this.plugin.getSpoofConfig();
|
||||||
|
final String name = player.getName();
|
||||||
|
|
||||||
|
spoofConfig.getJoinCommands().forEach(s -> this.plugin.getServer().dispatchCommand(consoleSender, s.replace("%player%", name)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static Spoof access$000(MiscHandler miscHandler) {
|
||||||
|
return miscHandler.plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
37
src/main/java/gg/spoof/spigot/listener/SpawnHandler.java
Normal file
37
src/main/java/gg/spoof/spigot/listener/SpawnHandler.java
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package gg.spoof.spigot.listener;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.api.manager.PlayerManager;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.spigotmc.event.player.PlayerSpawnLocationEvent;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class SpawnHandler implements Listener {
|
||||||
|
|
||||||
|
protected final Spoof plugin;
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
protected void onInitialSpawn(PlayerSpawnLocationEvent event) {
|
||||||
|
final Player player = event.getPlayer();
|
||||||
|
|
||||||
|
if (!PlayerManager.exists(player))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (player.hasPlayedBefore())
|
||||||
|
return;
|
||||||
|
|
||||||
|
final Location spawnLocation = this.plugin.getSpoofConfig().getSpawnLocation();
|
||||||
|
event.setSpawnLocation(spawnLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
66
src/main/java/gg/spoof/spigot/message/C.java
Normal file
66
src/main/java/gg/spoof/spigot/message/C.java
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
package gg.spoof.spigot.message;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.message.Placeholder;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
|
||||||
|
public final class C {
|
||||||
|
public static String color(String s) {
|
||||||
|
return ChatColor.translateAlternateColorCodes('&', s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String color(String s, Placeholder ... placeHolders) {
|
||||||
|
String message = s;
|
||||||
|
for (Placeholder placeHolder : placeHolders) {
|
||||||
|
message = C.color(message.replace(placeHolder.getPlaceHolder(), placeHolder.getReplace()));
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> color(List<String> s) {
|
||||||
|
ArrayList<String> toReturn = new ArrayList<String>();
|
||||||
|
for (String str : s) {
|
||||||
|
toReturn.add(C.color(str));
|
||||||
|
}
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> color(List<String> messages, Placeholder ... placeholders) {
|
||||||
|
ArrayList<String> colored = new ArrayList<String>();
|
||||||
|
Iterator<String> iterator = messages.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
String line;
|
||||||
|
String coloredLine = line = iterator.next();
|
||||||
|
for (Placeholder placeholder : placeholders) {
|
||||||
|
coloredLine = C.color(coloredLine.replace(placeholder.getPlaceHolder(), placeholder.getReplace()));
|
||||||
|
}
|
||||||
|
colored.add(coloredLine);
|
||||||
|
}
|
||||||
|
return colored;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String strip(String s) {
|
||||||
|
return ChatColor.stripColor(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String strip(String string, Placeholder ... placeHolders) {
|
||||||
|
String message = string;
|
||||||
|
for (Placeholder placeHolder : placeHolders) {
|
||||||
|
message = message.replace(placeHolder.getPlaceHolder(), placeHolder.getReplace());
|
||||||
|
}
|
||||||
|
return ChatColor.stripColor(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String capitalizeFirstLetter(String original) {
|
||||||
|
if (original == null || original.length() == 0) {
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
return original.substring(0, 1).toUpperCase() + original.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private C() {
|
||||||
|
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
|
||||||
|
}
|
||||||
|
}
|
46
src/main/java/gg/spoof/spigot/message/Placeholder.java
Normal file
46
src/main/java/gg/spoof/spigot/message/Placeholder.java
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package gg.spoof.spigot.message;
|
||||||
|
|
||||||
|
public class Placeholder {
|
||||||
|
|
||||||
|
private final String placeHolder;
|
||||||
|
private final String replace;
|
||||||
|
|
||||||
|
public Placeholder(String placeHolder, String replace) {
|
||||||
|
this.placeHolder = placeHolder;
|
||||||
|
this.replace = replace;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Placeholder(String placeHolder, boolean bool) {
|
||||||
|
this.replace = String.valueOf(bool);
|
||||||
|
this.placeHolder = placeHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Placeholder(String placeHolder, int i) {
|
||||||
|
this.replace = String.valueOf(i);
|
||||||
|
this.placeHolder = placeHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Placeholder(String placeHolder, double i) {
|
||||||
|
this.replace = String.valueOf(i);
|
||||||
|
this.placeHolder = placeHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Placeholder(String placeHolder, long i) {
|
||||||
|
this.replace = String.valueOf(i);
|
||||||
|
this.placeHolder = placeHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Placeholder(String placeHolder, float i) {
|
||||||
|
this.replace = String.valueOf(i);
|
||||||
|
this.placeHolder = placeHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPlaceHolder() {
|
||||||
|
return this.placeHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReplace() {
|
||||||
|
return this.replace;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
88
src/main/java/gg/spoof/spigot/message/TL.java
Normal file
88
src/main/java/gg/spoof/spigot/message/TL.java
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
package gg.spoof.spigot.message;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.message.C;
|
||||||
|
import gg.spoof.spigot.message.Placeholder;
|
||||||
|
import java.util.List;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public enum TL {
|
||||||
|
NO_PERMISSION("no_permission", "&cYou don't have the permission to do that."),
|
||||||
|
INVALID_ARGUMENT_NUMBER("invalid-number", "&c'<argument>' has to be a number"),
|
||||||
|
INVALID_COMMAND_USAGE("invalid-command-usage", "&eIncorrect Usage: &a<command>"),
|
||||||
|
PLAYER_ONLY("player-only", "&cThis command is for players only!"),
|
||||||
|
RELOADED("reload", "&8[&b&l\u26a1&8] &bSpoof v<version> &8- &fThe Ultimate Spoofing Solution&7."),
|
||||||
|
PLAYER_NOT_ONLINE("player-not-online", "&cPlayer seems to be not online!"),
|
||||||
|
INVALID_USER("invalid-user", "&b[&lSpoof&b] &7The username (&b<player>&7) specified is invalid!"),
|
||||||
|
ALREADY_ONLINE("already-online", "&b[&lSpoof&b] &7That player (&b<player>&7) is already online!"),
|
||||||
|
PLAYER_ADDED("player-added", "&b[&lSpoof&b] &7You added &b<player> &7to the server!"),
|
||||||
|
PLAYER_REMOVED("player-removed", "&b[&lSpoof&b] &7You removed &b<player> &7from the server!"),
|
||||||
|
NULL_PLAYER("player-not-found", "&b[&lSpoof&b] &7This spoof player (&b<player>&7) does not exist!"),
|
||||||
|
MISSING_AUCTION_ITEM("missing-auction-item", "&b[&lSpoof&b] &7You must have something in your hand to auction!"),
|
||||||
|
ITEM_AUCTIONED("item-auctioned", "&b[&lSpoof&b] &7You have auction an item under the spoofed player <player>!"),
|
||||||
|
INVALID_DONATION_PACKAGE("invalid-donation-package", "&b[&lSpoof&b] &7This package ID you have provided does not exist!"),
|
||||||
|
PLAYER_SUMMONED("player-teleported", "&aYou have summoned <player> to you!");
|
||||||
|
|
||||||
|
private String path;
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
private TL(String path, String message) {
|
||||||
|
this.path = path;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send(CommandSender sender) {
|
||||||
|
if (sender instanceof Player) {
|
||||||
|
sender.sendMessage(C.color(this.getMessage()));
|
||||||
|
} else {
|
||||||
|
sender.sendMessage(C.strip(this.getMessage()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send(CommandSender sender, Placeholder ... placeHolders) {
|
||||||
|
if (sender instanceof Player) {
|
||||||
|
sender.sendMessage(C.color(this.getMessage(), placeHolders));
|
||||||
|
} else {
|
||||||
|
sender.sendMessage(C.strip(this.getMessage(), placeHolders));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void broadcast(Placeholder ... placeholders) {
|
||||||
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||||
|
player.sendMessage(C.color(this.getMessage(), placeholders));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void message(CommandSender sender, String message) {
|
||||||
|
sender.sendMessage(C.color(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void message(CommandSender sender, String message, Placeholder ... placeHolders) {
|
||||||
|
sender.sendMessage(C.color(message, placeHolders));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void message(CommandSender sender, List<String> message) {
|
||||||
|
message.forEach(m -> sender.sendMessage(C.color(m)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void message(CommandSender sender, List<String> message, Placeholder ... placeHolders) {
|
||||||
|
message.forEach(m -> sender.sendMessage(C.color(m, placeHolders)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPath() {
|
||||||
|
return this.path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return this.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPath(String path) {
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
}
|
24
src/main/java/gg/spoof/spigot/module/ActionModule$1.java
Normal file
24
src/main/java/gg/spoof/spigot/module/ActionModule$1.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
//package gg.spoof.spigot.module;
|
||||||
|
//
|
||||||
|
//import java.util.List;
|
||||||
|
//import org.bukkit.entity.Player;
|
||||||
|
//import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
//
|
||||||
|
//class ActionModule$1 extends BukkitRunnable {
|
||||||
|
//
|
||||||
|
// ActionModule$1() {
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public native void run();
|
||||||
|
//
|
||||||
|
// private native void performActions();
|
||||||
|
//
|
||||||
|
// private native void lambda$performActions$3(Player var1, List var2);
|
||||||
|
//
|
||||||
|
// private static native boolean lambda$performActions$2(List var0);
|
||||||
|
//
|
||||||
|
// private native List lambda$performActions$1(String var1);
|
||||||
|
//
|
||||||
|
// private native boolean lambda$performActions$0(int var1, String var2);
|
||||||
|
//
|
||||||
|
//}
|
54
src/main/java/gg/spoof/spigot/module/ActionModule.java
Normal file
54
src/main/java/gg/spoof/spigot/module/ActionModule.java
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
//package gg.spoof.spigot.module;
|
||||||
|
//
|
||||||
|
//import gg.spoof.spigot.Spoof;
|
||||||
|
//import gg.spoof.spigot.actions.ActionRegistry;
|
||||||
|
//import gg.spoof.spigot.module.InternalModule;
|
||||||
|
//import gg.spoof.spigot.util.ReflectionUtil;
|
||||||
|
//import java.io.File;
|
||||||
|
//import java.io.FileOutputStream;
|
||||||
|
//import java.io.IOException;
|
||||||
|
//import java.io.InputStream;
|
||||||
|
//import java.io.OutputStream;
|
||||||
|
//import java.util.List;
|
||||||
|
//import org.bukkit.scheduler.BukkitTask;
|
||||||
|
//
|
||||||
|
//public class ActionModule extends InternalModule {
|
||||||
|
//
|
||||||
|
// private int minDelay;
|
||||||
|
// private int maxDelay;
|
||||||
|
// private List<String> actions;
|
||||||
|
// private ActionRegistry actionRegistry;
|
||||||
|
// private BukkitTask task;
|
||||||
|
//
|
||||||
|
// public ActionModule(Spoof plugin) {
|
||||||
|
// super(plugin);
|
||||||
|
// ReflectionUtil.validateInitBySpoof();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native String getName();
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public String getAuthor() {
|
||||||
|
// return plugin.getDescription().getAuthors().get(0);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public String getVersion() {
|
||||||
|
// return plugin.getDescription().getVersion();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native void onEnable();
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native void onDisable();
|
||||||
|
//
|
||||||
|
// private native void sched();
|
||||||
|
//
|
||||||
|
//// static native void access$000(ActionModule var0);
|
||||||
|
////
|
||||||
|
//// static native List access$100(ActionModule var0);
|
||||||
|
////
|
||||||
|
//// static native ActionRegistry access$200(ActionModule var0);
|
||||||
|
//}
|
12
src/main/java/gg/spoof/spigot/module/InternalModule.java
Normal file
12
src/main/java/gg/spoof/spigot/module/InternalModule.java
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package gg.spoof.spigot.module;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
import gg.spoof.spigot.api.Module;
|
||||||
|
|
||||||
|
public abstract class InternalModule extends Module<Spoof> {
|
||||||
|
|
||||||
|
protected InternalModule(Spoof plugin) {
|
||||||
|
super(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
13
src/main/java/gg/spoof/spigot/module/PickupModule$1.java
Normal file
13
src/main/java/gg/spoof/spigot/module/PickupModule$1.java
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
//package gg.spoof.spigot.module;
|
||||||
|
//
|
||||||
|
//import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
//
|
||||||
|
//class PickupModule$1 extends BukkitRunnable {
|
||||||
|
// PickupModule$1() {
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public native void run();
|
||||||
|
//
|
||||||
|
// private native void pickup();
|
||||||
|
//
|
||||||
|
//}
|
43
src/main/java/gg/spoof/spigot/module/PickupModule.java
Normal file
43
src/main/java/gg/spoof/spigot/module/PickupModule.java
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
//package gg.spoof.spigot.module;
|
||||||
|
//
|
||||||
|
//import gg.spoof.spigot.Spoof;
|
||||||
|
//import gg.spoof.spigot.module.InternalModule;
|
||||||
|
//import org.bukkit.plugin.Plugin;
|
||||||
|
//import org.bukkit.scheduler.BukkitTask;
|
||||||
|
//
|
||||||
|
//public class PickupModule extends InternalModule {
|
||||||
|
//
|
||||||
|
// private int minDelay;
|
||||||
|
// private int maxDelay;
|
||||||
|
// private BukkitTask task;
|
||||||
|
//
|
||||||
|
// public PickupModule(Spoof plugin) {
|
||||||
|
// super(plugin);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native String getName();
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public String getAuthor() {
|
||||||
|
// return plugin.getDescription().getAuthors().get(0);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public String getVersion() {
|
||||||
|
// return plugin.getDescription().getVersion();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native void onEnable();
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native void onDisable();
|
||||||
|
//
|
||||||
|
// private native void sched();
|
||||||
|
//
|
||||||
|
//// static native void access$000(PickupModule var0);
|
||||||
|
////
|
||||||
|
//// static native Plugin access$100(PickupModule var0);
|
||||||
|
//
|
||||||
|
//}
|
14
src/main/java/gg/spoof/spigot/module/PingModule$1.java
Normal file
14
src/main/java/gg/spoof/spigot/module/PingModule$1.java
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
//package gg.spoof.spigot.module;
|
||||||
|
//
|
||||||
|
//import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
//
|
||||||
|
//class PingModule$1 extends BukkitRunnable {
|
||||||
|
//
|
||||||
|
// PingModule$1() {
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public native void run();
|
||||||
|
//
|
||||||
|
// private native void updatePing();
|
||||||
|
//
|
||||||
|
//}
|
47
src/main/java/gg/spoof/spigot/module/PingModule.java
Normal file
47
src/main/java/gg/spoof/spigot/module/PingModule.java
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
//package gg.spoof.spigot.module;
|
||||||
|
//
|
||||||
|
//import gg.spoof.spigot.Spoof;
|
||||||
|
//import gg.spoof.spigot.module.InternalModule;
|
||||||
|
//import org.bukkit.plugin.Plugin;
|
||||||
|
//import org.bukkit.scheduler.BukkitTask;
|
||||||
|
//
|
||||||
|
//public class PingModule extends InternalModule {
|
||||||
|
//
|
||||||
|
// private int minDelay;
|
||||||
|
// private int maxDelay;
|
||||||
|
// private int minPing;
|
||||||
|
// private int maxPing;
|
||||||
|
// private BukkitTask task;
|
||||||
|
//
|
||||||
|
// public PingModule(Spoof plugin) {
|
||||||
|
// super(plugin);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native String getName();
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public String getAuthor() {
|
||||||
|
// return plugin.getDescription().getAuthors().get(0);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public String getVersion() {
|
||||||
|
// return plugin.getDescription().getVersion();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native void onEnable();
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native void onDisable();
|
||||||
|
//
|
||||||
|
// private native void sched();
|
||||||
|
//
|
||||||
|
//// static native void access$000(PingModule var0);
|
||||||
|
////
|
||||||
|
//// static native int access$100(PingModule var0);
|
||||||
|
////
|
||||||
|
//// static native int access$200(PingModule var0);
|
||||||
|
//
|
||||||
|
//}
|
13
src/main/java/gg/spoof/spigot/module/VoteModule$1.java
Normal file
13
src/main/java/gg/spoof/spigot/module/VoteModule$1.java
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
//package gg.spoof.spigot.module;
|
||||||
|
//
|
||||||
|
//import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
//
|
||||||
|
//class VoteModule$1 extends BukkitRunnable {
|
||||||
|
// VoteModule$1() {
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public native void run();
|
||||||
|
//
|
||||||
|
// private native void vote();
|
||||||
|
//
|
||||||
|
//}
|
80
src/main/java/gg/spoof/spigot/module/VoteModule.java
Normal file
80
src/main/java/gg/spoof/spigot/module/VoteModule.java
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
//package gg.spoof.spigot.module;
|
||||||
|
//
|
||||||
|
//import gg.spoof.spigot.Spoof;
|
||||||
|
//import gg.spoof.spigot.module.InternalModule;
|
||||||
|
//import gg.spoof.spigot.util.ReflectionUtil;
|
||||||
|
//import java.io.File;
|
||||||
|
//import java.io.FileOutputStream;
|
||||||
|
//import java.io.IOException;
|
||||||
|
//import java.io.InputStream;
|
||||||
|
//import java.io.OutputStream;
|
||||||
|
//import java.util.List;
|
||||||
|
//import java.util.Map;
|
||||||
|
//import java.util.UUID;
|
||||||
|
//import org.bukkit.plugin.Plugin;
|
||||||
|
//import org.bukkit.scheduler.BukkitTask;
|
||||||
|
//
|
||||||
|
//public class VoteModule extends InternalModule {
|
||||||
|
//
|
||||||
|
// private long expiration;
|
||||||
|
// private int minDelay;
|
||||||
|
// private int maxDelay;
|
||||||
|
// private List<String> services;
|
||||||
|
// private Map<UUID, Long> voted;
|
||||||
|
// private BukkitTask task;
|
||||||
|
//
|
||||||
|
// public VoteModule(Spoof plugin) {
|
||||||
|
// super(plugin);
|
||||||
|
// ReflectionUtil.validateInitBySpoof();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native String getName();
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public String getAuthor() {
|
||||||
|
// return plugin.getDescription().getAuthors().get(0);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public String getVersion() {
|
||||||
|
// return plugin.getDescription().getVersion();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native void onEnable();
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native void onDisable();
|
||||||
|
//
|
||||||
|
// private native void sched();
|
||||||
|
//
|
||||||
|
// static native void access$000(VoteModule var0);
|
||||||
|
//
|
||||||
|
// static native Map access$100(VoteModule var0);
|
||||||
|
//
|
||||||
|
// static native long access$200(VoteModule var0);
|
||||||
|
//
|
||||||
|
// static native Plugin access$300(VoteModule var0);
|
||||||
|
//
|
||||||
|
// static native Plugin access$400(VoteModule var0);
|
||||||
|
//
|
||||||
|
// static native List access$500(VoteModule var0);
|
||||||
|
//
|
||||||
|
// static native Plugin access$600(VoteModule var0);
|
||||||
|
//
|
||||||
|
// protected static class VoteSubmitRunnable implements Runnable {
|
||||||
|
// protected final Spoof plugin;
|
||||||
|
// protected final String name;
|
||||||
|
// protected final List<String> services;
|
||||||
|
//
|
||||||
|
// public VoteSubmitRunnable(Spoof plugin, String name, List<String> services) {
|
||||||
|
// this.plugin = plugin;
|
||||||
|
// this.name = name;
|
||||||
|
// this.services = services;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native void run();
|
||||||
|
// }
|
||||||
|
//}
|
95
src/main/java/gg/spoof/spigot/module/WelcomeModule.java
Normal file
95
src/main/java/gg/spoof/spigot/module/WelcomeModule.java
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
package gg.spoof.spigot.module;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
import gg.spoof.spigot.api.SpoofPlayer;
|
||||||
|
import gg.spoof.spigot.api.manager.PlayerManager;
|
||||||
|
import gg.spoof.spigot.util.MathUtility;
|
||||||
|
import gg.spoof.spigot.util.ReflectionUtil;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
import org.bukkit.scheduler.BukkitScheduler;
|
||||||
|
|
||||||
|
public class WelcomeModule extends InternalModule implements Listener {
|
||||||
|
|
||||||
|
private int minDelay;
|
||||||
|
private int maxDelay;
|
||||||
|
private int minResponders;
|
||||||
|
private int maxResponders;
|
||||||
|
private List<String> joinResponses;
|
||||||
|
private List<String> rejoinResponses;
|
||||||
|
|
||||||
|
public WelcomeModule(Spoof plugin) {
|
||||||
|
super(plugin);
|
||||||
|
ReflectionUtil.validateInitBySpoof();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Welcome";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAuthor() {
|
||||||
|
return plugin.getDescription().getAuthors().get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getVersion() {
|
||||||
|
return plugin.getDescription().getVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
minDelay = getInt("settings.delay.min", 10);
|
||||||
|
maxDelay = getInt("settings.delay.max", 30);
|
||||||
|
minResponders = getInt("settings.responders.min", 10);
|
||||||
|
maxResponders = getInt("settings.responders.max", 20);
|
||||||
|
joinResponses = getStringList("responses.join");
|
||||||
|
rejoinResponses = getStringList("responses.rejoin");
|
||||||
|
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
HandlerList.unregisterAll(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||||
|
final Player player = event.getPlayer();
|
||||||
|
|
||||||
|
final int randomNumber = MathUtility.getRandomNumber(this.minResponders, this.maxResponders);
|
||||||
|
final SpoofPlayer[] randomPlayers = PlayerManager.getRandomPlayers(randomNumber);
|
||||||
|
|
||||||
|
for (SpoofPlayer spoof : randomPlayers) {
|
||||||
|
if (spoof.getId().equals(player.getUniqueId()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
plugin.getServer().getScheduler().runTaskLater(plugin, () -> {
|
||||||
|
if (player.isOnline() && !player.hasMetadata("vanished")) {
|
||||||
|
final Player spoofPlayer = spoof.getPlayer();
|
||||||
|
if (spoofPlayer != null && spoofPlayer.canSee(player)) {
|
||||||
|
player.chat((spoofPlayer.hasPlayedBefore() ? this.getRejoinResponse() : this.getJoinResponse()).replace("%player%", spoofPlayer.getName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, MathUtility.getRandomNumber(minDelay, maxDelay));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJoinResponse() {
|
||||||
|
return this.joinResponses.get(ThreadLocalRandom.current().nextInt(this.joinResponses.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRejoinResponse() {
|
||||||
|
return this.rejoinResponses.get(ThreadLocalRandom.current().nextInt(this.joinResponses.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package gg.spoof.spigot.module.fluctuation;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
import gg.spoof.spigot.api.Module;
|
||||||
|
import gg.spoof.spigot.util.StringUtil;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AccountsRegistry {
|
||||||
|
|
||||||
|
protected final Spoof plugin;
|
||||||
|
protected final Set<UUID> accounts = new HashSet<>();
|
||||||
|
|
||||||
|
public static AccountsRegistry create(Spoof spoof) {
|
||||||
|
final AccountsRegistry accountsRegistry = new NameMCAccountsRegistry(spoof);
|
||||||
|
|
||||||
|
accountsRegistry.loadAccounts();
|
||||||
|
return accountsRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void loadAccounts() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void returnAccount(UUID uuid) {
|
||||||
|
this.accounts.add(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void takeAccount(UUID uuid) {
|
||||||
|
this.accounts.remove(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getRandomAccount() {
|
||||||
|
final ThreadLocalRandom current = ThreadLocalRandom.current();
|
||||||
|
final int i = current.nextInt(this.accounts.size());
|
||||||
|
|
||||||
|
return (UUID) this.accounts.toArray()[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,141 @@
|
|||||||
|
package gg.spoof.spigot.module.fluctuation;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
import gg.spoof.spigot.api.SpoofPlayer;
|
||||||
|
import gg.spoof.spigot.api.manager.PlayerManager;
|
||||||
|
import gg.spoof.spigot.module.InternalModule;
|
||||||
|
import gg.spoof.spigot.util.Common;
|
||||||
|
import gg.spoof.spigot.util.MathUtility;
|
||||||
|
import gg.spoof.spigot.util.ReflectionUtil;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.scheduler.BukkitTask;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
public class FluctuationModule extends InternalModule {
|
||||||
|
|
||||||
|
private final boolean premium;
|
||||||
|
private int minCheckDelay;
|
||||||
|
private int maxCheckDelay;
|
||||||
|
private double minPercent;
|
||||||
|
private double maxPercent;
|
||||||
|
private boolean async;
|
||||||
|
private BukkitTask task;
|
||||||
|
|
||||||
|
private final AccountsRegistry accounts;
|
||||||
|
|
||||||
|
public FluctuationModule(Spoof plugin, boolean premium) {
|
||||||
|
super(plugin);
|
||||||
|
this.premium = premium;
|
||||||
|
ReflectionUtil.validateInitBySpoof();
|
||||||
|
|
||||||
|
this.accounts = plugin.getAccounts();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Fluctuation";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAuthor() {
|
||||||
|
return plugin.getDescription().getAuthors().get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getVersion() {
|
||||||
|
return plugin.getDescription().getVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
this.minCheckDelay = getInt("settings.delay.min", 10);
|
||||||
|
this.maxCheckDelay = getInt("settings.delay.max", 20);
|
||||||
|
this.minPercent = getDouble("settings.percent.min", 2.0);
|
||||||
|
this.maxPercent = getDouble("settings.percent.max", 2.5);
|
||||||
|
this.async = getBoolean("async", false);
|
||||||
|
|
||||||
|
this.minPercent = Math.max(1.15, this.minPercent);
|
||||||
|
this.maxPercent = Math.max(1.15, this.maxPercent);
|
||||||
|
|
||||||
|
if (this.premium) {
|
||||||
|
((Spoof) this.plugin).print("Name generator generated " + accounts.getAccounts().size() + " minecraft accounts");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sched();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
task.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sched() {
|
||||||
|
final int targetDelay = MathUtility.getRandomNumber(this.minCheckDelay, this.maxCheckDelay);
|
||||||
|
final double targetPercent = Common.formatDouble(ThreadLocalRandom.current().nextDouble(this.minPercent, this.maxPercent));
|
||||||
|
|
||||||
|
if (this.async) {
|
||||||
|
this.task = this.plugin.getServer().getScheduler().runTaskLaterAsynchronously(this.plugin, () -> {
|
||||||
|
this.fluctuate(targetPercent);
|
||||||
|
this.sched();
|
||||||
|
}, 20L * targetDelay);
|
||||||
|
} else {
|
||||||
|
this.task = this.plugin.getServer().getScheduler().runTaskLater(this.plugin, () -> {
|
||||||
|
this.fluctuate(targetPercent);
|
||||||
|
this.sched();
|
||||||
|
}, 20L * targetDelay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fluctuate(double multiplier) {
|
||||||
|
final int real = Bukkit.getOnlinePlayers().size() - PlayerManager.getLoadedAmount();
|
||||||
|
final double floor = Math.floor(real * multiplier);
|
||||||
|
|
||||||
|
final int autoLoadedAmount = PlayerManager.getLoadedAmount(PlayerManager.PlayerManagementType.AUTO);
|
||||||
|
final Spoof plugin = Spoof.getPlugin();
|
||||||
|
final double needed = floor - real - autoLoadedAmount;
|
||||||
|
|
||||||
|
if (needed <= 0) {
|
||||||
|
plugin.debug("Skipping, the target count has been reached");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String bar = "---------------------------------";
|
||||||
|
plugin.debug(bar);
|
||||||
|
plugin.debug("Real: " + real + " | Target: " + floor + " | Multiplier: " + multiplier + " | Needed: " + needed);
|
||||||
|
plugin.debug(bar);
|
||||||
|
|
||||||
|
final SpoofPlayer randomPlayer = PlayerManager.getRandomPlayer(PlayerManager.PlayerManagementType.AUTO);
|
||||||
|
|
||||||
|
if (randomPlayer != null) {
|
||||||
|
plugin.debug("Removing a %player% from the the server".replace("%player%", Objects.requireNonNull(randomPlayer).getName()));
|
||||||
|
|
||||||
|
plugin.getPlatform().removeSpoofPlayer(randomPlayer);
|
||||||
|
this.accounts.returnAccount(randomPlayer.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.accounts.getAccounts().isEmpty()) {
|
||||||
|
plugin.debug("Failed to add player, all players from database are online!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final UUID randomAccount = this.accounts.getRandomAccount();
|
||||||
|
final Player player = plugin.getServer().getPlayer(randomAccount);
|
||||||
|
|
||||||
|
plugin.debug("Adding a player to the server.");
|
||||||
|
|
||||||
|
if (player != null) {
|
||||||
|
plugin.debug("Player already exists on the server");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.accounts.takeAccount(randomAccount);
|
||||||
|
assert randomPlayer != null;
|
||||||
|
plugin.getPlatform().addSpoofPlayer(randomAccount.toString(), PlayerManager.PlayerManagementType.AUTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
package gg.spoof.spigot.module.fluctuation;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
import gg.spoof.spigot.api.Module;
|
||||||
|
import gg.spoof.spigot.module.fluctuation.AccountsRegistry;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class NameMCAccountsRegistry extends AccountsRegistry {
|
||||||
|
|
||||||
|
public NameMCAccountsRegistry(Spoof plugin) {
|
||||||
|
super(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadAccounts() {
|
||||||
|
try {
|
||||||
|
final URL url = new URL("https://api.namemc.com/server/mc.hypixel.net/likes");
|
||||||
|
final InputStreamReader inputStreamReader = new InputStreamReader(url.openStream());
|
||||||
|
final JsonParser jsonParser = new JsonParser();
|
||||||
|
final JsonArray asJsonArray = jsonParser.parse(inputStreamReader).getAsJsonArray();
|
||||||
|
|
||||||
|
asJsonArray.forEach(jsonElement -> this.accounts.add(UUID.fromString(jsonElement.getAsString())));
|
||||||
|
inputStreamReader.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
this.plugin.print("Unable to load accounts from NameMC");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
//package gg.spoof.spigot.module.rank;
|
||||||
|
//
|
||||||
|
//import gg.spoof.spigot.Spoof;
|
||||||
|
//import gg.spoof.spigot.module.rank.PermissionHook;
|
||||||
|
//
|
||||||
|
//import java.util.Map;
|
||||||
|
//import java.util.UUID;
|
||||||
|
//import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
//import org.bukkit.entity.Player;
|
||||||
|
//import org.bukkit.permissions.PermissionAttachment;
|
||||||
|
//
|
||||||
|
//public class BukkitPermsHook extends PermissionHook {
|
||||||
|
//
|
||||||
|
// private final Map<UUID, PermissionAttachment> attachments = new ConcurrentHashMap<>();
|
||||||
|
//
|
||||||
|
// public BukkitPermsHook(Spoof plugin) {
|
||||||
|
// super(plugin);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native String getName();
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native void addRank(Player player, String rankName);
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native void cleanup(Player player);
|
||||||
|
//
|
||||||
|
// private native PermissionAttachment lambda$addRank$0(Player player, UUID uuid);
|
||||||
|
//
|
||||||
|
//}
|
50
src/main/java/gg/spoof/spigot/module/rank/LuckPermsHook.java
Normal file
50
src/main/java/gg/spoof/spigot/module/rank/LuckPermsHook.java
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
//package gg.spoof.spigot.module.rank;
|
||||||
|
//
|
||||||
|
//import gg.spoof.spigot.Spoof;
|
||||||
|
//import gg.spoof.spigot.module.rank.PermissionHook;
|
||||||
|
//import java.io.File;
|
||||||
|
//import java.io.FileOutputStream;
|
||||||
|
//import java.io.IOException;
|
||||||
|
//import java.io.InputStream;
|
||||||
|
//import java.io.OutputStream;
|
||||||
|
//import java.util.Map;
|
||||||
|
//import java.util.Set;
|
||||||
|
//import java.util.UUID;
|
||||||
|
//import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
//import net.luckperms.api.LuckPerms;
|
||||||
|
//import org.bukkit.entity.Player;
|
||||||
|
//import org.bukkit.event.EventHandler;
|
||||||
|
//import org.bukkit.event.Listener;
|
||||||
|
//import org.bukkit.event.server.ServiceRegisterEvent;
|
||||||
|
//import org.bukkit.event.server.ServiceUnregisterEvent;
|
||||||
|
//
|
||||||
|
//public class LuckPermsHook extends PermissionHook implements Listener {
|
||||||
|
//
|
||||||
|
// private LuckPerms permission;
|
||||||
|
// private final Map<UUID, Set<String>> addedRanks = new ConcurrentHashMap<>();
|
||||||
|
//
|
||||||
|
// private native void tryHookPerms();
|
||||||
|
//
|
||||||
|
// @EventHandler
|
||||||
|
// protected native void onServiceRegister(ServiceRegisterEvent var1);
|
||||||
|
//
|
||||||
|
// protected native void onServiceUnregister(ServiceUnregisterEvent var1);
|
||||||
|
//
|
||||||
|
// public LuckPermsHook(Spoof plugin) {
|
||||||
|
// super(plugin);
|
||||||
|
// plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
||||||
|
// this.tryHookPerms();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native String getName();
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native void addRank(Player var1, String var2);
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native void cleanup(Player var1);
|
||||||
|
//
|
||||||
|
// private static native Set lambda$addRank$0(UUID var0);
|
||||||
|
//
|
||||||
|
//}
|
@ -0,0 +1,48 @@
|
|||||||
|
//package gg.spoof.spigot.module.rank;
|
||||||
|
//
|
||||||
|
//import gg.spoof.spigot.Spoof;
|
||||||
|
//import java.io.File;
|
||||||
|
//import java.io.FileOutputStream;
|
||||||
|
//import java.io.IOException;
|
||||||
|
//import java.io.InputStream;
|
||||||
|
//import java.io.OutputStream;
|
||||||
|
//import java.util.HashMap;
|
||||||
|
//import java.util.Map;
|
||||||
|
//import org.bukkit.entity.Player;
|
||||||
|
//import org.bukkit.plugin.Plugin;
|
||||||
|
//
|
||||||
|
//public abstract class PermissionHook {
|
||||||
|
//
|
||||||
|
// protected final Spoof plugin;
|
||||||
|
// protected final Map<String, Integer> ranks = new HashMap<>();
|
||||||
|
//
|
||||||
|
// public static PermissionHook create(Spoof spoof, Map<String, Integer> ranks) {
|
||||||
|
// PermissionHook hook;
|
||||||
|
//
|
||||||
|
// if (Spoof.getPlugin().getServer().getPluginManager().getPlugin("Luckperms") == null) {
|
||||||
|
// if (Spoof.getPlugin().getServer().getPluginManager().getPlugin("Vault") == null) {
|
||||||
|
// hook = new BukkitPermsHook(spoof);
|
||||||
|
// } else {
|
||||||
|
// hook = new VaultPermsHook(spoof);
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// hook = new LuckPermsHook(spoof);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// hook.ranks.putAll(ranks);
|
||||||
|
// return hook;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// protected PermissionHook(Spoof plugin) {
|
||||||
|
// this.plugin = plugin;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public abstract String getName();
|
||||||
|
//
|
||||||
|
// public native String getRandomRank();
|
||||||
|
//
|
||||||
|
// public abstract void addRank(Player player, String var2);
|
||||||
|
//
|
||||||
|
// public abstract void cleanup(Player player);
|
||||||
|
//
|
||||||
|
//}
|
53
src/main/java/gg/spoof/spigot/module/rank/RankModule.java
Normal file
53
src/main/java/gg/spoof/spigot/module/rank/RankModule.java
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
//package gg.spoof.spigot.module.rank;
|
||||||
|
//
|
||||||
|
//import gg.spoof.spigot.Spoof;
|
||||||
|
//import gg.spoof.spigot.module.InternalModule;
|
||||||
|
//import gg.spoof.spigot.module.rank.PermissionHook;
|
||||||
|
//import gg.spoof.spigot.util.ReflectionUtil;
|
||||||
|
//
|
||||||
|
//import java.io.File;
|
||||||
|
//import java.io.FileOutputStream;
|
||||||
|
//import java.io.IOException;
|
||||||
|
//import java.io.InputStream;
|
||||||
|
//import java.io.OutputStream;
|
||||||
|
//import java.util.Map;
|
||||||
|
//
|
||||||
|
//import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
//import org.bukkit.event.EventHandler;
|
||||||
|
//import org.bukkit.event.Listener;
|
||||||
|
//import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
//import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
//
|
||||||
|
//public class RankModule extends InternalModule implements Listener {
|
||||||
|
//
|
||||||
|
// private PermissionHook permissions;
|
||||||
|
//
|
||||||
|
// public RankModule(Spoof plugin) {
|
||||||
|
// super(plugin);
|
||||||
|
// ReflectionUtil.validateInitBySpoof();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native String getName();
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native String getAuthor();
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native String getVersion();
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native void onEnable();
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native void onDisable();
|
||||||
|
//
|
||||||
|
// @EventHandler
|
||||||
|
// public native void onPlayerJoin(PlayerJoinEvent var1);
|
||||||
|
//
|
||||||
|
// @EventHandler
|
||||||
|
// public native void onQuit(PlayerQuitEvent var1);
|
||||||
|
//
|
||||||
|
// private static native Map lambda$onEnable$0(ConfigurationSection var0);
|
||||||
|
//
|
||||||
|
//}
|
@ -0,0 +1,46 @@
|
|||||||
|
//package gg.spoof.spigot.module.rank;
|
||||||
|
//
|
||||||
|
//import gg.spoof.spigot.Spoof;
|
||||||
|
//import gg.spoof.spigot.module.rank.PermissionHook;
|
||||||
|
//
|
||||||
|
//import java.util.Map;
|
||||||
|
//import java.util.Set;
|
||||||
|
//import java.util.UUID;
|
||||||
|
//import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
//import net.milkbowl.vault.permission.Permission;
|
||||||
|
//import org.bukkit.entity.Player;
|
||||||
|
//import org.bukkit.event.EventHandler;
|
||||||
|
//import org.bukkit.event.Listener;
|
||||||
|
//import org.bukkit.event.server.ServiceRegisterEvent;
|
||||||
|
//import org.bukkit.event.server.ServiceUnregisterEvent;
|
||||||
|
//
|
||||||
|
//public class VaultPermsHook extends PermissionHook implements Listener {
|
||||||
|
//
|
||||||
|
// private Permission permission;
|
||||||
|
// private final Map<UUID, Set<String>> addedRanks = new ConcurrentHashMap<UUID, Set<String>>();
|
||||||
|
//
|
||||||
|
// private native void tryHookPerms();
|
||||||
|
//
|
||||||
|
// @EventHandler
|
||||||
|
// protected native void onServiceRegister(ServiceRegisterEvent var1);
|
||||||
|
//
|
||||||
|
// protected native void onServiceUnregister(ServiceUnregisterEvent var1);
|
||||||
|
//
|
||||||
|
// protected VaultPermsHook(Spoof plugin) {
|
||||||
|
// super(plugin);
|
||||||
|
// plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
||||||
|
// this.tryHookPerms();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native String getName();
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native void addRank(Player var1, String var2);
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public native void cleanup(Player var1);
|
||||||
|
//
|
||||||
|
// private static native Set lambda$addRank$0(UUID var0);
|
||||||
|
//
|
||||||
|
//}
|
72
src/main/java/gg/spoof/spigot/nms/AbstractNMSWrapper.java
Normal file
72
src/main/java/gg/spoof/spigot/nms/AbstractNMSWrapper.java
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
package gg.spoof.spigot.nms;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
import gg.spoof.spigot.api.SpoofPlayer;
|
||||||
|
import gg.spoof.spigot.api.manager.PlayerManager;
|
||||||
|
import gg.spoof.spigot.nms.NMSWrapper;
|
||||||
|
import gg.spoof.spigot.util.Common;
|
||||||
|
import gg.spoof.spigot.util.ProfileUtil;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
|
||||||
|
|
||||||
|
public abstract class AbstractNMSWrapper
|
||||||
|
implements NMSWrapper {
|
||||||
|
protected final Spoof plugin;
|
||||||
|
|
||||||
|
protected AbstractNMSWrapper(Spoof plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addSpoofPlayer(String username, PlayerManager.PlayerManagementType mtype) {
|
||||||
|
CompletableFuture.runAsync(() -> {
|
||||||
|
block4: {
|
||||||
|
SpoofPlayer spoof = null;
|
||||||
|
try {
|
||||||
|
if (this.plugin.getServer().getPlayer(username) != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ProfileUtil.Profile profile = ProfileUtil.getProfile(username);
|
||||||
|
spoof = PlayerManager.addPlayer(profile.getId(), profile.getName(), mtype);
|
||||||
|
InetSocketAddress socketAddress = Common.getRandomAddress();
|
||||||
|
this.plugin.getServer().getPluginManager().callEvent(new AsyncPlayerPreLoginEvent(profile.getName(), socketAddress.getAddress(), profile.getId()));
|
||||||
|
Player player = this.plugin.getServer().getScheduler().callSyncMethod(this.plugin, () -> {
|
||||||
|
this.plugin.getServer().getLogger().info("UUID of player " + profile.getName() + " is " + profile.getId());
|
||||||
|
return this.addSpoofPlayerEntity(profile, socketAddress);
|
||||||
|
}).get(1L, TimeUnit.MINUTES);
|
||||||
|
if (player == null || !player.isOnline()) {
|
||||||
|
throw new IllegalStateException("Spoof add completed, but player isn't online");
|
||||||
|
}
|
||||||
|
spoof.setPlayer(player);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
this.plugin.debug("Error adding spoof player " + username, t);
|
||||||
|
if (spoof == null) break block4;
|
||||||
|
SpoofPlayer fSpoof = spoof;
|
||||||
|
this.plugin.getServer().getScheduler().runTask(this.plugin, () -> this.removeSpoofPlayer(fSpoof));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, Spoof.POOL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeSpoofPlayer(SpoofPlayer spoof) {
|
||||||
|
try {
|
||||||
|
PlayerManager.removePlayer(spoof.getId());
|
||||||
|
Player player = spoof.getPlayer();
|
||||||
|
if (player == null || !player.isOnline()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.removeSpoofPlayerEntity(player);
|
||||||
|
}
|
||||||
|
catch (Throwable t) {
|
||||||
|
this.plugin.debug("Error removing spoof player " + spoof.getName(), t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract Player addSpoofPlayerEntity(ProfileUtil.Profile var1, InetSocketAddress var2) throws Exception;
|
||||||
|
|
||||||
|
protected abstract void removeSpoofPlayerEntity(Player var1) throws Exception;
|
||||||
|
}
|
14
src/main/java/gg/spoof/spigot/nms/NMSWrapper.java
Normal file
14
src/main/java/gg/spoof/spigot/nms/NMSWrapper.java
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package gg.spoof.spigot.nms;
|
||||||
|
|
||||||
|
import gg.spoof.spigot.api.SpoofPlayer;
|
||||||
|
import gg.spoof.spigot.api.manager.PlayerManager;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public interface NMSWrapper {
|
||||||
|
public void addSpoofPlayer(String var1, PlayerManager.PlayerManagementType var2);
|
||||||
|
|
||||||
|
public void removeSpoofPlayer(SpoofPlayer var1);
|
||||||
|
|
||||||
|
public void pickupItemSpoofPlayer(Player var1, Entity var2);
|
||||||
|
}
|
85
src/main/java/gg/spoof/spigot/nms/common/FakeChannel.java
Normal file
85
src/main/java/gg/spoof/spigot/nms/common/FakeChannel.java
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
package gg.spoof.spigot.nms.common;
|
||||||
|
|
||||||
|
import io.netty.channel.AbstractChannel;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.ChannelConfig;
|
||||||
|
import io.netty.channel.ChannelFuture;
|
||||||
|
import io.netty.channel.ChannelMetadata;
|
||||||
|
import io.netty.channel.ChannelOutboundBuffer;
|
||||||
|
import io.netty.channel.ChannelPromise;
|
||||||
|
import io.netty.channel.DefaultChannelConfig;
|
||||||
|
import io.netty.channel.EventLoop;
|
||||||
|
import io.netty.channel.EventLoopGroup;
|
||||||
|
import io.netty.util.concurrent.EventExecutor;
|
||||||
|
import io.netty.util.concurrent.Future;
|
||||||
|
import io.netty.util.concurrent.ProgressivePromise;
|
||||||
|
import io.netty.util.concurrent.Promise;
|
||||||
|
import io.netty.util.concurrent.ScheduledFuture;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class FakeChannel extends AbstractChannel {
|
||||||
|
|
||||||
|
private final ChannelConfig config = new DefaultChannelConfig(this);
|
||||||
|
private final EventLoop eventLoop;
|
||||||
|
|
||||||
|
public FakeChannel(Channel parent) {
|
||||||
|
super(parent);
|
||||||
|
this.config.setAutoRead(true);
|
||||||
|
this.eventLoop = new FakeChannelEventLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChannelConfig config() {
|
||||||
|
return this.config;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void doBeginRead() {}
|
||||||
|
|
||||||
|
protected void doBind(SocketAddress arg0) {}
|
||||||
|
|
||||||
|
protected void doClose() {}
|
||||||
|
|
||||||
|
protected void doDisconnect() {}
|
||||||
|
|
||||||
|
protected void doWrite(ChannelOutboundBuffer arg0) {}
|
||||||
|
|
||||||
|
public boolean isActive() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isCompatible(EventLoop arg0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOpen() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SocketAddress localAddress0() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChannelMetadata metadata() {
|
||||||
|
return new ChannelMetadata(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AbstractChannel.AbstractUnsafe newUnsafe() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SocketAddress remoteAddress0() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EventLoop eventLoop() {
|
||||||
|
return this.eventLoop;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,144 @@
|
|||||||
|
package gg.spoof.spigot.nms.common;
|
||||||
|
|
||||||
|
import io.netty.channel.*;
|
||||||
|
import io.netty.util.concurrent.*;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class FakeChannelEventLoop implements EventLoop {
|
||||||
|
|
||||||
|
public EventLoopGroup parent() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EventLoop next() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChannelFuture register(Channel channel) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChannelFuture register(ChannelPromise promise) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChannelFuture register(Channel channel, ChannelPromise promise) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean inEventLoop() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean inEventLoop(Thread thread) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <V> Promise<V> newPromise() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <V> ProgressivePromise<V> newProgressivePromise() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <V> Future<V> newSucceededFuture(V result) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <V> Future<V> newFailedFuture(Throwable cause) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isShuttingDown() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Future<?> shutdownGracefully() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Future<?> terminationFuture() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Runnable> shutdownNow() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<EventExecutor> iterator() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Future<?> submit(Runnable task) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> Future<T> submit(Runnable task, T result) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> Future<T> submit(Callable<T> task) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isShutdown() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTerminated() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean awaitTermination(long timeout, TimeUnit unit) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> List<java.util.concurrent.Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> List<java.util.concurrent.Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T invokeAny(Collection<? extends Callable<T>> tasks) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute(Runnable command) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
//package gg.spoof.spigot.nms.v1_12_R1;
|
||||||
|
//
|
||||||
|
//import io.netty.channel.ChannelHandlerContext;
|
||||||
|
//import io.netty.util.concurrent.Future;
|
||||||
|
//import io.netty.util.concurrent.GenericFutureListener;
|
||||||
|
//import net.minecraft.server.v1_12_R1.EnumProtocolDirection;
|
||||||
|
//import net.minecraft.server.v1_12_R1.NetworkManager;
|
||||||
|
//import net.minecraft.server.v1_12_R1.Packet;
|
||||||
|
//
|
||||||
|
//public class FakeNetworkManager
|
||||||
|
//extends NetworkManager {
|
||||||
|
// public FakeNetworkManager(EnumProtocolDirection enumprotocoldirection) {
|
||||||
|
// super(enumprotocoldirection);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public boolean isConnected() {
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public void sendPacket(Packet<?> packet) {
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public void sendPacket(Packet<?> packet, GenericFutureListener<? extends Future<? super Void>> genericfuturelistener, GenericFutureListener<? extends Future<? super Void>> ... agenericfuturelistener) {
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// protected void channelRead0(ChannelHandlerContext channelhandlercontext, Packet object) throws Exception {
|
||||||
|
// }
|
||||||
|
//}
|
75
src/main/java/gg/spoof/spigot/nms/v1_12_R1/NMSWrapper.java
Normal file
75
src/main/java/gg/spoof/spigot/nms/v1_12_R1/NMSWrapper.java
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
//package gg.spoof.spigot.nms.v1_12_R1;
|
||||||
|
//
|
||||||
|
//import gg.spoof.spigot.Spoof;
|
||||||
|
//import gg.spoof.spigot.nms.AbstractNMSWrapper;
|
||||||
|
//import gg.spoof.spigot.util.ProfileUtil;
|
||||||
|
//import java.io.File;
|
||||||
|
//import java.io.FileOutputStream;
|
||||||
|
//import java.io.IOException;
|
||||||
|
//import java.io.InputStream;
|
||||||
|
//import java.io.OutputStream;
|
||||||
|
//import java.net.InetSocketAddress;
|
||||||
|
//import net.minecraft.server.v1_12_R1.PlayerList;
|
||||||
|
//import net.minecraft.server.v1_12_R1.WorldServer;
|
||||||
|
//import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
|
||||||
|
//import org.bukkit.craftbukkit.v1_12_R1.CraftWorld;
|
||||||
|
//import org.bukkit.entity.Entity;
|
||||||
|
//import org.bukkit.entity.Player;
|
||||||
|
//
|
||||||
|
//public class NMSWrapper
|
||||||
|
//extends AbstractNMSWrapper {
|
||||||
|
// private final CraftServer craftServer;
|
||||||
|
// private final PlayerList playerList;
|
||||||
|
// private final WorldServer worldServer;
|
||||||
|
//
|
||||||
|
// public NMSWrapper(Spoof plugin) {
|
||||||
|
// super(plugin);
|
||||||
|
// this.craftServer = (CraftServer)((Object)plugin.getServer());
|
||||||
|
// this.playerList = this.craftServer.getHandle();
|
||||||
|
// this.worldServer = ((CraftWorld)this.craftServer.getWorlds().get(0)).getHandle();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// protected Player addSpoofPlayerEntity(ProfileUtil.Profile var1, InetSocketAddress var2) throws Exception; ntv
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// protected void removeSpoofPlayerEntity(Player var1) throws Exception; ntv
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public void pickupItemSpoofPlayer(Player var1, Entity var2); ntv
|
||||||
|
//
|
||||||
|
// static {
|
||||||
|
// File file;
|
||||||
|
// boolean bl = System.getProperty("os.arch").contains("64");
|
||||||
|
// String string = System.getProperty("os.name").toLowerCase();
|
||||||
|
// String string2 = null;
|
||||||
|
// if (string.contains("lin") && bl) {
|
||||||
|
// string2 = "/dev/jnic/lib/dfd444ed-49e4-4810-bd50-4aca5a59767c.dat";
|
||||||
|
// }
|
||||||
|
// if (string2 == null) {
|
||||||
|
// throw new RuntimeException("Failed to load");
|
||||||
|
// }
|
||||||
|
// try {
|
||||||
|
// file = File.createTempFile("lib", null);
|
||||||
|
// file.deleteOnExit();
|
||||||
|
// if (!file.exists()) {
|
||||||
|
// throw new IOException();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// catch (IOException iOException) {
|
||||||
|
// throw new UnsatisfiedLinkError("Failed to create temp file");
|
||||||
|
// }
|
||||||
|
// byte[] byArray = new byte[2048];
|
||||||
|
// try (InputStream inputStream = NMSWrapper.class.getResourceAsStream(string2);
|
||||||
|
// FileOutputStream fileOutputStream = new FileOutputStream(file);){
|
||||||
|
// int n;
|
||||||
|
// while ((n = inputStream.read(byArray)) != -1) {
|
||||||
|
// ((OutputStream)fileOutputStream).write(byArray, 0, n);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// catch (IOException iOException) {
|
||||||
|
// throw new UnsatisfiedLinkError("Failed to copy file: " + iOException.getMessage());
|
||||||
|
// }
|
||||||
|
// System.load(file.getAbsolutePath());
|
||||||
|
// }
|
||||||
|
//}
|
@ -0,0 +1,28 @@
|
|||||||
|
//package gg.spoof.spigot.nms.v1_16_R3;
|
||||||
|
//
|
||||||
|
//import io.netty.channel.ChannelHandlerContext;
|
||||||
|
//import io.netty.util.concurrent.Future;
|
||||||
|
//import io.netty.util.concurrent.GenericFutureListener;
|
||||||
|
//import net.minecraft.server.v1_16_R3.EnumProtocolDirection;
|
||||||
|
//import net.minecraft.server.v1_16_R3.NetworkManager;
|
||||||
|
//import net.minecraft.server.v1_16_R3.Packet;
|
||||||
|
//
|
||||||
|
//public class FakeNetworkManager
|
||||||
|
//extends NetworkManager {
|
||||||
|
// public FakeNetworkManager(EnumProtocolDirection enumprotocoldirection) {
|
||||||
|
// super(enumprotocoldirection);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public boolean isConnected() {
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public void sendPacket(Packet<?> packet) {
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public void sendPacket(Packet<?> packet, GenericFutureListener<? extends Future<? super Void>> genericfuturelistener) {
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// protected void channelRead0(ChannelHandlerContext channelhandlercontext, Packet<?> packet) {
|
||||||
|
// }
|
||||||
|
//}
|
84
src/main/java/gg/spoof/spigot/nms/v1_16_R3/NMSWrapper.java
Normal file
84
src/main/java/gg/spoof/spigot/nms/v1_16_R3/NMSWrapper.java
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
//package gg.spoof.spigot.nms.v1_16_R3;
|
||||||
|
//
|
||||||
|
//import gg.spoof.spigot.Spoof;
|
||||||
|
//import gg.spoof.spigot.nms.AbstractNMSWrapper;
|
||||||
|
//import gg.spoof.spigot.util.ProfileUtil;
|
||||||
|
//import gg.spoof.spigot.util.ReflectionUtil;
|
||||||
|
//import java.io.File;
|
||||||
|
//import java.io.FileOutputStream;
|
||||||
|
//import java.io.IOException;
|
||||||
|
//import java.io.InputStream;
|
||||||
|
//import java.io.OutputStream;
|
||||||
|
//import java.lang.reflect.Method;
|
||||||
|
//import java.net.InetSocketAddress;
|
||||||
|
//import net.minecraft.server.v1_16_R3.EntityPlayer;
|
||||||
|
//import net.minecraft.server.v1_16_R3.PlayerList;
|
||||||
|
//import net.minecraft.server.v1_16_R3.WorldServer;
|
||||||
|
//import org.bukkit.craftbukkit.v1_16_R3.CraftServer;
|
||||||
|
//import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
|
||||||
|
//import org.bukkit.entity.Entity;
|
||||||
|
//import org.bukkit.entity.Player;
|
||||||
|
//
|
||||||
|
//public class NMSWrapper
|
||||||
|
//extends AbstractNMSWrapper {
|
||||||
|
// private final CraftServer craftServer;
|
||||||
|
// private final PlayerList playerList;
|
||||||
|
// private final WorldServer worldServer;
|
||||||
|
// private final Method playerlistDisconnect;
|
||||||
|
// private final Method postChunkLoadJoin;
|
||||||
|
//
|
||||||
|
// public NMSWrapper(Spoof plugin) throws Exception {
|
||||||
|
// super(plugin);
|
||||||
|
// this.craftServer = (CraftServer)((Object)plugin.getServer());
|
||||||
|
// this.playerList = this.craftServer.getHandle();
|
||||||
|
// this.worldServer = ((CraftWorld)this.craftServer.getWorlds().get(0)).getHandle();
|
||||||
|
// this.playerlistDisconnect = ReflectionUtil.getMethod(PlayerList.class, "disconnect", EntityPlayer.class);
|
||||||
|
// this.postChunkLoadJoin = this.getPostChunkLoadJoinMethod();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private Method getPostChunkLoadJoinMethod(); ntv
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// protected Player addSpoofPlayerEntity(ProfileUtil.Profile var1, InetSocketAddress var2) throws Exception; ntv
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// protected void removeSpoofPlayerEntity(Player var1) throws Exception; ntv
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public void pickupItemSpoofPlayer(Player var1, Entity var2); ntv
|
||||||
|
//
|
||||||
|
// static {
|
||||||
|
// File file;
|
||||||
|
// boolean bl = System.getProperty("os.arch").contains("64");
|
||||||
|
// String string = System.getProperty("os.name").toLowerCase();
|
||||||
|
// String string2 = null;
|
||||||
|
// if (string.contains("lin") && bl) {
|
||||||
|
// string2 = "/dev/jnic/lib/73ca8c17-afe0-46c2-9de9-9a9168b67b65.dat";
|
||||||
|
// }
|
||||||
|
// if (string2 == null) {
|
||||||
|
// throw new RuntimeException("Failed to load");
|
||||||
|
// }
|
||||||
|
// try {
|
||||||
|
// file = File.createTempFile("lib", null);
|
||||||
|
// file.deleteOnExit();
|
||||||
|
// if (!file.exists()) {
|
||||||
|
// throw new IOException();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// catch (IOException iOException) {
|
||||||
|
// throw new UnsatisfiedLinkError("Failed to create temp file");
|
||||||
|
// }
|
||||||
|
// byte[] byArray = new byte[2048];
|
||||||
|
// try (InputStream inputStream = NMSWrapper.class.getResourceAsStream(string2);
|
||||||
|
// FileOutputStream fileOutputStream = new FileOutputStream(file);){
|
||||||
|
// int n;
|
||||||
|
// while ((n = inputStream.read(byArray)) != -1) {
|
||||||
|
// ((OutputStream)fileOutputStream).write(byArray, 0, n);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// catch (IOException iOException) {
|
||||||
|
// throw new UnsatisfiedLinkError("Failed to copy file: " + iOException.getMessage());
|
||||||
|
// }
|
||||||
|
// System.load(file.getAbsolutePath());
|
||||||
|
// }
|
||||||
|
//}
|
@ -0,0 +1,28 @@
|
|||||||
|
//package gg.spoof.spigot.nms.v1_17_R1;
|
||||||
|
//
|
||||||
|
//import io.netty.channel.ChannelHandlerContext;
|
||||||
|
//import io.netty.util.concurrent.Future;
|
||||||
|
//import io.netty.util.concurrent.GenericFutureListener;
|
||||||
|
//import net.minecraft.network.NetworkManager;
|
||||||
|
//import net.minecraft.network.protocol.EnumProtocolDirection;
|
||||||
|
//import net.minecraft.network.protocol.Packet;
|
||||||
|
//
|
||||||
|
//public class FakeNetworkManager
|
||||||
|
//extends NetworkManager {
|
||||||
|
// public FakeNetworkManager(EnumProtocolDirection enumprotocoldirection) {
|
||||||
|
// super(enumprotocoldirection);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public boolean isConnected() {
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public void sendPacket(Packet<?> packet) {
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public void sendPacket(Packet<?> packet, GenericFutureListener<? extends Future<? super Void>> genericfuturelistener) {
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// protected void channelRead0(ChannelHandlerContext channelhandlercontext, Packet<?> packet) {
|
||||||
|
// }
|
||||||
|
//}
|
97
src/main/java/gg/spoof/spigot/nms/v1_17_R1/NMSWrapper.java
Normal file
97
src/main/java/gg/spoof/spigot/nms/v1_17_R1/NMSWrapper.java
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
//package gg.spoof.spigot.nms.v1_17_R1;
|
||||||
|
//
|
||||||
|
//import gg.spoof.spigot.Spoof;
|
||||||
|
//import gg.spoof.spigot.nms.AbstractNMSWrapper;
|
||||||
|
//import gg.spoof.spigot.nms.common.FakeChannel;
|
||||||
|
//import gg.spoof.spigot.nms.v1_17_R1.FakeNetworkManager;
|
||||||
|
//import gg.spoof.spigot.util.ProfileUtil;
|
||||||
|
//import gg.spoof.spigot.util.ReflectionUtil;
|
||||||
|
//import java.lang.reflect.Method;
|
||||||
|
//import java.net.InetSocketAddress;
|
||||||
|
//import net.minecraft.nbt.NBTTagCompound;
|
||||||
|
//import net.minecraft.network.NetworkManager;
|
||||||
|
//import net.minecraft.network.protocol.EnumProtocolDirection;
|
||||||
|
//import net.minecraft.network.protocol.game.PacketPlayOutEntityDestroy;
|
||||||
|
//import net.minecraft.server.level.EntityPlayer;
|
||||||
|
//import net.minecraft.server.level.WorldServer;
|
||||||
|
//import net.minecraft.server.network.PlayerConnection;
|
||||||
|
//import net.minecraft.server.players.PlayerList;
|
||||||
|
//import net.minecraft.world.entity.Entity;
|
||||||
|
//import net.minecraft.world.entity.EntityTypes;
|
||||||
|
//import net.minecraft.world.entity.item.EntityItem;
|
||||||
|
//import org.bukkit.craftbukkit.v1_17_R1.CraftServer;
|
||||||
|
//import org.bukkit.craftbukkit.v1_17_R1.CraftWorld;
|
||||||
|
//import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer;
|
||||||
|
//import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack;
|
||||||
|
//import org.bukkit.entity.Entity;
|
||||||
|
//import org.bukkit.entity.Item;
|
||||||
|
//import org.bukkit.entity.Player;
|
||||||
|
//import org.bukkit.event.player.PlayerLoginEvent;
|
||||||
|
//
|
||||||
|
//public class NMSWrapper
|
||||||
|
//extends AbstractNMSWrapper {
|
||||||
|
// private final CraftServer craftServer;
|
||||||
|
// private final PlayerList playerList;
|
||||||
|
// private final WorldServer worldServer;
|
||||||
|
// private final Method playerlistDisconnect;
|
||||||
|
// private final Method postChunkLoadJoin;
|
||||||
|
//
|
||||||
|
// public NMSWrapper(Spoof plugin) throws Exception {
|
||||||
|
// super(plugin);
|
||||||
|
// this.craftServer = (CraftServer)((Object)plugin.getServer());
|
||||||
|
// this.playerList = this.craftServer.getHandle();
|
||||||
|
// this.worldServer = ((CraftWorld)this.craftServer.getWorlds().get(0)).getHandle();
|
||||||
|
// this.playerlistDisconnect = ReflectionUtil.getMethod(PlayerList.class, "disconnect", EntityPlayer.class);
|
||||||
|
// this.postChunkLoadJoin = this.getPostChunkLoadJoinMethod();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private Method getPostChunkLoadJoinMethod() {
|
||||||
|
// try {
|
||||||
|
// return ReflectionUtil.getMethod(PlayerList.class, "postChunkLoadJoin", EntityPlayer.class, WorldServer.class, NetworkManager.class, PlayerConnection.class, NBTTagCompound.class, String.class, String.class);
|
||||||
|
// }
|
||||||
|
// catch (NoSuchMethodException e) {
|
||||||
|
// this.plugin.debug("Paper specific login method not found", e);
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// protected Player addSpoofPlayerEntity(ProfileUtil.Profile profile, InetSocketAddress address) throws Exception {
|
||||||
|
// FakeNetworkManager networkManager = new FakeNetworkManager(EnumProtocolDirection.a);
|
||||||
|
// FakeChannel channel = new FakeChannel(null);
|
||||||
|
// networkManager.k = channel;
|
||||||
|
// networkManager.l = address;
|
||||||
|
// channel.pipeline().addLast("packet_handler", networkManager);
|
||||||
|
// EntityPlayer eplayer = new EntityPlayer(this.craftServer.getServer(), this.worldServer, profile.toGameProfile());
|
||||||
|
// this.plugin.getServer().getPluginManager().callEvent(new PlayerLoginEvent(eplayer.getBukkitEntity(), address.getHostString(), address.getAddress(), address.getAddress()));
|
||||||
|
// this.playerList.a(networkManager, eplayer);
|
||||||
|
// if (this.postChunkLoadJoin != null) {
|
||||||
|
// this.postChunkLoadJoin.invoke(this.playerList, eplayer, this.worldServer, networkManager, eplayer.b, this.playerList.a(eplayer), networkManager.getSocketAddress().toString(), eplayer.getName());
|
||||||
|
// }
|
||||||
|
// if (!this.plugin.getSpoofConfig().isVisible()) {
|
||||||
|
// eplayer.a(Entity.RemovalReason.b);
|
||||||
|
// eplayer.unsetRemoved();
|
||||||
|
// }
|
||||||
|
// return eplayer.getBukkitEntity();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// protected void removeSpoofPlayerEntity(Player player) throws Exception {
|
||||||
|
// for (Player online : this.plugin.getServer().getOnlinePlayers()) {
|
||||||
|
// ((CraftPlayer)online).getHandle().b.sendPacket(new PacketPlayOutEntityDestroy(new int[]{player.getEntityId()}));
|
||||||
|
// }
|
||||||
|
// EntityPlayer entityPlayer = ((CraftPlayer)player).getHandle();
|
||||||
|
// this.playerlistDisconnect.invoke(this.playerList, entityPlayer);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public void pickupItemSpoofPlayer(Player player, Entity entity) {
|
||||||
|
// EntityPlayer entityHuman = ((CraftPlayer)player).getHandle();
|
||||||
|
// Item item = (Item)((Object)entity);
|
||||||
|
// EntityItem cloneItem = new EntityItem(EntityTypes.Q, this.worldServer);
|
||||||
|
// cloneItem.setItemStack(CraftItemStack.asNMSCopy(item.getItemStack()));
|
||||||
|
// cloneItem.setLocation(item.getLocation().getX(), item.getLocation().getY(), item.getLocation().getZ(), 0.0f, 0.0f);
|
||||||
|
// cloneItem.pickup(entityHuman);
|
||||||
|
// item.remove();
|
||||||
|
// }
|
||||||
|
//}
|
@ -0,0 +1,27 @@
|
|||||||
|
//package gg.spoof.spigot.nms.v1_18_R1;
|
||||||
|
//
|
||||||
|
//import io.netty.channel.ChannelHandlerContext;
|
||||||
|
//import io.netty.util.concurrent.Future;
|
||||||
|
//import io.netty.util.concurrent.GenericFutureListener;
|
||||||
|
//import net.minecraft.network.NetworkManager;
|
||||||
|
//import net.minecraft.network.protocol.EnumProtocolDirection;
|
||||||
|
//import net.minecraft.network.protocol.Packet;
|
||||||
|
//
|
||||||
|
//public class FakeNetworkManager extends NetworkManager {
|
||||||
|
// public FakeNetworkManager(EnumProtocolDirection enumprotocoldirection) {
|
||||||
|
// super(enumprotocoldirection);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public boolean h() {
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public void a(Packet<?> packet) {
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public void a(Packet<?> packet, GenericFutureListener<? extends Future<? super Void>> genericfuturelistener) {
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// protected void channelRead0(ChannelHandlerContext channelhandlercontext, Packet<?> packet) {
|
||||||
|
// }
|
||||||
|
//}
|
97
src/main/java/gg/spoof/spigot/nms/v1_18_R1/NMSWrapper.java
Normal file
97
src/main/java/gg/spoof/spigot/nms/v1_18_R1/NMSWrapper.java
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
//package gg.spoof.spigot.nms.v1_18_R1;
|
||||||
|
//
|
||||||
|
//import gg.spoof.spigot.Spoof;
|
||||||
|
//import gg.spoof.spigot.nms.AbstractNMSWrapper;
|
||||||
|
//import gg.spoof.spigot.nms.common.FakeChannel;
|
||||||
|
//import gg.spoof.spigot.nms.v1_18_R1.FakeNetworkManager;
|
||||||
|
//import gg.spoof.spigot.util.ProfileUtil;
|
||||||
|
//import gg.spoof.spigot.util.ReflectionUtil;
|
||||||
|
//import java.lang.reflect.Method;
|
||||||
|
//import java.net.InetSocketAddress;
|
||||||
|
//import net.minecraft.nbt.NBTTagCompound;
|
||||||
|
//import net.minecraft.network.NetworkManager;
|
||||||
|
//import net.minecraft.network.protocol.EnumProtocolDirection;
|
||||||
|
//import net.minecraft.network.protocol.game.PacketPlayOutEntityDestroy;
|
||||||
|
//import net.minecraft.server.level.EntityPlayer;
|
||||||
|
//import net.minecraft.server.level.WorldServer;
|
||||||
|
//import net.minecraft.server.network.PlayerConnection;
|
||||||
|
//import net.minecraft.server.players.PlayerList;
|
||||||
|
//import net.minecraft.world.entity.Entity;
|
||||||
|
//import net.minecraft.world.entity.EntityTypes;
|
||||||
|
//import net.minecraft.world.entity.item.EntityItem;
|
||||||
|
//import org.bukkit.craftbukkit.v1_18_R1.CraftServer;
|
||||||
|
//import org.bukkit.craftbukkit.v1_18_R1.CraftWorld;
|
||||||
|
//import org.bukkit.craftbukkit.v1_18_R1.entity.CraftPlayer;
|
||||||
|
//import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack;
|
||||||
|
//import org.bukkit.entity.Entity;
|
||||||
|
//import org.bukkit.entity.Item;
|
||||||
|
//import org.bukkit.entity.Player;
|
||||||
|
//import org.bukkit.event.player.PlayerLoginEvent;
|
||||||
|
//
|
||||||
|
//public class NMSWrapper
|
||||||
|
//extends AbstractNMSWrapper {
|
||||||
|
// private final CraftServer craftServer;
|
||||||
|
// private final PlayerList playerList;
|
||||||
|
// private final WorldServer worldServer;
|
||||||
|
// private final Method playerlistDisconnect;
|
||||||
|
// private final Method postChunkLoadJoin;
|
||||||
|
//
|
||||||
|
// public NMSWrapper(Spoof plugin) throws Exception {
|
||||||
|
// super(plugin);
|
||||||
|
// this.craftServer = (CraftServer)((Object)plugin.getServer());
|
||||||
|
// this.playerList = this.craftServer.getHandle();
|
||||||
|
// this.worldServer = ((CraftWorld)this.craftServer.getWorlds().get(0)).getHandle();
|
||||||
|
// this.playerlistDisconnect = ReflectionUtil.getMethod(PlayerList.class, "remove", EntityPlayer.class);
|
||||||
|
// this.postChunkLoadJoin = this.getPostChunkLoadJoinMethod();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private Method getPostChunkLoadJoinMethod() {
|
||||||
|
// try {
|
||||||
|
// return ReflectionUtil.getMethod(PlayerList.class, "postChunkLoadJoin", EntityPlayer.class, WorldServer.class, NetworkManager.class, PlayerConnection.class, NBTTagCompound.class, String.class, String.class);
|
||||||
|
// }
|
||||||
|
// catch (NoSuchMethodException e) {
|
||||||
|
// this.plugin.debug("Paper specific login method not found", e);
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// protected Player addSpoofPlayerEntity(ProfileUtil.Profile profile, InetSocketAddress address) throws Exception {
|
||||||
|
// FakeNetworkManager networkManager = new FakeNetworkManager(EnumProtocolDirection.a);
|
||||||
|
// FakeChannel channel = new FakeChannel(null);
|
||||||
|
// networkManager.k = channel;
|
||||||
|
// networkManager.l = address;
|
||||||
|
// channel.pipeline().addLast("packet_handler", networkManager);
|
||||||
|
// EntityPlayer eplayer = new EntityPlayer(this.craftServer.getServer(), this.worldServer, profile.toGameProfile());
|
||||||
|
// this.plugin.getServer().getPluginManager().callEvent(new PlayerLoginEvent(eplayer.getBukkitEntity(), address.getHostString(), address.getAddress(), address.getAddress()));
|
||||||
|
// this.playerList.a(networkManager, eplayer);
|
||||||
|
// if (this.postChunkLoadJoin != null) {
|
||||||
|
// this.postChunkLoadJoin.invoke(this.playerList, eplayer, this.worldServer, networkManager, eplayer.b, this.playerList.a(eplayer), networkManager.c().toString(), eplayer.co());
|
||||||
|
// }
|
||||||
|
// if (!this.plugin.getSpoofConfig().isVisible()) {
|
||||||
|
// eplayer.a(Entity.RemovalReason.b);
|
||||||
|
// eplayer.dq();
|
||||||
|
// }
|
||||||
|
// return eplayer.getBukkitEntity();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// protected void removeSpoofPlayerEntity(Player player) throws Exception {
|
||||||
|
// for (Player online : this.plugin.getServer().getOnlinePlayers()) {
|
||||||
|
// ((CraftPlayer)online).getHandle().b.a(new PacketPlayOutEntityDestroy(new int[]{player.getEntityId()}));
|
||||||
|
// }
|
||||||
|
// EntityPlayer entityPlayer = ((CraftPlayer)player).getHandle();
|
||||||
|
// this.playerlistDisconnect.invoke(this.playerList, entityPlayer);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public void pickupItemSpoofPlayer(Player player, Entity entity) {
|
||||||
|
// EntityPlayer entityHuman = ((CraftPlayer)player).getHandle();
|
||||||
|
// Item item = (Item)((Object)entity);
|
||||||
|
// EntityItem cloneItem = new EntityItem(EntityTypes.Q, this.worldServer);
|
||||||
|
// cloneItem.b(CraftItemStack.asNMSCopy(item.getItemStack()));
|
||||||
|
// cloneItem.b(item.getLocation().getX(), item.getLocation().getY(), item.getLocation().getZ(), 0.0f, 0.0f);
|
||||||
|
// cloneItem.b(entityHuman);
|
||||||
|
// item.remove();
|
||||||
|
// }
|
||||||
|
//}
|
@ -0,0 +1,29 @@
|
|||||||
|
package gg.spoof.spigot.nms.v1_8_R3;
|
||||||
|
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.util.concurrent.Future;
|
||||||
|
import io.netty.util.concurrent.GenericFutureListener;
|
||||||
|
import net.minecraft.server.v1_8_R3.EnumProtocolDirection;
|
||||||
|
import net.minecraft.server.v1_8_R3.NetworkManager;
|
||||||
|
import net.minecraft.server.v1_8_R3.Packet;
|
||||||
|
|
||||||
|
public class FakeNetworkManager extends NetworkManager {
|
||||||
|
|
||||||
|
public FakeNetworkManager(EnumProtocolDirection enumprotocoldirection) {
|
||||||
|
super(enumprotocoldirection);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean g() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void a(Packet packet, GenericFutureListener<? extends Future<? super Void>> genericfuturelistener, GenericFutureListener<? extends Future<? super Void>>... agenericfuturelistener) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handle(Packet packet) {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void channelRead0(ChannelHandlerContext channelhandlercontext, Packet object) throws Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
105
src/main/java/gg/spoof/spigot/nms/v1_8_R3/NMSWrapper.java
Normal file
105
src/main/java/gg/spoof/spigot/nms/v1_8_R3/NMSWrapper.java
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
package gg.spoof.spigot.nms.v1_8_R3;
|
||||||
|
|
||||||
|
import com.mojang.authlib.GameProfile;
|
||||||
|
import com.mojang.authlib.properties.Property;
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
import gg.spoof.spigot.api.SpoofConfig;
|
||||||
|
import gg.spoof.spigot.nms.AbstractNMSWrapper;
|
||||||
|
import gg.spoof.spigot.nms.common.FakeChannel;
|
||||||
|
import gg.spoof.spigot.util.ProfileUtil;
|
||||||
|
import net.minecraft.server.v1_8_R3.*;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.craftbukkit.v1_8_R3.CraftServer;
|
||||||
|
import org.bukkit.craftbukkit.v1_8_R3.CraftWorld;
|
||||||
|
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
|
||||||
|
import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftItemStack;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.Item;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.player.PlayerLoginEvent;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
public class NMSWrapper extends AbstractNMSWrapper {
|
||||||
|
|
||||||
|
private final CraftServer craftServer;
|
||||||
|
private final PlayerList playerList;
|
||||||
|
private final WorldServer worldServer;
|
||||||
|
|
||||||
|
public NMSWrapper(Spoof plugin) {
|
||||||
|
super(plugin);
|
||||||
|
this.craftServer = (CraftServer) plugin.getServer();
|
||||||
|
this.playerList = this.craftServer.getHandle();
|
||||||
|
this.worldServer = ((CraftWorld)this.craftServer.getWorlds().get(0)).getHandle();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Player addSpoofPlayerEntity(ProfileUtil.Profile profile, InetSocketAddress inetSocketAddress) throws Exception {
|
||||||
|
final FakeNetworkManager fakeNetworkManager = new FakeNetworkManager(EnumProtocolDirection.SERVERBOUND);
|
||||||
|
final FakeChannel fakeChannel = new FakeChannel(null);
|
||||||
|
fakeChannel.pipeline().addLast("packet_handler", fakeNetworkManager);
|
||||||
|
|
||||||
|
final MinecraftServer server = this.craftServer.getServer();
|
||||||
|
final WorldServer worldServer = this.worldServer;
|
||||||
|
final GameProfile gameProfile = profile.toGameProfile();
|
||||||
|
final PlayerInteractManager playerInteractManager = new PlayerInteractManager(worldServer);
|
||||||
|
|
||||||
|
gameProfile.getProperties().removeAll("textures");
|
||||||
|
gameProfile.getProperties().put("textures", profile.getProperty());
|
||||||
|
|
||||||
|
final EntityPlayer entityPlayer = new EntityPlayer(server, worldServer, gameProfile, playerInteractManager);
|
||||||
|
final CraftPlayer bukkitEntity = entityPlayer.getBukkitEntity();
|
||||||
|
|
||||||
|
entityPlayer.playerConnection = new PlayerConnection(server, fakeNetworkManager, entityPlayer);
|
||||||
|
entityPlayer.playerConnection.networkManager.channel = fakeChannel;
|
||||||
|
this.plugin.getServer().getPluginManager().callEvent(new PlayerLoginEvent(bukkitEntity, inetSocketAddress.getHostString(), inetSocketAddress.getAddress(), inetSocketAddress.getAddress()));
|
||||||
|
|
||||||
|
this.playerList.a(fakeNetworkManager, entityPlayer);
|
||||||
|
this.worldServer.getTracker().untrackPlayer(entityPlayer);
|
||||||
|
|
||||||
|
if (!this.plugin.getSpoofConfig().isVisible())
|
||||||
|
this.worldServer.removeEntity(entityPlayer);
|
||||||
|
|
||||||
|
entityPlayer.ping = ThreadLocalRandom.current().nextInt(10, 100);
|
||||||
|
|
||||||
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||||
|
PlayerConnection connection = ((CraftPlayer) player).getHandle().playerConnection;
|
||||||
|
connection.sendPacket(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, entityPlayer));
|
||||||
|
connection.sendPacket(new PacketPlayOutNamedEntitySpawn(entityPlayer));
|
||||||
|
}
|
||||||
|
|
||||||
|
Bukkit.getScheduler().scheduleSyncRepeatingTask(this.plugin, entityPlayer::t_, 1, 1);
|
||||||
|
|
||||||
|
return bukkitEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void removeSpoofPlayerEntity(Player player) throws Exception {
|
||||||
|
final EntityPlayer handle = ((CraftPlayer) player).getHandle();
|
||||||
|
this.playerList.disconnect(handle);
|
||||||
|
|
||||||
|
this.plugin.getServer().getOnlinePlayers().forEach(onlinePlayer -> {
|
||||||
|
final EntityPlayer entityPlayer = ((CraftPlayer) onlinePlayer).getHandle();
|
||||||
|
entityPlayer.playerConnection.sendPacket(new PacketPlayOutEntityDestroy(handle.getId()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void pickupItemSpoofPlayer(Player player, Entity entity) {
|
||||||
|
final EntityPlayer handle = ((CraftPlayer) player).getHandle();
|
||||||
|
final WorldServer worldServer = this.worldServer;
|
||||||
|
final Item item = (Item) entity;
|
||||||
|
final EntityItem entityItem = new EntityItem(worldServer);
|
||||||
|
final ItemStack itemStack = CraftItemStack.asNMSCopy(item.getItemStack());
|
||||||
|
|
||||||
|
final Location location = item.getLocation();
|
||||||
|
entityItem.setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
|
||||||
|
entityItem.setItemStack(itemStack);
|
||||||
|
entityItem.d(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
33
src/main/java/gg/spoof/spigot/util/Common.java
Normal file
33
src/main/java/gg/spoof/spigot/util/Common.java
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package gg.spoof.spigot.util;
|
||||||
|
|
||||||
|
import com.google.common.net.InetAddresses;
|
||||||
|
import gg.spoof.spigot.api.manager.PlayerManager;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.net.Inet4Address;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.SplittableRandom;
|
||||||
|
|
||||||
|
public class Common {
|
||||||
|
|
||||||
|
private static final SplittableRandom splittableRandom = new SplittableRandom();
|
||||||
|
|
||||||
|
public static InetSocketAddress getRandomAddress() {
|
||||||
|
final int i = splittableRandom.nextInt();
|
||||||
|
final Inet4Address inet4Address = InetAddresses.fromInteger(i);
|
||||||
|
|
||||||
|
final String hostAddress = inet4Address.getHostAddress();
|
||||||
|
final int port = splittableRandom.nextInt(55000, 60000);
|
||||||
|
return new InetSocketAddress(hostAddress, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Double formatDouble(Double aDouble) {
|
||||||
|
final long round = Math.round(aDouble * 100);
|
||||||
|
return round / 100.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isRealPlayer(Player player) {
|
||||||
|
return !player.hasMetadata("NPC") && !PlayerManager.exists(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
109
src/main/java/gg/spoof/spigot/util/JsonUtil.java
Normal file
109
src/main/java/gg/spoof/spigot/util/JsonUtil.java
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
package gg.spoof.spigot.util;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.internal.LinkedTreeMap;
|
||||||
|
import gg.spoof.spigot.util.Maps;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public final class JsonUtil {
|
||||||
|
private final Map<String, Object> items;
|
||||||
|
|
||||||
|
public JsonUtil(String json) {
|
||||||
|
this.items = (Map)new Gson().fromJson(json, LinkedTreeMap.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonUtil(Map<String, Object> items) {
|
||||||
|
this.items = items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object get(String path) {
|
||||||
|
return Maps.recursiveGet(this.items, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contains(String path) {
|
||||||
|
return this.get(path) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonUtil getJsonSection(String path) {
|
||||||
|
Object object = this.get(path);
|
||||||
|
if (this.isConfigSection(object)) {
|
||||||
|
return new JsonUtil((Map)object);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString(String path) {
|
||||||
|
Object object = this.get(path);
|
||||||
|
if (object instanceof String) {
|
||||||
|
return (String)object;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getInt(String path) {
|
||||||
|
Double d = this.getDouble(path);
|
||||||
|
return d == null ? null : Integer.valueOf(d.intValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getLong(String path) {
|
||||||
|
Double d = this.getDouble(path);
|
||||||
|
return d == null ? null : Long.valueOf(d.longValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getDouble(String path) {
|
||||||
|
Object object = this.get(path);
|
||||||
|
if (object instanceof Double) {
|
||||||
|
return (double)((Double)object);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getBoolean(String path) {
|
||||||
|
Object object = this.get(path);
|
||||||
|
if (object instanceof Boolean) {
|
||||||
|
return (boolean)((Boolean)object);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getStringList(String path) {
|
||||||
|
return this.getList(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<JsonUtil> getJsonList(String path) {
|
||||||
|
Object object = this.get(path);
|
||||||
|
if (object instanceof List) {
|
||||||
|
ArrayList<JsonUtil> jsons = new ArrayList<JsonUtil>();
|
||||||
|
for (Object obj : (List)object) {
|
||||||
|
if (!this.isConfigSection(obj)) continue;
|
||||||
|
jsons.add(new JsonUtil((Map)obj));
|
||||||
|
}
|
||||||
|
if (!jsons.isEmpty()) {
|
||||||
|
return jsons;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new ArrayList<JsonUtil>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> List<T> getList(String path) {
|
||||||
|
Object object = this.get(path);
|
||||||
|
if (object instanceof List) {
|
||||||
|
return (List)object;
|
||||||
|
}
|
||||||
|
return new ArrayList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> getAll() {
|
||||||
|
return this.items;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isConfigSection(Object object) {
|
||||||
|
Map map;
|
||||||
|
if (object instanceof Map && (map = (Map)object).size() >= 1) {
|
||||||
|
return map.keySet().toArray()[0] instanceof String && map.values().toArray()[0] != null;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
151
src/main/java/gg/spoof/spigot/util/Maps.java
Normal file
151
src/main/java/gg/spoof/spigot/util/Maps.java
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
package gg.spoof.spigot.util;
|
||||||
|
|
||||||
|
import java.util.AbstractMap;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
public class Maps {
|
||||||
|
private Maps() {
|
||||||
|
throw new RuntimeException("This class cannot be instantiated.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <K, V, R> Builder<K, V, R, V> builder(Map<K, V> implementation, R returnInstance, Consumer<Map<K, V>> build) {
|
||||||
|
return Maps.builder(implementation, returnInstance, build, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <K, V, R, T> Builder<K, V, R, T> builder(Map<K, V> implementation, R returnInstance, Consumer<Map<K, V>> build, Function<T, V> mapper) {
|
||||||
|
return new Builder(implementation, returnInstance, build, mapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <K, V> Builder<K, V, Map<K, V>, V> of(Map<K, V> implementation) {
|
||||||
|
return Maps.builder(implementation, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <K, V, T> Builder<K, V, Map<K, V>, T> of(Map<K, V> implementation, Function<T, V> mapper) {
|
||||||
|
return Maps.builder(implementation, null, null, mapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stream<Map.Entry<String, Object>> flatten(Map.Entry<String, Object> entry) {
|
||||||
|
return Maps.flatten(entry, Map.class, (f) -> f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Stream<Map.Entry<String, Object>> flatten(Map.Entry<String, Object> entry, Class<T> clazz, Function<T, Map<String, Object>> flatten) {
|
||||||
|
if (clazz.isInstance(entry.getValue())) {
|
||||||
|
return flatten.apply((T) entry.getValue()).entrySet().stream().map(e -> new AbstractMap.SimpleEntry((String)entry.getKey() + "." + (String)e.getKey(), e.getValue())).flatMap(e -> Maps.flatten(e, clazz, flatten));
|
||||||
|
}
|
||||||
|
if (entry.getValue() instanceof Collection) {
|
||||||
|
if (((Collection)entry.getValue()).stream().anyMatch(clazz::isInstance)) {
|
||||||
|
return Stream.of(new AbstractMap.SimpleEntry(entry.getKey(), ((Collection)entry.getValue()).stream().map(o -> {
|
||||||
|
if (clazz.isInstance(o)) {
|
||||||
|
return (flatten.apply((T) o)).entrySet().stream().flatMap(e -> Maps.flatten(new AbstractMap.SimpleEntry<String, Object>((String)entry.getKey() + "." + (String)e.getKey(), e.getValue()), clazz, flatten)).distinct().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
}).collect(Collectors.toList())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Stream.of(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Map<String, Object> map(Map<String, Object> map, Class<T> clazz, Function<T, Map<String, Object>> mapper) {
|
||||||
|
Map<String, Object> mapped = new HashMap();
|
||||||
|
|
||||||
|
for(Map.Entry<String, Object> entry : map.entrySet()) {
|
||||||
|
Object obj = entry.getValue();
|
||||||
|
if (clazz.isInstance(obj)) {
|
||||||
|
mapped.put(entry.getKey(), map(mapper.apply((T) obj), clazz, mapper));
|
||||||
|
} else if (entry.getValue() instanceof Collection && ((Collection)entry.getValue()).stream().anyMatch(clazz::isInstance)) {
|
||||||
|
mapped.put(entry.getKey(), ((Collection)entry.getValue()).stream().map((o) -> clazz.isInstance(o) ? map(mapper.apply((T) o), clazz, mapper) : o));
|
||||||
|
} else {
|
||||||
|
mapped.put(entry.getKey(), obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T recursiveGet(Map<String, T> map, String path) {
|
||||||
|
Object object = map.getOrDefault(path, null);
|
||||||
|
if (path.contains(".") && !path.startsWith(".") && !path.endsWith(".")) {
|
||||||
|
String[] areas = path.split("\\.");
|
||||||
|
object = map.getOrDefault(areas[0], null);
|
||||||
|
if (areas.length >= 2 && object != null) {
|
||||||
|
object = Maps.getBuriedObject(map, areas);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (T) object;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> T getBuriedObject(Map<String, T> map, String[] keys) {
|
||||||
|
int i = 1;
|
||||||
|
Map endObject = (Map)map.get(keys[0]);
|
||||||
|
while (Maps.instanceOfStringKeyMap(endObject.get(keys[i]))) {
|
||||||
|
endObject = (Map)endObject.get(keys[i++]);
|
||||||
|
}
|
||||||
|
return (T)endObject.get(keys[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean instanceOfStringKeyMap(Object obj) {
|
||||||
|
if (obj instanceof Map) {
|
||||||
|
Set keys = ((Map)obj).keySet();
|
||||||
|
return !keys.isEmpty() && keys.stream().allMatch(s -> s instanceof String);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class Builder<K, V, R, T> {
|
||||||
|
private final Map<K, V> map;
|
||||||
|
private final R returnInstance;
|
||||||
|
private final Consumer<Map<K, V>> build;
|
||||||
|
private final Function<T, V> mapper;
|
||||||
|
|
||||||
|
private Builder(Map<K, V> implementation, R returnInstance, Consumer<Map<K, V>> build, Function<T, V> mapper) {
|
||||||
|
this.map = implementation;
|
||||||
|
this.returnInstance = returnInstance;
|
||||||
|
this.build = build;
|
||||||
|
this.mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueBuilder key(K key) {
|
||||||
|
return this.key(key, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueBuilder key(K key, Predicate<V> requirement) {
|
||||||
|
return new ValueBuilder(key, requirement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public R build() {
|
||||||
|
if (this.returnInstance != null && this.build != null) {
|
||||||
|
this.build.accept(this.map);
|
||||||
|
return this.returnInstance;
|
||||||
|
}
|
||||||
|
return (R)this.map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class ValueBuilder {
|
||||||
|
private final K key;
|
||||||
|
private final Predicate<V> requirement;
|
||||||
|
|
||||||
|
private ValueBuilder(K key, Predicate<V> requirement) {
|
||||||
|
this.key = key;
|
||||||
|
this.requirement = requirement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder<K, V, R, T> value(T value) {
|
||||||
|
V real = Builder.this.mapper != null ? Builder.this.mapper.apply(value) : (V) value;
|
||||||
|
if (this.requirement != null && !this.requirement.test(real)) {
|
||||||
|
return Builder.this;
|
||||||
|
}
|
||||||
|
Builder.this.map.put(this.key, real);
|
||||||
|
return Builder.this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
src/main/java/gg/spoof/spigot/util/MathUtility.java
Normal file
15
src/main/java/gg/spoof/spigot/util/MathUtility.java
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package gg.spoof.spigot.util;
|
||||||
|
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
public class MathUtility {
|
||||||
|
public static int getRandomNumber(int min, int max) {
|
||||||
|
int realMin = Math.min(min, max);
|
||||||
|
int realMax = Math.max(min, max);
|
||||||
|
if (realMax == realMin) {
|
||||||
|
return realMin;
|
||||||
|
}
|
||||||
|
int exclusiveSize = realMax - realMin;
|
||||||
|
return ThreadLocalRandom.current().nextInt(exclusiveSize + 1) + realMin;
|
||||||
|
}
|
||||||
|
}
|
33
src/main/java/gg/spoof/spigot/util/PingUtil.java
Normal file
33
src/main/java/gg/spoof/spigot/util/PingUtil.java
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package gg.spoof.spigot.util;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public class PingUtil {
|
||||||
|
|
||||||
|
private static Method getHandleMethod;
|
||||||
|
private static Field pingField;
|
||||||
|
|
||||||
|
public static void setPing(Player player, int ping) {
|
||||||
|
try {
|
||||||
|
if (getHandleMethod == null) {
|
||||||
|
getHandleMethod = player.getClass().getDeclaredMethod("getHandle");
|
||||||
|
}
|
||||||
|
getHandleMethod.setAccessible(true);
|
||||||
|
|
||||||
|
Object handle = getHandleMethod.invoke(player);
|
||||||
|
|
||||||
|
if (pingField == null) {
|
||||||
|
pingField = handle.getClass().getDeclaredField("ping");
|
||||||
|
}
|
||||||
|
pingField.setAccessible(true);
|
||||||
|
|
||||||
|
pingField.setInt(handle, ping);
|
||||||
|
} catch (Exception exception) {
|
||||||
|
exception.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
117
src/main/java/gg/spoof/spigot/util/ProfileUtil.java
Normal file
117
src/main/java/gg/spoof/spigot/util/ProfileUtil.java
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
package gg.spoof.spigot.util;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import com.mojang.authlib.GameProfile;
|
||||||
|
import com.mojang.authlib.properties.Property;
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
public class ProfileUtil {
|
||||||
|
private static final ConcurrentHashMap<String, Profile> CACHE = new ConcurrentHashMap<>();
|
||||||
|
;
|
||||||
|
|
||||||
|
private static String readUrl(String urlString) throws Exception {
|
||||||
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new URL(urlString).openStream()));) {
|
||||||
|
int read;
|
||||||
|
StringBuilder buffer = new StringBuilder();
|
||||||
|
char[] chars = new char[1024];
|
||||||
|
while ((read = reader.read(chars)) != -1) {
|
||||||
|
buffer.append(chars, 0, read);
|
||||||
|
}
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Profile getProfile(String userOrUuid) throws InterruptedException, ExecutionException, TimeoutException {
|
||||||
|
CompletableFuture<Profile> async = CompletableFuture.supplyAsync(() -> {
|
||||||
|
try {
|
||||||
|
return ProfileUtil.submit(userOrUuid);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Error fetching profile for id " + userOrUuid, e);
|
||||||
|
}
|
||||||
|
}, Spoof.POOL);
|
||||||
|
Profile profile = async.get(10000L, TimeUnit.MILLISECONDS);
|
||||||
|
CACHE.put(ProfileUtil.strip(userOrUuid), profile);
|
||||||
|
return profile;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String strip(String str) {
|
||||||
|
return str.replace("-", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Profile submit(String str) throws Exception {
|
||||||
|
String stripped = strip(str);
|
||||||
|
|
||||||
|
if (CACHE.containsKey(stripped))
|
||||||
|
return CACHE.get(stripped);
|
||||||
|
|
||||||
|
if (!StringUtil.isUUID(stripped))
|
||||||
|
stripped = str;
|
||||||
|
|
||||||
|
final String url = "https://api.ashcon.app/mojang/v2/user/" + stripped;
|
||||||
|
final JsonUtil jsonUtil = new JsonUtil(readUrl(url));
|
||||||
|
|
||||||
|
if (jsonUtil.contains("code") && jsonUtil.getInt("code") == 404)
|
||||||
|
throw new IllegalArgumentException("Error whilst getting player: does not exist");
|
||||||
|
|
||||||
|
final String username = jsonUtil.getString("username");
|
||||||
|
final UUID uuid = UUID.fromString(Objects.requireNonNull(jsonUtil.getString("uuid")));
|
||||||
|
final Property property = new Property(
|
||||||
|
"textures",
|
||||||
|
jsonUtil.getString("textures.raw.value"),
|
||||||
|
jsonUtil.getString("textures.raw.signature")
|
||||||
|
);
|
||||||
|
|
||||||
|
return new Profile(username, uuid, property);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Profile {
|
||||||
|
private final UUID uuid;
|
||||||
|
private final String username;
|
||||||
|
private final Property property;
|
||||||
|
|
||||||
|
public Profile(String username, UUID uuid, Property property) {
|
||||||
|
this.uuid = uuid;
|
||||||
|
this.username = username;
|
||||||
|
this.property = property;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getId() {
|
||||||
|
return this.uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return this.username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Property getProperty() {
|
||||||
|
return this.property;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSkin(GameProfile gameProfile) {
|
||||||
|
gameProfile.getProperties().put("textures", this.property);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameProfile toGameProfile() {
|
||||||
|
GameProfile profile = new GameProfile(this.uuid, this.username);
|
||||||
|
this.setSkin(profile);
|
||||||
|
return profile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
103
src/main/java/gg/spoof/spigot/util/ReflectionUtil.java
Normal file
103
src/main/java/gg/spoof/spigot/util/ReflectionUtil.java
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
package gg.spoof.spigot.util;
|
||||||
|
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import gg.spoof.spigot.Spoof;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class ReflectionUtil {
|
||||||
|
private static final Map<String, ClassData> CACHE = Maps.newHashMap();
|
||||||
|
|
||||||
|
public static void validateInitBySpoof() {
|
||||||
|
String spoofClassName = Spoof.class.getName();
|
||||||
|
for (StackTraceElement element : new Exception("trace").getStackTrace()) {
|
||||||
|
if (!element.getClassName().equals(spoofClassName) || !element.getMethodName().equals("onEnable")) continue;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("This module can only be initalized by plugin itself in onEnable");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Field getField(Class<?> klass, String name) throws NoSuchFieldException, SecurityException {
|
||||||
|
Field field = klass.getDeclaredField(name);
|
||||||
|
field.setAccessible(true);
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Field getField(Object obj, String name) throws NoSuchFieldException, SecurityException {
|
||||||
|
Field field = obj.getClass().getDeclaredField(name);
|
||||||
|
field.setAccessible(true);
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Method getMethod(Class<?> klass, String name, Class<?> ... parameterTypes) throws NoSuchMethodException, SecurityException {
|
||||||
|
Method method = klass.getDeclaredMethod(name, parameterTypes);
|
||||||
|
method.setAccessible(true);
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void set(Field field, Object toUse, Object toReplace) {
|
||||||
|
try {
|
||||||
|
field.set(toUse, toReplace);
|
||||||
|
}
|
||||||
|
catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object getValue(Object obj, String name) {
|
||||||
|
try {
|
||||||
|
Field field = obj.getClass().getDeclaredField(name);
|
||||||
|
field.setAccessible(true);
|
||||||
|
return field.get(obj);
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setValue(Object obj, String fieldName, Object value) {
|
||||||
|
try {
|
||||||
|
Field field;
|
||||||
|
String className = obj.getClass().getName();
|
||||||
|
ClassData data = CACHE.get(className + fieldName);
|
||||||
|
if (data != null) {
|
||||||
|
field = data.field;
|
||||||
|
} else {
|
||||||
|
field = obj.getClass().getDeclaredField(fieldName);
|
||||||
|
field.setAccessible(true);
|
||||||
|
data = new ClassData(obj.getClass(), fieldName, field);
|
||||||
|
CACHE.put(className + fieldName, data);
|
||||||
|
}
|
||||||
|
field.set(obj, value);
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ClassData {
|
||||||
|
Class<? extends Object> className;
|
||||||
|
String fieldId;
|
||||||
|
Field field;
|
||||||
|
|
||||||
|
public ClassData(Class<? extends Object> className, String fieldId, Field field) {
|
||||||
|
this.className = className;
|
||||||
|
this.fieldId = fieldId;
|
||||||
|
this.field = field;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return this.className.hashCode() * 31 + this.fieldId.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object other) {
|
||||||
|
if (!(other instanceof ClassData)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ClassData otherClassData = (ClassData)other;
|
||||||
|
return otherClassData.field.equals(this.field) && otherClassData.fieldId.equals(this.fieldId) && otherClassData.className.equals(this.className);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
src/main/java/gg/spoof/spigot/util/StringUtil.java
Normal file
24
src/main/java/gg/spoof/spigot/util/StringUtil.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package gg.spoof.spigot.util;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
|
||||||
|
public class StringUtil {
|
||||||
|
public static boolean isUUID(String str) {
|
||||||
|
return str.matches("[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String translate(String message) {
|
||||||
|
return ChatColor.translateAlternateColorCodes('&', message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> translate(String ... message) {
|
||||||
|
return Arrays.stream(message).map(StringUtil::translate).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> translate(List<String> message) {
|
||||||
|
return message.stream().map(StringUtil::translate).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
102
src/main/java/gg/spoof/velocity/Spoof.java
Normal file
102
src/main/java/gg/spoof/velocity/Spoof.java
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
package gg.spoof.velocity;
|
||||||
|
|
||||||
|
import com.typesafe.config.Config;
|
||||||
|
import com.typesafe.config.ConfigFactory;
|
||||||
|
import com.velocitypowered.api.event.Subscribe;
|
||||||
|
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
|
||||||
|
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
|
||||||
|
import com.velocitypowered.api.plugin.annotation.DataDirectory;
|
||||||
|
import com.velocitypowered.api.proxy.ProxyServer;
|
||||||
|
import gg.spoof.common.utils.ResourceLoader;
|
||||||
|
import gg.spoof.velocity.controller.PluginMessageController;
|
||||||
|
import gg.spoof.velocity.controller.ProxyController;
|
||||||
|
import gg.spoof.velocity.controller.RedisController;
|
||||||
|
import gg.spoof.velocity.listener.VelocityPingListener;
|
||||||
|
import gg.spoof.velocity.util.ServerData;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class Spoof {
|
||||||
|
|
||||||
|
private final ProxyServer proxy;
|
||||||
|
private final Logger logger;
|
||||||
|
private final Path pluginDataDir;
|
||||||
|
private final Map<String, ServerData> servers = new ConcurrentHashMap<>();
|
||||||
|
private boolean debug;
|
||||||
|
private ProxyController controller;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public Spoof(ProxyServer proxy, Logger logger, @DataDirectory Path pluginDir) {
|
||||||
|
this.proxy = proxy;
|
||||||
|
this.logger = logger;
|
||||||
|
this.pluginDataDir = pluginDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void debug(String message) {
|
||||||
|
if (this.debug)
|
||||||
|
this.getLogger().info(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void debug(String message, Throwable t) {
|
||||||
|
if (this.debug)
|
||||||
|
this.getLogger().log(Level.INFO, message, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
protected void onEnable(ProxyInitializeEvent event) throws IOException {
|
||||||
|
final Path configFile = this.pluginDataDir.resolve("config.conf");
|
||||||
|
ResourceLoader.loadDefaultResource(this.getClass().getClassLoader(), "velocity-config.conf", configFile);
|
||||||
|
final Config config = ConfigFactory.parseFile(configFile.toFile());
|
||||||
|
|
||||||
|
this.debug = config.getBoolean("settings.debug");
|
||||||
|
this.registerController(config);
|
||||||
|
this.setupServersCleanup();
|
||||||
|
this.getProxy().getEventManager().register(this, new VelocityPingListener(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
protected void onDisable(ProxyShutdownEvent event) {
|
||||||
|
if (this.controller != null)
|
||||||
|
this.controller.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerController(Config config) {
|
||||||
|
String controllerType;
|
||||||
|
switch (controllerType = config.getString("settings.controller.selected").toLowerCase()) {
|
||||||
|
case "redis": {
|
||||||
|
final String[] address = config.getString("settings.controller.redis.address").split(":", 2);
|
||||||
|
final String password = config.getString("settings.controller.redis.password");
|
||||||
|
this.controller = new RedisController(this, address[0], Integer.parseInt(address[1]), password);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "messaging": {
|
||||||
|
this.controller = new PluginMessageController(this);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
throw new RuntimeException("The controller type '" + controllerType + "' isn't valid!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.getLogger().info("Using " + controllerType + " for the receiver.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupServersCleanup() {
|
||||||
|
this.getProxy().getScheduler().buildTask(this, () -> {
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
for (Map.Entry<String, ServerData> serverSet : this.servers.entrySet()) {
|
||||||
|
ServerData server = serverSet.getValue();
|
||||||
|
if (currentTime - server.getLastPing() <= TimeUnit.MINUTES.toMillis(1L)) continue;
|
||||||
|
this.servers.remove(serverSet.getKey());
|
||||||
|
}
|
||||||
|
}).delay(10L, TimeUnit.SECONDS).repeat(10L, TimeUnit.SECONDS).schedule();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
package gg.spoof.velocity.controller;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.event.Subscribe;
|
||||||
|
import com.velocitypowered.api.event.connection.PluginMessageEvent;
|
||||||
|
import com.velocitypowered.api.proxy.ServerConnection;
|
||||||
|
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
|
||||||
|
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
|
||||||
|
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||||
|
import gg.spoof.common.proxy.ProxyChannelFormat;
|
||||||
|
import gg.spoof.velocity.Spoof;
|
||||||
|
|
||||||
|
public class PluginMessageController extends ProxyController {
|
||||||
|
|
||||||
|
protected final ChannelIdentifier proxyboundServerPlayers = MinecraftChannelIdentifier.from("spoof:srv_pl");
|
||||||
|
protected final ChannelIdentifier serverboundProxyPlayerCount = MinecraftChannelIdentifier.from("spoof:pr_pl_cnt");
|
||||||
|
|
||||||
|
public PluginMessageController(Spoof plugin) {
|
||||||
|
super(plugin);
|
||||||
|
plugin.getProxy().getChannelRegistrar().register(this.proxyboundServerPlayers);
|
||||||
|
plugin.getProxy().getEventManager().register(plugin, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onPluginMessage(PluginMessageEvent event) {
|
||||||
|
if (!(event.getSource() instanceof ServerConnection))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!event.getIdentifier().equals(this.proxyboundServerPlayers))
|
||||||
|
return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
final ProxyChannelFormat.ServerPlayers serverPlayers = ProxyChannelFormat.decodeServerPlayers(event.getData());
|
||||||
|
this.updateServerPlayerCount(serverPlayers.getServerId(), serverPlayers.getCount());
|
||||||
|
} catch (Exception ex) {
|
||||||
|
this.plugin.debug("Error receiving server players", ex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
int proxyPlayerCount = this.getProxyPlayerCount();
|
||||||
|
byte[] proxyPlayerCountData = ProxyChannelFormat.encodeProxyPlayerCount(proxyPlayerCount);
|
||||||
|
for (RegisteredServer server : this.plugin.getProxy().getAllServers()) {
|
||||||
|
server.sendPluginMessage(this.serverboundProxyPlayerCount, proxyPlayerCountData);
|
||||||
|
}
|
||||||
|
this.plugin.debug("Sent proxy player count " + proxyPlayerCount);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
this.plugin.debug("Error sending proxy player count", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package gg.spoof.velocity.controller;
|
||||||
|
|
||||||
|
import gg.spoof.velocity.Spoof;
|
||||||
|
import gg.spoof.velocity.util.ServerData;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public abstract class ProxyController {
|
||||||
|
|
||||||
|
protected final Spoof plugin;
|
||||||
|
|
||||||
|
public abstract void close();
|
||||||
|
|
||||||
|
public int getProxyPlayerCount() {
|
||||||
|
return this.plugin.getServers().values().stream().mapToInt(ServerData::getOnline).sum();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateServerPlayerCount(String server, int online) {
|
||||||
|
this.plugin.getServers().computeIfAbsent(server, k -> new ServerData()).setOnline(online);
|
||||||
|
this.plugin.debug("Updated server " + server + " player count to " + online);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package gg.spoof.velocity.controller;
|
||||||
|
|
||||||
|
import gg.spoof.velocity.Spoof;
|
||||||
|
import gg.spoof.velocity.controller.redis.RedisPubSub;
|
||||||
|
import lombok.Getter;
|
||||||
|
import redis.clients.jedis.Jedis;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class RedisController extends ProxyController {
|
||||||
|
|
||||||
|
private Jedis jedisRX;
|
||||||
|
private Jedis jedisTX;
|
||||||
|
private final RedisPubSub redisPubSub;
|
||||||
|
|
||||||
|
public RedisController(final Spoof plugin, String host, int port, String password) {
|
||||||
|
super(plugin);
|
||||||
|
this.jedisRX = this.create(host, port, password);
|
||||||
|
this.jedisTX = this.create(host, port, password);
|
||||||
|
this.redisPubSub = new RedisPubSub(plugin, this);
|
||||||
|
|
||||||
|
plugin.getProxy().getScheduler().buildTask(plugin, () -> this.jedisRX.subscribe(this.redisPubSub, "spoof:srv_pl")).schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Jedis create(String host, int port, String password) {
|
||||||
|
final Jedis jedis = new Jedis(host, port);
|
||||||
|
jedis.connect();
|
||||||
|
|
||||||
|
if (!password.isEmpty())
|
||||||
|
jedis.auth(password);
|
||||||
|
|
||||||
|
if (!jedis.isConnected())
|
||||||
|
throw new IllegalStateException("Failed to connect to redis");
|
||||||
|
|
||||||
|
return jedis;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
if (this.jedisRX != null) {
|
||||||
|
this.jedisRX.close();
|
||||||
|
this.jedisRX = null;
|
||||||
|
}
|
||||||
|
if (this.jedisTX != null) {
|
||||||
|
this.jedisTX.close();
|
||||||
|
this.jedisTX = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package gg.spoof.velocity.controller.redis;
|
||||||
|
|
||||||
|
import gg.spoof.common.proxy.ProxyChannelFormat;
|
||||||
|
import gg.spoof.velocity.Spoof;
|
||||||
|
import gg.spoof.velocity.controller.RedisController;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import redis.clients.jedis.JedisPubSub;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class RedisPubSub extends JedisPubSub {
|
||||||
|
|
||||||
|
private final Spoof plugin;
|
||||||
|
private final RedisController redisController;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMessage(String channel, String message) {
|
||||||
|
try {
|
||||||
|
final ProxyChannelFormat.ServerPlayers players = ProxyChannelFormat.decodeB64ServerPlayers(message);
|
||||||
|
this.redisController.updateServerPlayerCount(players.getServerId(), players.getCount());
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
this.plugin.debug("Error receiving server players", ex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
int proxyPlayerCount = this.redisController.getProxyPlayerCount();
|
||||||
|
this.redisController.getJedisTX().publish("spoof:pr_pl_cnt", ProxyChannelFormat.encodeB64ProxyPlayerCount(proxyPlayerCount));
|
||||||
|
this.plugin.debug("Sent total player count " + proxyPlayerCount);
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
this.plugin.debug("Error sending proxy player count", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSubscribe(String channel, int subscribedChannels) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUnsubscribe(String channel, int subscribedChannels) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package gg.spoof.velocity.listener;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.event.Subscribe;
|
||||||
|
import com.velocitypowered.api.event.proxy.ProxyPingEvent;
|
||||||
|
import gg.spoof.velocity.Spoof;
|
||||||
|
import gg.spoof.velocity.util.ServerData;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class VelocityPingListener {
|
||||||
|
|
||||||
|
protected final Spoof plugin;
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onProxyPing(ProxyPingEvent event) {
|
||||||
|
int count = this.plugin.getServers().values().stream().mapToInt(ServerData::getOnline).sum();
|
||||||
|
this.plugin.debug("Setting proxy count to " + count + ".");
|
||||||
|
event.setPing(event.getPing().asBuilder().onlinePlayers(count).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
16
src/main/java/gg/spoof/velocity/util/ServerData.java
Normal file
16
src/main/java/gg/spoof/velocity/util/ServerData.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package gg.spoof.velocity.util;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class ServerData {
|
||||||
|
|
||||||
|
private volatile int online;
|
||||||
|
private volatile long lastPing;
|
||||||
|
|
||||||
|
public void setOnline(int online) {
|
||||||
|
this.online = online;
|
||||||
|
this.lastPing = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
16
src/main/resources/bungee-config.yml
Normal file
16
src/main/resources/bungee-config.yml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
settings:
|
||||||
|
# This is a developer mode, useful for logging
|
||||||
|
# various aspects of the plugin to console.
|
||||||
|
debug: true
|
||||||
|
|
||||||
|
controller:
|
||||||
|
# This is the controller type you wish to handle.
|
||||||
|
selected: "redis"
|
||||||
|
|
||||||
|
# Specify your redis credentials here if your server
|
||||||
|
# includes a proxy.
|
||||||
|
redis:
|
||||||
|
# Specify your address:port
|
||||||
|
address: '127.0.0.1:6379'
|
||||||
|
# If you use credentials, specify here
|
||||||
|
password: ''
|
4
src/main/resources/bungee.yml
Normal file
4
src/main/resources/bungee.yml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
name: Spoof
|
||||||
|
version: 2.5.2
|
||||||
|
main: gg.spoof.bungee.Spoof
|
||||||
|
author: "Stellar Dev"
|
184
src/main/resources/config.yml
Normal file
184
src/main/resources/config.yml
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
settings:
|
||||||
|
debug: true
|
||||||
|
|
||||||
|
# Whether the player entity should be shown
|
||||||
|
# in-game, useful for Hub servers.
|
||||||
|
show-bot-entity: true
|
||||||
|
|
||||||
|
# Add your username or uuid here to gain access to the in-game
|
||||||
|
# commands. This is to ensure others with full perms cannot
|
||||||
|
# see the plugin exists.
|
||||||
|
whitelisted:
|
||||||
|
- 'SpoofPlayer'
|
||||||
|
|
||||||
|
# If you wish to run within a proxy,
|
||||||
|
# enable this and specify redis settings below.
|
||||||
|
proxy-mode: false
|
||||||
|
|
||||||
|
# This is your unique server identifier, this MUST be
|
||||||
|
# set if using a proxy - e.g. BungeeCord.
|
||||||
|
server-id: "server"
|
||||||
|
|
||||||
|
# You can optionally run commands from console when a
|
||||||
|
# spoofed player joins. Use %player% for the players
|
||||||
|
# username, no slash is needed.
|
||||||
|
join-commands: []
|
||||||
|
join-commands-delay: 0
|
||||||
|
|
||||||
|
controller:
|
||||||
|
# This is the controller type you wish to use.
|
||||||
|
selected: "redis"
|
||||||
|
|
||||||
|
# Specify your redis credentials here if your server
|
||||||
|
# includes a proxy.
|
||||||
|
redis:
|
||||||
|
# Specify your address:port
|
||||||
|
address: '127.0.0.1:6379'
|
||||||
|
# If you use credentials, specify here
|
||||||
|
password: ''
|
||||||
|
|
||||||
|
# This is the location that the bots spawn in when loaded
|
||||||
|
spawn-locations:
|
||||||
|
x: 0
|
||||||
|
y: 0
|
||||||
|
z: 0
|
||||||
|
world: "world"
|
||||||
|
|
||||||
|
# These are your list of modules, a developer may ask
|
||||||
|
# you to add their own module name below.
|
||||||
|
modules:
|
||||||
|
# This module connects to Buycraft with fake donations
|
||||||
|
# and reacting to donations events with our forked buycraft
|
||||||
|
donations:
|
||||||
|
enabled: true
|
||||||
|
settings:
|
||||||
|
delay:
|
||||||
|
min: 10
|
||||||
|
max: 20
|
||||||
|
responders:
|
||||||
|
min: 1
|
||||||
|
max: 3
|
||||||
|
responses:
|
||||||
|
- "gg"
|
||||||
|
packages:
|
||||||
|
1: # The package ID for fake donations
|
||||||
|
message:
|
||||||
|
- "&7[&6Buycraft&7] &c&l<player> &7has bought &a1x &6Legendary &7key!"
|
||||||
|
|
||||||
|
# This module has the bots respond to people joining/rejoining
|
||||||
|
# with random responses and random selected players
|
||||||
|
welcome:
|
||||||
|
enabled: false
|
||||||
|
settings:
|
||||||
|
delay:
|
||||||
|
min: 10
|
||||||
|
max: 20
|
||||||
|
responders:
|
||||||
|
min: 1
|
||||||
|
max: 3
|
||||||
|
responses:
|
||||||
|
join:
|
||||||
|
- "Welcome to Stellar Dev %player%"
|
||||||
|
- "Aye looks whos here"
|
||||||
|
rejoin:
|
||||||
|
- "Wb"
|
||||||
|
- "Welcome back retard"
|
||||||
|
# This module gives random ranks to the bots
|
||||||
|
# useful to make bots look more realistic
|
||||||
|
ranks:
|
||||||
|
enabled: false
|
||||||
|
settings:
|
||||||
|
# RANK:CHANCE
|
||||||
|
rank-chances:
|
||||||
|
gem: 10
|
||||||
|
interstellar: 20
|
||||||
|
stellar: 30
|
||||||
|
elapsed: 40
|
||||||
|
beer: 50
|
||||||
|
|
||||||
|
# This module automatically fluctuates a random
|
||||||
|
# bots ping, useful for looking realistic.
|
||||||
|
ping:
|
||||||
|
enabled: true
|
||||||
|
settings:
|
||||||
|
delay:
|
||||||
|
min: 1
|
||||||
|
max: 10
|
||||||
|
ping:
|
||||||
|
min: 100
|
||||||
|
max: 150
|
||||||
|
|
||||||
|
# This module lets bots pickup items dropped nearby.
|
||||||
|
# Not recommended, but delay can be tweaked for performance.
|
||||||
|
pickup:
|
||||||
|
enabled: true
|
||||||
|
settings:
|
||||||
|
delay:
|
||||||
|
min: 5
|
||||||
|
max: 5
|
||||||
|
|
||||||
|
# This module lets you run a random command on a bot.
|
||||||
|
# This is useful for having bots automatically teleport etc.
|
||||||
|
action:
|
||||||
|
enabled: false
|
||||||
|
settings:
|
||||||
|
delay:
|
||||||
|
min: 1
|
||||||
|
max: 10
|
||||||
|
actions:
|
||||||
|
# You can add and remove these, e.g. a 70% and a 30% chance action.
|
||||||
|
test:
|
||||||
|
chance: 100
|
||||||
|
list:
|
||||||
|
- '[PLAYER] me woah, cool server!'
|
||||||
|
|
||||||
|
# This module makes a random bot vote (server-sided!).
|
||||||
|
# Enabling this usually motivates real players to want to vote.
|
||||||
|
vote:
|
||||||
|
enabled: false
|
||||||
|
settings:
|
||||||
|
expiration: 3600000
|
||||||
|
delay:
|
||||||
|
min: 1
|
||||||
|
max: 10
|
||||||
|
services:
|
||||||
|
- 'PMC'
|
||||||
|
- 'MinecraftMP'
|
||||||
|
|
||||||
|
# This module makes bots automatically join and leave, depending
|
||||||
|
# on how many real players are currently online.
|
||||||
|
#
|
||||||
|
# I'd recommend 1.2 (20%) to 1.25 (25%) on a production server.
|
||||||
|
fluctuation:
|
||||||
|
enabled: true
|
||||||
|
debug: true
|
||||||
|
settings:
|
||||||
|
# Legit uuids generator
|
||||||
|
accounts:
|
||||||
|
# NameMC, List
|
||||||
|
generator: "NameMC"
|
||||||
|
# List generator users
|
||||||
|
users:
|
||||||
|
- 'dbba4003-2ef3-4857-ab28-610501f34d51'
|
||||||
|
- '157e8dba-c2e6-4fe7-8d01-438b8e4cc898'
|
||||||
|
- '995d6b61-6588-44f6-a919-28f908d06862'
|
||||||
|
delay:
|
||||||
|
min: 1
|
||||||
|
max: 10
|
||||||
|
percent:
|
||||||
|
min: 2.0
|
||||||
|
max: 2.5
|
||||||
|
|
||||||
|
messages:
|
||||||
|
help:
|
||||||
|
- '&8[&b&l⚡&8] &bSpoof &8- &fThe Ultimate Spoofing Solution&7.'
|
||||||
|
- '&8[&b&l⚡ &b/spoof add&8] &7Add a spoofed player to the server'
|
||||||
|
- '&8[&b&l⚡ &b/spoof remove&8] &7Remove a spoofed player from the server'
|
||||||
|
- '&8[&b&l⚡ &b/spoof reload&8] &7Reload the modules and configs'
|
||||||
|
- '&8[&b&l⚡ &b/spoof modules&8] &7View the modules information'
|
||||||
|
- '&8[&b&l⚡ &b/spoof auction&8] &7Auction an item under a spoofed player'
|
||||||
|
- '&8[&b&l⚡ &b/spoof summon&8] &7Summon a spoofed player to your location'
|
||||||
|
- '&8[&b&l⚡ &b/spoof donation&8] &7Create a fake donation reaction with spoof players'
|
||||||
|
modules-information:
|
||||||
|
- '&8[&b&l⚡&8] &bSpoof &8- &fThe Ultimate Spoofing Solution&7.'
|
||||||
|
- '&8[&b&l⚡&8] &7Modules (&a<modules-size>&7): &b<module-loaded>'
|
5
src/main/resources/plugin.yml
Normal file
5
src/main/resources/plugin.yml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
name: Spoof
|
||||||
|
version: 2.5.2
|
||||||
|
main: gg.spoof.spigot.Spoof
|
||||||
|
author: "Stellar Dev"
|
||||||
|
softdepend: ["Votifier", "Vault", "LuckPerms"]
|
21
src/main/resources/velocity-config.conf
Normal file
21
src/main/resources/velocity-config.conf
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
license: licensekey
|
||||||
|
|
||||||
|
settings: {
|
||||||
|
# This is a developer mode, useful for logging
|
||||||
|
# various aspects of the plugin to console.
|
||||||
|
debug: true
|
||||||
|
|
||||||
|
controller: {
|
||||||
|
# This is the controller type you wish to handle.
|
||||||
|
selected: "redis"
|
||||||
|
|
||||||
|
# Specify your redis credentials here if your server
|
||||||
|
# includes a proxy.
|
||||||
|
redis: {
|
||||||
|
# Specify your address:port
|
||||||
|
address: "127.0.0.1:6379"
|
||||||
|
# If you use credentials, specify here
|
||||||
|
password: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
src/main/resources/velocity-plugin.json
Normal file
10
src/main/resources/velocity-plugin.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "spoof",
|
||||||
|
"id": "spoof",
|
||||||
|
"main": "gg.spoof.velocity.Spoof",
|
||||||
|
"version": "2.5.2",
|
||||||
|
"dependencies": [],
|
||||||
|
"authors": [
|
||||||
|
"Stellar Dev"
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user