Greatly improve the configuration format and docs, especially chat.

master
James T. Martin 2020-11-19 17:15:03 -08:00
parent 82b2ac79bd
commit 2b4d8c95a2
Signed by: james
GPG Key ID: 4B7F3DA9351E577C
12 changed files with 354 additions and 191 deletions

View File

@ -18,7 +18,7 @@ import me.jamestmartin.wasteland.listeners.RankListener;
import me.jamestmartin.wasteland.spawns.WastelandSpawner;
import me.jamestmartin.wasteland.towny.TownyDependency;
import me.jamestmartin.wasteland.towny.TownyDisabled;
import me.jamestmartin.wasteland.towny.TownyPrefix;
import me.jamestmartin.wasteland.towny.TownAbbreviationProvider;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
@ -29,7 +29,7 @@ public class Wasteland extends JavaPlugin {
private Database database;
private WastelandConfig config;
private RankListener rankListener;
private TownyPrefix townyPrefix;
private TownAbbreviationProvider townyAbbreviationProvider;
private WastelandSpawner spawner;
public static Wasteland getInstance() {
@ -44,8 +44,8 @@ public class Wasteland extends JavaPlugin {
return config;
}
public TownyPrefix getTownyPrefix() {
return townyPrefix;
public TownAbbreviationProvider getTownyAbbreviationProvider() {
return townyAbbreviationProvider;
}
public WastelandSpawner getSpawner() {
@ -63,9 +63,9 @@ public class Wasteland extends JavaPlugin {
private void initializeTowny() {
if (Wasteland.getInstance().getServer().getPluginManager().isPluginEnabled("Towny")) {
this.townyPrefix = new TownyDependency(config.prefixTownTagColor());
this.townyAbbreviationProvider = new TownyDependency();
} else {
this.townyPrefix = new TownyDisabled();
this.townyAbbreviationProvider = new TownyDisabled();
}
}
@ -90,7 +90,7 @@ public class Wasteland extends JavaPlugin {
this.getCommand("rankeligiblemobs").setExecutor(new CommandRankEligibleMobs(config.eligibleMobsName(), config.eligibleMobs()));
this.getCommand("ranks").setExecutor(new CommandRanks());
this.getCommand("setkills").setExecutor(new CommandSetKills());
this.getCommand("official").setExecutor(new CommandOfficial());
this.getCommand("official").setExecutor(new CommandOfficial(config.chat()));
// debug commands
this.getCommand("debugspawn").setExecutor(new CommandDebugSpawn());
@ -99,9 +99,8 @@ public class Wasteland extends JavaPlugin {
private void registerListeners() {
PluginManager manager = this.getServer().getPluginManager();
rankListener = new RankListener(config.eligibleMobs());
manager.registerEvents(rankListener, this);
manager.registerEvents(new ChatListener(), this);
manager.registerEvents(new RankListener(config.eligibleMobs()), this);
manager.registerEvents(new ChatListener(config.chat()), this);
}
@Override

View File

@ -1,17 +1,20 @@
package me.jamestmartin.wasteland.commands;
import java.util.Optional;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import me.jamestmartin.wasteland.Wasteland;
import me.jamestmartin.wasteland.config.ChatConfig;
import me.jamestmartin.wasteland.ranks.Rank;
public class CommandOfficial implements CommandExecutor {
private final ChatConfig config;
public CommandOfficial(ChatConfig config) {
this.config = config;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (args.length < 1) {
@ -19,29 +22,27 @@ public class CommandOfficial implements CommandExecutor {
return false;
}
String senderFormat;
final String message = String.join(" ", args);
final String format;
if (sender instanceof Player) {
Player player = (Player) sender;
Optional<Rank> rank = Rank.getOfficerRank(player);
if (!rank.isPresent()) {
final Player player = (Player) sender;
if (!Rank.getOfficerRank(player).isPresent()) {
sender.sendMessage("You are not a staff member.");
return true;
}
String rankFormat = rank.get().formatAbbreviated() + ChatColor.RESET;
if (Wasteland.getInstance().getSettings().bracketChatRank()) {
rankFormat = ChatColor.RESET + "[" + rankFormat + "]";
}
senderFormat = rankFormat + " " + player.getDisplayName();
format = config.getOfficialFormat(player).replaceFirst("%s", player.getDisplayName());
} else {
Optional<Rank> consoleRank = Wasteland.getInstance().getSettings().consoleRank();
if (!consoleRank.isPresent()) {
if (!Rank.getConsoleRank().isPresent()) {
sender.sendMessage("No console rank is configured to send messages with!");
return true;
}
senderFormat = consoleRank.get().formatFull();
format = config.getConsoleFormat();
}
sender.getServer().broadcastMessage(senderFormat + ChatColor.RESET + ": " + String.join(" ", args));
sender.getServer().broadcastMessage(format.replaceFirst("%s", message));
return true;
}
}

View File

@ -35,9 +35,6 @@ public class CommandRanks implements CommandExecutor {
sender.sendMessage("* " + makeElement(rank));
}
if (config.consoleRank().isPresent()) {
sender.sendMessage("* " + makeElement(config.consoleRank().get()));
}
return true;
}
}

View File

@ -0,0 +1,89 @@
package me.jamestmartin.wasteland.config;
import java.util.Optional;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import me.jamestmartin.wasteland.Wasteland;
import me.jamestmartin.wasteland.ranks.Rank;
import me.jamestmartin.wasteland.ranks.RankType;
public class ChatConfig {
private final String chatFormat;
private final String officerChatFormat;
private final String officialFormat;
private final String consoleFormat;
private final String rankPrefixFormat;
private final String townyPrefixFormat;
public ChatConfig(ConfigurationSection c) {
ConfigurationSection formats = c.getConfigurationSection("formats");
this.chatFormat = formats.getString("chat");
this.officerChatFormat = formats.getString("officer");
this.officialFormat = formats.getString("official");
this.consoleFormat = formats.getString("console");
ConfigurationSection prefixes = c.getConfigurationSection("prefixes");
this.rankPrefixFormat = prefixes.getString("rank");
this.townyPrefixFormat = prefixes.getString("towny");
}
public String formatRankPrefix(Player player, Rank rank) {
return rankPrefixFormat.replace("{abbr}", rank.formatAbbreviated());
}
public String formatPlayerRankPrefix(Player player, RankType rankType) {
Optional<Rank> rank = Rank.getRank(rankType, player);
if (rank.isEmpty()) {
return "";
}
return formatRankPrefix(player, rank.get());
}
public String formatPlayerTownPrefix(Player player) {
Optional<String> townTag = Wasteland.getInstance().getTownyAbbreviationProvider().getTownAbbreviation(player);
if (townTag.isEmpty()) {
return "";
}
return townyPrefixFormat.replace("{tag}", townTag.get());
}
private String substituteRankPrefixes(String format, Player player) {
// This is an inefficient way to do it, but chat doesn't need optimization.
String enlistedRankPrefix = formatPlayerRankPrefix(player, RankType.ENLISTED);
String officerRankPrefix = formatPlayerRankPrefix(player, RankType.OFFICER);
String highestRankPrefix = formatPlayerRankPrefix(player, RankType.HIGHEST);
return format
.replace("{enlisted}", enlistedRankPrefix)
.replace("{officer}", officerRankPrefix)
.replace("{rank}", highestRankPrefix);
}
private String substitutePlayerTownPrefix(String format, Player player) {
return format.replace("{towny}", formatPlayerTownPrefix(player));
}
private String substitutePlayerPrefixes(String format, Player player) {
return substitutePlayerTownPrefix(substituteRankPrefixes(format, player), player);
}
public String getPlayerChatFormat(Player player) {
return substitutePlayerPrefixes(chatFormat, player);
}
public String getOfficerChatFormat(Player player) {
return substitutePlayerPrefixes(officerChatFormat, player);
}
public String getOfficialFormat(Player player) {
return substitutePlayerPrefixes(officialFormat, player);
}
public String getConsoleFormat() {
return consoleFormat
.replace("{console}", Rank.getConsoleRank().get().formatAbbreviated())
.replace("{console_full}", Rank.getConsoleRank().get().formatFull());
}
}

View File

@ -20,10 +20,8 @@ import me.jamestmartin.wasteland.spawns.MonsterType;
public class WastelandConfig {
private final String databaseFile;
private final boolean prefixTownTag;
private final Optional<ChatColor> prefixTownTagColor;
private final boolean preferOfficerRank, bracketChatRank, nameUsesRankColor;
private final ChatConfig chat;
private final Collection<EnlistedRank> enlistedRanks;
private final Collection<Rank> officerRanks;
@ -41,60 +39,67 @@ public class WastelandConfig {
public WastelandConfig(ConfigurationSection c) {
this.databaseFile = c.getString("databaseFile", "wasteland.sqlite3");
this.prefixTownTag = c.getBoolean("prefixTownTag", true);
this.prefixTownTagColor = readColor(c, "prefixTownTagColor");
this.preferOfficerRank = c.getBoolean("preferOfficerRank", false);
this.bracketChatRank = c.getBoolean("bracketChatRank", true);
this.nameUsesRankColor = c.getBoolean("nameUsesRankColor", false);
ConfigurationSection ers = c.getConfigurationSection("enlistedRanks");
this.chat = new ChatConfig(c.getConfigurationSection("chat"));
ConfigurationSection enlistedSection = c.getConfigurationSection("enlisted");
ArrayList<EnlistedRank> enlistedRanks = new ArrayList<>();
this.enlistedRanks = enlistedRanks;
if (ers != null) {
Optional<ChatColor> defaultDecoration = readColor(c, "enlistedRankDefaultDecoration");
this.eligibleMobs = new HashSet<>();
if (enlistedSection != null) {
Optional<ChatColor> defaultDecoration = readColor(enlistedSection, "decoration");
Optional<String> defaultDescription =
Optional.ofNullable(c.getString("enlistedRankDefaultDescription"));
Optional.ofNullable(enlistedSection.getString("description"));
Set<String> rankIDs = ers.getKeys(false);
ConfigurationSection enlistedRanksSection = enlistedSection.getConfigurationSection("ranks");
Set<String> rankIDs = enlistedRanksSection.getKeys(false);
enlistedRanks.ensureCapacity(rankIDs.size());
for (String id : rankIDs) {
EnlistedRank result = new EnlistedRank(defaultDescription, defaultDecoration,
ers.getConfigurationSection(id));
enlistedRanksSection.getConfigurationSection(id));
enlistedRanks.add(result);
}
enlistedRanks.sort(new EnlistedRank.EnlistedRankComparator(enlistedRanks));
ConfigurationSection promotionSection = enlistedSection.getConfigurationSection("promotions");
ConfigurationSection eligibleSection = promotionSection.getConfigurationSection("eligible");
List<String> eligibleMobTypes = eligibleSection.getStringList("entities");
for (String mobType : eligibleMobTypes) {
this.eligibleMobs.addAll(Arrays.asList(EntityTypes.lookupEntityType(mobType)));
}
this.eligibleMobsName = eligibleSection.getString("name");
} else {
this.eligibleMobsName = "nothing";
}
ConfigurationSection ors = c.getConfigurationSection("officerRanks");
ConfigurationSection officerSection = c.getConfigurationSection("officer");
ArrayList<Rank> officerRanks = new ArrayList<>();
this.officerRanks = officerRanks;
if (ors != null) {
Optional<ChatColor> defaultDecoration = readColor(c, "officerRankDefaultDecoration");
if (officerSection != null) {
Optional<ChatColor> defaultDecoration = readColor(officerSection, "decoration");
Set<String> rankIDs = ors.getKeys(false);
ConfigurationSection officerRanksSection = officerSection.getConfigurationSection("ranks");
Set<String> rankIDs = officerRanksSection.getKeys(false);
officerRanks.ensureCapacity(rankIDs.size());
for (String id : rankIDs) {
ConfigurationSection rank = ors.getConfigurationSection(id);
ConfigurationSection rank = officerRanksSection.getConfigurationSection(id);
Rank result = new Rank(Optional.empty(), defaultDecoration, rank);
officerRanks.add(result);
}
officerRanks.sort(new Rank.RankComparator(officerRanks));
}
ConfigurationSection crs = c.getConfigurationSection("consoleRank");
if (crs == null) {
this.consoleRank = Optional.empty();
String consoleRankID = officerSection.getString("console", null);
if (consoleRankID == null) {
this.consoleRank = Optional.of(officerRanks.get(officerRanks.size() - 1));
} else {
this.consoleRank = Optional.of(officerRanks.stream().filter(rank -> rank.getId().equals(consoleRankID)).findFirst().get());
}
} else {
this.consoleRank = Optional.of(new Rank(Optional.empty(), Optional.empty(), crs));
this.consoleRank = Optional.empty();
}
List<String> eligibleMobTypes = c.getStringList("eligibleMobs");
this.eligibleMobs = new HashSet<>();
for (String mobType : eligibleMobTypes) {
this.eligibleMobs.addAll(Arrays.asList(EntityTypes.lookupEntityType(mobType)));
}
this.eligibleMobsName = c.getString("eligibleMobsName");
ConfigurationSection mss = c.getConfigurationSection("spawns");
this.spawns = new HashMap<>();
@ -109,12 +114,7 @@ public class WastelandConfig {
public String databaseFile() { return this.databaseFile; }
public boolean prefixTownTag() { return this.prefixTownTag; }
public Optional<ChatColor> prefixTownTagColor() { return this.prefixTownTagColor; }
public boolean preferOfficerRank() { return this.preferOfficerRank; }
public boolean bracketChatRank() { return this.bracketChatRank; }
public boolean nameUsesRankColor() { return this.nameUsesRankColor; }
public ChatConfig chat() { return this.chat; }
public Collection<EnlistedRank> enlistedRanks() { return this.enlistedRanks; }
public Collection<Rank> officerRanks() { return this.officerRanks; }

View File

@ -1,42 +1,26 @@
package me.jamestmartin.wasteland.listeners;
import java.util.Optional;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import me.jamestmartin.wasteland.Wasteland;
import me.jamestmartin.wasteland.ranks.EnlistedRank;
import me.jamestmartin.wasteland.ranks.Rank;
import me.jamestmartin.wasteland.config.ChatConfig;
public class ChatListener implements Listener {
private final ChatConfig config;
public ChatListener(final ChatConfig config) {
this.config = config;
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerChat(AsyncPlayerChatEvent event) {
Player player = event.getPlayer();
Optional<String> townyPrefixQ = Wasteland.getInstance().getTownyPrefix().getPrefix(player);
String townyPrefix = townyPrefixQ.map(x -> x + " ").orElse("");
Optional<Rank> rank;
if (Wasteland.getInstance().getSettings().preferOfficerRank()
|| player.hasPermission("wasteland.chat.officer")) {
rank = Rank.getHighestRank(player);
public void onPlayerChat(final AsyncPlayerChatEvent event) {
final Player player = event.getPlayer();
if (player.hasPermission("wasteland.chat.officer")) {
event.setFormat(config.getOfficerChatFormat(player));
} else {
rank = EnlistedRank.getEnlistedRank(player).map(x -> (Rank) x);
event.setFormat(config.getPlayerChatFormat(player));
}
String rankPrefix;
if (rank.isPresent()) {
rankPrefix = rank.get().formatAbbreviated() + ChatColor.RESET;
if (Wasteland.getInstance().getSettings().bracketChatRank())
rankPrefix = ChatColor.RESET + "[" + rankPrefix + "]";
rankPrefix = rankPrefix + " ";
} else {
rankPrefix = "";
}
event.setFormat(townyPrefix + rankPrefix + "%s" + ChatColor.RESET + ": %s");
}
}

View File

@ -115,6 +115,24 @@ public class Rank {
return EnlistedRank.getEnlistedRank(player).map(x -> (Rank) x);
}
public static Optional<Rank> getConsoleRank() {
return Wasteland.getInstance().getSettings().consoleRank();
}
public static Optional<Rank> getRank(RankType type, Player player) {
switch (type) {
case CONSOLE:
return getConsoleRank();
case ENLISTED:
return EnlistedRank.getEnlistedRank(player).map(x -> x);
case HIGHEST:
return getHighestRank(player);
case OFFICER:
return getOfficerRank(player);
}
throw new IllegalStateException("Unknown rank type.");
}
public static class RankComparator implements Comparator<Rank> {
private final Collection<Rank> ranks;

View File

@ -0,0 +1,9 @@
package me.jamestmartin.wasteland.ranks;
public enum RankType {
ENLISTED,
OFFICER,
CONSOLE,
/** Either enlisted, or officer if the player is one. */
HIGHEST;
}

View File

@ -4,6 +4,6 @@ import java.util.Optional;
import org.bukkit.entity.Player;
public interface TownyPrefix {
public Optional<String> getPrefix(Player player);
public interface TownAbbreviationProvider {
public Optional<String> getTownAbbreviation(Player player);
}

View File

@ -2,35 +2,20 @@ package me.jamestmartin.wasteland.towny;
import java.util.Optional;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import com.palmergames.bukkit.towny.TownyAPI;
import com.palmergames.bukkit.towny.exceptions.NotRegisteredException;
import com.palmergames.bukkit.towny.object.Resident;
public class TownyDependency implements TownyPrefix {
private final String townTagColor;
public TownyDependency(Optional<ChatColor> townTagColor) {
this.townTagColor = townTagColor.map(ChatColor::toString).orElse("");
}
public TownyDependency() {
this(Optional.empty());
}
public TownyDependency(ChatColor townTagColor) {
this(Optional.of(townTagColor));
}
public class TownyDependency implements TownAbbreviationProvider {
@Override
public Optional<String> getPrefix(Player player) {
public Optional<String> getTownAbbreviation(Player player) {
try {
Resident resident = TownyAPI.getInstance().getDataSource().getResident(player.getName());
String tag = resident.getTown().getTag();
if (tag != null && !tag.equals("")) {
return Optional.of(ChatColor.RESET + "[" + townTagColor + tag + ChatColor.RESET + "]");
return Optional.of(tag);
}
} catch (NotRegisteredException e) {
}

View File

@ -4,9 +4,9 @@ import java.util.Optional;
import org.bukkit.entity.Player;
public class TownyDisabled implements TownyPrefix {
public class TownyDisabled implements TownAbbreviationProvider {
@Override
public Optional<String> getPrefix(Player player) {
public Optional<String> getTownAbbreviation(Player player) {
return Optional.empty();
}
}

View File

@ -1,34 +1,42 @@
databaseFile: wasteland.sqlite3
# Colors and decoration names must be written in ALL_CAPS_USING_UNDERLINES.
# For a list of valid formatting codes, see https://minecraft.gamepedia.com/Formatting_codes#Color_codes
# If `true`, chat will be prefixed with the player's Towny town tag if the town's tag is set.
# These settings have no effect if Towny is not enabled.
prefixTownTag: true
prefixTownTagColor: BLUE
# If `true`, the officer rank will also be used in regular chat, not just `/official` messages.
# Even if false, this can still be set per-player using `wasteland.chat.officer`.
preferOfficerRank: false
# If `true`, chat shows as `[Pvt] HuskFodder` instead of `Pvt HuskFodder`.
bracketChatRank: true
chat:
# `{enlisted}`, `{officer}`, `{console}`, and `{rank}` indicate the rank prefix
# using the highest enlisted, officer, console, and overall ranks respectively.
#
# `{towny}` indicates the town prefix if the player is in a town and the town tag is set.
#
# The first `%s` is the player's name and the second is the message itself.
formats:
# The format used for chat.
chat: "{towny}{enlisted}%s: %s"
# The format used for chat player with the `wasteland.chat.officer` permission.
officer: "{towny}{officer}%s: %s"
# The format used for `/official` when used by a player.
official: "{officer}%s: %s"
# The format used for `/official` when used by the server.
console: "{console_full}§r: %s"
prefixes:
# `{abbr}` is the rank's abbreviation, with formatting
rank: "§r[{abbr}§r] "
# `{tag}` is the town's tag
towny: "§r[§9{tag}§r] "
#
# enlistedRanksDefaultDecoration: <ColorCode> # optional
# enlistedRankDefaultDescription: <description> # optional, may reference the rank's number of {kills}.
# enlistedRanks:
# <rankID>: # the rank permission will be `wasteland.rank.<rankID>`.
# enlisted:
# decoration: <ColorCode> # optional
# description: <description> # optional, may reference the rank's number of `{kills}`.
# ranks:
# <rankID>: # the rank permission will be `wasteland.rank.<rankID>`.
# name: <full rank name> # optional, defaults to the rank ID
# abbreviation: <rank abbreviation> # optional, defaults to the name
# description: <rank description> # optional, defaults to `enlistedRankDefaultDescription`.
# succeeds: <rankID> # optional, the prior rank
# description: <rank description> # optional, defaults to `enlisted.description`.
# succeeds: <rankID> # optional, the prior rank (defaults to nothing)
# preferred: <bool> # optional, used to disambiguate multiple ranks
# # which both succeed the same rank.
# # Defaults to `true`.
# color: <ColorCode> # optional
# decoration: <ColorCode> # optional, defaults to `enlistedRanksDefaultDecoration`
# decoration: <ColorCode> # optional, defaults to `enlisted.decoration`
# kills: <0+> # optional, but the rank won't be used without it
# ...
#
@ -41,10 +49,33 @@ bracketChatRank: true
# You may wish to remove the unused alternative ranks.
enlistedRankDefaultDescription: "{kills} kills."
enlistedRanks:
# A default rank which is not part of the marines.
fodder:
enlisted:
description: "{kills} kills."
promotions:
# The eligible monsters are the entity types which, if killed, will count towards your next promotion.
# Each value must be a valid Bukkit EntityType (e.g. `WITHER_SKELETON` or `ENDERMAN`),
# or one of these built-in entitiy collections:
# * `bosses`: The ender dragon or wither.
# * `hostiles`: Mobs which will attack you on sight, including the bosses.
# * `neutrals`: Mobs which will only attack you under certain conditions,
# e.g. wolves attack you if attacked, enderman attack you if looked at, spiders attack in the dark.
# * `monsters`: Mobs which are eligiable for the "Monster Hunter" achievement,
# which is to say all of the hostile mobs, endermen, spiders, and zombified piglins.
# * `zombies`: All zombies, including zombified piglins.
# * `spiders`: All spiders: regular spiders and cave spiders.
#
# The wiki lists which mobs are bosses, hostile, or neutral: https://minecraft.gamepedia.com/Mob#List_of_mobs
# Monsters are defined as the mobs which are eligible for the Monster Hunter achievement
# (all hostile mobs plus endermen, spiders, and zombified piglins).
#
# This defaults to monsters.
eligible:
# You must give a name for messages to the player, for e.g. "You must kill X more ??? before your next promotion."
name: monsters
entities: [bosses, monsters]
ranks:
# A default rank which is not part of the marines.
fodder:
# `name` is optional and defaults to the `title`.
name: Zombie Fodder
# `abbreviation` is optional and defaults to the rank ID.
@ -52,50 +83,50 @@ enlistedRanks:
description: This person probably won't survive long.
color: GRAY
kills: 0
pvt:
pvt:
name: Private
abbreviation: Pvt
succeeds: fodder
color: WHITE
kills: 100
pfc:
pfc:
name: Private First Class
abbreviation: PFC
succeeds: pvt
color: BLUE
kills: 250
lcpl:
lcpl:
name: Lieutenant Corporal
abbreviation: LCpl
succeeds: pfc
color: GREEN
kills: 500
cpl:
cpl:
name: Corporal
abbreviation: Cpl
succeeds: lcpl
color: RED
kills: 1000
sgt:
sgt:
name: Sergeant
abbreviation: Sgt
succeeds: cpl
color: LIGHT_PURPLE
kills: 2500
ssgt:
ssgt:
name: Staff Sergeant
abbreviation: SSgt
succeeds: sgt
color: YELLOW
kills: 5000
gysgt:
gysgt:
name: Gunnery Sergeant
abbreviation: GySgt
succeeds: ssgt
color: AQUA
kills: 10000
# Alternative DARK_RED rank, currently unused.
fstsgt:
# Alternative DARK_RED rank, currently unused.
fstsgt:
name: First Sergeant
abbreviation: 1stSgt
description: Unused alternative rank for {kills} kills.
@ -103,21 +134,21 @@ enlistedRanks:
preferred: false
color: DARK_RED
kills: 25000
msgt:
msgt:
name: Master Sergeant
abbreviation: MSgt
succeeds: gysgt
color: DARK_RED
kills: 25000
# Alternative DARK_PURPLE rank, currently unused.
sgtmaj:
# Alternative DARK_PURPLE rank, currently unused.
sgtmaj:
name: Sergeant Major
abbreviation: SgtMaj
description: Unused alternative rank for {kills} kills.
succeeds: fstsgt
color: DARK_PURPLE
kills: 50000
mgysgt:
mgysgt:
name: Master Gunnery Sergeant
abbreviation: MGySgt
description: A survivor of the wasteland, with over {kills} kills.
@ -125,8 +156,8 @@ enlistedRanks:
color: DARK_PURPLE
kills: 50000
# Officer ranks cannot be obtained by killing zombies.
# They must manually be set using permissions.
# Officer ranks cannot be obtained by killing zombies;
# they must manually be set using permissions.
# Setting permissions for any rank also gives permissions for all previous ranks.
# You may also optionally specify a rank `description`,
# which will be listed to describe what a staff member of that rank does,
@ -134,79 +165,129 @@ enlistedRanks:
# It may be best to remove ranks that you are not using to avoid cluttering the ranks list.
officerRankDefaultDecoration: BOLD
officerRanks:
sndlt:
officer:
decoration: BOLD
# The rank used by the console when it makes an official message.
# Defaults to whatever the last rank listed is.
console: gas
ranks:
sndlt:
name: Second Lieutenant
abbreviation: 2ndLt
color: WHITE
fstlt:
fstlt:
name: First Lieutenant
abbreviation: 1stLt
succeeds: sndlt
color: BLUE
capt:
capt:
name: Captain
abbreviation: Capt
succeeds: fstlt
color: GREEN
maj:
maj:
name: Major
abbreviation: Maj
succeeds: capt
color: RED
ltcol:
ltcol:
name: Lieutenant Colonel
abbreviation: LtCol
succeeds: maj
color: LIGHT_PURPLE
col:
col:
name: Colonel
abbreviation: Col
succeeds: ltcol
color: YELLOW
bgen:
bgen:
name: Brigadier General
abbreviation: BGen
succeeds: col
color: AQUA
majgen:
majgen:
name: Major General
abbreviation: MajGen
succeeds: bgen
color: DARK_RED
ltgen:
ltgen:
name: Lieutenant General
abbreviation: LtGen
succeeds: majgen
color: DARK_PURPLE
gen:
gen:
name: General
abbreviation: Gen
succeeds: ltgen
color: GOLD
gas:
name: General of the Armies
abbreviation: GAS
description: The server console.
color: GOLD
# The rank used by the console when it makes an official message.
consoleRank:
name: General of the Armies # mandatory
abbreviation: GAS # Currently unused
description: The server console.
color: GOLD
decoration: BOLD
# The entity types which, if killed, will count towards your enlisted rank.
# Each value must be a valid Bukkit EntityType (e.g. `WITHER_SKELETON` or `ENDERMAN`),
# or one of my built-in entity collections (`bosses`, hostiles`, `monsters`, `neutrals`, `zombies`, `spiders`).
# Beware that `hostiles` does not include endermen, spiders, or zombified piglins,
# although they are included in `monsters`.
#
# The wiki lists which mobs are bosses, hostile, or neutral: https://minecraft.gamepedia.com/Mob#List_of_mobs
# Monsters are defined as the mobs which are eligible for the Monster Hunter achievement
# (all hostile mobs plus endermen, spiders, and zombified piglins).
eligibleMobs: [monsters]
eligibleMobsName: monsters
# spawns:
# # Valid monster types are are CREEPER, SKELETON, SPIDER, and ZOMBIE.
# # The numbers generated by this section's configuration are multiplied together
# # to determine the probability of a monster spawning at a specific location,
# # and the amount by which a monster succeeds its probability check
# # count towards its spawn quality for the purpose of applying buffs.
# <MonsterType>:
# # The light levels in which a monster can spawn.
# # The probability of a monster spawning is determined by how much light is on the desired spawn block,
# # reaching a probability of 0.0 when the light reaches the specified maximum.
# light:
# maximum: <integer> # defaults to 9
#
# # A block's light level is the maximum of the block light and the sunlight and moonlight added together.
# # The weights affect how much each kind of light contributes toward the overall light level:
# # Before calculating the overall light level, each light source is multiplied by its respective weight.
# # The sun and block light level weights default to 1; the moon light level weight defaults to 0.
# #
# # A negative weight means that light from this source will *increase* the probability of a monster spawning
# # in a given light, including in brighter areas (so if you had `moon: -1.0`, on a full moon,
# # monsters would be able to spawn in block light levels up to `9 + 6`, whereas with `1.0` it would be `9 - 6`).
# #
# # Unlike in Vanilla, the sunlight level doesn't go directly between 15 and 0 at dawn and dusk.
# # There is a *gradual transition* between sunlight and moonlight for the duration of dawn and dusk,
# # and in vanilla, moonlight doesn't exist at all so that's a new thing too.
# #
# # Finally, sky light levels aren't calculated in quite the same way as block light levels.
# # Rather than diminishing one light level per block, the light diminishes by `1/15th` of its maximum per block.
# # This means that moonlight shines dramatically deeper into caves and buildings, albeit only at low intensity.
# #
# # Moonlight by phase of moon:
# # * FULL: 6
# # * WANING_GIBBOUS: 5
# # * THIRD_QUARTER: 3
# # * NEW: 0
# # * WAXING_CRESCENT: 2
# # * FIRST_QUARTER: 3
# # * WAXING_GIBBOUS: 4
# #
# # There isn't any particular reason for the moon phase light to be asymmetrical, and the numbers are arbitrary;
# # I made them asymmetrical to make things interesting, and the numbers were chosen just because they felt right.
# # Perhaps I will make the moonlight by phase configurable in the future.
# #
# weights:
# sun: <float>
# moon: <float>
# block: <float>
#
# # The y-levels within which a monster can spawn.
# # Like with light, the probability of a monster spawning is diminished the farther it is from the center of the region.
# height:
# minimum: <integer> # Defaults to 0
# maximum: <integer> # Defaults to the largest possible integer. `-1` will *not* work here!
#
# # The probability of spawning will be multiplied by the modifier specified here depending on what moon phase it is.
# # The moon phase multiplier *only* has effect between dusk and dawn, although it *does* have effect underground.
# phases:
# <MOON_PHASE>: <float>
# ...
# ...
#
spawns:
CREEPER: