Compare commits

...
22 Commits
Author SHA1 Message Date
Andre601 9b43428e5d Another fix for changelog... 2023-02-01 15:47:18 +01:00
Andre601 d34d926f9a Fix wrong version in api changelog 2023-02-01 15:46:57 +01:00
Andre601 844279b32d Rename the other Placeholder classes too. 2023-02-01 15:38:00 +01:00
Andre601 5916e9b495 Version was already bumped... whoops 2023-02-01 15:31:56 +01:00
Andre_601 72384488d8 Merge pull request #45 from Andre601/feature/events
Add PreServerListSetEvent
2023-02-01 15:29:38 +01:00
Andre601 11a8b07f32 Bump version 2023-02-01 15:24:13 +01:00
Andre601 cd7dfc9c15 Rename to resolve 2023-01-31 18:12:43 +01:00
Andre601 c715ed6163 Make values of Expression final 2023-01-31 18:12:21 +01:00
Andre601 5a35ebbef4 Trim left and right string to avoid comparison issues 2023-01-31 17:17:10 +01:00
Andre601 830eee5da3 Fix missing favicon from resolver. 2023-01-28 23:22:08 +01:00
Andre601 09b845e86e Changes 2023-01-28 23:13:41 +01:00
Andre601 a2bdd5c4e5 Add changelog file 2023-01-27 14:59:12 +01:00
Andre601 a72c0d326a Update to latest API changes 2023-01-27 00:59:29 +01:00
Andre601 40ef2e35d4 Make GenericPlayer.getVersion VelocityPlayer only 2023-01-25 22:13:39 +01:00
Andre601 8422d6d2de Minor doc improvements 2023-01-25 16:19:43 +01:00
Andre601 4683dab513 limit motd in ProfileEntry.Builder directly 2023-01-25 16:15:07 +01:00
Andre601 d5947b20e5 Update docs 2023-01-25 01:11:45 +01:00
Andre601 147f01dd1b Rename GenericProfileEntryEvent to GenericServerListEvent 2023-01-25 00:29:07 +01:00
Andre601 a6eddb3828 Remove unused method in ComponentParser 2023-01-25 00:05:09 +01:00
Andre601 41e11f79cc Move ProfileEntry completely. 2023-01-25 00:01:51 +01:00
Andre601 66597ce7fa Add PreServerListSetEvent 2023-01-24 23:38:23 +01:00
Andre_601 77f17b202c Update MODRINTH.md 2023-01-23 21:28:57 +01:00
51 changed files with 692 additions and 1018 deletions

No files matched your search

+4 -8
View File
@@ -76,14 +76,10 @@ You can disable this in the global bStats config file located in `/plugins/bstat
</a>
<!-- Links -->
[profiles]: https://github.com/Andre601/AdvancedServerList/wiki/Profiles
[conditions]: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#conditions
[placeholders]: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#placeholders
[minimessage]: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#minimessage
[placeholderapi]: https://www.spigotmc.org/resources/6245/
[modrinth]: https://modrinth.com/plugin/advancedserverlist
[profiles]: https://andre601.ch/AdvancedServerList/profiles
[conditions]: https://andre601.ch/AdvancedServerList/profiles/#conditions
[placeholders]: https://andre601.ch/AdvancedServerList/profiles/placeholders
[minimessage]: https://andre601.ch/AdvancedServerList/profiles/formatting
[protocollib]: https://www.spigotmc.org/resources/1997/
[placeholderapi]: https://www.spigotmc.org/resources/6245/
-59
View File
@@ -1,59 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ MIT License
~
~ Copyright (c) 2022-2023 Andre_601
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy
~ of this software and associated documentation files (the "Software"), to deal
~ in the Software without restriction, including without limitation the rights
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
~ copies of the Software, and to permit persons to whom the Software is
~ furnished to do so, subject to the following conditions:
~
~ The above copyright notice and this permission notice shall be included in all
~ copies or substantial portions of the Software.
~
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
~ SOFTWARE.
~
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>parent</artifactId>
<groupId>ch.andre601.advancedserverlist</groupId>
<version>parent</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>api</artifactId>
<packaging>jar</packaging>
<version>${plugin.version}</version>
<description>${plugin.description}</description>
<properties>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<finalName>AdvancedServerList-API-${plugin.version}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
</plugin>
</plugins>
</build>
</project>
@@ -1,98 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022-2023 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.api;
import ch.andre601.advancedserverlist.api.internal.CheckUtil;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
* Core class of the API for AdvancedServerList.
* <br>Use {@link #get() get()} to retrieve the instance currently used.
*/
public class AdvancedServerListAPI{
private static AdvancedServerListAPI instance;
private final Map<String, PlaceholderProvider> placeholderProviders = new HashMap<>();
private AdvancedServerListAPI(){}
/**
* Retrieves the instance used of this API.
* <br>If no instance has been made so far will a new one be created.
*
* @return Instance of this API.
*/
public static AdvancedServerListAPI get(){
if(instance != null)
return instance;
return (instance = new AdvancedServerListAPI());
}
/**
* Adds the provided {@link PlaceholderProvider PlaceholderProvider} to the list, if it passes the following checks:
* <ul>
* <li>The identifier is not null or empty.</li>
* <li>The identifier does not contain any spaces.</li>
* <li>A PlaceholderProvider with the same identifier doesn't exist already.</li>
* </ul>
* Not passing any of the above checks results in a
* {@link ch.andre601.advancedserverlist.api.exceptions.InvalidPlaceholderProviderException InvalidPlaceholderProviderException}
* being thrown.
*
* @param placeholderProvider
* The {@link PlaceholderProvider PlaceholderProvider} to add.
*
* @throws ch.andre601.advancedserverlist.api.exceptions.InvalidPlaceholderProviderException
* When the provided {@link PlaceholderProvider PlaceholderProvider instance} has a null or empty identifier,
* the identifier contains spaces or another provider with the same identifier is already loaded.
*/
public void addPlaceholderProvider(PlaceholderProvider placeholderProvider){
CheckUtil.notEmpty(placeholderProvider.getIdentifier(), "Identifier");
String identifier = placeholderProvider.getIdentifier().toLowerCase(Locale.ROOT);
CheckUtil.check(identifier.contains(" "), "Identifier may not contain spaces.");
CheckUtil.check(placeholderProviders.containsKey(identifier), "A PlaceholderProvider with name " + identifier + " already exists.");
placeholderProviders.put(identifier, placeholderProvider);
}
/**
* Retrieves the {@link PlaceholderProvider PlaceholderProvider} associated with the given identifier, or {@code null}
* should no such entry exist.
*
* @param identifier
* The identifier to find a matching {@link PlaceholderProvider PlaceholderProvider} for.
*
* @return Possibly-null {@link PlaceholderProvider PlaceholderProvider instance}.
*/
public PlaceholderProvider retrievePlaceholderProvider(String identifier){
return placeholderProviders.get(identifier.toLowerCase(Locale.ROOT));
}
}
@@ -1,97 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022-2023 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.api;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
/**
* Abstract class that is used to provide your own Placeholder patterns for AdvancedServerList to parse.
*
* <p>In order for your class to be considered a valid PlaceholderProvider will you need to set the
* {@link #identifier identifier} to a non-null, non-empty value without having any spaces in it.
* <br>Once set, use {@link ch.andre601.advancedserverlist.api.AdvancedServerListAPI#addPlaceholderProvider(PlaceholderProvider) AdvancedServerListAPI#addPlaceholderProvider(PlaceholderProvider)}
* to register your class for AdvancedServerList to use.
*/
public abstract class PlaceholderProvider{
private final String identifier;
/**
* Constructor used to set the identifier for the class extending the PlaceholderProvider class.
*
* <h2>Example</h2>
* <pre>{@code
* public class MyPlaceholders extends PlaceholderProvider {
*
* public MyPlaceholders() {
* super("myplaceholders");
* }
*
* @Override
* public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server) {
* if(placeholder.equals("hello")
* return "Hi!";
*
* return null;
* }
* }
* }</pre>
*
* @param identifier
* The identifier to use for the placeholder. Shouldn't be null nor empty.
*/
public PlaceholderProvider(String identifier){
this.identifier = identifier;
}
/**
* Method called by AdvancedServerList's StringReplacer class to replace any appearances of
* {@code ${<identifier> <placeholder>}} with whatever value a PlaceholderProvider may return.
*
* <p>Returning {@code null} will be treated as an invalid placeholder, returning the full placeholder as-is without
* any changes made.
*
* @param placeholder
* The part of the placeholder after the identifier ({@code ${<identifier> <placeholder>}}
* @param player
* The {@link GenericPlayer GenericPlayer instance} used.
* @param server
* The {@link GenericServer GenericServer instance} used.
*
* @return Parsed String based on the PlaceholderProvider or {@code null} for invalid placeholders.
*/
public abstract String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server);
/**
* Returns the identifier used by this instance.
*
* @return String containing the identifier used by this instance.
*/
public String getIdentifier(){
return identifier;
}
}
@@ -1,136 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022-2023 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.api.objects;
import java.util.UUID;
/**
* A basic abstract class used to store generic player data with to use in placeholder resolving.
* <br>The different variants of AdvancedServerList extend their own class with this one and may or may not use all values
* available here.
*
* <p>The following values will always be present, no matter the platform this class is used on:
* <ul>
* <li>{@link #getName() Name of Player}</li>
* <li>{@link #getProtocol() Protocol version of Player}</li>
* <li>{@link #getUUID() UUID of Player}</li>
* </ul>
* Any other value is not guaranteed to be accurate or even be set.
*/
public abstract class GenericPlayer{
protected String name = null;
protected int protocol = -1;
protected UUID uuid = null;
protected String version = null;
protected boolean playedBefore = false;
protected boolean banned = false;
protected boolean whitelisted = false;
/**
* Returns the name of the player.
* <br>Note that on Spigot, Paper and other forks can the name differ from the one cached by AdvancedServerList,
* if the plugin was able to retrieve an OfflinePlayer instance from the server. On BungeeCord and Velocity will
* the returned String always be the name from the cache.
*
* <p>Name may be whatever has been defined in AdvancedServerList's config.yml, should the player not be cached yet
* by AdvancedServerList.
*
* @return String representing the player's name.
*/
public String getName(){
return name;
}
/**
* Returns the protocol ID the player is using. The protocol ID is an integer used by Minecraft to determine what
* version a server or client is running.
*
* @return Integer representing the protocol version of this player.
*/
public int getProtocol(){
return protocol;
}
/**
* Returns the Unique ID associated with this player.
*
* <p>UUID may be whatever has been defined in AdvancedServerList's config.yml, should the player not be cached yet
* by AdvancedServerList.
*
* @return UUID of the player.
*/
public UUID getUUID(){
return uuid;
}
/**
* Returns the {@link #getProtocol() protocol version} in a readable MC version format (i.e. 1.19.3).
*
* <p>This only works on Velocity and will return {@code null} for any other platform.
*
* @return The readable MC version the player uses.
*/
public String getVersion(){
return version;
}
/**
* Returns whether this player has played on the Server before.
*
* <p>The returned boolean is <b>always</b> false on BungeeCord and Velocity due to a lack of any offline player data
* storage.
*
* @return Boolean indicating whether this player has played on this Server before.
*/
public boolean hasPlayedBefore() {
return playedBefore;
}
/**
* Returns whether this player is banned on the server.
*
* <p>The returned boolean is <b>always</b> false on BungeeCord and Velocity due to a lack of any offline player data
* storage.
*
* @return Boolean indicating whether this player was banned from the server.
*/
public boolean isBanned(){
return banned;
}
/**
* Returns whether this player is whitelisted on the server.
*
* <p>The returned boolean is <b>always</b> false on BungeeCord and Velocity due to a lack of any offline player data
* storage.
*
* @return Boolean indicating whether this player was banned from the server.
*/
public boolean isWhitelisted(){
return whitelisted;
}
}
@@ -1,70 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022-2023 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.api.objects;
/**
* Simple class used to wrap around some generic server data such as online player count, amount of total players that
* can join and the host (IP/Domain) that got pinged by the player.
*/
public class GenericServer{
private final int playersOnline;
private final int playersMax;
private final String host;
public GenericServer(int playersOnline, int playersMax, String host){
this.playersOnline = playersOnline;
this.playersMax = playersMax;
this.host = host;
}
/**
* Returns the number of players currently online on the server.
*
* @return Number of players online on the server.
*/
public int getPlayersOnline(){
return playersOnline;
}
/**
* Returns the number of total players that can join the server.
*
* @return Number of total players that can join the server.
*/
public int getPlayersMax(){
return playersMax;
}
/**
* Returns the IP/Domain that got pinged by the player.
*
* @return Possibly-null String containing the IP/Domain that got pinged by the player.
*/
public String getHost(){
return host;
}
}
+6
View File
@@ -58,6 +58,12 @@
<version>${plugin.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.andre601.asl-api</groupId>
<artifactId>platform-bungeecord</artifactId>
<version>${api.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
@@ -25,30 +25,23 @@
package ch.andre601.advancedserverlist.bungeecord;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.bungeecord.commands.CmdAdvancedServerList;
import ch.andre601.advancedserverlist.bungeecord.events.JoinEvent;
import ch.andre601.advancedserverlist.bungeecord.events.PingEvent;
import ch.andre601.advancedserverlist.bungeecord.logging.BungeeLogger;
import ch.andre601.advancedserverlist.bungeecord.objects.BungeePlayer;
import ch.andre601.advancedserverlist.bungeecord.objects.PlayerPlaceholders;
import ch.andre601.advancedserverlist.bungeecord.objects.BungeePlayerPlaceholders;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
import net.md_5.bungee.api.Favicon;
import net.md_5.bungee.api.ServerPing;
import net.md_5.bungee.api.plugin.Plugin;
import org.bstats.bungeecord.Metrics;
import org.bstats.charts.SimplePie;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class BungeeCordCore extends Plugin implements PluginCore<Favicon, ServerPing.PlayerInfo, BungeePlayer>{
public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
private AdvancedServerList core;
private FaviconHandler<Favicon> faviconHandler = null;
@@ -56,7 +49,7 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon, Server
@Override
public void onEnable(){
this.core = new AdvancedServerList(this, new PlayerPlaceholders());
this.core = new AdvancedServerList(this, new BungeePlayerPlaceholders());
}
@Override
@@ -128,19 +121,4 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon, Server
public String getLoader(){
return "bungeecord";
}
@Override
public List<ServerPing.PlayerInfo> createPlayers(List<String> lines, BungeePlayer player, GenericServer server){
List<ServerPing.PlayerInfo> players = new ArrayList<>(lines.size());
for(String line : lines){
String parsed = ComponentParser.text(line)
.applyReplacements(player, server)
.toString();
players.add(new ServerPing.PlayerInfo(parsed, UUID.randomUUID()));
}
return players;
}
}
@@ -26,11 +26,15 @@
package ch.andre601.advancedserverlist.bungeecord.events;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
import ch.andre601.advancedserverlist.bungeecord.objects.BungeePlayer;
import ch.andre601.advancedserverlist.bungeecord.objects.BungeePlayerImpl;
import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.interfaces.events.GenericEventWrapper;
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
import net.md_5.bungee.api.Favicon;
@@ -41,8 +45,9 @@ import net.md_5.bungee.api.event.ProxyPingEvent;
import java.awt.image.BufferedImage;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.UUID;
public class BungeeEventWrapper implements GenericEventWrapper<Favicon, ServerPing.PlayerInfo, BungeePlayer>{
public class BungeeEventWrapper implements GenericEventWrapper<Favicon, BungeePlayerImpl>{
private final BungeeCordCore plugin;
private final ProxyPingEvent event;
@@ -56,6 +61,14 @@ public class BungeeEventWrapper implements GenericEventWrapper<Favicon, ServerPi
this.ping = event.getResponse();
}
@Override
public GenericServerListEvent callEvent(ProfileEntry entry){
PreServerListSetEventImpl event = new PreServerListSetEventImpl(entry);
plugin.getProxy().getPluginManager().callEvent(event);
return event;
}
@Override
public void setMaxPlayers(int maxPlayers){
ping.getPlayers().setMax(maxPlayers);
@@ -78,11 +91,20 @@ public class BungeeEventWrapper implements GenericEventWrapper<Favicon, ServerPi
}
@Override
public void setPlayers(List<String> players, BungeePlayer player, GenericServer server){
ServerPing.PlayerInfo[] playerInfos = plugin.createPlayers(players, player, server).toArray(new ServerPing.PlayerInfo[0]);
public void setPlayers(List<String> lines, BungeePlayerImpl player, GenericServer server){
ServerPing.PlayerInfo[] players = new ServerPing.PlayerInfo[lines.size()];
if(playerInfos.length > 0)
ping.getPlayers().setSample(playerInfos);
for(int i = 0; i < players.length; i++){
String parsed = ComponentParser.text(lines.get(i))
.modifyText(text -> StringReplacer.replace(text, player, server))
.toString();
ServerPing.PlayerInfo pi = new ServerPing.PlayerInfo(parsed, UUID.randomUUID());
players[i] = pi;
}
if(players.length > 0)
ping.getPlayers().setSample(players);
}
@Override
@@ -127,7 +149,7 @@ public class BungeeEventWrapper implements GenericEventWrapper<Favicon, ServerPi
}
@Override
public String parsePAPIPlaceholders(String text, BungeePlayer player){
public String parsePAPIPlaceholders(String text, BungeePlayerImpl player){
return text;
}
@@ -137,13 +159,13 @@ public class BungeeEventWrapper implements GenericEventWrapper<Favicon, ServerPi
}
@Override
public PluginCore<Favicon, ServerPing.PlayerInfo, BungeePlayer> getPlugin(){
public PluginCore<Favicon> getPlugin(){
return plugin;
}
@Override
public BungeePlayer createPlayer(CachedPlayer player, int protocol){
return new BungeePlayer(player, protocol);
public BungeePlayerImpl createPlayer(CachedPlayer player, int protocol){
return new BungeePlayerImpl(player, protocol);
}
@Override
@@ -23,15 +23,13 @@
*
*/
package ch.andre601.advancedserverlist.api.exceptions;
package ch.andre601.advancedserverlist.bungeecord.events;
/**
* RuntimeException thrown whenever an invalid {@link ch.andre601.advancedserverlist.api.PlaceholderProvider PlaceholderProvider}
* has been given.
*/
public class InvalidPlaceholderProviderException extends RuntimeException{
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
public class PreServerListSetEventImpl extends PreServerListSetEvent{
public InvalidPlaceholderProviderException(String msg){
super(msg);
public PreServerListSetEventImpl(ProfileEntry entry){
super(entry);
}
}
@@ -25,12 +25,12 @@
package ch.andre601.advancedserverlist.bungeecord.objects;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
import ch.andre601.advancedserverlist.core.profiles.players.GenericPlayerImpl;
public class BungeePlayer extends GenericPlayer{
public class BungeePlayerImpl extends GenericPlayerImpl{
public BungeePlayer(CachedPlayer player, int protocol){
public BungeePlayerImpl(CachedPlayer player, int protocol){
this.name = player.getName();
this.protocol = protocol;
this.uuid = player.getUuid();
@@ -31,9 +31,9 @@ import ch.andre601.advancedserverlist.api.objects.GenericServer;
import java.util.Locale;
public class PlayerPlaceholders extends PlaceholderProvider{
public class BungeePlayerPlaceholders extends PlaceholderProvider{
public PlayerPlaceholders(){
public BungeePlayerPlaceholders(){
super("player");
}
+3 -2
View File
@@ -52,9 +52,10 @@
<dependencies>
<dependency>
<groupId>ch.andre601.advancedserverlist</groupId>
<groupId>ch.andre601.asl-api</groupId>
<artifactId>api</artifactId>
<version>${plugin.version}</version>
<version>${api.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.spongepowered</groupId>
@@ -27,11 +27,11 @@ package ch.andre601.advancedserverlist.core;
import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
import ch.andre601.advancedserverlist.api.internal.ServerPlaceholders;
import ch.andre601.advancedserverlist.core.check.UpdateChecker;
import ch.andre601.advancedserverlist.core.commands.CommandHandler;
import ch.andre601.advancedserverlist.core.file.FileHandler;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.objects.ServerPlaceholders;
import ch.andre601.advancedserverlist.core.profiles.players.PlayerHandler;
import java.io.IOException;
@@ -41,7 +41,7 @@ import java.util.Properties;
public class AdvancedServerList{
private final PluginCore<?, ?, ?> plugin;
private final PluginCore<?> plugin;
private final FileHandler fileHandler;
private final CommandHandler commandHandler;
private final PlayerHandler playerHandler;
@@ -51,18 +51,19 @@ public class AdvancedServerList{
private String version;
public AdvancedServerList(PluginCore<?, ?, ?> plugin, PlaceholderProvider player){
public AdvancedServerList(PluginCore<?> plugin, PlaceholderProvider player){
this.plugin = plugin;
this.fileHandler = new FileHandler(this);
this.commandHandler = new CommandHandler(this);
this.playerHandler = new PlayerHandler(this);
this.api.addPlaceholderProvider(player);
this.api.addPlaceholderProvider(new ServerPlaceholders());
load();
}
public PluginCore<?, ?, ?> getPlugin(){
public PluginCore<?> getPlugin(){
return plugin;
}
@@ -25,23 +25,25 @@
package ch.andre601.advancedserverlist.core.events;
import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.interfaces.events.GenericEventWrapper;
import ch.andre601.advancedserverlist.core.objects.GenericServerImpl;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileEntry;
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileManager;
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
public class PingEventHandler{
public static <F, PL, P extends GenericPlayer> void handleEvent(GenericEventWrapper<F, PL, P> event){
public static <F, P extends GenericPlayer> void handleEvent(GenericEventWrapper<F, P> event){
if(event.isInvalidProtocol())
return;
PluginCore<F, PL, P> plugin = event.getPlugin();
PluginCore<F> plugin = event.getPlugin();
String host = event.getVirtualHost();
int online = event.getOnlinePlayers();
@@ -51,53 +53,57 @@ public class PingEventHandler{
plugin.getCore().getPlayerHandler().getCachedPlayer(event.getPlayerIP()),
event.getProtocolVersion()
);
GenericServer server = new GenericServer(online, max, host);
ServerListProfile profile = ProfileManager.get(plugin.getCore())
.applyReplacements(player, server)
.getProfile();
GenericServer server = new GenericServerImpl(online, max, host);
ServerListProfile profile = ProfileManager.resolveProfile(plugin.getCore(), player, server);
if(profile == null)
return;
ProfileEntry entry = ProfileManager.merge(profile);
if(entry.isExtraPlayersEnabled().getValue(false)){
GenericServerListEvent e = event.callEvent(ProfileManager.merge(profile));
if(e == null || e.isCancelled())
return;
ProfileEntry entry = e.getEntry();
if(entry.isInvalid())
return;
if(ProfileManager.checkOption(entry.isExtraPlayersEnabled())){
max = online + (entry.getExtraPlayersCount() == null ? 0 : entry.getExtraPlayersCount());
event.setMaxPlayers(max);
}
server = new GenericServer(online, max, host);
GenericServer finalServer = new GenericServerImpl(online, max, host);
if(!entry.getMOTD().isEmpty()){
if(ProfileManager.checkOption(entry.getMotd())){
event.setMotd(
ComponentParser.list(entry.getMOTD())
.applyReplacements(player, server)
ComponentParser.list(entry.getMotd())
.modifyText(text -> StringReplacer.replace(text, player, finalServer))
.modifyText(text -> event.parsePAPIPlaceholders(text, player))
.toComponent()
);
}
boolean hidePlayers = entry.isHidePlayersEnabled().getValue(false);
boolean hidePlayers = ProfileManager.checkOption(entry.isHidePlayersEnabled());
if(hidePlayers){
event.hidePlayers();
}
if(!entry.getPlayerCountText().isEmpty() && !hidePlayers){
if(ProfileManager.checkOption(entry.getPlayerCountText()) && !hidePlayers){
event.setPlayerCount(
ComponentParser.text(entry.getPlayerCountText())
.applyReplacements(player, server)
.modifyText(text -> StringReplacer.replace(text, player, finalServer))
.modifyText(text -> event.parsePAPIPlaceholders(text, player))
.toString()
);
}
if(!entry.getPlayers().isEmpty() && !hidePlayers){
if(ProfileManager.checkOption(entry.getPlayers()) && !hidePlayers){
event.setPlayers(entry.getPlayers(), player, server);
}
if(!entry.getFavicon().isEmpty()){
if(ProfileManager.checkOption(entry.getFavicon())){
String favicon = StringReplacer.replace(entry.getFavicon(), player, server);
F fav = plugin.getFaviconHandler().getFavicon(favicon, image -> {
@@ -28,7 +28,7 @@ package ch.andre601.advancedserverlist.core.file;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileEntry;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileSerializer;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
@@ -25,16 +25,13 @@
package ch.andre601.advancedserverlist.core.interfaces.core;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
import java.nio.file.Path;
import java.util.List;
public interface PluginCore<F, PL, P extends GenericPlayer>{
public interface PluginCore<F>{
void loadCommands();
@@ -57,6 +54,4 @@ public interface PluginCore<F, PL, P extends GenericPlayer>{
String getPlatformVersion();
String getLoader();
List<PL> createPlayers(List<String> lines, P player, GenericServer server);
}
@@ -27,6 +27,8 @@ package ch.andre601.advancedserverlist.core.interfaces.events;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
import net.kyori.adventure.text.Component;
@@ -35,7 +37,9 @@ import java.awt.image.BufferedImage;
import java.net.InetSocketAddress;
import java.util.List;
public interface GenericEventWrapper<F, PL, P extends GenericPlayer>{
public interface GenericEventWrapper<F, P extends GenericPlayer>{
GenericServerListEvent callEvent(ProfileEntry entry);
void setMaxPlayers(int maxPlayers);
@@ -67,7 +71,7 @@ public interface GenericEventWrapper<F, PL, P extends GenericPlayer>{
String getVirtualHost();
PluginCore<F, PL, P> getPlugin();
PluginCore<F> getPlugin();
P createPlayer(CachedPlayer player, int protocol);
@@ -25,29 +25,32 @@
package ch.andre601.advancedserverlist.core.objects;
/*
* A simple class to allow having a nullable boolean without having to deal with possible NPEs
* when trying to get Boolean.getValue() while it is null...
*
* Here, it simply checks if the value is null and if it is, returns a default. Otherwise, it gives
* the value.
*/
public class NullBool{
import ch.andre601.advancedserverlist.api.objects.GenericServer;
public class GenericServerImpl implements GenericServer{
public static final NullBool FALSE = new NullBool(false);
public static final NullBool NULL = new NullBool(null);
private final int online;
private final int max;
private final String host;
private final Boolean value;
public NullBool(Boolean value){
this.value = value;
public GenericServerImpl(int online, int max, String host){
this.online = online;
this.max = max;
this.host = host;
}
public boolean isNull(){
return value == null;
@Override
public int getPlayersOnline(){
return online;
}
public boolean getValue(boolean def){
return isNull() ? def : value;
@Override
public int getPlayersMax(){
return max;
}
@Override
public String getHost(){
return host;
}
}
@@ -23,7 +23,7 @@
*
*/
package ch.andre601.advancedserverlist.api.internal;
package ch.andre601.advancedserverlist.core.objects;
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
@@ -36,11 +36,11 @@ public class ServerPlaceholders extends PlaceholderProvider{
}
@Override
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
public String parsePlaceholder(String placeholder, GenericPlayer genericPlayer, GenericServer genericServer){
return switch(placeholder){
case "playersOnline" -> String.valueOf(server.getPlayersOnline());
case "playersMax" -> String.valueOf(server.getPlayersMax());
case "host" -> server.getHost();
case "playersOnline" -> String.valueOf(genericServer.getPlayersOnline());
case "playersMax" -> String.valueOf(genericServer.getPlayersMax());
case "host" -> genericServer.getHost();
default -> null;
};
}
@@ -25,9 +25,6 @@
package ch.andre601.advancedserverlist.core.parsing;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
@@ -59,11 +56,6 @@ public class ComponentParser{
return new ComponentParser(String.join("\n", lines));
}
public ComponentParser applyReplacements(GenericPlayer player, GenericServer server){
text = StringReplacer.replace(text, player, server);
return this;
}
public ComponentParser modifyText(Function<String, String> function){
this.text = function.apply(text);
return this;
@@ -27,9 +27,9 @@ package ch.andre601.advancedserverlist.core.profiles;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.profiles.conditions.Expression;
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileEntry;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
@@ -96,19 +96,19 @@ public class ServerListProfile{
*/
public boolean isInvalidProfile(){
if(profiles.isEmpty())
return defaultProfile.isInvalidProfile();
return defaultProfile.isInvalid();
boolean profilesValid = false;
for(ProfileEntry profile : profiles){
if(profile.isInvalidProfile())
if(profile.isInvalid())
continue;
profilesValid = true;
break;
}
return !profilesValid && defaultProfile.isInvalidProfile();
return !profilesValid && defaultProfile.isInvalid();
}
public static class Builder{
@@ -150,7 +150,7 @@ public class ServerListProfile{
return this;
for(String str : temp){
Expression expr = new Expression(str);
Expression expr = Expression.resolve(str);
if(expr.getResult() != Expression.ExpressionResult.VALID){
logger.warn("Found invalid expression in condition '%s'! Reason: %s", str, expr.getResult().getMessage());
@@ -31,37 +31,34 @@ import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
public class Expression{
private ExpressionResult result = ExpressionResult.VALID;
private final ExpressionResult result;
private String left;
private Operator operator = Operator.UNKNOWN;
private String right;
private final String left;
private final Operator operator;
private final String right;
public Expression(String expression){
resolveExpression(expression);
private Expression(ExpressionResult result, String left, Operator operator, String right){
this.result = result;
this.left = left;
this.operator = operator;
this.right = right;
}
public boolean evaluate(GenericPlayer player, GenericServer server){
String newLeft = StringReplacer.replace(left, player, server);
String newRight = StringReplacer.replace(right, player, server);
public static Expression createInvalid(ExpressionResult result){
return new Expression(result, null, Operator.UNKNOWN, null);
}
public static Expression resolve(String expression){
Operator operator = Operator.UNKNOWN;
return operator.evaluate(newLeft, newRight);
}
public ExpressionResult getResult(){
return result;
}
private void resolveExpression(String expression){
if(expression == null || expression.isEmpty()){
result = ExpressionResult.INVALID_NO_EXPRESSION;
return;
return Expression.createInvalid(ExpressionResult.INVALID_NO_EXPRESSION);
}
char[] chars = expression.toCharArray();
StringBuilder left = new StringBuilder();
StringBuilder right = new StringBuilder();
StringBuilder leftBuilder = new StringBuilder();
StringBuilder rightBuilder = new StringBuilder();
boolean foundOperator = false;
@@ -81,19 +78,28 @@ public class Expression{
}
if(foundOperator){
right.append(c);
rightBuilder.append(c);
}else{
left.append(c);
leftBuilder.append(c);
}
}
if(left.isEmpty() || right.isEmpty()){
result = ExpressionResult.INVALID_EMPTY_PARTS;
return;
if(leftBuilder.isEmpty() || rightBuilder.isEmpty()){
return Expression.createInvalid(ExpressionResult.INVALID_EMPTY_PARTS);
}
this.left = left.toString();
this.right = right.toString();
return new Expression(ExpressionResult.VALID, leftBuilder.toString().trim(), operator, rightBuilder.toString().trim());
}
public boolean evaluate(GenericPlayer player, GenericServer server){
String newLeft = StringReplacer.replace(left, player, server);
String newRight = StringReplacer.replace(right, player, server);
return operator.evaluate(newLeft, newRight);
}
public ExpressionResult getResult(){
return result;
}
public enum Operator{
@@ -0,0 +1,52 @@
/*
* MIT License
*
* Copyright (c) 2022-2023 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.core.profiles.players;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import java.util.UUID;
public abstract class GenericPlayerImpl implements GenericPlayer{
protected String name = null;
protected int protocol = 0;
protected UUID uuid = null;
@Override
public String getName(){
return name;
}
@Override
public int getProtocol(){
return protocol;
}
@Override
public UUID getUUID(){
return uuid;
}
}
@@ -1,194 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022-2023 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.core.profiles.profile;
import ch.andre601.advancedserverlist.core.objects.NullBool;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ProfileEntry{
private final List<String> motd;
private final List<String> players;
private final String playerCountText;
private final String favicon;
private final NullBool hidePlayersEnabled;
private final NullBool extraPlayersEnabled;
private final Integer extraPlayersCount;
public ProfileEntry(List<String> motd, List<String> players,
String playerCountText, String favicon, NullBool hidePlayersEnabled,
NullBool extraPlayersEnabled, Integer extraPlayersCount){
this.motd = motd;
this.players = players;
this.playerCountText = playerCountText;
this.favicon = favicon;
this.hidePlayersEnabled = hidePlayersEnabled;
this.extraPlayersEnabled = extraPlayersEnabled;
this.extraPlayersCount = extraPlayersCount;
}
public static ProfileEntry empty(){
return new ProfileEntry(Collections.emptyList(), Collections.emptyList(), "", "",
NullBool.FALSE, NullBool.FALSE, 0);
}
public List<String> getMOTD(){
return motd;
}
public List<String> getPlayers(){
return players;
}
public String getPlayerCountText(){
return playerCountText;
}
public String getFavicon(){
return favicon;
}
public NullBool isHidePlayersEnabled(){
return hidePlayersEnabled;
}
public NullBool isExtraPlayersEnabled(){
return extraPlayersEnabled;
}
public Integer getExtraPlayersCount(){
return extraPlayersCount;
}
public boolean isInvalidProfile(){
return getMOTD().isEmpty() &&
getPlayers().isEmpty() &&
(getPlayerCountText().isEmpty() && !isHidePlayersEnabled().getValue(false)) &&
getFavicon().isEmpty();
}
public static class Builder{
private final ConfigurationNode node;
private List<String> motd = new ArrayList<>();
private List<String> players = new ArrayList<>();
private String playerCountText = null;
private String favicon = null;
private NullBool hidePlayersEnabled = NullBool.FALSE;
private NullBool extraPlayersEnabled = NullBool.FALSE;
private Integer extraPlayersCount = 0;
private Builder(ConfigurationNode node){
this.node = node;
}
public static Builder resolve(ConfigurationNode node){
return new Builder(node)
.resolveMOTD()
.resolvePlayers()
.resolvePlayerCountText()
.resolveFavicon()
.resolveHidePlayersEnabled()
.resolveExtraPlayersEnabled()
.resolveExtraPlayersCount();
}
public Builder resolveMOTD(){
List<String> motd = resolveList(node, "motd");
if(motd.size() <= 2){
this.motd = motd;
return this;
}
this.motd = motd.subList(0, 2);
return this;
}
public Builder resolvePlayers(){
this.players = this.resolveList(node, "playerCount", "hover");
return this;
}
public Builder resolvePlayerCountText(){
this.playerCountText = node.node("playerCount", "text").getString("");
return this;
}
public Builder resolveFavicon(){
this.favicon = node.node("favicon").getString("");
return this;
}
public Builder resolveHidePlayersEnabled(){
if(node.node("playerCount", "hidePlayers").virtual()){
this.hidePlayersEnabled = NullBool.NULL;
return this;
}
this.hidePlayersEnabled = new NullBool(node.node("playerCount", "hidePlayers").getBoolean());
return this;
}
public Builder resolveExtraPlayersEnabled(){
if(node.node("playerCount", "extraPlayers", "enabled").virtual()){
this.extraPlayersEnabled = NullBool.NULL;
return this;
}
this.extraPlayersEnabled = new NullBool(node.node("playerCount", "extraPlayers", "enabled").getBoolean());
return this;
}
public Builder resolveExtraPlayersCount(){
if(node.node("playerCount", "extraPlayers", "amount").virtual()){
this.extraPlayersCount = null;
return this;
}
this.extraPlayersCount = node.node("playerCount", "extraPlayers", "amount").getInt();
return this;
}
public ProfileEntry build(){
return new ProfileEntry(this.motd, this.players, this.playerCountText,
this.favicon, this.hidePlayersEnabled, this.extraPlayersEnabled, this.extraPlayersCount);
}
private List<String> resolveList(ConfigurationNode node, Object... path){
try{
return node.node(path).getList(String.class);
}catch(SerializationException ex){
return Collections.emptyList();
}
}
}
}
@@ -27,46 +27,18 @@ package ch.andre601.advancedserverlist.core.profiles.profile;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.api.objects.NullBool;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.objects.NullBool;
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
import java.util.Collections;
import java.util.List;
public class ProfileManager{
private final AdvancedServerList core;
private GenericPlayer player;
private GenericServer server;
private ProfileManager(AdvancedServerList core){
this.core = core;
}
public static ProfileManager get(AdvancedServerList core){
return new ProfileManager(core);
}
public ProfileManager applyReplacements(GenericPlayer player, GenericServer server){
this.player = player;
this.server = server;
return this;
}
public ServerListProfile getProfile(){
for(ServerListProfile profile : core.getFileHandler().getProfiles()){
if(profile.isInvalidProfile())
continue;
if(profile.evalConditions(player, server))
return profile;
}
return null;
}
/*
* Convenience method to get a ProfileEntry instance with values merged.
* If the random profile's value is not null will it be used instead of the default one.
@@ -84,49 +56,98 @@ public class ProfileManager{
Integer extraPlayersCount = resolveExtraPlayersCount(entry, defEntry);
return new ProfileEntry(motd, players, playerCountText, favicon,
new NullBool(isHidePlayersEnabled), new NullBool(isExtraPlayersEnabled), extraPlayersCount);
NullBool.resolve(isHidePlayersEnabled), NullBool.resolve(isExtraPlayersEnabled), extraPlayersCount);
}
public static ServerListProfile resolveProfile(AdvancedServerList core, GenericPlayer player, GenericServer server){
for(ServerListProfile profile : core.getFileHandler().getProfiles()){
if(profile.isInvalidProfile())
continue;
if(profile.evalConditions(player, server))
return profile;
}
return null;
}
public static ProfileEntry retrieveProfileEntry(ConfigurationNode node){
List<String> motd = resolveList(node, "motd");
List<String> players = resolveList(node, "playerCount", "hover");
String playerCountText = node.node("playerCount", "text").getString("");
String favicon = node.node("favicon").getString("");
NullBool hidePlayers = resolveNullBool(node, "playerCount", "hidePlayers");
NullBool extraPlayersEnabled = resolveNullBool(node, "playerCount", "extraPlayers", "enabled");
Integer extraPlayers = resolveNullableInt(node);
return new ProfileEntry.Builder()
.setMotd(motd)
.setPlayers(players)
.setPlayerCountText(playerCountText)
.setFavicon(favicon)
.setHidePlayersEnabled(hidePlayers)
.setExtraPlayersEnabled(extraPlayersEnabled)
.setExtraPlayerCount(extraPlayers)
.build();
}
public static boolean checkOption(Object obj){
if(obj == null)
return false;
if(obj instanceof List<?> list){
return !list.isEmpty(); // Check if list isn't empty
}else
if(obj instanceof String str){
return !str.isEmpty(); // Check if list is not empty
}else
if(obj instanceof NullBool nb){
return nb.getOrDefault(false); // Return NullBool's value
}
return false;
}
private static List<String> resolveMOTD(ProfileEntry profile, ProfileEntry defaultProfile){
if(profile == null || profile.getMOTD().isEmpty())
return defaultProfile.getMOTD();
if(profile == null || !checkOption(profile.getMotd()))
return defaultProfile.getMotd();
return profile.getMOTD();
return profile.getMotd();
}
private static List<String> resolvePlayers(ProfileEntry profile, ProfileEntry defaultProfile){
if(profile == null || profile.getPlayers().isEmpty())
if(profile == null || !checkOption(profile.getPlayers()))
return defaultProfile.getPlayers();
return profile.getPlayers();
}
private static String resolvePlayerCountText(ProfileEntry profile, ProfileEntry defaultProfile){
if(profile == null || profile.getPlayerCountText().isEmpty())
if(profile == null || !checkOption(profile.getPlayerCountText()))
return defaultProfile.getPlayerCountText();
return profile.getPlayerCountText();
}
private static String resolveFavicon(ProfileEntry profile, ProfileEntry defaultProfile){
if(profile == null || profile.getFavicon().isEmpty())
if(profile == null || !checkOption(profile.getFavicon()))
return defaultProfile.getFavicon();
return profile.getFavicon();
}
private static boolean resolveHidePlayersEnabled(ProfileEntry profile, ProfileEntry defaultProfile){
if(profile == null || profile.isHidePlayersEnabled().isNull())
return defaultProfile.isHidePlayersEnabled().getValue(false);
if(profile == null || !checkOption(profile.isHidePlayersEnabled()))
return defaultProfile.isHidePlayersEnabled().getOrDefault(false);
return profile.isHidePlayersEnabled().getValue(false);
return profile.isHidePlayersEnabled().getOrDefault(false);
}
private static boolean resolveExtraPlayersEnabled(ProfileEntry profile, ProfileEntry defaultProfile){
if(profile == null || profile.isExtraPlayersEnabled().isNull())
return defaultProfile.isExtraPlayersEnabled().getValue(false);
if(profile == null || !checkOption(profile.isExtraPlayersEnabled()))
return defaultProfile.isExtraPlayersEnabled().getOrDefault(false);
return profile.isExtraPlayersEnabled().getValue(false);
return profile.isExtraPlayersEnabled().getOrDefault(false);
}
private static Integer resolveExtraPlayersCount(ProfileEntry profile, ProfileEntry defaultProfile){
@@ -136,4 +157,25 @@ public class ProfileManager{
return profile.getExtraPlayersCount();
}
private static List<String> resolveList(ConfigurationNode node, Object... path){
try{
return node.node(path).getList(String.class);
}catch(SerializationException ex){
return Collections.emptyList();
}
}
private static NullBool resolveNullBool(ConfigurationNode node, Object... path){
if(node.node(path).virtual())
return NullBool.NOT_SET;
return NullBool.resolve(node.node(path).getBoolean());
}
private static Integer resolveNullableInt(ConfigurationNode node){
if(node.node("playerCount", "extraPlayers", "amount").virtual())
return null;
return node.node("playerCount", "extraPlayers", "amount").getInt();
}
}
@@ -29,6 +29,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
import org.spongepowered.configurate.serialize.TypeSerializer;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import java.lang.reflect.Type;
@@ -37,7 +38,7 @@ public class ProfileSerializer implements TypeSerializer<ProfileEntry>{
@Override
public ProfileEntry deserialize(Type type, ConfigurationNode node){
return ProfileEntry.Builder.resolve(node).build();
return ProfileManager.retrieveProfileEntry(node);
}
@Override
@@ -47,7 +48,7 @@ public class ProfileSerializer implements TypeSerializer<ProfileEntry>{
return;
}
node.node("motd").set(profile.getMOTD());
node.node("motd").set(profile.getMotd());
node.node("playerCount", "hover").set(profile.getPlayers());
node.node("playerCount", "text").set(profile.getPlayerCountText());
node.node("favicon").set(profile.getFavicon());
@@ -33,6 +33,9 @@ import ch.andre601.advancedserverlist.api.objects.GenericServer;
public class StringReplacer{
public static String replace(String input, GenericPlayer player, GenericServer server){
if(input == null)
return null;
char[] chars = input.toCharArray();
StringBuilder builder = new StringBuilder(input.length());
+53
View File
@@ -0,0 +1,53 @@
# Changelog
This page lists the recent changes made towards the AdvancedServerListAPI.
They are ordered newest to oldest.
## v2.0.0
### :octicons-alert-24:{ .changelog-breaking title="Breaking Changes" } Breaking Changes { #v2-breaking }
- `platform-paper` has been removed. It used the same code as `platform-spigot` and was therefore considered duplicate code and useless.
- `core` has been removed. The `CachedPlayer` is no longer needed in the platform-specific APIs.
### :octicons-plus-circle-24:{ .changelog-added title="Added" } Added { #v2-added }
- `PreServerListSetEvent` to the different platform-specific APIs.
- Called before AdvancedServerList alters the server list.
- Allows to override the `ProfileEntry` used or even cancel the event.
- `ProfileEntry`
- Used for setting the different values of the server list.
- Own instances can be made using the nested `Builder` class.
- Has methods to create a Builder instance from itself, or make a copy from another ProfileEntry-instance.
### :octicons-pencil-24:{ .changelog-changed title="Changed" } Changed { #v2-changed }
- Converted `GenericPlayer`, `GenericServer`, `BungeePlayer`, `SpigotPlayer` and `VelocityPlayer` into interfaces.
- `GenericPlayer` no longer has `getVersion()`, `hasPlayedBefore()`, `isBanned()` and `isWhitelisted()`. They have been moved to `VelocityPlayer` (Only `getVersion()`) and `SpigotPlayer` respectively.
- Converted `NullBool` from a class to an enum.
- Contains `TRUE`, `FALSE` and `NOT_SET`.
- `isNull()` is now `isNotSet()`.
### :octicons-trash-24:{ .changelog-removed title="Removed" } Removed { #v2-removed }
- `UnsupportedAPIAccessException` as it is no longer used in the API itself.
## v1.0.0
### :octicons-plus-circle-24:{ .changelog-added title="Added" } Added { #v1-added }
- `AdvancedServerListAPI`
- Main class used to add your own `PlaceholderProvider` instances.
- `PlaceholderProvider`
- Abstract class used to add your own placeholders to parse in AdvancedServerList.
<!--
Templates for changelog
### :octicons-alert-24:{ .changelog-breaking title="Breaking Changes" } Breaking Changes { #v-breaking }
### :octicons-plus-circle-24:{ .changelog-added title="Added" } Added { #v-added }
### :octicons-pencil-24:{ .changelog-changed title="Changed" } Changed { #v-changed }
### :octicons-trash-24:{ .changelog-removed title="Removed" } Removed { #v-removed }
-->
+16 -1
View File
@@ -139,4 +139,19 @@ Example:
AdvancedServerListAPI api = AdvancedServerListAPI.get();
api.addPlaceholderProvider(new MyPlaceholders());
```
```
## Events
!!! info "Note"
The mentioned event is only accessible through one of the platform dependencies, as those are used in the platform's respective event handler system.
v1.1.0 of the API adds the `PreServerListSetEvent` to the different platform dependencies to use.
It allows you to modify the ProfileEntry used for the player pinging the server/proxy or even cancelling the event altogether.
### ProfileEntry
The ProfileEntry class has been moved to the API in v1.1.0 allowing you to create your own versions using the available Builder class.
The ProfileEntry is what contains the necessary data from the server list profiles. This can be an entry from the "profiles" list, the settings themselves in the file or a mix of both depending on what options are present.
You can create a new entry or copy an existing one (i.e. from the [`PreServerListSetEvent`](#events)) to modify and use in the server list by setting it in the aforementioned `PreServerListSetEvent`.
+16
View File
@@ -5,4 +5,20 @@
.md-header__button.md-logo {
padding-right: unset;
padding-left: unset;
}
.changelog-added {
color: #2ea043;
}
.changelog-removed {
color: #f85149;
}
.changelog-changed {
color: #1f6feb;
}
.changelog-breaking {
color: #9e6a03
}
+4 -1
View File
@@ -98,7 +98,9 @@ nav:
- profiles/index.md
- Formatting: profiles/formatting.md
- Placeholders: profiles/placeholders.md
- API: api.md
- API:
- api/index.md
- Changelog: api/changelog.md
- Examples: examples.md
# +--------------------------------------------------------------------------------------------------------+
@@ -482,6 +484,7 @@ markdown_extensions:
- markdown.extensions.admonition:
- markdown.extensions.toc:
permalink: true
- markdown.extensions.attr_list:
- pymdownx.emoji:
emoji_index: !!python/name:materialx.emoji.twemoji
emoji_generator: !!python/name:materialx.emoji.to_svg
+5
View File
@@ -61,6 +61,11 @@
<version>${plugin.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.andre601.asl-api</groupId>
<artifactId>platform-spigot</artifactId>
<version>${api.version}</version>
</dependency>
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
@@ -25,33 +25,24 @@
package ch.andre601.advancedserverlist.paper;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
import ch.andre601.advancedserverlist.paper.commands.CmdAdvancedServerList;
import ch.andre601.advancedserverlist.paper.events.JoinEvent;
import ch.andre601.advancedserverlist.paper.events.PingEvent;
import ch.andre601.advancedserverlist.paper.logging.PaperLogger;
import ch.andre601.advancedserverlist.paper.objects.PaperPlayer;
import ch.andre601.advancedserverlist.paper.objects.PlayerPlaceholders;
import com.destroystokyo.paper.profile.PlayerProfile;
import me.clip.placeholderapi.PlaceholderAPI;
import ch.andre601.advancedserverlist.paper.objects.PaperPlayerPlaceholders;
import org.bstats.bukkit.Metrics;
import org.bstats.charts.SimplePie;
import org.bukkit.Bukkit;
import org.bukkit.command.PluginCommand;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.util.CachedServerIcon;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class PaperCore extends JavaPlugin implements PluginCore<CachedServerIcon, PlayerProfile, PaperPlayer>{
public class PaperCore extends JavaPlugin implements PluginCore<CachedServerIcon>{
private final PluginLogger logger = new PaperLogger(getLogger());
@@ -151,29 +142,8 @@ public class PaperCore extends JavaPlugin implements PluginCore<CachedServerIcon
return "paper";
}
@Override
public List<PlayerProfile> createPlayers(List<String> lines, PaperPlayer player, GenericServer server){
List<PlayerProfile> players = new ArrayList<>(lines.size());
for(String line : lines){
String parsed = ComponentParser.text(line)
.applyReplacements(player, server)
.modifyText(text -> {
if(getServer().getPluginManager().isPluginEnabled("PlaceholderAPI"))
return PlaceholderAPI.setPlaceholders(player.getPlayer(), text);
return text;
})
.toString();
players.add(Bukkit.createProfile(UUID.randomUUID(), parsed));
}
return players;
}
private void enable(){
this.core = new AdvancedServerList(this, new PlayerPlaceholders());
this.core = new AdvancedServerList(this, new PaperPlayerPlaceholders());
}
private void printSpigotWarning(){
@@ -25,12 +25,16 @@
package ch.andre601.advancedserverlist.paper.events;
import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.interfaces.events.GenericEventWrapper;
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
import ch.andre601.advancedserverlist.paper.PaperCore;
import ch.andre601.advancedserverlist.paper.objects.PaperPlayer;
import ch.andre601.advancedserverlist.paper.objects.PaperPlayerImpl;
import com.destroystokyo.paper.event.server.PaperServerListPingEvent;
import com.destroystokyo.paper.profile.PlayerProfile;
import me.clip.placeholderapi.PlaceholderAPI;
@@ -40,9 +44,11 @@ import org.bukkit.OfflinePlayer;
import org.bukkit.util.CachedServerIcon;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon, PlayerProfile, PaperPlayer>{
public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon, PaperPlayerImpl>{
private final PaperCore plugin;
private final PaperServerListPingEvent event;
@@ -52,6 +58,14 @@ public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon,
this.event = event;
}
@Override
public GenericServerListEvent callEvent(ProfileEntry entry){
PreServerListSetEventImpl event = new PreServerListSetEventImpl(entry);
plugin.getServer().getPluginManager().callEvent(event);
return event;
}
@Override
public void setMaxPlayers(int maxPlayers){
event.setMaxPlayers(maxPlayers);
@@ -74,12 +88,25 @@ public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon,
}
@Override
public void setPlayers(List<String> players, PaperPlayer player, GenericServer server){
public void setPlayers(List<String> lines, PaperPlayerImpl player, GenericServer server){
event.getPlayerSample().clear();
List<PlayerProfile> players = new ArrayList<>(lines.size());
event.getPlayerSample().addAll(
plugin.createPlayers(players, player, server)
);
for(String line : lines){
String parsed = ComponentParser.text(line)
.modifyText(text -> StringReplacer.replace(text, player, server))
.modifyText(text -> {
if(plugin.getServer().getPluginManager().isPluginEnabled("PlaceholderAPI"))
return PlaceholderAPI.setPlaceholders(player.getPlayer(), text);
return text;
})
.toString();
players.add(Bukkit.createProfile(UUID.randomUUID(), parsed));
}
event.getPlayerSample().addAll(players);
}
@Override
@@ -123,7 +150,7 @@ public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon,
}
@Override
public String parsePAPIPlaceholders(String text, PaperPlayer player){
public String parsePAPIPlaceholders(String text, PaperPlayerImpl player){
if(plugin.getServer().getPluginManager().isPluginEnabled("PlaceholderAPI"))
return PlaceholderAPI.setPlaceholders(player.getPlayer(), text);
@@ -136,15 +163,15 @@ public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon,
}
@Override
public PluginCore<CachedServerIcon, PlayerProfile, PaperPlayer> getPlugin(){
public PluginCore<CachedServerIcon> getPlugin(){
return plugin;
}
@Override
public PaperPlayer createPlayer(CachedPlayer player, int protocol){
public PaperPlayerImpl createPlayer(CachedPlayer player, int protocol){
OfflinePlayer pl = Bukkit.getOfflinePlayer(player.getUuid());
return new PaperPlayer(pl.hasPlayedBefore() ? pl : null, player, protocol);
return new PaperPlayerImpl(pl.hasPlayedBefore() ? pl : null, player, protocol);
}
@Override
@@ -23,18 +23,14 @@
*
*/
package ch.andre601.advancedserverlist.api.internal;
package ch.andre601.advancedserverlist.paper.events;
import ch.andre601.advancedserverlist.api.exceptions.InvalidPlaceholderProviderException;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.spigot.events.PreServerListSetEvent;
public class CheckUtil{
public class PreServerListSetEventImpl extends PreServerListSetEvent{
public static void notEmpty(String text, String name){
check(text == null || text.isEmpty(), name + " may not be null or empty.");
}
public static void check(boolean condition, String msg){
if(condition)
throw new InvalidPlaceholderProviderException(msg);
public PreServerListSetEventImpl(ProfileEntry entry){
super(entry);
}
}
@@ -25,15 +25,19 @@
package ch.andre601.advancedserverlist.paper.objects;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
import ch.andre601.advancedserverlist.core.profiles.players.GenericPlayerImpl;
import ch.andre601.advancedserverlist.spigot.objects.SpigotPlayer;
import org.bukkit.OfflinePlayer;
public class PaperPlayer extends GenericPlayer{
public class PaperPlayerImpl extends GenericPlayerImpl implements SpigotPlayer{
private final OfflinePlayer player;
private boolean playedBefore = false;
private boolean banned = false;
private boolean whitelisted = false;
public PaperPlayer(OfflinePlayer player, CachedPlayer cachedPlayer, int protocol){
public PaperPlayerImpl(OfflinePlayer player, CachedPlayer cachedPlayer, int protocol){
this.player = player;
this.name = player == null ? cachedPlayer.getName() : player.getName();
@@ -48,7 +52,23 @@ public class PaperPlayer extends GenericPlayer{
this.whitelisted = player.isWhitelisted();
}
@Override
public OfflinePlayer getPlayer(){
return player;
}
@Override
public boolean hasPlayedBefore(){
return playedBefore;
}
@Override
public boolean isBanned(){
return banned;
}
@Override
public boolean isWhitelisted(){
return whitelisted;
}
}
@@ -28,29 +28,30 @@ package ch.andre601.advancedserverlist.paper.objects;
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.spigot.objects.SpigotPlayer;
public class PlayerPlaceholders extends PlaceholderProvider{
public class PaperPlayerPlaceholders extends PlaceholderProvider{
public PlayerPlaceholders(){
public PaperPlayerPlaceholders(){
super("player");
}
@Override
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
PaperPlayer paperPlayer = (PaperPlayer)player;
SpigotPlayer paperPlayer = (SpigotPlayer)player;
return switch(placeholder){
case "name" -> paperPlayer.getName();
case "protocol" -> String.valueOf(paperPlayer.getProtocol());
case "uuid" -> String.valueOf(paperPlayer.getUUID());
case "hasPlayedBefore" -> returnValue(paperPlayer, player.hasPlayedBefore());
case "isBanned" -> returnValue(paperPlayer, player.isBanned());
case "isWhitelisted" -> returnValue(paperPlayer, player.isWhitelisted());
case "hasPlayedBefore" -> returnValue(paperPlayer, paperPlayer.hasPlayedBefore());
case "isBanned" -> returnValue(paperPlayer, paperPlayer.isBanned());
case "isWhitelisted" -> returnValue(paperPlayer, paperPlayer.isWhitelisted());
default -> null;
};
}
private String returnValue(PaperPlayer player, Object value){
private String returnValue(SpigotPlayer player, Object value){
return player.getPlayer() == null ? null : String.valueOf(value);
}
}
+11 -3
View File
@@ -37,15 +37,23 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<plugin.version>2.0.0</plugin.version>
<plugin.version>2.1.0</plugin.version>
<plugin.description>Create multiple Server lists based on conditions.</plugin.description>
<api.version>v2.0.0</api.version>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
</properties>
<repositories>
<repository>
<id>jitpack</id>
<url>https://jitpack.io/</url>
</repository>
</repositories>
<modules>
<module>api</module>
<module>core</module>
<module>bungeecord</module>
<module>paper</module>
+6
View File
@@ -65,6 +65,12 @@
<version>${plugin.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.andre601.asl-api</groupId>
<artifactId>platform-spigot</artifactId>
<version>${api.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
@@ -25,31 +25,23 @@
package ch.andre601.advancedserverlist.spigot;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
import ch.andre601.advancedserverlist.spigot.commands.CmdAdvancedServerList;
import ch.andre601.advancedserverlist.spigot.events.LoadEvent;
import ch.andre601.advancedserverlist.spigot.logging.SpigotLogger;
import ch.andre601.advancedserverlist.spigot.objects.PlayerPlaceholders;
import ch.andre601.advancedserverlist.spigot.objects.SpigotPlayer;
import com.comphenix.protocol.wrappers.WrappedGameProfile;
import ch.andre601.advancedserverlist.spigot.objects.SpigotPlayerPlaceholders;
import com.comphenix.protocol.wrappers.WrappedServerPing;
import me.clip.placeholderapi.PlaceholderAPI;
import org.bstats.bukkit.Metrics;
import org.bstats.charts.SimplePie;
import org.bukkit.command.PluginCommand;
import org.bukkit.plugin.java.JavaPlugin;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class SpigotCore extends JavaPlugin implements PluginCore<WrappedServerPing.CompressedImage, WrappedGameProfile, SpigotPlayer>{
public class SpigotCore extends JavaPlugin implements PluginCore<WrappedServerPing.CompressedImage>{
private final PluginLogger logger = new SpigotLogger(getLogger());
@@ -71,7 +63,7 @@ public class SpigotCore extends JavaPlugin implements PluginCore<WrappedServerPi
}catch(ClassNotFoundException ignored){}
}
this.core = new AdvancedServerList(this, new PlayerPlaceholders());
this.core = new AdvancedServerList(this, new SpigotPlayerPlaceholders());
}
@Override
@@ -147,27 +139,6 @@ public class SpigotCore extends JavaPlugin implements PluginCore<WrappedServerPi
return "spigot";
}
@Override
public List<WrappedGameProfile> createPlayers(List<String> lines, SpigotPlayer player, GenericServer server){
List<WrappedGameProfile> players = new ArrayList<>(lines.size());
for(String line : lines){
String parsed = ComponentParser.text(line)
.applyReplacements(player, server)
.modifyText(text -> {
if(getServer().getPluginManager().isPluginEnabled("PlaceholderAPI"))
return PlaceholderAPI.setPlaceholders(player.getPlayer(), text);
return text;
})
.toString();
players.add(new WrappedGameProfile(UUID.randomUUID(), parsed));
}
return players;
}
private void printPaperInfo(){
getPluginLogger().warn("======================================================================================");
getPluginLogger().warn("You are using the Spigot version of AdvancedServerList on a Paper server.");
@@ -0,0 +1,35 @@
/*
* MIT License
*
* Copyright (c) 2022-2023 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.spigot.events;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
public class PreServerListSetEventImpl extends PreServerListSetEvent{
public PreServerListSetEventImpl(ProfileEntry entry){
super(entry);
}
}
@@ -25,12 +25,16 @@
package ch.andre601.advancedserverlist.spigot.events;
import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.interfaces.events.GenericEventWrapper;
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
import ch.andre601.advancedserverlist.spigot.SpigotCore;
import ch.andre601.advancedserverlist.spigot.objects.SpigotPlayer;
import ch.andre601.advancedserverlist.spigot.objects.SpigotPlayerImpl;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.wrappers.AdventureComponentConverter;
import com.comphenix.protocol.wrappers.WrappedGameProfile;
@@ -41,10 +45,12 @@ import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public class ProtocolLibEventWrapper implements GenericEventWrapper<WrappedServerPing.CompressedImage, WrappedGameProfile, SpigotPlayer>{
public class ProtocolLibEventWrapper implements GenericEventWrapper<WrappedServerPing.CompressedImage, SpigotPlayerImpl>{
private final SpigotCore plugin;
private final PacketEvent event;
@@ -60,6 +66,14 @@ public class ProtocolLibEventWrapper implements GenericEventWrapper<WrappedServe
this.hostAddresses = hostAddresses;
}
@Override
public GenericServerListEvent callEvent(ProfileEntry entry){
PreServerListSetEventImpl event = new PreServerListSetEventImpl(entry);
plugin.getServer().getPluginManager().callEvent(event);
return event;
}
@Override
public void setMaxPlayers(int maxPlayers){
ping.setPlayersMaximum(maxPlayers);
@@ -82,10 +96,24 @@ public class ProtocolLibEventWrapper implements GenericEventWrapper<WrappedServe
}
@Override
public void setPlayers(List<String> players, SpigotPlayer player, GenericServer server){
ping.setPlayers(
plugin.createPlayers(players, player, server)
);
public void setPlayers(List<String> lines, SpigotPlayerImpl player, GenericServer server){
List<WrappedGameProfile> players = new ArrayList<>(lines.size());
for(String line : lines){
String parsed = ComponentParser.text(line)
.modifyText(text -> StringReplacer.replace(text, player, server))
.modifyText(text -> {
if(plugin.getServer().getPluginManager().isPluginEnabled("PlaceholderAPI"))
return PlaceholderAPI.setPlaceholders(player.getPlayer(), text);
return text;
})
.toString();
players.add(new WrappedGameProfile(UUID.randomUUID(), parsed));
}
ping.setPlayers(players);
}
@Override
@@ -128,7 +156,7 @@ public class ProtocolLibEventWrapper implements GenericEventWrapper<WrappedServe
}
@Override
public String parsePAPIPlaceholders(String text, SpigotPlayer player){
public String parsePAPIPlaceholders(String text, SpigotPlayerImpl player){
if(plugin.getServer().getPluginManager().isPluginEnabled("PlaceholderAPI"))
return PlaceholderAPI.setPlaceholders(player.getPlayer(), text);
@@ -145,15 +173,15 @@ public class ProtocolLibEventWrapper implements GenericEventWrapper<WrappedServe
}
@Override
public PluginCore<WrappedServerPing.CompressedImage, WrappedGameProfile, SpigotPlayer> getPlugin(){
public PluginCore<WrappedServerPing.CompressedImage> getPlugin(){
return plugin;
}
@Override
public SpigotPlayer createPlayer(CachedPlayer player, int protocol){
public SpigotPlayerImpl createPlayer(CachedPlayer player, int protocol){
OfflinePlayer pl = Bukkit.getOfflinePlayer(player.getUuid());
return new SpigotPlayer(pl.hasPlayedBefore() ? pl : null, player, protocol);
return new SpigotPlayerImpl(pl.hasPlayedBefore() ? pl : null, player, protocol);
}
@Override
@@ -25,15 +25,18 @@
package ch.andre601.advancedserverlist.spigot.objects;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
import ch.andre601.advancedserverlist.core.profiles.players.GenericPlayerImpl;
import org.bukkit.OfflinePlayer;
public class SpigotPlayer extends GenericPlayer{
public class SpigotPlayerImpl extends GenericPlayerImpl implements SpigotPlayer{
private final OfflinePlayer player;
private boolean playedBefore = false;
private boolean banned = false;
private boolean whitelisted = false;
public SpigotPlayer(OfflinePlayer player, CachedPlayer cachedPlayer, int protocol){
public SpigotPlayerImpl(OfflinePlayer player, CachedPlayer cachedPlayer, int protocol){
this.player = player;
this.name = player == null ? cachedPlayer.getName() : player.getName();
@@ -49,7 +52,23 @@ public class SpigotPlayer extends GenericPlayer{
this.whitelisted = player.isWhitelisted();
}
@Override
public OfflinePlayer getPlayer(){
return player;
}
@Override
public boolean hasPlayedBefore(){
return playedBefore;
}
@Override
public boolean isBanned(){
return banned;
}
@Override
public boolean isWhitelisted(){
return whitelisted;
}
}
@@ -29,9 +29,9 @@ import ch.andre601.advancedserverlist.api.PlaceholderProvider;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
public class PlayerPlaceholders extends PlaceholderProvider{
public class SpigotPlayerPlaceholders extends PlaceholderProvider{
public PlayerPlaceholders(){
public SpigotPlayerPlaceholders(){
super("player");
}
@@ -43,9 +43,9 @@ public class PlayerPlaceholders extends PlaceholderProvider{
case "name" -> spigotPlayer.getName();
case "protocol" -> String.valueOf(spigotPlayer.getProtocol());
case "uuid" -> String.valueOf(spigotPlayer.getUUID());
case "hasPlayedBefore" -> returnValue(spigotPlayer, player.hasPlayedBefore());
case "isBanned" -> returnValue(spigotPlayer, player.isBanned());
case "isWhitelisted" -> returnValue(spigotPlayer, player.isWhitelisted());
case "hasPlayedBefore" -> returnValue(spigotPlayer, spigotPlayer.hasPlayedBefore());
case "isBanned" -> returnValue(spigotPlayer, spigotPlayer.isBanned());
case "isWhitelisted" -> returnValue(spigotPlayer, spigotPlayer.isWhitelisted());
default -> null;
};
}
+6
View File
@@ -57,6 +57,12 @@
<version>${plugin.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.andre601.asl-api</groupId>
<artifactId>platform-velocity</artifactId>
<version>${api.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.velocitypowered</groupId>
<artifactId>velocity-api</artifactId>
@@ -25,18 +25,15 @@
package ch.andre601.advancedserverlist.velocity;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
import ch.andre601.advancedserverlist.velocity.commands.CmdAdvancedServerList;
import ch.andre601.advancedserverlist.velocity.events.JoinEvent;
import ch.andre601.advancedserverlist.velocity.events.PingEvent;
import ch.andre601.advancedserverlist.velocity.logging.VelocityLogger;
import ch.andre601.advancedserverlist.velocity.objects.PlayerPlaceholders;
import ch.andre601.advancedserverlist.velocity.objects.VelocityPlayer;
import ch.andre601.advancedserverlist.velocity.objects.VelocityPlayerPlaceholders;
import com.google.inject.Inject;
import com.velocitypowered.api.command.CommandMeta;
import com.velocitypowered.api.event.Subscribe;
@@ -44,18 +41,14 @@ import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
import com.velocitypowered.api.plugin.annotation.DataDirectory;
import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.server.ServerPing;
import com.velocitypowered.api.util.Favicon;
import org.bstats.charts.SimplePie;
import org.bstats.velocity.Metrics;
import org.slf4j.LoggerFactory;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class VelocityCore implements PluginCore<Favicon, ServerPing.SamplePlayer, VelocityPlayer>{
public class VelocityCore implements PluginCore<Favicon>{
private final PluginLogger logger;
private final ProxyServer proxy;
@@ -76,7 +69,7 @@ public class VelocityCore implements PluginCore<Favicon, ServerPing.SamplePlayer
@Subscribe
public void init(ProxyInitializeEvent event){
this.core = new AdvancedServerList(this, new PlayerPlaceholders());
this.core = new AdvancedServerList(this, new VelocityPlayerPlaceholders());
}
@Subscribe
@@ -138,21 +131,6 @@ public class VelocityCore implements PluginCore<Favicon, ServerPing.SamplePlayer
return faviconHandler;
}
@Override
public List<ServerPing.SamplePlayer> createPlayers(List<String> lines, VelocityPlayer player, GenericServer server){
List<ServerPing.SamplePlayer> players = new ArrayList<>(lines.size());
for(String line : lines){
String parsed = ComponentParser.text(line)
.applyReplacements(player, server)
.toString();
players.add(new ServerPing.SamplePlayer(parsed, UUID.randomUUID()));
}
return players;
}
@Override
public String getPlatformName(){
return getProxy().getVersion().getName();
@@ -0,0 +1,34 @@
/*
* MIT License
*
* Copyright (c) 2022-2023 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.velocity.events;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
public class PreServerListSetEventImpl extends PreServerListSetEvent{
public PreServerListSetEventImpl(ProfileEntry entry){
super(entry);
}
}
@@ -25,12 +25,16 @@
package ch.andre601.advancedserverlist.velocity.events;
import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.interfaces.events.GenericEventWrapper;
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
import ch.andre601.advancedserverlist.velocity.VelocityCore;
import ch.andre601.advancedserverlist.velocity.objects.VelocityPlayer;
import ch.andre601.advancedserverlist.velocity.objects.VelocityPlayerImpl;
import com.velocitypowered.api.event.proxy.ProxyPingEvent;
import com.velocitypowered.api.proxy.server.ServerPing;
import com.velocitypowered.api.util.Favicon;
@@ -38,8 +42,10 @@ import net.kyori.adventure.text.Component;
import java.awt.image.BufferedImage;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
public class VelocityEventWrapper implements GenericEventWrapper<Favicon, ServerPing.SamplePlayer, VelocityPlayer>{
public class VelocityEventWrapper implements GenericEventWrapper<Favicon, VelocityPlayerImpl>{
private final VelocityCore plugin;
private final ProxyPingEvent event;
@@ -53,6 +59,18 @@ public class VelocityEventWrapper implements GenericEventWrapper<Favicon, Server
this.protocol = event.getPing().getVersion();
}
@Override
public GenericServerListEvent callEvent(ProfileEntry entry){
PreServerListSetEventImpl event = new PreServerListSetEventImpl(entry);
try{
plugin.getProxy().getEventManager().fire(event).get();
}catch(InterruptedException | ExecutionException ignored){
return null;
}
return event;
}
@Override
public void setMaxPlayers(int maxPlayers){
builder.maximumPlayers(maxPlayers);
@@ -74,12 +92,19 @@ public class VelocityEventWrapper implements GenericEventWrapper<Favicon, Server
}
@Override
public void setPlayers(List<String> players, VelocityPlayer player, GenericServer server){
ServerPing.SamplePlayer[] playerSamples = plugin.createPlayers(players, player, server)
.toArray(new ServerPing.SamplePlayer[0]);
public void setPlayers(List<String> lines, VelocityPlayerImpl player, GenericServer server){
ServerPing.SamplePlayer[] players = new ServerPing.SamplePlayer[lines.size()];
if(playerSamples.length > 0)
builder.clearSamplePlayers().samplePlayers(playerSamples);
for(int i = 0; i < players.length; i++){
String parsed = ComponentParser.text(lines.get(i))
.modifyText(text -> StringReplacer.replace(text, player, server))
.toString();
players[i] = new ServerPing.SamplePlayer(parsed, UUID.randomUUID());
}
if(players.length > 0)
builder.clearSamplePlayers().samplePlayers(players);
}
@Override
@@ -122,7 +147,7 @@ public class VelocityEventWrapper implements GenericEventWrapper<Favicon, Server
}
@Override
public String parsePAPIPlaceholders(String text, VelocityPlayer player){
public String parsePAPIPlaceholders(String text, VelocityPlayerImpl player){
return text;
}
@@ -132,13 +157,13 @@ public class VelocityEventWrapper implements GenericEventWrapper<Favicon, Server
}
@Override
public PluginCore<Favicon, ServerPing.SamplePlayer, VelocityPlayer> getPlugin(){
public PluginCore<Favicon> getPlugin(){
return plugin;
}
@Override
public VelocityPlayer createPlayer(CachedPlayer player, int protocol){
return new VelocityPlayer(player, protocol);
public VelocityPlayerImpl createPlayer(CachedPlayer player, int protocol){
return new VelocityPlayerImpl(player, protocol);
}
@Override
@@ -25,17 +25,23 @@
package ch.andre601.advancedserverlist.velocity.objects;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
import ch.andre601.advancedserverlist.core.profiles.players.GenericPlayerImpl;
import com.velocitypowered.api.network.ProtocolVersion;
public class VelocityPlayer extends GenericPlayer{
public class VelocityPlayerImpl extends GenericPlayerImpl implements VelocityPlayer{
public VelocityPlayer(CachedPlayer player, int protocol){
private final String version;
public VelocityPlayerImpl(CachedPlayer player, int protocol){
this.name = player.getName();
this.protocol = protocol;
this.uuid = player.getUuid();
this.version = ProtocolVersion.getProtocolVersion(protocol).getVersionIntroducedIn();
}
@Override
public String getVersion(){
return version;
}
}
@@ -29,9 +29,9 @@ import ch.andre601.advancedserverlist.api.PlaceholderProvider;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
public class PlayerPlaceholders extends PlaceholderProvider{
public class VelocityPlayerPlaceholders extends PlaceholderProvider{
public PlayerPlaceholders(){
public VelocityPlayerPlaceholders(){
super("player");
}
@@ -41,7 +41,7 @@ public class PlayerPlaceholders extends PlaceholderProvider{
case "name" -> player.getName();
case "protocol" -> String.valueOf(player.getProtocol());
case "uuid" -> String.valueOf(player.getUUID());
case "version" -> player.getVersion();
case "version" -> ((VelocityPlayerImpl)player).getVersion();
default -> null;
};
}