Compare commits

..
10 Commits
17 changed files with 318 additions and 159 deletions

No files matched your search

+1
View File
@@ -46,6 +46,7 @@ You can download AdvancedServerList on the following locations:
- Custom MOTD.
- Custom Player count text.
- Custom hover for the player count hover.
- Hide player count (Turn to `???`)
- MiniMessage formatting for MOTD, player count and player count hover [[Read More][minimessage]]
- Placeholder support [[Read More][placeholders]]
@@ -85,6 +85,16 @@ public class PingEvent implements Listener{
ping.setDescriptionComponent(component);
}
if(profile.shouldHidePlayers()){
ping.setPlayers(null);
ping.setFavicon(ping.getFaviconObject());
ping.setVersion(protocol);
event.setResponse(ping);
return;
}
if(!profile.getPlayerCount().isEmpty()){
protocol.setName(ComponentParser.text(profile.getPlayerCount())
.replacements(replacements)
@@ -44,8 +44,8 @@ public class BungeeLogger implements PluginLogger{
}
@Override
public void warn(String msg){
logger.warning(msg);
public void warn(String msg, Object... args){
logger.warning(String.format(msg, args));
}
@Override
@@ -130,7 +130,7 @@ public class FileHandler{
if(tmp == null)
continue;
profiles.add(new ServerListProfile(tmp));
profiles.add(new ServerListProfile(tmp, logger));
logger.info("Loaded " + file.getName());
}
@@ -29,7 +29,7 @@ public interface PluginLogger{
void info(String msg, Object... args);
void warn(String msg);
void warn(String msg, Object... args);
void warn(String msg, Throwable throwable);
}
@@ -1,137 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 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;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
import java.util.*;
public class ConditionsHolder{
private final List<String> expressions = new ArrayList<>();
private final Map<String, Object> replacements = new HashMap<>();
public ConditionsHolder(List<String> expressions){
if(expressions != null && !expressions.isEmpty())
this.expressions.addAll(expressions);
}
public void replacements(Map<String, Object> replacements){
this.replacements.putAll(replacements);
}
public boolean eval(PluginLogger logger){
if(expressions.isEmpty())
return true;
for(String expression : expressions){
if(!parseExpression(expression, logger))
return false;
}
return true;
}
private boolean parseExpression(String expression, PluginLogger logger){
if(expression == null || expression.isEmpty())
return true;
String newExpression = StringReplacer.replace(expression, replacements);
char[] chars = newExpression.toCharArray();
StringBuilder left = new StringBuilder();
StringBuilder operator = new StringBuilder();
StringBuilder right = new StringBuilder();
boolean operatorFound = false;
for(int i = 0; i < chars.length; i++){
char c = chars[i];
if(c == ' ')
continue;
if((c != '<' && c != '>' && c != '=' && c != '!') || i + 1 >= chars.length){
if(operatorFound){
right.append(c);
continue;
}
left.append(c);
continue;
}
if(operatorFound){
logger.warn("Encountered second operator in condition! AdvancedServerList currently only supports one operator!");
return false;
}
operatorFound = true;
char next = chars[i + 1];
if(c == '!' && next != '='){
logger.warn("Invalid condition found. Expected '!=' but found '!" + next + "' in condition " + newExpression);
return false;
}
operator.append(c);
i++;
if(c == '!' || ((c == '<' || c == '>') && next == '=')){
operator.append(next);
}
}
if(left.isEmpty() || operator.isEmpty() || right.isEmpty()){
logger.warn("Failed to evaluate condition. One part of the expression was empty!");
return false;
}
int leftInt = tryParse(left.toString());
int rightInt = tryParse(right.toString());
return switch(operator.toString().toLowerCase(Locale.ROOT)){
case ">" -> leftInt > rightInt;
case ">=" -> leftInt >= rightInt;
case "=" -> left.toString().equals(right.toString());
case "!=" -> !left.toString().equals(right.toString());
case "<" -> leftInt < rightInt;
case "<=" -> leftInt <= rightInt;
default -> false;
};
}
private int tryParse(String value){
try{
return Integer.parseInt(value);
}catch(NumberFormatException ex){
return value.length();
}
}
}
@@ -53,10 +53,8 @@ public class ProfileManager{
for(ServerListProfile profile : core.getFileHandler().getProfiles()){
if(profile.getMotd().isEmpty() && profile.getPlayers().isEmpty() && profile.getPlayerCount().isEmpty())
continue;
ConditionsHolder conditions = profile.getConditions();
conditions.replacements(replacements);
if(conditions.eval(core.getPluginLogger()))
if(profile.evalConditions(replacements))
return profile;
}
@@ -25,32 +25,34 @@
package ch.andre601.advancedserverlist.core.profiles;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.profiles.conditions.Expression;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class ServerListProfile{
private final ConditionsHolder conditions;
private final int priority;
private final List<Expression> expressions;
private final List<String> motd;
private final List<String> players;
private final String playerCount;
private final boolean hidePlayers;
public ServerListProfile(ConfigurationNode node){
this.conditions = new ConditionsHolder(getList(node, "conditions", false));
public ServerListProfile(ConfigurationNode node, PluginLogger logger){
this.priority = node.node("priority").getInt();
this.expressions = createExpressions(getList(node, "conditions", false), logger);
this.motd = getList(node, "motd", true);
this.players = getList(node, "players", false);
this.playerCount = node.node("playerCount").getString("");
}
public ConditionsHolder getConditions(){
return conditions;
this.hidePlayers = node.node("hidePlayers").getBoolean();
}
public int getPriority(){
@@ -69,6 +71,42 @@ public class ServerListProfile{
return playerCount;
}
public boolean shouldHidePlayers(){
return hidePlayers;
}
public boolean evalConditions(Map<String, Object> replacements){
if(expressions.isEmpty())
return true;
for(Expression expression : expressions){
if(!expression.evaluate(replacements)){
return false;
}
}
return true;
}
private List<Expression> createExpressions(List<String> list, PluginLogger logger) {
if(list.isEmpty())
return Collections.emptyList();
List<Expression> expressions = new ArrayList<>();
for(String str : list){
Expression expression = new Expression(str);
if(expression.getResult() != Expression.ExpressionResult.VALID){
logger.warn("Detected Invalid condition '%s'! Cause: %s", str, expression.getResult().getMessage());
continue;
}
expressions.add(expression);
}
return expressions;
}
private List<String> getList(ConfigurationNode node, String key, boolean trim){
List<String> list;
try{
@@ -0,0 +1,222 @@
/*
* MIT License
*
* Copyright (c) 2022 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.conditions;
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
import java.util.Map;
public class Expression{
private ExpressionResult result = ExpressionResult.VALID;
private String left;
private Operator operator = Operator.UNKNOWN;
private String right;
public Expression(String expression){
resolveExpression(expression);
}
public boolean evaluate(Map<String, Object> replacements){
String newLeft = StringReplacer.replace(left, replacements).trim();
String newRight = StringReplacer.replace(right, replacements).trim();
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;
}
char[] chars = expression.toCharArray();
StringBuilder left = new StringBuilder();
StringBuilder right = new StringBuilder();
boolean foundOperator = false;
for(int i = 0; i < chars.length; i++){
char c = chars[i];
char next = (i == (chars.length - 1)) ? '\0' : chars[i + 1];
Operator tmp = Operator.getOperand(c, next);
if(tmp == Operator.UNKNOWN){
if(foundOperator){
right.append(c);
}else{
left.append(c);
}
continue;
}
if(foundOperator){
result = ExpressionResult.INVALID_DOUBLE_OPERATOR;
return;
}
operator = tmp;
foundOperator = true;
}
if(left.isEmpty() || right.isEmpty()){
result = ExpressionResult.INVALID_EMPTY_PARTS;
return;
}
this.left = left.toString();
this.right = right.toString();
}
public enum Operator{
LESS_THAN('<', '\0'){
@Override
public boolean evaluate(String left, String right){
int leftInt = Operator.getInt(left);
int rightInt = Operator.getInt(right);
return leftInt < rightInt;
}
},
LESS_OR_EQUAL('<', '='){
@Override
public boolean evaluate(String left, String right){
int leftInt = Operator.getInt(left);
int rightInt = Operator.getInt(right);
return leftInt <= rightInt;
}
},
EQUAL('=', '\0'){
@Override
public boolean evaluate(String left, String right){
return left.equals(right);
}
},
NOT_EQUAL('!', '='){
@Override
public boolean evaluate(String left, String right){
return !left.equals(right);
}
},
GREATER_THAN('>', '\0'){
@Override
public boolean evaluate(String left, String right){
int leftInt = Operator.getInt(left);
int rightInt = Operator.getInt(right);
return leftInt > rightInt;
}
},
GREATER_OR_EQUAL('>', '='){
@Override
public boolean evaluate(String left, String right){
int leftInt = Operator.getInt(left);
int rightInt = Operator.getInt(right);
return leftInt >= rightInt;
}
},
UNKNOWN('\0', '\0'){
@Override
public boolean evaluate(String left, String right){
return false;
}
};
private static final Operator[] VALUES = values();
private final char first;
private final char second;
Operator(char first, char second){
this.first = first;
this.second = second;
}
public static Operator getOperand(char first, char second){
for(Operator operator : VALUES){
if(operator.first == first){
if((!operator.hasSecond() && second != '=') || operator.second == second)
return operator;
}
}
return Operator.UNKNOWN;
}
public boolean hasSecond(){
return second != '\0';
}
public abstract boolean evaluate(String left, String right);
private static int getInt(String text){
try{
return Integer.parseInt(text);
}catch(NumberFormatException ex){
return text.length();
}
}
}
public enum ExpressionResult{
VALID{
@Override
public String getMessage(){
return null;
}
},
INVALID_NO_EXPRESSION{
@Override
public String getMessage(){
return "Received empty condition which isn't allowed!";
}
},
INVALID_DOUBLE_OPERATOR{
@Override
public String getMessage(){
return "Condition contained two operands.";
}
},
INVALID_EMPTY_PARTS{
@Override
public String getMessage(){
return "Received condition with either left or right part being empty.";
}
};
public abstract String getMessage();
}
}
@@ -27,6 +27,15 @@ motd:
- '<grey>Line 1'
- '<grey>Line 2'
#
# Sets if players should be hidden.
# When set to true will the player count be replaced with ???
# Additionally will the options 'players' and 'playerCount' be ignored by the plugin.
#
# Read more: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#hideplayers
#
hidePlayers: false
#
# Set the hover text that usually displays online players.
# Only normal colours such as <grey> or <aqua> are supported.
@@ -86,6 +86,11 @@ public class PingEvent implements Listener{
.toComponent());
}
if(profile.shouldHidePlayers()){
event.setHidePlayers(true);
return;
}
if(!profile.getPlayerCount().isEmpty()){
event.setVersion(ComponentParser.text(profile.getPlayerCount())
.replacements(replacements)
@@ -44,8 +44,8 @@ public class PaperLogger implements PluginLogger{
}
@Override
public void warn(String msg){
logger.warning(msg);
public void warn(String msg, Object... args){
logger.warning(String.format(msg, args));
}
@Override
+1 -1
View File
@@ -12,7 +12,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<plugin.version>1.1.0</plugin.version>
<plugin.version>1.2.0</plugin.version>
<plugin.description>Create multiple Server lists based on conditions.</plugin.description>
<plugin.depend.mc>1.19-R0.1-SNAPSHOT</plugin.depend.mc>
@@ -74,6 +74,7 @@ public class PingEvent implements Listener{
hostAddresses.put(address.getHostString(), host);
}
});
protocolManager.addPacketListener(new PacketAdapter(spigotPlugin, ListenerPriority.LOW, PacketType.Status.Server.SERVER_INFO){
@Override
public void onPacketSending(PacketEvent event){
@@ -114,6 +115,11 @@ public class PingEvent implements Listener{
ping.setMotD(AdventureComponentConverter.fromComponent(component));
}
if(profile.shouldHidePlayers()){
ping.setPlayersVisible(false);
return;
}
if(!profile.getPlayerCount().isEmpty()){
ping.setVersionName(ComponentParser.text(profile.getPlayerCount())
.replacements(replacements)
@@ -44,8 +44,8 @@ public class SpigotLogger implements PluginLogger{
}
@Override
public void warn(String msg){
logger.warning(msg);
public void warn(String msg, Object... args){
logger.warning(String.format(msg, args));
}
@Override
@@ -85,6 +85,13 @@ public class PingEvent{
);
}
if(profile.shouldHidePlayers()){
builder.nullPlayers();
event.setPing(builder.build());
return;
}
if(!profile.getPlayerCount().isEmpty()){
builder.version(new ServerPing.Version(
-1,
@@ -42,8 +42,8 @@ public class VelocityLogger implements PluginLogger{
}
@Override
public void warn(String msg){
logger.warn(msg);
public void warn(String msg, Object... args){
logger.warn(msg, args);
}
@Override