Skip to content

Commit

Permalink
Update Resident Modes system. (#7646)
Browse files Browse the repository at this point in the history
* Update Resident Modes system.

Adds the ability to assign a permission node to a mode, and when
present, will require the player to have the permission node to toggle a
node.

This permission node is not required if the mode is part of a player's
default modes set via the permission plugin.

Additionally, the ability to clear a residents modes via command now
requires a permission node.

All together this makes it possible for admins to set modes that players
cannot remove.

Adds a ResidentModesInitializeEvent with which plugins can add Resident
Modes.

Uses a AbstractResidentMode class to allow for different types of Modes
to be made, which makes it possible for Modes to be exclusive of each
other: ie: you can no longer have townclaim and townunclaim modes active
at the same time.

New Permissions:
- towny.command.resident.set.mode.clear
- towny.command.resident.toggle.bedspawn
- towny.command.resident.toggle.bordertitles
- towny.command.resident.toggle.ignoreotherchannels
- towny.command.resident.toggle.infotool
- towny.command.resident.toggle.plotgroup
- towny.command.resident.toggle.townborder
- towny.command.resident.toggle.townunclaim

Additionally, the tab completer for toggling and setting modes should no
longer fall out of date, as ResidentModes will automatically get added
to the ResidentCommand tabcompleters.

* Cleaning up:

Removes the un-needed SetDefaultModes task.
Fix an errant ! in toggleMode that kept permissions from working right.
Unneeded diffs.

* Make townborder mode not a BorderResidentMode, so that it can be active
while other plot border modes are enabled.

* Prevent clearing being able to be done via /res set mode {modename}
  • Loading branch information
LlmDl authored Oct 26, 2024
1 parent 0c175c4 commit 775b1d8
Show file tree
Hide file tree
Showing 18 changed files with 573 additions and 254 deletions.
32 changes: 25 additions & 7 deletions Towny/src/main/java/com/palmergames/bukkit/towny/Towny.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import com.palmergames.bukkit.towny.object.Translation;
import com.palmergames.bukkit.towny.object.WorldCoord;
import com.palmergames.bukkit.towny.object.metadata.MetadataLoader;
import com.palmergames.bukkit.towny.object.resident.mode.ResidentModeHandler;
import com.palmergames.bukkit.towny.permissions.TownyPerms;
import com.palmergames.bukkit.towny.regen.TownyRegenAPI;
import com.palmergames.bukkit.towny.scheduling.TaskScheduler;
Expand Down Expand Up @@ -236,6 +237,9 @@ public void loadFoundation(boolean reload) {
// Initialize the special log4j hook logger.
TownyLogger.initialize();

// Initialize the ResidentModeHandler.
ResidentModeHandler.initialize();

// Clear all objects from the TownyUniverse class.
townyUniverse.clearAllObjects();

Expand Down Expand Up @@ -682,46 +686,60 @@ public void resetCache(Player player) {
getCache(player).resetAndUpdate(WorldCoord.parseWorldCoord(player));
}

/**
* @deprecated since 0.100.4.6, use {@link ResidentModeHandler#toggleModes(Player, String[], boolean)} instead.
* @param player Player to act upon.
* @param modes String[] of mode names to toggle.
* @param notify whether to notify the player of their modes afterwards.
*/
@Deprecated
public void setPlayerMode(Player player, String[] modes, boolean notify) {

if (player == null)
return;

Resident resident = TownyUniverse.getInstance().getResident(player.getName());
if (resident != null)
resident.setModes(modes, notify);
if (resident == null)
return;

ResidentModeHandler.toggleModes(resident, modes, notify, false);
}

/**
* Remove ALL current modes (and set the defaults)
*
* @param player - player, whose modes are to be reset (all removed).
* @deprecated since 0.100.4.6, use {@link ResidentModeHandler#clearModes(Player))} instead.
* @param player Player, whose modes are to be reset (all removed).
*/
@Deprecated
public void removePlayerMode(Player player) {

Resident resident = TownyUniverse.getInstance().getResident(player.getName());
if (resident != null)
resident.clearModes();
ResidentModeHandler.clearModes(resident, false);
}

/**
* Remove ALL current modes.
*
* @deprecated since 0.100.4.6, use {@link ResidentModeHandler#clearModes(Player)} instead.
* @param player - player, whose modes are to be reset (all removed).
*/
@Deprecated
public void removePlayerModes(Player player) {

Resident resident = TownyUniverse.getInstance().getResident(player.getName());
if (resident != null)
resident.resetModes(new String[0], true);
}
ResidentModeHandler.clearModes(resident, false);
}

/**
* Fetch a list of all the players current modes.
*
* @deprecated since 0.100.4.6, use {@link ResidentModeHandler#getModes(Player)} instead.
* @param player - player, whose modes are to be listed, taken.
* @return list of modes
*/
@Deprecated
public List<String> getPlayerMode(Player player) {

return getPlayerMode(player.getName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import com.palmergames.bukkit.towny.TownyUniverse;
import com.palmergames.bukkit.towny.TownyCommandAddonAPI.CommandType;
import com.palmergames.bukkit.towny.confirmations.Confirmation;
import com.palmergames.bukkit.towny.exceptions.NoPermissionException;
import com.palmergames.bukkit.towny.exceptions.TownyException;
import com.palmergames.bukkit.towny.object.Resident;
import com.palmergames.bukkit.towny.object.SpawnType;
Expand All @@ -19,6 +18,7 @@
import com.palmergames.bukkit.towny.object.Translatable;
import com.palmergames.bukkit.towny.object.Translator;
import com.palmergames.bukkit.towny.object.jail.UnJailReason;
import com.palmergames.bukkit.towny.object.resident.mode.ResidentModeHandler;
import com.palmergames.bukkit.towny.permissions.PermissionNodes;
import com.palmergames.bukkit.towny.tasks.CooldownTimerTask;
import com.palmergames.bukkit.towny.tasks.CooldownTimerTask.CooldownType;
Expand Down Expand Up @@ -68,43 +68,6 @@ public class ResidentCommand extends BaseCommand implements CommandExecutor {
"list"
);

private static final List<String> residentToggleTabCompletes = Arrays.asList(
"pvp",
"fire",
"mobs",
"explosion",
"adminbypass",
"bedspawn",
"plotborder",
"constantplotborder",
"townborder",
"ignoreplots",
"ignoreotherchannels",
"bordertitles",
"townclaim",
"townunclaim",
"plotgroup",
"map",
"spy",
"reset",
"clear",
"infotool"
);

private static final List<String> residentModeTabCompletes = Arrays.asList(
"map",
"townclaim",
"townunclaim",
"plotborder",
"constantplotborder",
"townborder",
"ignoreplots",
"ignoreotherchannels",
"reset",
"clear",
"infotool"
);

private static final List<String> residentConsoleTabCompletes = Arrays.asList(
"?",
"help",
Expand All @@ -129,14 +92,17 @@ public class ResidentCommand extends BaseCommand implements CommandExecutor {
"mobs",
"explosion"
);

private static final List<String> residentToggleModes = new ArrayList<>(residentToggleTabCompletes).stream()
.filter(str -> !residentToggleChoices.contains(str))
.collect(Collectors.toList());

private static final List<String> residentToggleModesUnionToggles = Stream.concat(
new ArrayList<>(residentToggleModes).stream(),
BaseCommand.setOnOffCompletes.stream()
private static final List<String> residentToggleModeTabCompletes = ResidentModeHandler.getValidModeNames();

private static final List<String> residentSetModeTabCompletesWithClearAndReset = Stream.concat(
Arrays.asList("reset", "clear").stream(),
new ArrayList<>(residentToggleModeTabCompletes).stream()
).collect(Collectors.toList());

private static final List<String> residentCompleteToggleChoices = Stream.concat(
new ArrayList<>(residentToggleChoices).stream(),
new ArrayList<>(residentToggleModeTabCompletes).stream()
).collect(Collectors.toList());

public ResidentCommand(Towny instance) {
Expand Down Expand Up @@ -191,16 +157,9 @@ public List<String> onTabComplete(CommandSender sender, Command command, String
break;
case "toggle":
if (args.length == 2) {
return NameUtil.filterByStart(TownyCommandAddonAPI.getTabCompletes(CommandType.RESIDENT_TOGGLE, residentToggleTabCompletes), args[1]);
return NameUtil.filterByStart(TownyCommandAddonAPI.getTabCompletes(CommandType.RESIDENT_TOGGLE, residentCompleteToggleChoices), args[1]);
} else if (args.length == 3 && residentToggleChoices.contains(args[1].toLowerCase(Locale.ROOT))) {
return NameUtil.filterByStart(BaseCommand.setOnOffCompletes, args[2]);
} else if (args.length >= 3) {
String prevArg = args[args.length - 2].toLowerCase(Locale.ROOT);
if (residentToggleModes.contains(prevArg)) {
return NameUtil.filterByStart(residentToggleModesUnionToggles, args[args.length - 1]);
} else if (BaseCommand.setOnOffCompletes.contains(prevArg)) {
return NameUtil.filterByStart(residentToggleModes, args[args.length - 1]);
}
}
break;
case "set":
Expand All @@ -212,7 +171,10 @@ public List<String> onTabComplete(CommandSender sender, Command command, String

switch (args[1].toLowerCase(Locale.ROOT)) {
case "mode":
return NameUtil.filterByStart(residentModeTabCompletes, args[args.length - 1]);
if (args.length == 3)
return NameUtil.filterByStart(residentSetModeTabCompletesWithClearAndReset, args[2]);
else
return NameUtil.filterByStart(residentToggleModeTabCompletes, args[args.length - 1]);
case "perm":
return permTabComplete(StringMgmt.remArgs(args, 2));
case "about":
Expand Down Expand Up @@ -430,8 +392,14 @@ private void residentToggle(Player player, String[] newSplit) throws TownyExcept
}

// Check if we're reseting before trying for nodes.
if (newSplit[0].equalsIgnoreCase("reset") || newSplit[0].equalsIgnoreCase("clear")) {
plugin.removePlayerMode(player);
if (newSplit[0].equalsIgnoreCase("clear")) {
checkPermOrThrow(resident.getPlayer(), PermissionNodes.TOWNY_COMMAND_RESIDENT_SET_MODE_CLEAR.getNode());
ResidentModeHandler.clearModes(resident, false);
return;
}

if (newSplit[0].equalsIgnoreCase("reset")) {
ResidentModeHandler.resetModes(resident, false);
return;
}
TownyPermission perm = resident.getPermissions();
Expand All @@ -441,14 +409,7 @@ private void residentToggle(Player player, String[] newSplit) throws TownyExcept
choice = BaseCommand.parseToggleChoice(newSplit[1]);
}

// Special case chat spy
if (StringMgmt.containsIgnoreCase(Arrays.asList(newSplit), "spy")) {
checkPermOrThrow(player, PermissionNodes.TOWNY_CHAT_SPY.getNode());

resident.toggleMode(newSplit, true);
return;

} else if (newSplit[0].equalsIgnoreCase("pvp")) {
if (newSplit[0].equalsIgnoreCase("pvp")) {
checkPermOrThrow(player, PermissionNodes.TOWNY_COMMAND_RESIDENT_TOGGLE_PVP.getNode());

Town town = resident.getTownOrNull();
Expand Down Expand Up @@ -481,8 +442,7 @@ private void residentToggle(Player player, String[] newSplit) throws TownyExcept
TownyCommandAddonAPI.getAddonCommand(CommandType.RESIDENT_TOGGLE, newSplit[0]).execute(player, "resident", newSplit);
return;
} else {

resident.toggleMode(newSplit, true);
ResidentModeHandler.toggleMode(resident, newSplit[0].toLowerCase(Locale.ROOT), true);
return;

}
Expand Down Expand Up @@ -545,7 +505,7 @@ public void residentSet(Player player, String[] split) throws TownyException {
checkPermOrThrow(player, PermissionNodes.TOWNY_COMMAND_RESIDENT_SET_PERM.getNode());
TownCommand.setTownBlockPermissions(player, resident, resident.getPermissions(), StringMgmt.remFirstArg(split), true);
}
case "mode" -> setMode(player, StringMgmt.remFirstArg(split));
case "mode" -> setMode(resident, StringMgmt.remFirstArg(split));
case "about" -> setAbout(player, String.join(" ", StringMgmt.remFirstArg(split)), resident);
default -> {
if (TownyCommandAddonAPI.hasCommand(CommandType.RESIDENT_SET, split[0])) {
Expand All @@ -559,31 +519,26 @@ public void residentSet(Player player, String[] split) throws TownyException {
resident.save();
}

private void setMode(Player player, String[] split) throws NoPermissionException {
checkPermOrThrow(player, PermissionNodes.TOWNY_COMMAND_RESIDENT_SET_MODE.getNode());

private void setMode(Resident resident, String[] split) throws TownyException {
if (split.length == 0) {
HelpMenu.RESIDENT_SET_MODE.send(player);
HelpMenu.RESIDENT_SET_MODE.send(resident.getPlayer());
return;
}

if (split[0].equalsIgnoreCase("clear")) {
plugin.removePlayerModes(player);
checkPermOrThrow(resident.getPlayer(), PermissionNodes.TOWNY_COMMAND_RESIDENT_SET_MODE_CLEAR.getNode());
ResidentModeHandler.clearModes(resident, true);
return;
}

if (split[0].equalsIgnoreCase("reset")) {
plugin.removePlayerMode(player);
ResidentModeHandler.resetModes(resident, true);
return;
}

List<String> list = Arrays.asList(split);
if (list.contains("spy"))
checkPermOrThrow(player, PermissionNodes.TOWNY_CHAT_SPY.getNode());

plugin.setPlayerMode(player, split, true);
ResidentModeHandler.toggleModes(resident, split, true, false);
}

private void setAbout(Player player, String about, Resident resident) throws TownyException {
checkPermOrThrow(player, PermissionNodes.TOWNY_COMMAND_RESIDENT_SET_ABOUT.getNode());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.palmergames.bukkit.towny.object.TownyObject;
import com.palmergames.bukkit.towny.object.TownyWorld;
import com.palmergames.bukkit.towny.object.gui.SelectionGUI;
import com.palmergames.bukkit.towny.object.resident.mode.ResidentModeHandler;
import com.palmergames.bukkit.towny.permissions.PermissionNodes;
import com.palmergames.bukkit.towny.utils.NameUtil;
import com.palmergames.bukkit.towny.utils.ResidentUtil;
Expand Down Expand Up @@ -274,10 +275,7 @@ else if (split.length > 1 && split[1].equalsIgnoreCase("hud"))
}
case "spy": {
catchConsole(sender);
checkPermOrThrow(sender, PermissionNodes.TOWNY_CHAT_SPY.getNode());

Resident resident = getResidentOrThrow(player);
resident.toggleMode(split, true);
ResidentModeHandler.toggleMode(getResidentOrThrow(player), "spy", true);
break;
}
default: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import com.palmergames.bukkit.towny.object.Translation;
import com.palmergames.bukkit.towny.object.WorldCoord;
import com.palmergames.bukkit.towny.object.metadata.DataFieldIO;
import com.palmergames.bukkit.towny.object.resident.mode.ResidentModeHandler;
import com.palmergames.bukkit.towny.object.jail.Jail;
import com.palmergames.bukkit.towny.object.jail.UnJailReason;
import com.palmergames.bukkit.towny.regen.PlotBlockData;
Expand Down Expand Up @@ -429,7 +430,7 @@ public boolean removeTown(@NotNull Town town, @NotNull DeleteTownEvent.Cause cau
town.getAccount().removeAccount();

for (Resident resident : toSave) {
resident.clearModes(false);
ResidentModeHandler.resetModes(resident, false);
resident.removeTown(true);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.palmergames.bukkit.towny.event;

import org.bukkit.Bukkit;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;

import com.palmergames.bukkit.towny.exceptions.TownyException;
import com.palmergames.bukkit.towny.object.resident.mode.AbstractResidentMode;
import com.palmergames.bukkit.towny.object.resident.mode.ResidentModeHandler;

public class ResidentModesInitializeEvent extends Event {
private static final HandlerList handlers = new HandlerList();

public ResidentModesInitializeEvent() {
super(!Bukkit.isPrimaryThread());
}

/**
* Registers a new ResidentMode.
* @param mode The ResidentMode you want to register.
* @throws TownyException - If a mode with this name is already registered.
*/
public void registerMode(@NotNull AbstractResidentMode mode) throws TownyException {
ResidentModeHandler.registerMode(mode);
}

@Override
public @NotNull HandlerList getHandlers() {
return handlers;
}

public static HandlerList getHandlerList() {
return handlers;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ public void onPlayerQuit(PlayerQuitEvent event) {
// Don't set last online if the player was vanished.
if (!event.getPlayer().getMetadata("vanished").stream().anyMatch(MetadataValue::asBoolean))
resident.setLastOnline(System.currentTimeMillis());
resident.clearModes();
resident.clearModes(false);
resident.save();

if (TownyTimerHandler.isTeleportWarmupRunning()) {
Expand Down
Loading

0 comments on commit 775b1d8

Please sign in to comment.