├── .gitignore
├── LICENSE
├── blccpsapibukkit
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── net
│ │ └── badlion
│ │ └── blccpsapibukkit
│ │ ├── BlcCpsApiBukkit.java
│ │ ├── Conf.java
│ │ └── listener
│ │ └── PlayerListener.java
│ └── resources
│ └── plugin.yml
├── blccpsapibungee
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── net
│ │ └── badlion
│ │ └── blccpsapibungee
│ │ ├── BlcCpsApiBungee.java
│ │ ├── Conf.java
│ │ └── listener
│ │ └── PlayerListener.java
│ └── resources
│ └── plugin.yml
├── pom.xml
└── readme.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .settings
3 | .project
4 | .classpath
5 | *.class
6 | bin/*
7 | lib/*
8 | include/*
9 | bin/
10 | .idea/
11 | *.iml
12 | out/*
13 |
14 | # maven
15 | target/
16 | dependency-reduced-pom.xml
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018-2020 ESL Gaming Online, Inc
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/blccpsapibukkit/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | badlionclientclickspersecondapi
7 | net.badlion
8 | 1.2.1
9 |
10 | 4.0.0
11 |
12 | blccpsapibukkit
13 |
14 |
15 | UTF-8
16 |
17 |
18 |
19 | clean install
20 | badlionclientcpsapibukkit
21 | src/main/java
22 |
23 |
24 | .
25 | true
26 | src/main/resources/
27 |
28 | *.yml
29 |
30 |
31 |
32 |
33 |
34 |
35 | org.apache.maven.plugins
36 | maven-compiler-plugin
37 |
38 | 1.6
39 | 1.6
40 |
41 |
42 |
43 | org.apache.maven.plugins
44 | maven-shade-plugin
45 | 3.1.0
46 |
47 |
48 | package
49 |
50 | shade
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | org.bukkit
61 | bukkit
62 | 1.12.2-R0.1-SNAPSHOT
63 | provided
64 |
65 |
66 | com.google.code.gson
67 | gson
68 | 2.6.2
69 | compile
70 |
71 |
72 |
73 |
74 |
75 | spigot-repo
76 | https://hub.spigotmc.org/nexus/content/repositories/snapshots/
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/blccpsapibukkit/src/main/java/net/badlion/blccpsapibukkit/BlcCpsApiBukkit.java:
--------------------------------------------------------------------------------
1 | package net.badlion.blccpsapibukkit;
2 |
3 | import com.google.gson.Gson;
4 | import com.google.gson.GsonBuilder;
5 | import net.badlion.blccpsapibukkit.listener.PlayerListener;
6 | import org.bukkit.plugin.java.JavaPlugin;
7 |
8 | import java.io.File;
9 | import java.io.FileNotFoundException;
10 | import java.io.FileReader;
11 | import java.io.FileWriter;
12 | import java.io.IOException;
13 | import java.util.logging.Level;
14 |
15 | public class BlcCpsApiBukkit extends JavaPlugin {
16 |
17 | public static final Gson GSON_NON_PRETTY = new GsonBuilder().enableComplexMapKeySerialization().disableHtmlEscaping().create();
18 | private static final Gson GSON_PRETTY = new GsonBuilder().enableComplexMapKeySerialization().disableHtmlEscaping().setPrettyPrinting().create();
19 |
20 | private Conf conf;
21 |
22 | @Override
23 | public void onEnable() {
24 |
25 | if (!this.getDataFolder().exists()) {
26 | if (!this.getDataFolder().mkdir()) {
27 | this.getLogger().log(Level.SEVERE, "Failed to create plugin directory.");
28 | }
29 | }
30 |
31 | try {
32 | this.conf = loadConf(new File(this.getDataFolder(), "config.json"));
33 |
34 | // Register channel
35 | this.getServer().getMessenger().registerOutgoingPluginChannel(this, "badlion:cps");
36 |
37 | // Only register the listener if the config loads successfully
38 | this.getServer().getPluginManager().registerEvents(new PlayerListener(this), this);
39 |
40 | this.getLogger().log(Level.INFO, "Successfully setup BadlionClientCPSAPI plugin.");
41 | } catch (Exception ex) {
42 | this.getLogger().log(Level.SEVERE, "Error with config for BadlionClientCPSAPI plugin : " + ex.getMessage(), ex);
43 | }
44 | }
45 |
46 | @Override
47 | public void onDisable() {
48 |
49 | }
50 |
51 | private Conf loadConf(File file) {
52 | FileReader fileReader = null;
53 |
54 | try {
55 | fileReader = new FileReader(file);
56 | return BlcCpsApiBukkit.GSON_NON_PRETTY.fromJson(fileReader, Conf.class);
57 | } catch (FileNotFoundException ex) {
58 | this.getLogger().log(Level.INFO,"No Config Found: Saving default...");
59 | Conf conf = new Conf();
60 | this.saveConf(conf, file);
61 | return conf;
62 | } finally {
63 | if (fileReader != null) {
64 | try {
65 | fileReader.close();
66 | } catch (IOException ignored) {
67 |
68 | }
69 | }
70 | }
71 | }
72 |
73 | private void saveConf(Conf conf, File file) {
74 | FileWriter fileWriter = null;
75 |
76 | try {
77 | fileWriter = new FileWriter(file);
78 | BlcCpsApiBukkit.GSON_PRETTY.toJson(conf, fileWriter);
79 | } catch (Exception ex) {
80 | ex.printStackTrace();
81 | } finally {
82 | if (fileWriter != null) {
83 | try {
84 | fileWriter.close();
85 | } catch (IOException ignored) {
86 |
87 | }
88 | }
89 | }
90 | }
91 |
92 | public Conf getConf() {
93 | return this.conf;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/blccpsapibukkit/src/main/java/net/badlion/blccpsapibukkit/Conf.java:
--------------------------------------------------------------------------------
1 | package net.badlion.blccpsapibukkit;
2 |
3 | public class Conf {
4 | private int clicksPerSecondLimitRight = 20;
5 | private int clicksPerSecondLimit = 20;
6 | }
7 |
--------------------------------------------------------------------------------
/blccpsapibukkit/src/main/java/net/badlion/blccpsapibukkit/listener/PlayerListener.java:
--------------------------------------------------------------------------------
1 | package net.badlion.blccpsapibukkit.listener;
2 |
3 | import net.badlion.blccpsapibukkit.BlcCpsApiBukkit;
4 | import org.bukkit.entity.Player;
5 | import org.bukkit.event.EventHandler;
6 | import org.bukkit.event.Listener;
7 | import org.bukkit.event.player.PlayerJoinEvent;
8 |
9 | import java.lang.reflect.Constructor;
10 | import java.lang.reflect.Field;
11 | import java.lang.reflect.InvocationTargetException;
12 | import java.lang.reflect.Method;
13 | import java.util.Arrays;
14 |
15 | public class PlayerListener implements Listener {
16 |
17 | private BlcCpsApiBukkit plugin;
18 | private String versionSuffix;
19 |
20 | private Method getHandleMethod;
21 |
22 | private Field playerConnectionField;
23 |
24 | private Method sendPacketMethod;
25 |
26 | private Constructor> packetPlayOutCustomPayloadConstructor;
27 |
28 | // Bukkit 1.8+ support
29 | private Class> packetDataSerializerClass;
30 | private Constructor> packetDataSerializerConstructor;
31 |
32 | // Bukkit 1.13+ support
33 | private Class> minecraftKeyClass;
34 | private Constructor> minecraftKeyConstructor;
35 |
36 | private Method wrappedBufferMethod;
37 |
38 | public PlayerListener(BlcCpsApiBukkit plugin) {
39 | this.plugin = plugin;
40 |
41 | // Get the v1_X_Y from the end of the package name, e.g. v_1_7_R4 or v_1_12_R1
42 | String packageName = plugin.getServer().getClass().getPackage().getName();
43 | String[] parts = packageName.split("\\.");
44 |
45 | if (parts.length > 0) {
46 | String suffix = parts[parts.length - 1];
47 | if (!suffix.startsWith("v")) {
48 | throw new RuntimeException("Failed to find version for running Minecraft server, got suffix " + suffix);
49 | }
50 |
51 | this.versionSuffix = suffix;
52 |
53 | this.plugin.getLogger().info("Found version " + this.versionSuffix);
54 | }
55 |
56 | // We need to use reflection because Bukkit by default handles plugin messages in a really silly way
57 | // Reflection stuff
58 | Class> craftPlayerClass = this.getClass("org.bukkit.craftbukkit." + this.versionSuffix + ".entity.CraftPlayer");
59 | if (craftPlayerClass == null) {
60 | throw new RuntimeException("Failed to find CraftPlayer class");
61 | }
62 |
63 | Class> nmsPlayerClass = this.getClass("net.minecraft.server." + this.versionSuffix + ".EntityPlayer");
64 | if (nmsPlayerClass == null) {
65 | throw new RuntimeException("Failed to find EntityPlayer class");
66 | }
67 |
68 | Class> playerConnectionClass = this.getClass("net.minecraft.server." + this.versionSuffix + ".PlayerConnection");
69 | if (playerConnectionClass == null) {
70 | throw new RuntimeException("Failed to find PlayerConnection class");
71 | }
72 |
73 | Class> packetPlayOutCustomPayloadClass = this.getClass("net.minecraft.server." + this.versionSuffix + ".PacketPlayOutCustomPayload");
74 | if (packetPlayOutCustomPayloadClass == null) {
75 | throw new RuntimeException("Failed to find PacketPlayOutCustomPayload class");
76 | }
77 |
78 | this.packetPlayOutCustomPayloadConstructor = this.getConstructor(packetPlayOutCustomPayloadClass, String.class, byte[].class);
79 | if (this.packetPlayOutCustomPayloadConstructor == null) {
80 | // Newer versions of Minecraft use a different custom packet system
81 | this.packetDataSerializerClass = this.getClass("net.minecraft.server." + this.versionSuffix + ".PacketDataSerializer");
82 | if (this.packetDataSerializerClass == null) {
83 | throw new RuntimeException("Failed to find PacketPlayOutCustomPayload constructor or PacketDataSerializer class");
84 | }
85 |
86 | // Netty classes used by newer 1.8 and newer
87 | Class> byteBufClass = this.getClass("io.netty.buffer.ByteBuf");
88 | if (byteBufClass == null) {
89 | throw new RuntimeException("Failed to find PacketPlayOutCustomPayload constructor or ByteBuf class");
90 | }
91 |
92 | this.packetDataSerializerConstructor = this.getConstructor(this.packetDataSerializerClass, byteBufClass);
93 | if (this.packetDataSerializerConstructor == null) {
94 | throw new RuntimeException("Failed to find PacketPlayOutCustomPayload constructor or PacketDataSerializer constructor");
95 | }
96 |
97 | Class> unpooledClass = this.getClass("io.netty.buffer.Unpooled");
98 | if (unpooledClass == null) {
99 | throw new RuntimeException("Failed to find PacketPlayOutCustomPayload constructor or Unpooled class");
100 | }
101 |
102 | this.wrappedBufferMethod = this.getMethod(unpooledClass, "wrappedBuffer", byte[].class);
103 | if (this.wrappedBufferMethod == null) {
104 | throw new RuntimeException("Failed to find PacketPlayOutCustomPayload constructor or wrappedBuffer()");
105 | }
106 |
107 | // If we made it this far in theory we are on at least 1.8
108 | this.packetPlayOutCustomPayloadConstructor = this.getConstructor(packetPlayOutCustomPayloadClass, String.class, this.packetDataSerializerClass);
109 | if (this.packetPlayOutCustomPayloadConstructor == null) {
110 | // Ok we are in 1.13 or higher now...
111 | this.minecraftKeyClass = this.getClass("net.minecraft.server." + this.versionSuffix + ".MinecraftKey");
112 | if (this.minecraftKeyClass == null) {
113 | throw new RuntimeException("Failed to find PacketPlayOutCustomPayload constructor or MinecraftKey class");
114 | }
115 |
116 | this.minecraftKeyConstructor = this.getConstructor(this.minecraftKeyClass, String.class, String.class);
117 | if (this.minecraftKeyConstructor == null) {
118 | throw new RuntimeException("Failed to find PacketPlayOutCustomPayload constructor or MinecraftKey constructor");
119 | }
120 |
121 | // If we still can't find this...unknown version
122 | this.packetPlayOutCustomPayloadConstructor = this.getConstructor(packetPlayOutCustomPayloadClass, this.minecraftKeyClass, this.packetDataSerializerClass);
123 | if (this.packetPlayOutCustomPayloadConstructor == null) {
124 | throw new RuntimeException("Failed to find PacketPlayOutCustomPayload constructor");
125 | }
126 | }
127 | }
128 |
129 | this.getHandleMethod = this.getMethod(craftPlayerClass, "getHandle");
130 | if (this.getHandleMethod == null) {
131 | throw new RuntimeException("Failed to find CraftPlayer.getHandle()");
132 | }
133 |
134 | this.playerConnectionField = this.getField(nmsPlayerClass, "playerConnection");
135 | if (this.playerConnectionField == null) {
136 | throw new RuntimeException("Failed to find EntityPlayer.playerConnection");
137 | }
138 |
139 | this.sendPacketMethod = this.getMethod(playerConnectionClass, "sendPacket");
140 | if (this.sendPacketMethod == null) {
141 | throw new RuntimeException("Failed to find PlayerConnection.sendPacket()");
142 | }
143 | }
144 |
145 | @EventHandler
146 | public void onPlayerJoin(PlayerJoinEvent event) {
147 | Player player = event.getPlayer();
148 |
149 | // Create data we need for packet;
150 | String channel = "badlion:cps";
151 | byte[] message = BlcCpsApiBukkit.GSON_NON_PRETTY.toJson(this.plugin.getConf()).getBytes();
152 |
153 | try {
154 | Object packet;
155 |
156 | // 1.13+
157 | if (this.minecraftKeyClass != null) {
158 | Object minecraftKey = this.minecraftKeyConstructor.newInstance("badlion", "cps");
159 | Object byteBuf = this.wrappedBufferMethod.invoke(null, (Object) message);
160 | Object packetDataSerializer = this.packetDataSerializerConstructor.newInstance(byteBuf);
161 |
162 | packet = this.packetPlayOutCustomPayloadConstructor.newInstance(minecraftKey, packetDataSerializer);
163 | } else if (this.packetDataSerializerClass != null) { // 1.8+
164 | Object byteBuf = this.wrappedBufferMethod.invoke(null, (Object) message);
165 | Object packetDataSerializer = this.packetDataSerializerConstructor.newInstance(byteBuf);
166 |
167 | packet = this.packetPlayOutCustomPayloadConstructor.newInstance(channel, packetDataSerializer);
168 | } else { // 1.7
169 | // Work our magic to make the packet
170 | packet = this.packetPlayOutCustomPayloadConstructor.newInstance(channel, message);
171 | }
172 |
173 | // Work our magic to send the packet
174 | Object nmsPlayer = this.getHandleMethod.invoke(player);
175 | Object playerConnection = this.playerConnectionField.get(nmsPlayer);
176 | this.sendPacketMethod.invoke(playerConnection, packet);
177 | } catch (IllegalAccessException e) {
178 | this.plugin.getLogger().severe("Failed to send BLC CPS packet");
179 | e.printStackTrace();
180 | } catch (InvocationTargetException e) {
181 | this.plugin.getLogger().severe("Failed to send BLC CPS packet");
182 | e.printStackTrace();
183 | } catch (InstantiationException e) {
184 | this.plugin.getLogger().severe("Failed to send BLC CPS packet");
185 | e.printStackTrace();
186 | }
187 | }
188 |
189 | private Class> getClass(String className) {
190 | try {
191 | return Class.forName(className);
192 | } catch (ClassNotFoundException e) {
193 | return null;
194 | }
195 | }
196 |
197 | private Constructor> getConstructor(Class> clazz, Class>... params) {
198 | for (final Constructor> constructor : clazz.getDeclaredConstructors()) {
199 | if (Arrays.equals(constructor.getParameterTypes(), params)) {
200 | constructor.setAccessible(true);
201 | return constructor;
202 | }
203 | }
204 |
205 | return null;
206 | }
207 |
208 | private Method getMethod(Class> clazz, String methodName, Class>... params) {
209 | for (final Method method : clazz.getDeclaredMethods()) {
210 | if (method.getName().equals(methodName)) {
211 | if (params.length > 0) {
212 | if (Arrays.equals(method.getParameterTypes(), params)) {
213 | method.setAccessible(true);
214 | return method;
215 | }
216 | } else {
217 | method.setAccessible(true);
218 | return method;
219 | }
220 | }
221 | }
222 |
223 | return null;
224 | }
225 |
226 | private Field getField(Class> clazz, String fieldName) {
227 | for (final Field field : clazz.getDeclaredFields()) {
228 | if (field.getName().equals(fieldName)) {
229 | field.setAccessible(true);
230 | return field;
231 | }
232 | }
233 |
234 | return null;
235 | }
236 |
237 | }
238 |
--------------------------------------------------------------------------------
/blccpsapibukkit/src/main/resources/plugin.yml:
--------------------------------------------------------------------------------
1 | name: BadlionClientCPSAPI
2 | main: net.badlion.blccpsapibukkit.BlcCpsApiBukkit
3 | version: 1.0
4 | author: Badlion
--------------------------------------------------------------------------------
/blccpsapibungee/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | badlionclientclickspersecondapi
7 | net.badlion
8 | 1.2.1
9 |
10 | 4.0.0
11 |
12 | blccpsapibungee
13 |
14 |
15 | UTF-8
16 |
17 |
18 |
19 | clean install
20 | badlionclientcpsapibungee
21 | src/main/java
22 |
23 |
24 | .
25 | true
26 | src/main/resources/
27 |
28 | *.yml
29 |
30 |
31 |
32 |
33 |
34 |
35 | org.apache.maven.plugins
36 | maven-compiler-plugin
37 |
38 | 1.7
39 | 1.7
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | net.md-5
48 | bungeecord-api
49 | 1.12-SNAPSHOT
50 | jar
51 | provided
52 |
53 |
54 | net.md-5
55 | bungeecord-api
56 | 1.12-SNAPSHOT
57 | javadoc
58 | provided
59 |
60 |
61 |
62 |
63 |
64 | bungeecord-repo
65 | https://oss.sonatype.org/content/repositories/snapshots
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/blccpsapibungee/src/main/java/net/badlion/blccpsapibungee/BlcCpsApiBungee.java:
--------------------------------------------------------------------------------
1 | package net.badlion.blccpsapibungee;
2 |
3 | import com.google.gson.Gson;
4 | import com.google.gson.GsonBuilder;
5 | import net.badlion.blccpsapibungee.listener.PlayerListener;
6 | import net.md_5.bungee.api.plugin.Plugin;
7 |
8 | import java.io.File;
9 | import java.io.FileNotFoundException;
10 | import java.io.FileReader;
11 | import java.io.FileWriter;
12 | import java.io.IOException;
13 | import java.util.logging.Level;
14 |
15 | public class BlcCpsApiBungee extends Plugin {
16 |
17 | public static final Gson GSON_NON_PRETTY = new GsonBuilder().enableComplexMapKeySerialization().disableHtmlEscaping().create();
18 | private static final Gson GSON_PRETTY = new GsonBuilder().enableComplexMapKeySerialization().disableHtmlEscaping().setPrettyPrinting().create();
19 |
20 | private Conf conf;
21 |
22 | @Override
23 | public void onEnable() {
24 | if (!this.getDataFolder().exists()) {
25 | if (!this.getDataFolder().mkdir()) {
26 | this.getLogger().log(Level.SEVERE, "Failed to create plugin directory.");
27 | }
28 | }
29 |
30 | try {
31 | this.conf = loadConf(new File(this.getDataFolder(), "config.json"));
32 |
33 | // Only register the listener if the config loads successfully
34 | this.getProxy().getPluginManager().registerListener(this, new PlayerListener(this));
35 |
36 | this.getLogger().log(Level.INFO, "Successfully setup BadlionClientCPSAPI plugin.");
37 | } catch (Exception e) {
38 | this.getLogger().log(Level.SEVERE, "Error with config for BadlionClientCPSAPI plugin.");
39 | e.printStackTrace();
40 | }
41 | }
42 |
43 | @Override
44 | public void onDisable() {
45 |
46 | }
47 |
48 | private Conf loadConf(File file) throws IOException {
49 |
50 | try (FileReader fileReader = new FileReader(file)) {
51 | return BlcCpsApiBungee.GSON_NON_PRETTY.fromJson(fileReader, Conf.class);
52 | } catch (FileNotFoundException ex) {
53 | this.getLogger().log(Level.INFO, "No Config Found: Saving default...");
54 | Conf conf = new Conf();
55 | this.saveConf(conf, file);
56 | return conf;
57 | }
58 | }
59 |
60 | private void saveConf(Conf conf, File file) {
61 |
62 | try (FileWriter fileWriter = new FileWriter(file)) {
63 | BlcCpsApiBungee.GSON_PRETTY.toJson(conf, fileWriter);
64 | } catch (Exception ex) {
65 | ex.printStackTrace();
66 | }
67 | }
68 |
69 | public Conf getConf() {
70 | return this.conf;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/blccpsapibungee/src/main/java/net/badlion/blccpsapibungee/Conf.java:
--------------------------------------------------------------------------------
1 | package net.badlion.blccpsapibungee;
2 |
3 | public class Conf {
4 | private int clicksPerSecondLimitRight = 20;
5 | private int clicksPerSecondLimit = 20;
6 | }
7 |
--------------------------------------------------------------------------------
/blccpsapibungee/src/main/java/net/badlion/blccpsapibungee/listener/PlayerListener.java:
--------------------------------------------------------------------------------
1 | package net.badlion.blccpsapibungee.listener;
2 |
3 | import net.badlion.blccpsapibungee.BlcCpsApiBungee;
4 | import net.md_5.bungee.api.connection.ProxiedPlayer;
5 | import net.md_5.bungee.api.event.PostLoginEvent;
6 | import net.md_5.bungee.api.plugin.Listener;
7 | import net.md_5.bungee.event.EventHandler;
8 | import net.md_5.bungee.protocol.packet.PluginMessage;
9 |
10 | public class PlayerListener implements Listener {
11 |
12 | private BlcCpsApiBungee plugin;
13 |
14 | public PlayerListener(BlcCpsApiBungee plugin) {
15 | this.plugin = plugin;
16 | }
17 |
18 | @EventHandler
19 | public void onLogin(PostLoginEvent event) {
20 | // Send the click speed limitation to players when they login to the proxy. A notification will appear on the Badlion Client so they know their CPS has been limited
21 | ProxiedPlayer player = event.getPlayer();
22 | player.unsafe().sendPacket(new PluginMessage("badlion:cps", BlcCpsApiBungee.GSON_NON_PRETTY.toJson(this.plugin.getConf()).getBytes(), false));
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/blccpsapibungee/src/main/resources/plugin.yml:
--------------------------------------------------------------------------------
1 | name: BadlionClientCPSAPI
2 | main: net.badlion.blccpsapibungee.BlcCpsApiBungee
3 | version: 1.0
4 | author: Badlion
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | 4.0.0
7 |
8 | net.badlion
9 | badlionclientclickspersecondapi
10 | pom
11 | 1.2.1
12 |
13 |
14 | blccpsapibungee
15 | blccpsapibukkit
16 |
17 |
18 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Badlion Client CPS API
2 |
3 | This repository explains how to limit the clicks per second (cps) of a Badlion Client user via a simple Bungee/Bukkit plugin.
4 |
5 | By default there is no limitation to how fast you can click with the Badlion Client.
6 |
7 | ### Installation
8 |
9 | How to install the Badlion Client CPS API on your server.
10 |
11 | #### Quick Installation (for non-programmers)
12 |
13 | 1. Download **either** the latest bukkit or bungee plugin from our releases (you don't need both, we recommend using the BungeeCord plugin if you are running BungeeCord): https://github.com/BadlionNetwork/BadlionClientCPSAPI/releases
14 | 2. Place the downloaded plugin into your `plugins` directory on your server.
15 | 3. Turn on the BungeeCord or Bukkit server and a default config will be automatically made in `plugins/BadlionClientCPSAPI/config.json`
16 | 4. Edit the config as you see fit and reboot the server after you have finished editing the config (see below for more information).
17 |
18 | #### Do it yourself (for programmers)
19 |
20 | 1. Clone this repository
21 | 2. Compile the plugin(s) you want to use (you only need one per Minecraft network).
22 | 2. Place the compiled plugins from the `target` directories into your `plugins` directory on your server.
23 | 3. Turn on the BungeeCord or Bukkit server and a default config will be automatically made in `plugins/BadlionClientCPSAPI/config.json`
24 | 4. Edit the config as you see fit and reboot the server after you have finished editing the config (see below for more information).
25 |
26 | ### Example Config
27 |
28 | To make a config place the information below example into `plugins/BadlionClientCPSAPI/config.json`. If you have any JSON errors it will not load the plugin properly. A quick and easy way to test that your JSON config is valid is to use this tool: https://jsonformatter.curiousconcept.com/
29 |
30 | This example config will limit a user to 20 clicks per second (cps) when playing on your server with the Badlion Client.
31 |
32 | ```json
33 | {
34 | "clicksPerSecondLimit": 20,
35 | "clicksPerSecondLimitRight": 20
36 | }
37 | ```
38 |
39 | The first value `clicksPerSecondLimit` is for left click and the second value `clicksPerSecondLimitRight` is for right click.
40 |
--------------------------------------------------------------------------------