Placeholders for speech bubbles, /npc command errormsg

This commit is contained in:
fullwall 2022-08-21 16:15:40 +08:00
parent 9592de5716
commit 30b2f5a8e2
6 changed files with 35 additions and 15 deletions

View File

@ -129,6 +129,7 @@ public class Settings {
NEW_PATHFINDER_CHECK_BOUNDING_BOXES("npc.pathfinding.new-finder.check-bounding-boxes", false), NEW_PATHFINDER_CHECK_BOUNDING_BOXES("npc.pathfinding.new-finder.check-bounding-boxes", false),
NEW_PATHFINDER_OPENS_DOORS("npc.pathfinding.new-finder.open-doors", false), NEW_PATHFINDER_OPENS_DOORS("npc.pathfinding.new-finder.open-doors", false),
NPC_ATTACK_DISTANCE("npc.pathfinding.attack-range", 1.75 * 1.75), NPC_ATTACK_DISTANCE("npc.pathfinding.attack-range", 1.75 * 1.75),
NPC_COMMAND_GLOBAL_COMMAND_DELAY("npc.commands.global-delay-seconds", 0),
NPC_COMMAND_MAXIMUM_TIMES_USED_MESSAGE("npc.commands.error-messages.maximum-times-used", NPC_COMMAND_MAXIMUM_TIMES_USED_MESSAGE("npc.commands.error-messages.maximum-times-used",
"You have reached the maximum number of uses ({0})."), "You have reached the maximum number of uses ({0})."),
NPC_COMMAND_MISSING_ITEM_MESSAGE("npc.commands.error-messages.missing-item", "Missing {1} {0}"), NPC_COMMAND_MISSING_ITEM_MESSAGE("npc.commands.error-messages.missing-item", "Missing {1} {0}"),

View File

@ -98,6 +98,7 @@ import net.citizensnpcs.trait.Anchors;
import net.citizensnpcs.trait.ArmorStandTrait; import net.citizensnpcs.trait.ArmorStandTrait;
import net.citizensnpcs.trait.ClickRedirectTrait; import net.citizensnpcs.trait.ClickRedirectTrait;
import net.citizensnpcs.trait.CommandTrait; import net.citizensnpcs.trait.CommandTrait;
import net.citizensnpcs.trait.CommandTrait.CommandTraitMessages;
import net.citizensnpcs.trait.CommandTrait.ExecutionMode; import net.citizensnpcs.trait.CommandTrait.ExecutionMode;
import net.citizensnpcs.trait.CommandTrait.ItemRequirementGUI; import net.citizensnpcs.trait.CommandTrait.ItemRequirementGUI;
import net.citizensnpcs.trait.CommandTrait.NPCCommandBuilder; import net.citizensnpcs.trait.CommandTrait.NPCCommandBuilder;
@ -375,7 +376,7 @@ public class NPCCommands {
@Command( @Command(
aliases = { "npc" }, aliases = { "npc" },
usage = "command|cmd (add [command] | remove [id] | permissions [permissions] | sequential | random | (exp|item)cost [cost]) (-l[eft]/-r[ight]) (-p[layer] -o[p]), --cooldown --gcooldown [seconds] --delay [ticks] --permissions [perms] --n [max # of uses]", usage = "command|cmd (add [command] | remove [id] | permissions [permissions] | sequential | random | errormsg [type] [msg] | (exp|item)cost [cost]) (-l[eft]/-r[ight]) (-p[layer] -o[p]), --cooldown --gcooldown [seconds] --delay [ticks] --permissions [perms] --n [max # of uses]",
desc = "Controls commands which will be run when clicking on an NPC", desc = "Controls commands which will be run when clicking on an NPC",
help = Messages.NPC_COMMAND_HELP, help = Messages.NPC_COMMAND_HELP,
modifiers = { "command", "cmd" }, modifiers = { "command", "cmd" },
@ -444,6 +445,12 @@ public class NPCCommands {
if (!(sender instanceof Player)) if (!(sender instanceof Player))
throw new CommandException(CommandMessages.MUST_BE_INGAME); throw new CommandException(CommandMessages.MUST_BE_INGAME);
InventoryMenu.createSelfRegistered(new ItemRequirementGUI(commands)).present(((Player) sender)); InventoryMenu.createSelfRegistered(new ItemRequirementGUI(commands)).present(((Player) sender));
} else if (args.getString(1).equalsIgnoreCase("errormsg")) {
CommandTraitMessages which = Util.matchEnum(CommandTraitMessages.values(), args.getString(2));
if (which == null)
throw new CommandException(Messages.NPC_COMMAND_INVALID_ERROR_MESSAGE,
Util.listValuesPretty(CommandTraitMessages.values()));
commands.setCustomErrorMessage(which, args.getString(3));
} else { } else {
throw new CommandUsageException(); throw new CommandUsageException();
} }

View File

@ -61,10 +61,10 @@ public class CommandTrait extends Trait {
@Persist(keyType = Integer.class) @Persist(keyType = Integer.class)
@DelegatePersistence(NPCCommandPersister.class) @DelegatePersistence(NPCCommandPersister.class)
private final Map<Integer, NPCCommand> commands = Maps.newHashMap(); private final Map<Integer, NPCCommand> commands = Maps.newHashMap();
@Persist(keyType = UUID.class, reify = true)
private final Map<UUID, PlayerNPCCommand> cooldowns = Maps.newHashMap();
@Persist @Persist
private double cost = -1; private double cost = -1;
@Persist
private final Map<CommandTraitMessages, String> customErrorMessages = Maps.newEnumMap(CommandTraitMessages.class);
private final Map<String, Set<CommandTraitMessages>> executionErrors = Maps.newHashMap(); private final Map<String, Set<CommandTraitMessages>> executionErrors = Maps.newHashMap();
@Persist @Persist
private ExecutionMode executionMode = ExecutionMode.LINEAR; private ExecutionMode executionMode = ExecutionMode.LINEAR;
@ -76,6 +76,8 @@ public class CommandTrait extends Trait {
private boolean hideErrorMessages; private boolean hideErrorMessages;
@Persist @Persist
private final List<ItemStack> itemRequirements = Lists.newArrayList(); private final List<ItemStack> itemRequirements = Lists.newArrayList();
@Persist(keyType = UUID.class, reify = true, value = "cooldowns")
private final Map<UUID, PlayerNPCCommand> playerTracking = Maps.newHashMap();
@Persist @Persist
private final List<String> temporaryPermissions = Lists.newArrayList(); private final List<String> temporaryPermissions = Lists.newArrayList();
@ -231,7 +233,7 @@ public class CommandTrait extends Trait {
} }
for (NPCCommand command : commandList) { for (NPCCommand command : commandList) {
if (executionMode == ExecutionMode.SEQUENTIAL) { if (executionMode == ExecutionMode.SEQUENTIAL) {
PlayerNPCCommand info = cooldowns.get(player.getUniqueId()); PlayerNPCCommand info = playerTracking.get(player.getUniqueId());
if (info != null && info.lastUsedHand != hand) { if (info != null && info.lastUsedHand != hand) {
info.lastUsedHand = hand; info.lastUsedHand = hand;
info.lastUsedId = -1; info.lastUsedId = -1;
@ -255,10 +257,10 @@ public class CommandTrait extends Trait {
Runnable runnable = new Runnable() { Runnable runnable = new Runnable() {
@Override @Override
public void run() { public void run() {
PlayerNPCCommand info = cooldowns.get(player.getUniqueId()); PlayerNPCCommand info = playerTracking.get(player.getUniqueId());
if (info == null && (executionMode == ExecutionMode.SEQUENTIAL if (info == null && (executionMode == ExecutionMode.SEQUENTIAL
|| PlayerNPCCommand.requiresTracking(command))) { || PlayerNPCCommand.requiresTracking(command))) {
cooldowns.put(player.getUniqueId(), info = new PlayerNPCCommand()); playerTracking.put(player.getUniqueId(), info = new PlayerNPCCommand());
} }
if (info != null && !info.canUse(CommandTrait.this, player, command)) { if (info != null && !info.canUse(CommandTrait.this, player, command)) {
return; return;
@ -329,7 +331,7 @@ public class CommandTrait extends Trait {
@Override @Override
public void save(DataKey key) { public void save(DataKey key) {
Collection<NPCCommand> commands = this.commands.values(); Collection<NPCCommand> commands = this.commands.values();
for (PlayerNPCCommand playerCommand : cooldowns.values()) { for (PlayerNPCCommand playerCommand : playerTracking.values()) {
playerCommand.prune(globalCooldowns, commands); playerCommand.prune(globalCooldowns, commands);
} }
} }
@ -345,7 +347,7 @@ public class CommandTrait extends Trait {
return; return;
sent.add(msg); sent.add(msg);
} }
String messageRaw = msg.setting.asString(); String messageRaw = customErrorMessages.getOrDefault(msg, msg.setting.asString());
if (transform != null) { if (transform != null) {
messageRaw = transform.apply(messageRaw); messageRaw = transform.apply(messageRaw);
} }
@ -358,6 +360,10 @@ public class CommandTrait extends Trait {
this.cost = cost; this.cost = cost;
} }
public void setCustomErrorMessage(CommandTraitMessages which, String message) {
customErrorMessages.put(which, message);
}
public void setExecutionMode(ExecutionMode mode) { public void setExecutionMode(ExecutionMode mode) {
this.executionMode = mode; this.executionMode = mode;
} }
@ -375,7 +381,7 @@ public class CommandTrait extends Trait {
temporaryPermissions.addAll(permissions); temporaryPermissions.addAll(permissions);
} }
private enum CommandTraitMessages { public enum CommandTraitMessages {
MAXIMUM_TIMES_USED(Setting.NPC_COMMAND_MAXIMUM_TIMES_USED_MESSAGE), MAXIMUM_TIMES_USED(Setting.NPC_COMMAND_MAXIMUM_TIMES_USED_MESSAGE),
MISSING_EXPERIENCE(Setting.NPC_COMMAND_NOT_ENOUGH_EXPERIENCE_MESSAGE), MISSING_EXPERIENCE(Setting.NPC_COMMAND_NOT_ENOUGH_EXPERIENCE_MESSAGE),
MISSING_ITEM(Setting.NPC_COMMAND_MISSING_ITEM_MESSAGE), MISSING_ITEM(Setting.NPC_COMMAND_MISSING_ITEM_MESSAGE),
@ -644,10 +650,11 @@ public class CommandTrait extends Trait {
return false; return false;
} }
} }
long globalDelay = Setting.NPC_COMMAND_GLOBAL_COMMAND_DELAY.asLong();
long currentTimeSec = System.currentTimeMillis() / 1000; long currentTimeSec = System.currentTimeMillis() / 1000;
String commandKey = command.getEncodedKey(); String commandKey = command.getEncodedKey();
if (lastUsed.containsKey(commandKey)) { if (lastUsed.containsKey(commandKey)) {
long deadline = ((Number) lastUsed.get(commandKey)).longValue() + command.cooldown; long deadline = ((Number) lastUsed.get(commandKey)).longValue() + command.cooldown + globalDelay;
if (currentTimeSec < deadline) { if (currentTimeSec < deadline) {
long seconds = deadline - currentTimeSec; long seconds = deadline - currentTimeSec;
trait.sendErrorMessage(player, CommandTraitMessages.ON_COOLDOWN, trait.sendErrorMessage(player, CommandTraitMessages.ON_COOLDOWN,
@ -671,7 +678,7 @@ public class CommandTrait extends Trait {
trait.sendErrorMessage(player, CommandTraitMessages.MAXIMUM_TIMES_USED, null, command.n); trait.sendErrorMessage(player, CommandTraitMessages.MAXIMUM_TIMES_USED, null, command.n);
return false; return false;
} }
if (command.cooldown > 0) { if (command.cooldown > 0 || globalDelay > 0) {
lastUsed.put(commandKey, currentTimeSec); lastUsed.put(commandKey, currentTimeSec);
} }
if (command.globalCooldown > 0) { if (command.globalCooldown > 0) {
@ -691,7 +698,8 @@ public class CommandTrait extends Trait {
String commandKey = command.getEncodedKey(); String commandKey = command.getEncodedKey();
commandKeys.add(commandKey); commandKeys.add(commandKey);
Number number = lastUsed.get(commandKey); Number number = lastUsed.get(commandKey);
if (number != null && number.longValue() + command.cooldown <= currentTimeSec) { if (number != null && number.longValue() + command.cooldown
+ Setting.NPC_COMMAND_GLOBAL_COMMAND_DELAY.asLong() <= currentTimeSec) {
lastUsed.remove(commandKey); lastUsed.remove(commandKey);
} }
if (globalCooldowns != null) { if (globalCooldowns != null) {
@ -718,7 +726,8 @@ public class CommandTrait extends Trait {
public static boolean requiresTracking(NPCCommand command) { public static boolean requiresTracking(NPCCommand command) {
return command.globalCooldown > 0 || command.cooldown > 0 || command.n > 0 return command.globalCooldown > 0 || command.cooldown > 0 || command.n > 0
|| (command.perms != null && command.perms.size() > 0); || (command.perms != null && command.perms.size() > 0)
|| Setting.NPC_COMMAND_GLOBAL_COMMAND_DELAY.asLong() > 0;
} }
} }

View File

@ -31,6 +31,7 @@ import net.citizensnpcs.api.trait.TraitName;
import net.citizensnpcs.api.util.DataKey; import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.api.util.Messaging; import net.citizensnpcs.api.util.Messaging;
import net.citizensnpcs.api.util.Paginator; import net.citizensnpcs.api.util.Paginator;
import net.citizensnpcs.api.util.Placeholders;
import net.citizensnpcs.editor.Editor; import net.citizensnpcs.editor.Editor;
import net.citizensnpcs.trait.HologramTrait; import net.citizensnpcs.trait.HologramTrait;
import net.citizensnpcs.util.Messages; import net.citizensnpcs.util.Messages;
@ -265,10 +266,10 @@ public class Text extends Trait implements Runnable, Listener, ConversationAband
HologramTrait trait = npc.getOrAddTrait(HologramTrait.class); HologramTrait trait = npc.getOrAddTrait(HologramTrait.class);
if (speechIndex == -1) { if (speechIndex == -1) {
speechIndex = trait.getLines().size(); speechIndex = trait.getLines().size();
trait.addLine(text.get(index)); trait.addLine(Placeholders.replace(text.get(index), player));
bubbleTicks = Setting.DEFAULT_TEXT_SPEECH_BUBBLE_TICKS.asInt(); bubbleTicks = Setting.DEFAULT_TEXT_SPEECH_BUBBLE_TICKS.asInt();
} else if (speechIndex < trait.getLines().size()) { } else if (speechIndex < trait.getLines().size()) {
trait.setLine(speechIndex, text.get(index)); trait.setLine(speechIndex, Placeholders.replace(text.get(index), player));
} }
} else { } else {
npc.getDefaultSpeechController().speak(new SpeechContext(text.get(index), player)); npc.getDefaultSpeechController().speak(new SpeechContext(text.get(index), player));

View File

@ -240,6 +240,7 @@ public class Messages {
public static final String NPC_ALREADY_SELECTED = "citizens.commands.npc.select.already-selected"; public static final String NPC_ALREADY_SELECTED = "citizens.commands.npc.select.already-selected";
public static final String NPC_ALREADY_SPAWNED = "citizens.commands.npc.spawn.already-spawned"; public static final String NPC_ALREADY_SPAWNED = "citizens.commands.npc.spawn.already-spawned";
public static final String NPC_COMMAND_HELP = "citizens.commands.npc.command.help"; public static final String NPC_COMMAND_HELP = "citizens.commands.npc.command.help";
public static final String NPC_COMMAND_INVALID_ERROR_MESSAGE = "citizens.commands.npc.command.invalid-error-message";
public static final String NPC_COPIED = "citizens.commands.npc.copy.copied"; public static final String NPC_COPIED = "citizens.commands.npc.copy.copied";
public static final String NPC_CREATE_INVALID_MOBTYPE = "citizens.commands.npc.create.invalid-mobtype"; public static final String NPC_CREATE_INVALID_MOBTYPE = "citizens.commands.npc.create.invalid-mobtype";
public static final String NPC_CREATE_MISSING_MOBTYPE = "citizens.commands.npc.create.mobtype-missing"; public static final String NPC_CREATE_MISSING_MOBTYPE = "citizens.commands.npc.create.mobtype-missing";

View File

@ -54,6 +54,7 @@ citizens.commands.npc.collidable.set=[[{0}]] will now collide with entities.
citizens.commands.npc.collidable.unset=[[{0}]] will no longer collide with entities. citizens.commands.npc.collidable.unset=[[{0}]] will no longer collide with entities.
citizens.commands.npc.command.none-added=No commands have been added. citizens.commands.npc.command.none-added=No commands have been added.
citizens.commands.npc.command.cost-set=Set cost per click to [[{0}]]. citizens.commands.npc.command.cost-set=Set cost per click to [[{0}]].
citizens.commands.npc.command.invalid-error-message=Invalid error message. Valid messages are [[{0}]].
citizens.commands.npc.command.hide-error-messages-set=Now hiding error messages. citizens.commands.npc.command.hide-error-messages-set=Now hiding error messages.
citizens.commands.npc.command.hide-error-messages-unset=No longer hiding error messages. citizens.commands.npc.command.hide-error-messages-unset=No longer hiding error messages.
citizens.commands.npc.command.experience-cost-set=Set experience cost per click to [[{0}]]. citizens.commands.npc.command.experience-cost-set=Set experience cost per click to [[{0}]].