Initial commit. Chat and ranks.

master
James T. Martin 2019-09-09 15:53:48 -07:00
parent 48ab7d3cf4
commit e3a46529cf
14 changed files with 925 additions and 0 deletions

6
.gitignore vendored
View File

@ -21,3 +21,9 @@
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
# Eclipse junk
.classpath
.project
.settings/
bin/

1
src/config.yml Normal file
View File

@ -0,0 +1 @@
databaseFile: wasteland.sqlite3

View File

@ -0,0 +1,101 @@
package me.jtmar.wasteland;
import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.bukkit.entity.Player;
public class Database implements AutoCloseable {
private static final String CREATE_KILLS_TABLE =
"CREATE TABLE IF NOT EXISTS player_kills"
+ "( `player` VARCHAR(36) PRIMARY KEY"
+ ", `kills` UNSIGNED INT NOT NULL"
+ ")";
private static final String INIT_PLAYER_KILLS =
"INSERT OR IGNORE INTO `player_kills`(`player`, `kills`) VALUES (?, 0)";
private static final String GET_PLAYER_KILLS =
"SELECT `kills` FROM `player_kills` WHERE `player` = ?";
private static final String INCREMENT_PLAYER_KILLS =
"UPDATE `player_kills` SET `kills`=`kills` + 1 WHERE `player` = ?";
private static final String SET_PLAYER_KILLS =
"UPDATE `player_kills` SET `kills` = ? WHERE `player` = ?";
private final Connection connection;
private final PreparedStatement psInitPlayerKills;
private final PreparedStatement psGetPlayerKills;
private final PreparedStatement psIncrementPlayerKills;
private final PreparedStatement psSetPlayerKills;
public Database(File file)
throws IOException, ClassNotFoundException, SQLException {
if (!file.exists()) {
file.getParentFile().mkdirs();
file.createNewFile();
}
// Ensures that JDBC is installed.
Class.forName("org.sqlite.JDBC");
connection = DriverManager.getConnection("jdbc:sqlite:" + file);
// I want to let this be true, but it doesn't work if it's true.
// I can't figure out why.
connection.setAutoCommit(false);
// Initialize database tables
Statement s = connection.createStatement();
s.executeUpdate(CREATE_KILLS_TABLE);
s.close();
psInitPlayerKills = connection.prepareStatement(INIT_PLAYER_KILLS);
psGetPlayerKills = connection.prepareStatement(GET_PLAYER_KILLS);
psIncrementPlayerKills = connection.prepareStatement(INCREMENT_PLAYER_KILLS);
psSetPlayerKills = connection.prepareStatement(SET_PLAYER_KILLS);
}
public void initPlayerKills(Player player) throws SQLException {
String playerUUID = player.getUniqueId().toString();
psInitPlayerKills.setString(1, playerUUID);
psInitPlayerKills.executeUpdate();
connection.commit();
}
public int getPlayerKills(Player player) throws SQLException
{
String playerUUID = player.getUniqueId().toString();
psGetPlayerKills.setString(1, playerUUID);
try (ResultSet result = psGetPlayerKills.executeQuery()) {
if (!result.next()) return 0;
return result.getInt("kills");
}
}
public void incrementPlayerKills(Player player) throws SQLException {
String playerUUID = player.getUniqueId().toString();
psIncrementPlayerKills.setString(1, playerUUID);
psIncrementPlayerKills.executeUpdate();;
connection.commit();
}
public void setPlayerKills(Player player, int kills) throws SQLException {
if (kills < 0)
throw new IllegalArgumentException("Number of kills must not be negative: " + kills);
String playerUUID = player.getUniqueId().toString();
psSetPlayerKills.setInt(1, kills);
psSetPlayerKills.setString(2, playerUUID);
psSetPlayerKills.executeUpdate();;
connection.commit();
}
@Override
public void close() throws SQLException {
psInitPlayerKills.close();
psGetPlayerKills.close();
psIncrementPlayerKills.close();
psSetPlayerKills.close();
connection.commit();
connection.close();
}
}

View File

@ -0,0 +1,87 @@
package me.jtmar.wasteland;
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.logging.Level;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import me.jtmar.wasteland.commands.CommandRank;
import me.jtmar.wasteland.commands.CommandRanks;
import me.jtmar.wasteland.commands.CommandOfficial;
import me.jtmar.wasteland.commands.CommandSetKills;
import me.jtmar.wasteland.listeners.ChatListener;
import me.jtmar.wasteland.listeners.RankListener;
public class Wasteland extends JavaPlugin {
private static Wasteland instance;
private Database database;
private RankListener rankListener;
public static Wasteland getInstance() {
return instance;
}
public Database getDatabase() {
return database;
}
public void updatePlayerRank(Player player) throws SQLException {
rankListener.updatePlayerRank(player);
}
private void initializeDatabase() {
String databaseFilename = this.getConfig().getString("databaseFile");
try {
database = new Database(new File(this.getDataFolder(), databaseFilename));
} catch (IOException e) {
this.getLogger().log(Level.SEVERE, "Failed to write database file: " + e.getMessage());
this.getPluginLoader().disablePlugin(this);
} catch (ClassNotFoundException e) {
this.getLogger().log(Level.SEVERE, "You need the SQLite JBDC library. Google it. Put it in /lib folder.");
this.getPluginLoader().disablePlugin(this);
} catch (SQLException e) {
this.getLogger().log(Level.SEVERE, "SQLite exception on initialize.", e);
this.getPluginLoader().disablePlugin(this);
}
}
private void registerCommands() {
this.getCommand("rank").setExecutor(new CommandRank());
this.getCommand("setkills").setExecutor(new CommandSetKills());
this.getCommand("official").setExecutor(new CommandOfficial());
this.getCommand("ranks").setExecutor(new CommandRanks());
}
private void registerListeners() {
PluginManager manager = this.getServer().getPluginManager();
rankListener = new RankListener();
manager.registerEvents(rankListener, this);
manager.registerEvents(new ChatListener(), this);
}
@Override
public void onEnable() {
instance = this;
this.saveDefaultConfig();
initializeDatabase();
registerCommands();
registerListeners();
}
@Override
public void onDisable() {
rankListener.close();
rankListener = null;
try {
database.close();
} catch (SQLException e) {
this.getLogger().log(Level.SEVERE, "Failed to close database.", e);
}
instance = null;
}
}

View File

@ -0,0 +1,35 @@
package me.jtmar.wasteland.commands;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import me.jtmar.wasteland.ranks.OfficerRank;
import net.md_5.bungee.api.ChatColor;
public class CommandOfficial implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (args.length < 1) {
sender.sendMessage("Don't you actually have something to say?");
return false;
}
String senderFormat;
if (sender instanceof Player) {
Player player = (Player) sender;
OfficerRank rank = OfficerRank.getRank(player);
if (rank == null) {
sender.sendMessage("You are not a staff member.");
return true;
}
senderFormat = "[" + rank.format() + ChatColor.RESET + "] " + player.getDisplayName();
} else {
senderFormat = ChatColor.GOLD + ChatColor.BOLD.toString() + "The General of the Armies";
}
sender.getServer().broadcastMessage(senderFormat + ChatColor.RESET + ": " + ChatColor.ITALIC + String.join(" ", args));
return true;
}
}

View File

@ -0,0 +1,77 @@
package me.jtmar.wasteland.commands;
import java.sql.SQLException;
import java.util.logging.Level;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import me.jtmar.wasteland.Wasteland;
import me.jtmar.wasteland.ranks.EnlistedRank;
public class CommandRank implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (args.length > 1) {
sender.sendMessage("Too many arguments!");
sender.sendMessage(command.getUsage());
return false;
}
String playerName;
String has;
String is;
String need;
Player subject;
if (args.length == 1) {
subject = sender.getServer().getPlayer(args[0]);
if (!sender.equals(subject) && !sender.hasPermission("wasteland.kills.other")) {
sender.sendMessage("You do not have permission to view another player's kills.");
return false;
}
if (subject == null) {
sender.sendMessage("Unknown player: " + args[0]);
return false;
}
playerName = subject.getDisplayName();
has = " has ";
is = " is ";
need = " needs ";
} else if (sender instanceof Player) {
if (!sender.hasPermission("wasteland.kills")) {
sender.sendMessage("You do not have permission to view your own kills.");
}
subject = (Player) sender;
playerName = "You";
has = " have ";
is = " are ";
need = " need ";
} else {
sender.sendMessage("You are not a player! Please specify a player whose kills you want to view.");
sender.sendMessage(command.getUsage());
return false;
}
try {
int kills = Wasteland.getInstance().getDatabase().getPlayerKills(subject);
EnlistedRank rank = EnlistedRank.getRankFromKills(kills);
EnlistedRank nextRank = EnlistedRank.getNextRank(subject);
sender.sendMessage(playerName + is + "rank " + rank.formatFull() + ".");
String beginString = playerName + has + "killed " + kills + " zombies";
if (nextRank == null) {
sender.sendMessage(beginString + ".");
} else {
int moreZombies = nextRank.getMinimumKills() - kills;
sender.sendMessage(beginString + " and " + need + "to kill " + moreZombies
+ " more to reach " + nextRank.formatFull() + ".");
}
} catch (SQLException e) {
sender.sendMessage("Command failed due to database exception. Contact the server administrator.");
Wasteland.getInstance().getLogger().log(Level.SEVERE, "Failed to get player kills.", e);
}
return true;
}
}

View File

@ -0,0 +1,31 @@
package me.jtmar.wasteland.commands;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import me.jtmar.wasteland.ranks.EnlistedRank;
import me.jtmar.wasteland.ranks.OfficerRank;
import net.md_5.bungee.api.ChatColor;
public class CommandRanks implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (args.length > 0) {
sender.sendMessage("Too many arguments.");
return false;
}
sender.sendMessage("Enlisted ranks:");
for (EnlistedRank rank : EnlistedRank.values()) {
sender.sendMessage("* " + rank.formatFull() + ": " + rank.getMinimumKills() + " kills");
}
sender.sendMessage("Officer (server staff) ranks:");
for (OfficerRank rank : OfficerRank.values()) {
sender.sendMessage("* " + rank.formatFull());
}
sender.sendMessage("* " + ChatColor.GOLD + ChatColor.BOLD.toString() + "General of the Armies");
return true;
}
}

View File

@ -0,0 +1,79 @@
package me.jtmar.wasteland.commands;
import java.sql.SQLException;
import java.util.logging.Level;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import me.jtmar.wasteland.Wasteland;
public class CommandSetKills implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!sender.hasPermission("wasteland.kills.set")) {
sender.sendMessage("You do not have permission to set a player's kills.");
return true;
}
if (args.length < 1) {
sender.sendMessage("You must specify the number of kills to set to.");
return false;
}
if (args.length > 2) {
sender.sendMessage("Too many arguments.");
return false;
}
String playerNowHas;
Player subject;
if (args.length == 1) {
if (!(sender instanceof Player)) {
sender.sendMessage("You are not a player! Don't forget to specify a player argument.");
return false;
}
subject = (Player) sender;
playerNowHas = "You now have";
} else {
subject = sender.getServer().getPlayer(args[0]);
if (subject == null) {
sender.sendMessage("Unknown player: " + args[0]);
return false;
}
playerNowHas = subject.getDisplayName() + " now has";
}
String killsArg;
if (args.length == 1) {
killsArg = args[0];
} else {
killsArg = args[1];
}
int kills;
try {
kills = Integer.valueOf(killsArg);
} catch (NumberFormatException e) {
sender.sendMessage("Not a valid number of kills: " + killsArg);
return false;
}
if (kills < 0) {
sender.sendMessage("The number of kills must not be negative!");
return false;
}
try {
Wasteland.getInstance().getDatabase().setPlayerKills(subject, kills);
Wasteland.getInstance().updatePlayerRank(subject);
sender.sendMessage(playerNowHas + " " + kills + " kills.");
} catch (SQLException e) {
Wasteland.getInstance().getLogger().log(Level.SEVERE, "Failed to set player kills.", e);
sender.sendMessage("ERROR: Failed to update player kills. Please notify a server administrator.");
}
return true;
}
}

View File

@ -0,0 +1,18 @@
package me.jtmar.wasteland.listeners;
import org.bukkit.ChatColor;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import me.jtmar.wasteland.ranks.EnlistedRank;
public class ChatListener implements Listener {
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerChat(AsyncPlayerChatEvent event) {
event.setFormat(
"[" + EnlistedRank.getRank(event.getPlayer()).format() + ChatColor.RESET + "] " + " "
+ "%s" + ChatColor.WHITE + ": %s");
}
}

View File

@ -0,0 +1,112 @@
package me.jtmar.wasteland.listeners;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Level;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.permissions.PermissionAttachment;
import me.jtmar.wasteland.Wasteland;
import me.jtmar.wasteland.ranks.EnlistedRank;
import me.jtmar.wasteland.ranks.Rank;
import net.md_5.bungee.api.ChatColor;
public class RankListener implements Listener, AutoCloseable {
private Map<UUID, PermissionAttachment> attachments = new HashMap<>();
public RankListener() {
for (Player player : Wasteland.getInstance().getServer().getOnlinePlayers()) {
try {
initializePlayer(player);
} catch (SQLException e) {
Wasteland.getInstance().getLogger().log(Level.SEVERE, "Failed to get player's kills.", e);
}
}
}
private void createAttachment(Player player) throws SQLException {
PermissionAttachment attachment = player.addAttachment(Wasteland.getInstance());
attachments.put(player.getUniqueId(), attachment);
int kills = Wasteland.getInstance().getDatabase().getPlayerKills(player);
EnlistedRank rank = EnlistedRank.getRankFromKills(kills);
attachments.get(player.getUniqueId()).setPermission(rank.getPermission(), true);
}
private void removeAttachment(Player player) {
PermissionAttachment attachment = attachments.remove(player.getUniqueId());
player.removeAttachment(attachment);
}
private void initializePlayer(Player player) throws SQLException {
Wasteland.getInstance().getDatabase().initPlayerKills(player);
createAttachment(player);
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerJoin(PlayerJoinEvent event) {
Player player = event.getPlayer();
try {
initializePlayer(player);
} catch (SQLException e) {
Wasteland.getInstance().getLogger().log(Level.SEVERE, "Failed to get player's kills.", e);
return;
}
}
public void updatePlayerRank(Player player) throws SQLException {
removeAttachment(player);
createAttachment(player);
}
@EventHandler(priority = EventPriority.MONITOR)
public void onEntityDeath(EntityDeathEvent event) {
Player player = event.getEntity().getKiller();
if (player == null) return;
switch (event.getEntityType()) {
case HUSK:
case PIG_ZOMBIE:
case ZOMBIE:
case ZOMBIE_VILLAGER:
try {
Wasteland.getInstance().getDatabase().incrementPlayerKills(player);
Rank oldRank = EnlistedRank.getRank(player);
updatePlayerRank(player);
Rank newRank = EnlistedRank.getRank(player);
if (!newRank.equals(oldRank)) {
final String formatString = "%s " + ChatColor.RESET + "has been promoted from %s " + ChatColor.RESET + "to %s" + ChatColor.RESET + "!";
player.getServer().broadcastMessage(String.format(formatString, player.getDisplayName(), oldRank.formatFull(), newRank.formatFull()));
}
} catch (SQLException e) {
Wasteland.getInstance().getLogger().log(Level.SEVERE, "Failed to increment player kills.", e);
}
default:
break;
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerLeave(PlayerQuitEvent event) {
PermissionAttachment attachment = attachments.remove(event.getPlayer().getUniqueId());
event.getPlayer().removeAttachment(attachment);
}
@Override
public void close() {
/*for(Map.Entry<UUID, PermissionAttachment> attachment : attachments.entrySet()) {
Wasteland.getInstance().getServer().getPlayer(attachment.getKey())
.removeAttachment(attachment.getValue());
attachments.remove(attachment.getKey());
}*/
attachments = null;
}
}

View File

@ -0,0 +1,112 @@
package me.jtmar.wasteland.ranks;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
public enum EnlistedRank implements Rank {
FODDER( 0, "Fodder", "Zombie Fodder"),
PVT ( 100, "Pvt", "Private"),
PFC ( 250, "Pfc", "Private First Class"),
LCPL ( 500, "LCpl", "Lance Corporal"),
CPL ( 1_000, "Cpl", "Corporal"),
SGT ( 2_500, "Sgt", "Sergeant"),
SSGT ( 5_000, "SSgt", "Staff Sergeant"),
GYSGT (10_000, "GySgt", "Gunnery Sergeant"),
MSGT (25_000, "MSgt", "Master Sergeant"),
MGYSGT(50_000, "MGySgt", "Master Gunnery Sergeant");
private final int minKills;
private final String abbreviation;
private final String fullName;
private EnlistedRank(int minKills, String abbreviation, String fullName) {
if(minKills < 0)
throw new IllegalArgumentException("Number of kills must not be negative: " + minKills);
this.minKills = minKills;
this.abbreviation = abbreviation;
this.fullName = fullName;
}
public static EnlistedRank getRankFromKills(int kills) {
if (kills < 0)
throw new IllegalArgumentException("Number of kills must not be negative: " + kills);
EnlistedRank result = null;
for(EnlistedRank rank : EnlistedRank.values()) {
if (kills < rank.getMinimumKills()) break;
result = rank;
}
if (result == null) throw new IllegalStateException("Null KillsRank.");
return result;
}
public static EnlistedRank getRank(Player player) {
EnlistedRank result = FODDER;
for (EnlistedRank rank : EnlistedRank.values()) {
if (player.hasPermission(rank.getPermission())) {
result = rank;
}
}
return result;
}
/**
* @param player
* @return Returns null if the player is at the maximum rank.
*/
public static EnlistedRank getNextRank(Player player) {
EnlistedRank nextRank = null;
for (EnlistedRank rank : EnlistedRank.values()) {
if (!player.hasPermission(rank.getPermission())) {
nextRank = rank;
break;
}
}
return nextRank;
}
public int getMinimumKills() {
return this.minKills;
}
@Override
public String getAbbreviation() {
return this.abbreviation;
}
@Override
public String getFullName() {
return this.fullName;
}
@Override
public String toString() {
return this.getAbbreviation();
}
@Override
public ChatColor getColor() {
switch (this) {
case FODDER:
return ChatColor.GRAY;
case PVT:
return ChatColor.WHITE;
case PFC:
return ChatColor.BLUE;
case LCPL:
return ChatColor.GREEN;
case CPL:
return ChatColor.RED;
case SGT:
return ChatColor.LIGHT_PURPLE;
case SSGT:
return ChatColor.YELLOW;
case GYSGT:
return ChatColor.AQUA;
case MSGT:
return ChatColor.DARK_RED;
case MGYSGT:
return ChatColor.DARK_PURPLE;
}
throw new IllegalStateException();
}
}

View File

@ -0,0 +1,86 @@
package me.jtmar.wasteland.ranks;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
public enum OfficerRank implements Rank {
SNDLT ("2ndLt", "Second Lieutenant"),
FSTLT ("1stLt", "First Lieutenant"),
CAPT ("Capt", "Captain"),
MAJ ("Maj", "Major"),
LTCOL ("LtCol", "Lieutenant Colonel"),
COL ("Col", "Colonel"),
BGEN ("BGen", "Brigadier General"),
MAJGEN("MajGen", "Major General"),
LTGEN ("LtGen", "Lieutenant General"),
GEN ("Gen", "General");
private final String abbreviation;
private final String fullName;
private OfficerRank(String abbreviation, String fullName) {
this.abbreviation = abbreviation;
this.fullName = fullName;
}
/**
* @param player
* @return Returns `null` if the player is not staff.
*/
public static OfficerRank getRank(Player player) {
OfficerRank result = null;
for (OfficerRank rank : OfficerRank.values()) {
if (player.hasPermission(rank.getPermission())) {
result = rank;
}
}
return result;
}
@Override
public String getAbbreviation() {
return abbreviation;
}
@Override
public String getFullName() {
return fullName;
}
@Override
public String toString() {
return this.getAbbreviation();
}
@Override
public ChatColor getColor() {
switch (this) {
case SNDLT:
return ChatColor.WHITE;
case FSTLT:
return ChatColor.BLUE;
case CAPT:
return ChatColor.GREEN;
case MAJ:
return ChatColor.RED;
case LTCOL:
return ChatColor.LIGHT_PURPLE;
case COL:
return ChatColor.YELLOW;
case BGEN:
return ChatColor.AQUA;
case MAJGEN:
return ChatColor.DARK_RED;
case LTGEN:
return ChatColor.DARK_PURPLE;
case GEN:
return ChatColor.GOLD;
}
throw new IllegalStateException();
}
@Override
public ChatColor getDecoration() {
return ChatColor.BOLD;
}
}

View File

@ -0,0 +1,51 @@
package me.jtmar.wasteland.ranks;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
public interface Rank {
String getAbbreviation();
String getFullName();
ChatColor getColor();
public default ChatColor getDecoration() {
return null;
}
public default String format() {
ChatColor decoration = getDecoration();
if (decoration != null) {
return getColor() + decoration.toString() + getAbbreviation();
}
return getColor() + getAbbreviation();
}
public default String formatFull() {
ChatColor decoration = getDecoration();
if (decoration != null) {
return getColor() + decoration.toString() + getFullName();
}
return getColor() + getFullName();
}
public default String formatExtended() {
return formatFull() + ChatColor.RESET + " (" + format() + ChatColor.RESET + ")";
}
/**
* @param player
* @return Does the player have at least this permission?
*/
public default boolean hasRank(Player player) {
return player.hasPermission(getPermission());
}
public default String getPermission() {
return "wasteland.rank." + getAbbreviation().toLowerCase();
}
public static Rank getRank(Player player) {
OfficerRank rank = OfficerRank.getRank(player);
if (rank != null) return rank;
return EnlistedRank.getRank(player);
}
}

129
src/plugin.yml Normal file
View File

@ -0,0 +1,129 @@
name: Wasteland
author: jtmar
main: me.jtmar.wasteland.Wasteland
version: 0.0.0
api-version: 1.12
softdepend: [Towny]
commands:
rank:
description: View your rank and how many monsters you have killed.
usage: "Usage: /<command> [player]"
aliases: [zkills, kills]
permission: wasteland.kills
permission-message: You do not have permission to view your own kills.
ranks:
description: List the server ranks.
usage: "Usage: /<command>"
setkills:
description: Set another player's number of kills for debugging.
usage: "Usage: /<command> [player] kills"
permission: wasteland.kills.set
permission-message: You do not have permission to set anyone's kills.
official:
description: Make an official announcement using your staff rank.
usage: "Usage: /<command> [message]"
permission: wasteland.official
permission-message: You are not a staff member.
permissions:
wasteland.kills:
description: Allows you to view your /kills.
default: true
wasteland.kills.other:
description: Allows you to view another player's /kills.
default: op
children:
wasteland.kills: true
wasteland.kills.set:
description: Allows you to set player kills using /setkills.
default: op
children:
wasteland.kills.other: true
# Kill ranks
wasteland.rank.fodder:
default: true
wasteland.rank.pvt:
default: false
children:
wasteland.rank.fodder: true
wasteland.rank.pfc:
default: false
children:
wasteland.rank.pvt: true
wasteland.rank.lcpl:
default: false
children:
wasteland.rank.pfc: true
wasteland.rank.cpl:
default: false
children:
wasteland.rank.lcpl: true
wasteland.rank.sgt:
default: false
children:
wasteland.rank.cpl: true
wasteland.rank.ssgt:
default: false
children:
wasteland.rank.sgt: true
wasteland.rank.gysgt:
default: false
children:
wasteland.rank.ssgt: true
wasteland.rank.msgt:
default: false
children:
wasteland.rank.gysgt: true
wasteland.rank.mgysgt:
default: false
children:
wasteland.rank.msgt: true
# Staff ranks
wasteland.official:
default: ops
wasteland.rank.2ndlt:
default: false
children:
wasteland.official: true
wasteland.rank.1stlt:
default: false
children:
wasteland.rank.2ndlt: true
wasteland.rank.capt:
default: false
children:
wasteland.rank.1stlt: true
wasteland.rank.maj:
default: false
children:
wasteland.rank.capt: true
wasteland.rank.ltcol:
default: false
children:
wasteland.rank.maj: true
wasteland.rank.col:
default: false
children:
wasteland.rank.ltcol: true
wasteland.rank.bgen:
default: false
children:
wasteland.rank.col: true
wasteland.rank.majgen:
default: false
children:
wasteland.rank.bgen: true
wasteland.rank.ltgen:
default: false
children:
wasteland.rank.majgen: true
wasteland.rank.gen:
default: false
children:
wasteland.rank.ltgen: true