Fixing a shit ton of warning / code style and stuff (code inspector from IDEA)

This commit is contained in:
Marc Baloup 2022-07-10 00:55:56 +02:00
parent 276b1d323a
commit b6104a76c1
118 changed files with 1116 additions and 1574 deletions

View File

@ -33,9 +33,7 @@ import net.md_5.bungee.api.plugin.TabExecutor;
import net.md_5.bungee.command.ConsoleCommandSender; import net.md_5.bungee.command.ConsoleCommandSender;
public abstract class BrigadierCommand extends ChatStatic { public abstract class BrigadierCommand extends ChatStatic {
private LiteralCommandNode<CommandSender> commandNode;
protected BrigadierDispatcher dispatcher; protected BrigadierDispatcher dispatcher;
public BrigadierCommand() { public BrigadierCommand() {
@ -56,8 +54,8 @@ public abstract class BrigadierCommand extends ChatStatic {
} }
if (aliases == null) if (aliases == null)
aliases = new String[0]; aliases = new String[0];
commandNode = dispatcher.register(builder); LiteralCommandNode<CommandSender> commandNode = dispatcher.register(builder);
// still have to be registered for console // still have to be registered for console
BungeeCord.getInstance().getPluginManager().registerCommand(dispatcher.plugin, new CommandRelay(commandNode.getLiteral())); BungeeCord.getInstance().getPluginManager().registerCommand(dispatcher.plugin, new CommandRelay(commandNode.getLiteral()));
@ -75,7 +73,7 @@ public abstract class BrigadierCommand extends ChatStatic {
} }
private class CommandRelay extends Command implements TabExecutor { private class CommandRelay extends Command implements TabExecutor {
private String alias; private final String alias;
public CommandRelay(String alias) { public CommandRelay(String alias) {
super(alias); super(alias);
this.alias = alias; this.alias = alias;
@ -98,7 +96,7 @@ public abstract class BrigadierCommand extends ChatStatic {
return suggestions.getList() return suggestions.getList()
.stream() .stream()
.filter(s -> s.getRange().equals(supportedRange)) .filter(s -> s.getRange().equals(supportedRange))
.map(s -> s.getText()) .map(Suggestion::getText)
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
} }
@ -125,7 +123,7 @@ public abstract class BrigadierCommand extends ChatStatic {
} }
public static Predicate<CommandSender> isPlayer() { public static Predicate<CommandSender> isPlayer() {
return sender -> isPlayer(sender); return BrigadierCommand::isPlayer;
} }
public static boolean isPlayer(CommandSender sender) { public static boolean isPlayer(CommandSender sender) {
@ -133,7 +131,7 @@ public abstract class BrigadierCommand extends ChatStatic {
} }
public static Predicate<CommandSender> isConsole() { public static Predicate<CommandSender> isConsole() {
return sender -> isConsole(sender); return BrigadierCommand::isConsole;
} }
public static boolean isConsole(CommandSender sender) { public static boolean isConsole(CommandSender sender) {
@ -172,16 +170,14 @@ public abstract class BrigadierCommand extends ChatStatic {
String message = builder.getInput(); String message = builder.getInput();
try { try {
int tokenStartPos = builder.getStart(); int tokenStartPos = builder.getStart();
List<String> results = Collections.emptyList();
int firstSpacePos = message.indexOf(" "); int firstSpacePos = message.indexOf(" ");
String[] args = (firstSpacePos + 1 > tokenStartPos - 1) ? new String[0] String[] args = (firstSpacePos + 1 > tokenStartPos - 1) ? new String[0]
: message.substring(firstSpacePos + 1, tokenStartPos - 1).split(" ", -1); : message.substring(firstSpacePos + 1, tokenStartPos - 1).split(" ", -1);
args = Arrays.copyOf(args, args.length + 1); args = Arrays.copyOf(args, args.length + 1);
args[args.length - 1] = message.substring(tokenStartPos); args[args.length - 1] = message.substring(tokenStartPos);
results = suggestions.getSuggestions(sender, args.length - 1, args[args.length - 1], args); List<String> results = suggestions.getSuggestions(sender, args.length - 1, args[args.length - 1], args);
for (String s : results) { for (String s : results) {
if (s != null) if (s != null)

View File

@ -46,8 +46,8 @@ public class BrigadierDispatcher implements Listener {
private CommandDispatcher<CommandSender> dispatcher; private final CommandDispatcher<CommandSender> dispatcher;
/* package */ Plugin plugin; /* package */ final Plugin plugin;
private BrigadierDispatcher(Plugin pl) { private BrigadierDispatcher(Plugin pl) {
plugin = pl; plugin = pl;
@ -114,27 +114,23 @@ public class BrigadierDispatcher implements Listener {
event.setCancelled(true); event.setCancelled(true);
ProxyServer.getInstance().getScheduler().runAsync(plugin, () -> { ProxyServer.getInstance().getScheduler().runAsync(plugin, () -> execute((ProxiedPlayer) event.getSender(), commandLine));
execute((ProxiedPlayer) event.getSender(), commandLine);
});
} }
/* package */ int execute(CommandSender sender, String commandWithoutSlash) { /* package */ void execute(CommandSender sender, String commandWithoutSlash) {
ParseResults<CommandSender> parsed = dispatcher.parse(commandWithoutSlash, sender); ParseResults<CommandSender> parsed = dispatcher.parse(commandWithoutSlash, sender);
try { try {
return dispatcher.execute(parsed); dispatcher.execute(parsed);
} catch (CommandSyntaxException e) { } catch (CommandSyntaxException e) {
sender.sendMessage(Chat.failureText("Erreur d'utilisation de la commande : " + e.getMessage()).get()); sender.sendMessage(Chat.failureText("Erreur d'utilisation de la commande : " + e.getMessage()).get());
return 0;
} catch (Throwable e) { } catch (Throwable e) {
sender.sendMessage(Chat.failureText("Erreur lors de l'exécution de la commande : " + e.getMessage()).get()); sender.sendMessage(Chat.failureText("Erreur lors de l'exécution de la commande : " + e.getMessage()).get());
Log.severe(e); Log.severe(e);
return 0;
} }
} }

View File

@ -25,7 +25,7 @@ public class PluginMessagePassthrough implements Listener {
public static void clear() { public static void clear() {
synchronized (channels) { synchronized (channels) {
new ArrayList<>(channels).forEach(c -> unregister(c)); unregisterAll(channels.toArray(new String[0]));
} }
} }

View File

@ -1,7 +1,6 @@
package fr.pandacube.lib.cli; package fr.pandacube.lib.cli;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@ -22,16 +21,14 @@ import fr.pandacube.lib.core.util.Log;
import fr.pandacube.lib.core.util.Reflect; import fr.pandacube.lib.core.util.Reflect;
public abstract class BrigadierCommand extends ChatStatic { public abstract class BrigadierCommand extends ChatStatic {
private LiteralCommandNode<Object> commandNode;
public BrigadierCommand() { public BrigadierCommand() {
LiteralArgumentBuilder<Object> builder = buildCommand(); LiteralArgumentBuilder<Object> builder = buildCommand();
String[] aliases = getAliases(); String[] aliases = getAliases();
if (aliases == null) if (aliases == null)
aliases = new String[0]; aliases = new String[0];
commandNode = BrigadierDispatcher.instance.register(builder); LiteralCommandNode<Object> commandNode = BrigadierDispatcher.instance.register(builder);
for (String alias : aliases) { for (String alias : aliases) {
@ -94,16 +91,14 @@ public abstract class BrigadierCommand extends ChatStatic {
String message = builder.getInput(); String message = builder.getInput();
try { try {
int tokenStartPos = builder.getStart(); int tokenStartPos = builder.getStart();
List<String> results = Collections.emptyList();
int firstSpacePos = message.indexOf(" "); int firstSpacePos = message.indexOf(" ");
String[] args = (firstSpacePos + 1 > tokenStartPos - 1) ? new String[0] String[] args = (firstSpacePos + 1 > tokenStartPos - 1) ? new String[0]
: message.substring(firstSpacePos + 1, tokenStartPos - 1).split(" ", -1); : message.substring(firstSpacePos + 1, tokenStartPos - 1).split(" ", -1);
args = Arrays.copyOf(args, args.length + 1); args = Arrays.copyOf(args, args.length + 1);
args[args.length - 1] = message.substring(tokenStartPos); args[args.length - 1] = message.substring(tokenStartPos);
results = suggestions.getSuggestions(sender, args.length - 1, args[args.length - 1], args); List<String> results = suggestions.getSuggestions(sender, args.length - 1, args[args.length - 1], args);
for (String s : results) { for (String s : results) {
if (s != null) if (s != null)

View File

@ -31,9 +31,9 @@ public class BrigadierDispatcher implements Completer {
private CommandDispatcher<Object> dispatcher; private final CommandDispatcher<Object> dispatcher;
private Object sender = new Object(); private final Object sender = new Object();
public BrigadierDispatcher() { public BrigadierDispatcher() {
dispatcher = new CommandDispatcher<>(); dispatcher = new CommandDispatcher<>();
@ -69,7 +69,9 @@ public class BrigadierDispatcher implements Completer {
Suggestions completeResult = getSuggestions(bufferBeforeCursor); Suggestions completeResult = getSuggestions(bufferBeforeCursor);
completeResult.getList().stream().map(s -> s.getText()).forEach(candidates::add); completeResult.getList().stream()
.map(Suggestion::getText)
.forEach(candidates::add);
return completeResult.getRange().getStart(); return completeResult.getRange().getStart();
} }

View File

@ -38,8 +38,8 @@ public class CLI {
private ConsoleReader reader; private final ConsoleReader reader;
private Logger logger; private final Logger logger;
public CLI() throws IOException { public CLI() throws IOException {
@ -78,9 +78,7 @@ public class CLI {
if (line.trim().equals("")) if (line.trim().equals(""))
continue; continue;
String cmdLine = line; String cmdLine = line;
new Thread(() -> { new Thread(() -> BrigadierDispatcher.instance.execute(cmdLine), "CLICmdThread #"+(i++)).start();
BrigadierDispatcher.instance.execute(cmdLine);
}, "CLICmdThread #"+(i++)).start();
} }
} catch (IOException e) { } catch (IOException e) {

View File

@ -12,9 +12,9 @@ import java.util.logging.Handler;
import java.util.logging.LogRecord; import java.util.logging.LogRecord;
class DailyLogRotateFileHandler extends Handler { class DailyLogRotateFileHandler extends Handler {
private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
private BufferedWriter currentFile = null; private BufferedWriter currentFile = null;
private DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
private String currentFileDate = getCurrentDay(); private String currentFileDate = getCurrentDay();
private boolean closed = false; private boolean closed = false;
@ -24,7 +24,7 @@ class DailyLogRotateFileHandler extends Handler {
closed = true; closed = true;
if (currentFile != null) try { if (currentFile != null) try {
currentFile.close(); currentFile.close();
} catch (IOException e) {} } catch (IOException ignored) {}
} }
@Override @Override
@ -33,7 +33,7 @@ class DailyLogRotateFileHandler extends Handler {
if (currentFile == null) return; if (currentFile == null) return;
try { try {
currentFile.flush(); currentFile.flush();
} catch (IOException e) {} } catch (IOException ignored) {}
} }
@Override @Override
@ -68,7 +68,7 @@ class DailyLogRotateFileHandler extends Handler {
try { try {
currentFile.flush(); currentFile.flush();
currentFile.close(); currentFile.close();
} catch (IOException e) {} } catch (IOException ignored) {}
new File("logs/latest.log").renameTo(new File("logs/" + currentFileDate + ".log")); new File("logs/latest.log").renameTo(new File("logs/" + currentFileDate + ".log"));
} }
@ -76,11 +76,10 @@ class DailyLogRotateFileHandler extends Handler {
try { try {
File logDir = new File("logs"); File logDir = new File("logs");
logDir.mkdir(); logDir.mkdir();
currentFile = new BufferedWriter(new FileWriter(new File("logs/latest.log"), true)); currentFile = new BufferedWriter(new FileWriter("logs/latest.log", true));
} catch (SecurityException | IOException e) { } catch (SecurityException | IOException e) {
reportError("Erreur lors de l'initialisation d'un fichier log", e, ErrorManager.OPEN_FAILURE); reportError("Erreur lors de l'initialisation d'un fichier log", e, ErrorManager.OPEN_FAILURE);
currentFile = null; currentFile = null;
return;
} }
} }

View File

@ -36,24 +36,24 @@
<dependency> <dependency>
<groupId>net.kyori</groupId> <groupId>net.kyori</groupId>
<artifactId>adventure-api</artifactId> <artifactId>adventure-api</artifactId>
<version>4.8.1</version> <version>4.11.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.kyori</groupId> <groupId>net.kyori</groupId>
<artifactId>adventure-platform-bungeecord</artifactId> <artifactId>adventure-platform-bungeecord</artifactId>
<version>4.0.1-SNAPSHOT</version> <version>4.1.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.kyori</groupId> <groupId>net.kyori</groupId>
<artifactId>adventure-text-serializer-plain</artifactId> <artifactId>adventure-text-serializer-plain</artifactId>
<version>4.8.1</version> <version>4.11.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.github.classgraph</groupId> <groupId>io.github.classgraph</groupId>
<artifactId>classgraph</artifactId> <artifactId>classgraph</artifactId>
<version>4.8.108</version> <version>4.8.147</version>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -36,7 +36,7 @@ import net.md_5.bungee.api.chat.BaseComponent;
public abstract sealed class Chat extends ChatStatic implements HoverEventSource<Component>, ComponentLike { public abstract sealed class Chat extends ChatStatic implements HoverEventSource<Component>, ComponentLike {
protected ComponentBuilder<?, ?> builder; protected final ComponentBuilder<?, ?> builder;
protected boolean console = false; protected boolean console = false;
/* package */ Chat(ComponentBuilder<?, ?> b) { /* package */ Chat(ComponentBuilder<?, ?> b) {
@ -76,12 +76,11 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource
public Chat then(Component comp) { public Chat then(Component comp) {
if (comp instanceof TextComponent) { if (comp instanceof TextComponent txtComp) {
TextComponent txtComp = (TextComponent) comp; if (!txtComp.hasStyling() && (txtComp.content().isEmpty())) {
if (!txtComp.hasStyling() && (txtComp.content() == null || txtComp.content().isEmpty())) {
// no need to add the provided component to the current component. // no need to add the provided component to the current component.
// but eventual child component must be added // but eventual child component must be added
if (txtComp.children() != null && !txtComp.children().isEmpty()) { if (!txtComp.children().isEmpty()) {
for (Component child : txtComp.children()) for (Component child : txtComp.children())
then(child); then(child);
} }
@ -313,9 +312,8 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj == null || !(obj instanceof Chat)) return obj instanceof Chat c
return false; && getAdv().equals(c.getAdv());
return getAdv().equals(((Chat)obj).getAdv());
} }
@Override @Override
@ -330,18 +328,7 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource
/* package */ static Object[] filterChatToBaseComponent(Object[] values) {
if (values == null)
return null;
for (int i = 0; i < values.length; i++) {
Object v = values[i];
if (v instanceof Chat)
values[i] = ((Chat) v).get();
}
return values;
}
/* package */ static ComponentLike[] filterObjToComponentLike(Object[] values) { /* package */ static ComponentLike[] filterObjToComponentLike(Object[] values) {
if (values == null) if (values == null)

View File

@ -18,18 +18,16 @@ public class ChatColorUtil {
public static final String ALL_COLORS = "0123456789AaBbCcDdEeFf"; public static final String ALL_COLORS = "0123456789AaBbCcDdEeFf";
private static Pattern HEX_COLOR_PATTERN = Pattern.compile("§x(?>§[0-9a-f]){6}", Pattern.CASE_INSENSITIVE); private static final Pattern HEX_COLOR_PATTERN = Pattern.compile("§x(?>§[\\da-f]){6}", Pattern.CASE_INSENSITIVE);
private static Pattern ESS_COLOR_PATTERN = Pattern.compile("§#[0-9a-f]{6}", Pattern.CASE_INSENSITIVE); private static final Pattern ESS_COLOR_PATTERN = Pattern.compile("§#[\\da-f]{6}", Pattern.CASE_INSENSITIVE);
/** /**
* Return the legacy format needed to reproduce the format at the end of the provided legacy text. * Return the legacy format needed to reproduce the format at the end of the provided legacy text.
* Supports standard chat colors and formats, BungeeCord Chat rgb format and EssentialsX rgb format. * Supports standard chat colors and formats, BungeeCord Chat rgb format and EssentialsX rgb format.
* The RGB value from EssentialsX format is converted to BungeeCord Chat when included in the returned value. * The RGB value from EssentialsX format is converted to BungeeCord Chat when included in the returned value.
* @param legacyText
* @return
*/ */
public static String getLastColors(String legacyText) { public static String getLastColors(String legacyText) {
String result = ""; StringBuilder result = new StringBuilder();
int length = legacyText.length(); int length = legacyText.length();
for (int index = length - 2; index >= 0; index--) { for (int index = length - 2; index >= 0; index--) {
@ -42,7 +40,7 @@ public class ChatColorUtil {
&& (legacyText.charAt(index - 11) == 'x' && (legacyText.charAt(index - 11) == 'x'
|| legacyText.charAt(index - 11) == 'X') || legacyText.charAt(index - 11) == 'X')
&& HEX_COLOR_PATTERN.matcher(rgb = legacyText.substring(index - 12, index + 2)).matches()) { && HEX_COLOR_PATTERN.matcher(rgb = legacyText.substring(index - 12, index + 2)).matches()) {
result = rgb + result; result.insert(0, rgb);
break; break;
} }
@ -53,7 +51,7 @@ public class ChatColorUtil {
rgb = "§x§" + rgb.charAt(2) + "§" + rgb.charAt(3) rgb = "§x§" + rgb.charAt(2) + "§" + rgb.charAt(3)
+ "§" + rgb.charAt(4) + "§" + rgb.charAt(5) + "§" + rgb.charAt(4) + "§" + rgb.charAt(5)
+ "§" + rgb.charAt(6) + "§" + rgb.charAt(7); + "§" + rgb.charAt(6) + "§" + rgb.charAt(7);
result = rgb + result; result.insert(0, rgb);
break; break;
} }
@ -62,7 +60,7 @@ public class ChatColorUtil {
ChatColor legacyColor = getChatColorByChar(colorChar); ChatColor legacyColor = getChatColorByChar(colorChar);
if (legacyColor != null) { if (legacyColor != null) {
result = legacyColor.toString() + result; result.insert(0, legacyColor);
// Once we find a color or reset we can stop searching // Once we find a color or reset we can stop searching
char col = legacyColor.toString().charAt(1); char col = legacyColor.toString().charAt(1);
@ -75,7 +73,7 @@ public class ChatColorUtil {
} }
} }
return result; return result.toString();
} }
public static ChatColor getChatColorByChar(char code) { public static ChatColor getChatColorByChar(char code) {
@ -215,7 +213,7 @@ public class ChatColorUtil {
private static String forceFormat(String legacyText, ChatColor format) { private static String forceFormat(String legacyText, ChatColor format) {
return format + legacyText return format + legacyText
.replace(format.toString(), "") // remove previous tag to make the result cleaner .replace(format.toString(), "") // remove previous tag to make the result cleaner
.replaceAll("§([a-frA-FR0-9])", "§$1" + format); .replaceAll("§([a-frA-FR\\d])", "§$1" + format);
} }
@ -270,7 +268,7 @@ public class ChatColorUtil {
public static class ChatValueGradient { public static class ChatValueGradient {
private record GradientValueColor(float value, TextColor color) { } // Java 16 private record GradientValueColor(float value, TextColor color) { } // Java 16
List<GradientValueColor> colors = new ArrayList<>(); final List<GradientValueColor> colors = new ArrayList<>();
public synchronized ChatValueGradient add(float v, TextColor col) { public synchronized ChatValueGradient add(float v, TextColor col) {
colors.add(new GradientValueColor(v, col)); colors.add(new GradientValueColor(v, col));

View File

@ -114,16 +114,5 @@ public abstract class ChatStatic {
} }
// public static void main(String[] args) {
// for (Chat c : new Chat[] {
// chat(),
// text("toto").color(NamedTextColor.GRAY),
// legacyText("tot§9o").color(NamedTextColor.GRAY),
// }) {
// System.out.println(GsonComponentSerializer.gson().serialize(c.getAdv()));
// }
// }
} }

View File

@ -1,9 +1,5 @@
package fr.pandacube.lib.core.chat; package fr.pandacube.lib.core.chat;
import static fr.pandacube.lib.core.chat.ChatStatic.chat;
import static fr.pandacube.lib.core.chat.ChatStatic.legacyText;
import static fr.pandacube.lib.core.chat.ChatStatic.text;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -13,8 +9,6 @@ import java.util.TreeSet;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import fr.pandacube.lib.core.chat.Chat.FormatableChat;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.TranslatableComponent; import net.kyori.adventure.text.TranslatableComponent;
@ -24,6 +18,12 @@ import net.kyori.adventure.text.format.TextDecoration;
import net.kyori.adventure.text.format.TextDecoration.State; import net.kyori.adventure.text.format.TextDecoration.State;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
import fr.pandacube.lib.core.chat.Chat.FormatableChat;
import static fr.pandacube.lib.core.chat.ChatStatic.chat;
import static fr.pandacube.lib.core.chat.ChatStatic.legacyText;
import static fr.pandacube.lib.core.chat.ChatStatic.text;
public class ChatUtil { public class ChatUtil {
public static final int DEFAULT_CHAR_SIZE = 6; public static final int DEFAULT_CHAR_SIZE = 6;
@ -328,12 +328,10 @@ public class ChatUtil {
for (Component c : ((TranslatableComponent)component).args()) for (Component c : ((TranslatableComponent)component).args())
count += componentWidth(c, console, actuallyBold); count += componentWidth(c, console, actuallyBold);
} }
if (component.children() != null) { for (Component c : component.children())
for (Component c : component.children()) count += componentWidth(c, console, actuallyBold);
count += componentWidth(c, console, actuallyBold);
}
return count; return count;
} }
@ -345,7 +343,7 @@ public class ChatUtil {
int count = 0; int count = 0;
for (char c : str.toCharArray()) for (char c : str.toCharArray())
count += charW(c, console, bold); count += charW(c, console, bold);
return (count < 0) ? 0 : count; return Math.max(count, 0);
} }
public static int charW(char c, boolean console, boolean bold) { public static int charW(char c, boolean console, boolean bold) {
@ -364,7 +362,7 @@ public class ChatUtil {
public static List<Chat> wrapInLimitedPixelsToChat(String legacyText, int pixelWidth) { public static List<Chat> wrapInLimitedPixelsToChat(String legacyText, int pixelWidth) {
return wrapInLimitedPixels(legacyText, pixelWidth).stream() return wrapInLimitedPixels(legacyText, pixelWidth).stream()
.map(t -> legacyText(t)) .map(ChatStatic::legacyText)
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@ -377,7 +375,7 @@ public class ChatUtil {
int currentLineSize = 0; int currentLineSize = 0;
int index = 0; int index = 0;
String currentWord = ""; StringBuilder currentWord = new StringBuilder();
int currentWordSize = 0; int currentWordSize = 0;
boolean bold = false; boolean bold = false;
boolean firstCharCurrentWordBold = false; boolean firstCharCurrentWordBold = false;
@ -385,9 +383,9 @@ public class ChatUtil {
do { do {
char c = legacyText.charAt(index); char c = legacyText.charAt(index);
if (c == ChatColor.COLOR_CHAR && index < legacyText.length() - 1) { if (c == ChatColor.COLOR_CHAR && index < legacyText.length() - 1) {
currentWord += c; currentWord.append(c);
c = legacyText.charAt(++index); c = legacyText.charAt(++index);
currentWord += c; currentWord.append(c);
if (c == 'l' || c == 'L') // bold if (c == 'l' || c == 'L') // bold
bold = true; bold = true;
@ -404,7 +402,7 @@ public class ChatUtil {
lines.add(currentLine); lines.add(currentLine);
String lastStyle = ChatColorUtil.getLastColors(currentLine); String lastStyle = ChatColorUtil.getLastColors(currentLine);
if (currentWord.charAt(0) == ' ') { if (currentWord.charAt(0) == ' ') {
currentWord = currentWord.substring(1); currentWord = new StringBuilder(currentWord.substring(1));
currentWordSize -= charW(' ', false, firstCharCurrentWordBold); currentWordSize -= charW(' ', false, firstCharCurrentWordBold);
} }
currentLine = (lastStyle.equals("§r") ? "" : lastStyle) + currentWord; currentLine = (lastStyle.equals("§r") ? "" : lastStyle) + currentWord;
@ -414,7 +412,7 @@ public class ChatUtil {
currentLine += currentWord; currentLine += currentWord;
currentLineSize += currentWordSize; currentLineSize += currentWordSize;
} }
currentWord = ""+c; currentWord = new StringBuilder("" + c);
currentWordSize = charW(c, false, bold); currentWordSize = charW(c, false, bold);
firstCharCurrentWordBold = bold; firstCharCurrentWordBold = bold;
} }
@ -423,15 +421,12 @@ public class ChatUtil {
lines.add(currentLine); lines.add(currentLine);
String lastStyle = ChatColorUtil.getLastColors(currentLine); String lastStyle = ChatColorUtil.getLastColors(currentLine);
if (currentWord.charAt(0) == ' ') { if (currentWord.charAt(0) == ' ') {
currentWord = currentWord.substring(1); currentWord = new StringBuilder(currentWord.substring(1));
currentWordSize -= charW(' ', false, firstCharCurrentWordBold);
} }
currentLine = (lastStyle.equals("§r") ? "" : lastStyle) + currentWord; currentLine = (lastStyle.equals("§r") ? "" : lastStyle) + currentWord;
currentLineSize = currentWordSize;
} }
else { else {
currentLine += currentWord; currentLine += currentWord;
currentLineSize += currentWordSize;
} }
// wrap after // wrap after
lines.add(currentLine); lines.add(currentLine);
@ -439,12 +434,12 @@ public class ChatUtil {
currentLine = lastStyle.equals("§r") ? "" : lastStyle; currentLine = lastStyle.equals("§r") ? "" : lastStyle;
currentLineSize = 0; currentLineSize = 0;
currentWord = ""; currentWord = new StringBuilder();
currentWordSize = 0; currentWordSize = 0;
firstCharCurrentWordBold = bold; firstCharCurrentWordBold = bold;
} }
else { else {
currentWord += c; currentWord.append(c);
currentWordSize += charW(c, false, bold); currentWordSize += charW(c, false, bold);
} }
@ -674,7 +669,6 @@ public class ChatUtil {
* *
* Each element in the returned list represent 1 line of the tree view. * Each element in the returned list represent 1 line of the tree view.
* Thus, the caller may send each line separately or at once depending of the quantity of data. * Thus, the caller may send each line separately or at once depending of the quantity of data.
* @param node
* @return A array of component, each element being a single line. * @return A array of component, each element being a single line.
*/ */
public static List<Chat> treeView(DisplayTreeNode node, boolean console) { public static List<Chat> treeView(DisplayTreeNode node, boolean console) {

View File

@ -30,11 +30,8 @@ public class AbstractCommand extends ChatStatic {
* Le premier élément est l'argument qui suit le nom de la commande. * Le premier élément est l'argument qui suit le nom de la commande.
* Usuellement, ce paramètre correspond au paramètre * Usuellement, ce paramètre correspond au paramètre
* <code>args</code> de la méthode onCommand * <code>args</code> de la méthode onCommand
* @param index
* @return
*/ */
public static String getLastParams(String[] args, int index) { public static String getLastParams(String[] args, int index) {
if (index < 0 || index >= args.length) return null;
return String.join(" ", Arrays.copyOfRange(args, index, args.length)); return String.join(" ", Arrays.copyOfRange(args, index, args.length));
} }

View File

@ -11,7 +11,6 @@ import java.util.logging.Logger;
* *
*/ */
public class BadCommandUsage extends RuntimeException { public class BadCommandUsage extends RuntimeException {
private static final long serialVersionUID = 1L;
public BadCommandUsage() { public BadCommandUsage() {
super(); super();

View File

@ -19,17 +19,17 @@ public interface SuggestionsSupplier<S> {
/** /**
* Number of suggestion visible at once without having to scroll * Number of suggestion visible at once without having to scroll
*/ */
public static int VISIBLE_SUGGESTION_COUNT = 10; int VISIBLE_SUGGESTION_COUNT = 10;
public abstract List<String> getSuggestions(S sender, int tokenIndex, String token, String[] args); List<String> getSuggestions(S sender, int tokenIndex, String token, String[] args);
public static Predicate<String> filter(String token) { static Predicate<String> filter(String token) {
return suggestion -> suggestion != null && suggestion.toLowerCase().startsWith(token.toLowerCase()); return suggestion -> suggestion != null && suggestion.toLowerCase().startsWith(token.toLowerCase());
} }
@ -39,7 +39,7 @@ public interface SuggestionsSupplier<S> {
* *
* This methods consume the provided stream, so will not be usable anymore. * This methods consume the provided stream, so will not be usable anymore.
*/ */
public static List<String> collectFilteredStream(Stream<String> stream, String token) { static List<String> collectFilteredStream(Stream<String> stream, String token) {
return stream.filter(filter(token)).sorted().collect(Collectors.toList()); return stream.filter(filter(token)).sorted().collect(Collectors.toList());
} }
@ -47,40 +47,40 @@ public interface SuggestionsSupplier<S> {
public static <S> SuggestionsSupplier<S> empty() { return (s, ti, t, a) -> Collections.emptyList(); } static <S> SuggestionsSupplier<S> empty() { return (s, ti, t, a) -> Collections.emptyList(); }
public static <S> SuggestionsSupplier<S> fromCollectionsSupplier(Supplier<Collection<String>> streamSupplier) { static <S> SuggestionsSupplier<S> fromCollectionsSupplier(Supplier<Collection<String>> streamSupplier) {
return (s, ti, token, a) -> collectFilteredStream(streamSupplier.get().stream(), token); return (s, ti, token, a) -> collectFilteredStream(streamSupplier.get().stream(), token);
} }
public static <S> SuggestionsSupplier<S> fromStreamSupplier(Supplier<Stream<String>> streamSupplier) { static <S> SuggestionsSupplier<S> fromStreamSupplier(Supplier<Stream<String>> streamSupplier) {
return (s, ti, token, a) -> collectFilteredStream(streamSupplier.get(), token); return (s, ti, token, a) -> collectFilteredStream(streamSupplier.get(), token);
} }
public static <S> SuggestionsSupplier<S> fromCollection(Collection<String> suggestions) { static <S> SuggestionsSupplier<S> fromCollection(Collection<String> suggestions) {
return fromStreamSupplier(suggestions::stream); return fromStreamSupplier(suggestions::stream);
} }
public static <S> SuggestionsSupplier<S> fromArray(String... suggestions) { static <S> SuggestionsSupplier<S> fromArray(String... suggestions) {
return fromStreamSupplier(() -> Arrays.stream(suggestions)); return fromStreamSupplier(() -> Arrays.stream(suggestions));
} }
public static <E extends Enum<E>, S> SuggestionsSupplier<S> fromEnum(Class<E> enumClass) { static <E extends Enum<E>, S> SuggestionsSupplier<S> fromEnum(Class<E> enumClass) {
return fromEnumValues(enumClass.getEnumConstants()); return fromEnumValues(enumClass.getEnumConstants());
} }
public static <E extends Enum<E>, S> SuggestionsSupplier<S> fromEnum(Class<E> enumClass, boolean lowerCase) { static <E extends Enum<E>, S> SuggestionsSupplier<S> fromEnum(Class<E> enumClass, boolean lowerCase) {
return fromEnumValues(lowerCase, enumClass.getEnumConstants()); return fromEnumValues(lowerCase, enumClass.getEnumConstants());
} }
@SafeVarargs @SafeVarargs
public static <E extends Enum<E>, S> SuggestionsSupplier<S> fromEnumValues(E... enumValues) { static <E extends Enum<E>, S> SuggestionsSupplier<S> fromEnumValues(E... enumValues) {
return fromEnumValues(false, enumValues); return fromEnumValues(false, enumValues);
} }
@SafeVarargs @SafeVarargs
public static <E extends Enum<E>, S> SuggestionsSupplier<S> fromEnumValues(boolean lowerCase, E... enumValues) { static <E extends Enum<E>, S> SuggestionsSupplier<S> fromEnumValues(boolean lowerCase, E... enumValues) {
return (s, ti, token, a) -> { return (s, ti, token, a) -> {
Stream<String> st = Arrays.stream(enumValues).map(Enum::name); Stream<String> st = Arrays.stream(enumValues).map(Enum::name);
if (lowerCase) if (lowerCase)
@ -91,7 +91,7 @@ public interface SuggestionsSupplier<S> {
public static <S> SuggestionsSupplier<S> booleanValues() { static <S> SuggestionsSupplier<S> booleanValues() {
return fromCollection(Arrays.asList("true", "false")); return fromCollection(Arrays.asList("true", "false"));
} }
@ -103,11 +103,8 @@ public interface SuggestionsSupplier<S> {
* Create a {@link SuggestionsSupplier} that suggest numbers according to the provided range. * Create a {@link SuggestionsSupplier} that suggest numbers according to the provided range.
* *
* The current implementation only support range that include either -1 or 1. * The current implementation only support range that include either -1 or 1.
* @param min
* @param max
* @return
*/ */
public static <S> SuggestionsSupplier<S> fromIntRange(int min, int max, boolean compact) { static <S> SuggestionsSupplier<S> fromIntRange(int min, int max, boolean compact) {
return fromLongRange(min, max, compact); return fromLongRange(min, max, compact);
} }
@ -118,11 +115,8 @@ public interface SuggestionsSupplier<S> {
* Create a {@link SuggestionsSupplier} that suggest numbers according to the provided range. * Create a {@link SuggestionsSupplier} that suggest numbers according to the provided range.
* *
* The current implementation only support range that include either -1 or 1. * The current implementation only support range that include either -1 or 1.
* @param min
* @param max
* @return
*/ */
public static <S> SuggestionsSupplier<S> fromLongRange(long min, long max, boolean compact) { static <S> SuggestionsSupplier<S> fromLongRange(long min, long max, boolean compact) {
if (max < min) { if (max < min) {
throw new IllegalArgumentException("min should be less or equals than max"); throw new IllegalArgumentException("min should be less or equals than max");
} }
@ -179,7 +173,7 @@ public interface SuggestionsSupplier<S> {
} }
} }
return collectFilteredStream(proposedValues.stream().map(i -> i.toString()), token); return collectFilteredStream(proposedValues.stream().map(Object::toString), token);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
return Collections.emptyList(); return Collections.emptyList();
} }
@ -196,9 +190,8 @@ public interface SuggestionsSupplier<S> {
/** /**
* Create a {@link SuggestionsSupplier} that support greedy strings argument using the suggestion from this {@link SuggestionsSupplier}. * Create a {@link SuggestionsSupplier} that support greedy strings argument using the suggestion from this {@link SuggestionsSupplier}.
* @param index the index of the first argument of the greedy string argument * @param index the index of the first argument of the greedy string argument
* @return
*/ */
public default SuggestionsSupplier<S> greedyString(int index) { default SuggestionsSupplier<S> greedyString(int index) {
return (s, ti, token, args) -> { return (s, ti, token, args) -> {
@ -233,7 +226,7 @@ public interface SuggestionsSupplier<S> {
public default SuggestionsSupplier<S> quotableString() { default SuggestionsSupplier<S> quotableString() {
return (s, ti, token, a) -> { return (s, ti, token, a) -> {
boolean startWithQuote = token.length() > 0 && (token.charAt(0) == '"' || token.charAt(0) == '\''); boolean startWithQuote = token.length() > 0 && (token.charAt(0) == '"' || token.charAt(0) == '\'');
String realToken = startWithQuote ? unescapeBrigadierQuotable(token.substring(1), token.charAt(0)) : token; String realToken = startWithQuote ? unescapeBrigadierQuotable(token.substring(1), token.charAt(0)) : token;
@ -309,10 +302,8 @@ public interface SuggestionsSupplier<S> {
public default SuggestionsSupplier<S> requires(Predicate<S> check) { default SuggestionsSupplier<S> requires(Predicate<S> check) {
return (s, ti, to, a) -> { return (s, ti, to, a) -> check.test(s) ? getSuggestions(s, ti, to, a) : Collections.emptyList();
return check.test(s) ? getSuggestions(s, ti, to, a) : Collections.emptyList();
};
} }
@ -320,10 +311,8 @@ public interface SuggestionsSupplier<S> {
/** /**
* Returns a new {@link SuggestionsSupplier} containing all the element of this instance then the element of the provided one, * Returns a new {@link SuggestionsSupplier} containing all the element of this instance then the element of the provided one,
* with all duplicated values removed using {@link Stream#distinct()}. * with all duplicated values removed using {@link Stream#distinct()}.
* @param other
* @return
*/ */
public default SuggestionsSupplier<S> merge(SuggestionsSupplier<S> other) { default SuggestionsSupplier<S> merge(SuggestionsSupplier<S> other) {
return (s, ti, to, a) -> { return (s, ti, to, a) -> {
List<String> l1 = getSuggestions(s, ti, to, a); List<String> l1 = getSuggestions(s, ti, to, a);
List<String> l2 = other.getSuggestions(s, ti, to, a); List<String> l2 = other.getSuggestions(s, ti, to, a);
@ -337,10 +326,8 @@ public interface SuggestionsSupplier<S> {
/** /**
* Returns a new {@link SuggestionsSupplier} containing all the suggestions of this instance, * Returns a new {@link SuggestionsSupplier} containing all the suggestions of this instance,
* but if this list is still empty, returns the suggestions from the provided one. * but if this list is still empty, returns the suggestions from the provided one.
* @param other
* @return
*/ */
public default SuggestionsSupplier<S> orIfEmpty(SuggestionsSupplier<S> other) { default SuggestionsSupplier<S> orIfEmpty(SuggestionsSupplier<S> other) {
return (s, ti, to, a) -> { return (s, ti, to, a) -> {
List<String> l1 = getSuggestions(s, ti, to, a); List<String> l1 = getSuggestions(s, ti, to, a);
return !l1.isEmpty() ? l1 : other.getSuggestions(s, ti, to, a); return !l1.isEmpty() ? l1 : other.getSuggestions(s, ti, to, a);

View File

@ -6,14 +6,12 @@ import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import fr.pandacube.lib.core.chat.ChatColorUtil; import fr.pandacube.lib.core.chat.ChatColorUtil;
import fr.pandacube.lib.core.util.Log; import fr.pandacube.lib.core.util.Log;
/** /**
* Classe chargeant en mémoire un fichier de configuration ou un dossier donné * Class tht loads a specific config file or directory
* @author Marc Baloup
* *
*/ */
public abstract class AbstractConfig { public abstract class AbstractConfig {
@ -22,12 +20,13 @@ public abstract class AbstractConfig {
* Correspond au dossier ou au fichier de configuration traité par la sous-classe * Correspond au dossier ou au fichier de configuration traité par la sous-classe
* courante de {@link AbstractConfig} * courante de {@link AbstractConfig}
*/ */
protected File configFile; protected final File configFile;
/** /**
* @param fileOrDirName le nom du fichier ou du dossier correspondant à la sous-classe de {@link AbstractConfig} * @param configDir the parent directory
* @param isDir <code>true</code> si il s'agit d'un dossier, <code>false</code> sinon * @param fileOrDirName The name of the config file or folder
* @throws IOException si le fichier est impossible à créer * @param type if the provided name is a file or a directory
* @throws IOException if we cannot create the file
*/ */
public AbstractConfig(File configDir, String fileOrDirName, FileType type) throws IOException { public AbstractConfig(File configDir, String fileOrDirName, FileType type) throws IOException {
configFile = new File(configDir, fileOrDirName); configFile = new File(configDir, fileOrDirName);
@ -38,13 +37,12 @@ public abstract class AbstractConfig {
} }
/** /**
* Retourne toutes les lignes d'un fichier donné * Gets the lines from the config file
* @param ignoreEmpty <code>true</code> si on doit ignorer les lignes vides * @param ignoreEmpty <code>true</code> if we ignore the empty lines
* @param ignoreHashtagComment <code>true</code> si on doit ignorer les lignes commentés (commençant par un #) * @param ignoreHashtagComment <code>true</code> if we ignore the comment lines (starting with {@code #})
* @param trimOutput <code>true</code> si on doit appeller la méthode String.trim() sur chaque ligne retournée * @param trimOutput <code>true</code> if we want to trim all lines using {@link String#trim()}
* @param f le fichier à lire * @param f the file to read
* @return la liste des lignes utiles * @return the list of lines, filtered according to the parameters
* @throws IOException
*/ */
protected List<String> getFileLines(boolean ignoreEmpty, boolean ignoreHashtagComment, boolean trimOutput, File f) throws IOException { protected List<String> getFileLines(boolean ignoreEmpty, boolean ignoreHashtagComment, boolean trimOutput, File f) throws IOException {
if (!f.isFile()) if (!f.isFile())
@ -83,7 +81,6 @@ public abstract class AbstractConfig {
* @param ignoreHashtagComment <code>true</code> si on doit ignorer les lignes commentés (commençant par un #) * @param ignoreHashtagComment <code>true</code> si on doit ignorer les lignes commentés (commençant par un #)
* @param trimOutput <code>true</code> si on doit appeller la méthode String.trim() sur chaque ligne retournée * @param trimOutput <code>true</code> si on doit appeller la méthode String.trim() sur chaque ligne retournée
* @return la liste des lignes utiles * @return la liste des lignes utiles
* @throws IOException
*/ */
protected List<String> getFileLines(boolean ignoreEmpty, boolean ignoreHashtagComment, boolean trimOutput) throws IOException { protected List<String> getFileLines(boolean ignoreEmpty, boolean ignoreHashtagComment, boolean trimOutput) throws IOException {
return getFileLines(ignoreEmpty, ignoreHashtagComment, trimOutput, configFile); return getFileLines(ignoreEmpty, ignoreHashtagComment, trimOutput, configFile);
@ -119,7 +116,7 @@ public abstract class AbstractConfig {
public static List<String> getSplittedString(String value, String split) { public static List<String> getSplittedString(String value, String split) {
return Collections.unmodifiableList(Arrays.asList(value.split(split))); return List.of(value.split(split));
} }

View File

@ -17,13 +17,11 @@ public abstract class AbstractConfigManager {
/** /**
* Implementation must close all closeable configuration (saving for example) * Implementation must close all closeable configuration (saving for example)
* @throws IOException
*/ */
public abstract void close() throws IOException; public abstract void close() throws IOException;
/** /**
* Implementation must init all config data * Implementation must init all config data
* @throws IOException
*/ */
public abstract void init() throws IOException; public abstract void init() throws IOException;

View File

@ -18,15 +18,15 @@ import fr.pandacube.lib.core.util.Log;
/** /**
* Static class to handle most of the database operations. * Static class to handle most of the database operations.
* *
* To use this database library, first call {@link #init(DBConnection)} with an appropriate {@link DBConnection}, * To use this database library, first call {@link #init(DBConnection, String)} with an appropriate {@link DBConnection},
* they you can initialize every table you need for your application, using {@link #initTable(Class)}. * they you can initialize every table you need for your application, using {@link #initTable(Class)}.
* *
* @author Marc Baloup * @author Marc Baloup
*/ */
public final class DB { public final class DB {
private static List<Class<? extends SQLElement<?>>> tables = new ArrayList<>(); private static final List<Class<? extends SQLElement<?>>> tables = new ArrayList<>();
private static Map<Class<? extends SQLElement<?>>, String> tableNames = new HashMap<>(); private static final Map<Class<? extends SQLElement<?>>, String> tableNames = new HashMap<>();
private static DBConnection connection; private static DBConnection connection;
/* package */ static String tablePrefix = ""; /* package */ static String tablePrefix = "";
@ -35,7 +35,7 @@ public final class DB {
return connection; return connection;
} }
public synchronized static <E extends SQLElement<E>> void init(DBConnection conn, String tablePrefix) { public synchronized static void init(DBConnection conn, String tablePrefix) {
connection = conn; connection = conn;
DB.tablePrefix = Objects.requireNonNull(tablePrefix); DB.tablePrefix = Objects.requireNonNull(tablePrefix);
} }
@ -62,7 +62,7 @@ public final class DB {
String tableName = tablePrefix + elem.tableName(); String tableName = tablePrefix + elem.tableName();
String sql = "CREATE TABLE IF NOT EXISTS " + tableName + " ("; StringBuilder sql = new StringBuilder("CREATE TABLE IF NOT EXISTS " + tableName + " (");
List<Object> params = new ArrayList<>(); List<Object> params = new ArrayList<>();
Collection<SQLField<E, ?>> tableFields = elem.getFields().values(); Collection<SQLField<E, ?>> tableFields = elem.getFields().values();
@ -71,14 +71,15 @@ public final class DB {
ParameterizedSQLString statementPart = f.forSQLPreparedStatement(); ParameterizedSQLString statementPart = f.forSQLPreparedStatement();
params.addAll(statementPart.parameters()); params.addAll(statementPart.parameters());
if (!first) sql += ", "; if (!first)
sql.append(", ");
first = false; first = false;
sql += statementPart.sqlString(); sql.append(statementPart.sqlString());
} }
sql += ", PRIMARY KEY id(id))"; sql.append(", PRIMARY KEY id(id))");
try (PreparedStatement ps = connection.getNativeConnection().prepareStatement(sql)) { try (PreparedStatement ps = connection.getNativeConnection().prepareStatement(sql.toString())) {
int i = 1; int i = 1;
for (Object val : params) for (Object val : params)
ps.setObject(i++, val); ps.setObject(i++, val);
@ -93,11 +94,9 @@ public final class DB {
} }
private static boolean tableExistInDB(String tableName) throws SQLException { private static boolean tableExistInDB(String tableName) throws SQLException {
boolean exist = false;
try (ResultSet set = connection.getNativeConnection().getMetaData().getTables(null, null, tableName, null)) { try (ResultSet set = connection.getNativeConnection().getMetaData().getTables(null, null, tableName, null)) {
exist = set.next(); return set.next();
} }
return exist;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -277,7 +276,7 @@ public final class DB {
public static <E extends SQLElement<E>> SQLUpdate<E> update(Class<E> elemClass, SQLWhere<E> where) throws DBException { public static <E extends SQLElement<E>> SQLUpdate<E> update(Class<E> elemClass, SQLWhere<E> where) {
return new SQLUpdate<>(elemClass, where); return new SQLUpdate<>(elemClass, where);
} }
@ -291,7 +290,6 @@ public final class DB {
* @param elemClass the SQLElement representing the table. * @param elemClass the SQLElement representing the table.
* @param where the condition to meet for an element to be deleted from the table. If null, the table is truncated using {@link #truncateTable(Class)}. * @param where the condition to meet for an element to be deleted from the table. If null, the table is truncated using {@link #truncateTable(Class)}.
* @return The return value of {@link PreparedStatement#executeUpdate()}, for an SQL query {@code DELETE}. * @return The return value of {@link PreparedStatement#executeUpdate()}, for an SQL query {@code DELETE}.
* @throws DBException
*/ */
public static <E extends SQLElement<E>> int delete(Class<E> elemClass, SQLWhere<E> where) throws DBException { public static <E extends SQLElement<E>> int delete(Class<E> elemClass, SQLWhere<E> where) throws DBException {
initTable(elemClass); initTable(elemClass);
@ -369,7 +367,7 @@ public final class DB {
val = ((SQLCustomType<Object, Object>)sqlField.type).dbToJavaConv.apply(val); val = ((SQLCustomType<Object, Object>)sqlField.type).dbToJavaConv.apply(val);
} catch (Exception e) { } catch (Exception e) {
throw new DBException("Error while converting value of field '"+sqlField.getName()+"' with SQLCustomType from "+((SQLCustomType<Object, Object>)sqlField.type).intermediateJavaType throw new DBException("Error while converting value of field '"+sqlField.getName()+"' with SQLCustomType from "+((SQLCustomType<Object, Object>)sqlField.type).intermediateJavaType
+"(jdbc source) to "+sqlField.type.getJavaType()+"(java destination). The original value is '"+val.toString()+"'", e); +"(jdbc source) to "+sqlField.type.getJavaType()+"(java destination). The original value is '"+ val +"'", e);
} }
} }
@ -383,7 +381,7 @@ public final class DB {
} }
if (!instance.isValidForSave()) throw new DBException( if (!instance.isValidForSave()) throw new DBException(
"This SQLElement representing a database entry is not valid for save : " + instance.toString()); "This SQLElement representing a database entry is not valid for save : " + instance);
return instance; return instance;
} catch (ReflectiveOperationException | IllegalArgumentException | SecurityException | SQLException e) { } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException | SQLException e) {

View File

@ -11,15 +11,14 @@ public class DBConnection {
private static final long CONNECTION_CHECK_TIMEOUT = 30000; // in ms private static final long CONNECTION_CHECK_TIMEOUT = 30000; // in ms
private Connection conn; private Connection conn;
private String url; private final String url;
private String login; private final String login;
private String pass; private final String pass;
private long timeOfLastCheck = 0; private long timeOfLastCheck = 0;
public DBConnection(String host, int port, String dbname, String l, String p) public DBConnection(String host, int port, String dbname, String l, String p)
throws ClassNotFoundException, SQLException { throws SQLException {
//Class.forName("com.mysql.jdbc.Driver"); // apparently this is deprecated now
url = "jdbc:mysql://" + host + ":" + port + "/" + dbname url = "jdbc:mysql://" + host + ":" + port + "/" + dbname
+ "?autoReconnect=true" + "?autoReconnect=true"
+ "&useUnicode=true" + "&useUnicode=true"
@ -58,7 +57,7 @@ public class DBConnection {
return true; return true;
try (ResultSet rs = conn.createStatement().executeQuery("SELECT 1;")) { try (ResultSet rs = conn.createStatement().executeQuery("SELECT 1;")) {
return rs == null ? false : rs.next(); return rs != null && rs.next();
} }
} catch (Exception e) { } catch (Exception e) {
return false; return false;
@ -78,7 +77,7 @@ public class DBConnection {
public void close() { public void close() {
try { try {
conn.close(); conn.close();
} catch (Exception e) {} } catch (Exception ignored) {}
} }
} }

View File

@ -1,7 +1,6 @@
package fr.pandacube.lib.core.db; package fr.pandacube.lib.core.db;
public class DBException extends Exception { public class DBException extends Exception {
private static final long serialVersionUID = 1L;
public DBException(Throwable initCause) { public DBException(Throwable initCause) {
super(initCause); super(initCause);

View File

@ -1,11 +1,6 @@
package fr.pandacube.lib.core.db; package fr.pandacube.lib.core.db;
public class DBInitTableException extends DBException { public class DBInitTableException extends DBException {
private static final long serialVersionUID = 1L;
/* package */ <E extends SQLElement<E>> DBInitTableException(Class<E> tableElem) {
super("Error while initializing table " + ((tableElem != null) ? tableElem.getName() : "null"));
}
/* package */ <E extends SQLElement<E>> DBInitTableException(Class<E> tableElem, Throwable t) { /* package */ <E extends SQLElement<E>> DBInitTableException(Class<E> tableElem, Throwable t) {
super("Error while initializing table " + ((tableElem != null) ? tableElem.getName() : "null"), t); super("Error while initializing table " + ((tableElem != null) ? tableElem.getName() : "null"), t);

View File

@ -2,13 +2,7 @@ package fr.pandacube.lib.core.db;
import java.util.List; import java.util.List;
//public record ParameterizedSQLString(String sqlString, List<Object> parameters) { } // Java 16 public record ParameterizedSQLString(String sqlString, List<Object> parameters) {
public class ParameterizedSQLString {
private final String sqlString;
private final List<Object> parameters;
public ParameterizedSQLString(String sqlString, List<Object> parameters) {
this.sqlString = sqlString; this.parameters = parameters;
}
public String sqlString() { return sqlString; }
public List<Object> parameters() { return parameters; }
} }

View File

@ -1,5 +1,12 @@
package fr.pandacube.lib.core.db; package fr.pandacube.lib.core.db;
import com.google.common.base.MoreObjects;
import com.google.common.base.MoreObjects.ToStringHelper;
import com.google.gson.JsonObject;
import fr.pandacube.lib.core.util.EnumUtil;
import fr.pandacube.lib.core.util.Json;
import fr.pandacube.lib.core.util.Log;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.sql.Date; import java.sql.Date;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
@ -17,19 +24,11 @@ import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import com.google.common.base.MoreObjects;
import com.google.common.base.MoreObjects.ToStringHelper;
import com.google.gson.JsonObject;
import fr.pandacube.lib.core.util.EnumUtil;
import fr.pandacube.lib.core.util.Json;
import fr.pandacube.lib.core.util.Log;
public abstract class SQLElement<E extends SQLElement<E>> { public abstract class SQLElement<E extends SQLElement<E>> {
/** cache for fields for each subclass of SQLElement */ /** cache for fields for each subclass of SQLElement */
/* package */ static final Map<Class<? extends SQLElement<?>>, SQLFieldMap<? extends SQLElement<?>>> fieldsCache = new HashMap<>(); /* package */ static final Map<Class<? extends SQLElement<?>>, SQLFieldMap<? extends SQLElement<?>>> fieldsCache = new HashMap<>();
DBConnection db = DB.getConnection(); private final DBConnection db = DB.getConnection();
private boolean stored = false; private boolean stored = false;
private int id; private int id;
@ -109,7 +108,7 @@ public abstract class SQLElement<E extends SQLElement<E>> {
field.setAccessible(true); field.setAccessible(true);
try { try {
Object val = field.get(null); Object val = field.get(null);
if (val == null || !(val instanceof SQLField)) { if (!(val instanceof SQLField)) {
Log.severe("[ORM] The field " + field.getDeclaringClass().getName() + "." + field.getName() + " can't be initialized because its value is null."); Log.severe("[ORM] The field " + field.getDeclaringClass().getName() + "." + field.getName() + " can't be initialized because its value is null.");
continue; continue;
} }
@ -122,7 +121,7 @@ public abstract class SQLElement<E extends SQLElement<E>> {
checkedF.setSQLElementType((Class<E>) getClass()); checkedF.setSQLElementType((Class<E>) getClass());
listToFill.addField((SQLField<?, ?>) val); listToFill.addField((SQLField<?, ?>) val);
} catch (IllegalArgumentException | IllegalAccessException e) { } catch (IllegalArgumentException | IllegalAccessException e) {
Log.severe("Can't get value of static field " + field.toString(), e); Log.severe("Can't get value of static field " + field, e);
} }
} }
@ -147,20 +146,18 @@ public abstract class SQLElement<E extends SQLElement<E>> {
if (!fields.containsValue(sqlField)) // should not append at runtime because of generic type check at compilation if (!fields.containsValue(sqlField)) // should not append at runtime because of generic type check at compilation
throw new IllegalStateException("In the table "+getClass().getName()+ ": the field asked for modification is not initialized properly."); throw new IllegalStateException("In the table "+getClass().getName()+ ": the field asked for modification is not initialized properly.");
boolean modify = false;
if (value == null) { if (value == null) {
if (sqlField.canBeNull || (sqlField.autoIncrement && !stored)) modify = true; if (!sqlField.canBeNull && (!sqlField.autoIncrement || stored))
else
throw new IllegalArgumentException( throw new IllegalArgumentException(
"SQLField '" + sqlField.getName() + "' of " + getClass().getName() + " is a NOT NULL field"); "SQLField '" + sqlField.getName() + "' of " + getClass().getName() + " is a NOT NULL field");
} }
else if (sqlField.type.isAssignableFrom(value)) modify = true; else if (!sqlField.type.isInstance(value)) {
else
throw new IllegalArgumentException("SQLField '" + sqlField.getName() + "' of " + getClass().getName() throw new IllegalArgumentException("SQLField '" + sqlField.getName() + "' of " + getClass().getName()
+ " type is '" + sqlField.type.toString() + "' and can't accept values of type " + " type is '" + sqlField.type + "' and can't accept values of type "
+ value.getClass().getName()); + value.getClass().getName());
}
if (modify) if (!values.containsKey(sqlField)) { if (!values.containsKey(sqlField)) {
values.put(sqlField, value); values.put(sqlField, value);
if (setModified) modifiedSinceLastSave.add(sqlField.getName()); if (setModified) modifiedSinceLastSave.add(sqlField.getName());
} }
@ -227,7 +224,7 @@ public abstract class SQLElement<E extends SQLElement<E>> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public E save() throws DBException { public E save() throws DBException {
if (!isValidForSave()) if (!isValidForSave())
throw new IllegalStateException(toString() + " has at least one undefined value and can't be saved."); throw new IllegalStateException(this + " has at least one undefined value and can't be saved.");
DB.initTable((Class<E>)getClass()); DB.initTable((Class<E>)getClass());
try { try {
@ -251,24 +248,24 @@ public abstract class SQLElement<E extends SQLElement<E>> {
// values // values
values.put(fields.get("id"), null); values.put(fields.get("id"), null);
String concat_vals = ""; StringBuilder concatValues = new StringBuilder();
String concat_fields = ""; StringBuilder concatFields = new StringBuilder();
List<Object> psValues = new ArrayList<>(); List<Object> psValues = new ArrayList<>();
boolean first = true; boolean first = true;
for (Map.Entry<SQLField<E, ?>, Object> entry : values.entrySet()) { for (Map.Entry<SQLField<E, ?>, Object> entry : values.entrySet()) {
if (!first) { if (!first) {
concat_vals += ","; concatValues.append(",");
concat_fields += ","; concatFields.append(",");
} }
first = false; first = false;
concat_vals += " ? "; concatValues.append(" ? ");
concat_fields += "`" + entry.getKey().getName() + "`"; concatFields.append("`").append(entry.getKey().getName()).append("`");
addValueToSQLObjectList(psValues, entry.getKey(), entry.getValue()); addValueToSQLObjectList(psValues, entry.getKey(), entry.getValue());
} }
try (PreparedStatement ps = db.getNativeConnection().prepareStatement( try (PreparedStatement ps = db.getNativeConnection().prepareStatement(
"INSERT INTO " + DB.tablePrefix + tableName() + " (" + concat_fields + ") VALUES (" + concat_vals + ")", "INSERT INTO " + DB.tablePrefix + tableName() + " (" + concatFields + ") VALUES (" + concatValues + ")",
Statement.RETURN_GENERATED_KEYS)) { Statement.RETURN_GENERATED_KEYS)) {
int i = 1; int i = 1;
@ -300,7 +297,7 @@ public abstract class SQLElement<E extends SQLElement<E>> {
jValue = ((SQLCustomType)field.type).javaToDbConv.apply(jValue); jValue = ((SQLCustomType)field.type).javaToDbConv.apply(jValue);
} catch (Exception e) { } catch (Exception e) {
throw new DBException("Error while converting value of field '"+field.getName()+"' with SQLCustomType from "+field.type.getJavaType() throw new DBException("Error while converting value of field '"+field.getName()+"' with SQLCustomType from "+field.type.getJavaType()
+"(java source) to "+((SQLCustomType<?, ?>)field.type).intermediateJavaType+"(jdbc destination). The original value is '"+jValue.toString()+"'", e); +"(java source) to "+((SQLCustomType<?, ?>)field.type).intermediateJavaType+"(jdbc destination). The original value is '"+jValue+"'", e);
} }
} }
list.add(jValue); list.add(jValue);
@ -346,8 +343,6 @@ public abstract class SQLElement<E extends SQLElement<E>> {
} }
protected static class SQLFieldMap<E extends SQLElement<E>> extends LinkedHashMap<String, SQLField<E, ?>> { protected static class SQLFieldMap<E extends SQLElement<E>> extends LinkedHashMap<String, SQLField<E, ?>> {
private static final long serialVersionUID = 1L;
private final Class<E> sqlElemClass; private final Class<E> sqlElemClass;
private SQLFieldMap(Class<E> elemClass) { private SQLFieldMap(Class<E> elemClass) {
@ -382,7 +377,7 @@ public abstract class SQLElement<E extends SQLElement<E>> {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (o == null || !(getClass().isInstance(o))) return false; if (!(getClass().isInstance(o))) return false;
SQLElement<?> oEl = (SQLElement<?>) o; SQLElement<?> oEl = (SQLElement<?>) o;
if (oEl.getId() == null) return false; if (oEl.getId() == null) return false;
return oEl.getId().equals(getId()); return oEl.getId().equals(getId());
@ -390,7 +385,7 @@ public abstract class SQLElement<E extends SQLElement<E>> {
@Override @Override
public int hashCode() { public int hashCode() {
return super.hashCode(); return getClass().hashCode() ^ Objects.hashCode(getId());
} }
@ -466,12 +461,12 @@ public abstract class SQLElement<E extends SQLElement<E>> {
public static final SQLType<Double> DOUBLE = new SQLType<>("DOUBLE", Double.class); public static final SQLType<Double> DOUBLE = new SQLType<>("DOUBLE", Double.class);
public static final SQLType<String> CHAR(int charCount) { public static SQLType<String> CHAR(int charCount) {
if (charCount <= 0) throw new IllegalArgumentException("charCount must be positive."); if (charCount <= 0) throw new IllegalArgumentException("charCount must be positive.");
return new SQLType<>("CHAR(" + charCount + ")", String.class); return new SQLType<>("CHAR(" + charCount + ")", String.class);
} }
public static final SQLType<String> VARCHAR(int charCount) { public static SQLType<String> VARCHAR(int charCount) {
if (charCount <= 0) throw new IllegalArgumentException("charCount must be positive."); if (charCount <= 0) throw new IllegalArgumentException("charCount must be positive.");
return new SQLType<>("VARCHAR(" + charCount + ")", String.class); return new SQLType<>("VARCHAR(" + charCount + ")", String.class);
} }
@ -479,29 +474,29 @@ public abstract class SQLElement<E extends SQLElement<E>> {
public static final SQLType<String> TEXT = new SQLType<>("TEXT", String.class); public static final SQLType<String> TEXT = new SQLType<>("TEXT", String.class);
public static final SQLType<String> STRING = TEXT; public static final SQLType<String> STRING = TEXT;
public static final SQLType<byte[]> BINARY(int byteCount) { public static SQLType<byte[]> BINARY(int byteCount) {
if (byteCount <= 0) throw new IllegalArgumentException("byteCount must be positive."); if (byteCount <= 0) throw new IllegalArgumentException("byteCount must be positive.");
return new SQLType<>("BINARY(" + byteCount + ")", byte[].class); return new SQLType<>("BINARY(" + byteCount + ")", byte[].class);
} }
public static final SQLType<byte[]> VARBINARY(int byteCount) { public static SQLType<byte[]> VARBINARY(int byteCount) {
if (byteCount <= 0) throw new IllegalArgumentException("byteCount must be positive."); if (byteCount <= 0) throw new IllegalArgumentException("byteCount must be positive.");
return new SQLType<>("VARBINARY(" + byteCount + ")", byte[].class); return new SQLType<>("VARBINARY(" + byteCount + ")", byte[].class);
} }
public static final SQLType<byte[]> BLOB = new SQLType<>("BLOB", byte[].class); public static final SQLType<byte[]> BLOB = new SQLType<>("BLOB", byte[].class);
public static final <T extends Enum<T>> SQLType<T> ENUM(Class<T> enumType) { public static <T extends Enum<T>> SQLType<T> ENUM(Class<T> enumType) {
if (enumType == null) throw new IllegalArgumentException("enumType can't be null."); if (enumType == null) throw new IllegalArgumentException("enumType can't be null.");
String enumStr = "'"; StringBuilder enumStr = new StringBuilder("'");
boolean first = true; boolean first = true;
for (T el : enumType.getEnumConstants()) { for (T el : enumType.getEnumConstants()) {
if (!first) enumStr += "', '"; if (!first) enumStr.append("', '");
first = false; first = false;
enumStr += el.name(); enumStr.append(el.name());
} }
enumStr += "'"; enumStr.append("'");
return new SQLCustomType<>("VARCHAR(" + enumStr + ")", String.class, enumType, s -> EnumUtil.searchEnum(enumType, s), Enum::name); return new SQLCustomType<>("VARCHAR(" + enumStr + ")", String.class, enumType, s -> EnumUtil.searchEnum(enumType, s), Enum::name);
} }

View File

@ -1,25 +1,23 @@
package fr.pandacube.lib.core.db; package fr.pandacube.lib.core.db;
import java.sql.SQLException; import com.google.gson.JsonArray;
import fr.pandacube.lib.core.util.Log;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.google.gson.JsonArray;
import fr.pandacube.lib.core.util.Log;
/** /**
* *
* @param <E> * @param <E>
*/ */
public class SQLElementList<E extends SQLElement<E>> extends ArrayList<E> { public class SQLElementList<E extends SQLElement<E>> extends ArrayList<E> {
private static final long serialVersionUID = 1L;
private final Map<SQLField<E, ?>, Object> modifiedValues = new LinkedHashMap<>(); private final Map<SQLField<E, ?>, Object> modifiedValues = new LinkedHashMap<>();
@ -38,14 +36,13 @@ public class SQLElementList<E extends SQLElement<E>> extends ArrayList<E> {
* que lors de * que lors de
* l'appel à {@link #saveCommon()} * l'appel à {@link #saveCommon()}
* *
* @param <T>
* @param field le champs à modifier * @param field le champs à modifier
* @param value la valeur à lui appliquer * @param value la valeur à lui appliquer
*/ */
public synchronized <T> void setCommon(SQLField<E, T> field, T value) { public synchronized <T> void setCommon(SQLField<E, T> field, T value) {
if (field == null) if (field == null)
throw new IllegalArgumentException("field can't be null"); throw new IllegalArgumentException("field can't be null");
if (field.getName() == "id") if (Objects.equals(field.getName(), "id"))
throw new IllegalArgumentException("Can't modify id field in a SQLElementList"); throw new IllegalArgumentException("Can't modify id field in a SQLElementList");
Class<E> elemClass = field.getSQLElementType(); Class<E> elemClass = field.getSQLElementType();
@ -72,8 +69,6 @@ public class SQLElementList<E extends SQLElement<E>> extends ArrayList<E> {
* {@link SQLElement#set(SQLField, Object)}.<br/> * {@link SQLElement#set(SQLField, Object)}.<br/>
* Les objets de cette liste qui n'ont pas leur données en base de données * Les objets de cette liste qui n'ont pas leur données en base de données
* sont ignorées. * sont ignorées.
*
* @throws SQLException
*/ */
public synchronized int saveCommon() throws DBException { public synchronized int saveCommon() throws DBException {
List<E> storedEl = getStoredEl(); List<E> storedEl = getStoredEl();
@ -102,7 +97,7 @@ public class SQLElementList<E extends SQLElement<E>> extends ArrayList<E> {
} }
private List<E> getStoredEl() { private List<E> getStoredEl() {
return stream().filter(SQLElement::isStored).collect(Collectors.toCollection(() -> new ArrayList<>())); return stream().filter(SQLElement::isStored).collect(Collectors.toCollection(ArrayList::new));
} }
/** /**

View File

@ -63,7 +63,7 @@ public class SQLField<E extends SQLElement<E>, T> {
} }
/** /**
* <b>Don't use this {@link #toString()} method in a SQL query, because * <b>Don't use this {@code toString()} method in a SQL query, because
* the default value is not escaped correctly</b> * the default value is not escaped correctly</b>
* *
* @see java.lang.Object#toString() * @see java.lang.Object#toString()
@ -76,12 +76,9 @@ public class SQLField<E extends SQLElement<E>, T> {
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj == null) return false; return obj instanceof SQLField<?, ?> f
if (!(obj instanceof SQLField)) return false; && f.getName().equals(getName())
SQLField<?, ?> f = (SQLField<?, ?>) obj; && f.sqlElemClass.equals(sqlElemClass);
if (!f.getName().equals(getName())) return false;
if (!f.sqlElemClass.equals(sqlElemClass)) return false;
return true;
} }
@Override @Override

View File

@ -2,10 +2,11 @@ package fr.pandacube.lib.core.db;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
public class SQLOrderBy<E extends SQLElement<E>> { public class SQLOrderBy<E extends SQLElement<E>> {
private List<OBField> orderByFields = new ArrayList<>(); private final List<OBField> orderByFields = new ArrayList<>();
/** /**
* Construit une nouvelle clause ORDER BY * Construit une nouvelle clause ORDER BY
@ -45,14 +46,9 @@ public class SQLOrderBy<E extends SQLElement<E>> {
} }
/* package */ String toSQL() { /* package */ String toSQL() {
String ret = ""; return orderByFields.stream()
boolean first = true; .map(f -> "`" + f.field.getName() + "` " + f.direction.name())
for (OBField f : orderByFields) { .collect(Collectors.joining(", "));
if (!first) ret += ", ";
first = false;
ret += "`" + f.field.getName() + "` " + f.direction.name();
}
return ret;
} }
@Override @Override
@ -72,7 +68,7 @@ public class SQLOrderBy<E extends SQLElement<E>> {
} }
private enum Direction { private enum Direction {
ASC, DESC; ASC, DESC
} }

View File

@ -15,9 +15,8 @@ public class SQLType<T> {
return sqlDeclaration; return sqlDeclaration;
} }
public boolean isAssignableFrom(Object val) { public boolean isInstance(Object val) {
if (javaTypes.isInstance(val)) return true; return javaTypes.isInstance(val);
return false;
} }
@Override @Override
@ -27,8 +26,8 @@ public class SQLType<T> {
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj == null || !(obj instanceof SQLType)) return false; return obj instanceof SQLType o
return toString().equals(((SQLType<?>) obj).toString()); && toString().equals(o.toString());
} }
public Class<T> getJavaType() { public Class<T> getJavaType() {

View File

@ -42,27 +42,27 @@ public class SQLUpdate<E extends SQLElement<E>> {
return 0; return 0;
} }
String sql = "UPDATE " + DB.getTableName(elemClass) + " SET "; StringBuilder sql = new StringBuilder("UPDATE " + DB.getTableName(elemClass) + " SET ");
List<Object> params = new ArrayList<>(); List<Object> params = new ArrayList<>();
boolean first = true; boolean first = true;
for (Map.Entry<SQLField<E, ?>, Object> entry : values.entrySet()) { for (Map.Entry<SQLField<E, ?>, Object> entry : values.entrySet()) {
if (!first) if (!first)
sql += ", "; sql.append(", ");
sql += "`" + entry.getKey().getName() + "` = ? "; sql.append("`").append(entry.getKey().getName()).append("` = ? ");
SQLElement.addValueToSQLObjectList(params, entry.getKey(), entry.getValue()); SQLElement.addValueToSQLObjectList(params, entry.getKey(), entry.getValue());
first = false; first = false;
} }
if (where != null) { if (where != null) {
ParameterizedSQLString ret = where.toSQL(); ParameterizedSQLString ret = where.toSQL();
sql += " WHERE " + ret.sqlString(); sql.append(" WHERE ").append(ret.sqlString());
params.addAll(ret.parameters()); params.addAll(ret.parameters());
} }
sql += ";"; sql.append(";");
return DB.customUpdateStatement(sql, params); return DB.customUpdateStatement(sql.toString(), params);
} }
} }

View File

@ -50,8 +50,8 @@ public abstract class SQLWhere<E extends SQLElement<E>> {
public static abstract class SQLWhereChain<E extends SQLElement<E>> extends SQLWhere<E> { public static abstract class SQLWhereChain<E extends SQLElement<E>> extends SQLWhere<E> {
private SQLBoolOp operator; private final SQLBoolOp operator;
protected List<SQLWhere<E>> conditions = new ArrayList<>(); private final List<SQLWhere<E>> conditions = new ArrayList<>();
private SQLWhereChain(SQLBoolOp op) { private SQLWhereChain(SQLBoolOp op) {
if (op == null) throw new IllegalArgumentException("op can't be null"); if (op == null) throw new IllegalArgumentException("op can't be null");
@ -73,20 +73,21 @@ public abstract class SQLWhere<E extends SQLElement<E>> {
throw new DBException("SQLWhereChain needs at least one element inside !"); throw new DBException("SQLWhereChain needs at least one element inside !");
} }
String sql = ""; StringBuilder sql = new StringBuilder();
List<Object> params = new ArrayList<>(); List<Object> params = new ArrayList<>();
boolean first = true; boolean first = true;
for (SQLWhere<E> w : conditions) { for (SQLWhere<E> w : conditions) {
if (!first) sql += " " + operator.sql + " "; if (!first)
sql.append(" ").append(operator.sql).append(" ");
first = false; first = false;
ParameterizedSQLString ret = w.toSQL(); ParameterizedSQLString ret = w.toSQL();
sql += "(" + ret.sqlString() + ")"; sql.append("(").append(ret.sqlString()).append(")");
params.addAll(ret.parameters()); params.addAll(ret.parameters());
} }
return new ParameterizedSQLString(sql, params); return new ParameterizedSQLString(sql.toString(), params);
} }
protected enum SQLBoolOp { protected enum SQLBoolOp {
@ -96,7 +97,7 @@ public abstract class SQLWhere<E extends SQLElement<E>> {
OR("OR"); OR("OR");
/* package */ final String sql; /* package */ final String sql;
private SQLBoolOp(String s) { SQLBoolOp(String s) {
sql = s; sql = s;
} }
@ -151,9 +152,9 @@ public abstract class SQLWhere<E extends SQLElement<E>> {
/* package */ static class SQLWhereComp<E extends SQLElement<E>> extends SQLWhere<E> { /* package */ static class SQLWhereComp<E extends SQLElement<E>> extends SQLWhere<E> {
private SQLField<E, ?> left; private final SQLField<E, ?> left;
private SQLComparator comp; private final SQLComparator comp;
private Object right; private final Object right;
/** /**
* Compare a field with a value * Compare a field with a value
@ -193,7 +194,7 @@ public abstract class SQLWhere<E extends SQLElement<E>> {
/* package */ final String sql; /* package */ final String sql;
private SQLComparator(String s) { SQLComparator(String s) {
sql = s; sql = s;
} }
@ -208,8 +209,8 @@ public abstract class SQLWhere<E extends SQLElement<E>> {
/* package */ static class SQLWhereIn<E extends SQLElement<E>> extends SQLWhere<E> { /* package */ static class SQLWhereIn<E extends SQLElement<E>> extends SQLWhere<E> {
private SQLField<E, ?> field; private final SQLField<E, ?> field;
private Collection<?> values; private final Collection<?> values;
/* package */ <T> SQLWhereIn(SQLField<E, T> f, Collection<T> v) { /* package */ <T> SQLWhereIn(SQLField<E, T> f, Collection<T> v) {
if (f == null || v == null) if (f == null || v == null)
@ -246,8 +247,8 @@ public abstract class SQLWhere<E extends SQLElement<E>> {
/* package */ static class SQLWhereLike<E extends SQLElement<E>> extends SQLWhere<E> { /* package */ static class SQLWhereLike<E extends SQLElement<E>> extends SQLWhere<E> {
private SQLField<E, ?> field; private final SQLField<E, ?> field;
private String likeExpr; private final String likeExpr;
/** /**
* Compare a field with a value * Compare a field with a value
@ -279,8 +280,8 @@ public abstract class SQLWhere<E extends SQLElement<E>> {
/* package */ static class SQLWhereNull<E extends SQLElement<E>> extends SQLWhere<E> { /* package */ static class SQLWhereNull<E extends SQLElement<E>> extends SQLWhere<E> {
private SQLField<E, ?> fild; private final SQLField<E, ?> field;
private boolean nulll; private final boolean isNull;
/** /**
* Init a IS NULL / IS NOT NULL expression for a SQL WHERE condition. * Init a IS NULL / IS NOT NULL expression for a SQL WHERE condition.
@ -294,13 +295,13 @@ public abstract class SQLWhere<E extends SQLElement<E>> {
if (!field.canBeNull) Log.getLogger().log(Level.WARNING, if (!field.canBeNull) Log.getLogger().log(Level.WARNING,
"Useless : Trying to check IS [NOT] NULL on the field " + field.getSQLElementType().getName() + "#" "Useless : Trying to check IS [NOT] NULL on the field " + field.getSQLElementType().getName() + "#"
+ field.getName() + " which is declared in the ORM as 'can't be null'"); + field.getName() + " which is declared in the ORM as 'can't be null'");
fild = field; this.field = field;
nulll = isNull; this.isNull = isNull;
} }
@Override @Override
public ParameterizedSQLString toSQL() { public ParameterizedSQLString toSQL() {
return new ParameterizedSQLString("`" + fild.getName() + "` IS " + ((nulll) ? "NULL" : "NOT NULL"), new ArrayList<>()); return new ParameterizedSQLString("`" + field.getName() + "` IS " + ((isNull) ? "NULL" : "NOT NULL"), new ArrayList<>());
} }
} }

View File

@ -23,8 +23,6 @@ public class Array8Bit {
/** /**
* i = 0 is the lowest significant bit * i = 0 is the lowest significant bit
* @param i
* @return
*/ */
public boolean getBit(int i) { public boolean getBit(int i) {
return values[i]; return values[i];
@ -32,8 +30,6 @@ public class Array8Bit {
/** /**
* i = 0 is the lowest significant bit * i = 0 is the lowest significant bit
* @param i
* @param b
*/ */
public void setBit(int i, boolean b) { public void setBit(int i, boolean b) {
values[i] = b; values[i] = b;

View File

@ -1,13 +1,14 @@
package fr.pandacube.lib.core.net; package fr.pandacube.lib.core.net;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
public final class ByteBuffer implements Cloneable { public final class ByteBuffer implements Cloneable {
public static final Charset NETWORK_CHARSET = Charset.forName("UTF-8"); public static final Charset NETWORK_CHARSET = StandardCharsets.UTF_8;
private java.nio.ByteBuffer buff; private java.nio.ByteBuffer buff;
@ -64,7 +65,6 @@ public final class ByteBuffer implements Cloneable {
/** /**
* Return the next byte array wich is preceded with his size as integer, * Return the next byte array wich is preceded with his size as integer,
* or null if the founded size is negative. * or null if the founded size is negative.
* @return
*/ */
public byte[] getSizedByteArray() { public byte[] getSizedByteArray() {
int size = getInt(); int size = getInt();
@ -218,7 +218,6 @@ public final class ByteBuffer implements Cloneable {
/** /**
* *
* @param s null String are supported * @param s null String are supported
* @return
*/ */
public ByteBuffer putString(String s) { public ByteBuffer putString(String s) {
if (s == null) { if (s == null) {
@ -229,7 +228,6 @@ public final class ByteBuffer implements Cloneable {
/** /**
* returned string can be null * returned string can be null
* @return
*/ */
public String getString() { public String getString() {
byte[] binaryString = getSizedByteArray(); byte[] binaryString = getSizedByteArray();
@ -239,7 +237,6 @@ public final class ByteBuffer implements Cloneable {
/** /**
* *
* @param list The list can be null, and any String can be null too. * @param list The list can be null, and any String can be null too.
* @return
*/ */
public ByteBuffer putListOfString(List<String> list) { public ByteBuffer putListOfString(List<String> list) {
if (list == null) { if (list == null) {

View File

@ -3,9 +3,9 @@ package fr.pandacube.lib.core.net;
import java.util.Arrays; import java.util.Arrays;
public class PPacket { public class PPacket {
public String name; public final String name;
/* package */ int id; /* package */ int id;
public byte[] content; public final byte[] content;
/** /**
* Construct a new PPacket based on the content of the provided buffer before his position. * Construct a new PPacket based on the content of the provided buffer before his position.

View File

@ -3,7 +3,7 @@ package fr.pandacube.lib.core.net;
import java.util.Arrays; import java.util.Arrays;
public class PPacketAnswer extends PPacket { public class PPacketAnswer extends PPacket {
/* package */ int answer; /* package */ final int answer;
/** /**
* Construct a new PPacketAnswer based on the content of the provided buffer before his position. * Construct a new PPacketAnswer based on the content of the provided buffer before his position.

View File

@ -8,6 +8,6 @@ public interface PPacketListener<P extends PPacket> {
* @param connection the connection from where the packet comes * @param connection the connection from where the packet comes
* @param packet the received packet * @param packet the received packet
*/ */
public void onPacketReceive(PSocket connection, P packet); void onPacketReceive(PSocket connection, P packet);
} }

View File

@ -17,25 +17,25 @@ import com.google.common.base.MoreObjects;
import fr.pandacube.lib.core.util.Log; import fr.pandacube.lib.core.util.Log;
public class PServer extends Thread implements Closeable { public class PServer extends Thread implements Closeable {
private static AtomicInteger connectionCounterId = new AtomicInteger(0); private static final AtomicInteger connectionCounterId = new AtomicInteger(0);
private int port; private final int port;
private ServerSocket socket; private ServerSocket socket;
private String socketName; private final String socketName;
private List<TCPServerClientConnection> clients = Collections.synchronizedList(new ArrayList<>()); private final List<TCPServerClientConnection> clients = Collections.synchronizedList(new ArrayList<>());
private AtomicBoolean isClosed = new AtomicBoolean(false); private final AtomicBoolean isClosed = new AtomicBoolean(false);
private List<PPacketListener<PPacket>> globalPacketListeners = Collections.synchronizedList(new ArrayList<>()); private final List<PPacketListener<PPacket>> globalPacketListeners = Collections.synchronizedList(new ArrayList<>());
private List<PSocketConnectionListener> clientConnectionListeners = Collections.synchronizedList(new ArrayList<>()); private final List<PSocketConnectionListener> clientConnectionListeners = Collections.synchronizedList(new ArrayList<>());
private String password; private final String password;
public PServer(int port, String sckName, String password) throws IOException { public PServer(int port, String sckName, String password) {
super("PServer " + sckName); super("PServer " + sckName);
setDaemon(true); setDaemon(true);
if (port <= 0 || port > 65535) throw new IllegalArgumentException("le numéro de port est invalide"); if (port <= 0 || port > 65535) throw new IllegalArgumentException("le numéro de port est invalide");
@ -59,17 +59,11 @@ public class PServer extends Thread implements Closeable {
socketClient.setSendBufferSize(PSocket.NETWORK_TCP_BUFFER_SIZE); socketClient.setSendBufferSize(PSocket.NETWORK_TCP_BUFFER_SIZE);
socketClient.setSoTimeout(PSocket.NETWORK_TIMEOUT); socketClient.setSoTimeout(PSocket.NETWORK_TIMEOUT);
try { TCPServerClientConnection co = new TCPServerClientConnection(socketClient,
@SuppressWarnings("resource") connectionCounterId.getAndIncrement());
TCPServerClientConnection co = new TCPServerClientConnection(socketClient, co.start();
connectionCounterId.getAndIncrement());
co.start();
} catch (IOException e) {
Log.severe("Connexion impossible avec " + socketClient.getInetAddress());
}
} }
} catch(SocketException e) { } catch (SocketException ignored) {
} catch (Exception e) { } catch (Exception e) {
Log.warning("Plus aucune connexion ne peux être acceptée", e); Log.warning("Plus aucune connexion ne peux être acceptée", e);
} }
@ -97,7 +91,7 @@ public class PServer extends Thread implements Closeable {
boolean loggedIn; boolean loggedIn;
private TCPServerClientConnection(Socket s, int coId) throws IOException { private TCPServerClientConnection(Socket s, int coId) {
super(s, "Conn#" + coId + " via TCPSv " + socketName, password); super(s, "Conn#" + coId + " via TCPSv " + socketName, password);
addConnectionListener(new PSocketConnectionListener() { addConnectionListener(new PSocketConnectionListener() {
@Override @Override
@ -114,16 +108,16 @@ public class PServer extends Thread implements Closeable {
clientConnectionListeners.forEach(l -> l.onConnect(connection)); clientConnectionListeners.forEach(l -> l.onConnect(connection));
} }
}); });
addPacketListener((conn, packet) -> { addPacketListener((conn, packet) ->
globalPacketListeners.forEach(l -> { globalPacketListeners.forEach(l -> {
try { try {
l.onPacketReceive(conn, packet); l.onPacketReceive(conn, packet);
} catch (Exception e) { } catch (Exception e) {
Log.severe("Exception while calling PPacketListener.onPacketReceive().", e); Log.severe("Exception while calling PPacketListener.onPacketReceive().", e);
sendSilently(PPacketAnswer.buildExceptionPacket(packet, e.toString())); sendSilently(PPacketAnswer.buildExceptionPacket(packet, e.toString()));
} }
}); })
}); );
} }
} }
@ -137,7 +131,7 @@ public class PServer extends Thread implements Closeable {
clients.forEach(PSocket::close); clients.forEach(PSocket::close);
socket.close(); socket.close();
} catch (IOException e) {} } catch (IOException ignored) {}
} }
public boolean isClosed() { public boolean isClosed() {

View File

@ -40,17 +40,17 @@ public class PSocket extends Thread implements Closeable {
private boolean server = false; private boolean server = false;
private Socket socket; private Socket socket;
private SocketAddress addr; private final SocketAddress addr;
private DataInputStream in; private DataInputStream in;
private DataOutputStream out; private DataOutputStream out;
private Object outSynchronizer = new Object(); private final Object outSynchronizer = new Object();
private String password; private String password;
private AtomicBoolean isClosed = new AtomicBoolean(false); private final AtomicBoolean isClosed = new AtomicBoolean(false);
private List<PPacketListener<PPacket>> packetListeners = Collections.synchronizedList(new ArrayList<>()); private final List<PPacketListener<PPacket>> packetListeners = Collections.synchronizedList(new ArrayList<>());
private List<PSocketConnectionListener> connectionListeners = Collections.synchronizedList(new ArrayList<>()); private final List<PSocketConnectionListener> connectionListeners = Collections.synchronizedList(new ArrayList<>());
private Map<Integer, PPacketListener<PPacketAnswer>> answersCallbacks = Collections.synchronizedMap(new HashMap<>()); private final Map<Integer, PPacketListener<PPacketAnswer>> answersCallbacks = Collections.synchronizedMap(new HashMap<>());
private int nextSendId = 0; private int nextSendId = 0;
@ -58,7 +58,7 @@ public class PSocket extends Thread implements Closeable {
* Create a new PSocket that will connect to the specified SocketAddress. * Create a new PSocket that will connect to the specified SocketAddress.
* @param a The target server to connect to * @param a The target server to connect to
* @param connName the name of the connection, used to name the Thread used to receive the packet. * @param connName the name of the connection, used to name the Thread used to receive the packet.
* @param the password to send to the server. * @param pass the password to send to the server.
*/ */
public PSocket(SocketAddress a, String connName, String pass) { public PSocket(SocketAddress a, String connName, String pass) {
super("PSocket " + connName); super("PSocket " + connName);
@ -115,7 +115,6 @@ public class PSocket extends Thread implements Closeable {
} }
send(PPacketAnswer.buildLoginOkPacket(packet)); send(PPacketAnswer.buildLoginOkPacket(packet));
// login ok at this point // login ok at this point
password = null;
} }
else { else {
send(PPacket.buildLoginPacket(password)); send(PPacket.buildLoginPacket(password));
@ -136,9 +135,9 @@ public class PSocket extends Thread implements Closeable {
return; return;
} }
// login ok at this point // login ok at this point
password = null;
} }
password = null;
socket.setSoTimeout(NETWORK_TIMEOUT); socket.setSoTimeout(NETWORK_TIMEOUT);
Log.info(getName() + " connected."); Log.info(getName() + " connected.");
@ -189,7 +188,6 @@ public class PSocket extends Thread implements Closeable {
/** /**
* Return the packet read in the socket, or null if the packet is in a bad format. * Return the packet read in the socket, or null if the packet is in a bad format.
* @return the packet * @return the packet
* @throws IOException
* *
*/ */
private PPacket readPacket() throws IOException { private PPacket readPacket() throws IOException {
@ -232,8 +230,6 @@ public class PSocket extends Thread implements Closeable {
/** /**
* Send the provided packet, without waiting for an answer. * Send the provided packet, without waiting for an answer.
* @param packet
* @throws IOException
*/ */
public void send(PPacket packet) throws IOException { public void send(PPacket packet) throws IOException {
if (packet == null) if (packet == null)
@ -271,7 +267,7 @@ public class PSocket extends Thread implements Closeable {
public void sendSilently(PPacket packet) { public void sendSilently(PPacket packet) {
try { try {
send(packet); send(packet);
} catch (IOException e) {} } catch (IOException ignored) {}
} }

View File

@ -6,12 +6,12 @@ public interface PSocketConnectionListener {
* Called when a socket is connected * Called when a socket is connected
* @param connection the connection * @param connection the connection
*/ */
public void onConnect(PSocket connection); void onConnect(PSocket connection);
/** /**
* Called just before a socket is disconnected * Called just before a socket is disconnected
* @param connection the connection * @param connection the connection
*/ */
public void onDisconnect(PSocket connection); void onDisconnect(PSocket connection);
} }

View File

@ -6,7 +6,7 @@ import java.io.PrintStream;
public abstract class AbstractRequest { public abstract class AbstractRequest {
private final String pass; private final String pass;
private String command; private final String command;
private String data; private String data;
protected AbstractRequest(String cmd, String p) { protected AbstractRequest(String cmd, String p) {

View File

@ -35,7 +35,7 @@ public class ResponseAnalyser {
if (line == null) if (line == null)
throw new IOException("Not enough data to read second line of response."); throw new IOException("Not enough data to read second line of response.");
int data_size = 0; int data_size;
try { try {
data_size = Integer.parseInt(line); data_size = Integer.parseInt(line);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
@ -45,7 +45,7 @@ public class ResponseAnalyser {
// lecture du reste // lecture du reste
StringBuilder sB_data = new StringBuilder(); StringBuilder sB_data = new StringBuilder();
char[] c = new char[100]; char[] c = new char[100];
int nbC = 0; int nbC;
while ((nbC = in.read(c)) != -1) while ((nbC = in.read(c)) != -1)
sB_data.append(c, 0, nbC); sB_data.append(c, 0, nbC);
data = sB_data.toString(); data = sB_data.toString();

View File

@ -10,11 +10,11 @@ import fr.pandacube.lib.core.util.Log;
@Deprecated @Deprecated
public class NetworkAPIListener implements Runnable { public class NetworkAPIListener implements Runnable {
private int port = 0; private final int port;
String pass; final String pass;
private ServerSocket serverSocket; private ServerSocket serverSocket;
private HashMap<String, AbstractRequestExecutor> requestExecutors = new HashMap<>(); private final HashMap<String, AbstractRequestExecutor> requestExecutors = new HashMap<>();
private String name; private final String name;
/** /**
* Instencie le côté serveur du NetworkAPI * Instencie le côté serveur du NetworkAPI
@ -22,8 +22,6 @@ public class NetworkAPIListener implements Runnable {
* @param n nom du networkAPI (permet l'identification dans les logs) * @param n nom du networkAPI (permet l'identification dans les logs)
* @param p le port d'écoute * @param p le port d'écoute
* @param pa le mot de passe réseau * @param pa le mot de passe réseau
* @param peh PacketExecutionHandler permettant de prendre en charge
* l'exécution asynchrone d'une requête reçu pas un client
*/ */
public NetworkAPIListener(String n, int p, String pa) { public NetworkAPIListener(String n, int p, String pa) {
port = p; port = p;
@ -51,12 +49,13 @@ public class NetworkAPIListener implements Runnable {
t.setDaemon(true); t.setDaemon(true);
t.start(); t.start();
} }
} catch (IOException e) {} } catch (IOException ignored) {}
synchronized (this) { synchronized (this) {
try { try {
if (!serverSocket.isClosed()) serverSocket.close(); if (!serverSocket.isClosed())
} catch (IOException e) {} serverSocket.close();
} catch (IOException ignored) {}
} }
Log.info("NetworkAPI '" + name + "' ferme le port " + port); Log.info("NetworkAPI '" + name + "' ferme le port " + port);
@ -70,7 +69,7 @@ public class NetworkAPIListener implements Runnable {
public synchronized void closeServerSocket() { public synchronized void closeServerSocket() {
if (serverSocket != null) try { if (serverSocket != null) try {
serverSocket.close(); serverSocket.close();
} catch (IOException e) {} } catch (IOException ignored) {}
} }
public int getPort() { public int getPort() {

View File

@ -18,8 +18,8 @@ import fr.pandacube.lib.core.util.Log;
*/ */
@Deprecated @Deprecated
public class PacketExecutor implements Runnable { public class PacketExecutor implements Runnable {
private Socket socket; private final Socket socket;
private NetworkAPIListener networkAPIListener; private final NetworkAPIListener networkAPIListener;
public PacketExecutor(Socket s, NetworkAPIListener napiListener) { public PacketExecutor(Socket s, NetworkAPIListener napiListener) {
socket = s; socket = s;
@ -43,9 +43,9 @@ public class PacketExecutor implements Runnable {
rep.data = e.toString(); rep.data = e.toString();
try { try {
rep.sendPacket(new PrintStream(socket.getOutputStream())); rep.sendPacket(new PrintStream(socket.getOutputStream()));
} catch (IOException e1) {} } catch (IOException ignored) {}
if (e instanceof IOException) if (e instanceof IOException)
Log.warning("Unable to read packet from socket " + socket + ": " + e.toString()); Log.warning("Unable to read packet from socket " + socket + ": " + e);
else if(e instanceof BadRequestException) { else if(e instanceof BadRequestException) {
if (e.getMessage().equals("wrong_password")) if (e.getMessage().equals("wrong_password"))
Log.warning("Wrong password received from socket " + socket); Log.warning("Wrong password received from socket " + socket);
@ -60,6 +60,6 @@ public class PacketExecutor implements Runnable {
try { try {
socket.close(); socket.close();
} catch (Exception e) {} } catch (Exception ignored) {}
} }
} }

View File

@ -8,7 +8,6 @@ import java.net.Socket;
@Deprecated @Deprecated
public class RequestAnalyser { public class RequestAnalyser {
private NetworkAPIListener networkAPIListener;
public final String command; public final String command;
public final String data; public final String data;
@ -17,8 +16,6 @@ public class RequestAnalyser {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"le socket doit être non null et doit être ouvert sur le flux d'entrée et napiListener ne doit pas être null"); "le socket doit être non null et doit être ouvert sur le flux d'entrée et napiListener ne doit pas être null");
networkAPIListener = napiListener;
// on lis la réponse // on lis la réponse
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
@ -26,18 +23,18 @@ public class RequestAnalyser {
// lecture de la première ligne // lecture de la première ligne
line = in.readLine(); line = in.readLine();
if (line == null || !line.equals(networkAPIListener.pass)) throw new BadRequestException("wrong_password"); if (line == null || !line.equals(napiListener.pass)) throw new BadRequestException("wrong_password");
// lecture de la deuxième ligne // lecture de la deuxième ligne
line = in.readLine(); line = in.readLine();
if (line == null || networkAPIListener.getRequestExecutor(line) == null) if (line == null || napiListener.getRequestExecutor(line) == null)
throw new BadRequestException("command_not_exists"); throw new BadRequestException("command_not_exists");
command = line; command = line;
// lecture de la troisième ligne // lecture de la troisième ligne
line = in.readLine(); line = in.readLine();
int data_size = 0; int data_size;
try { try {
data_size = Integer.parseInt(line); data_size = Integer.parseInt(line);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
@ -47,7 +44,7 @@ public class RequestAnalyser {
// lecture du reste // lecture du reste
StringBuilder sB_data = new StringBuilder(); StringBuilder sB_data = new StringBuilder();
char[] c = new char[100]; char[] c = new char[100];
int nbC = 0; int nbC;
while ((nbC = in.read(c)) != -1) while ((nbC = in.read(c)) != -1)
sB_data.append(c, 0, nbC); sB_data.append(c, 0, nbC);
@ -58,9 +55,7 @@ public class RequestAnalyser {
socket.shutdownInput(); socket.shutdownInput();
} }
public class BadRequestException extends Exception { public static class BadRequestException extends Exception {
private static final long serialVersionUID = 1L;
public BadRequestException(String message) { public BadRequestException(String message) {
super(message); super(message);

View File

@ -33,12 +33,11 @@ public abstract class PermEntity {
* Tells if the current entity inherits directly or indirectly from the specified group * Tells if the current entity inherits directly or indirectly from the specified group
* @param group the group to search for * @param group the group to search for
* @param recursive true to search in the inheritance tree, or false to search only in the inheritance list of the current entity. * @param recursive true to search in the inheritance tree, or false to search only in the inheritance list of the current entity.
* @return
*/ */
public boolean inheritsFromGroup(String group, boolean recursive) { public boolean inheritsFromGroup(String group, boolean recursive) {
if (group == null) if (group == null)
return false; return false;
return getInheritances().stream().anyMatch(g -> g.name.equals(group) || (recursive && g.inheritsFromGroup(group, recursive))); return getInheritances().stream().anyMatch(g -> g.name.equals(group) || (recursive && g.inheritsFromGroup(group, true)));
} }
public String getPrefix() { public String getPrefix() {
@ -105,8 +104,8 @@ public abstract class PermEntity {
String prefixWithEndingDot = permissionPrefix.endsWith(".") ? permissionPrefix : (permissionPrefix + "."); String prefixWithEndingDot = permissionPrefix.endsWith(".") ? permissionPrefix : (permissionPrefix + ".");
int prefixLength = prefixWithEndingDot.length(); int prefixLength = prefixWithEndingDot.length();
return listEffectivePermissions(server, world).entrySet().stream() return listEffectivePermissions(server, world).entrySet().stream()
.filter(e -> e.getValue()) // permission must be positive .filter(Map.Entry::getValue) // permission must be positive
.map(e -> e.getKey()) // keep only the permission node (key), since the value is always true .map(Map.Entry::getKey) // keep only the permission node (key), since the value is always true
.filter(p -> p.startsWith(prefixWithEndingDot)) // keep only relevant permissions .filter(p -> p.startsWith(prefixWithEndingDot)) // keep only relevant permissions
.map(p -> p.substring(prefixLength)) // keep only what is after the prefix .map(p -> p.substring(prefixLength)) // keep only what is after the prefix
.map(suffix -> { // convert to long .map(suffix -> { // convert to long
@ -117,7 +116,7 @@ public abstract class PermEntity {
return null; return null;
} }
}) })
.filter(longSuffix -> longSuffix != null) .filter(Objects::nonNull)
.mapToLong(longSuffix -> longSuffix) .mapToLong(longSuffix -> longSuffix)
.sorted(); .sorted();
} }
@ -224,10 +223,9 @@ public abstract class PermEntity {
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj == null || !(obj instanceof PermEntity)) return obj instanceof PermEntity o
return false; && Objects.equals(name, o.name)
PermEntity o = (PermEntity) obj; && type == o.type;
return Objects.equals(name, o.name) && type == o.type;
} }
@Override @Override

View File

@ -50,7 +50,6 @@ public class PermPlayer extends PermEntity {
/** /**
* Alias for {@link #getInheritances()}. * Alias for {@link #getInheritances()}.
* @return
*/ */
public List<PermGroup> getGroups() { public List<PermGroup> getGroups() {
return getInheritances(); return getInheritances();
@ -58,7 +57,6 @@ public class PermPlayer extends PermEntity {
/** /**
* Alias for {@link #getInheritances()}. * Alias for {@link #getInheritances()}.
* @return
*/ */
public List<String> getGroupsString() { public List<String> getGroupsString() {
return getInheritancesString(); return getInheritancesString();
@ -68,7 +66,6 @@ public class PermPlayer extends PermEntity {
* Tells if the player is directly part of a group. * Tells if the player is directly part of a group.
* This is equivalent to {@link #inheritsFromGroup(String, boolean) inheritsFromGroup(group, false)} * This is equivalent to {@link #inheritsFromGroup(String, boolean) inheritsFromGroup(group, false)}
* @param group the group to search for * @param group the group to search for
* @return
*/ */
public boolean isInGroup(String group) { public boolean isInGroup(String group) {
return inheritsFromGroup(group, false); return inheritsFromGroup(group, false);

View File

@ -1,9 +1,11 @@
package fr.pandacube.lib.core.permissions; package fr.pandacube.lib.core.permissions;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import fr.pandacube.lib.core.db.DB; import fr.pandacube.lib.core.db.DB;
import fr.pandacube.lib.core.db.DBConnection;
import fr.pandacube.lib.core.db.DBException; import fr.pandacube.lib.core.db.DBException;
import fr.pandacube.lib.core.util.Log; import fr.pandacube.lib.core.util.Log;
@ -16,7 +18,6 @@ public class Permissions {
/** /**
* Initialize the permission system. * Initialize the permission system.
* The connection to the database needs to be initialized first, using {@link DB#init(DBConnection, String)}. * The connection to the database needs to be initialized first, using {@link DB#init(DBConnection, String)}.
* @throws DBException
*/ */
public static void init() throws DBException { public static void init() throws DBException {
if (backendReader != null) if (backendReader != null)
@ -38,8 +39,7 @@ public class Permissions {
checkInitialized(); checkInitialized();
if (specialPermissions == null) if (specialPermissions == null)
return; return;
for (SpecialPermission sp : specialPermissions) resolver.specialPermissions.addAll(Arrays.asList(specialPermissions));
resolver.specialPermissions.add(sp);
} }
private static void checkInitialized() { private static void checkInitialized() {

View File

@ -57,22 +57,20 @@ import fr.pandacube.lib.core.permissions.SQLPermissions.EntityType;
.and(SQLPermissions.type.eq(EntityType.Group.getCode())) .and(SQLPermissions.type.eq(EntityType.Group.getCode()))
.and(SQLPermissions.key.like("default")) .and(SQLPermissions.key.like("default"))
); );
if (entry == null && !deflt) { if (entry != null) {
return; if (deflt) {
// update just in case
if ("true".equals(entry.get(SQLPermissions.value)))
return;
entry.set(SQLPermissions.value, "true");
entry.save();
}
else {
// delete
entry.delete();
}
} }
else if (entry != null && deflt) { else if (deflt) {
// update
if ("true".equals(entry.get(SQLPermissions.value)))
return;
entry.set(SQLPermissions.value, "true");
entry.save();
return;
}
else if (entry != null && !deflt) {
// delete
entry.delete();
}
else {
// insert // insert
addEntry(name, EntityType.Group, "default", "true", null, null); addEntry(name, EntityType.Group, "default", "true", null, null);
} }
@ -97,20 +95,18 @@ import fr.pandacube.lib.core.permissions.SQLPermissions.EntityType;
.and(SQLPermissions.type.eq(type.getCode())) .and(SQLPermissions.type.eq(type.getCode()))
.and(SQLPermissions.key.like("prefix")) .and(SQLPermissions.key.like("prefix"))
); );
if (entry == null && prefix == null) { if (entry != null) {
return; if (prefix != null) {
// update
entry.set(SQLPermissions.value, prefix);
entry.save();
}
else {
// delete
entry.delete();
}
} }
else if (entry != null && prefix != null) { else if (prefix != null) {
// update
entry.set(SQLPermissions.value, prefix);
entry.save();
return;
}
else if (entry != null && prefix == null) {
// delete
entry.delete();
}
else {
// insert // insert
addEntry(name, type, "prefix", prefix, null, null); addEntry(name, type, "prefix", prefix, null, null);
} }
@ -130,20 +126,18 @@ import fr.pandacube.lib.core.permissions.SQLPermissions.EntityType;
.and(SQLPermissions.type.eq(type.getCode())) .and(SQLPermissions.type.eq(type.getCode()))
.and(SQLPermissions.key.like("suffix")) .and(SQLPermissions.key.like("suffix"))
); );
if (entry == null && suffix == null) { if (entry != null) {
return; if (suffix != null) {
// update
entry.set(SQLPermissions.value, suffix);
entry.save();
}
else {
// delete
entry.delete();
}
} }
else if (entry != null && suffix != null) { else if (suffix != null) {
// update
entry.set(SQLPermissions.value, suffix);
entry.save();
return;
}
else if (entry != null && suffix == null) {
// delete
entry.delete();
}
else {
// insert // insert
addEntry(name, type, "suffix", suffix, null, null); addEntry(name, type, "suffix", suffix, null, null);
} }
@ -175,7 +169,7 @@ import fr.pandacube.lib.core.permissions.SQLPermissions.EntityType;
throw new IllegalStateException("Inheritance already set"); throw new IllegalStateException("Inheritance already set");
addEntry(name, type, key, inheritance, null, null); addEntry(name, type, key, inheritance, null, null);
} catch (DBException e) { } catch (DBException e) {
new RuntimeException(e); throw new RuntimeException(e);
} }
} }

View File

@ -29,10 +29,10 @@ import fr.pandacube.lib.core.util.Log;
private Cache<UUID, CachedPlayer> usersCache = CacheBuilder.newBuilder() private final Cache<UUID, CachedPlayer> usersCache = CacheBuilder.newBuilder()
.expireAfterAccess(10, TimeUnit.MINUTES) .expireAfterAccess(10, TimeUnit.MINUTES)
.build(); .build();
private Set<String> fullPermissionsList = new TreeSet<String>(); private Set<String> fullPermissionsList = new TreeSet<>();
/* package */ synchronized List<String> getFullPermissionsList() { /* package */ synchronized List<String> getFullPermissionsList() {
return new ArrayList<>(fullPermissionsList); return new ArrayList<>(fullPermissionsList);
@ -105,14 +105,12 @@ import fr.pandacube.lib.core.util.Log;
if (playerRawData.containsKey("groups")) { if (playerRawData.containsKey("groups")) {
playerRawData.get("groups").stream() playerRawData.get("groups").stream()
.map(e -> e.get(SQLPermissions.value)) .map(e -> e.get(SQLPermissions.value))
.forEach(g -> { .forEach(g -> player.groups.add(getCachedGroup(g)));
player.groups.add(getCachedGroup(g));
});
} }
if (player.groups.isEmpty()) { if (player.groups.isEmpty()) {
player.usingDefaultGroups = true; player.usingDefaultGroups = true;
getDefaultGroups().forEach(player.groups::add); player.groups.addAll(getDefaultGroups());
} }
return player; return player;
@ -121,7 +119,7 @@ import fr.pandacube.lib.core.util.Log;
private Map<String, CachedGroup> groupsCache = new LinkedHashMap<>(); private final Map<String, CachedGroup> groupsCache = new LinkedHashMap<>();
private boolean cacheIsUpdating = false; private boolean cacheIsUpdating = false;
@ -207,8 +205,7 @@ import fr.pandacube.lib.core.util.Log;
Map<String, List<SQLPermissions>> groupRawData = groupsRawData.getOrDefault(groupName, new LinkedHashMap<>()); Map<String, List<SQLPermissions>> groupRawData = groupsRawData.getOrDefault(groupName, new LinkedHashMap<>());
boolean groupDefault = groupRawData.containsKey("default") boolean groupDefault = groupRawData.containsKey("default")
? "true".equals(groupRawData.get("default").get(0).get(SQLPermissions.value)) && "true".equals(groupRawData.get("default").get(0).get(SQLPermissions.value));
: false;
String groupSelfPrefix = null; String groupSelfPrefix = null;
if (groupRawData.containsKey("prefix")) { if (groupRawData.containsKey("prefix")) {

View File

@ -29,7 +29,7 @@ import net.md_5.bungee.api.ChatColor;
public class PermissionsResolver { public class PermissionsResolver {
private PermissionsCachedBackendReader backendReader; private final PermissionsCachedBackendReader backendReader;
/* package */ PermissionsResolver(PermissionsCachedBackendReader b) { /* package */ PermissionsResolver(PermissionsCachedBackendReader b) {
backendReader = b; backendReader = b;
@ -74,7 +74,7 @@ public class PermissionsResolver {
return debugData(name, type, DataType.SUFFIX); return debugData(name, type, DataType.SUFFIX);
} }
private Cache<DataCacheKey, String> effectiveDataCache = CacheBuilder.newBuilder() private final Cache<DataCacheKey, String> effectiveDataCache = CacheBuilder.newBuilder()
.expireAfterAccess(10, TimeUnit.MINUTES) .expireAfterAccess(10, TimeUnit.MINUTES)
.build(); .build();
@ -83,9 +83,7 @@ public class PermissionsResolver {
Objects.requireNonNull(type, "type cant be null"); Objects.requireNonNull(type, "type cant be null");
try { try {
return effectiveDataCache.get(new DataCacheKey(name, type, dataType), () -> { return effectiveDataCache.get(new DataCacheKey(name, type, dataType), () -> resolveData(name, type, dataType));
return resolveData(name, type, dataType);
});
} catch (ExecutionException e) { } catch (ExecutionException e) {
Log.severe(e); Log.severe(e);
return null; return null;
@ -108,7 +106,7 @@ public class PermissionsResolver {
if (resolutionResult.conflict) { if (resolutionResult.conflict) {
Log.warning("For data " + dataType + ":\n" Log.warning("For data " + dataType + ":\n"
+ ChatUtil.treeView(resolutionResult.toDisplayTreeNode(), true).stream() + ChatUtil.treeView(resolutionResult.toDisplayTreeNode(), true).stream()
.map(cmp -> cmp.getLegacyText()) .map(Chat::getLegacyText)
.collect(Collectors.joining(ChatColor.RESET + "\n"))); .collect(Collectors.joining(ChatColor.RESET + "\n")));
} }
@ -140,7 +138,7 @@ public class PermissionsResolver {
Set<String> inheritedPermissions = inheritedResults.stream() Set<String> inheritedPermissions = inheritedResults.stream()
.map(g -> g.result) .map(g -> g.result)
.filter(r -> r != null) .filter(Objects::nonNull)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
if (inheritedPermissions.size() == 1) if (inheritedPermissions.size() == 1)
@ -176,7 +174,7 @@ public class PermissionsResolver {
c.thenFailure(" " + conflictMessage); c.thenFailure(" " + conflictMessage);
DisplayTreeNode node = new DisplayTreeNode(c); DisplayTreeNode node = new DisplayTreeNode(c);
if (result == null && conflict == false && !inheritances.isEmpty()) { if (result == null && !conflict && !inheritances.isEmpty()) {
// there is nothing interesting to show on current or subnode // there is nothing interesting to show on current or subnode
node.children.add(new DisplayTreeNode(Chat.text("(Inheritances hidden for brevety)").darkGray().italic())); node.children.add(new DisplayTreeNode(Chat.text("(Inheritances hidden for brevety)").darkGray().italic()));
return node; return node;
@ -197,10 +195,8 @@ public class PermissionsResolver {
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj == null || !(obj instanceof DataCacheKey)) return obj instanceof DataCacheKey o
return false; && Objects.equals(name, o.name)
DataCacheKey o = (DataCacheKey) obj;
return Objects.equals(name, o.name)
&& Objects.equals(type, o.type) && Objects.equals(type, o.type)
&& dataType == o.dataType; && dataType == o.dataType;
} }
@ -211,7 +207,7 @@ public class PermissionsResolver {
SUFFIX(CachedEntity::getSelfSuffix); SUFFIX(CachedEntity::getSelfSuffix);
private final CachedEntityGetter<String> getter; private final CachedEntityGetter<String> getter;
private DataType(CachedEntityGetter<String> g) { DataType(CachedEntityGetter<String> g) {
getter = g; getter = g;
} }
} }
@ -233,7 +229,7 @@ public class PermissionsResolver {
private Cache<PermCacheKey, Map<String, Boolean>> effectivePermissionsListCache = CacheBuilder.newBuilder() private final Cache<PermCacheKey, Map<String, Boolean>> effectivePermissionsListCache = CacheBuilder.newBuilder()
.expireAfterAccess(10, TimeUnit.MINUTES) .expireAfterAccess(10, TimeUnit.MINUTES)
.build(); .build();
@ -265,7 +261,7 @@ public class PermissionsResolver {
} }
private Cache<PermCacheKey, PermState> effectivePermissionsCache = CacheBuilder.newBuilder() private final Cache<PermCacheKey, PermState> effectivePermissionsCache = CacheBuilder.newBuilder()
.expireAfterAccess(10, TimeUnit.MINUTES) .expireAfterAccess(10, TimeUnit.MINUTES)
.build(); .build();
@ -281,14 +277,14 @@ public class PermissionsResolver {
reversed = true; reversed = true;
} }
String fPermission = permission == null ? null : permission.toLowerCase(); String fPermission = permission.toLowerCase();
String fServer = server == null ? null : server.toLowerCase(); String fServer = server == null ? null : server.toLowerCase();
String fWorld = world == null ? null : world.toLowerCase(); String fWorld = world == null ? null : world.toLowerCase();
try { try {
Boolean resolved = effectivePermissionsCache.get(new PermCacheKey(name, type, fPermission, fServer, fWorld), () -> { Boolean resolved = effectivePermissionsCache.get(new PermCacheKey(name, type, fPermission, fServer, fWorld),
return resolvePermission(name, type, fPermission, fServer, fWorld); () -> resolvePermission(name, type, fPermission, fServer, fWorld)
}).value; ).value;
return resolved == null ? null : (reversed != resolved.booleanValue()); return resolved == null ? null : (reversed != resolved);
} catch (ExecutionException e) { } catch (ExecutionException e) {
Log.severe(e); Log.severe(e);
return null; return null;
@ -312,7 +308,7 @@ public class PermissionsResolver {
if (resolutionResult.conflict) { if (resolutionResult.conflict) {
Log.warning("For permission " + permission + ":\n" Log.warning("For permission " + permission + ":\n"
+ ChatUtil.treeView(resolutionResult.toDisplayTreeNode(), true).stream() + ChatUtil.treeView(resolutionResult.toDisplayTreeNode(), true).stream()
.map(cmp -> cmp.getLegacyText()) .map(Chat::getLegacyText)
.collect(Collectors.joining(ChatColor.RESET + "\n"))); .collect(Collectors.joining(ChatColor.RESET + "\n")));
} }
@ -374,7 +370,7 @@ public class PermissionsResolver {
if (inheritancesGranted != inheritancesRevoqued) { if (inheritancesGranted != inheritancesRevoqued) {
resolutionNode.result = inheritancesGranted ? PermState.GRANTED : PermState.REVOQUED; resolutionNode.result = inheritancesGranted ? PermState.GRANTED : PermState.REVOQUED;
} }
else if (inheritancesGranted && inheritancesRevoqued) { else if (inheritancesGranted) {
resolutionNode.conflictMessage = (resolutionNode.conflictMessage == null ? "" : (resolutionNode.conflictMessage + " ; ")) resolutionNode.conflictMessage = (resolutionNode.conflictMessage == null ? "" : (resolutionNode.conflictMessage + " ; "))
+ "Unsolvable conflict between inheritances"; + "Unsolvable conflict between inheritances";
resolutionNode.conflict = true; resolutionNode.conflict = true;
@ -388,7 +384,7 @@ public class PermissionsResolver {
/* package */ List<SpecialPermission> specialPermissions = new ArrayList<>(); /* package */ final List<SpecialPermission> specialPermissions = new ArrayList<>();
@ -436,7 +432,7 @@ public class PermissionsResolver {
resNode = new ParsedSelfPermission(p, false, PermType.WILDCARD); resNode = new ParsedSelfPermission(p, false, PermType.WILDCARD);
return resNode; return resNode;
}) })
.filter(p -> p != null) .filter(Objects::nonNull)
.collect(Collectors.toList()); .collect(Collectors.toList());
boolean explicitGranted = foundPerms.stream() boolean explicitGranted = foundPerms.stream()
@ -459,13 +455,13 @@ public class PermissionsResolver {
conflict = "Unnecessary explicit permission already granted by self wildcard permissions"; // redundent explicit perm conflict = "Unnecessary explicit permission already granted by self wildcard permissions"; // redundent explicit perm
} }
} }
else if (explicitGranted && explicitRevoqued) { else if (explicitGranted) {
conflict = "Unsolvable conflit between explicit permissions"; conflict = "Unsolvable conflit between explicit permissions";
} }
else if (wildcardGranted != wildcardRevoqued) { else if (wildcardGranted != wildcardRevoqued) {
result = PermState.of(wildcardGranted); result = PermState.of(wildcardGranted);
} }
else if (wildcardGranted && wildcardRevoqued) { else if (wildcardGranted) {
conflict = "Unsolvable conflit between wildcard permissions"; conflict = "Unsolvable conflit between wildcard permissions";
} }
} }
@ -505,7 +501,7 @@ public class PermissionsResolver {
selfPermissions.forEach(p -> node.children.add(p.toDisplayTreeNode())); selfPermissions.forEach(p -> node.children.add(p.toDisplayTreeNode()));
if (result == PermState.UNDEFINED && conflict == false && !inheritances.isEmpty()) { if (result == PermState.UNDEFINED && !conflict && !inheritances.isEmpty()) {
// there is nothing interesting to show on current or subnode // there is nothing interesting to show on current or subnode
node.children.add(new DisplayTreeNode(Chat.text("(Inheritances hidden for brevety)").darkGray().italic())); node.children.add(new DisplayTreeNode(Chat.text("(Inheritances hidden for brevety)").darkGray().italic()));
return node; return node;
@ -542,10 +538,8 @@ public class PermissionsResolver {
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj == null || !(obj instanceof PermCacheKey)) return obj instanceof PermCacheKey o
return false; && Objects.equals(name, o.name)
PermCacheKey o = (PermCacheKey) obj;
return Objects.equals(name, o.name)
&& Objects.equals(type, o.type) && Objects.equals(type, o.type)
&& Objects.equals(permission, o.permission) && Objects.equals(permission, o.permission)
&& Objects.equals(server, o.server) && Objects.equals(server, o.server)
@ -554,7 +548,7 @@ public class PermissionsResolver {
} }
private enum PermType { private enum PermType {
EXPLICIT, WILDCARD, SPECIAL; EXPLICIT, WILDCARD, SPECIAL
} }
private enum PermState { private enum PermState {
@ -562,7 +556,7 @@ public class PermissionsResolver {
REVOQUED(false), REVOQUED(false),
UNDEFINED(null); UNDEFINED(null);
final Boolean value; final Boolean value;
private PermState(Boolean v) { value = v; } PermState(Boolean v) { value = v; }
private static PermState of(Boolean v) { private static PermState of(Boolean v) {
return v == null ? UNDEFINED : v ? GRANTED : REVOQUED; return v == null ? UNDEFINED : v ? GRANTED : REVOQUED;
} }

View File

@ -10,10 +10,8 @@ public class ServerWorldKey implements Comparable<ServerWorldKey> {
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj == null || !(obj instanceof ServerWorldKey)) return obj instanceof ServerWorldKey o
return false; && Objects.equals(server, o.server)
ServerWorldKey o = (ServerWorldKey) obj;
return Objects.equals(server, o.server)
&& Objects.equals(world, o.world); && Objects.equals(world, o.world);
} }
@Override @Override

View File

@ -20,7 +20,7 @@ import fr.pandacube.lib.core.util.Log;
public interface IOffPlayer { public interface IOffPlayer {
/** From how long the last web activity should be before considering the user offline (in ms)? */ /** From how long the last web activity should be before considering the user offline (in ms)? */
public static final long TIMEOUT_WEB_SESSION = 10000; // msec long TIMEOUT_WEB_SESSION = 10000; // msec
@ -34,7 +34,7 @@ public interface IOffPlayer {
* *
* @return the id of the player * @return the id of the player
*/ */
public abstract UUID getUniqueId(); UUID getUniqueId();
/** /**
@ -42,7 +42,7 @@ public interface IOffPlayer {
* *
* An alt account uses a specific bit in the UUID to distinguish themselves from the original account. * An alt account uses a specific bit in the UUID to distinguish themselves from the original account.
*/ */
public default boolean isAltAccount() { default boolean isAltAccount() {
return (getUniqueId().getMostSignificantBits() & 0x8000L) == 0x8000L; return (getUniqueId().getMostSignificantBits() & 0x8000L) == 0x8000L;
} }
@ -53,14 +53,14 @@ public interface IOffPlayer {
* *
* This method will return undetermined value if {@link #isAltAccount()} is false. * This method will return undetermined value if {@link #isAltAccount()} is false.
*/ */
public default int getAltIndex() { default int getAltIndex() {
return (int) (getUniqueId().getMostSignificantBits() >> 8) & 0xF; return (int) (getUniqueId().getMostSignificantBits() >> 8) & 0xF;
} }
/** /**
* @return the last known player name of this player, or null if this player never joined the network. * @return the last known player name of this player, or null if this player never joined the network.
*/ */
public default String getName() { default String getName() {
return PlayerFinder.getLastKnownName(getUniqueId()); return PlayerFinder.getLastKnownName(getUniqueId());
} }
@ -68,7 +68,7 @@ public interface IOffPlayer {
* Indicate if this player is connected to the current node (server or proxy, depending on interface implementation) * Indicate if this player is connected to the current node (server or proxy, depending on interface implementation)
* @return wether the player is online or not * @return wether the player is online or not
*/ */
public abstract boolean isOnline(); boolean isOnline();
@ -80,7 +80,7 @@ public interface IOffPlayer {
* If the player is online in game, it provides the current server they are * If the player is online in game, it provides the current server they are
* connected. * connected.
*/ */
public default PlayerStatusOnServer getPlayerStatus() { default PlayerStatusOnServer getPlayerStatus() {
IOnlinePlayer op = getOnlineInstance(); IOnlinePlayer op = getOnlineInstance();
if (op != null && !op.isVanished()) if (op != null && !op.isVanished())
@ -103,7 +103,7 @@ public interface IOffPlayer {
return new PlayerStatusOnServer(PlayerStatusOnServer.PlayerStatus.OFFLINE, null); return new PlayerStatusOnServer(PlayerStatusOnServer.PlayerStatus.OFFLINE, null);
} }
public record PlayerStatusOnServer(PlayerStatus status, String server) { record PlayerStatusOnServer(PlayerStatus status, String server) {
public Chat toComponent() { public Chat toComponent() {
if (status == PlayerStatus.ONLINE_IG) if (status == PlayerStatus.ONLINE_IG)
return successText("En ligne, " + server); return successText("En ligne, " + server);
@ -130,12 +130,12 @@ public interface IOffPlayer {
* Floodgate related stuff * Floodgate related stuff
*/ */
public default boolean isBedrockAccount() { default boolean isBedrockAccount() {
int v = getUniqueId().version(); int v = getUniqueId().version();
return v == 0 || v == 8; // also 8 if one day we supports alt accounts for floodgate players return v == 0 || v == 8; // also 8 if one day we supports alt accounts for floodgate players
} }
public default boolean isJavaAccount() { default boolean isJavaAccount() {
return !isBedrockAccount(); return !isBedrockAccount();
} }
@ -149,13 +149,12 @@ public interface IOffPlayer {
* Return the online instance of this player, if any exists. * Return the online instance of this player, if any exists.
* May return itself if the current instance already represent an online player. * May return itself if the current instance already represent an online player.
*/ */
public abstract IOnlinePlayer getOnlineInstance(); IOnlinePlayer getOnlineInstance();
/** /**
* Get the database entry of this player, or null if the player never joined the network. * Get the database entry of this player, or null if the player never joined the network.
* @throws DBException
*/ */
public default SQLPlayer getDbPlayer() throws DBException { default SQLPlayer getDbPlayer() throws DBException {
return SQLPlayer.getPlayerFromUUID(getUniqueId()); return SQLPlayer.getPlayerFromUUID(getUniqueId());
} }
@ -163,7 +162,7 @@ public interface IOffPlayer {
* Get the permission instance of this player. This will never return null. * Get the permission instance of this player. This will never return null.
* @return the permission instance of this player * @return the permission instance of this player
*/ */
public default PermPlayer getPermissionUser() { default PermPlayer getPermissionUser() {
return Permissions.getPlayer(getUniqueId()); return Permissions.getPlayer(getUniqueId());
} }
@ -181,15 +180,14 @@ public interface IOffPlayer {
* (and team for bukkit implementation) * (and team for bukkit implementation)
* @return the display name of the player * @return the display name of the player
*/ */
public abstract String getDisplayName(); String getDisplayName();
/** /**
* Get an updated display name of the user, * Get an updated display name of the user,
* generated using eventual permissions prefix(es) and suffix(es) of the player, * generated using eventual permissions prefix(es) and suffix(es) of the player,
* and with color codes translated to Minecrafts native {@code §}. * and with color codes translated to Minecrafts native {@code §}.
* @return
*/ */
public default String getDisplayNameFromPermissionSystem() { default String getDisplayNameFromPermissionSystem() {
PermPlayer permU = getPermissionUser(); PermPlayer permU = getPermissionUser();
return ChatColorUtil.translateAlternateColorCodes('&', return ChatColorUtil.translateAlternateColorCodes('&',
permU.getPrefix() + getName() + permU.getSuffix()); permU.getPrefix() + getName() + permU.getSuffix());
@ -215,7 +213,7 @@ public interface IOffPlayer {
* @param permission the permission node to test * @param permission the permission node to test
* @return whether this player has the provided permission * @return whether this player has the provided permission
*/ */
public default boolean hasPermission(String permission) { default boolean hasPermission(String permission) {
IOnlinePlayer online = getOnlineInstance(); IOnlinePlayer online = getOnlineInstance();
if (online != null) if (online != null)
@ -233,10 +231,10 @@ public interface IOffPlayer {
* loop. * loop.
* If the player is offline, it just call the Pandacube * If the player is offline, it just call the Pandacube
* permission system. * permission system.
* @param permission the permission node to test * @param permissionExpression the permission node to test
* @return whether this player has the provided permission * @return whether this player has the provided permission
*/ */
public default boolean hasPermissionExpression(String permissionExpression) { default boolean hasPermissionExpression(String permissionExpression) {
IOnlinePlayer online = getOnlineInstance(); IOnlinePlayer online = getOnlineInstance();
if (online != null) if (online != null)
@ -259,7 +257,7 @@ public interface IOffPlayer {
* @param permissionPrefix the permission prefix to search for. * @param permissionPrefix the permission prefix to search for.
* @return a LongStream containing all the values found for the specified permission prefix. * @return a LongStream containing all the values found for the specified permission prefix.
*/ */
public default LongStream getPermissionRangeValues(String permissionPrefix) { default LongStream getPermissionRangeValues(String permissionPrefix) {
IOnlinePlayer online = getOnlineInstance(); IOnlinePlayer online = getOnlineInstance();
if (online != null) if (online != null)
@ -272,7 +270,7 @@ public interface IOffPlayer {
/** /**
* Returns the maximum value returned by {@link IOffPlayer#getPermissionRangeValues(String)}. * Returns the maximum value returned by {@link IOffPlayer#getPermissionRangeValues(String)}.
*/ */
public default OptionalLong getPermissionRangeMax(String permissionPrefix) { default OptionalLong getPermissionRangeMax(String permissionPrefix) {
IOnlinePlayer online = getOnlineInstance(); IOnlinePlayer online = getOnlineInstance();
if (online != null) if (online != null)
@ -289,14 +287,14 @@ public interface IOffPlayer {
* @return <i>true</i> if this player is part of the group, * @return <i>true</i> if this player is part of the group,
* <i>false</i> otherwise * <i>false</i> otherwise
*/ */
public default boolean isInGroup(String group) { default boolean isInGroup(String group) {
return getPermissionUser().isInGroup(group); return getPermissionUser().isInGroup(group);
} }
/** /**
* Tells if this player is part of the staff, based on permission groups * Tells if this player is part of the staff, based on permission groups
*/ */
public default boolean isInStaff() { default boolean isInStaff() {
return getPermissionUser().inheritsFromGroup("staff-base", true); return getPermissionUser().inheritsFromGroup("staff-base", true);
} }
@ -315,7 +313,7 @@ public interface IOffPlayer {
* @param ignored the player that is potentially ignored by this player. * @param ignored the player that is potentially ignored by this player.
* If this parameter is null, this method returns false. * If this parameter is null, this method returns false.
*/ */
public default boolean canIgnore(IOffPlayer ignored) { default boolean canIgnore(IOffPlayer ignored) {
if (ignored == null) if (ignored == null)
return false; return false;
if (equals(ignored)) if (equals(ignored))
@ -331,7 +329,7 @@ public interface IOffPlayer {
* If this parameter is null, this method returns false. * If this parameter is null, this method returns false.
* @implNote the default implementation just calls {@link #canIgnore(IOffPlayer) ignorer.canIgnore(this)}. * @implNote the default implementation just calls {@link #canIgnore(IOffPlayer) ignorer.canIgnore(this)}.
*/ */
public default boolean canBeIgnoredBy(IOffPlayer ignorer) { default boolean canBeIgnoredBy(IOffPlayer ignorer) {
if (ignorer == null) if (ignorer == null)
return false; return false;
return ignorer.canIgnore(this); return ignorer.canIgnore(this);
@ -343,7 +341,7 @@ public interface IOffPlayer {
* If this parameter is null, this method returns false. * If this parameter is null, this method returns false.
* @return true if this player have to right to ignore the provided player and is actually ignoring him. * @return true if this player have to right to ignore the provided player and is actually ignoring him.
*/ */
public default boolean isIgnoring(IOffPlayer ignored) { default boolean isIgnoring(IOffPlayer ignored) {
if (!canIgnore(ignored)) if (!canIgnore(ignored))
return false; return false;
@ -363,7 +361,7 @@ public interface IOffPlayer {
* @return true if the provided player have to right to ignore this player and is actually ignoring him. * @return true if the provided player have to right to ignore this player and is actually ignoring him.
* @implNote the default implementation just calls {@link #isIgnoring(IOffPlayer) ignorer.isIgnoring(this)}. * @implNote the default implementation just calls {@link #isIgnoring(IOffPlayer) ignorer.isIgnoring(this)}.
*/ */
public default boolean isIgnoredBy(IOffPlayer ignorer) { default boolean isIgnoredBy(IOffPlayer ignorer) {
return ignorer.isIgnoring(this); return ignorer.isIgnoring(this);
} }
@ -379,7 +377,7 @@ public interface IOffPlayer {
* Retrieve the time when the player will be unmuted, or null if the player is not muted. * Retrieve the time when the player will be unmuted, or null if the player is not muted.
* @return the timestamp in millisecond of when the player will be unmuted * @return the timestamp in millisecond of when the player will be unmuted
*/ */
public default Long getMuteTimeout() { default Long getMuteTimeout() {
try { try {
Long muteTimeout = getDbPlayer().get(SQLPlayer.muteTimeout); Long muteTimeout = getDbPlayer().get(SQLPlayer.muteTimeout);
if (muteTimeout == null || muteTimeout <= System.currentTimeMillis()) if (muteTimeout == null || muteTimeout <= System.currentTimeMillis())
@ -394,9 +392,8 @@ public interface IOffPlayer {
/** /**
* Tells if the player is currently muted, meaning that they cannot communicate * Tells if the player is currently muted, meaning that they cannot communicate
* through the chat or private messages. * through the chat or private messages.
* @return
*/ */
public default boolean isMuted() { default boolean isMuted() {
return getMuteTimeout() != null; return getMuteTimeout() != null;
} }
@ -408,7 +405,7 @@ public interface IOffPlayer {
* Birthday * Birthday
*/ */
public default void setBirthday(int day, int month, Integer year) { default void setBirthday(int day, int month, Integer year) {
try { try {
SQLPlayer dbPlayer = getDbPlayer(); SQLPlayer dbPlayer = getDbPlayer();
dbPlayer.setBirthday(day, month, year); dbPlayer.setBirthday(day, month, year);
@ -418,7 +415,7 @@ public interface IOffPlayer {
} }
} }
public default Calendar getBirthday() { default Calendar getBirthday() {
try { try {
return getDbPlayer().getBirthday(); return getDbPlayer().getBirthday();
} catch (DBException e) { } catch (DBException e) {
@ -434,25 +431,25 @@ public interface IOffPlayer {
* Player config * Player config
*/ */
public default String getConfig(String key) throws DBException { default String getConfig(String key) throws DBException {
return SQLPlayerConfig.get(getUniqueId(), key); return SQLPlayerConfig.get(getUniqueId(), key);
} }
public default String getConfig(String key, String deflt) throws DBException { default String getConfig(String key, String deflt) throws DBException {
return SQLPlayerConfig.get(getUniqueId(), key, deflt); return SQLPlayerConfig.get(getUniqueId(), key, deflt);
} }
public default void setConfig(String key, String value) throws DBException { default void setConfig(String key, String value) throws DBException {
SQLPlayerConfig.set(getUniqueId(), key, value); SQLPlayerConfig.set(getUniqueId(), key, value);
} }
public default void unsetConfig(String key) throws DBException { default void unsetConfig(String key) throws DBException {
SQLPlayerConfig.unset(getUniqueId(), key); SQLPlayerConfig.unset(getUniqueId(), key);
} }
public default boolean isWelcomeQuizzDone() { default boolean isWelcomeQuizzDone() {
try { try {
return Boolean.valueOf(getConfig("welcome.quizz.done", "false")); return Boolean.parseBoolean(getConfig("welcome.quizz.done", "false"));
} catch (DBException e) { } catch (DBException e) {
Log.severe("Error knowing if player has already done the quizz. Assuming they did for now.", e); Log.severe("Error knowing if player has already done the quizz. Assuming they did for now.", e);
return true; return true;

View File

@ -29,11 +29,11 @@ public interface IOnlinePlayer extends IOffPlayer {
* @implSpec The implementation is expected to call the environment API * @implSpec The implementation is expected to call the environment API
* (Bukkit/Bungee) to get the name of the player. * (Bukkit/Bungee) to get the name of the player.
*/ */
public abstract String getName(); String getName();
public abstract String getServerName(); String getServerName();
public abstract String getWorldName(); String getWorldName();
@ -42,7 +42,7 @@ public interface IOnlinePlayer extends IOffPlayer {
* Floodgate related * Floodgate related
*/ */
public default boolean isBedrockClient() { default boolean isBedrockClient() {
try { try {
return FloodgateApi.getInstance().isFloodgatePlayer(getUniqueId()); return FloodgateApi.getInstance().isFloodgatePlayer(getUniqueId());
} catch (NoClassDefFoundError e) { } catch (NoClassDefFoundError e) {
@ -50,11 +50,11 @@ public interface IOnlinePlayer extends IOffPlayer {
} }
} }
public default FloodgatePlayer getBedrockClient() { default FloodgatePlayer getBedrockClient() {
return FloodgateApi.getInstance().getPlayer(getUniqueId()); return FloodgateApi.getInstance().getPlayer(getUniqueId());
} }
public default boolean isJavaClient() { default boolean isJavaClient() {
return !isBedrockClient(); return !isBedrockClient();
} }
@ -70,7 +70,7 @@ public interface IOnlinePlayer extends IOffPlayer {
* @throws DBException if a database access error occurs * @throws DBException if a database access error occurs
*/ */
@Override @Override
public default SQLPlayer getDbPlayer() throws DBException { default SQLPlayer getDbPlayer() throws DBException {
SQLPlayer p = SQLPlayer.getPlayerFromUUID(getUniqueId()); SQLPlayer p = SQLPlayer.getPlayerFromUUID(getUniqueId());
if (p == null) if (p == null)
throw new IllegalStateException("The player was not found in the database: " + getUniqueId()); throw new IllegalStateException("The player was not found in the database: " + getUniqueId());
@ -93,7 +93,7 @@ public interface IOnlinePlayer extends IOffPlayer {
* indirectly call the method {@link IOffPlayer#hasPermission(String)}, * indirectly call the method {@link IOffPlayer#hasPermission(String)},
* or it may result in a {@link StackOverflowError}. * or it may result in a {@link StackOverflowError}.
*/ */
public abstract boolean hasPermission(String permission); boolean hasPermission(String permission);
/** /**
* Tells if this online player has the permission resulted from the provided expression. * Tells if this online player has the permission resulted from the provided expression.
@ -101,7 +101,7 @@ public interface IOnlinePlayer extends IOffPlayer {
* indirectly call the method {@link IOffPlayer#hasPermissionExpression(String)}, * indirectly call the method {@link IOffPlayer#hasPermissionExpression(String)},
* or it may result in a {@link StackOverflowError}. * or it may result in a {@link StackOverflowError}.
*/ */
public abstract boolean hasPermissionExpression(String permission); boolean hasPermissionExpression(String permission);
/** /**
* Lists all the values for a set of permission indicating an integer in a range. * Lists all the values for a set of permission indicating an integer in a range.
@ -116,12 +116,12 @@ public interface IOnlinePlayer extends IOffPlayer {
* @param permissionPrefix the permission prefix to search for. * @param permissionPrefix the permission prefix to search for.
* @return a LongStream containing all the values found for the specified permission prefix. * @return a LongStream containing all the values found for the specified permission prefix.
*/ */
public abstract LongStream getPermissionRangeValues(String permissionPrefix); LongStream getPermissionRangeValues(String permissionPrefix);
/** /**
* Returns the maximum value returned by {@link IOffPlayer#getPermissionRangeValues(String)}. * Returns the maximum value returned by {@link IOffPlayer#getPermissionRangeValues(String)}.
*/ */
public abstract OptionalLong getPermissionRangeMax(String permissionPrefix); OptionalLong getPermissionRangeMax(String permissionPrefix);
@ -135,9 +135,9 @@ public interface IOnlinePlayer extends IOffPlayer {
* Vanish * Vanish
*/ */
public abstract boolean isVanished(); boolean isVanished();
public default boolean isVanishedFor(IOffPlayer other) { default boolean isVanishedFor(IOffPlayer other) {
if (!isVanished()) if (!isVanished())
return false; // can see unvanished return false; // can see unvanished
@ -168,14 +168,14 @@ public interface IOnlinePlayer extends IOffPlayer {
* the chat is activated. * the chat is activated.
* @param message the message to display. * @param message the message to display.
*/ */
public abstract void sendMessage(Component message); void sendMessage(Component message);
/** /**
* Display the provided message in the players chat, if * Display the provided message in the players chat, if
* the chat is activated. * the chat is activated.
* @param message the message to display. * @param message the message to display.
*/ */
public default void sendMessage(ComponentLike message) { default void sendMessage(ComponentLike message) {
sendMessage(message.asComponent()); sendMessage(message.asComponent());
} }
@ -184,7 +184,7 @@ public interface IOnlinePlayer extends IOffPlayer {
* the chat is activated * the chat is activated
* @param message the message to display * @param message the message to display
*/ */
public default void sendMessage(Chat message) { default void sendMessage(Chat message) {
sendMessage(message.getAdv()); sendMessage(message.getAdv());
} }
@ -198,7 +198,7 @@ public interface IOnlinePlayer extends IOffPlayer {
* the sender. This parameter is only there to be transmitted to the client, so client side filtering can * the sender. This parameter is only there to be transmitted to the client, so client side filtering can
* be processed. * be processed.
*/ */
public default void sendMessage(Component message, UUID sender) { default void sendMessage(Component message, UUID sender) {
sendMessage(message, () -> sender == null ? Identity.nil() : Identity.identity(sender)); sendMessage(message, () -> sender == null ? Identity.nil() : Identity.identity(sender));
} }
@ -212,7 +212,7 @@ public interface IOnlinePlayer extends IOffPlayer {
* the sender. This parameter is only there to be transmitted to the client, so client side filtering can * the sender. This parameter is only there to be transmitted to the client, so client side filtering can
* be processed. * be processed.
*/ */
public abstract void sendMessage(Component message, Identified sender); void sendMessage(Component message, Identified sender);
/** /**
* Display the provided message in the players chat, if * Display the provided message in the players chat, if
@ -221,7 +221,7 @@ public interface IOnlinePlayer extends IOffPlayer {
* @param sender the player causing the send of this message. Client side filtering may occur. * @param sender the player causing the send of this message. Client side filtering may occur.
* May be null if we dont want client filtering, but still consider the message as CHAT message. * May be null if we dont want client filtering, but still consider the message as CHAT message.
*/ */
public default void sendMessage(ComponentLike message, UUID sender) { default void sendMessage(ComponentLike message, UUID sender) {
sendMessage(message.asComponent(), sender); sendMessage(message.asComponent(), sender);
} }
@ -232,7 +232,7 @@ public interface IOnlinePlayer extends IOffPlayer {
* @param sender the player causing the send of this message. Client side filtering may occur. * @param sender the player causing the send of this message. Client side filtering may occur.
* May be null if we dont want client filtering, but still consider the message as CHAT message. * May be null if we dont want client filtering, but still consider the message as CHAT message.
*/ */
public default void sendMessage(Chat message, UUID sender) { default void sendMessage(Chat message, UUID sender) {
sendMessage(message.getAdv(), sender); sendMessage(message.getAdv(), sender);
} }
@ -241,7 +241,7 @@ public interface IOnlinePlayer extends IOffPlayer {
* activated, prepended with the server prefix. * activated, prepended with the server prefix.
* @param message the message to display * @param message the message to display
*/ */
public default void sendPrefixedMessage(Component message) { default void sendPrefixedMessage(Component message) {
sendMessage(IPlayerManager.prefixedAndColored(message)); sendMessage(IPlayerManager.prefixedAndColored(message));
} }
@ -250,7 +250,7 @@ public interface IOnlinePlayer extends IOffPlayer {
* activated, prepended with the server prefix. * activated, prepended with the server prefix.
* @param message the message to display * @param message the message to display
*/ */
public default void sendPrefixedMessage(Chat message) { default void sendPrefixedMessage(Chat message) {
sendPrefixedMessage(message.getAdv()); sendPrefixedMessage(message.getAdv());
} }
@ -262,7 +262,7 @@ public interface IOnlinePlayer extends IOffPlayer {
* @param stay Stay time in tick * @param stay Stay time in tick
* @param fadeOut Fade out time in tick * @param fadeOut Fade out time in tick
*/ */
public abstract void sendTitle(Component title, Component subtitle, int fadeIn, int stay, int fadeOut); void sendTitle(Component title, Component subtitle, int fadeIn, int stay, int fadeOut);
/** /**
* Display a title in the middle of the screen. * Display a title in the middle of the screen.
@ -272,7 +272,7 @@ public interface IOnlinePlayer extends IOffPlayer {
* @param stay Stay time in tick * @param stay Stay time in tick
* @param fadeOut Fade out time in tick * @param fadeOut Fade out time in tick
*/ */
public default void sendTitle(Chat title, Chat subtitle, int fadeIn, int stay, int fadeOut) { default void sendTitle(Chat title, Chat subtitle, int fadeIn, int stay, int fadeOut) {
sendTitle(title.getAdv(), subtitle.getAdv(), fadeIn, stay, fadeOut); sendTitle(title.getAdv(), subtitle.getAdv(), fadeIn, stay, fadeOut);
} }
@ -282,7 +282,7 @@ public interface IOnlinePlayer extends IOffPlayer {
* line break. * line break.
* @param brand the server brand to send to the client. * @param brand the server brand to send to the client.
*/ */
public abstract void sendServerBrand(String brand); void sendServerBrand(String brand);
@ -297,17 +297,17 @@ public interface IOnlinePlayer extends IOffPlayer {
public abstract ClientOptions getClientOptions(); ClientOptions getClientOptions();
public interface ClientOptions { interface ClientOptions {
public Locale getLocale(); Locale getLocale();
public int getViewDistance(); int getViewDistance();
public boolean hasChatColorEnabled(); boolean hasChatColorEnabled();
/** /**
* Tells if the client is configured to completely hide the chat to the * Tells if the client is configured to completely hide the chat to the
@ -316,7 +316,7 @@ public interface IOnlinePlayer extends IOffPlayer {
* @implSpec if the value is unknown, it is assumed that the chat is * @implSpec if the value is unknown, it is assumed that the chat is
* fully visible. * fully visible.
*/ */
public boolean isChatHidden(); boolean isChatHidden();
/** /**
* Tells if the client is configured to display the chat normally. * Tells if the client is configured to display the chat normally.
@ -326,7 +326,7 @@ public interface IOnlinePlayer extends IOffPlayer {
* @implSpec if the value is unknown, it is assumed that the chat is * @implSpec if the value is unknown, it is assumed that the chat is
* fully visible. * fully visible.
*/ */
public boolean isChatFullyVisible(); boolean isChatFullyVisible();
/** /**
* Tells if the client is configured to only display system messages * Tells if the client is configured to only display system messages
@ -336,7 +336,7 @@ public interface IOnlinePlayer extends IOffPlayer {
* @implSpec if the value is unknown, it is assumed that the chat is * @implSpec if the value is unknown, it is assumed that the chat is
* fully visible. * fully visible.
*/ */
public boolean isChatOnlyDisplayingSystemMessages(); boolean isChatOnlyDisplayingSystemMessages();
@ -345,44 +345,44 @@ public interface IOnlinePlayer extends IOffPlayer {
* @implSpec if the value is unknown, it is assumed that the main hand * @implSpec if the value is unknown, it is assumed that the main hand
* is on the right. * is on the right.
*/ */
public boolean isLeftHanded(); boolean isLeftHanded();
/** /**
* Tells if the client has configured the main hand on the right. * Tells if the client has configured the main hand on the right.
* @implSpec if the value is unknown, it is assumed that the main hand * @implSpec if the value is unknown, it is assumed that the main hand
* is on the right. * is on the right.
*/ */
public boolean isRightHanded(); boolean isRightHanded();
/** /**
* Tells if the client has enabled the filtering of texts on sign and book titles. * Tells if the client has enabled the filtering of texts on sign and book titles.
* Always false as of MC 1.18. * Always false as of MC 1.18.
*/ */
public boolean isTextFilteringEnabled(); boolean isTextFilteringEnabled();
/** /**
* Tells if the client allows the server to list their player name in the * Tells if the client allows the server to list their player name in the
* multiplayer menu. * multiplayer menu.
*/ */
public boolean allowsServerListing(); boolean allowsServerListing();
public boolean hasSkinCapeEnabled(); boolean hasSkinCapeEnabled();
public boolean hasSkinJacketEnabled(); boolean hasSkinJacketEnabled();
public boolean hasSkinLeftSleeveEnabled(); boolean hasSkinLeftSleeveEnabled();
public boolean hasSkinRightSleeveEnabled(); boolean hasSkinRightSleeveEnabled();
public boolean hasSkinLeftPantsEnabled(); boolean hasSkinLeftPantsEnabled();
public boolean hasSkinRightPantsEnabled(); boolean hasSkinRightPantsEnabled();
public boolean hasSkinHatsEnabled(); boolean hasSkinHatsEnabled();
} }
@ -393,9 +393,8 @@ public interface IOnlinePlayer extends IOffPlayer {
* Chat messages represent public communication between players. By default, * Chat messages represent public communication between players. By default,
* it only include actual chat message. This method may be used in commands * it only include actual chat message. This method may be used in commands
* like /me, /afk or the login/logout broadcasted messages * like /me, /afk or the login/logout broadcasted messages
* @return
*/ */
public default boolean canChat() { default boolean canChat() {
return getClientOptions().isChatFullyVisible(); return getClientOptions().isChatFullyVisible();
} }

View File

@ -19,6 +19,7 @@ import fr.pandacube.lib.core.db.DB;
import fr.pandacube.lib.core.db.DBInitTableException; import fr.pandacube.lib.core.db.DBInitTableException;
import fr.pandacube.lib.core.util.Log; import fr.pandacube.lib.core.util.Log;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentLike;
import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.BaseComponent;
public abstract class IPlayerManager<OP extends IOnlinePlayer, OF extends IOffPlayer> { public abstract class IPlayerManager<OP extends IOnlinePlayer, OF extends IOffPlayer> {
@ -45,11 +46,11 @@ public abstract class IPlayerManager<OP extends IOnlinePlayer, OF extends IOffPl
private Map<UUID, OP> onlinePlayers = Collections.synchronizedMap(new HashMap<>()); private final Map<UUID, OP> onlinePlayers = Collections.synchronizedMap(new HashMap<>());
private LoadingCache<UUID, OF> offlinePlayers = CacheBuilder.newBuilder() private final LoadingCache<UUID, OF> offlinePlayers = CacheBuilder.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES) .expireAfterWrite(10, TimeUnit.MINUTES)
.build(CacheLoader.from(pId -> newOffPlayerInstance(pId))); .build(CacheLoader.from(this::newOffPlayerInstance));
public IPlayerManager() throws DBInitTableException { public IPlayerManager() throws DBInitTableException {
@ -90,7 +91,7 @@ public abstract class IPlayerManager<OP extends IOnlinePlayer, OF extends IOffPl
public List<OP> getAllNotVanished() { public List<OP> getAllNotVanished() {
List<OP> players = getAll(); List<OP> players = getAll();
players.removeIf(op -> op.isVanished()); players.removeIf(IOnlinePlayer::isVanished);
return players; return players;
} }
@ -183,8 +184,8 @@ public abstract class IPlayerManager<OP extends IOnlinePlayer, OF extends IOffPl
/* /*
* Message broadcasting * Message broadcasting
*/ */
// BaseComponent/Chat/String message // ComponentLike message
// boolean prefix // boolean prefix
// boolean console = (permission == null) // boolean console = (permission == null)
// String permission = null // String permission = null
@ -205,13 +206,13 @@ public abstract class IPlayerManager<OP extends IOnlinePlayer, OF extends IOffPl
* *
* @throws IllegalArgumentException if message is null. * @throws IllegalArgumentException if message is null.
*/ */
public static void broadcast(Component message, boolean prefix, boolean console, String permission, UUID sourcePlayer) { public static void broadcast(ComponentLike message, boolean prefix, boolean console, String permission, UUID sourcePlayer) {
Objects.requireNonNull(message, "message cannot be null"); Objects.requireNonNull(message, "message cannot be null");
IOffPlayer oSourcePlayer = getInstance().getOffline(sourcePlayer); IOffPlayer oSourcePlayer = getInstance().getOffline(sourcePlayer);
if (prefix) if (prefix)
message = prefixedAndColored(message); message = prefixedAndColored(message.asComponent());
for (IOnlinePlayer op : getInstance().getAll()) { for (IOnlinePlayer op : getInstance().getAll()) {
if (permission != null && !(op.hasPermission(permission))) continue; if (permission != null && !(op.hasPermission(permission))) continue;
@ -231,14 +232,14 @@ public abstract class IPlayerManager<OP extends IOnlinePlayer, OF extends IOffPl
} }
if (console) if (console)
getInstance().sendMessageToConsole(message); getInstance().sendMessageToConsole(message.asComponent());
} }
/** /**
* Broadcast a message to some or all players, and eventually to the console. * Broadcast a message to some or all players, and eventually to the console.
* <p> * <p>
* This method assumes this message is not caused by a specific player. To specify the source player, use * This method assumes this message is not caused by a specific player. To specify the source player, use
* {@link #broadcast(BaseComponent, boolean, boolean, String, UUID)}. * {@link #broadcast(ComponentLike, boolean, boolean, String, UUID)}.
* *
* @param message the message to send. * @param message the message to send.
* @param prefix if the server prefix will be prepended to the message. * @param prefix if the server prefix will be prepended to the message.
@ -246,7 +247,7 @@ public abstract class IPlayerManager<OP extends IOnlinePlayer, OF extends IOffPl
* @param permission if not null, the message is only sent to player with this permission. * @param permission if not null, the message is only sent to player with this permission.
* @throws IllegalArgumentException if message is null. * @throws IllegalArgumentException if message is null.
*/ */
public static void broadcast(Component message, boolean prefix, boolean console, String permission) { public static void broadcast(ComponentLike message, boolean prefix, boolean console, String permission) {
broadcast(message, prefix, console, permission, null); broadcast(message, prefix, console, permission, null);
} }
@ -254,7 +255,7 @@ public abstract class IPlayerManager<OP extends IOnlinePlayer, OF extends IOffPl
* Broadcast a message to all players, and eventually to the console. * Broadcast a message to all players, and eventually to the console.
* <p> * <p>
* This method does not restrict the reception of the message to a specific permission. If you * This method does not restrict the reception of the message to a specific permission. If you
* want to specify a permission, use {@link #broadcast(BaseComponent, boolean, boolean, String, UUID)}. * want to specify a permission, use {@link #broadcast(ComponentLike, boolean, boolean, String, UUID)}.
* *
* @param message the message to send. * @param message the message to send.
* @param prefix if the server prefix will be prepended to the message. * @param prefix if the server prefix will be prepended to the message.
@ -265,7 +266,7 @@ public abstract class IPlayerManager<OP extends IOnlinePlayer, OF extends IOffPl
* to players ignoring the provided player. * to players ignoring the provided player.
* @throws IllegalArgumentException if message is null. * @throws IllegalArgumentException if message is null.
*/ */
public static void broadcast(Component message, boolean prefix, boolean console, UUID sourcePlayer) { public static void broadcast(ComponentLike message, boolean prefix, boolean console, UUID sourcePlayer) {
broadcast(message, prefix, console, null, sourcePlayer); broadcast(message, prefix, console, null, sourcePlayer);
} }
@ -273,36 +274,17 @@ public abstract class IPlayerManager<OP extends IOnlinePlayer, OF extends IOffPl
* Broadcast a message to all players, and eventually to the console. * Broadcast a message to all players, and eventually to the console.
* <p> * <p>
* This method does not restrict the reception of the message to a specific permission. If you * This method does not restrict the reception of the message to a specific permission. If you
* want to specify a permission, use {@link #broadcast(BaseComponent, boolean, boolean, String)}. * want to specify a permission, use {@link #broadcast(ComponentLike, boolean, boolean, String)}.
* <p> * <p>
* This method assumes this message is not caused by a specific player. To specify the source player, use * This method assumes this message is not caused by a specific player. To specify the source player, use
* {@link #broadcast(BaseComponent, boolean, boolean, UUID)}. * {@link #broadcast(ComponentLike, boolean, boolean, UUID)}.
* *
* @param message the message to send. * @param message the message to send.
* @param prefix if the server prefix will be prepended to the message. * @param prefix if the server prefix will be prepended to the message.
* @param console if the message must be displayed in the console. * @param console if the message must be displayed in the console.
* @throws IllegalArgumentException if message is null. * @throws IllegalArgumentException if message is null.
*/ */
@Deprecated public static void broadcast(ComponentLike message, boolean prefix, boolean console) {
public static void broadcast(BaseComponent message, boolean prefix, boolean console) {
broadcast(Chat.toAdventure(message), prefix, console, null, null);
}
/**
* Broadcast a message to all players, and eventually to the console.
* <p>
* This method does not restrict the reception of the message to a specific permission. If you
* want to specify a permission, use {@link #broadcast(BaseComponent, boolean, boolean, String)}.
* <p>
* This method assumes this message is not caused by a specific player. To specify the source player, use
* {@link #broadcast(BaseComponent, boolean, boolean, UUID)}.
*
* @param message the message to send.
* @param prefix if the server prefix will be prepended to the message.
* @param console if the message must be displayed in the console.
* @throws IllegalArgumentException if message is null.
*/
public static void broadcast(Component message, boolean prefix, boolean console) {
broadcast(message, prefix, console, null, null); broadcast(message, prefix, console, null, null);
} }
@ -310,11 +292,11 @@ public abstract class IPlayerManager<OP extends IOnlinePlayer, OF extends IOffPl
* Broadcast a message to some or all players, and eventually to the console. * Broadcast a message to some or all players, and eventually to the console.
* <p> * <p>
* This method assumes this message is not caused by a specific player. To specify the source player, use * This method assumes this message is not caused by a specific player. To specify the source player, use
* {@link #broadcast(BaseComponent, boolean, String, UUID)}. * {@link #broadcast(ComponentLike, boolean, String, UUID)}.
* <p> * <p>
* This method decides to send the message to the console depending on whether {@code permission} * This method decides to send the message to the console depending on whether {@code permission}
* is null (will send to console) or not (will not send to console). To specify this behaviour, use * is null (will send to console) or not (will not send to console). To specify this behaviour, use
* {@link #broadcast(BaseComponent, boolean, boolean, String)}. * {@link #broadcast(ComponentLike, boolean, boolean, String)}.
* *
* @param message the message to send. * @param message the message to send.
* @param prefix if the server prefix will be prepended to the message. * @param prefix if the server prefix will be prepended to the message.
@ -322,7 +304,7 @@ public abstract class IPlayerManager<OP extends IOnlinePlayer, OF extends IOffPl
* If null, the message will be sent to all players and to console. * If null, the message will be sent to all players and to console.
* @throws IllegalArgumentException if message is null. * @throws IllegalArgumentException if message is null.
*/ */
public static void broadcast(Component message, boolean prefix, String permission) { public static void broadcast(ComponentLike message, boolean prefix, String permission) {
broadcast(message, prefix, (permission == null), permission, null); broadcast(message, prefix, (permission == null), permission, null);
} }
@ -330,10 +312,10 @@ public abstract class IPlayerManager<OP extends IOnlinePlayer, OF extends IOffPl
* Broadcast a message to all players, and to the console. * Broadcast a message to all players, and to the console.
* <p> * <p>
* This method does not restrict the reception of the message to a specific permission. If you * This method does not restrict the reception of the message to a specific permission. If you
* want to specify a permission, use {@link #broadcast(BaseComponent, boolean, String, UUID)}. * want to specify a permission, use {@link #broadcast(ComponentLike, boolean, String, UUID)}.
* <p> * <p>
* This method sends the message to the console. To change this behaviour, use * This method sends the message to the console. To change this behaviour, use
* {@link #broadcast(BaseComponent, boolean, boolean, UUID)}. * {@link #broadcast(ComponentLike, boolean, boolean, UUID)}.
* *
* @param message the message to send. * @param message the message to send.
* @param prefix if the server prefix will be prepended to the message. * @param prefix if the server prefix will be prepended to the message.
@ -343,162 +325,46 @@ public abstract class IPlayerManager<OP extends IOnlinePlayer, OF extends IOffPl
* to players ignoring the provided player. * to players ignoring the provided player.
* @throws IllegalArgumentException if message is null. * @throws IllegalArgumentException if message is null.
*/ */
public static void broadcast(Component message, boolean prefix, UUID sourcePlayer) { public static void broadcast(ComponentLike message, boolean prefix, UUID sourcePlayer) {
broadcast(message, prefix, true, null, sourcePlayer); broadcast(message, prefix, true, null, sourcePlayer);
} }
/** /**
* Broadcast a message to all players, and to the console. * Broadcast a message to all players, and to the console.
* <p> * <p>
* This method assumes this message is not caused by a specific player. To specify the source player, use
* {@link #broadcast(BaseComponent, boolean, UUID)}.
* <p>
* This method does not restrict the reception of the message to a specific permission. If you
* want to specify a permission, use {@link #broadcast(BaseComponent, boolean, String)}.
* <p>
* This method sends the message to the console. To change this behaviour, use * This method sends the message to the console. To change this behaviour, use
* {@link #broadcast(BaseComponent, boolean, boolean)}. * {@link #broadcast(ComponentLike, boolean, boolean, String, UUID)}.
*
* @param message the message to send.
* @param prefix if the server prefix will be prepended to the message.
* @throws IllegalArgumentException if message is null.
*/
public static void broadcast(Component message, boolean prefix) {
broadcast(message, prefix, true, null, null);
}
/**
* Broadcast a message to some or all players, and eventually to the console.
*
* @param message the message to send.
* @param prefix if the server prefix will be prepended to the message.
* @param console if the message must be displayed in the console.
* @param permission if not null, the message is only sent to player with this permission.
* @param sourcePlayer specifiy the eventual player that is the source of the message.
* If null, the message will be sent as a SYSTEM chat message.
* If not null, the message will be sent as a CHAT message, and will not be sent
* to players ignoring the provided player.
* @throws IllegalArgumentException if message is null.
*/
public static void broadcast(Chat message, boolean prefix, boolean console, String permission, UUID sourcePlayer) {
Objects.requireNonNull(message, "message cannot be null");
broadcast(message.getAdv(), prefix, console, permission, sourcePlayer);
}
/**
* Broadcast a message to some or all players, and eventually to the console.
* <p>
* This method assumes this message is not caused by a specific player. To specify the source player, use
* {@link #broadcast(BaseComponent, boolean, boolean, String, UUID)}.
*
* @param message the message to send.
* @param prefix if the server prefix will be prepended to the message.
* @param console if the message must be displayed in the console.
* @param permission if not null, the message is only sent to player with this permission.
* @throws IllegalArgumentException if message is null.
*/
public static void broadcast(Chat message, boolean prefix, boolean console, String permission) {
broadcast(message, prefix, console, permission, null);
}
/**
* Broadcast a message to all players, and eventually to the console.
* <p>
* This method does not restrict the reception of the message to a specific permission. If you
* want to specify a permission, use {@link #broadcast(BaseComponent, boolean, boolean, String, UUID)}.
*
* @param message the message to send.
* @param prefix if the server prefix will be prepended to the message.
* @param console if the message must be displayed in the console.
* @param sourcePlayer specifiy the eventual player that is the source of the message.
* If null, the message will be sent as a SYSTEM chat message.
* If not null, the message will be sent as a CHAT message, and will not be sent
* to players ignoring the provided player.
* @throws IllegalArgumentException if message is null.
*/
public static void broadcast(Chat message, boolean prefix, boolean console, UUID sourcePlayer) {
broadcast(message, prefix, console, null, sourcePlayer);
}
/**
* Broadcast a message to all players, and eventually to the console.
* <p>
* This method does not restrict the reception of the message to a specific permission. If you
* want to specify a permission, use {@link #broadcast(BaseComponent, boolean, boolean, String)}.
* <p>
* This method assumes this message is not caused by a specific player. To specify the source player, use
* {@link #broadcast(BaseComponent, boolean, boolean, UUID)}.
*
* @param message the message to send.
* @param prefix if the server prefix will be prepended to the message.
* @param console if the message must be displayed in the console.
* @throws IllegalArgumentException if message is null.
*/
public static void broadcast(Chat message, boolean prefix, boolean console) {
broadcast(message, prefix, console, null, null);
}
/**
* Broadcast a message to some or all players, and eventually to the console.
* <p>
* This method assumes this message is not caused by a specific player. To specify the source player, use
* {@link #broadcast(BaseComponent, boolean, String, UUID)}.
* <p>
* This method decides to send the message to the console depending on whether {@code permission}
* is null (will send to console) or not (will not send to console). To specify this behaviour, use
* {@link #broadcast(BaseComponent, boolean, boolean, String)}.
* *
* @param message the message to send. * @param message the message to send.
* @param prefix if the server prefix will be prepended to the message. * @param prefix if the server prefix will be prepended to the message.
* @param permission if not null, the message is only sent to player with this permission (but not to console). * @param permission if not null, the message is only sent to player with this permission (but not to console).
* If null, the message will be sent to all players and to console. * If null, the message will be sent to all players and to console.
* @throws IllegalArgumentException if message is null.
*/
public static void broadcast(Chat message, boolean prefix, String permission) {
broadcast(message, prefix, (permission == null), permission, null);
}
/**
* Broadcast a message to all players, and to the console.
* <p>
* This method does not restrict the reception of the message to a specific permission. If you
* want to specify a permission, use {@link #broadcast(BaseComponent, boolean, String, UUID)}.
* <p>
* This method sends the message to the console. To change this behaviour, use
* {@link #broadcast(BaseComponent, boolean, boolean, UUID)}.
*
* @param message the message to send.
* @param prefix if the server prefix will be prepended to the message.
* @param sourcePlayer specifiy the eventual player that is the source of the message. * @param sourcePlayer specifiy the eventual player that is the source of the message.
* If null, the message will be sent as a SYSTEM chat message. * If null, the message will be sent as a SYSTEM chat message.
* If not null, the message will be sent as a CHAT message, and will not be sent * If not null, the message will be sent as a CHAT message, and will not be sent
* to players ignoring the provided player. * to players ignoring the provided player.
* @throws IllegalArgumentException if message is null. * @throws IllegalArgumentException if message is null.
*/ */
public static void broadcast(Chat message, boolean prefix, UUID sourcePlayer) { public static void broadcast(ComponentLike message, boolean prefix, String permission, UUID sourcePlayer) {
broadcast(message, prefix, true, null, sourcePlayer); broadcast(message, prefix, true, permission, sourcePlayer);
} }
/** /**
* Broadcast a message to all players, and to the console. * Broadcast a message to all players, and to the console.
* <p> * <p>
* This method assumes this message is not caused by a specific player. To specify the source player, use * This method assumes this message is not caused by a specific player. To specify the source player, use
* {@link #broadcast(BaseComponent, boolean, UUID)}. * {@link #broadcast(ComponentLike, boolean, UUID)}.
* <p> * <p>
* This method does not restrict the reception of the message to a specific permission. If you * This method does not restrict the reception of the message to a specific permission. If you
* want to specify a permission, use {@link #broadcast(BaseComponent, boolean, String)}. * want to specify a permission, use {@link #broadcast(ComponentLike, boolean, String)}.
* <p> * <p>
* This method sends the message to the console. To change this behaviour, use * This method sends the message to the console. To change this behaviour, use
* {@link #broadcast(BaseComponent, boolean, boolean)}. * {@link #broadcast(ComponentLike, boolean, boolean)}.
* *
* @param message the message to send. * @param message the message to send.
* @param prefix if the server prefix will be prepended to the message. * @param prefix if the server prefix will be prepended to the message.
* @throws IllegalArgumentException if message is null. * @throws IllegalArgumentException if message is null.
*/ */
public static void broadcast(Chat message, boolean prefix) { public static void broadcast(ComponentLike message, boolean prefix) {
broadcast(message, prefix, true, null, null); broadcast(message, prefix, true, null, null);
} }

View File

@ -32,13 +32,13 @@ import fr.pandacube.lib.core.util.Log;
*/ */
public class PlayerFinder { public class PlayerFinder {
private static Cache<UUID, String> playerLastKnownName = CacheBuilder.newBuilder() private static final Cache<UUID, String> playerLastKnownName = CacheBuilder.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES) .expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(1000) .maximumSize(1000)
.build(); .build();
record PlayerIdCacheKey(String pName, boolean old) { } record PlayerIdCacheKey(String pName, boolean old) { }
private static Cache<PlayerIdCacheKey, UUID> playerId = CacheBuilder.newBuilder() private static final Cache<PlayerIdCacheKey, UUID> playerId = CacheBuilder.newBuilder()
.expireAfterWrite(2, TimeUnit.MINUTES) .expireAfterWrite(2, TimeUnit.MINUTES)
.maximumSize(1000) .maximumSize(1000)
.build(); .build();
@ -142,7 +142,7 @@ public class PlayerFinder {
public static boolean isValidPlayerName(String name) { public static boolean isValidPlayerName(String name) {
if (name == null) return false; if (name == null) return false;
return name.matches("[0-9a-zA-Z_.]{2,20}"); return name.matches("[\\da-zA-Z_.]{2,20}");
} }
public static SQLPlayer getDBPlayer(UUID id) throws DBException { public static SQLPlayer getDBPlayer(UUID id) throws DBException {
@ -167,7 +167,7 @@ public class PlayerFinder {
}; };
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static final <S> SuggestionsSupplier<S> TAB_PLAYER_OFFLINE() { public static <S> SuggestionsSupplier<S> TAB_PLAYER_OFFLINE() {
return (SuggestionsSupplier<S>) TAB_PLAYER_OFFLINE; return (SuggestionsSupplier<S>) TAB_PLAYER_OFFLINE;
} }
@ -188,12 +188,12 @@ public class PlayerFinder {
public static int OLD_NICK_MULTIPLIER = 2; public static int OLD_NICK_MULTIPLIER = 2;
private static List<List<Character>> CONFUSABLE_CHARACTERS = ImmutableList.of( private static final List<List<Character>> CONFUSABLE_CHARACTERS = ImmutableList.of(
ImmutableList.of('o', '0'), ImmutableList.of('o', '0'),
ImmutableList.of('i', '1', 'l'), ImmutableList.of('i', '1', 'l'),
ImmutableList.of('b', '8') ImmutableList.of('b', '8')
); );
private static ToIntBiFunction<Character, Character> CHAR_DISTANCE = (c1, c2) -> { private static final ToIntBiFunction<Character, Character> CHAR_DISTANCE = (c1, c2) -> {
if (c1.equals(c2)) if (c1.equals(c2))
return 0; return 0;
for (List<Character> charTab : CONFUSABLE_CHARACTERS) { for (List<Character> charTab : CONFUSABLE_CHARACTERS) {
@ -205,7 +205,7 @@ public class PlayerFinder {
record NamesCacheResult(String name, String lowercaseName, UUID id) { } // Java 16 record NamesCacheResult(String name, String lowercaseName, UUID id) { } // Java 16
private static LoadingCache<String, List<NamesCacheResult>> namesCache = CacheBuilder.newBuilder() private static final LoadingCache<String, List<NamesCacheResult>> namesCache = CacheBuilder.newBuilder()
.expireAfterWrite(2, TimeUnit.MINUTES) .expireAfterWrite(2, TimeUnit.MINUTES)
.maximumSize(1) .maximumSize(1)
.build(CacheLoader.from((String k) -> { .build(CacheLoader.from((String k) -> {
@ -221,7 +221,7 @@ public class PlayerFinder {
return cached; return cached;
})); }));
private static LoadingCache<String, SearchResponse> searchCache = CacheBuilder.newBuilder() private static final LoadingCache<String, SearchResponse> searchCache = CacheBuilder.newBuilder()
.expireAfterWrite(2, TimeUnit.MINUTES) .expireAfterWrite(2, TimeUnit.MINUTES)
.maximumSize(100) .maximumSize(100)
.build(CacheLoader.from((String query) -> { .build(CacheLoader.from((String query) -> {

View File

@ -46,7 +46,6 @@ public class SQLPlayerIgnore extends SQLElement<SQLPlayerIgnore> {
} }
if (el != null && !newIgnoreState) { if (el != null && !newIgnoreState) {
el.delete(); el.delete();
return;
} }
} }

View File

@ -1,5 +1,9 @@
package fr.pandacube.lib.core.search; package fr.pandacube.lib.core.search;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import fr.pandacube.lib.core.util.Log;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@ -7,15 +11,9 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import fr.pandacube.lib.core.util.Log;
/** /**
* Utility class to manage searching among a set of * Utility class to manage searching among a set of
* SearchResult instances, using case insensitive * SearchResult instances, using case insensitive
@ -23,15 +21,15 @@ import fr.pandacube.lib.core.util.Log;
*/ */
public class SearchEngine<R extends SearchResult> { public class SearchEngine<R extends SearchResult> {
Map<String, Set<R>> searchKeywordsResultMap = new HashMap<>(); private final Map<String, Set<R>> searchKeywordsResultMap = new HashMap<>();
Map<R, Set<String>> resultsSearchKeywordsMap = new HashMap<>(); private final Map<R, Set<String>> resultsSearchKeywordsMap = new HashMap<>();
Map<String, Set<R>> suggestionsKeywordsResultMap = new HashMap<>(); private final Map<String, Set<R>> suggestionsKeywordsResultMap = new HashMap<>();
Map<R, Set<String>> resultsSuggestionsKeywordsMap = new HashMap<>(); private final Map<R, Set<String>> resultsSuggestionsKeywordsMap = new HashMap<>();
private final Set<R> resultSet = new HashSet<>();
Set<R> resultSet = new HashSet<>(); private final Cache<Set<String>, List<String>> suggestionsCache;
private Cache<Set<String>, List<String>> suggestionsCache;
public SearchEngine(int suggestionsCacheSize) { public SearchEngine(int suggestionsCacheSize) {
suggestionsCache = CacheBuilder.newBuilder() suggestionsCache = CacheBuilder.newBuilder()
@ -50,7 +48,7 @@ public class SearchEngine<R extends SearchResult> {
searchKw = result.getSearchKeywords(); searchKw = result.getSearchKeywords();
Objects.requireNonNull(searchKw, "SearchResult instance must provide a non null set of search keywords"); Objects.requireNonNull(searchKw, "SearchResult instance must provide a non null set of search keywords");
searchKw = searchKw.stream() searchKw = searchKw.stream()
.filter(e -> e != null) .filter(Objects::nonNull)
.map(String::toLowerCase) .map(String::toLowerCase)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
} catch (Exception e) { } catch (Exception e) {
@ -63,7 +61,7 @@ public class SearchEngine<R extends SearchResult> {
suggestsKw = result.getSuggestionKeywords(); suggestsKw = result.getSuggestionKeywords();
Objects.requireNonNull(suggestsKw, "SearchResult instance must provide a non null set of suggestions keywords"); Objects.requireNonNull(suggestsKw, "SearchResult instance must provide a non null set of suggestions keywords");
suggestsKw = new HashSet<>(suggestsKw); suggestsKw = new HashSet<>(suggestsKw);
suggestsKw.removeIf(e -> e == null); suggestsKw.removeIf(Objects::isNull);
} catch (Exception e) { } catch (Exception e) {
Log.severe(e); Log.severe(e);
return; return;
@ -123,7 +121,7 @@ public class SearchEngine<R extends SearchResult> {
public synchronized Set<R> search(Set<String> searchTerms) { public synchronized Set<R> search(Set<String> searchTerms) {
if (searchTerms == null) if (searchTerms == null)
searchTerms = new HashSet<String>(); searchTerms = new HashSet<>();
Set<R> retainedResults = new HashSet<>(resultSet); Set<R> retainedResults = new HashSet<>(resultSet);
for (String term : searchTerms) { for (String term : searchTerms) {
@ -157,7 +155,7 @@ public class SearchEngine<R extends SearchResult> {
.collect(Collectors.toSet()); .collect(Collectors.toSet());
try { try {
return suggestionsCache.get(lowerCaseSearchTerm, (Callable<List<String>>) () -> { return suggestionsCache.get(lowerCaseSearchTerm, () -> {
Set<R> prevResults = search(lowerCaseSearchTerm); Set<R> prevResults = search(lowerCaseSearchTerm);
Set<String> suggestions = new HashSet<>(); Set<String> suggestions = new HashSet<>();

View File

@ -4,8 +4,8 @@ import java.util.Set;
public interface SearchResult { public interface SearchResult {
public Set<String> getSearchKeywords(); Set<String> getSearchKeywords();
public Set<String> getSuggestionKeywords(); Set<String> getSuggestionKeywords();
} }

View File

@ -19,7 +19,7 @@ public class AmountPerTimeLimiter {
private class Entry { private static class Entry {
private final long time; private final long time;
private double amount; private double amount;
public Entry(long t, double a) { public Entry(long t, double a) {

View File

@ -11,8 +11,8 @@ import java.util.function.Supplier;
public class BiMap<K, V> implements Iterable<Entry<K, V>> { public class BiMap<K, V> implements Iterable<Entry<K, V>> {
protected Map<K, V> map; protected final Map<K, V> map;
protected Map<V, K> inversedMap; protected final Map<V, K> inversedMap;
private BiMap<V, K> reversedView = null; private BiMap<V, K> reversedView = null;

View File

@ -299,7 +299,7 @@ public class CronExpression {
this.hourField = new SimpleField(CronFieldType.HOUR, parts[ix++]); this.hourField = new SimpleField(CronFieldType.HOUR, parts[ix++]);
this.dayOfMonthField = new DayOfMonthField(parts[ix++]); this.dayOfMonthField = new DayOfMonthField(parts[ix++]);
this.monthField = new SimpleField(CronFieldType.MONTH, parts[ix++]); this.monthField = new SimpleField(CronFieldType.MONTH, parts[ix++]);
this.dayOfWeekField = new DayOfWeekField(parts[ix++]); this.dayOfWeekField = new DayOfWeekField(parts[ix]);
} }
public static CronExpression create(final String expr) { public static CronExpression create(final String expr) {
@ -336,7 +336,7 @@ public class CronExpression {
if (!monthField.nextMatch(nextDateTime)) { if (!monthField.nextMatch(nextDateTime)) {
continue; continue;
} }
if (!findDay(nextDateTime, dateTimeBarrier)) { if (!findDay(nextDateTime)) {
continue; continue;
} }
if (!hourField.nextMatch(nextDateTime)) { if (!hourField.nextMatch(nextDateTime)) {
@ -361,11 +361,10 @@ public class CronExpression {
* to handle them together in the same method. * to handle them together in the same method.
* *
* @param dateTime Initial {@link ZonedDateTime} instance to start from * @param dateTime Initial {@link ZonedDateTime} instance to start from
* @param dateTimeBarrier At which point stop searching for next execution time
* @return {@code true} if a match was found for this field or {@code false} if the field overflowed * @return {@code true} if a match was found for this field or {@code false} if the field overflowed
* @see {@link SimpleField#nextMatch(ZonedDateTime[])} * @see SimpleField#nextMatch(ZonedDateTime[])
*/ */
private boolean findDay(ZonedDateTime[] dateTime, ZonedDateTime dateTimeBarrier) { private boolean findDay(ZonedDateTime[] dateTime) {
int month = dateTime[0].getMonthValue(); int month = dateTime[0].getMonthValue();
while (!(dayOfMonthField.matches(dateTime[0].toLocalDate()) while (!(dayOfMonthField.matches(dateTime[0].toLocalDate())
@ -400,16 +399,19 @@ public class CronExpression {
} }
abstract static class BasicField { abstract static class BasicField {
@SuppressWarnings({"RegExpRepeatedSpace", "RegExpSimplifiable", "RegExpSingleCharAlternation", "RegExpRedundantEscape"})
private static final Pattern CRON_FIELD_REGEXP = Pattern private static final Pattern CRON_FIELD_REGEXP = Pattern
.compile("(?: # start of group 1\n" .compile("""
+ " (?:(?<all>\\*)|(?<ignore>\\?)|(?<last>L)) # global flag (L, ?, *)\n" (?: # start of group 1
+ " | (?<start>[0-9]{1,2}|[a-z]{3,3}) # or start number or symbol\n" (?:(?<all>\\*)|(?<ignore>\\?)|(?<last>L)) # global flag (L, ?, *)
+ " (?: # start of group 2\n" | (?<start>[0-9]{1,2}|[a-z]{3,3}) # or start number or symbol
+ " (?<mod>L|W) # modifier (L,W)\n" (?: # start of group 2
+ " | -(?<end>[0-9]{1,2}|[a-z]{3,3}) # or end nummer or symbol (in range)\n" (?<mod>L|W) # modifier (L,W)
+ " )? # end of group 2\n" | -(?<end>[0-9]{1,2}|[a-z]{3,3}) # or end nummer or symbol (in range)
+ ") # end of group 1\n" )? # end of group 2
+ "(?:(?<incmod>/|\\#)(?<inc>[0-9]{1,7}))? # increment and increment modifier (/ or \\#)\n", ) # end of group 1
(?:(?<incmod>/|\\#)(?<inc>[0-9]{1,7}))? # increment and increment modifier (/ or \\#)
""",
Pattern.CASE_INSENSITIVE | Pattern.COMMENTS); Pattern.CASE_INSENSITIVE | Pattern.COMMENTS);
final CronFieldType fieldType; final CronFieldType fieldType;
@ -500,10 +502,7 @@ public class CronExpression {
} }
protected boolean matches(int val, FieldPart part) { protected boolean matches(int val, FieldPart part) {
if (val >= part.from && val <= part.to && (val - part.from) % part.increment == 0) { return val >= part.from && val <= part.to && (val - part.from) % part.increment == 0;
return true;
}
return false;
} }
protected int nextMatch(int val, FieldPart part) { protected int nextMatch(int val, FieldPart part) {
@ -529,17 +528,6 @@ public class CronExpression {
super(fieldType, fieldExpr); super(fieldType, fieldExpr);
} }
public boolean matches(int val) {
if (val >= fieldType.from && val <= fieldType.to) {
for (FieldPart part : parts) {
if (matches(val, part)) {
return true;
}
}
}
return false;
}
/** /**
* Find the next match for this field. If a match cannot be found force an overflow and increase the next * Find the next match for this field. If a match cannot be found force an overflow and increase the next
* greatest field. * greatest field.
@ -602,9 +590,9 @@ public class CronExpression {
@Override @Override
protected void validatePart(FieldPart part) { protected void validatePart(FieldPart part) {
if (part.modifier != null && Arrays.asList("L", "?").indexOf(part.modifier) == -1) { if (part.modifier != null && !Arrays.asList("L", "?").contains(part.modifier)) {
throw new IllegalArgumentException(String.format("Invalid modifier [%s]", part.modifier)); throw new IllegalArgumentException(String.format("Invalid modifier [%s]", part.modifier));
} else if (part.incrementModifier != null && Arrays.asList("/", "#").indexOf(part.incrementModifier) == -1) { } else if (part.incrementModifier != null && !Arrays.asList("/", "#").contains(part.incrementModifier)) {
throw new IllegalArgumentException(String.format("Invalid increment modifier [%s]", part.incrementModifier)); throw new IllegalArgumentException(String.format("Invalid increment modifier [%s]", part.incrementModifier));
} }
} }
@ -639,7 +627,7 @@ public class CronExpression {
@Override @Override
protected void validatePart(FieldPart part) { protected void validatePart(FieldPart part) {
if (part.modifier != null && Arrays.asList("L", "W", "?").indexOf(part.modifier) == -1) { if (part.modifier != null && !Arrays.asList("L", "W", "?").contains(part.modifier)) {
throw new IllegalArgumentException(String.format("Invalid modifier [%s]", part.modifier)); throw new IllegalArgumentException(String.format("Invalid modifier [%s]", part.modifier));
} else if (part.incrementModifier != null && !"/".equals(part.incrementModifier)) { } else if (part.incrementModifier != null && !"/".equals(part.incrementModifier)) {
throw new IllegalArgumentException(String.format("Invalid increment modifier [%s]", part.incrementModifier)); throw new IllegalArgumentException(String.format("Invalid increment modifier [%s]", part.incrementModifier));

View File

@ -19,8 +19,8 @@ public class DistanceUtil {
String precisionFormat = "##0"; String precisionFormat = "##0";
if (precision > 0) precisionFormat += "."; if (precision > 0) precisionFormat += ".";
for (int i = 0; i < precision; i++) precisionFormat += "0".repeat(precision);
precisionFormat += "0";
DecimalFormat df = new DecimalFormat(precisionFormat); DecimalFormat df = new DecimalFormat(precisionFormat);
double dist = meterDist / choosenUnit.multiplicator; double dist = meterDist / choosenUnit.multiplicator;
@ -33,12 +33,17 @@ public class DistanceUtil {
} }
public enum DistanceUnit { public enum DistanceUnit {
NM(0.000000001, "nm"), µM(0.000001, "µm"), MM(0.001, "mm"), CM(0.01, "cm"), M(1, "m"), KM(1000, "km"); NM(0.000000001, "nm"),
UM(0.000001, "µm"),
MM(0.001, "mm"),
CM(0.01, "cm"),
M(1, "m"),
KM(1000, "km");
private final double multiplicator; private final double multiplicator;
private final String unitStr; private final String unitStr;
private DistanceUnit(double mult, String s) { DistanceUnit(double mult, String s) {
multiplicator = mult; multiplicator = mult;
unitStr = s; unitStr = s;
} }

View File

@ -1,5 +1,8 @@
package fr.pandacube.lib.core.util; package fr.pandacube.lib.core.util;
import java.util.Arrays;
import java.util.stream.Collectors;
public class EnumUtil { public class EnumUtil {
/** /**
@ -10,17 +13,9 @@ public class EnumUtil {
* @return a string representation of the enum class. * @return a string representation of the enum class.
*/ */
public static <T extends Enum<T>> String enumList(Class<T> enumType, String separator) { public static <T extends Enum<T>> String enumList(Class<T> enumType, String separator) {
T[] elements = enumType.getEnumConstants(); return Arrays.stream(enumType.getEnumConstants())
.map(Enum::name)
String out = ""; .collect(Collectors.joining(separator));
boolean first = true;
for (T el : elements) {
if (!first) out += separator;
first = false;
out += el.name();
}
return out;
} }
/** /**

View File

@ -3,6 +3,7 @@ package fr.pandacube.lib.core.util;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.attribute.BasicFileAttributes;
public class FileUtils { public class FileUtils {
@ -20,12 +21,17 @@ public class FileUtils {
if (target.exists() && !target.isDirectory()) { if (target.exists() && !target.isDirectory()) {
throw new IllegalStateException("target file already exists: " + target); throw new IllegalStateException("target file already exists: " + target);
} }
if (source.isDirectory()) { BasicFileAttributes sourceAttr = Files.readAttributes(source.toPath(), BasicFileAttributes.class);
target.mkdir(); if (sourceAttr.isDirectory()) {
for (String child : source.list()) if (target.mkdir()) {
copy(new File(source, child), new File(target, child)); for (String child : source.list())
copy(new File(source, child), new File(target, child));
}
else {
throw new IOException("Cannot create directory " + target);
}
} }
else if (source.isFile()) { else if (sourceAttr.isRegularFile()) {
Files.copy(source.toPath(), target.toPath()); Files.copy(source.toPath(), target.toPath());
} }
} }

View File

@ -103,13 +103,7 @@ public class GifDecoder {
protected ArrayList<GifFrame> frames; // frames read from current file protected ArrayList<GifFrame> frames; // frames read from current file
protected int frameCount; protected int frameCount;
static class GifFrame { record GifFrame(BufferedImage image, int delay) {
public GifFrame(BufferedImage im, int del) {
image = im;
delay = del;
}
public BufferedImage image;
public int delay;
} }
/** /**
@ -184,12 +178,7 @@ public class GifDecoder {
if (lastDispose == 2) { if (lastDispose == 2) {
// fill last image rect area with background color // fill last image rect area with background color
Graphics2D g = image.createGraphics(); Graphics2D g = image.createGraphics();
Color c = null; Color c = transparency ? new Color(0, 0, 0, 0) : new Color(lastBgColor);
if (transparency) {
c = new Color(0, 0, 0, 0); // assume background is transparent
} else {
c = new Color(lastBgColor); // use given background color
}
g.setColor(c); g.setColor(c);
g.setComposite(AlphaComposite.Src); // replace area g.setComposite(AlphaComposite.Src); // replace area
g.fill(lastRect); g.fill(lastRect);
@ -270,7 +259,7 @@ public class GifDecoder {
/** /**
* Reads GIF image from stream * Reads GIF image from stream
* *
* @param BufferedInputStream containing GIF file. * @param is containing GIF file.
* @return read status code (0 = no errors) * @return read status code (0 = no errors)
*/ */
public int read(BufferedInputStream is) { public int read(BufferedInputStream is) {
@ -286,7 +275,7 @@ public class GifDecoder {
} }
try { try {
is.close(); is.close();
} catch (IOException e) { } catch (IOException ignored) {
} }
} else { } else {
status = STATUS_OPEN_ERROR; status = STATUS_OPEN_ERROR;
@ -297,7 +286,7 @@ public class GifDecoder {
/** /**
* Reads GIF image from stream * Reads GIF image from stream
* *
* @param InputStream containing GIF file. * @param is containing GIF file.
* @return read status code (0 = no errors) * @return read status code (0 = no errors)
*/ */
public int read(InputStream is) { public int read(InputStream is) {
@ -315,7 +304,7 @@ public class GifDecoder {
} }
try { try {
is.close(); is.close();
} catch (IOException e) { } catch (IOException ignored) {
} }
} else { } else {
status = STATUS_OPEN_ERROR; status = STATUS_OPEN_ERROR;
@ -334,7 +323,7 @@ public class GifDecoder {
status = STATUS_OK; status = STATUS_OK;
try { try {
name = name.trim().toLowerCase(); name = name.trim().toLowerCase();
if ((name.indexOf("file:") >= 0) || if ((name.contains("file:")) ||
(name.indexOf(":/") > 0)) { (name.indexOf(":/") > 0)) {
URL url = new URL(name); URL url = new URL(name);
in = new BufferedInputStream(url.openStream()); in = new BufferedInputStream(url.openStream());
@ -524,14 +513,14 @@ public class GifDecoder {
int n = 0; int n = 0;
if (blockSize > 0) { if (blockSize > 0) {
try { try {
int count = 0; int count;
while (n < blockSize) { while (n < blockSize) {
count = in.read(block, n, blockSize - n); count = in.read(block, n, blockSize - n);
if (count == -1) if (count == -1)
break; break;
n += count; n += count;
} }
} catch (IOException e) { } catch (IOException ignored) {
} }
if (n < blockSize) { if (n < blockSize) {
@ -554,7 +543,7 @@ public class GifDecoder {
int n = 0; int n = 0;
try { try {
n = in.read(c); n = in.read(c);
} catch (IOException e) { } catch (IOException ignored) {
} }
if (n < nbytes) { if (n < nbytes) {
status = STATUS_FORMAT_ERROR; status = STATUS_FORMAT_ERROR;
@ -595,11 +584,11 @@ public class GifDecoder {
case 0xff : // application extension case 0xff : // application extension
readBlock(); readBlock();
String app = ""; StringBuilder app = new StringBuilder();
for (int i = 0; i < 11; i++) { for (int i = 0; i < 11; i++) {
app += (char) block[i]; app.append((char) block[i]);
} }
if (app.equals("NETSCAPE2.0")) { if (app.toString().equals("NETSCAPE2.0")) {
readNetscapeExt(); readNetscapeExt();
} }
else else
@ -644,11 +633,11 @@ public class GifDecoder {
* Reads GIF file header information. * Reads GIF file header information.
*/ */
protected void readHeader() { protected void readHeader() {
String id = ""; StringBuilder id = new StringBuilder();
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
id += (char) read(); id.append((char) read());
} }
if (!id.startsWith("GIF")) { if (!id.toString().startsWith("GIF")) {
status = STATUS_FORMAT_ERROR; status = STATUS_FORMAT_ERROR;
return; return;
} }
@ -769,9 +758,6 @@ public class GifDecoder {
lastRect = new Rectangle(ix, iy, iw, ih); lastRect = new Rectangle(ix, iy, iw, ih);
lastImage = image; lastImage = image;
lastBgColor = bgColor; lastBgColor = bgColor;
/*int dispose = 0;
boolean transparency = false;
int delay = 0;*/
lct = null; lct = null;
} }

View File

@ -9,7 +9,7 @@ import java.util.NoSuchElementException;
public class IteratorIterator<T> implements Iterator<T> { public class IteratorIterator<T> implements Iterator<T> {
public static <T> IteratorIterator<T> ofCollectionOfIterable(Collection<Iterable<T>> coll) { public static <T> IteratorIterator<T> ofCollectionOfIterable(Collection<Iterable<T>> coll) {
return new IteratorIterator<>(coll.stream().map(i -> i.iterator()).iterator()); return new IteratorIterator<>(coll.stream().map(Iterable::iterator).iterator());
} }
public static <T> IteratorIterator<T> ofCollectionOfIterator(Collection<Iterator<T>> coll) { public static <T> IteratorIterator<T> ofCollectionOfIterator(Collection<Iterator<T>> coll) {
@ -18,7 +18,7 @@ public class IteratorIterator<T> implements Iterator<T> {
@SafeVarargs @SafeVarargs
public static <T> IteratorIterator<T> ofArrayOfIterable(Iterable<T>... arr) { public static <T> IteratorIterator<T> ofArrayOfIterable(Iterable<T>... arr) {
return new IteratorIterator<>(Arrays.stream(arr).map(i -> i.iterator()).iterator()); return new IteratorIterator<>(Arrays.stream(arr).map(Iterable::iterator).iterator());
} }
@SafeVarargs @SafeVarargs
@ -26,7 +26,7 @@ public class IteratorIterator<T> implements Iterator<T> {
return new IteratorIterator<>(Arrays.asList(arr).iterator()); return new IteratorIterator<>(Arrays.asList(arr).iterator());
} }
private Iterator<Iterator<T>> iterators; private final Iterator<Iterator<T>> iterators;
private Iterator<T> currentIterator = null; private Iterator<T> currentIterator = null;
@ -59,5 +59,16 @@ public class IteratorIterator<T> implements Iterator<T> {
throw new NoSuchElementException("No next value found in iterator."); throw new NoSuchElementException("No next value found in iterator.");
return currentIterator.next(); return currentIterator.next();
} }
/**
* @implNote The current implementation of {@link IteratorIterator} may not support
* running this method if the current position is the last value of one of
* the underlying iterable, and if the {@link #hasNext()} method has been called before this one.
*/
@Override
public void remove() {
// TODO change code to avoid currentIterator being null because we are about to change currentIterator
if (currentIterator != null)
currentIterator.remove();
}
} }

View File

@ -53,7 +53,7 @@ pour les calculs (division par zero, etc...).
*/ */
// Classe servant <EFBFBD> palier l'absence de passage par variables ou reference // Classe servant à palier l'absence de passage par variables ou reference
class VariableInt { class VariableInt {
public int mValue; public int mValue;
@ -65,8 +65,8 @@ public class JArithmeticInterpreter {
// Variables // Variables
int mOperator; final int mOperator;
double mValue; final double mValue;
JArithmeticInterpreter fg, fd; JArithmeticInterpreter fg, fd;
// Methods // Methods
@ -75,27 +75,21 @@ public class JArithmeticInterpreter {
// Node // Node
private JArithmeticInterpreter() { private JArithmeticInterpreter() {
this(0, 0, null, null); this(0, 0);
} }
// .................................................................................... // ....................................................................................
// Node // Node
private JArithmeticInterpreter(int Operator, double Value, JArithmeticInterpreter Fg, JArithmeticInterpreter Fd) { private JArithmeticInterpreter(int Operator, double Value) {
mOperator = Operator; mOperator = Operator;
mValue = Value; mValue = Value;
fg = Fg;
fd = Fd;
}
private JArithmeticInterpreter(int Operator, double Value) {
this(Operator, Value, null, null);
} }
// .................................................................................... // ....................................................................................
// Construct_Tree // Construct_Tree
private static JArithmeticInterpreter constructTree(StringBuffer string, int length, int error) { private static JArithmeticInterpreter constructTree(StringBuffer string, int length) {
int imbric, Bimbric; int imbric, Bimbric;
int priorite, ope; int priorite, ope;
int position, positionv, i, j; int position, positionv, i, j;
@ -108,7 +102,6 @@ public class JArithmeticInterpreter {
// Initialisation des variables // Initialisation des variables
if (length <= 0) { if (length <= 0) {
error = 3;
return null; return null;
} }
@ -180,7 +173,6 @@ public class JArithmeticInterpreter {
i++; i++;
} }
else { else {
error = 2; // symbole non reconnu
return null; return null;
} }
} }
@ -202,7 +194,7 @@ public class JArithmeticInterpreter {
position = i; position = i;
caspp = 0; caspp = 0;
} }
else if ((imbric == Bimbric) && (priorite >= 1)) { else if (imbric == Bimbric) {
priorite = 1; priorite = 1;
ope = 1; ope = 1;
position = i; position = i;
@ -238,7 +230,7 @@ public class JArithmeticInterpreter {
caspp = 0; caspp = 0;
} }
} }
else if ((imbric == Bimbric) && (priorite >= 1)) if ((i - 1) < 0) { else if (imbric == Bimbric) if ((i - 1) < 0) {
if (priorite > 5) { if (priorite > 5) {
priorite = 1; priorite = 1;
position = i; position = i;
@ -308,12 +300,10 @@ public class JArithmeticInterpreter {
i++; i++;
break; break;
default: default:
error = 2; // symbole non reconnu
return null; return null;
} }
if (imbric != 0) { if (imbric != 0) {
error = 1; // erreur de "parenthesage"
return null; return null;
} }
@ -330,46 +320,42 @@ public class JArithmeticInterpreter {
node.fd = new JArithmeticInterpreter(); node.fd = new JArithmeticInterpreter();
if ((length - position - 1 - Bimbric) == 0) { // argument absent if ((length - position - 1 - Bimbric) == 0) { // argument absent
error = 3;
return null; return null;
} }
StringBuffer temp = CopyPartialString(string, (position + 1), (length - 1 - Bimbric)); StringBuffer temp = CopyPartialString(string, (position + 1), (length - 1 - Bimbric));
node.fd = constructTree(temp, (length - position - 1 - Bimbric), error); node.fd = constructTree(temp, (length - position - 1 - Bimbric));
return node; return node;
} }
else if (priorite == 5) { else if (priorite == 5) {
node = new JArithmeticInterpreter(0, calc_const(string, positionv), null, null); node = new JArithmeticInterpreter(0, calc_const(string, positionv));
return node; return node;
} }
else if (ope > 5) { else if (ope > 5) {
node = new JArithmeticInterpreter(ope, 0, null, null); node = new JArithmeticInterpreter(ope, 0);
if ((length - position - espa - Bimbric) == 0) { // argument absent if ((length - position - espa - Bimbric) == 0) { // argument absent
error = 3;
return null; return null;
} }
StringBuffer temp = CopyPartialString(string, (position + espa), (length - 1)); StringBuffer temp = CopyPartialString(string, (position + espa), (length - 1));
node.fg = constructTree(temp, (length - position - espa - Bimbric), error); node.fg = constructTree(temp, (length - position - espa - Bimbric));
return node; return node;
} }
else { else {
node = new JArithmeticInterpreter(ope, 0, null, null); node = new JArithmeticInterpreter(ope, 0);
if ((position - Bimbric) == 0) { // argument absent if ((position - Bimbric) == 0) { // argument absent
error = 3;
return null; return null;
} }
StringBuffer temp = CopyPartialString(string, Bimbric, (position - 1)); StringBuffer temp = CopyPartialString(string, Bimbric, (position - 1));
node.fg = constructTree(temp, (position - Bimbric), error); node.fg = constructTree(temp, (position - Bimbric));
if ((length - position - 1 - Bimbric) == 0) { // argument absent if ((length - position - 1 - Bimbric) == 0) { // argument absent
error = 3;
return null; return null;
} }
temp = CopyPartialString(string, (position + 1), (length - 1 - Bimbric)); temp = CopyPartialString(string, (position + 1), (length - 1 - Bimbric));
node.fd = constructTree(temp, (length - position - 1 - Bimbric), error); node.fd = constructTree(temp, (length - position - 1 - Bimbric));
return node; return node;
} }
} }
@ -378,15 +364,12 @@ public class JArithmeticInterpreter {
private double computeTree() { private double computeTree() {
if (mOperator == 0) return mValue; if (mOperator == 0) return mValue;
int error = 0;
double valueL = fg.computeTree(); double valueL = fg.computeTree();
if (error != 0) return 0;
double valueR = 0; double valueR = 0;
if (fd != null) valueR = fd.computeTree(); if (fd != null) valueR = fd.computeTree();
if (error != 0) return 0;
switch (mOperator) { switch (mOperator) {
case 1: // + case 1: // +
@ -397,7 +380,6 @@ public class JArithmeticInterpreter {
return (valueL * valueR); return (valueL * valueR);
case 4: // - case 4: // -
if (valueR == 0) { if (valueR == 0) {
error = 1;
return 0; return 0;
} }
return (valueL / valueR); return (valueL / valueR);
@ -407,23 +389,16 @@ public class JArithmeticInterpreter {
return Math.exp(valueL); return Math.exp(valueL);
case 7: // ln case 7: // ln
if (valueL <= 0) { if (valueL <= 0) {
if (valueL < 0) error = 2;
else
error = 1;
return 0; return 0;
} }
return (Math.log(valueL) / Math.log(2)); return (Math.log(valueL) / Math.log(2));
case 8: // log case 8: // log
if (valueL <= 0) { if (valueL <= 0) {
if (valueL < 0) error = 2;
else
error = 1;
return 0; return 0;
} }
return Math.log(valueL); return Math.log(valueL);
case 9: // sqrt case 9: // sqrt
if (valueL < 0) { if (valueL < 0) {
error = 2;
return 0; return 0;
} }
return Math.sqrt(valueL); return Math.sqrt(valueL);
@ -462,8 +437,7 @@ public class JArithmeticInterpreter {
fd.writeTree(string); fd.writeTree(string);
break; break;
case 2: case 2:
if ((fg.mOperator == 0) && (fg.mValue == 0)) ; if (fg.mOperator != 0 || fg.mValue != 0)
else
fg.writeTree(string); fg.writeTree(string);
string.append('-'); string.append('-');
if ((fd.mOperator == 1) || (fd.mOperator == 2)) { if ((fd.mOperator == 1) || (fd.mOperator == 2)) {
@ -471,7 +445,7 @@ public class JArithmeticInterpreter {
string.append('('); string.append('(');
} }
fd.writeTree(string); fd.writeTree(string);
if (parenthese == true) string.append(')'); if (parenthese) string.append(')');
break; break;
case 3: case 3:
if ((fg.mOperator == 1) || (fg.mOperator == 2)) { if ((fg.mOperator == 1) || (fg.mOperator == 2)) {
@ -479,7 +453,7 @@ public class JArithmeticInterpreter {
string.append('('); string.append('(');
} }
fg.writeTree(string); fg.writeTree(string);
if (parenthese == true) string.append(')'); if (parenthese) string.append(')');
parenthese = false; parenthese = false;
string.append('*'); string.append('*');
if ((fd.mOperator == 1) || (fd.mOperator == 2)) { if ((fd.mOperator == 1) || (fd.mOperator == 2)) {
@ -487,7 +461,7 @@ public class JArithmeticInterpreter {
string.append('('); string.append('(');
} }
fd.writeTree(string); fd.writeTree(string);
if (parenthese == true) string.append(')'); if (parenthese) string.append(')');
break; break;
case 4: case 4:
if ((fg.mOperator == 1) || (fg.mOperator == 2)) { if ((fg.mOperator == 1) || (fg.mOperator == 2)) {
@ -495,7 +469,7 @@ public class JArithmeticInterpreter {
string.append('('); string.append('(');
} }
fg.writeTree(string); fg.writeTree(string);
if (parenthese == true) string.append(')'); if (parenthese) string.append(')');
parenthese = false; parenthese = false;
string.append('/'); string.append('/');
if ((fd.mOperator > 0) && (fd.mOperator < 5)) { if ((fd.mOperator > 0) && (fd.mOperator < 5)) {
@ -503,7 +477,7 @@ public class JArithmeticInterpreter {
string.append('('); string.append('(');
} }
fd.writeTree(string); fd.writeTree(string);
if (parenthese == true) string.append(')'); if (parenthese) string.append(')');
break; break;
case 5: case 5:
if ((fg.mOperator > 0) && (fg.mOperator < 5)) { if ((fg.mOperator > 0) && (fg.mOperator < 5)) {
@ -511,7 +485,7 @@ public class JArithmeticInterpreter {
string.append('('); string.append('(');
} }
fg.writeTree(string); fg.writeTree(string);
if (parenthese == true) string.append(')'); if (parenthese) string.append(')');
parenthese = false; parenthese = false;
string.append('^'); string.append('^');
if ((fd.mOperator > 0) && (fd.mOperator < 5)) { if ((fd.mOperator > 0) && (fd.mOperator < 5)) {
@ -519,7 +493,7 @@ public class JArithmeticInterpreter {
string.append('('); string.append('(');
} }
fd.writeTree(string); fd.writeTree(string);
if (parenthese == true) string.append(')'); if (parenthese) string.append(')');
break; break;
case 6: case 6:
string.append("exp("); string.append("exp(");
@ -732,8 +706,8 @@ public class JArithmeticInterpreter {
JArithmeticInterpreter jai = null; JArithmeticInterpreter jai = null;
try { try {
jai = JArithmeticInterpreter.constructTree(input, input.length(), 0); jai = JArithmeticInterpreter.constructTree(input, input.length());
} catch (Exception e) {} } catch (Exception ignored) {}
if (jai == null) throw new IllegalArgumentException("Le calcul passé en paramètre est invalide"); if (jai == null) throw new IllegalArgumentException("Le calcul passé en paramètre est invalide");
@ -749,7 +723,7 @@ public class JArithmeticInterpreter {
return getResultFromExpression(expr, null); return getResultFromExpression(expr, null);
} }
public static void main(String args[]) { public static void main(String[] args) {
StringBuffer b = new StringBuffer(0); StringBuffer b = new StringBuffer(0);

View File

@ -18,9 +18,9 @@ import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
public class Json { public class Json {
public static final Gson gson = build(b -> b); public static final Gson gson = build(Function.identity());
public static final Gson gsonPrettyPrinting = build(b -> b.setPrettyPrinting()); public static final Gson gsonPrettyPrinting = build(GsonBuilder::setPrettyPrinting);
public static final Gson gsonSerializeNulls = build(b -> b.serializeNulls()); public static final Gson gsonSerializeNulls = build(GsonBuilder::serializeNulls);
public static final Gson gsonSerializeNullsPrettyPrinting = build(b -> b.serializeNulls().setPrettyPrinting()); public static final Gson gsonSerializeNullsPrettyPrinting = build(b -> b.serializeNulls().setPrettyPrinting());
@ -46,9 +46,9 @@ public class Json {
} }
private static class RecordTypeAdapter<T> extends TypeAdapter<T> { private static class RecordTypeAdapter<T> extends TypeAdapter<T> {
private Gson gson; private final Gson gson;
private TypeAdapterFactory factory; private final TypeAdapterFactory factory;
private TypeToken<T> type; private final TypeToken<T> type;
public RecordTypeAdapter(Gson gson, TypeAdapterFactory factory, TypeToken<T> type) { public RecordTypeAdapter(Gson gson, TypeAdapterFactory factory, TypeToken<T> type) {
this.gson = gson; this.gson = gson;
@ -72,8 +72,8 @@ public class Json {
RecordComponent[] recordComponents = clazz.getRecordComponents(); RecordComponent[] recordComponents = clazz.getRecordComponents();
Map<String, TypeToken<?>> typeMap = new HashMap<>(); Map<String, TypeToken<?>> typeMap = new HashMap<>();
for (int i = 0; i < recordComponents.length; i++) { for (RecordComponent recordComponent : recordComponents) {
typeMap.put(recordComponents[i].getName(), TypeToken.get(recordComponents[i].getGenericType())); typeMap.put(recordComponent.getName(), TypeToken.get(recordComponent.getGenericType()));
} }
var argsMap = new HashMap<String, Object>(); var argsMap = new HashMap<String, Object>();
reader.beginObject(); reader.beginObject();

View File

@ -2,6 +2,8 @@ package fr.pandacube.lib.core.util;
import java.util.Objects; import java.util.Objects;
import fr.pandacube.lib.core.util.ThrowableUtil.SupplierException;
/** /**
* Represents a lazy loaded value. * Represents a lazy loaded value.
* *
@ -42,11 +44,5 @@ public class LazyOrException<T> {
cachedValue = value; cachedValue = value;
cached = true; cached = true;
} }
@FunctionalInterface
public interface SupplierException<T> {
public T get() throws Exception;
}
} }

View File

@ -5,12 +5,12 @@ import java.util.function.ToIntBiFunction;
public class LevenshteinDistance { public class LevenshteinDistance {
private String initialList; private final String initialList;
private int elementAdditionScore; private final int elementAdditionScore;
private int elementDeletionScore; private final int elementDeletionScore;
private ToIntBiFunction<Character, Character> elementDistanceFunction; private final ToIntBiFunction<Character, Character> elementDistanceFunction;
private int[] prev, curr; private int[] prev, curr;

View File

@ -7,7 +7,7 @@ import java.util.logging.Logger;
public class Log { public class Log {
private static Logger logger = Logger.getGlobal(); private static Logger logger = Logger.getGlobal();
private static AtomicBoolean logDebug = new AtomicBoolean(false); private static final AtomicBoolean logDebug = new AtomicBoolean(false);
public static void setDebug(boolean newVal) { public static void setDebug(boolean newVal) {
logDebug.set(newVal); logDebug.set(newVal);

View File

@ -1,12 +1,23 @@
package fr.pandacube.lib.core.util; package fr.pandacube.lib.core.util;
import java.util.AbstractList; import java.util.AbstractList;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.ListIterator;
import java.util.function.Function; import java.util.function.Function;
/**
* A Wrapper list that provides a mapped view of the backend list.
* Every modification of this list will modify the bakend list.
* For each time a value is accessed or modified, the appropriate
* setter or getter is used to convert the value between the source {@code S}
* and the visible {@code T} type.
* @param <S> the source (backend) type
* @param <T> the visible (mapped) type
*/
public class MappedListView<S, T> extends AbstractList<T> { public class MappedListView<S, T> extends AbstractList<T> {
private final List<S> backend; protected final List<S> backend;
private final Function<S, T> getter; private final Function<S, T> getter;
private final Function<T, S> setter; private final Function<T, S> setter;
@ -28,25 +39,149 @@ public class MappedListView<S, T> extends AbstractList<T> {
@Override @Override
public int size() { return backend.size(); } public int size() {
return backend.size();
}
@Override @Override
public T get(int index) { return getter.apply(backend.get(index)); } public T get(int index) {
return getter.apply(backend.get(index));
}
@Override @Override
public T set(int index, T element) { return getter.apply(backend.set(index, setter.apply(element))); } public T set(int index, T element) {
return getter.apply(backend.set(index, setter.apply(element)));
}
@Override @Override
public void add(int index, T element) { backend.add(index, setter.apply(element)); } public boolean add(T element) {
return backend.add(setter.apply(element));
}
@Override @Override
public T remove(int index) { return getter.apply(backend.remove(index)); } public void add(int index, T element) {
backend.add(index, setter.apply(element));
}
@Override @Override
public void clear() { backend.clear(); } public T remove(int index) {
return getter.apply(backend.remove(index));
}
@Override
public void clear() {
backend.clear();
}
@Override @Override
public List<T> subList(int fromIndex, int toIndex) { public List<T> subList(int fromIndex, int toIndex) {
return new MappedListView<S, T>(backend.subList(fromIndex, toIndex), getter, setter); return new MappedListView<>(backend.subList(fromIndex, toIndex), getter, setter);
} }
@Override @Override
protected void removeRange(int fromIndex, int toIndex) { protected void removeRange(int fromIndex, int toIndex) {
backend.subList(fromIndex, toIndex).clear(); backend.subList(fromIndex, toIndex).clear();
} }
@Override
public boolean equals(Object o) {
return backend.equals(o);
}
@Override
public int hashCode() {
return backend.hashCode();
}
@SuppressWarnings("unchecked")
@Override
public int indexOf(Object o) {
return backend.indexOf(setter.apply((T) o));
}
@SuppressWarnings("unchecked")
@Override
public int lastIndexOf(Object o) {
return backend.lastIndexOf(setter.apply((T) o));
}
@Override
public Iterator<T> iterator() {
return new Iterator<>() {
final Iterator<S> wrappedIt = backend.iterator();
@Override
public boolean hasNext() {
return wrappedIt.hasNext();
}
@Override
public T next() {
return getter.apply(wrappedIt.next());
}
@Override
public void remove() {
wrappedIt.remove();
}
};
}
@Override
public ListIterator<T> listIterator() {
return listIterator(0);
}
@Override
public ListIterator<T> listIterator(int index) {
return new ListIterator<>() {
final ListIterator<S> wrappedIt = backend.listIterator(index);
@Override
public boolean hasNext() {
return wrappedIt.hasNext();
}
@Override
public T next() {
return getter.apply(wrappedIt.next());
}
@Override
public boolean hasPrevious() {
return wrappedIt.hasPrevious();
}
@Override
public T previous() {
return getter.apply(wrappedIt.previous());
}
@Override
public int nextIndex() {
return wrappedIt.nextIndex();
}
@Override
public int previousIndex() {
return wrappedIt.previousIndex();
}
@Override
public void remove() {
wrappedIt.remove();
}
@Override
public void set(T w) {
wrappedIt.set(setter.apply(w));
}
@Override
public void add(T w) {
wrappedIt.add(setter.apply(w));
}
};
}

View File

@ -30,7 +30,7 @@ public class MemoryUtil {
return unitMultiplier == null ? "o" : (unitMultiplier + (si ? "o" : "io")); return unitMultiplier == null ? "o" : (unitMultiplier + (si ? "o" : "io"));
} }
private MemoryUnit(long vTrad, long vSI, String uMult) { MemoryUnit(long vTrad, long vSI, String uMult) {
valueTrad = vTrad; valueTrad = vTrad;
valueSI = vSI; valueSI = vSI;
unitMultiplier = uMult; unitMultiplier = uMult;

View File

@ -59,7 +59,7 @@ public enum MinecraftVersion {
v1_19(759, "1.19"); v1_19(759, "1.19");
// IMPORTANT: don't forget to update the versionMergeDisplay value when adding a new version; // IMPORTANT: don't forget to update the versionMergeDisplay value when adding a new version;
private static Map<EnumSet<MinecraftVersion>, List<String>> versionMergeDisplay; private static final Map<EnumSet<MinecraftVersion>, List<String>> versionMergeDisplay;
static { static {
versionMergeDisplay = new HashMap<>(); versionMergeDisplay = new HashMap<>();
@ -157,7 +157,7 @@ public enum MinecraftVersion {
public final int id; public final int id;
public final List<String> versionDisplay; public final List<String> versionDisplay;
private MinecraftVersion(int v, String... d) { MinecraftVersion(int v, String... d) {
id = v; id = v;
versionDisplay = Arrays.asList(d); versionDisplay = Arrays.asList(d);
} }
@ -193,7 +193,7 @@ public enum MinecraftVersion {
} }
public static final List<String> getVersionsDisplayList(List<MinecraftVersion> vList) { public static List<String> getVersionsDisplayList(List<MinecraftVersion> vList) {
if (vList == null) if (vList == null)
return new ArrayList<>(); return new ArrayList<>();
Set<MinecraftVersion> vSet = EnumSet.copyOf(vList); Set<MinecraftVersion> vSet = EnumSet.copyOf(vList);

View File

@ -7,8 +7,6 @@ public class MinecraftWebUtil {
/** /**
Convert a legacy Minecraft color coded String into HTML Format. Convert a legacy Minecraft color coded String into HTML Format.
@param
*/ */
// TODO update to support RGB colors (Bungee and Essentials notation). // TODO update to support RGB colors (Bungee and Essentials notation).
// See JavaScript implementation at https://www.pandacube.fr/assets/js/global.js // See JavaScript implementation at https://www.pandacube.fr/assets/js/global.js
@ -16,7 +14,7 @@ public class MinecraftWebUtil {
{ {
String color_char = "0123456789abcdefr"; String color_char = "0123456789abcdefr";
String builder = ""; StringBuilder builder = new StringBuilder();
char currentColor = 'r'; char currentColor = 'r';
boolean bold = false, italic = false, underlined = false, strikethrough = false; boolean bold = false, italic = false, underlined = false, strikethrough = false;
@ -26,67 +24,67 @@ public class MinecraftWebUtil {
if (c == code_prefix && (i<ligne.length()-1)) { if (c == code_prefix && (i<ligne.length()-1)) {
i++; i++;
c = ligne.charAt(i); c = ligne.charAt(i);
if (color_char.contains(new String(new char[] {Character.toLowerCase(c)}))) { if (color_char.contains(String.valueOf(Character.toLowerCase(c)))) {
if (bold) { if (bold) {
builder += "</span>"; builder.append("</span>");
bold = false; bold = false;
} }
if (italic) { if (italic) {
builder += "</span>"; builder.append("</span>");
italic = false; italic = false;
} }
if (underlined) { if (underlined) {
builder += "</span>"; builder.append("</span>");
underlined = false; underlined = false;
} }
if (strikethrough) { if (strikethrough) {
builder += "</span>"; builder.append("</span>");
strikethrough = false; strikethrough = false;
} }
if (Character.toLowerCase(c) != currentColor) { if (Character.toLowerCase(c) != currentColor) {
if (currentColor != 'r') if (currentColor != 'r')
builder += "</span>"; builder.append("</span>");
if (Character.toLowerCase(c) != 'r') if (Character.toLowerCase(c) != 'r')
builder += "<span class=\"c" + Character.toUpperCase(c) + "\">"; builder.append("<span class=\"c").append(Character.toUpperCase(c)).append("\">");
currentColor = Character.toLowerCase(c); currentColor = Character.toLowerCase(c);
} }
} }
else if (Character.toLowerCase(c) == 'l') { else if (Character.toLowerCase(c) == 'l') {
if (!bold) { if (!bold) {
builder += "<span class=\"cL\">"; builder.append("<span class=\"cL\">");
bold = true; bold = true;
} }
} }
else if (Character.toLowerCase(c) == 'm') { else if (Character.toLowerCase(c) == 'm') {
if (!strikethrough) { if (!strikethrough) {
builder += "<span class=\"cM\">"; builder.append("<span class=\"cM\">");
strikethrough = true; strikethrough = true;
} }
} }
else if (Character.toLowerCase(c) == 'n') { else if (Character.toLowerCase(c) == 'n') {
if (!underlined) { if (!underlined) {
builder += "<span class=\"cN\">"; builder.append("<span class=\"cN\">");
underlined = true; underlined = true;
} }
} }
else if (Character.toLowerCase(c) == 'o') { else if (Character.toLowerCase(c) == 'o') {
if (!italic) { if (!italic) {
builder += "<span class=\"cO\">"; builder.append("<span class=\"cO\">");
italic = true; italic = true;
} }
} }
else { else {
builder += code_prefix + c; builder.append(code_prefix + c);
} }
} }
else else
builder += c; builder.append(c);
} }
return builder; return builder.toString();
} }

View File

@ -1,6 +1,6 @@
package fr.pandacube.lib.core.util; package fr.pandacube.lib.core.util;
import java.nio.charset.Charset; import java.nio.charset.StandardCharsets;
import java.util.Objects; import java.util.Objects;
import java.util.Scanner; import java.util.Scanner;
import java.util.UUID; import java.util.UUID;
@ -8,7 +8,7 @@ import java.util.UUID;
public class OfflineUUID { public class OfflineUUID {
public static UUID getFromNickName(String nickname) { public static UUID getFromNickName(String nickname) {
byte[] from_str = ("OfflinePlayer:" + nickname).getBytes(Charset.forName("UTF-8")); byte[] from_str = ("OfflinePlayer:" + nickname).getBytes(StandardCharsets.UTF_8);
return UUID.nameUUIDFromBytes(from_str); return UUID.nameUUIDFromBytes(from_str);
} }

View File

@ -6,7 +6,7 @@ import java.util.Set;
public class RandomUtil { public class RandomUtil {
public static Random rand = new Random(); public static final Random rand = new Random();
public static int nextIntBetween(int minInclu, int maxExclu) { public static int nextIntBetween(int minInclu, int maxExclu) {
return rand.nextInt(maxExclu - minInclu) + minInclu; return rand.nextInt(maxExclu - minInclu) + minInclu;
@ -32,8 +32,8 @@ public class RandomUtil {
* Returns a random value from a set. * Returns a random value from a set.
* *
* May not be optimized (Actually O(n) ) * May not be optimized (Actually O(n) )
* @param arr * @param set the Set from which to pick a random value
* @return * @return a random value from the set
*/ */
public static <T> T setElement(Set<T> set) { public static <T> T setElement(Set<T> set) {
if (set.isEmpty()) if (set.isEmpty())
@ -51,26 +51,26 @@ public class RandomUtil {
* Return a value between 0 and the number of parameter minus 1, using the provided frequencies. * Return a value between 0 and the number of parameter minus 1, using the provided frequencies.
* *
* The probability of each value to be returned depends of the frequencies provided. * The probability of each value to be returned depends of the frequencies provided.
* @param frequencies the frequencies of each entries * @param f the frequencies of each entries
* @return the index of an entry, or -1 if it is unable to pick anything (all the frequencies are 0 or there is not provided frequency) * @return the index of an entry, or -1 if it is unable to pick anything (all the frequencies are 0 or there is not provided frequency)
*/ */
public static int randomIndexOfFrequencies(double... frequencies) { public static int randomIndexOfFrequencies(double... f) {
if (frequencies == null) if (f == null)
return -1; throw new IllegalArgumentException("f cannot be null");
int n = f.length;
double[] fSums = new double[n];
double sum = 0; double sum = 0;
for (double f : frequencies) for (int i = 0; i < n; i++) {
sum += f; if (f[i] < 0)
if (sum == 0) throw new IllegalArgumentException("f[" + i + "] cannot be negative.");
return -1; fSums[i] = (sum += f[i]);
double r = rand.nextDouble() * sum;
int i = -1;
double limit = frequencies[++i];
while (i < frequencies.length) {
if (r < limit)
return i;
limit += frequencies[++i];
} }
return frequencies.length - 1; double r = rand.nextDouble() * sum;
for (int i = 0; i < n; i++) {
if (fSums[i] > r)
return i;
}
return n - 1;
} }
@ -81,7 +81,7 @@ public class RandomUtil {
public static final String PASSWORD_CHARSET_LATIN_LOWERCASE = "abcdefghijklmnopqrstuvwxyz"; public static final String PASSWORD_CHARSET_LATIN_LOWERCASE = "abcdefghijklmnopqrstuvwxyz";
public static final String PASSWORD_CHARSET_LATIN_UPPERCASE = PASSWORD_CHARSET_LATIN_LOWERCASE.toUpperCase(); public static final String PASSWORD_CHARSET_LATIN_UPPERCASE = PASSWORD_CHARSET_LATIN_LOWERCASE.toUpperCase();
public static final String PASSWORD_CHARSET_DIGIT = "0123456789"; public static final String PASSWORD_CHARSET_DIGIT = "0123456789";
public static final String PASSWORD_CHARSET_SPECIAL = "@#+*/-;:,.?!='()[]{}&\"\\"; public static final String PASSWORD_CHARSET_SPECIAL = "@#+*/-;:,.?!='()[]{}&";
public static final String PASSWORD_CHARSET_NO_ANBIGUITY = "abcdefghkmnpqrstwxyzACDEFGHKLMNPQRSTWXYZ2345679"; public static final String PASSWORD_CHARSET_NO_ANBIGUITY = "abcdefghkmnpqrstwxyzACDEFGHKLMNPQRSTWXYZ2345679";
public static String randomPassword(int length) { public static String randomPassword(int length) {

View File

@ -4,6 +4,7 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@ -73,7 +74,7 @@ public class Reflect {
} }
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {
return other != null && other instanceof MethodIdentifier o return other instanceof MethodIdentifier o
&& o.methodName.equals(methodName) && o.methodName.equals(methodName)
&& Arrays.equals(o.parameters, parameters); && Arrays.equals(o.parameters, parameters);
} }
@ -89,7 +90,7 @@ public class Reflect {
} }
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {
return other != null && other instanceof ConstructorIdentifier o return other instanceof ConstructorIdentifier o
&& Arrays.equals(o.parameters, parameters); && Arrays.equals(o.parameters, parameters);
} }
@Override @Override
@ -196,10 +197,10 @@ public class Reflect {
public static abstract class ReflectMember<T, ID, EL, EX extends ReflectiveOperationException> { public static abstract class ReflectMember<T, ID, EL, EX extends ReflectiveOperationException> {
ReflectClass<T> reflectClass; protected final ReflectClass<T> reflectClass;
protected ID identifier; protected final ID identifier;
protected EL cached; protected final EL cached;
protected ReflectMember(ReflectClass<T> c, ID id, boolean bypassFilter) throws EX { protected ReflectMember(ReflectClass<T> c, ID id, boolean bypassFilter) throws EX {
reflectClass = c; reflectClass = c;
@ -210,78 +211,71 @@ public class Reflect {
protected EL fetch() throws EX { protected EL fetch() throws EX {
EX ex = null;
// get element in current class // get element in current class
try { try {
EL el = fetchFromClass(reflectClass.clazz); EL el = fetchFromClass(reflectClass.clazz);
setAccessible(el); setAccessible(el);
return el; return el;
} catch (ReflectiveOperationException e) { } catch (ReflectiveOperationException e1) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
EX ee = (EX) e; EX ex = (EX) e1;
ex = ee;
// get parent class
Class<? super T> superClass = reflectClass.clazz.getSuperclass();
if (superClass == null)
throw ex;
// get element in parent class (will do recursion)
try {
EL el = fetchFromReflectClass(ofClass(superClass));
setAccessible(el);
return el;
} catch (ReflectiveOperationException e2) {
ex.addSuppressed(e2);
throw ex;
}
} }
// get parent class
Class<? super T> superClass = reflectClass.clazz.getSuperclass();
if (superClass == null)
throw ex;
// get element in parent class (will do recursion)
try {
EL el = fetchFromReflectClass(ofClass(superClass));
setAccessible(el);
return el;
} catch (ReflectiveOperationException e) {
ex.addSuppressed(e);
throw ex;
}
} }
protected EL fetchFiltered() throws EX { protected EL fetchFiltered() throws EX {
EX ex = null;
// get element in current class // get element in current class
try { try {
EL el = fetchFromClass(reflectClass.clazz); EL el = fetchFromClass(reflectClass.clazz);
setAccessible(el); setAccessible(el);
return el; return el;
} catch (ReflectiveOperationException e) { } catch (ReflectiveOperationException e1) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
EX ee = (EX) e; EX ex = (EX) e1;
ex = ee;
// trying to bypass filtered member
try {
@SuppressWarnings("unchecked")
EL[] elements = (EL[]) Reflect.ofClassOfInstance(reflectClass.clazz)
.method(internalMethodNameElementArray(), boolean.class)
.invoke(reflectClass.clazz, false);
for (EL element : elements) {
if (isEqualOurElement(element)) {
// the values in the elements array have to be copied
// (using special private methods in reflection api) before using it
Object reflectionFactoryOfClazz = Reflect.ofClassOfInstance(reflectClass.clazz)
.method("getReflectionFactory")
.invoke(reflectClass.clazz);
@SuppressWarnings("unchecked")
EL copiedElement = (EL) Reflect.ofClassOfInstance(reflectionFactoryOfClazz)
.method(internalMethodNameCopyElement(), element.getClass())
.invoke(reflectionFactoryOfClazz, element);
setAccessible(copiedElement);
return copiedElement;
}
}
} catch (ReflectiveOperationException e2) {
ex.addSuppressed(e2);
}
throw ex;
} }
// trying to bypass filtered member
try {
@SuppressWarnings("unchecked")
EL[] elements = (EL[]) Reflect.ofClassOfInstance(reflectClass.clazz)
.method(internalMethodNameElementArray(), boolean.class)
.invoke(reflectClass.clazz, false);
for (EL element : elements) {
if (isEqualOurElement(element)) {
// the values in the elements array have to be copied
// (using special private methods in reflection api) before using it
Object reflectionFactoryOfClazz = Reflect.ofClassOfInstance(reflectClass.clazz)
.method("getReflectionFactory")
.invoke(reflectClass.clazz);
@SuppressWarnings("unchecked")
EL copiedElement = (EL) Reflect.ofClassOfInstance(reflectionFactoryOfClazz)
.method(internalMethodNameCopyElement(), element.getClass())
.invoke(reflectionFactoryOfClazz, element);
EL el = copiedElement;
setAccessible(el);
return el;
}
}
} catch (ReflectiveOperationException e) {
ex.addSuppressed(e);
}
throw ex;
} }
protected abstract EL fetchFromClass(Class<T> clazz) throws EX; protected abstract EL fetchFromClass(Class<T> clazz) throws EX;
@ -311,11 +305,11 @@ public class Reflect {
super(c, name, bypassFilter); super(c, name, bypassFilter);
} }
@Override protected Field fetchFromClass(Class<T> clazz) throws NoSuchFieldException { return clazz.getDeclaredField(identifier); }; @Override protected Field fetchFromClass(Class<T> clazz) throws NoSuchFieldException { return clazz.getDeclaredField(identifier); }
@Override protected Field fetchFromReflectClass(ReflectClass<?> rc) throws NoSuchFieldException { return rc.field(identifier).get(); }; @Override protected Field fetchFromReflectClass(ReflectClass<?> rc) throws NoSuchFieldException { return rc.field(identifier).get(); }
@Override protected boolean isEqualOurElement(Field el) { return identifier.equals(el.getName()); }; @Override protected boolean isEqualOurElement(Field el) { return identifier.equals(el.getName()); }
@Override protected String internalMethodNameElementArray() { return "getDeclaredFields0"; }; @Override protected String internalMethodNameElementArray() { return "getDeclaredFields0"; }
@Override protected String internalMethodNameCopyElement() { return "copyField"; }; @Override protected String internalMethodNameCopyElement() { return "copyField"; }
@Override protected void setAccessible(Field el) { el.setAccessible(true); } @Override protected void setAccessible(Field el) { el.setAccessible(true); }
@ -379,11 +373,11 @@ public class Reflect {
super(c, methodId, bypassFilter); super(c, methodId, bypassFilter);
} }
@Override protected Method fetchFromClass(Class<T> clazz) throws NoSuchMethodException { return clazz.getDeclaredMethod(identifier.methodName, identifier.parameters); }; @Override protected Method fetchFromClass(Class<T> clazz) throws NoSuchMethodException { return clazz.getDeclaredMethod(identifier.methodName, identifier.parameters); }
@Override protected Method fetchFromReflectClass(ReflectClass<?> rc) throws NoSuchMethodException { return rc.method(identifier, false).get(); }; @Override protected Method fetchFromReflectClass(ReflectClass<?> rc) throws NoSuchMethodException { return rc.method(identifier, false).get(); }
@Override protected boolean isEqualOurElement(Method el) { return identifier.methodName.equals(el.getName()) && Arrays.equals(identifier.parameters, el.getParameterTypes()); }; @Override protected boolean isEqualOurElement(Method el) { return identifier.methodName.equals(el.getName()) && Arrays.equals(identifier.parameters, el.getParameterTypes()); }
@Override protected String internalMethodNameElementArray() { return "getDeclaredMethods0"; }; @Override protected String internalMethodNameElementArray() { return "getDeclaredMethods0"; }
@Override protected String internalMethodNameCopyElement() { return "copyMethod"; }; @Override protected String internalMethodNameCopyElement() { return "copyMethod"; }
@Override protected void setAccessible(Method el) { el.setAccessible(true); } @Override protected void setAccessible(Method el) { el.setAccessible(true); }
public Object invoke(Object instance, Object... values) throws ReflectiveOperationException { public Object invoke(Object instance, Object... values) throws ReflectiveOperationException {
@ -415,17 +409,16 @@ public class Reflect {
// Override since we don't want to recursively search for a constructor // Override since we don't want to recursively search for a constructor
@Override @Override
protected Constructor<T> fetch() throws NoSuchMethodException { protected Constructor<T> fetch() throws NoSuchMethodException {
Constructor<T> el = null; Constructor<T> el = fetchFromClass(reflectClass.clazz);
el = fetchFromClass(reflectClass.clazz);
setAccessible(el); setAccessible(el);
return el; return el;
} }
@Override protected Constructor<T> fetchFromClass(Class<T> clazz) throws NoSuchMethodException { return clazz.getDeclaredConstructor(identifier.parameters); }; @Override protected Constructor<T> fetchFromClass(Class<T> clazz) throws NoSuchMethodException { return clazz.getDeclaredConstructor(identifier.parameters); }
@Override protected Constructor<T> fetchFromReflectClass(ReflectClass<?> rc) throws NoSuchMethodException { throw new UnsupportedOperationException(); }; @Override protected Constructor<T> fetchFromReflectClass(ReflectClass<?> rc) { throw new UnsupportedOperationException(); }
@Override protected boolean isEqualOurElement(Constructor<T> el) { return Arrays.equals(identifier.parameters, el.getParameterTypes()); }; @Override protected boolean isEqualOurElement(Constructor<T> el) { return Arrays.equals(identifier.parameters, el.getParameterTypes()); }
@Override protected String internalMethodNameElementArray() { return "getDeclaredConstructors0"; }; @Override protected String internalMethodNameElementArray() { return "getDeclaredConstructors0"; }
@Override protected String internalMethodNameCopyElement() { return "copyConstructor"; }; @Override protected String internalMethodNameCopyElement() { return "copyConstructor"; }
@Override protected void setAccessible(Constructor<T> el) { el.setAccessible(true); } @Override protected void setAccessible(Constructor<T> el) { el.setAccessible(true); }
public T instanciate(Object... values) throws ReflectiveOperationException { public T instanciate(Object... values) throws ReflectiveOperationException {
@ -453,7 +446,7 @@ public class Reflect {
private static Cache<Class<?>, List<Class<?>>> subClassesLists = CacheBuilder.newBuilder() private static final Cache<Class<?>, List<Class<?>>> subClassesLists = CacheBuilder.newBuilder()
.expireAfterAccess(10, TimeUnit.MINUTES) .expireAfterAccess(10, TimeUnit.MINUTES)
.build(); .build();
@ -468,7 +461,7 @@ public class Reflect {
return classes; return classes;
} catch(ExecutionException e) { } catch(ExecutionException e) {
Log.severe(e); Log.severe(e);
return null; return new ArrayList<>();
} }
} }

View File

@ -6,12 +6,13 @@ import java.io.File;
import java.io.FileReader; import java.io.FileReader;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.util.Objects;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
public class ServerPropertyFile { public class ServerPropertyFile {
private transient File file; private final transient File file;
private String name = "default_name"; private String name = "default_name";
private String memory = "512M"; private String memory = "512M";
@ -22,8 +23,7 @@ public class ServerPropertyFile {
private boolean run = true; private boolean run = true;
public ServerPropertyFile(File f) { public ServerPropertyFile(File f) {
if (f == null) throw new IllegalArgumentException("f ne doit pas être null"); file = Objects.requireNonNull(f, "f");
file = f;
} }
@ -101,7 +101,7 @@ public class ServerPropertyFile {
} }
public void setMemory(String m) { public void setMemory(String m) {
if (m == null || !m.matches("^[0-9]+[mgMG]$")) throw new IllegalArgumentException(); if (m == null || !m.matches("^\\d+[mgMG]$")) throw new IllegalArgumentException();
memory = m; memory = m;
} }

View File

@ -4,6 +4,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.nio.charset.StandardCharsets;
public class ThrowableUtil { public class ThrowableUtil {
@ -11,11 +12,11 @@ public class ThrowableUtil {
public static String stacktraceToString(Throwable t) { public static String stacktraceToString(Throwable t) {
if (t == null) return null; if (t == null) return null;
try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
try (PrintStream ps = new PrintStream(os, false, "UTF-8")) { try (PrintStream ps = new PrintStream(os, false, StandardCharsets.UTF_8)) {
t.printStackTrace(ps); t.printStackTrace(ps);
ps.flush(); ps.flush();
} }
return os.toString("UTF-8"); return os.toString(StandardCharsets.UTF_8);
} catch (IOException e) { } catch (IOException e) {
return null; return null;
} }
@ -90,7 +91,7 @@ public class ThrowableUtil {
*/ */
@FunctionalInterface @FunctionalInterface
public interface SupplierException<T> { public interface SupplierException<T> {
public T get() throws Exception; T get() throws Exception;
} }
@ -100,7 +101,7 @@ public class ThrowableUtil {
*/ */
@FunctionalInterface @FunctionalInterface
public interface RunnableException { public interface RunnableException {
public void run() throws Exception; void run() throws Exception;
} }
@ -135,10 +136,6 @@ public class ThrowableUtil {
er = new InstantiationError(); er = new InstantiationError();
er.initCause(ce); er.initCause(ce);
} }
else if (t instanceof IllegalAccessException ce) {
er = new IllegalAccessError();
er.initCause(ce);
}
if (er != null) if (er != null)
throw er; throw er;

View File

@ -14,7 +14,7 @@ public class Tick {
/** /**
* Returns the number of tick is the provided duration, in second * Returns the number of tick is the provided duration, in second
* @param seconds the duration in second * @param minutes the duration in minutes
* @return the same duration as provided, but in Minecraft server ticks * @return the same duration as provided, but in Minecraft server ticks
*/ */
public static long min(long minutes) { public static long min(long minutes) {

View File

@ -1,5 +1,7 @@
package fr.pandacube.lib.core.util; package fr.pandacube.lib.core.util;
import fr.pandacube.lib.core.commands.SuggestionsSupplier;
import java.time.Instant; import java.time.Instant;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
@ -7,10 +9,10 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Objects;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@ -19,21 +21,19 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import fr.pandacube.lib.core.commands.SuggestionsSupplier;
public class TimeUtil { public class TimeUtil {
private static DateTimeFormatter cmpDayOfWeekFormatter = DateTimeFormatter.ofPattern("EEE", Locale.getDefault()); private static final DateTimeFormatter cmpDayOfWeekFormatter = DateTimeFormatter.ofPattern("EEE", Locale.getDefault());
private static DateTimeFormatter dayOfWeekFormatter = DateTimeFormatter.ofPattern("EEEE", Locale.getDefault()); private static final DateTimeFormatter dayOfWeekFormatter = DateTimeFormatter.ofPattern("EEEE", Locale.getDefault());
private static DateTimeFormatter dayOfMonthFormatter = DateTimeFormatter.ofPattern("d", Locale.getDefault()); private static final DateTimeFormatter dayOfMonthFormatter = DateTimeFormatter.ofPattern("d", Locale.getDefault());
private static DateTimeFormatter cmpMonthFormatter = DateTimeFormatter.ofPattern("MMM", Locale.getDefault()); private static final DateTimeFormatter cmpMonthFormatter = DateTimeFormatter.ofPattern("MMM", Locale.getDefault());
private static DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("MMMM", Locale.getDefault()); private static final DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("MMMM", Locale.getDefault());
private static DateTimeFormatter yearFormatter = DateTimeFormatter.ofPattern("uuuu", Locale.getDefault()); private static final DateTimeFormatter yearFormatter = DateTimeFormatter.ofPattern("uuuu", Locale.getDefault());
private static DateTimeFormatter HMSFormatter = DateTimeFormatter.ofPattern("HH:mm:ss", Locale.getDefault()); private static final DateTimeFormatter HMSFormatter = DateTimeFormatter.ofPattern("HH:mm:ss", Locale.getDefault());
private static DateTimeFormatter HMFormatter = DateTimeFormatter.ofPattern("HH:mm", Locale.getDefault()); private static final DateTimeFormatter HMFormatter = DateTimeFormatter.ofPattern("HH:mm", Locale.getDefault());
private static DateTimeFormatter HFormatter = DateTimeFormatter.ofPattern("H'h'", Locale.getDefault()); private static final DateTimeFormatter HFormatter = DateTimeFormatter.ofPattern("H'h'", Locale.getDefault());
public static String relativeDateFr(long displayTime, boolean showSeconds, boolean compactWords) { public static String relativeDateFr(long displayTime, boolean showSeconds, boolean compactWords) {
@ -67,7 +67,7 @@ public class TimeUtil {
if (timeDiffSec > -60*2) // dans 2 min if (timeDiffSec > -60*2) // dans 2 min
return compactWords ? "dans 1min" : "dans une minute"; return compactWords ? "dans 1min" : "dans une minute";
if (timeDiffSec > -3600) // dans moins d1h if (timeDiffSec > -3600) // dans moins d1h
return "dans " + (int)Math.floor((-timeDiffSec)/60) + (compactWords ? "min" : " minutes"); return "dans " + (-timeDiffSec/60) + (compactWords ? "min" : " minutes");
} }
if (relPrecision.morePreciseOrEqTo(RelativePrecision.HOURS)) { if (relPrecision.morePreciseOrEqTo(RelativePrecision.HOURS)) {
if (timeDiffSec > -3600) // dans moins d1h if (timeDiffSec > -3600) // dans moins d1h
@ -75,7 +75,7 @@ public class TimeUtil {
if (timeDiffSec > -3600*2) // dans moins de 2h if (timeDiffSec > -3600*2) // dans moins de 2h
return compactWords ? "dans 1h" : "dans une heure"; return compactWords ? "dans 1h" : "dans une heure";
if (timeDiffSec > -3600*12) // dans moins de 12h if (timeDiffSec > -3600*12) // dans moins de 12h
return "dans " + (int)Math.floor((-timeDiffSec)/3600) + (compactWords ? "h" : " heures"); return "dans " + (-timeDiffSec/3600) + (compactWords ? "h" : " heures");
} }
if (relPrecision.morePreciseOrEqTo(RelativePrecision.DAYS)) { if (relPrecision.morePreciseOrEqTo(RelativePrecision.DAYS)) {
LocalDateTime nextMidnight = LocalDateTime.of(currentDateTime.getYear(), currentDateTime.getMonth(), currentDateTime.getDayOfMonth(), 0, 0).plusDays(1); LocalDateTime nextMidnight = LocalDateTime.of(currentDateTime.getYear(), currentDateTime.getMonth(), currentDateTime.getDayOfMonth(), 0, 0).plusDays(1);
@ -88,9 +88,7 @@ public class TimeUtil {
+ dayOfMonthFormatter.format(displayDateTime) + " à " + dayOfMonthFormatter.format(displayDateTime) + " à "
+ dayTimeFr(displayTime, dispPrecision); + dayTimeFr(displayTime, dispPrecision);
} }
return fullDateFr(displayTime, dispPrecision, true, compactWords);
} }
else { else {
// present and past // present and past
@ -107,7 +105,7 @@ public class TimeUtil {
if (timeDiffSec < 60*2) // ya moins de 2 min if (timeDiffSec < 60*2) // ya moins de 2 min
return compactWords ? "il y a 1min" : "il y a une minute"; return compactWords ? "il y a 1min" : "il y a une minute";
if (timeDiffSec < 3600) // ya moins d'1h if (timeDiffSec < 3600) // ya moins d'1h
return "il y a " + (int)Math.floor(timeDiffSec/60) + (compactWords ? "min" : " minutes"); return "il y a " + (timeDiffSec/60) + (compactWords ? "min" : " minutes");
} }
if (relPrecision.morePreciseOrEqTo(RelativePrecision.HOURS)) { if (relPrecision.morePreciseOrEqTo(RelativePrecision.HOURS)) {
if (timeDiffSec < 3600) // ya moins d'1h if (timeDiffSec < 3600) // ya moins d'1h
@ -115,7 +113,7 @@ public class TimeUtil {
if (timeDiffSec < 3600*2) // ya moins de 2h if (timeDiffSec < 3600*2) // ya moins de 2h
return "il y a une heure"; return "il y a une heure";
if (timeDiffSec < 3600*12) // ya moins de 12h if (timeDiffSec < 3600*12) // ya moins de 12h
return "il y a " + (int)Math.floor(timeDiffSec/3600) + " heures"; return "il y a " + (timeDiffSec/3600) + " heures";
} }
if (relPrecision.morePreciseOrEqTo(RelativePrecision.DAYS)) { if (relPrecision.morePreciseOrEqTo(RelativePrecision.DAYS)) {
LocalDateTime lastMidnight = LocalDateTime.of(currentDateTime.getYear(), currentDateTime.getMonth(), currentDateTime.getDayOfMonth(), 0, 0); LocalDateTime lastMidnight = LocalDateTime.of(currentDateTime.getYear(), currentDateTime.getMonth(), currentDateTime.getDayOfMonth(), 0, 0);
@ -127,11 +125,10 @@ public class TimeUtil {
return (compactWords ? cmpDayOfWeekFormatter : dayOfWeekFormatter).format(displayDateTime) + " dernier à " return (compactWords ? cmpDayOfWeekFormatter : dayOfWeekFormatter).format(displayDateTime) + " dernier à "
+ dayTimeFr(displayTime, dispPrecision); + dayTimeFr(displayTime, dispPrecision);
} }
return fullDateFr(displayTime, dispPrecision, true, compactWords);
} }
return fullDateFr(displayTime, dispPrecision, true, compactWords);
} }
@ -207,7 +204,7 @@ public class TimeUtil {
String ret = Arrays.stream(TimeUnit.values()) String ret = Arrays.stream(TimeUnit.values())
.sequential() .sequential()
.filter(u -> u.compareTo(fLUnit) >= 0 && u.compareTo(fHUnit) <= 0) .filter(u -> u.compareTo(fLUnit) >= 0 && u.compareTo(fHUnit) <= 0)
.sorted((u1, u2) -> u2.compareTo(u1)) .sorted(Comparator.reverseOrder())
.filter(u -> { .filter(u -> {
if (u.convert(remainingTime.get(), TimeUnit.MILLISECONDS) == 0 && !oneDisplayed.get()) if (u.convert(remainingTime.get(), TimeUnit.MILLISECONDS) == 0 && !oneDisplayed.get())
return false; return false;
@ -226,40 +223,23 @@ public class TimeUtil {
public static String timeUnitToSuffix(TimeUnit u, boolean fr) { public static String timeUnitToSuffix(TimeUnit u, boolean fr) {
switch (u) { return switch (u) {
case DAYS: case DAYS -> fr ? "j" : "d";
return fr ? "j" : "d"; case HOURS -> "h";
case HOURS: case MINUTES -> "m";
return "h"; case SECONDS -> "s";
case MINUTES: case MILLISECONDS -> "ms";
return "m"; case MICROSECONDS -> "μs";
case SECONDS: case NANOSECONDS -> "ns";
return "s"; };
case MILLISECONDS:
return "ms";
case MICROSECONDS:
return "μs";
case NANOSECONDS:
return "ns";
default:
throw new IllegalArgumentException("Invalid TimeUnit: " + Objects.toString(u));
}
} }
public static int timeUnitToLeftPadLength(TimeUnit u) { public static int timeUnitToLeftPadLength(TimeUnit u) {
switch (u) { return switch (u) {
case NANOSECONDS: case NANOSECONDS, MICROSECONDS, MILLISECONDS -> 3;
case MICROSECONDS: case SECONDS, MINUTES, HOURS -> 2;
case MILLISECONDS: case DAYS -> 1;
return 3; };
case SECONDS:
case MINUTES:
case HOURS:
return 2;
case DAYS:
default:
return 1;
}
} }
public static String toString(long value, int leftPad) { public static String toString(long value, int leftPad) {
@ -279,7 +259,6 @@ public class TimeUtil {
* Equivalent to {@link #durationToLongString(long, TimeUnit, TimeUnit, boolean, boolean, boolean) TimeUnit.durationToLongString(msDuration, TimeUnit.DAYS, milliseconds ? TimeUnit.MILLISECONDS : TimeUnit.SECONDS, true, true, false)} * Equivalent to {@link #durationToLongString(long, TimeUnit, TimeUnit, boolean, boolean, boolean) TimeUnit.durationToLongString(msDuration, TimeUnit.DAYS, milliseconds ? TimeUnit.MILLISECONDS : TimeUnit.SECONDS, true, true, false)}
* @param msDuration the duration in ms * @param msDuration the duration in ms
* @param milliseconds if the milliseconds are displayed or not * @param milliseconds if the milliseconds are displayed or not
* @return
*/ */
public static String durationToString(long msDuration, boolean milliseconds) { public static String durationToString(long msDuration, boolean milliseconds) {
return durationToLongString(msDuration, TimeUnit.DAYS, milliseconds ? TimeUnit.MILLISECONDS : TimeUnit.SECONDS, true, true, false); return durationToLongString(msDuration, TimeUnit.DAYS, milliseconds ? TimeUnit.MILLISECONDS : TimeUnit.SECONDS, true, true, false);
@ -287,8 +266,7 @@ public class TimeUtil {
/** /**
* Equivalent to {@link #durationToLongString(long, TimeUnit, TimeUnit, boolean, boolean, boolean) TimeUnit.durationToLongString(msDuration, TimeUnit.DAYS, TimeUnit.SECONDS, true, true, false)} * Equivalent to {@link #durationToLongString(long, TimeUnit, TimeUnit, boolean, boolean, boolean) TimeUnit.durationToLongString(msDuration, TimeUnit.DAYS, TimeUnit.SECONDS, true, true, false)}
* @param msDuration * @param msDuration the duration in ms
* @return
*/ */
public static String durationToString(long msDuration) { public static String durationToString(long msDuration) {
return durationToLongString(msDuration, TimeUnit.DAYS, TimeUnit.SECONDS, true, true, false); return durationToLongString(msDuration, TimeUnit.DAYS, TimeUnit.SECONDS, true, true, false);
@ -296,8 +274,7 @@ public class TimeUtil {
/** /**
* Equivalent to {@link #durationToLongString(long, TimeUnit, TimeUnit, boolean, boolean, boolean) TimeUnit.durationToLongString(msDuration, TimeUnit.DAYS, TimeUnit.SECONDS, false, false, false)} * Equivalent to {@link #durationToLongString(long, TimeUnit, TimeUnit, boolean, boolean, boolean) TimeUnit.durationToLongString(msDuration, TimeUnit.DAYS, TimeUnit.SECONDS, false, false, false)}
* @param msDuration * @param msDuration the duration in ms
* @return
*/ */
public static String durationToParsableString(long msDuration) { public static String durationToParsableString(long msDuration) {
return durationToLongString(msDuration, TimeUnit.DAYS, TimeUnit.SECONDS, false, false, false); return durationToLongString(msDuration, TimeUnit.DAYS, TimeUnit.SECONDS, false, false, false);
@ -306,9 +283,10 @@ public class TimeUtil {
/** /**
* @see {@link com.earth2me.essentials.utils.DateUtil#parseDuration(String, boolean)} * @see <a href="https://github.com/EssentialsX/Essentials/blob/2.x/Essentials/src/main/java/com/earth2me/essentials/utils/DateUtil.java">Essentials DateUtil#parseDuration(String, boolean)</a>
*/ */
public static long parseDuration(String time, boolean future) throws Exception { public static long parseDuration(String time, boolean future) throws Exception {
@SuppressWarnings("RegExpSimplifiable")
Pattern timePattern = Pattern.compile("(?:([0-9]+)\\s*y[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*mo[a-z]*[,\\s]*)?" Pattern timePattern = Pattern.compile("(?:([0-9]+)\\s*y[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*mo[a-z]*[,\\s]*)?"
+ "(?:([0-9]+)\\s*w[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*d[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*w[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*d[a-z]*[,\\s]*)?"
+ "(?:([0-9]+)\\s*h[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*m[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*h[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*m[a-z]*[,\\s]*)?"
@ -367,17 +345,13 @@ public class TimeUtil {
List<String> remainingSuffixes = new ArrayList<>(allSuffixes); List<String> remainingSuffixes = new ArrayList<>(allSuffixes);
char[] tokenChars = token.toCharArray(); char[] tokenChars = token.toCharArray();
String accSuffix = ""; String accSuffix = "";
for (int i = 0; i < tokenChars.length; i++) { for (char c : tokenChars) {
char c = tokenChars[i];
if (Character.isDigit(c)) { if (Character.isDigit(c)) {
scanAndRemovePastSuffixes(remainingSuffixes, accSuffix); scanAndRemovePastSuffixes(remainingSuffixes, accSuffix);
accSuffix = ""; accSuffix = "";
continue; } else if (Character.isLetter(c)) {
}
else if (Character.isLetter(c)) {
accSuffix += c; accSuffix += c;
} } else
else
return Collections.emptyList(); return Collections.emptyList();
} }
String prefixToken = token.substring(0, token.length() - accSuffix.length()); String prefixToken = token.substring(0, token.length() - accSuffix.length());
@ -388,14 +362,12 @@ public class TimeUtil {
}; };
} }
private static List<String> allSuffixes = Arrays.asList("y", "mo", "w", "d", "h", "m", "s"); private static final List<String> allSuffixes = Arrays.asList("y", "mo", "w", "d", "h", "m", "s");
private static List<String> emptyTokenSuggestions = allSuffixes.stream().map(p -> "1" + p).collect(Collectors.toList()); private static final List<String> emptyTokenSuggestions = allSuffixes.stream().map(p -> "1" + p).collect(Collectors.toList());
private static void scanAndRemovePastSuffixes(List<String> suffixes, String foundSuffix) { private static void scanAndRemovePastSuffixes(List<String> suffixes, String foundSuffix) {
for (int i = 0; i < suffixes.size(); i++) { for (int i = 0; i < suffixes.size(); i++) {
if (foundSuffix.startsWith(suffixes.get(i))) { if (foundSuffix.startsWith(suffixes.get(i))) {
for (int j = i; j >= 0; j--) { suffixes.subList(0, i + 1).clear();
suffixes.remove(j);
}
return; return;
} }
} }

View File

@ -116,9 +116,7 @@ public class TypeConverter {
* @param o the object to convert to good type * @param o the object to convert to good type
* @param mapIntKeys if the String key representing an int should be duplicated as integer type, * @param mapIntKeys if the String key representing an int should be duplicated as integer type,
* which map to the same value as the original String key. For example, if a key is "12" and map * which map to the same value as the original String key. For example, if a key is "12" and map
* to the object <i>o</i>, an integer key 12 will be added and map to the same object * to the object <i>o</i>, an integer key 12 will be added and map to the same object <i>o</i>
* <i>o</i>
* @return
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Map<Object, Object> toMap(Object o, boolean mapIntKeys) { public static Map<Object, Object> toMap(Object o, boolean mapIntKeys) {
@ -139,7 +137,7 @@ public class TypeConverter {
try { try {
int intKey = Integer.parseInt((String)entry.getKey()); int intKey = Integer.parseInt((String)entry.getKey());
newEntries.put(intKey, entry.getValue()); newEntries.put(intKey, entry.getValue());
} catch (NumberFormatException e) { } } catch (NumberFormatException ignored) { }
} }
} }
if (!newEntries.isEmpty()) { if (!newEntries.isEmpty()) {
@ -150,8 +148,7 @@ public class TypeConverter {
return currMap; return currMap;
} }
if (o instanceof List) { if (o instanceof List<?> list) {
List<?> list = (List<?>) o;
Map<Object, Object> map = new HashMap<>(); Map<Object, Object> map = new HashMap<>();
for(int i = 0; i < list.size(); i++) { for(int i = 0; i < list.size(); i++) {
map.put(Integer.toString(i), list.get(i)); map.put(Integer.toString(i), list.get(i));
@ -200,7 +197,6 @@ public class TypeConverter {
public static class ConvertionException extends RuntimeException { public static class ConvertionException extends RuntimeException {
private static final long serialVersionUID = 1L;
public ConvertionException(String m) { public ConvertionException(String m) {
super(m); super(m);

View File

@ -30,13 +30,13 @@ import fr.pandacube.lib.paper.util.BukkitEvent;
*/ */
public class GUIHotBar implements Listener { public class GUIHotBar implements Listener {
private Map<ItemStack, BiConsumer<PlayerInventory, ItemStack>> itemsAndSetters = new HashMap<>(); private final Map<ItemStack, BiConsumer<PlayerInventory, ItemStack>> itemsAndSetters = new HashMap<>();
private Map<ItemStack, Consumer<Player>> itemsAndRunnables = new HashMap<>(); private final Map<ItemStack, Consumer<Player>> itemsAndRunnables = new HashMap<>();
private final int defltSlot; private final int defltSlot;
private List<Player> currentPlayers = new ArrayList<>(); private final List<Player> currentPlayers = new ArrayList<>();
public GUIHotBar(int defaultSlot) { public GUIHotBar(int defaultSlot) {
defltSlot = Math.max(0, Math.min(8, defaultSlot)); defltSlot = Math.max(0, Math.min(8, defaultSlot));
@ -50,7 +50,6 @@ public class GUIHotBar implements Listener {
* @param i the item stack * @param i the item stack
* @param setter code executed to put the item in the inventory. Additionally check for permission before doing the addition. * @param setter code executed to put the item in the inventory. Additionally check for permission before doing the addition.
* @param run the Runnable to run when the user right click on the item in the hotbar. * @param run the Runnable to run when the user right click on the item in the hotbar.
* @return
*/ */
public GUIHotBar addItem(ItemStack i, BiConsumer<PlayerInventory, ItemStack> setter, Consumer<Player> run) { public GUIHotBar addItem(ItemStack i, BiConsumer<PlayerInventory, ItemStack> setter, Consumer<Player> run) {
itemsAndSetters.put(i, setter); itemsAndSetters.put(i, setter);
@ -65,8 +64,7 @@ public class GUIHotBar implements Listener {
/** /**
* Add the hotbar elements to this player. * Add the hotbar elements to this player.
* *
* The players is automatically removed when it quit. You can remove it before by calling {@link #removePlayer(Player)}. * The players is automatically removed when they quit. You can remove it before by calling {@link #removePlayer(Player)}.
* @param p
*/ */
public void addPlayer(Player p) { public void addPlayer(Player p) {
if (!currentPlayers.contains(p)) if (!currentPlayers.contains(p))
@ -81,7 +79,6 @@ public class GUIHotBar implements Listener {
/** /**
* Detach this player from this hotbar manager and removes the managed items from the players inventory. * Detach this player from this hotbar manager and removes the managed items from the players inventory.
* @param p
*/ */
public void removePlayer(Player p) { public void removePlayer(Player p) {
if (!currentPlayers.contains(p)) if (!currentPlayers.contains(p))
@ -134,7 +131,7 @@ public class GUIHotBar implements Listener {
ItemStack item = event.getItemDrop().getItemStack(); ItemStack item = event.getItemDrop().getItemStack();
for (ItemStack managed : itemsAndSetters.keySet()) { for (ItemStack managed : itemsAndSetters.keySet()) {
if (item != null && item.isSimilar(managed)) { if (item.isSimilar(managed)) {
event.setCancelled(true); event.setCancelled(true);
return; return;
} }
@ -173,12 +170,10 @@ public class GUIHotBar implements Listener {
@EventHandler @EventHandler
public void onInventoryClick(InventoryClickEvent event) { public void onInventoryClick(InventoryClickEvent event) {
if (event.getClickedInventory() == null || !(event.getClickedInventory() instanceof PlayerInventory)) if (event.getClickedInventory() == null || !(event.getClickedInventory() instanceof PlayerInventory inv))
return; return;
PlayerInventory inv = (PlayerInventory) event.getClickedInventory(); if (!currentPlayers.contains((Player) inv.getHolder()))
if (!currentPlayers.contains(inv.getHolder()))
return; return;
ItemStack item = event.getCurrentItem(); ItemStack item = event.getCurrentItem();

View File

@ -30,11 +30,11 @@ public class GUIInventory implements Listener {
public static final Map<Enchantment, Integer> FAKE_ENCHANT = ImmutableMap.of(Enchantment.DURABILITY, 1); public static final Map<Enchantment, Integer> FAKE_ENCHANT = ImmutableMap.of(Enchantment.DURABILITY, 1);
private Player player; private final Player player;
private Inventory inv; private final Inventory inv;
private Consumer<InventoryCloseEvent> onCloseEvent; private Consumer<InventoryCloseEvent> onCloseEvent;
private boolean isOpened = false; private boolean isOpened = false;
private Map<Integer, Consumer<InventoryClickEvent>> onClickEvents; private final Map<Integer, Consumer<InventoryClickEvent>> onClickEvents;
public GUIInventory(Player p, int nbLines, Chat title, Consumer<InventoryCloseEvent> closeEventAction, public GUIInventory(Player p, int nbLines, Chat title, Consumer<InventoryCloseEvent> closeEventAction,
Plugin pl) { Plugin pl) {

View File

@ -139,9 +139,8 @@ public class NMSReflect {
/** /**
* @param mojName the binary name of the desired class, on the mojang mapping. * @param mojName the binary name of the desired class, on the mojang mapping.
* @throws NullPointerException if there is no mapping for the provided Mojang mapped class. * @throws NullPointerException if there is no mapping for the provided Mojang mapped class.
* @throws ClassNotFoundException if there is a mapping, but the runtime class was not found.
*/ */
public static ClassMapping mojClass(String mojName) throws ClassNotFoundException { public static ClassMapping mojClass(String mojName) {
return Objects.requireNonNull(CLASSES_BY_MOJ.get(mojName), "Unable to find the Mojang mapped class '" + mojName + "'"); return Objects.requireNonNull(CLASSES_BY_MOJ.get(mojName), "Unable to find the Mojang mapped class '" + mojName + "'");
} }
@ -339,7 +338,6 @@ public class NMSReflect {
* @param mojParametersType the list of parameters of the method. * @param mojParametersType the list of parameters of the method.
* Each parameter type must be an instance of one of the following type: * Each parameter type must be an instance of one of the following type:
* {@link Type}, {@link Class}, {@link ReflectClass} or {@link ClassMapping}. * {@link Type}, {@link Class}, {@link ReflectClass} or {@link ClassMapping}.
* @return
* @throws IllegalArgumentException if one of the parameter has an invalid type * @throws IllegalArgumentException if one of the parameter has an invalid type
* @throws NullPointerException if one of the parameter is null, or if there is no mapping for the provided Mojang mapped method. * @throws NullPointerException if one of the parameter is null, or if there is no mapping for the provided Mojang mapped method.
* @throws ClassNotFoundException if there is no runtime class to represent one of the provided parametersType. * @throws ClassNotFoundException if there is no runtime class to represent one of the provided parametersType.
@ -368,7 +366,6 @@ public class NMSReflect {
/** /**
* *
* @param mojName the Mojang mapped name of the field. * @param mojName the Mojang mapped name of the field.
* @return
* @throws NullPointerException if there is no mapping for the provided Mojang mapped field. * @throws NullPointerException if there is no mapping for the provided Mojang mapped field.
* @throws NoSuchFieldException if there is no runtime method to represent the provided method. * @throws NoSuchFieldException if there is no runtime method to represent the provided method.
*/ */
@ -393,9 +390,7 @@ public class NMSReflect {
String classToPrint = isObfClass ? obfName : mojName; String classToPrint = isObfClass ? obfName : mojName;
String classSimpleName = classToPrint.substring(classToPrint.lastIndexOf('.') + 1); String classSimpleName = classToPrint.substring(classToPrint.lastIndexOf('.') + 1);
String htmlTitle = classSimpleName.equals(classToPrint) ? "" : (" title='" + classToPrint + "'"); String htmlTitle = classSimpleName.equals(classToPrint) ? "" : (" title='" + classToPrint + "'");
String typeHTML = "<a href='#c" + id + "'" + htmlTitle + " class='cl'>" + classSimpleName + "</a>"; return "<a href='#c" + id + "'" + htmlTitle + " class='cl'>" + classSimpleName + "</a>";
return typeHTML;
} }
@ -420,7 +415,7 @@ public class NMSReflect {
String classToPrint = obf ? obfName : mojName; String classToPrint = obf ? obfName : mojName;
int packageSep = classToPrint.lastIndexOf('.'); int packageSep = classToPrint.lastIndexOf('.');
String classSimpleName = classToPrint.substring(packageSep + 1); String classSimpleName = classToPrint.substring(packageSep + 1);
String classPackages = classToPrint.substring(0, packageSep > 0 ? packageSep : 0); String classPackages = classToPrint.substring(0, Math.max(packageSep, 0));
String classHTML = (packageSep >= 0 ? (classPackages + ".") : "") + "<b class='cl'>" + classSimpleName + "</b>"; String classHTML = (packageSep >= 0 ? (classPackages + ".") : "") + "<b class='cl'>" + classSimpleName + "</b>";
Type superClass = superClass(obf); Type superClass = superClass(obf);
@ -487,7 +482,7 @@ public class NMSReflect {
private static record MethodId(String name, List<Type> parametersType) implements Comparable<MethodId> { private record MethodId(String name, List<Type> parametersType) implements Comparable<MethodId> {
@Override @Override
public int compareTo(MethodId o) { public int compareTo(MethodId o) {
int cmp = name.compareTo(o.name); int cmp = name.compareTo(o.name);
@ -497,14 +492,13 @@ public class NMSReflect {
} }
private String toHTML(boolean isObfClass, boolean isStatic, boolean isFinal) { private String toHTML(boolean isObfClass, boolean isStatic, boolean isFinal) {
String paramsHTML = parametersType.stream().map(p -> p.toHTML(isObfClass)).collect(Collectors.joining(", ")); String paramsHTML = parametersType.stream().map(p -> p.toHTML(isObfClass)).collect(Collectors.joining(", "));
String cl = "mtd"; String cl = "mtd";
if (isStatic) if (isStatic)
cl += " st"; cl += " st";
if (isFinal) if (isFinal)
cl += " fn"; cl += " fn";
String identifierHTML = "<span class='" + cl + "'>" + name + "</span>(" + paramsHTML + ")"; return "<span class='" + cl + "'>" + name + "</span>(" + paramsHTML + ")";
return identifierHTML;
} }
public String toString() { public String toString() {
@ -516,7 +510,7 @@ public class NMSReflect {
private static record MemberDesc<I extends Comparable<I>>(I identifier, Type returnType) { private record MemberDesc<I extends Comparable<I>>(I identifier, Type returnType) {
private String toHTML(boolean isObfClass, boolean isStatic, boolean isFinal) { private String toHTML(boolean isObfClass, boolean isStatic, boolean isFinal) {
String identifierHTML = ""; String identifierHTML = "";
if (identifier instanceof MethodId mId) if (identifier instanceof MethodId mId)
@ -541,7 +535,7 @@ public class NMSReflect {
List<Type> paramsType = new ArrayList<>(); List<Type> paramsType = new ArrayList<>();
while ((r = (char) descReader.read()) != ')') { while (((char) descReader.read()) != ')') {
descReader.skip(-1); descReader.skip(-1);
paramsType.add(Type.parse(descReader)); paramsType.add(Type.parse(descReader));
} }
@ -565,8 +559,8 @@ public class NMSReflect {
private static abstract class MemberMapping<I extends Comparable<I>, R extends ReflectMember<?, ?, ?, ?>> { private static abstract class MemberMapping<I extends Comparable<I>, R extends ReflectMember<?, ?, ?, ?>> {
private String htmlTypeChar; private final String htmlTypeChar;
/* package */ MemberDesc<I> obfDesc, mojDesc; /* package */ final MemberDesc<I> obfDesc, mojDesc;
/* package */ ClassMapping declaringClass; /* package */ ClassMapping declaringClass;
private MemberMapping(String htmlType, MemberDesc<I> obfDesc, MemberDesc<I> mojDesc) { private MemberMapping(String htmlType, MemberDesc<I> obfDesc, MemberDesc<I> mojDesc) {
htmlTypeChar = htmlType; htmlTypeChar = htmlType;

View File

@ -141,14 +141,11 @@ public class Type implements Comparable<Type> {
/* package */ static Type parse(StringReader desc) { /* package */ static Type parse(StringReader desc) {
try { try {
StringBuilder sbRaw = new StringBuilder();
int arrayDepth = 0; int arrayDepth = 0;
char c; char c;
while ((c = (char) desc.read()) == '[') { while ((c = (char) desc.read()) == '[') {
sbRaw.append(c);
arrayDepth++; arrayDepth++;
} }
sbRaw.append(c);
String type = switch(c) { String type = switch(c) {
case 'Z' -> "boolean"; case 'Z' -> "boolean";
case 'B' -> "byte"; case 'B' -> "byte";
@ -162,10 +159,8 @@ public class Type implements Comparable<Type> {
StringBuilder sbClass = new StringBuilder(); StringBuilder sbClass = new StringBuilder();
char r; char r;
while ((r = (char) desc.read()) != ';') { while ((r = (char) desc.read()) != ';') {
sbRaw.append(c);
sbClass.append(r); sbClass.append(r);
} }
sbRaw.append(c);
yield NMSReflect.binaryClassName(sbClass.toString()); yield NMSReflect.binaryClassName(sbClass.toString());
} }
default -> "void"; default -> "void";

View File

@ -1,18 +1,13 @@
package fr.pandacube.lib.paper.reflect.wrapper; package fr.pandacube.lib.paper.reflect.wrapper;
import java.util.AbstractList;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.ListIterator;
import java.util.Objects;
import java.util.function.Supplier; import java.util.function.Supplier;
import static fr.pandacube.lib.paper.reflect.wrapper.ReflectWrapper.unwrap; import fr.pandacube.lib.core.util.MappedListView;
public class ReflectListWrapper<W extends ReflectWrapperI> extends AbstractList<W> implements ReflectWrapperTypedI<List<Object>> { public class ReflectListWrapper<W extends ReflectWrapperI> extends MappedListView<Object, W> implements ReflectWrapperTypedI<List<Object>> {
private final List<Object> wrappedList;
private final Class<W> expectedWrapperClass; private final Class<W> expectedWrapperClass;
/* package */ ReflectListWrapper(Class<W> expectedWrapperClass) { /* package */ ReflectListWrapper(Class<W> expectedWrapperClass) {
@ -25,159 +20,23 @@ public class ReflectListWrapper<W extends ReflectWrapperI> extends AbstractList<
this((List<Object>) (listCreator == null ? new ArrayList<>() : listCreator.get()), expectedWrapperClass); this((List<Object>) (listCreator == null ? new ArrayList<>() : listCreator.get()), expectedWrapperClass);
} }
/* package */ ReflectListWrapper(List<Object> wrappedList, Class<W> expectedWrapperClass) { /* package */ ReflectListWrapper(List<Object> wrappedList, Class<W> expectedWrapperClass) {
this.wrappedList = Objects.requireNonNull(wrappedList); super(wrappedList, el -> ReflectWrapper.wrap(el, expectedWrapperClass), ReflectWrapper::unwrap);
this.expectedWrapperClass = expectedWrapperClass; this.expectedWrapperClass = expectedWrapperClass;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public Class<List<Object>> __getRuntimeClass() { public Class<List<Object>> __getRuntimeClass() {
return (Class<List<Object>>) wrappedList.getClass(); return (Class<List<Object>>) backend.getClass();
} }
@Override @Override
public List<Object> __getRuntimeInstance() { public List<Object> __getRuntimeInstance() {
return wrappedList; return backend;
}
private W wrap(Object el) {
return ReflectWrapper.wrap(el, expectedWrapperClass);
}
@Override
public W get(int index) {
return wrap(wrappedList.get(index));
}
@Override
public int size() {
return wrappedList.size();
}
@Override
public boolean add(W w) {
return wrappedList.add(unwrap(w));
}
@Override
public W set(int index, W element) {
return wrap(wrappedList.set(index, unwrap(element)));
}
@Override
public void add(int index, W element) {
wrappedList.add(index, unwrap(element));
}
@Override
public W remove(int index) {
return wrap(wrappedList.remove(index));
}
@Override
public int indexOf(Object o) {
return wrappedList.indexOf(o instanceof ReflectWrapperI w ? w.__getRuntimeInstance() : o);
}
@Override
public int lastIndexOf(Object o) {
return wrappedList.lastIndexOf(o instanceof ReflectWrapperI w ? w.__getRuntimeInstance() : o);
}
@Override
public void clear() {
wrappedList.clear();
}
@Override
public Iterator<W> iterator() {
return new Iterator<W>() {
final Iterator<Object> wrappedIt = wrappedList.iterator();
@Override
public boolean hasNext() {
return wrappedIt.hasNext();
}
@Override
public W next() {
return wrap(wrappedIt.next());
}
@Override
public void remove() {
wrappedIt.remove();
}
};
}
@Override
public ListIterator<W> listIterator() {
return listIterator(0);
}
@Override
public ListIterator<W> listIterator(int index) {
return new ListIterator<W>() {
final ListIterator<Object> wrappedIt = wrappedList.listIterator(index);
@Override
public boolean hasNext() {
return wrappedIt.hasNext();
}
@Override
public W next() {
return wrap(wrappedIt.next());
}
@Override
public boolean hasPrevious() {
return wrappedIt.hasPrevious();
}
@Override
public W previous() {
return wrap(wrappedIt.previous());
}
@Override
public int nextIndex() {
return wrappedIt.nextIndex();
}
@Override
public int previousIndex() {
return wrappedIt.previousIndex();
}
@Override
public void remove() {
wrappedIt.remove();
}
@Override
public void set(W w) {
wrappedIt.set(unwrap(w));
}
@Override
public void add(W w) {
wrappedIt.add(unwrap(w));
}
};
} }
@Override @Override
public List<W> subList(int fromIndex, int toIndex) { public List<W> subList(int fromIndex, int toIndex) {
return new ReflectListWrapper<>(wrappedList.subList(fromIndex, toIndex), expectedWrapperClass); return new ReflectListWrapper<>(backend.subList(fromIndex, toIndex), expectedWrapperClass);
}
@Override
public boolean equals(Object o) {
return wrappedList.equals(o);
}
@Override
public int hashCode() {
return wrappedList.hashCode();
} }
} }

View File

@ -25,6 +25,9 @@ public abstract class ReflectWrapper implements ReflectWrapperI {
public static <W extends ReflectWrapperI> W wrap(Object runtimeObj) { public static <W extends ReflectWrapperI> W wrap(Object runtimeObj) {
return wrap(runtimeObj, null); return wrap(runtimeObj, null);
} }
public static <T, W extends ReflectWrapperTypedI<T>> W wrapTyped(T runtimeObj, Class<W> expectedWrapperClass) {
return wrap(runtimeObj, expectedWrapperClass);
}
public static <W extends ReflectWrapperI> W wrap(Object runtimeObj, Class<W> expectedWrapperClass) { public static <W extends ReflectWrapperI> W wrap(Object runtimeObj, Class<W> expectedWrapperClass) {
if (runtimeObj == null) if (runtimeObj == null)
return null; return null;

View File

@ -214,23 +214,10 @@ public class WrapperRegistry {
} }
private record RegistryEntry(Class<?> runtimeClass,
Class<? extends ReflectWrapperI> wrapperClass,
Class<? extends ReflectWrapperI> concreteWrapperClass,
ReflectConstructor<? extends ReflectWrapperI> objectWrapperConstructor) {
private static class RegistryEntry {
Class<?> runtimeClass;
Class<? extends ReflectWrapperI> wrapperClass;
Class<? extends ReflectWrapperI> concreteWrapperClass;
ReflectConstructor<? extends ReflectWrapperI> objectWrapperConstructor;
public RegistryEntry(Class<?> runtimeClass, Class<? extends ReflectWrapperI> wrapperClass, Class<? extends ReflectWrapperI> concreteWrapperClass, ReflectConstructor<? extends ReflectWrapperI> objectWrapperConstructor) {
this.runtimeClass = runtimeClass;
this.wrapperClass = wrapperClass;
this.concreteWrapperClass = concreteWrapperClass;
this.objectWrapperConstructor = objectWrapperConstructor;
}
} }
} }

View File

@ -1,7 +1,6 @@
package fr.pandacube.lib.paper.reflect.wrapper.brigadier; package fr.pandacube.lib.paper.reflect.wrapper.brigadier;
import fr.pandacube.lib.core.util.Reflect; import fr.pandacube.lib.core.util.Reflect;
import fr.pandacube.lib.paper.reflect.wrapper.ReflectWrapper;
import fr.pandacube.lib.paper.reflect.wrapper.ReflectWrapperTyped; import fr.pandacube.lib.paper.reflect.wrapper.ReflectWrapperTyped;
import static fr.pandacube.lib.core.util.ThrowableUtil.wrapEx; import static fr.pandacube.lib.core.util.ThrowableUtil.wrapEx;

View File

@ -10,11 +10,11 @@ import static fr.pandacube.lib.core.util.ThrowableUtil.wrapEx;
@ConcreteWrapper(WorldVersion.__concrete.class) @ConcreteWrapper(WorldVersion.__concrete.class)
public interface WorldVersion extends ReflectWrapperI { public interface WorldVersion extends ReflectWrapperI {
public static final ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.WorldVersion")); ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.WorldVersion"));
public static class __concrete extends ReflectWrapper implements WorldVersion { class __concrete extends ReflectWrapper implements WorldVersion {
private __concrete(Object obj) { private __concrete(Object obj) {
super(obj); super(obj);
} }

View File

@ -12,8 +12,9 @@ public class BlockPosArgument extends ReflectWrapperTyped<ArgumentType<?>> {
public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.commands.arguments.coordinates.BlockPosArgument")); public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.commands.arguments.coordinates.BlockPosArgument"));
private static final Reflect.ReflectMethod<?> blockPos = wrapEx(() -> MAPPING.mojMethod("blockPos")); private static final Reflect.ReflectMethod<?> blockPos = wrapEx(() -> MAPPING.mojMethod("blockPos"));
public static ArgumentType<?> blockPos() { @SuppressWarnings("unchecked")
return (ArgumentType<?>) wrapReflectEx(() -> blockPos.invokeStatic()); public static ArgumentType<Object> blockPos() {
return (ArgumentType<Object>) wrapReflectEx(() -> blockPos.invokeStatic());
} }
protected BlockPosArgument(Object obj) { protected BlockPosArgument(Object obj) {

View File

@ -12,8 +12,9 @@ public class ComponentArgument extends ReflectWrapperTyped<ArgumentType<?>> {
public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.commands.arguments.ComponentArgument")); public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.commands.arguments.ComponentArgument"));
private static final Reflect.ReflectMethod<?> textComponent = wrapEx(() -> MAPPING.mojMethod("textComponent")); private static final Reflect.ReflectMethod<?> textComponent = wrapEx(() -> MAPPING.mojMethod("textComponent"));
public static ArgumentType<?> textComponent() { @SuppressWarnings("unchecked")
return (ArgumentType<?>) wrapReflectEx(() -> textComponent.invokeStatic()); public static ArgumentType<Object> textComponent() {
return (ArgumentType<Object>) wrapReflectEx(() -> textComponent.invokeStatic());
} }
protected ComponentArgument(Object obj) { protected ComponentArgument(Object obj) {

View File

@ -15,19 +15,19 @@ import static fr.pandacube.lib.paper.reflect.wrapper.ReflectWrapper.wrap;
@ConcreteWrapper(Coordinates.__concrete.class) @ConcreteWrapper(Coordinates.__concrete.class)
public interface Coordinates extends ReflectWrapperI { public interface Coordinates extends ReflectWrapperI {
public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.commands.arguments.coordinates.Coordinates")); NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.commands.arguments.coordinates.Coordinates"));
public static final Reflect.ReflectMethod<?> getPosition = wrapEx(() -> MAPPING.mojMethod("getPosition", CommandSourceStack.MAPPING)); Reflect.ReflectMethod<?> getPosition = wrapEx(() -> MAPPING.mojMethod("getPosition", CommandSourceStack.MAPPING));
public static final Reflect.ReflectMethod<?> getBlockPos = wrapEx(() -> MAPPING.mojMethod("getBlockPos", CommandSourceStack.MAPPING)); Reflect.ReflectMethod<?> getBlockPos = wrapEx(() -> MAPPING.mojMethod("getBlockPos", CommandSourceStack.MAPPING));
public default Vec3 getPosition(BukkitBrigadierCommandSource source) { default Vec3 getPosition(BukkitBrigadierCommandSource source) {
return wrap(wrapReflectEx(() -> getPosition.invoke(__getRuntimeInstance(), source)), Vec3.class); return wrap(wrapReflectEx(() -> getPosition.invoke(__getRuntimeInstance(), source)), Vec3.class);
} }
public default BlockPos getBlockPos(BukkitBrigadierCommandSource source) { default BlockPos getBlockPos(BukkitBrigadierCommandSource source) {
return wrap(wrapReflectEx(() -> getBlockPos.invoke(__getRuntimeInstance(), source)), BlockPos.class); return wrap(wrapReflectEx(() -> getBlockPos.invoke(__getRuntimeInstance(), source)), BlockPos.class);
} }
static class __concrete extends ReflectWrapper implements Coordinates { class __concrete extends ReflectWrapper implements Coordinates {
protected __concrete(Object obj) { protected __concrete(Object obj) {
super(obj); super(obj);
} }

View File

@ -15,20 +15,24 @@ public class EntityArgument extends ReflectWrapperTyped<ArgumentType<?>> {
private static final Reflect.ReflectMethod<?> player = wrapEx(() -> MAPPING.mojMethod("player")); private static final Reflect.ReflectMethod<?> player = wrapEx(() -> MAPPING.mojMethod("player"));
private static final Reflect.ReflectMethod<?> players = wrapEx(() -> MAPPING.mojMethod("players")); private static final Reflect.ReflectMethod<?> players = wrapEx(() -> MAPPING.mojMethod("players"));
public static ArgumentType<?> entity() { @SuppressWarnings("unchecked")
return (ArgumentType<?>) wrapReflectEx(() -> entity.invokeStatic()); public static ArgumentType<Object> entity() {
return (ArgumentType<Object>) wrapReflectEx(() -> entity.invokeStatic());
} }
public static ArgumentType<?> entities() { @SuppressWarnings("unchecked")
return (ArgumentType<?>) wrapReflectEx(() -> entities.invokeStatic()); public static ArgumentType<Object> entities() {
return (ArgumentType<Object>) wrapReflectEx(() -> entities.invokeStatic());
} }
public static ArgumentType<?> player() { @SuppressWarnings("unchecked")
return (ArgumentType<?>) wrapReflectEx(() -> player.invokeStatic()); public static ArgumentType<Object> player() {
return (ArgumentType<Object>) wrapReflectEx(() -> player.invokeStatic());
} }
public static ArgumentType<?> players() { @SuppressWarnings("unchecked")
return (ArgumentType<?>) wrapReflectEx(() -> players.invokeStatic()); public static ArgumentType<Object> players() {
return (ArgumentType<Object>) wrapReflectEx(() -> players.invokeStatic());
} }

View File

@ -12,8 +12,9 @@ public class GameProfileArgument extends ReflectWrapperTyped<ArgumentType<?>> {
public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.commands.arguments.GameProfileArgument")); public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.commands.arguments.GameProfileArgument"));
private static final Reflect.ReflectMethod<?> gameProfile = wrapEx(() -> MAPPING.mojMethod("gameProfile")); private static final Reflect.ReflectMethod<?> gameProfile = wrapEx(() -> MAPPING.mojMethod("gameProfile"));
public static ArgumentType<?> gameProfile() { @SuppressWarnings("unchecked")
return (ArgumentType<?>) wrapReflectEx(() -> gameProfile.invokeStatic()); public static ArgumentType<Object> gameProfile() {
return (ArgumentType<Object>) wrapReflectEx(() -> gameProfile.invokeStatic());
} }
protected GameProfileArgument(Object obj) { protected GameProfileArgument(Object obj) {

View File

@ -12,8 +12,9 @@ public class ResourceLocationArgument extends ReflectWrapperTyped<ArgumentType<?
public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.commands.arguments.ResourceLocationArgument")); public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.commands.arguments.ResourceLocationArgument"));
private static final Reflect.ReflectMethod<?> id = wrapEx(() -> MAPPING.mojMethod("id")); private static final Reflect.ReflectMethod<?> id = wrapEx(() -> MAPPING.mojMethod("id"));
public static ArgumentType<?> id() { @SuppressWarnings("unchecked")
return (ArgumentType<?>) wrapReflectEx(() -> id.invokeStatic()); public static ArgumentType<Object> id() {
return (ArgumentType<Object>) wrapReflectEx(() -> id.invokeStatic());
} }
protected ResourceLocationArgument(Object obj) { protected ResourceLocationArgument(Object obj) {

View File

@ -12,8 +12,9 @@ public class Vec3Argument extends ReflectWrapperTyped<ArgumentType<?>> {
public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.commands.arguments.coordinates.Vec3Argument")); public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.commands.arguments.coordinates.Vec3Argument"));
private static final Reflect.ReflectMethod<?> vec3 = wrapEx(() -> MAPPING.mojMethod("vec3", boolean.class)); private static final Reflect.ReflectMethod<?> vec3 = wrapEx(() -> MAPPING.mojMethod("vec3", boolean.class));
public static ArgumentType<?> vec3(boolean centerIntegers) { @SuppressWarnings("unchecked")
return (ArgumentType<?>) wrapReflectEx(() -> vec3.invokeStatic(centerIntegers)); public static ArgumentType<Object> vec3(boolean centerIntegers) {
return (ArgumentType<Object>) wrapReflectEx(() -> vec3.invokeStatic(centerIntegers));
} }

View File

@ -1,8 +1,6 @@
package fr.pandacube.lib.paper.reflect.wrapper.minecraft.core; package fr.pandacube.lib.paper.reflect.wrapper.minecraft.core;
import fr.pandacube.lib.core.util.Reflect;
import fr.pandacube.lib.paper.reflect.NMSReflect; import fr.pandacube.lib.paper.reflect.NMSReflect;
import fr.pandacube.lib.paper.reflect.wrapper.ReflectWrapper;
import static fr.pandacube.lib.core.util.ThrowableUtil.wrapEx; import static fr.pandacube.lib.core.util.ThrowableUtil.wrapEx;

View File

@ -12,17 +12,17 @@ import fr.pandacube.lib.paper.reflect.wrapper.ReflectWrapperI;
@ConcreteWrapper(Tag.__concrete.class) @ConcreteWrapper(Tag.__concrete.class)
public interface Tag extends ReflectWrapperI { public interface Tag extends ReflectWrapperI {
public static final ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.nbt.Tag")); ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.nbt.Tag"));
public static final ReflectMethod<?> getAsString = wrapEx(() -> MAPPING.mojMethod("getAsString")); ReflectMethod<?> getAsString = wrapEx(() -> MAPPING.mojMethod("getAsString"));
public default String getAsString() { default String getAsString() {
return wrapReflectEx(() -> (String) getAsString.invoke(__getRuntimeInstance())); return wrapReflectEx(() -> (String) getAsString.invoke(__getRuntimeInstance()));
} }
public static class __concrete extends ReflectWrapper implements Tag { class __concrete extends ReflectWrapper implements Tag {
private __concrete(Object obj) { private __concrete(Object obj) {
super(obj); super(obj);
} }

View File

@ -9,10 +9,10 @@ import static fr.pandacube.lib.core.util.ThrowableUtil.wrapEx;
@ConcreteWrapper(Component.__concrete.class) @ConcreteWrapper(Component.__concrete.class)
public interface Component extends ReflectWrapperI { public interface Component extends ReflectWrapperI {
public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.network.chat.Component")); NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.network.chat.Component"));
public class __concrete extends ReflectWrapper implements Component { class __concrete extends ReflectWrapper implements Component {
protected __concrete(Object obj) { protected __concrete(Object obj) {
super(obj); super(obj);
} }

Some files were not shown because too many files have changed in this diff Show More