parent
4503f15d6c
commit
621c006590
15 changed files with 233 additions and 51 deletions
19
README.md
Normal file
19
README.md
Normal file
|
@ -0,0 +1,19 @@
|
|||
# tweaks724
|
||||
|
||||
Dependencies: ProtocolLib
|
||||
|
||||
### Caveats
|
||||
Disable "secure chat"
|
||||
|
||||
### Chatrooms
|
||||
- `/c` to see info about current chatroom
|
||||
- `/c <name>` to join a chatroom
|
||||
- `/cm create <name>` to create a chatroom
|
||||
- `/cm set* <name>` to change a setting (for owners)
|
||||
|
||||
### Commands
|
||||
- `/dkick` - discreet kick. The player will be kicked with a cryptic error message, and those smarter will think it's a plugin bug.[^1] Brilliant!
|
||||
- `/ping` - checks ping. Ping is checked using a more accurate[^2] method
|
||||
|
||||
[^1]: or, better, client bug, if they don't trust their client
|
||||
[^2]: not
|
36
pom.xml
36
pom.xml
|
@ -5,7 +5,7 @@
|
|||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>eu.m724</groupId>
|
||||
<artifactId>mutils</artifactId>
|
||||
<artifactId>tweaks</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
|
@ -21,6 +21,40 @@
|
|||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<!-- this is to reduce jar size by 1 or 2 kb -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.6.0</version>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<minimizeJar>true</minimizeJar>
|
||||
<artifactSet>
|
||||
<includes>
|
||||
<include>eu.m724:tweaks</include>
|
||||
</includes>
|
||||
</artifactSet>
|
||||
<filters>
|
||||
<filter>
|
||||
<artifact>*</artifact>
|
||||
<excludes>
|
||||
<exclude>META-INF/**</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
</filters>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!-- end of this -->
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
|
|
|
@ -25,5 +25,6 @@ public class TweaksPlugin extends JavaPlugin {
|
|||
new F3NameListener(this).init();
|
||||
new PingChecker(this).init();
|
||||
Objects.requireNonNull(getCommand("ping")).setExecutor(new PingCommands());
|
||||
Objects.requireNonNull(getCommand("dkick")).setExecutor(new PingCommands());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,17 +30,12 @@ public class ChatCommands implements CommandExecutor {
|
|||
ChatRoom chatRoom = manager.getPlayerChatRoom(player);
|
||||
|
||||
if (args.length == 0) { // show room
|
||||
BaseComponent[] component = new ComponentBuilder("Active chat room: ").color(ChatColor.GOLD)
|
||||
.append(chatRoom.id).color(chatRoom.color)
|
||||
.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(chatRoom.getInfoComponent())))
|
||||
.create();
|
||||
player.spigot().sendMessage(component);
|
||||
player.spigot().sendMessage(chatRoom.getInfoComponent());
|
||||
} else { // join room
|
||||
// TODO move joining logic
|
||||
String id = args[0];
|
||||
String password = null;
|
||||
if (args.length > 1) {
|
||||
password = Arrays.stream(args).skip(1).collect(Collectors.joining(" ")).strip();
|
||||
password = Arrays.stream(args).skip(1).collect(Collectors.joining(" "));
|
||||
}
|
||||
|
||||
boolean authenticated = false;
|
||||
|
@ -105,7 +100,8 @@ public class ChatCommands implements CommandExecutor {
|
|||
case "delete" -> {
|
||||
if (argument.equals(chatRoom.id)) {
|
||||
if (isOwner) {
|
||||
// TODO
|
||||
manager.deleteChatRoom(chatRoom);
|
||||
sender.sendMessage("Room %s deleted".formatted(chatRoom.id));
|
||||
} else {
|
||||
sender.sendMessage("You're not the owner of %s, please enter the room you want to make changes in".formatted(chatRoom.id));
|
||||
}
|
||||
|
@ -134,7 +130,7 @@ public class ChatCommands implements CommandExecutor {
|
|||
}
|
||||
case "setpassword" -> {
|
||||
if (isOwner) {
|
||||
chatRoom.password = Arrays.stream(args).skip(1).collect(Collectors.joining(" ")).strip();
|
||||
chatRoom.password = Arrays.stream(args).skip(1).collect(Collectors.joining(" "));
|
||||
try {
|
||||
manager.saveChatRoom(chatRoom);
|
||||
sender.sendMessage("Password changed");
|
||||
|
@ -174,13 +170,13 @@ public class ChatCommands implements CommandExecutor {
|
|||
case "create" ->
|
||||
sender.sendMessage("Please pass a room name as an argument. The room name must be of characters and digits.");
|
||||
case "delete" ->
|
||||
sender.sendMessage("You want to delete room %s. Confirm by passing its name as an argument for this action.".formatted(chatRoom));
|
||||
sender.sendMessage("You want to delete room %s. Confirm by passing its name as an argument for this action.".formatted(chatRoom.id));
|
||||
case "setowner" ->
|
||||
sender.sendMessage("To transfer ownership of room %s, pass the new owner name as an argument for this action.".formatted(chatRoom));
|
||||
sender.sendMessage("To transfer ownership of room %s, pass the new owner name as an argument for this action.".formatted(chatRoom.id));
|
||||
case "setpassword" ->
|
||||
sender.sendMessage("To change the password of room %s, pass the new password as an argument for this action.".formatted(chatRoom));
|
||||
sender.sendMessage("To change the password of room %s, pass the new password as an argument for this action.".formatted(chatRoom.id));
|
||||
case "setcolor" ->
|
||||
sender.sendMessage("To change the message color of room %s, pass the new color as an argument for this action. #hex or color name.".formatted(chatRoom));
|
||||
sender.sendMessage("To change the message color of room %s, pass the new color as an argument for this action. #hex or color name.".formatted(chatRoom.id));
|
||||
default ->
|
||||
sender.sendMessage("Actions: create, delete, setowner, setpassword, setcolor");
|
||||
}
|
||||
|
|
39
src/main/java/eu/m724/tweaks/chat/ChatFormatUtils.java
Normal file
39
src/main/java/eu/m724/tweaks/chat/ChatFormatUtils.java
Normal file
|
@ -0,0 +1,39 @@
|
|||
package eu.m724.tweaks.chat;
|
||||
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||
import net.md_5.bungee.api.chat.HoverEvent;
|
||||
import net.md_5.bungee.api.chat.hover.content.Text;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class ChatFormatUtils {
|
||||
public static BaseComponent[] formatPlayer(Player player) {
|
||||
ChatColor nameColor = ChatColor.of("#" + Integer.toHexString(player.getName().hashCode()).substring(0, 6));
|
||||
|
||||
if (player.getCustomName() != null) {
|
||||
return new ComponentBuilder()
|
||||
.append("~" + player.getCustomName()).color(nameColor)
|
||||
.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(player.getName())))
|
||||
.create();
|
||||
} else {
|
||||
return new ComponentBuilder()
|
||||
.append(player.getName()).color(nameColor)
|
||||
.create();
|
||||
}
|
||||
}
|
||||
|
||||
public static BaseComponent[] chatRoomPrefixShort(ChatRoom chatRoom) {
|
||||
ChatColor prefixColor = ChatColor.of(chatRoom.color.getColor().darker());
|
||||
|
||||
return new ComponentBuilder(chatRoom.id.charAt(0) + " ").color(prefixColor)
|
||||
.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(chatRoom.getInfoComponent())))
|
||||
.create();
|
||||
}
|
||||
|
||||
public static BaseComponent[] formatChatRoom(ChatRoom chatRoom) {
|
||||
return new ComponentBuilder(chatRoom.id).color(chatRoom.color)
|
||||
.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(chatRoom.getInfoComponent())))
|
||||
.create();
|
||||
}
|
||||
}
|
|
@ -3,13 +3,12 @@ package eu.m724.tweaks.chat;
|
|||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||
import net.md_5.bungee.api.chat.HoverEvent;
|
||||
import net.md_5.bungee.api.chat.hover.content.Text;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
public class ChatListener implements Listener {
|
||||
private final ChatManager chatManager;
|
||||
|
@ -24,12 +23,37 @@ public class ChatListener implements Listener {
|
|||
ChatRoom chatRoom = chatManager.getPlayerChatRoom(player);
|
||||
|
||||
BaseComponent[] component = new ComponentBuilder("Chat room: ").color(ChatColor.GOLD)
|
||||
.append(chatRoom.id).color(ChatColor.AQUA)
|
||||
.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(chatRoom.getInfoComponent())))
|
||||
.append(ChatFormatUtils.formatChatRoom(chatRoom))
|
||||
.create();
|
||||
player.spigot().sendMessage(component);
|
||||
|
||||
event.setJoinMessage(null); // TODO room messages
|
||||
chatRoom.broadcast(
|
||||
new ComponentBuilder()
|
||||
.append(ChatFormatUtils.chatRoomPrefixShort(chatRoom))
|
||||
.append(ChatFormatUtils.formatPlayer(player))
|
||||
.append(" has joined the server").color(ChatColor.GREEN)
|
||||
.create()
|
||||
);
|
||||
|
||||
// remove Minecraft join message
|
||||
event.setJoinMessage(null);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
ChatRoom chatRoom = chatManager.removePlayer(player);
|
||||
|
||||
chatRoom.broadcast(
|
||||
new ComponentBuilder()
|
||||
.append(ChatFormatUtils.chatRoomPrefixShort(chatRoom))
|
||||
.append(ChatFormatUtils.formatPlayer(player))
|
||||
.append(" has left the server").color(ChatColor.RED)
|
||||
.create()
|
||||
);
|
||||
|
||||
// remove Minecraft quit message
|
||||
event.setQuitMessage(null);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
|
@ -38,24 +62,14 @@ public class ChatListener implements Listener {
|
|||
ChatRoom chatRoom = chatManager.getPlayerChatRoom(player);
|
||||
String message = event.getMessage();
|
||||
|
||||
// TODO move sending logic
|
||||
ChatColor prefixColor = ChatColor.of(chatRoom.color.getColor().darker());
|
||||
ChatColor nameColor = ChatColor.of("#" + Integer.toHexString(player.getName().hashCode()).substring(0, 6));
|
||||
|
||||
ComponentBuilder builder = new ComponentBuilder(chatRoom.id.charAt(0) + " ").color(prefixColor)
|
||||
.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(chatRoom.getInfoComponent())));
|
||||
|
||||
if (player.getCustomName() != null) {
|
||||
builder = builder.append("~" + player.getCustomName() + ": ").color(nameColor)
|
||||
.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(chatRoom.getInfoComponent())));
|
||||
} else {
|
||||
builder = builder.append(player.getName() + ": ").color(nameColor);
|
||||
}
|
||||
|
||||
builder = builder.append(message).color(chatRoom.color);
|
||||
ComponentBuilder builder = new ComponentBuilder();
|
||||
builder.append(ChatFormatUtils.chatRoomPrefixShort(chatRoom));
|
||||
builder.append(ChatFormatUtils.formatPlayer(player)).append(": ");
|
||||
builder.append(message).color(chatRoom.color);
|
||||
|
||||
chatRoom.broadcast(builder.create());
|
||||
|
||||
// remove the original message
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package eu.m724.tweaks.chat;
|
||||
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
|
@ -27,6 +29,18 @@ public class ChatManager {
|
|||
plugin.getServer().getPluginManager().registerEvents(new ChatListener(this), plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* removes player from the server and their chatroom
|
||||
* @param player the player
|
||||
* @return the chatroom the player was removed from
|
||||
*/
|
||||
public ChatRoom removePlayer(Player player) {
|
||||
ChatRoom chatRoom = playerMap.remove(player);
|
||||
chatRoom.players.remove(player);
|
||||
|
||||
return chatRoom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a chat room by id.<br>
|
||||
* If the chat room is not loaded, it's loaded.
|
||||
|
@ -59,6 +73,22 @@ public class ChatManager {
|
|||
player.getPersistentDataContainer().set(chatRoomKey, PersistentDataType.STRING, chatRoom.id);
|
||||
playerMap.put(player, chatRoom);
|
||||
chatRoom.players.add(player);
|
||||
|
||||
chatRoom.broadcast(
|
||||
new ComponentBuilder()
|
||||
.append(ChatFormatUtils.chatRoomPrefixShort(chatRoom))
|
||||
.append(ChatFormatUtils.formatPlayer(player))
|
||||
.append(" has left the chat room").color(ChatColor.RED)
|
||||
.create()
|
||||
);
|
||||
|
||||
chatRoom.broadcast(
|
||||
new ComponentBuilder()
|
||||
.append(ChatFormatUtils.chatRoomPrefixShort(chatRoom))
|
||||
.append(ChatFormatUtils.formatPlayer(player))
|
||||
.append(" has joined the chat room").color(ChatColor.GREEN)
|
||||
.create()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -123,6 +153,14 @@ public class ChatManager {
|
|||
ChatRoomLoader.save(plugin, chatRoom);
|
||||
}
|
||||
|
||||
public void deleteChatRoom(ChatRoom chatRoom) {
|
||||
roomIdMap.remove(chatRoom.id);
|
||||
ChatRoomLoader.getFile(plugin, chatRoom.id).delete();
|
||||
chatRoom.players.forEach(player -> {
|
||||
setPlayerChatRoom(getById("global"), player);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* If an ID is too short, too long, wrong composition, etc.
|
||||
*/
|
||||
|
|
|
@ -25,7 +25,6 @@ public class ChatRoom {
|
|||
this.owner = owner;
|
||||
}
|
||||
|
||||
// TODO not recompute every time
|
||||
/**
|
||||
* @return A nicely formatted text block with info such as room id, owner, online, etc.
|
||||
*/
|
||||
|
@ -46,7 +45,7 @@ public class ChatRoom {
|
|||
builder = builder.append(playersList.removeFirst().getName()).color(ChatColor.GRAY);
|
||||
|
||||
for (Player player : playersList) {
|
||||
builder = builder.append(", ").color(ChatColor.GRAY)
|
||||
builder = builder.append(", ").color(ChatColor.GREEN)
|
||||
.append(player.getName()).color(ChatColor.AQUA);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,13 +12,18 @@ import java.nio.file.Paths;
|
|||
import java.util.UUID;
|
||||
|
||||
public class ChatRoomLoader {
|
||||
private static File getFile(Plugin plugin, String id) {
|
||||
/**
|
||||
* Get the file of persistent storage of a chat room
|
||||
* @return the file or null if ID is invalid
|
||||
*/
|
||||
static File getFile(Plugin plugin, String id) {
|
||||
Path chatRoomsPath = Paths.get(plugin.getDataFolder().getPath(), "rooms");
|
||||
chatRoomsPath.toFile().mkdirs();
|
||||
|
||||
// TODO sanitize
|
||||
File chatRoomFile = Paths.get(chatRoomsPath.toFile().getPath(), id + ".yml").toFile();
|
||||
return chatRoomFile;
|
||||
if (validateId(id) != 0)
|
||||
throw new RuntimeException("Invalid id: " + id);
|
||||
|
||||
return Paths.get(chatRoomsPath.toFile().getPath(), id + ".yml").toFile();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -20,7 +20,7 @@ public class DoorListener implements Listener {
|
|||
@EventHandler
|
||||
public void onBlockDamage(BlockDamageEvent event) {
|
||||
Block block = event.getBlock();
|
||||
if (!(block.getBlockData() instanceof Door door)) return;
|
||||
if (!(block.getBlockData() instanceof Door)) return;
|
||||
|
||||
World world = block.getLocation().getWorld();
|
||||
Player player = event.getPlayer();
|
||||
|
@ -41,11 +41,10 @@ public class DoorListener implements Listener {
|
|||
pitch = ThreadLocalRandom.current().nextFloat(0.5f, 0.7f);
|
||||
}
|
||||
|
||||
PotionEffect weakness = player.getPotionEffect(PotionEffectType.WEAKNESS);
|
||||
PotionEffect fatigue = player.getPotionEffect(PotionEffectType.MINING_FATIGUE);
|
||||
int level = (weakness != null ? weakness.getAmplifier() : 0) + (fatigue != null ? fatigue.getAmplifier() : 0);
|
||||
|
||||
if (weakness != null || fatigue != null) {
|
||||
if (fatigue != null) {
|
||||
int level = fatigue.getAmplifier();
|
||||
volume /= level / 3f;
|
||||
pitch /= level;
|
||||
}
|
||||
|
@ -53,7 +52,7 @@ public class DoorListener implements Listener {
|
|||
volume *= (float) ((10.0 - Math.min(distance - 2, 10.0)) / 10.0);
|
||||
|
||||
world.playSound(hitLocation, sound, volume, pitch);
|
||||
world.spawnParticle(Particle.BLOCK, hitLocation, (int) (10 * volume), door);
|
||||
//world.spawnParticle(Particle.BLOCK, hitLocation, (int) (10 * volume), door);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
|
|
|
@ -14,6 +14,6 @@ public class MsptChecker extends BukkitRunnable {
|
|||
}
|
||||
|
||||
public void init(Plugin plugin) {
|
||||
this.runTaskTimerAsynchronously(plugin, 0, 100); // 5 secs
|
||||
this.runTaskTimer(plugin, 0, 100); // 5 secs
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
public class PingChecker extends BukkitRunnable {
|
||||
private final Plugin plugin;
|
||||
|
||||
// TODO concurrnet too?
|
||||
// this is in nanoseconds
|
||||
private final Map<Player, Long> pending = new ConcurrentHashMap<>();
|
||||
|
||||
|
@ -39,8 +38,13 @@ public class PingChecker extends BukkitRunnable {
|
|||
|
||||
long start = pending.remove(player);
|
||||
PlayerPing.pings.put(player, System.nanoTime() - start);
|
||||
|
||||
// gotta cancel because the server will kick
|
||||
event.setCancelled(true);
|
||||
if (!PlayerPing.kickQueue.contains(player)) {
|
||||
event.setCancelled(true);
|
||||
} else {
|
||||
PlayerPing.kickQueue.remove(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -52,7 +56,8 @@ public class PingChecker extends BukkitRunnable {
|
|||
@Override
|
||||
public void run() {
|
||||
plugin.getServer().getOnlinePlayers().forEach(player -> {
|
||||
if (pending.containsKey(player)) return;
|
||||
// dropped packets happen so timing out a request after 30 seconds
|
||||
if (System.nanoTime() - pending.getOrDefault(player, 0L) < 30000000000L) return;
|
||||
pending.put(player, System.nanoTime()); // here or at the bottom? probably doesn't matter
|
||||
|
||||
PacketContainer packet = new PacketContainer(PacketType.Play.Server.COOKIE_REQUEST);
|
||||
|
|
|
@ -3,6 +3,7 @@ package eu.m724.tweaks.ping;
|
|||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
@ -18,6 +19,25 @@ public class PingCommands implements CommandExecutor {
|
|||
.append("%.2fms".formatted(PlayerPing.getPingMillis(player))).color(ChatColor.AQUA)
|
||||
.create();
|
||||
player.spigot().sendMessage(component);
|
||||
} else if (command.getName().equals("dkick")) {
|
||||
if (args.length == 0) {
|
||||
sender.sendMessage("Include one or more player names");
|
||||
} else {
|
||||
for (String name : args) {
|
||||
Player player = Bukkit.getPlayer(name);
|
||||
if (player == null) {
|
||||
sender.sendMessage("Player %s is not online".formatted(name));
|
||||
}
|
||||
if (PlayerPing.kick(player)) {
|
||||
if (player.getName().equals(sender.getName())) {
|
||||
sender.sendMessage("Kicking yourself? Very well");
|
||||
}
|
||||
sender.sendMessage("Player %s will be kicked shortly".formatted(name));
|
||||
} else {
|
||||
sender.sendMessage("Player %s is already queued".formatted(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -3,14 +3,16 @@ package eu.m724.tweaks.ping;
|
|||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class PlayerPing {
|
||||
// TODO concurrnet?
|
||||
// in nanos
|
||||
static final Map<Player, Long> pings = new ConcurrentHashMap<>();
|
||||
// nanos per tick
|
||||
static long nspt = 0L;
|
||||
static volatile long nspt = 0L;
|
||||
|
||||
static final Set<Player> kickQueue = ConcurrentHashMap.newKeySet();
|
||||
|
||||
public static long getPingNanos(Player player) {
|
||||
return pings.getOrDefault(player, -1L);
|
||||
|
@ -27,4 +29,8 @@ public class PlayerPing {
|
|||
public static double getMillisPerTick() {
|
||||
return nspt / 1000000.0; // a mil ns in ms
|
||||
}
|
||||
|
||||
public static boolean kick(Player player) {
|
||||
return kickQueue.add(player);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,4 +15,11 @@ commands:
|
|||
aliases: [cm, crm]
|
||||
ping:
|
||||
description: Your ping
|
||||
dkick:
|
||||
description: Kick a player discreetly
|
||||
permission: tweaks724.dkick
|
||||
|
||||
permissions:
|
||||
tweaks724.dkick:
|
||||
default: op
|
||||
|
||||
|
|
Loading…
Reference in a new issue