Merge pull request #83 from D3v1s0m/2.X

action delay and fallback skin server
This commit is contained in:
Pyr 2023-08-18 00:50:48 +02:00 committed by GitHub
commit 6e6cef56f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 139 additions and 57 deletions

@ -6,12 +6,14 @@ import java.util.UUID;
public abstract class InteractionAction { public abstract class InteractionAction {
private final UUID id; private final UUID id;
private final long cooldown;
private final long delay; private final long delay;
private final InteractionType interactionType; private final InteractionType interactionType;
protected InteractionAction(long delay, InteractionType interactionType) { protected InteractionAction(long cooldown, long delay, InteractionType interactionType) {
this.interactionType = interactionType; this.interactionType = interactionType;
this.id = UUID.randomUUID(); this.id = UUID.randomUUID();
this.cooldown = cooldown;
this.delay = delay; this.delay = delay;
} }
@ -20,6 +22,10 @@ public abstract class InteractionAction {
} }
public long getCooldown() { public long getCooldown() {
return cooldown;
}
public long getDelay() {
return delay; return delay;
} }

@ -149,7 +149,7 @@ public class ZNpcsPlus extends JavaPlugin {
typeRegistry.registerDefault(packetEvents, propertyRegistry); typeRegistry.registerDefault(packetEvents, propertyRegistry);
actionRegistry.registerTypes(scheduler, adventure, bungeeConnector, textSerializer); actionRegistry.registerTypes(scheduler, adventure, bungeeConnector, textSerializer);
packetEvents.getEventManager().registerListener(new InteractionPacketListener(userManager, npcRegistry), PacketListenerPriority.MONITOR); packetEvents.getEventManager().registerListener(new InteractionPacketListener(userManager, npcRegistry, scheduler), PacketListenerPriority.MONITOR);
new Metrics(this, 18244); new Metrics(this, 18244);
pluginManager.registerEvents(new UserListener(userManager), this); pluginManager.registerEvents(new UserListener(userManager), this);
getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord"); getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord");

@ -153,18 +153,18 @@ public class ZNpcImporter implements DataImporter {
throw new IllegalArgumentException("Couldn't adapt znpcs click type: " + clickType); throw new IllegalArgumentException("Couldn't adapt znpcs click type: " + clickType);
} }
private InteractionActionImpl adaptAction(String type, InteractionType clickType, String parameter, int delay) { private InteractionActionImpl adaptAction(String type, InteractionType clickType, String parameter, int cooldown) {
switch (type.toLowerCase()) { switch (type.toLowerCase()) {
case "cmd": case "cmd":
return new PlayerCommandAction(taskScheduler, parameter, clickType, delay * 1000L); return new PlayerCommandAction(taskScheduler, parameter, clickType, cooldown * 1000L, 0);
case "console": case "console":
return new ConsoleCommandAction(taskScheduler, parameter, clickType, delay * 1000L); return new ConsoleCommandAction(taskScheduler, parameter, clickType, cooldown * 1000L, 0);
case "chat": case "chat":
return new PlayerChatAction(taskScheduler, parameter, clickType, delay * 1000L); return new PlayerChatAction(taskScheduler, parameter, clickType, cooldown * 1000L, 0);
case "message": case "message":
return new MessageAction(adventure, parameter, clickType, textSerializer, delay * 1000L); return new MessageAction(adventure, parameter, clickType, textSerializer, cooldown * 1000L, 0);
case "server": case "server":
return new SwitchServerAction(bungeeConnector, parameter, clickType, delay * 1000L); return new SwitchServerAction(bungeeConnector, parameter, clickType, cooldown * 1000L, 0);
} }
throw new IllegalArgumentException("Couldn't adapt znpcs click action: " + type); throw new IllegalArgumentException("Couldn't adapt znpcs click action: " + type);
} }

@ -6,8 +6,8 @@ import lol.pyr.znpcsplus.api.interaction.InteractionType;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
public abstract class InteractionActionImpl extends InteractionAction { public abstract class InteractionActionImpl extends InteractionAction {
protected InteractionActionImpl(long delay, InteractionType interactionType) { protected InteractionActionImpl(long cooldown, long delay, InteractionType interactionType) {
super(delay, interactionType); super(cooldown, delay, interactionType);
} }
public abstract Component getInfo(String id, int index, CommandContext context); public abstract Component getInfo(String id, int index, CommandContext context);

@ -10,6 +10,7 @@ import lol.pyr.znpcsplus.api.interaction.InteractionType;
import lol.pyr.znpcsplus.npc.NpcEntryImpl; import lol.pyr.znpcsplus.npc.NpcEntryImpl;
import lol.pyr.znpcsplus.npc.NpcImpl; import lol.pyr.znpcsplus.npc.NpcImpl;
import lol.pyr.znpcsplus.npc.NpcRegistryImpl; import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
import lol.pyr.znpcsplus.user.User; import lol.pyr.znpcsplus.user.User;
import lol.pyr.znpcsplus.user.UserManager; import lol.pyr.znpcsplus.user.UserManager;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -18,10 +19,12 @@ import org.bukkit.entity.Player;
public class InteractionPacketListener implements PacketListener { public class InteractionPacketListener implements PacketListener {
private final UserManager userManager; private final UserManager userManager;
private final NpcRegistryImpl npcRegistry; private final NpcRegistryImpl npcRegistry;
private final TaskScheduler scheduler;
public InteractionPacketListener(UserManager userManager, NpcRegistryImpl npcRegistry) { public InteractionPacketListener(UserManager userManager, NpcRegistryImpl npcRegistry, TaskScheduler scheduler) {
this.userManager = userManager; this.userManager = userManager;
this.npcRegistry = npcRegistry; this.npcRegistry = npcRegistry;
this.scheduler = scheduler;
} }
@Override @Override
@ -46,7 +49,7 @@ public class InteractionPacketListener implements PacketListener {
for (InteractionAction action : npc.getActions()) { for (InteractionAction action : npc.getActions()) {
if (action.getInteractionType() != InteractionType.ANY_CLICK && action.getInteractionType() != type) continue; if (action.getInteractionType() != InteractionType.ANY_CLICK && action.getInteractionType() != type) continue;
if (action.getCooldown() > 0 && !user.actionCooldownCheck(action)) continue; if (action.getCooldown() > 0 && !user.actionCooldownCheck(action)) continue;
action.run(player); scheduler.runLaterAsync(() -> action.run(player), action.getDelay());
} }
} }

@ -16,8 +16,8 @@ public class ConsoleCommandAction extends InteractionActionImpl {
private final TaskScheduler scheduler; private final TaskScheduler scheduler;
private final String command; private final String command;
public ConsoleCommandAction(TaskScheduler scheduler, String command, InteractionType interactionType, long delay) { public ConsoleCommandAction(TaskScheduler scheduler, String command, InteractionType interactionType, long cooldown, long delay) {
super(delay, interactionType); super(cooldown, delay, interactionType);
this.scheduler = scheduler; this.scheduler = scheduler;
this.command = command; this.command = command;
} }
@ -35,7 +35,7 @@ public class ConsoleCommandAction extends InteractionActionImpl {
.hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT, .hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT,
Component.text("Click to edit this action", NamedTextColor.GRAY))) Component.text("Click to edit this action", NamedTextColor.GRAY)))
.clickEvent(ClickEvent.clickEvent(ClickEvent.Action.SUGGEST_COMMAND, .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.SUGGEST_COMMAND,
"/" + context.getLabel() + " action edit " + id + " " + index + " consolecommand " + getInteractionType().name() + " " + getCooldown()/1000 + " " + command)) "/" + context.getLabel() + " action edit " + id + " " + index + " consolecommand " + getInteractionType().name() + " " + getCooldown()/1000 + " " + getDelay() + " " + command))
.append(Component.text(" | ", NamedTextColor.GRAY)) .append(Component.text(" | ", NamedTextColor.GRAY))
.append(Component.text("[DELETE]", NamedTextColor.RED) .append(Component.text("[DELETE]", NamedTextColor.RED)
.hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT, .hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT,
@ -45,7 +45,7 @@ public class ConsoleCommandAction extends InteractionActionImpl {
.append(Component.text(" | ", NamedTextColor.GRAY)) .append(Component.text(" | ", NamedTextColor.GRAY))
.append(Component.text("Console Command: ", NamedTextColor.GREEN) .append(Component.text("Console Command: ", NamedTextColor.GREEN)
.hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT, .hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT,
Component.text("Click Type: " + getInteractionType().name() + " Cooldown: " + getCooldown()/1000, NamedTextColor.GREEN)))) Component.text("Click Type: " + getInteractionType().name() + " Cooldown: " + getCooldown()/1000 + " Delay: " + getDelay(), NamedTextColor.GRAY))))
.append(Component.text(command, NamedTextColor.WHITE))); .append(Component.text(command, NamedTextColor.WHITE)));
} }

@ -22,14 +22,14 @@ public class ConsoleCommandActionType implements InteractionActionType<ConsoleCo
@Override @Override
public String serialize(ConsoleCommandAction obj) { public String serialize(ConsoleCommandAction obj) {
return Base64.getEncoder().encodeToString(obj.getCommand().getBytes(StandardCharsets.UTF_8)) + ";" + obj.getCooldown() + ";" + obj.getInteractionType().name(); return Base64.getEncoder().encodeToString(obj.getCommand().getBytes(StandardCharsets.UTF_8)) + ";" + obj.getCooldown() + ";" + obj.getInteractionType().name() + ";" + obj.getDelay();
} }
@Override @Override
public ConsoleCommandAction deserialize(String str) { public ConsoleCommandAction deserialize(String str) {
String[] split = str.split(";"); String[] split = str.split(";");
InteractionType type = split.length > 2 ? InteractionType.valueOf(split[2]) : InteractionType.ANY_CLICK; InteractionType type = split.length > 2 ? InteractionType.valueOf(split[2]) : InteractionType.ANY_CLICK;
return new ConsoleCommandAction(scheduler, new String(Base64.getDecoder().decode(split[0]), StandardCharsets.UTF_8), type, Long.parseLong(split[1])); return new ConsoleCommandAction(scheduler, new String(Base64.getDecoder().decode(split[0]), StandardCharsets.UTF_8), type, Long.parseLong(split[1]), Long.parseLong(split.length > 3 ? split[3] : "0"));
} }
@Override @Override
@ -44,21 +44,23 @@ public class ConsoleCommandActionType implements InteractionActionType<ConsoleCo
@Override @Override
public void appendUsage(CommandContext context) { public void appendUsage(CommandContext context) {
context.setUsage(context.getUsage() + " " + getSubcommandName() + " <id> <click type> <cooldown seconds> <server>"); context.setUsage(context.getUsage() + " " + getSubcommandName() + " <id> <click type> <cooldown seconds> <delay ticks> <server>");
} }
@Override @Override
public InteractionActionImpl parse(CommandContext context) throws CommandExecutionException { public InteractionActionImpl parse(CommandContext context) throws CommandExecutionException {
InteractionType type = context.parse(InteractionType.class); InteractionType type = context.parse(InteractionType.class);
long cooldown = (long) (context.parse(Double.class) * 1000D); long cooldown = (long) (context.parse(Double.class) * 1000D);
long delay = (long) (context.parse(Integer.class) * 1D);
String command = context.dumpAllArgs(); String command = context.dumpAllArgs();
return new ConsoleCommandAction(scheduler, command, type, cooldown); return new ConsoleCommandAction(scheduler, command, type, cooldown, delay);
} }
@Override @Override
public List<String> suggest(CommandContext context) throws CommandExecutionException { public List<String> suggest(CommandContext context) throws CommandExecutionException {
if (context.argSize() == 1) return context.suggestEnum(InteractionType.values()); if (context.argSize() == 1) return context.suggestEnum(InteractionType.values());
if (context.argSize() == 2) return context.suggestLiteral("1"); if (context.argSize() == 2) return context.suggestLiteral("1");
if (context.argSize() == 3) return context.suggestLiteral("0");
return Collections.emptyList(); return Collections.emptyList();
} }
} }

@ -17,8 +17,8 @@ public class MessageAction extends InteractionActionImpl {
private final String message; private final String message;
private final LegacyComponentSerializer textSerializer; private final LegacyComponentSerializer textSerializer;
public MessageAction(BukkitAudiences adventure, String message, InteractionType interactionType, LegacyComponentSerializer textSerializer, long delay) { public MessageAction(BukkitAudiences adventure, String message, InteractionType interactionType, LegacyComponentSerializer textSerializer, long cooldown, long delay) {
super(delay, interactionType); super(cooldown, delay, interactionType);
this.adventure = adventure; this.adventure = adventure;
this.message = message; this.message = message;
this.textSerializer = textSerializer; this.textSerializer = textSerializer;
@ -38,7 +38,7 @@ public class MessageAction extends InteractionActionImpl {
.hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT, .hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT,
Component.text("Click to edit this action", NamedTextColor.GRAY))) Component.text("Click to edit this action", NamedTextColor.GRAY)))
.clickEvent(ClickEvent.clickEvent(ClickEvent.Action.SUGGEST_COMMAND, .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.SUGGEST_COMMAND,
"/" + context.getLabel() + " action edit " + id + " " + index + " message " + getInteractionType().name() + " " + getCooldown()/1000 + " " + message)) "/" + context.getLabel() + " action edit " + id + " " + index + " message " + getInteractionType().name() + " " + getCooldown()/1000 + " " + getDelay() + " " + message))
.append(Component.text(" | ", NamedTextColor.GRAY)) .append(Component.text(" | ", NamedTextColor.GRAY))
.append(Component.text("[DELETE]", NamedTextColor.RED) .append(Component.text("[DELETE]", NamedTextColor.RED)
.hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT, .hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT,
@ -48,7 +48,7 @@ public class MessageAction extends InteractionActionImpl {
.append(Component.text(" | ", NamedTextColor.GRAY)) .append(Component.text(" | ", NamedTextColor.GRAY))
.append(Component.text("Message: ", NamedTextColor.GREEN) .append(Component.text("Message: ", NamedTextColor.GREEN)
.hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT, .hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT,
Component.text("Click Type: " + getInteractionType().name() + " Cooldown: " + getCooldown()/1000, NamedTextColor.GREEN)))) Component.text("Click Type: " + getInteractionType().name() + " Cooldown: " + getCooldown()/1000 + " Delay: " + getDelay(), NamedTextColor.GRAY))))
.append(Component.text(message, NamedTextColor.WHITE))); .append(Component.text(message, NamedTextColor.WHITE)));
} }

@ -25,14 +25,14 @@ public class MessageActionType implements InteractionActionType<MessageAction>,
@Override @Override
public String serialize(MessageAction obj) { public String serialize(MessageAction obj) {
return Base64.getEncoder().encodeToString(obj.getMessage().getBytes(StandardCharsets.UTF_8)) + ";" + obj.getCooldown() + ";" + obj.getInteractionType().name(); return Base64.getEncoder().encodeToString(obj.getMessage().getBytes(StandardCharsets.UTF_8)) + ";" + obj.getCooldown() + ";" + obj.getInteractionType().name() + ";" + obj.getDelay();
} }
@Override @Override
public MessageAction deserialize(String str) { public MessageAction deserialize(String str) {
String[] split = str.split(";"); String[] split = str.split(";");
InteractionType type = split.length > 2 ? InteractionType.valueOf(split[2]) : InteractionType.ANY_CLICK; InteractionType type = split.length > 2 ? InteractionType.valueOf(split[2]) : InteractionType.ANY_CLICK;
return new MessageAction(adventure, new String(Base64.getDecoder().decode(split[0]), StandardCharsets.UTF_8), type, textSerializer, Long.parseLong(split[1])); return new MessageAction(adventure, new String(Base64.getDecoder().decode(split[0]), StandardCharsets.UTF_8), type, textSerializer, Long.parseLong(split[1]), Long.parseLong(split.length > 3 ? split[3] : "0"));
} }
@Override @Override
@ -47,21 +47,23 @@ public class MessageActionType implements InteractionActionType<MessageAction>,
@Override @Override
public void appendUsage(CommandContext context) { public void appendUsage(CommandContext context) {
context.setUsage(context.getUsage() + " " + getSubcommandName() + " <id> <click type> <cooldown seconds> <message>"); context.setUsage(context.getUsage() + " " + getSubcommandName() + " <id> <click type> <cooldown seconds> <delay ticks> <message>");
} }
@Override @Override
public InteractionActionImpl parse(CommandContext context) throws CommandExecutionException { public InteractionActionImpl parse(CommandContext context) throws CommandExecutionException {
InteractionType type = context.parse(InteractionType.class); InteractionType type = context.parse(InteractionType.class);
long cooldown = (long) (context.parse(Double.class) * 1000D); long cooldown = (long) (context.parse(Double.class) * 1000D);
long delay = (long) (context.parse(Integer.class) * 1D);
String message = context.dumpAllArgs(); String message = context.dumpAllArgs();
return new MessageAction(adventure, message, type, textSerializer, cooldown); return new MessageAction(adventure, message, type, textSerializer, cooldown, delay);
} }
@Override @Override
public List<String> suggest(CommandContext context) throws CommandExecutionException { public List<String> suggest(CommandContext context) throws CommandExecutionException {
if (context.argSize() == 1) return context.suggestEnum(InteractionType.values()); if (context.argSize() == 1) return context.suggestEnum(InteractionType.values());
if (context.argSize() == 2) return context.suggestLiteral("1"); if (context.argSize() == 2) return context.suggestLiteral("1");
if (context.argSize() == 3) return context.suggestLiteral("0");
return Collections.emptyList(); return Collections.emptyList();
} }
} }

@ -14,8 +14,8 @@ public class PlayerChatAction extends InteractionActionImpl {
private final String message; private final String message;
private final TaskScheduler scheduler; private final TaskScheduler scheduler;
public PlayerChatAction(TaskScheduler scheduler, String message, InteractionType interactionType, long delay) { public PlayerChatAction(TaskScheduler scheduler, String message, InteractionType interactionType, long cooldown, long delay) {
super(delay, interactionType); super(cooldown, delay, interactionType);
this.message = message; this.message = message;
this.scheduler = scheduler; this.scheduler = scheduler;
} }
@ -33,7 +33,7 @@ public class PlayerChatAction extends InteractionActionImpl {
.hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT, .hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT,
Component.text("Click to edit this action", NamedTextColor.GRAY))) Component.text("Click to edit this action", NamedTextColor.GRAY)))
.clickEvent(ClickEvent.clickEvent(ClickEvent.Action.SUGGEST_COMMAND, .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.SUGGEST_COMMAND,
"/" + context.getLabel() + " action edit " + id + " " + index + " playerchat " + getInteractionType().name() + " " + getCooldown()/1000 + " " + message)) "/" + context.getLabel() + " action edit " + id + " " + index + " playerchat " + getInteractionType().name() + " " + getCooldown()/1000 + " " + getDelay() + " " + message))
.append(Component.text(" | ", NamedTextColor.GRAY)) .append(Component.text(" | ", NamedTextColor.GRAY))
.append(Component.text("[DELETE]", NamedTextColor.RED) .append(Component.text("[DELETE]", NamedTextColor.RED)
.hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT, .hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT,
@ -43,7 +43,7 @@ public class PlayerChatAction extends InteractionActionImpl {
.append(Component.text(" | ", NamedTextColor.GRAY)) .append(Component.text(" | ", NamedTextColor.GRAY))
.append(Component.text("Player Chat: ", NamedTextColor.GREEN) .append(Component.text("Player Chat: ", NamedTextColor.GREEN)
.hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT, .hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT,
Component.text("Click Type: " + getInteractionType().name() + " Cooldown: " + getCooldown()/1000, NamedTextColor.GREEN)))) Component.text("Click Type: " + getInteractionType().name() + " Cooldown: " + getCooldown()/1000 + " Delay: " + getDelay(), NamedTextColor.GRAY))))
.append(Component.text(message, NamedTextColor.WHITE))); .append(Component.text(message, NamedTextColor.WHITE)));
} }

@ -22,13 +22,13 @@ public class PlayerChatActionType implements InteractionActionType<PlayerChatAct
@Override @Override
public String serialize(PlayerChatAction obj) { public String serialize(PlayerChatAction obj) {
return Base64.getEncoder().encodeToString(obj.getMessage().getBytes(StandardCharsets.UTF_8)) + ";" + obj.getCooldown() + ";" + obj.getInteractionType().name(); return Base64.getEncoder().encodeToString(obj.getMessage().getBytes(StandardCharsets.UTF_8)) + ";" + obj.getCooldown() + ";" + obj.getInteractionType().name() + ";" + obj.getDelay();
} }
@Override @Override
public PlayerChatAction deserialize(String str) { public PlayerChatAction deserialize(String str) {
String[] split = str.split(";"); String[] split = str.split(";");
return new PlayerChatAction(scheduler, new String(Base64.getDecoder().decode(split[0]), StandardCharsets.UTF_8), InteractionType.valueOf(split[2]), Long.parseLong(split[1])); return new PlayerChatAction(scheduler, new String(Base64.getDecoder().decode(split[0]), StandardCharsets.UTF_8), InteractionType.valueOf(split[2]), Long.parseLong(split[1]), Long.parseLong(split.length > 3 ? split[3] : "0"));
} }
@Override @Override
@ -43,21 +43,23 @@ public class PlayerChatActionType implements InteractionActionType<PlayerChatAct
@Override @Override
public void appendUsage(CommandContext context) { public void appendUsage(CommandContext context) {
context.setUsage(context.getUsage() + " " + getSubcommandName() + " <id> <click type> <cooldown seconds> <server>"); context.setUsage(context.getUsage() + " " + getSubcommandName() + " <id> <click type> <cooldown seconds> <delay ticks> <server>");
} }
@Override @Override
public InteractionActionImpl parse(CommandContext context) throws CommandExecutionException { public InteractionActionImpl parse(CommandContext context) throws CommandExecutionException {
InteractionType type = context.parse(InteractionType.class); InteractionType type = context.parse(InteractionType.class);
long cooldown = (long) (context.parse(Double.class) * 1000D); long cooldown = (long) (context.parse(Double.class) * 1000D);
long delay = (long) (context.parse(Integer.class) * 1D);
String message = context.dumpAllArgs(); String message = context.dumpAllArgs();
return new PlayerChatAction(scheduler, message, type, cooldown); return new PlayerChatAction(scheduler, message, type, cooldown, delay);
} }
@Override @Override
public List<String> suggest(CommandContext context) throws CommandExecutionException { public List<String> suggest(CommandContext context) throws CommandExecutionException {
if (context.argSize() == 1) return context.suggestEnum(InteractionType.values()); if (context.argSize() == 1) return context.suggestEnum(InteractionType.values());
if (context.argSize() == 2) return context.suggestLiteral("1"); if (context.argSize() == 2) return context.suggestLiteral("1");
if (context.argSize() == 3) return context.suggestLiteral("0");
return Collections.emptyList(); return Collections.emptyList();
} }
} }

@ -15,8 +15,8 @@ public class PlayerCommandAction extends InteractionActionImpl {
private final TaskScheduler scheduler; private final TaskScheduler scheduler;
private final String command; private final String command;
public PlayerCommandAction(TaskScheduler scheduler, String command, InteractionType interactionType, long delay) { public PlayerCommandAction(TaskScheduler scheduler, String command, InteractionType interactionType, long cooldown, long delay) {
super(delay, interactionType); super(cooldown, delay, interactionType);
this.scheduler = scheduler; this.scheduler = scheduler;
this.command = command; this.command = command;
} }
@ -34,7 +34,7 @@ public class PlayerCommandAction extends InteractionActionImpl {
.hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT, .hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT,
Component.text("Click to edit this action", NamedTextColor.GRAY))) Component.text("Click to edit this action", NamedTextColor.GRAY)))
.clickEvent(ClickEvent.clickEvent(ClickEvent.Action.SUGGEST_COMMAND, .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.SUGGEST_COMMAND,
"/" + context.getLabel() + " action edit " + id + " " + index + " playercommand " + getInteractionType().name() + " " + getCooldown()/1000 + " " + command)) "/" + context.getLabel() + " action edit " + id + " " + index + " playercommand " + getInteractionType().name() + " " + getCooldown()/1000 + " " + getDelay() + " " + command))
.append(Component.text(" | ", NamedTextColor.GRAY)) .append(Component.text(" | ", NamedTextColor.GRAY))
.append(Component.text("[DELETE]", NamedTextColor.RED) .append(Component.text("[DELETE]", NamedTextColor.RED)
.hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT, .hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT,
@ -44,7 +44,7 @@ public class PlayerCommandAction extends InteractionActionImpl {
.append(Component.text(" | ", NamedTextColor.GRAY)) .append(Component.text(" | ", NamedTextColor.GRAY))
.append(Component.text("Player Command: ", NamedTextColor.GREEN) .append(Component.text("Player Command: ", NamedTextColor.GREEN)
.hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT, .hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT,
Component.text("Click Type: " + getInteractionType().name() + " Cooldown: " + getCooldown()/1000, NamedTextColor.GREEN)))) Component.text("Click Type: " + getInteractionType().name() + " Cooldown: " + getCooldown()/1000 + " Delay: " + getDelay(), NamedTextColor.GRAY))))
.append(Component.text(command, NamedTextColor.WHITE))); .append(Component.text(command, NamedTextColor.WHITE)));
} }

@ -22,14 +22,14 @@ public class PlayerCommandActionType implements InteractionActionType<PlayerComm
@Override @Override
public String serialize(PlayerCommandAction obj) { public String serialize(PlayerCommandAction obj) {
return Base64.getEncoder().encodeToString(obj.getCommand().getBytes(StandardCharsets.UTF_8)) + ";" + obj.getCooldown() + ";" + obj.getInteractionType().name(); return Base64.getEncoder().encodeToString(obj.getCommand().getBytes(StandardCharsets.UTF_8)) + ";" + obj.getCooldown() + ";" + obj.getInteractionType().name() + ";" + obj.getDelay();
} }
@Override @Override
public PlayerCommandAction deserialize(String str) { public PlayerCommandAction deserialize(String str) {
String[] split = str.split(";"); String[] split = str.split(";");
InteractionType type = split.length > 2 ? InteractionType.valueOf(split[2]) : InteractionType.ANY_CLICK; InteractionType type = split.length > 2 ? InteractionType.valueOf(split[2]) : InteractionType.ANY_CLICK;
return new PlayerCommandAction(scheduler, new String(Base64.getDecoder().decode(split[0]), StandardCharsets.UTF_8), type, Long.parseLong(split[1])); return new PlayerCommandAction(scheduler, new String(Base64.getDecoder().decode(split[0]), StandardCharsets.UTF_8), type, Long.parseLong(split[1]), Long.parseLong(split.length > 3 ? split[3] : "0"));
} }
@Override @Override
@ -44,21 +44,23 @@ public class PlayerCommandActionType implements InteractionActionType<PlayerComm
@Override @Override
public void appendUsage(CommandContext context) { public void appendUsage(CommandContext context) {
context.setUsage(context.getUsage() + " " + getSubcommandName() + " <id> <click type> <cooldown seconds> <command>"); context.setUsage(context.getUsage() + " " + getSubcommandName() + " <id> <click type> <cooldown seconds> <delay ticks> <command>");
} }
@Override @Override
public InteractionActionImpl parse(CommandContext context) throws CommandExecutionException { public InteractionActionImpl parse(CommandContext context) throws CommandExecutionException {
InteractionType type = context.parse(InteractionType.class); InteractionType type = context.parse(InteractionType.class);
long cooldown = (long) (context.parse(Double.class) * 1000D); long cooldown = (long) (context.parse(Double.class) * 1000D);
long delay = (long) (context.parse(Integer.class) * 1D);
String command = context.dumpAllArgs(); String command = context.dumpAllArgs();
return new PlayerCommandAction(scheduler, command, type, cooldown); return new PlayerCommandAction(scheduler, command, type, cooldown, delay);
} }
@Override @Override
public List<String> suggest(CommandContext context) throws CommandExecutionException { public List<String> suggest(CommandContext context) throws CommandExecutionException {
if (context.argSize() == 1) return context.suggestEnum(InteractionType.values()); if (context.argSize() == 1) return context.suggestEnum(InteractionType.values());
if (context.argSize() == 2) return context.suggestLiteral("1"); if (context.argSize() == 2) return context.suggestLiteral("1");
if (context.argSize() == 3) return context.suggestLiteral("0");
return Collections.emptyList(); return Collections.emptyList();
} }
} }

@ -14,8 +14,8 @@ public class SwitchServerAction extends InteractionActionImpl {
private final BungeeConnector bungeeConnector; private final BungeeConnector bungeeConnector;
private final String server; private final String server;
public SwitchServerAction(BungeeConnector bungeeConnector, String server, InteractionType interactionType, long delay) { public SwitchServerAction(BungeeConnector bungeeConnector, String server, InteractionType interactionType, long cooldown, long delay) {
super(delay, interactionType); super(cooldown, delay, interactionType);
this.bungeeConnector = bungeeConnector; this.bungeeConnector = bungeeConnector;
this.server = server; this.server = server;
} }
@ -32,7 +32,7 @@ public class SwitchServerAction extends InteractionActionImpl {
.hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT, .hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT,
Component.text("Click to edit this action", NamedTextColor.GRAY))) Component.text("Click to edit this action", NamedTextColor.GRAY)))
.clickEvent(ClickEvent.clickEvent(ClickEvent.Action.SUGGEST_COMMAND, .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.SUGGEST_COMMAND,
"/" + context.getLabel() + " action edit " + id + " " + index + " switcserver " + getInteractionType().name() + " " + getCooldown()/1000 + " " + server)) "/" + context.getLabel() + " action edit " + id + " " + index + " switcserver " + getInteractionType().name() + " " + getCooldown()/1000 + " " + getDelay() + " " + server))
.append(Component.text(" | ", NamedTextColor.GRAY)) .append(Component.text(" | ", NamedTextColor.GRAY))
.append(Component.text("[DELETE]", NamedTextColor.RED) .append(Component.text("[DELETE]", NamedTextColor.RED)
.hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT, .hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT,
@ -42,7 +42,7 @@ public class SwitchServerAction extends InteractionActionImpl {
.append(Component.text(" | ", NamedTextColor.GRAY)) .append(Component.text(" | ", NamedTextColor.GRAY))
.append(Component.text("Switch Server: ", NamedTextColor.GREEN) .append(Component.text("Switch Server: ", NamedTextColor.GREEN)
.hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT, .hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT,
Component.text("Click Type: " + getInteractionType().name() + " Cooldown: " + getCooldown()/1000, NamedTextColor.GREEN)))) Component.text("Click Type: " + getInteractionType().name() + " Cooldown: " + getCooldown()/1000 + " Delay: " + getDelay(), NamedTextColor.GRAY))))
.append(Component.text(server, NamedTextColor.WHITE))); .append(Component.text(server, NamedTextColor.WHITE)));
} }

@ -22,14 +22,14 @@ public class SwitchServerActionType implements InteractionActionType<SwitchServe
@Override @Override
public String serialize(SwitchServerAction obj) { public String serialize(SwitchServerAction obj) {
return Base64.getEncoder().encodeToString(obj.getServer().getBytes(StandardCharsets.UTF_8)) + ";" + obj.getCooldown() + ";" + obj.getInteractionType().name(); return Base64.getEncoder().encodeToString(obj.getServer().getBytes(StandardCharsets.UTF_8)) + ";" + obj.getCooldown() + ";" + obj.getInteractionType().name() + ";" + obj.getDelay();
} }
@Override @Override
public SwitchServerAction deserialize(String str) { public SwitchServerAction deserialize(String str) {
String[] split = str.split(";"); String[] split = str.split(";");
InteractionType type = split.length > 2 ? InteractionType.valueOf(split[2]) : InteractionType.ANY_CLICK; InteractionType type = split.length > 2 ? InteractionType.valueOf(split[2]) : InteractionType.ANY_CLICK;
return new SwitchServerAction(bungeeConnector, new String(Base64.getDecoder().decode(split[0]), StandardCharsets.UTF_8), type, Long.parseLong(split[1])); return new SwitchServerAction(bungeeConnector, new String(Base64.getDecoder().decode(split[0]), StandardCharsets.UTF_8), type, Long.parseLong(split[1]), Long.parseLong(split.length > 3 ? split[3] : "0"));
} }
@Override @Override
@ -44,21 +44,23 @@ public class SwitchServerActionType implements InteractionActionType<SwitchServe
@Override @Override
public void appendUsage(CommandContext context) { public void appendUsage(CommandContext context) {
context.setUsage(context.getUsage() + " " + getSubcommandName() + " <id> <click type> <cooldown seconds> <server>"); context.setUsage(context.getUsage() + " " + getSubcommandName() + " <id> <click type> <cooldown seconds> <delay ticks> <server>");
} }
@Override @Override
public InteractionActionImpl parse(CommandContext context) throws CommandExecutionException { public InteractionActionImpl parse(CommandContext context) throws CommandExecutionException {
InteractionType type = context.parse(InteractionType.class); InteractionType type = context.parse(InteractionType.class);
long cooldown = (long) (context.parse(Double.class) * 1000D); long cooldown = (long) (context.parse(Double.class) * 1000D);
long delay = (long) (context.parse(Integer.class) * 1D);
String server = context.dumpAllArgs(); String server = context.dumpAllArgs();
return new SwitchServerAction(bungeeConnector, server, type, cooldown); return new SwitchServerAction(bungeeConnector, server, type, cooldown, delay);
} }
@Override @Override
public List<String> suggest(CommandContext context) throws CommandExecutionException { public List<String> suggest(CommandContext context) throws CommandExecutionException {
if (context.argSize() == 1) return context.suggestEnum(InteractionType.values()); if (context.argSize() == 1) return context.suggestEnum(InteractionType.values());
if (context.argSize() == 2) return context.suggestLiteral("1"); if (context.argSize() == 2) return context.suggestLiteral("1");
if (context.argSize() == 3) return context.suggestLiteral("0");
return Collections.emptyList(); return Collections.emptyList();
} }
} }

@ -169,6 +169,14 @@ public final class Reflections {
.setStrict(FoliaUtil.isFolia()) .setStrict(FoliaUtil.isFolia())
.toMethodReflection(); .toMethodReflection();
public static final ReflectionLazyLoader<Method> FOLIA_RUN_NOW_ASYNC =
new ReflectionBuilder(ASYNC_SCHEDULER_CLASS)
.withMethodName("runNow")
.withParameterTypes(Plugin.class, Consumer.class)
.withExpectResult(SCHEDULED_TASK_CLASS)
.setStrict(FoliaUtil.isFolia())
.toMethodReflection();
public static final ReflectionLazyLoader<Method> FOLIA_RUN_DELAYED_ASYNC = public static final ReflectionLazyLoader<Method> FOLIA_RUN_DELAYED_ASYNC =
new ReflectionBuilder(ASYNC_SCHEDULER_CLASS) new ReflectionBuilder(ASYNC_SCHEDULER_CLASS)
.withMethodName("runDelayed") .withMethodName("runDelayed")

@ -43,6 +43,16 @@ public class FoliaScheduler extends TaskScheduler {
} }
} }
@Override
public void runAsyncGlobal(Runnable runnable) {
try {
Object scheduler = Reflections.FOLIA_GET_ASYNC_SCHEDULER.get().invoke(null);
Reflections.FOLIA_RUN_NOW_ASYNC.get().invoke(scheduler, plugin, (Consumer<Object>) o -> runnable.run());
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
@Override @Override
public void runLaterAsync(Runnable runnable, long delay) { public void runLaterAsync(Runnable runnable, long delay) {
try { try {

@ -24,6 +24,11 @@ public class SpigotScheduler extends TaskScheduler {
Bukkit.getScheduler().runTask(plugin, runnable); Bukkit.getScheduler().runTask(plugin, runnable);
} }
@Override
public void runAsyncGlobal(Runnable runnable) {
Bukkit.getScheduler().runTaskAsynchronously(plugin, runnable);
}
@Override @Override
public void runLaterAsync(Runnable runnable, long delay) { public void runLaterAsync(Runnable runnable, long delay) {
Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, runnable, delay); Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, runnable, delay);

@ -13,6 +13,7 @@ public abstract class TaskScheduler {
public abstract void schedulePlayerChat(Player player, String message); public abstract void schedulePlayerChat(Player player, String message);
public abstract void schedulePlayerCommand(Player player, String command); public abstract void schedulePlayerCommand(Player player, String command);
public abstract void runSyncGlobal(Runnable runnable); public abstract void runSyncGlobal(Runnable runnable);
public abstract void runAsyncGlobal(Runnable runnable);
public abstract void runLaterAsync(Runnable runnable, long delay); public abstract void runLaterAsync(Runnable runnable, long delay);
public abstract void runDelayedTimerAsync(Runnable runnable, long delay, long interval); public abstract void runDelayedTimerAsync(Runnable runnable, long delay, long interval);
public abstract void cancelAll(); public abstract void cancelAll();

@ -42,7 +42,7 @@ public class MojangSkinCache {
Player player = Bukkit.getPlayerExact(name); Player player = Bukkit.getPlayerExact(name);
if (player != null && player.isOnline()) return CompletableFuture.completedFuture(getFromPlayer(player)); if (player != null && player.isOnline()) return CompletableFuture.completedFuture(getFromPlayer(player));
if (cache.containsKey(name.toLowerCase())) return fetchByUUID(idCache.get(name.toLowerCase()).getId()); if (idCache.containsKey(name.toLowerCase())) return fetchByUUID(idCache.get(name.toLowerCase()).getId());
return CompletableFuture.supplyAsync(() -> { return CompletableFuture.supplyAsync(() -> {
URL url = parseUrl("https://api.mojang.com/users/profiles/minecraft/" + name); URL url = parseUrl("https://api.mojang.com/users/profiles/minecraft/" + name);
@ -52,14 +52,52 @@ public class MojangSkinCache {
connection.setRequestMethod("GET"); connection.setRequestMethod("GET");
try (Reader reader = new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8)) { try (Reader reader = new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8)) {
JsonObject obj = JsonParser.parseReader(reader).getAsJsonObject(); JsonObject obj = JsonParser.parseReader(reader).getAsJsonObject();
if (obj.has("errorMessage")) return null; if (obj.has("errorMessage")) return fetchByNameFallback(name).join();
String id = obj.get("id").getAsString(); String id = obj.get("id").getAsString();
idCache.put(name.toLowerCase(), new CachedId(id)); idCache.put(name.toLowerCase(), new CachedId(id));
return fetchByUUID(id).join(); Skin skin = fetchByUUID(id).join();
if (skin == null) return fetchByNameFallback(name).join();
return skin;
} }
} catch (IOException exception) { } catch (IOException exception) {
if (!configManager.getConfig().disableSkinFetcherWarnings()) { if (!configManager.getConfig().disableSkinFetcherWarnings()) {
logger.warning("Failed to get uuid from player name:"); logger.warning("Failed to get uuid from player name, trying to use fallback server:");
exception.printStackTrace();
}
return fetchByNameFallback(name).join();
} finally {
if (connection != null) connection.disconnect();
}
});
}
public CompletableFuture<Skin> fetchByNameFallback(String name) {
Player player = Bukkit.getPlayerExact(name);
if (player != null && player.isOnline()) return CompletableFuture.completedFuture(getFromPlayer(player));
if (idCache.containsKey(name.toLowerCase())) return fetchByUUID(idCache.get(name.toLowerCase()).getId());
return CompletableFuture.supplyAsync(() -> {
URL url = parseUrl("https://api.ashcon.app/mojang/v2/user/" + name);
HttpURLConnection connection = null;
try {
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
try (Reader reader = new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8)) {
JsonObject obj = JsonParser.parseReader(reader).getAsJsonObject();
if (obj.has("error")) return null;
String uuid = obj.get("uuid").getAsString();
idCache.put(name.toLowerCase(), new CachedId(uuid));
JsonObject textures = obj.get("textures").getAsJsonObject();
String value = textures.get("raw").getAsJsonObject().get("value").getAsString();
String signature = textures.get("raw").getAsJsonObject().get("signature").getAsString();
Skin skin = new Skin(value, signature);
cache.put(uuid, skin);
return skin;
}
} catch (IOException exception) {
if (!configManager.getConfig().disableSkinFetcherWarnings()) {
logger.warning("Failed to fetch skin from fallback server:");
exception.printStackTrace(); exception.printStackTrace();
} }
} finally { } finally {
@ -105,13 +143,14 @@ public class MojangSkinCache {
connection.setRequestMethod("GET"); connection.setRequestMethod("GET");
try (Reader reader = new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8)) { try (Reader reader = new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8)) {
JsonObject obj = JsonParser.parseReader(reader).getAsJsonObject(); JsonObject obj = JsonParser.parseReader(reader).getAsJsonObject();
if (obj.has("errorMessage")) return null;
Skin skin = new Skin(obj); Skin skin = new Skin(obj);
cache.put(uuid, skin); cache.put(uuid, skin);
return skin; return skin;
} }
} catch (IOException exception) { } catch (IOException exception) {
if (!configManager.getConfig().disableSkinFetcherWarnings()) { if (!configManager.getConfig().disableSkinFetcherWarnings()) {
logger.warning("Failed to fetch skin:"); logger.warning("Failed to fetch skin, trying to use fallback server:");
exception.printStackTrace(); exception.printStackTrace();
} }
} finally { } finally {