Skip to content

Commit

Permalink
Modernize server list ping event determinations (#2585)
Browse files Browse the repository at this point in the history
* Modernize `server list ping` event

* Fix strange new line?

I must have accidentally pressed enter

* Add prefixes for `MOTD` and `max_players`
  • Loading branch information
BreadcrumbIsTaken committed Jan 7, 2024
1 parent ca689a5 commit df669a2
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 104 deletions.
Expand Up @@ -4,12 +4,10 @@
import com.denizenscript.denizen.objects.PlayerTag;
import com.denizenscript.denizen.paper.PaperModule;
import com.denizenscript.denizencore.utilities.debugging.Debug;
import com.denizenscript.denizencore.objects.ArgumentHelper;
import com.denizenscript.denizencore.objects.ObjectTag;
import com.denizenscript.denizencore.objects.core.ElementTag;
import com.denizenscript.denizencore.objects.core.ListTag;
import com.denizenscript.denizencore.utilities.CoreConfiguration;
import com.denizenscript.denizencore.utilities.CoreUtilities;
import com.destroystokyo.paper.event.server.PaperServerListPingEvent;
import com.destroystokyo.paper.profile.PlayerProfile;
import com.destroystokyo.paper.profile.ProfileProperty;
Expand All @@ -25,6 +23,46 @@

public class ServerListPingScriptEventPaperImpl extends ListPingScriptEvent {

public ServerListPingScriptEventPaperImpl() {
this.<ServerListPingScriptEventPaperImpl, ElementTag>registerOptionalDetermination("protocol_version", ElementTag.class, (evt, context, version) -> {
if (version.isInt()) {
((PaperServerListPingEvent) event).setProtocolVersion(version.asInt());
return true;
}
return false;
});
this.<ServerListPingScriptEventPaperImpl, ElementTag>registerOptionalDetermination("version_name", ElementTag.class, (evt, context, name) -> {
((PaperServerListPingEvent) event).setVersion(name.toString());
return true;
});
this.<ServerListPingScriptEventPaperImpl, ListTag>registerOptionalDetermination("exclude_players", ListTag.class, (evt, context, list) -> {
HashSet<UUID> exclusions = new HashSet<>();
for (PlayerTag player : list.filter(PlayerTag.class, context)) {
exclusions.add(player.getUUID());
}
Iterator<Player> players = ((PaperServerListPingEvent) event).iterator();
while (players.hasNext()) {
if (exclusions.contains(players.next().getUniqueId())) {
players.remove();
}
}
return true;
});
this.<ServerListPingScriptEventPaperImpl, ListTag>registerOptionalDetermination("alternate_player_text", ListTag.class, (evt, context, text) -> {
if (!CoreConfiguration.allowRestrictedActions) {
Debug.echoError("Cannot use 'alternate_player_text' in list ping event: 'Allow restricted actions' is disabled in Denizen config.yml.");
return false;
}
((PaperServerListPingEvent) event).getPlayerSample().clear();
for (String line : text) {
FakeProfile lineProf = new FakeProfile();
lineProf.setName(line);
((PaperServerListPingEvent) event).getPlayerSample().add(lineProf);
}
return true;
});
}

public static class FakeProfile implements PlayerProfile {
public String name;
@Override public @Nullable String getName() {
Expand Down Expand Up @@ -57,65 +95,20 @@ public static class FakeProfile implements PlayerProfile {
@Override public @NotNull Map<String, Object> serialize() { return null; }
}

@Override
public boolean applyDetermination(ScriptPath path, ObjectTag determinationObj) {
String determination = determinationObj.toString();
String lower = CoreUtilities.toLowerCase(determination);
if (lower.startsWith("protocol_version:") && ArgumentHelper.matchesInteger(determination.substring("protocol_version:".length()))) {
((PaperServerListPingEvent) event).setProtocolVersion(Integer.parseInt(determination.substring("protocol_version:".length())));
return true;
}
else if (lower.startsWith("version_name:")) {
((PaperServerListPingEvent) event).setVersion(determination.substring("version_name:".length()));
return true;
}
else if (lower.startsWith("exclude_players:")) {
HashSet<UUID> exclusions = new HashSet<>();
for (PlayerTag player : ListTag.valueOf(determination.substring("exclude_players:".length()), getTagContext(path)).filter(PlayerTag.class, getTagContext(path))) {
exclusions.add(player.getUUID());
}
Iterator<Player> players = ((PaperServerListPingEvent) event).iterator();
while (players.hasNext()) {
if (exclusions.contains(players.next().getUniqueId())) {
players.remove();
}
}
return true;
}
else if (lower.startsWith("alternate_player_text:")) {
if (!CoreConfiguration.allowRestrictedActions) {
Debug.echoError("Cannot use 'alternate_player_text' in list ping event: 'Allow restricted actions' is disabled in Denizen config.yml.");
return true;
}
((PaperServerListPingEvent) event).getPlayerSample().clear();
for (String line : ListTag.valueOf(determination.substring("alternate_player_text:".length()), getTagContext(path))) {
FakeProfile lineProf = new FakeProfile();
lineProf.setName(line);
((PaperServerListPingEvent) event).getPlayerSample().add(lineProf);
}
return true;
}
return super.applyDetermination(path, determinationObj);
}

@Override
public void setMotd(String text) {
event.motd(PaperModule.parseFormattedText(text, ChatColor.WHITE));
}

@Override
public ObjectTag getContext(String name) {
switch (name) {
case "motd":
return new ElementTag(PaperModule.stringifyComponent(event.motd()));
case "protocol_version":
return new ElementTag(((PaperServerListPingEvent) event).getProtocolVersion());
case "version_name":
return new ElementTag(((PaperServerListPingEvent) event).getVersion());
case "client_protocol_version":
return new ElementTag(((PaperServerListPingEvent) event).getClient().getProtocolVersion());
}
return super.getContext(name);
return switch (name) {
case "motd" -> new ElementTag(PaperModule.stringifyComponent(event.motd()));
case "protocol_version" -> new ElementTag(((PaperServerListPingEvent) event).getProtocolVersion());
case "version_name" -> new ElementTag(((PaperServerListPingEvent) event).getVersion());
case "client_protocol_version" -> new ElementTag(((PaperServerListPingEvent) event).getClient().getProtocolVersion());
default -> super.getContext(name);
};
}

@EventHandler
Expand Down
Expand Up @@ -6,7 +6,7 @@
import com.denizenscript.denizencore.objects.ArgumentHelper;
import com.denizenscript.denizencore.objects.core.ElementTag;
import com.denizenscript.denizencore.objects.ObjectTag;
import com.denizenscript.denizencore.utilities.CoreUtilities;
import com.denizenscript.denizencore.objects.core.ListTag;
import com.denizenscript.denizencore.utilities.debugging.Debug;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
Expand All @@ -16,7 +16,6 @@

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

Expand All @@ -40,35 +39,43 @@ public class ListPingScriptEvent extends BukkitScriptEvent implements Listener {
// <context.client_protocol_version> returns the client's protocol version ID (only on Paper).
//
// @Determine
// ElementTag(Number) to change the max player amount that will show.
// "MAX_PLAYERS:<ElementTag(Number)>" to change the max player amount that will show.
// "ICON:<ElementTag>" of a file path to an icon image, to change the icon that will display.
// "PROTOCOL_VERSION:<ElementTag(Number)>" to change the protocol ID number of the server's version (only on Paper).
// "VERSION_NAME:<ElementTag>" to change the server's version name (only on Paper).
// "EXCLUDE_PLAYERS:<ListTag(PlayerTag)>" to exclude a set of players from showing in the player count or preview of online players (only on Paper).
// "ALTERNATE_PLAYER_TEXT:<ListTag>" to set custom text for the player list section of the server status (only on Paper). (Requires "Allow restricted actions" in Denizen/config.yml). Usage of this to present lines that look like player names (but aren't) is forbidden.
// ElementTag to change the MOTD that will show.
// "MOTD:<ElementTag>" to change the MOTD that will show.
//
// -->

public ListPingScriptEvent() {
registerCouldMatcher("server list ping");
}

public ServerListPingEvent event;

// Despite the 'cached' class name, there's no actual internal cache.
public static HashMap<String, CachedServerIcon> iconCache = new HashMap<>();

public void setMotd(String text) {
event.setMotd(text);
}

@Override
public boolean applyDetermination(ScriptPath path, ObjectTag determinationObj) {
String determination = determinationObj.toString();
String determineLow = CoreUtilities.toLowerCase(determination);
if (determineLow.startsWith("icon:")) {
String iconFile = determination.substring("icon:".length());
this.<ListPingScriptEvent, ListTag>registerOptionalDetermination(null, ListTag.class, (evt, context, list) -> {
if (ArgumentHelper.matchesInteger(list.get(0))) {
evt.event.setMaxPlayers(Integer.parseInt(list.get(0)));
if (list.size() == 2) {
setMotd(list.get(1));
}
}
else {
setMotd(list.get(0));
}
return true;
});
this.<ListPingScriptEvent, ElementTag>registerOptionalDetermination("max_players", ElementTag.class, (evt, context, max) -> {
if (max.isInt()) {
evt.event.setMaxPlayers(max.asInt());
return true;
}
return false;
});
this.<ListPingScriptEvent, ElementTag>registerOptionalDetermination("motd", ElementTag.class, (evt, context, motd) -> {
setMotd(motd.toString());
return true;
});
this.<ListPingScriptEvent, ElementTag>registerOptionalDetermination("icon", ElementTag.class, (evt, context, iconPath) -> {
String iconFile = iconPath.toString();
CachedServerIcon icon = iconCache.get(iconFile);
if (icon != null) {
event.setServerIcon(icon);
Expand All @@ -88,40 +95,31 @@ public boolean applyDetermination(ScriptPath path, ObjectTag determinationObj) {
if (icon != null) {
iconCache.put(iconFile, icon);
event.setServerIcon(icon);
return true;
}
return true;
}
if (determination.length() > 0 && !determineLow.equalsIgnoreCase("none")) {
List<String> values = CoreUtilities.split(determination, '|', 2);
if (ArgumentHelper.matchesInteger(values.get(0))) {
event.setMaxPlayers(Integer.parseInt(values.get(0)));
if (values.size() == 2) {
setMotd(values.get(1));
}
}
else {
setMotd(determination);
}
return true;
}
else {
return super.applyDetermination(path, determinationObj);
}
return false;
});
}


public ServerListPingEvent event;

// Despite the 'cached' class name, there's no actual internal cache.
public static HashMap<String, CachedServerIcon> iconCache = new HashMap<>();

public void setMotd(String text) {
event.setMotd(text);
}

@Override
public ObjectTag getContext(String name) {
switch (name) {
case "motd":
return new ElementTag(event.getMotd());
case "max_players":
return new ElementTag(event.getMaxPlayers());
case "num_players":
return new ElementTag(event.getNumPlayers());
case "address":
return new ElementTag(event.getAddress().toString());
}
return super.getContext(name);
return switch (name) {
case "motd" -> new ElementTag(event.getMotd());
case "max_players" -> new ElementTag(event.getMaxPlayers());
case "num_players" -> new ElementTag(event.getNumPlayers());
case "address" -> new ElementTag(event.getAddress().toString());
default -> super.getContext(name);
};
}

public void syncFire(ServerListPingEvent event) {
Expand Down

0 comments on commit df669a2

Please sign in to comment.