Compare commits
No commits in common. "5edd8cdfec514dd88842a0400911eb893ce785db" and "69b72ef90d9b1aa8e6a773ecf18673f31958bd79" have entirely different histories.
5edd8cdfec
...
69b72ef90d
@ -3,7 +3,7 @@
|
||||
### Development library for Minecraft server applications and plugins
|
||||
|
||||
This repository contains a collection of maven modules that are used for the development of our Minecraft server. Those
|
||||
modules are made open source, so they can be used by other developers. Each of them provides different functionalities
|
||||
modules are made open source so they can be used by other developpers. Each of them provides different functionalities
|
||||
that are detailed in their respective Readme file (if any).
|
||||
|
||||
- `pandalib-util` General purpose utility and helper classes;
|
||||
@ -18,9 +18,10 @@ that are detailed in their respective Readme file (if any).
|
||||
- `pandalib-players` A library to handle classes representing online or offline players;
|
||||
- `pandalib-players-permissible` An extension of `pandalib-players` with support for the permission system `pandalib-permissions`;
|
||||
- `pandalib-netapi` A poorly designed, but working TCP network library;
|
||||
- `pandalib-net` A better-designed, packet-based TCP network library (_still in development_);
|
||||
- `pandalib-commands` An abstract command manager working on top of [Brigadier](https://github.com/Mojang/brigadier);
|
||||
- `pandalib-cli` Utility and helper classes for a standalone CLI Java application.
|
||||
- `pandalib-core` A catch-all module for some helper classes that didn't have their own module yet;
|
||||
- `pandalib-core` A catch-all module for some helper classes that didn’t have their own module yet;
|
||||
|
||||
### Use in your projects
|
||||
|
||||
|
@ -6,11 +6,10 @@ import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("CanBeFinal")
|
||||
public class BungeeBackupConfig {
|
||||
public boolean workdirBackupEnabled = true;
|
||||
public boolean logsBackupEnabled = true;
|
||||
public String scheduling = "0 2 * * *"; // cron format, here is every day at 2am
|
||||
public String scheduling = "0 2 * * *"; // cron format, here is everyday at 2am
|
||||
public File backupDirectory = null;
|
||||
public BackupCleaner workdirBackupCleaner = BackupCleaner.KEEPING_1_EVERY_N_MONTH(3).merge(BackupCleaner.KEEPING_N_LAST(5));
|
||||
public List<String> workdirIgnoreList = new ArrayList<>();
|
||||
|
@ -18,12 +18,15 @@ public class BungeeWorkdirProcess extends BackupProcess {
|
||||
|
||||
|
||||
public BiPredicate<File, String> getFilenameFilter() {
|
||||
return (file, path) -> {
|
||||
if (new File(getSourceDir(), "logs").equals(file))
|
||||
return false;
|
||||
if (file.isFile() && file.getName().endsWith(".lck"))
|
||||
return false;
|
||||
return BungeeWorkdirProcess.super.getFilenameFilter().test(file, path);
|
||||
return new BiPredicate<>() {
|
||||
@Override
|
||||
public boolean test(File file, String path) {
|
||||
if (new File(getSourceDir(), "logs").equals(file))
|
||||
return false;
|
||||
if (file.isFile() && file.getName().endsWith(".lck"))
|
||||
return false;
|
||||
return BungeeWorkdirProcess.super.getFilenameFilter().test(file, path);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -28,10 +28,10 @@ public abstract class BungeeBrigadierCommand extends BrigadierCommand<CommandSen
|
||||
/**
|
||||
* The command dispatcher.
|
||||
*/
|
||||
protected final BungeeBrigadierDispatcher dispatcher = BungeeBrigadierDispatcher.getInstance();
|
||||
protected BungeeBrigadierDispatcher dispatcher = BungeeBrigadierDispatcher.getInstance();
|
||||
|
||||
/**
|
||||
* Instantiate this command instance.
|
||||
* Instanciate this command instance.
|
||||
*/
|
||||
public BungeeBrigadierCommand() {
|
||||
LiteralCommandNode<CommandSender> commandNode;
|
||||
|
@ -39,7 +39,7 @@ public class BungeeBrigadierDispatcher extends BrigadierDispatcher<CommandSender
|
||||
*/
|
||||
public BungeeBrigadierDispatcher(Plugin pl) {
|
||||
if (instance != null)
|
||||
throw new IllegalStateException("Cannot instantiate more than one BungeeBrigadierDispatcher");
|
||||
throw new IllegalStateException("Cannot instanciante more than one BungeeBrigadierDispatcher");
|
||||
instance = this;
|
||||
plugin = pl;
|
||||
ProxyServer.getInstance().getPluginManager().registerListener(plugin, this);
|
||||
@ -47,7 +47,7 @@ public class BungeeBrigadierDispatcher extends BrigadierDispatcher<CommandSender
|
||||
|
||||
|
||||
/**
|
||||
* Called when a player sends a chat message. Used to get the typed command and execute it.
|
||||
* Called when a player sends a chat message. Used to gets the typed command and execute it.
|
||||
* @param event the event.
|
||||
*/
|
||||
@EventHandler
|
||||
|
@ -4,6 +4,7 @@ import fr.pandacube.lib.chat.Chat;
|
||||
import fr.pandacube.lib.core.mc_version.ProtocolVersion;
|
||||
import fr.pandacube.lib.players.standalone.AbstractOnlinePlayer;
|
||||
import fr.pandacube.lib.reflect.Reflect;
|
||||
import fr.pandacube.lib.util.MinecraftVersion;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import net.kyori.adventure.text.Component;
|
||||
@ -48,6 +49,16 @@ public interface BungeeOnlinePlayer extends BungeeOffPlayer, AbstractOnlinePlaye
|
||||
return getBungeeProxiedPlayer().getServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minecraft version of this player’s client.
|
||||
* @return the minecraft version of this player’s client.
|
||||
* @deprecated use {@link #getProtocolVersion()} instead.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
default MinecraftVersion getMinecraftVersion() {
|
||||
return MinecraftVersion.getVersion(getBungeeProxiedPlayer().getPendingConnection().getVersion());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the protocol version of this player’s client.
|
||||
* @return the protocol version of this player’s client.
|
||||
|
@ -9,7 +9,7 @@ import java.util.logging.Level;
|
||||
import java.util.logging.LogRecord;
|
||||
|
||||
/**
|
||||
* A log rotate that extends the functionalities of {@link DailyLogRotateFileHandler}
|
||||
* A log rotate that extends the functionnalities of {@link DailyLogRotateFileHandler}
|
||||
* to adapt with bungee specificities.
|
||||
*/
|
||||
public class BungeeDailyLogRotateFileHandler extends DailyLogRotateFileHandler {
|
||||
@ -35,10 +35,9 @@ public class BungeeDailyLogRotateFileHandler extends DailyLogRotateFileHandler {
|
||||
@Override
|
||||
public boolean isLoggable(LogRecord record) {
|
||||
String formattedRecord = getFormatter().format(record);
|
||||
return !(
|
||||
formattedRecord.contains("<-> InitialHandler has connected")
|
||||
|| formattedRecord.contains("<-> InitialHandler has pinged")
|
||||
);
|
||||
if (formattedRecord.contains("<-> InitialHandler has connected")) return false;
|
||||
if (formattedRecord.contains("<-> InitialHandler has pinged")) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,7 +23,6 @@ import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* A builder for chat components.
|
||||
@ -31,10 +30,10 @@ import org.jetbrains.annotations.NotNull;
|
||||
* Use one of the provided static methods to create a new instance.
|
||||
* <p>
|
||||
* This class implements {@link ComponentLike} and {@link HoverEventSource} so they can be used directly in
|
||||
* Adventure API and its implementation without using the final methods of this builder.
|
||||
* Adventure API and its implentation without using the final methods of this builder.
|
||||
* <p>
|
||||
* The unique possible concrete subclass of this class, {@link FormatableChat}, takes care of the formatting of the
|
||||
* built component. The rationale for this design is explained in the documentation of {@link FormatableChat}.
|
||||
* The unique possible concrete subclass of this class, {@link FormatableChat}, takes care of the formating of the
|
||||
* builded component. The rationale for this design is explained in the documentation of {@link FormatableChat}.
|
||||
*/
|
||||
public abstract sealed class Chat extends ChatStatic implements HoverEventSource<Component>, ComponentLike {
|
||||
|
||||
@ -61,7 +60,7 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource
|
||||
|
||||
/**
|
||||
* Builds the component into Adventure Component instance.
|
||||
* @return the {@link Component} built from this {@link Chat} component.
|
||||
* @return the {@link Component} builded from this {@link Chat} component.
|
||||
*/
|
||||
public Component getAdv() {
|
||||
return builder.build();
|
||||
@ -69,7 +68,7 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource
|
||||
|
||||
/**
|
||||
* Builds the component into BungeeCord {@link BaseComponent} instance.
|
||||
* @return the {@link BaseComponent} built from this {@link Chat} component.
|
||||
* @return the {@link BaseComponent} builded from this {@link Chat} component.
|
||||
*/
|
||||
public BaseComponent get() {
|
||||
return toBungee(getAdv());
|
||||
@ -77,27 +76,27 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource
|
||||
|
||||
/**
|
||||
* Builds the component into BungeeCord {@link BaseComponent} array.
|
||||
* @return the {@link BaseComponent} array built from this {@link Chat} component.
|
||||
* @return the {@link BaseComponent} array builded from this {@link Chat} component.
|
||||
*/
|
||||
public BaseComponent[] getAsArray() {
|
||||
return toBungeeArray(getAdv());
|
||||
}
|
||||
|
||||
private static final LegacyComponentSerializer LEGACY_SERIALIZER_BUNGEE_FRIENDLY = LegacyComponentSerializer.builder()
|
||||
private static final LegacyComponentSerializer LEGACY_SERIALIZER_BUNGEE_FIENDLY = LegacyComponentSerializer.builder()
|
||||
.hexColors()
|
||||
.useUnusualXRepeatedCharacterHexFormat()
|
||||
.build();
|
||||
|
||||
/**
|
||||
* Converts the built component into legacy text.
|
||||
* Converts the builded component into legacy text.
|
||||
* @return the legacy text. RGB colors are in BungeeCord format.
|
||||
*/
|
||||
public String getLegacyText() {
|
||||
return LEGACY_SERIALIZER_BUNGEE_FRIENDLY.serialize(getAdv());
|
||||
return LEGACY_SERIALIZER_BUNGEE_FIENDLY.serialize(getAdv());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the built component into plain text.
|
||||
* Converts the builded component into plain text.
|
||||
* @return the plain text of this component.
|
||||
*/
|
||||
public String getPlainText() {
|
||||
@ -105,16 +104,16 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HoverEvent<Component> asHoverEvent(@NotNull UnaryOperator<Component> op) {
|
||||
public HoverEvent<Component> asHoverEvent(UnaryOperator<Component> op) {
|
||||
return HoverEvent.showText(op.apply(getAdv()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the component into Adventure Component instance.
|
||||
* @return the {@link Component} built from this {@link Chat} component.
|
||||
* @return the {@link Component} builded from this {@link Chat} component.
|
||||
*/
|
||||
@Override
|
||||
public @NotNull Component asComponent() {
|
||||
public Component asComponent() {
|
||||
return getAdv();
|
||||
}
|
||||
|
||||
@ -285,8 +284,8 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource
|
||||
public Chat thenTranslation(String key, Object... with) { return then(translation(key, with)); }
|
||||
|
||||
/**
|
||||
* Appends a component with the provided keybinding.
|
||||
* @param key the keybinding to display.
|
||||
* Appends a component with the provided keybind.
|
||||
* @param key the keybind to display.
|
||||
* @return this.
|
||||
*/
|
||||
public Chat thenKeyBind(String key) { return then(keybind(key)); }
|
||||
@ -444,19 +443,19 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource
|
||||
|
||||
|
||||
/**
|
||||
* Appends a component filling a chat line with the configured decoration character and
|
||||
* Appends a component filling a line of chat (or console) with the configured decoration character and
|
||||
* color and a left-aligned text.
|
||||
* @param leftText the text aligned to the left.
|
||||
* @return a new {@link FormatableChat} filling a chat line with the configured decoration character
|
||||
* @return a new {@link FormatableChat} filling a line of chat (or console) with the configured decoration character
|
||||
* and color and a left-aligned text.
|
||||
*/
|
||||
public Chat thenLeftText(ComponentLike leftText) { return then(leftText(leftText, console)); }
|
||||
|
||||
/**
|
||||
* Appends a component filling a chat line with the configured decoration character and
|
||||
* Appends a component filling a line of chat (or console) with the configured decoration character and
|
||||
* color and a left-aligned text.
|
||||
* @param leftText the text aligned to the left.
|
||||
* @return a new {@link FormatableChat} filling a chat line with the configured decoration character
|
||||
* @return a new {@link FormatableChat} filling a line of chat (or console) with the configured decoration character
|
||||
* and color and a left-aligned text.
|
||||
* @deprecated uses Bungeecord chat API.
|
||||
*/
|
||||
@ -464,19 +463,19 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource
|
||||
public Chat thenLeftText(BaseComponent leftText) { return thenLeftText(chatComponent(leftText)); }
|
||||
|
||||
/**
|
||||
* Appends a component filling a chat line with the configured decoration character and
|
||||
* Appends a component filling a line of chat (or console) with the configured decoration character and
|
||||
* color and a right-aligned text.
|
||||
* @param rightText the text aligned to the right.
|
||||
* @return a new {@link FormatableChat} filling a chat line with the configured decoration character
|
||||
* @return a new {@link FormatableChat} filling a line of chat (or console) with the configured decoration character
|
||||
* and color and a right-aligned text.
|
||||
*/
|
||||
public Chat thenRightText(ComponentLike rightText) { return then(rightText(rightText, console)); }
|
||||
|
||||
/**
|
||||
* Appends a component filling a chat line with the configured decoration character and
|
||||
* Appends a component filling a line of chat (or console) with the configured decoration character and
|
||||
* color and a right-aligned text.
|
||||
* @param rightText the text aligned to the right.
|
||||
* @return a new {@link FormatableChat} filling a chat line with the configured decoration character
|
||||
* @return a new {@link FormatableChat} filling a line of chat (or console) with the configured decoration character
|
||||
* and color and a right-aligned text.
|
||||
* @deprecated uses Bungeecord chat API.
|
||||
*/
|
||||
@ -484,10 +483,10 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource
|
||||
public Chat thenRightText(BaseComponent rightText) { return thenRightText(chatComponent(rightText)); }
|
||||
|
||||
/**
|
||||
* Appends a component filling a chat line with the configured decoration character and
|
||||
* Appends a component filling a line of chat (or console) with the configured decoration character and
|
||||
* color and a centered text.
|
||||
* @param centerText the text aligned to the center.
|
||||
* @return a new {@link FormatableChat} filling a chat line with the configured decoration character
|
||||
* @return a new {@link FormatableChat} filling a line of chat (or console) with the configured decoration character
|
||||
* and color and a centered text.
|
||||
*/
|
||||
public Chat thenCenterText(ComponentLike centerText) {
|
||||
@ -495,10 +494,10 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a component filling a chat line with the configured decoration character and
|
||||
* Appends a component filling a line of chat (or console) with the configured decoration character and
|
||||
* color and a centered text.
|
||||
* @param centerText the text aligned to the center.
|
||||
* @return a new {@link FormatableChat} filling a chat line with the configured decoration character
|
||||
* @return a new {@link FormatableChat} filling a line of chat (or console) with the configured decoration character
|
||||
* and color and a centered text.
|
||||
* @deprecated uses Bungeecord chat API.
|
||||
*/
|
||||
@ -508,8 +507,8 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a component filling a chat line with the configured decoration character and color.
|
||||
* @return a new {@link FormatableChat} filling a chat line with a decoration character and color.
|
||||
* Appends a component filling a line of chat (or console) with the configured decoration character and color.
|
||||
* @return a new {@link FormatableChat} filling a line of chat (or console) with a decoration character and color.
|
||||
*/
|
||||
public Chat thenFilledLine() { return then(filledLine(console)); }
|
||||
|
||||
@ -535,11 +534,11 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource
|
||||
* .append("!").color(ChatColor.RED)
|
||||
* .create();
|
||||
* }</pre>
|
||||
* Here, when you call a formatting method (like {@code bold(boolean)} or {@code color(ChatColor)}) after the
|
||||
* {@code append(String)} method, the formatting apply to the last subcomponent appended.
|
||||
* Here, when you call a formating method (like {@code bold(boolean)} or {@code color(ChatColor)}) after the
|
||||
* {@code append(String)} method, the formating apply to the last sub-component appended.
|
||||
* <p>
|
||||
* In our design, we want the formatting to apply to the currently built component, not the last appended one.
|
||||
* The purpose is to make the component structure clearer and have better control of the formatting over the
|
||||
* In our design, we want the formating to apply to the currently builded component, not the last appended one.
|
||||
* The purpose is to make the component structure clearer and have better control of the formating over the
|
||||
* component hierarchy.
|
||||
* Here is the equivalent of the above code, with the {@link Chat} API:
|
||||
* <pre>{@code
|
||||
@ -548,9 +547,9 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource
|
||||
* .thenText("!"); // short for .then(Chat.text("!"))
|
||||
* // the red color for "!" is not needed because the parent component is already red.
|
||||
* }</pre>
|
||||
* When calling {@link #then(Component) #then(...)} on a {@link FormatableChat}, the method returns itself, cast
|
||||
* to {@link Chat}, to prevent future formatting (that the programmer would think it formats the previously appended
|
||||
* subcomponent). If the formatting of the currently built component is needed, since {@link Chat} is a sealed
|
||||
* When calling {@link #then(Component) #then(...)} on a {@link FormatableChat}, the method returns itself, casted
|
||||
* to {@link Chat}, to prevent future formating (that the programmer would think it formats the previously appended
|
||||
* sub-component). If the formatting of the currently builded component is needed, since {@link Chat} is a sealed
|
||||
* class which only subclass is {@link FormatableChat}, you can cast the builder, and use the format methods again.
|
||||
* <pre>{@code
|
||||
* Chat component = Chat.text("Hello ").red()
|
||||
@ -987,7 +986,7 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource
|
||||
}
|
||||
|
||||
/**
|
||||
* Force the italic formatting to be set to false if it is not explicitly set in the component.
|
||||
* Force the italic formating to be set to false if it is not explicitely set in the component.
|
||||
* This is useful for item lores that defaults to italic in the game UI.
|
||||
* @param c the {@link Chat} in which to set the italic property if needed.
|
||||
* @return the provided {@link Chat} instance.
|
||||
|
@ -6,7 +6,7 @@ import java.util.List;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
|
||||
/**
|
||||
* A custom gradient with at least 2 colors in it.
|
||||
* A custom gradient with a least 2 colors in it.
|
||||
*/
|
||||
public class ChatColorGradient {
|
||||
private record GradientColor(float location, TextColor color) { }
|
||||
|
@ -14,7 +14,7 @@ public class ChatColorUtil {
|
||||
|
||||
|
||||
/**
|
||||
* All characters that represent a color code.
|
||||
* All characters that represent a colorcode.
|
||||
*/
|
||||
public static final String ALL_COLORS = "0123456789AaBbCcDdEeFf";
|
||||
/**
|
||||
@ -30,7 +30,7 @@ public class ChatColorUtil {
|
||||
* Returns 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.
|
||||
* The RGB value from EssentialsX format is converted to BungeeCord Chat when included in the returned value.
|
||||
* @param legacyText the legacy formatted text.
|
||||
* @param legacyText the legacy formated text.
|
||||
* @return the active format at the end of the provided text.
|
||||
*/
|
||||
public static String getLastColors(String legacyText) {
|
||||
@ -84,8 +84,8 @@ public class ChatColorUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ChatColor} associated with the provided char, case-insensitive.
|
||||
* @param code the case-insensitive char code.
|
||||
* Returns the {@link ChatColor} associated with the provided char, case insensitive.
|
||||
* @param code the case insensitive char code.
|
||||
* @return the corresponding {@link ChatColor}.
|
||||
*/
|
||||
public static ChatColor getChatColorByChar(char code) {
|
||||
|
@ -8,7 +8,6 @@ import net.kyori.adventure.text.format.TextColor;
|
||||
/**
|
||||
* Class holding static configuration values for chat component rendering.
|
||||
*/
|
||||
@SuppressWarnings("CanBeFinal")
|
||||
public class ChatConfig {
|
||||
|
||||
/**
|
||||
@ -30,7 +29,7 @@ public class ChatConfig {
|
||||
/**
|
||||
* The color used for successful messages.
|
||||
*/
|
||||
public static TextColor successColor = PandaTheme.CHAT_GREEN_MAX_SAT;
|
||||
public static TextColor successColor = PandaTheme.CHAT_GREEN_SATMAX;
|
||||
|
||||
/**
|
||||
* The color used for error/failure messages.
|
||||
@ -68,14 +67,14 @@ public class ChatConfig {
|
||||
public static TextColor highlightedCommandColor = NamedTextColor.WHITE;
|
||||
|
||||
/**
|
||||
* The color used for broadcast messages.
|
||||
* The color used for broadcasted messages.
|
||||
* It is often used in combination with {@link #prefix}.
|
||||
*/
|
||||
public static TextColor broadcastColor = NamedTextColor.YELLOW;
|
||||
|
||||
/**
|
||||
* The prefix used for prefixed messages.
|
||||
* It can be a stylized name of the server, like {@code "[Pandacube] "}.
|
||||
* It can be a sylized name of the server, like {@code "[Pandacube] "}.
|
||||
* It is often used in combination with {@link #broadcastColor}.
|
||||
*/
|
||||
public static Supplier<Chat> prefix = PandaTheme::CHAT_MESSAGE_PREFIX;
|
||||
@ -105,7 +104,7 @@ public class ChatConfig {
|
||||
public static final TextColor CHAT_GREEN_4 = TextColor.fromHexString("#abe3b0"); // h=126 s=50 l=78
|
||||
|
||||
/** Green max saturation color. */
|
||||
public static final TextColor CHAT_GREEN_MAX_SAT = TextColor.fromHexString("#00ff19"); // h=126 s=100 l=50
|
||||
public static final TextColor CHAT_GREEN_SATMAX = TextColor.fromHexString("#00ff19"); // h=126 s=100 l=50
|
||||
/** Green 1 saturated color. */
|
||||
public static final TextColor CHAT_GREEN_1_SAT = TextColor.fromHexString("#20d532"); // h=126 s=50 l=48
|
||||
/** Green 2 saturated color. */
|
||||
|
@ -140,7 +140,7 @@ public class ChatFilledLine implements ComponentLike {
|
||||
|
||||
/**
|
||||
* Renders this line to a {@link FormatableChat}.
|
||||
* @return a new {@link FormatableChat} built by this {@link ChatFilledLine}.
|
||||
* @return a new {@link FormatableChat} builded by this {@link ChatFilledLine}.
|
||||
*/
|
||||
public FormatableChat toChat() {
|
||||
int maxWidth = (this.maxWidth != null)
|
||||
|
@ -227,9 +227,9 @@ public abstract class ChatStatic {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link FormatableChat} with the provided keybinding.
|
||||
* @param key the keybinding to display.
|
||||
* @return a new {@link FormatableChat} with the provided keybinding.
|
||||
* Creates a {@link FormatableChat} with the provided keybind.
|
||||
* @param key the keybind to display.
|
||||
* @return a new {@link FormatableChat} with the provided keybind.
|
||||
*/
|
||||
public static FormatableChat keybind(String key) {
|
||||
return new FormatableChat(Component.keybind().keybind(key));
|
||||
@ -451,12 +451,12 @@ public abstract class ChatStatic {
|
||||
|
||||
|
||||
/**
|
||||
* Creates a {@link FormatableChat} filling a chat line with decoration and a left-aligned text.
|
||||
* Creates a {@link FormatableChat} filling a line of chat (or console) with decoration and a left-aligned text.
|
||||
* @param text the text aligned to the left.
|
||||
* @param decorationChar the character used for decoration around the text.
|
||||
* @param decorationColor the color used for the decoration characters.
|
||||
* @param console if the line is rendered on console (true) or IG (false).
|
||||
* @return a new {@link FormatableChat} filling a chat line with decoration and a left-aligned text.
|
||||
* @return a new {@link FormatableChat} filling a line of chat (or console) with decoration and a left-aligned text.
|
||||
* @see ChatFilledLine#leftText(ComponentLike)
|
||||
*/
|
||||
public static FormatableChat leftText(ComponentLike text, char decorationChar, TextColor decorationColor, boolean console) {
|
||||
@ -464,11 +464,11 @@ public abstract class ChatStatic {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link FormatableChat} filling a chat line with the configured decoration character and
|
||||
* Creates a {@link FormatableChat} filling a line of chat (or console) with the configured decoration character and
|
||||
* color and a left-aligned text.
|
||||
* @param text the text aligned to the left.
|
||||
* @param console if the line is rendered on console (true) or IG (false).
|
||||
* @return a new {@link FormatableChat} filling a chat line with the configured decoration character
|
||||
* @return a new {@link FormatableChat} filling a line of chat (or console) with the configured decoration character
|
||||
* and color and a left-aligned text.
|
||||
* @see ChatFilledLine#leftText(ComponentLike)
|
||||
* @see ChatConfig#decorationChar
|
||||
@ -479,12 +479,12 @@ public abstract class ChatStatic {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link FormatableChat} filling a chat line with decoration and a right-aligned text.
|
||||
* Creates a {@link FormatableChat} filling a line of chat (or console) with decoration and a right-aligned text.
|
||||
* @param text the text aligned to the right.
|
||||
* @param decorationChar the character used for decoration around the text.
|
||||
* @param decorationColor the color used for the decoration characters.
|
||||
* @param console if the line is rendered on console (true) or IG (false).
|
||||
* @return a new {@link FormatableChat} filling a chat line with decoration and a right-aligned
|
||||
* @return a new {@link FormatableChat} filling a line of chat (or console) with decoration and a right-aligned
|
||||
* text.
|
||||
* @see ChatFilledLine#rightText(ComponentLike)
|
||||
*/
|
||||
@ -493,11 +493,11 @@ public abstract class ChatStatic {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link FormatableChat} filling a chat line with the configured decoration character and
|
||||
* Creates a {@link FormatableChat} filling a line of chat (or console) with the configured decoration character and
|
||||
* color and a right-aligned text.
|
||||
* @param text the text aligned to the right.
|
||||
* @param console if the line is rendered on console (true) or IG (false).
|
||||
* @return a new {@link FormatableChat} filling a chat line with the configured decoration character
|
||||
* @return a new {@link FormatableChat} filling a line of chat (or console) with the configured decoration character
|
||||
* and color and a right-aligned text.
|
||||
* @see ChatFilledLine#rightText(ComponentLike)
|
||||
* @see ChatConfig#decorationChar
|
||||
@ -508,12 +508,12 @@ public abstract class ChatStatic {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link FormatableChat} filling a chat line with decoration and a centered text.
|
||||
* Creates a {@link FormatableChat} filling a line of chat (or console) with decoration and a centered text.
|
||||
* @param text the text aligned to the center.
|
||||
* @param decorationChar the character used for decoration around the text.
|
||||
* @param decorationColor the color used for the decoration characters.
|
||||
* @param console if the line is rendered on console (true) or IG (false).
|
||||
* @return a new {@link FormatableChat} filling a chat line with decoration and a centered text.
|
||||
* @return a new {@link FormatableChat} filling a line of chat (or console) with decoration and a centered text.
|
||||
* @see ChatFilledLine#centerText(ComponentLike)
|
||||
*/
|
||||
public static FormatableChat centerText(ComponentLike text, char decorationChar, TextColor decorationColor, boolean console) {
|
||||
@ -521,11 +521,11 @@ public abstract class ChatStatic {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link FormatableChat} filling a chat line with the configured decoration character and
|
||||
* Creates a {@link FormatableChat} filling a line of chat (or console) with the configured decoration character and
|
||||
* color and a centered text.
|
||||
* @param text the text aligned to the center.
|
||||
* @param console if the line is rendered on console (true) or IG (false).
|
||||
* @return a new {@link FormatableChat} filling a chat line with the configured decoration character
|
||||
* @return a new {@link FormatableChat} filling a line of chat (or console) with the configured decoration character
|
||||
* and color and a centered text.
|
||||
* @see ChatFilledLine#centerText(ComponentLike)
|
||||
* @see ChatConfig#decorationChar
|
||||
@ -536,11 +536,11 @@ public abstract class ChatStatic {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link FormatableChat} filling a chat line with a decoration character and color.
|
||||
* Creates a {@link FormatableChat} filling a line of chat (or console) with a decoration character and color.
|
||||
* @param decorationChar the character used for decoration.
|
||||
* @param decorationColor the color used for the decoration characters.
|
||||
* @param console if the line is rendered on console (true) or IG (false).
|
||||
* @return a new {@link FormatableChat} filling a chat line with a decoration character and color.
|
||||
* @return a new {@link FormatableChat} filling a line of chat (or console) with a decoration character and color.
|
||||
* @see ChatFilledLine#filled()
|
||||
*/
|
||||
public static FormatableChat filledLine(char decorationChar, TextColor decorationColor, boolean console) {
|
||||
@ -548,10 +548,10 @@ public abstract class ChatStatic {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link FormatableChat} filling a chat line with the configured decoration character and
|
||||
* Creates a {@link FormatableChat} filling a line of chat (or console) with the configured decoration character and
|
||||
* color.
|
||||
* @param console if the line is rendered on console (true) or IG (false).
|
||||
* @return a new {@link FormatableChat} filling a chat line with a decoration character and color.
|
||||
* @return a new {@link FormatableChat} filling a line of chat (or console) with a decoration character and color.
|
||||
* @see ChatFilledLine#filled()
|
||||
* @see ChatConfig#decorationChar
|
||||
* @see ChatConfig#decorationColor
|
||||
@ -633,7 +633,7 @@ public abstract class ChatStatic {
|
||||
.storage(((StorageNBTComponent) c).storage());
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Unknown component type " + c.getClass());
|
||||
throw new IllegalArgumentException("Unknows component type " + c.getClass());
|
||||
}
|
||||
return builder.style(c.style()).append(c.children());
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ public class ChatTreeNode {
|
||||
public final List<ChatTreeNode> children = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Construct a new {@link ChatTreeNode}.
|
||||
* Construct an new {@link ChatTreeNode}.
|
||||
* @param cmp the component for the current node.
|
||||
*/
|
||||
public ChatTreeNode(Chat cmp) {
|
||||
@ -48,7 +48,7 @@ public class ChatTreeNode {
|
||||
* Generate a tree view based on this tree structure.
|
||||
* <p>
|
||||
* Each element in the returned list represent 1 line of this tree view.
|
||||
* Thus, the caller may send each line separately or at once, depending on the quantity of data.
|
||||
* Thus, the caller may send each line separately or at once depending of the quantity of data.
|
||||
* @param console true to render for console, false otherwise.
|
||||
* @return an array of component, each element being a single line.
|
||||
*/
|
||||
|
@ -22,7 +22,7 @@ import net.md_5.bungee.api.ChatColor;
|
||||
import fr.pandacube.lib.chat.Chat.FormatableChat;
|
||||
|
||||
/**
|
||||
* Provides various methods and properties to manipulate text displayed in chat and other parts of the game.
|
||||
* Provides various methods and properties to manipulate text displayed in chat an other parts of the game.
|
||||
*/
|
||||
public class ChatUtil {
|
||||
|
||||
@ -48,7 +48,7 @@ public class ChatUtil {
|
||||
|
||||
/**
|
||||
* Mapping indicating the text pixel with for specific characters in the default Minecraft font.
|
||||
* If a character doesn't have a mapping in this map, then its width is {@link #DEFAULT_CHAR_SIZE}.
|
||||
* If a character doesn’t have a mapping in this map, then its width is {@link #DEFAULT_CHAR_SIZE}.
|
||||
*/
|
||||
public static final Map<Character, Integer> CHAR_SIZES;
|
||||
static {
|
||||
@ -112,7 +112,7 @@ public class ChatUtil {
|
||||
* @param nbPages the number of pages.
|
||||
* @param nbPagesToDisplay the number of pages to display around the first page, the last page and the
|
||||
* {@code currentPage}.
|
||||
* @return a {@link Chat} containing the created page navigator.
|
||||
* @return a {@link Chat} containging the created page navigator.
|
||||
*/
|
||||
public static Chat createPagination(String prefix, String cmdFormat, int currentPage, int nbPages, int nbPagesToDisplay) {
|
||||
Set<Integer> pagesToDisplay = new TreeSet<>();
|
||||
@ -149,11 +149,11 @@ public class ChatUtil {
|
||||
else
|
||||
first = false;
|
||||
|
||||
FormatableChat pDisplay = Chat.clickableCommand(Chat.text(page), String.format(cmdFormat, page), Chat.text("Aller à la page " + page));
|
||||
FormatableChat pDisp = Chat.clickableCommand(Chat.text(page), String.format(cmdFormat, page), Chat.text("Aller à la page " + page));
|
||||
if (page == currentPage) {
|
||||
pDisplay.highlightedCommandColor();
|
||||
pDisp.highlightedCommandColor();
|
||||
}
|
||||
d.then(pDisplay);
|
||||
d.then(pDisp);
|
||||
|
||||
previous = page;
|
||||
}
|
||||
@ -258,7 +258,7 @@ public class ChatUtil {
|
||||
|
||||
|
||||
/**
|
||||
* Wraps the provided text in multiple lines, taking into account the legacy formatting.
|
||||
* Wraps the provided text in multiple lines, taking into account the legacy formating.
|
||||
* <p>
|
||||
* This method only takes into account IG text width. Use a regular text-wrapper for console instead.
|
||||
* @param legacyText the text to wrap.
|
||||
@ -272,7 +272,7 @@ public class ChatUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the provided text in multiple lines, taking into account the legacy formatting.
|
||||
* Wraps the provided text in multiple lines, taking into account the legacy formating.
|
||||
* <p>
|
||||
* This method only takes into account IG text width. Use a regular text-wrapper for console instead.
|
||||
* @param legacyText the text to wrap.
|
||||
@ -369,7 +369,7 @@ public class ChatUtil {
|
||||
|
||||
/**
|
||||
* Try to render a matrix of {@link Chat} components into a table in the chat or console.
|
||||
* @param data the component, in the form of {@link List} of {@link List} of {@link Chat}. The parent list holds
|
||||
* @param data the component, in the form of {@link List} of {@link List} of {@link Chat}. The englobing list holds
|
||||
* the table lines (line 0 being the top line). Each sublist holds the cells content (element 0 is the
|
||||
* leftText one). The row lengths can be different.
|
||||
* @param space a spacer to put between columns.
|
||||
@ -392,7 +392,7 @@ public class ChatUtil {
|
||||
|
||||
/**
|
||||
* Try to render a matrix of {@link Component} components into a table in the chat or console.
|
||||
* @param data the component, in the form of {@link List} of {@link List} of {@link Component}. The parent list holds
|
||||
* @param data the component, in the form of {@link List} of {@link List} of {@link Component}. The englobing list holds
|
||||
* the table lines (line 0 being the top line). Each sublist holds the cells content (element 0 is the
|
||||
* leftText one). The row lengths can be different.
|
||||
* @param space a spacer to put between columns.
|
||||
@ -505,9 +505,9 @@ public class ChatUtil {
|
||||
private static final char PROGRESS_BAR_FULL_CHAR = '|';
|
||||
|
||||
/**
|
||||
* Generate a (eventually multipart) progress bar using text.
|
||||
* Generate a (eventually multi-part) progress bar using text.
|
||||
* @param values the values to render in the progress bar.
|
||||
* @param colors the colors attributed to each value.
|
||||
* @param colors the colors attributed to each values.
|
||||
* @param total the total value of the progress bar.
|
||||
* @param width the width in which the progress bar should fit (in pixel for IG, in character count for console)
|
||||
* @param console true if the progress bar is intended to be displayed on the console, false if it’s in game chat.
|
||||
|
@ -11,7 +11,7 @@ import org.fusesource.jansi.AnsiConsole;
|
||||
import fr.pandacube.lib.util.Log;
|
||||
|
||||
/**
|
||||
* Class to handle general standard IO operation for a CLI application. It uses Jline’s {@link ConsoleReader} for the
|
||||
* Class to hangle general standard IO operation for a CLI application. It uses Jline’s {@link ConsoleReader} for the
|
||||
* console rendering, a JUL {@link Logger} for logging, and Brigadier to handle commands.
|
||||
*/
|
||||
public class CLI extends Thread {
|
||||
@ -33,7 +33,7 @@ public class CLI extends Thread {
|
||||
reader.setPrompt(">");
|
||||
reader.addCompleter(CLIBrigadierDispatcher.instance);
|
||||
|
||||
// configure logger's formatter
|
||||
// configuration du formatteur pour le logger
|
||||
System.setProperty("net.md_5.bungee.log-date-format", "yyyy-MM-dd HH:mm:ss");
|
||||
logger = CLILogger.getLogger(this);
|
||||
}
|
||||
|
@ -64,7 +64,6 @@ public abstract class CLIApplication {
|
||||
private final Object stopLock = new Object();
|
||||
private final AtomicBoolean stopping = new AtomicBoolean(false);
|
||||
|
||||
@SuppressWarnings("finally")
|
||||
public final void stop() {
|
||||
synchronized (stopLock) {
|
||||
synchronized (stopping) {
|
||||
|
@ -15,7 +15,7 @@ import java.util.function.Predicate;
|
||||
public abstract class CLIBrigadierCommand extends BrigadierCommand<CLICommandSender> {
|
||||
|
||||
/**
|
||||
* Instantiate this command instance.
|
||||
* Instanciate this command instance.
|
||||
*/
|
||||
public CLIBrigadierCommand() {
|
||||
LiteralCommandNode<CLICommandSender> commandNode = buildCommand().build();
|
||||
|
@ -27,7 +27,7 @@ public class CLIBrigadierDispatcher extends BrigadierDispatcher<CLICommandSender
|
||||
|
||||
/**
|
||||
* Executes the provided command as the console.
|
||||
* @param commandWithoutSlash the command, without the eventual slash at the beginning.
|
||||
* @param commandWithoutSlash the command, without the eventual slash at the begining.
|
||||
* @return the value returned by the executed command.
|
||||
*/
|
||||
public int execute(String commandWithoutSlash) {
|
||||
|
@ -4,7 +4,6 @@ import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.audience.MessageType;
|
||||
import net.kyori.adventure.identity.Identity;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* A command sender.
|
||||
@ -42,5 +41,5 @@ public interface CLICommandSender extends Audience {
|
||||
void sendMessage(String message);
|
||||
|
||||
@Override // force implementation of super-interface default method
|
||||
void sendMessage(@NotNull Identity source, @NotNull Component message, @NotNull MessageType type);
|
||||
void sendMessage(Identity source, Component message, MessageType type);
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ import fr.pandacube.lib.util.Log;
|
||||
import net.kyori.adventure.audience.MessageType;
|
||||
import net.kyori.adventure.identity.Identity;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* The console command sender.
|
||||
@ -32,7 +31,7 @@ public class CLIConsoleCommandSender implements CLICommandSender {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(@NotNull Identity source, @NotNull Component message, @NotNull MessageType type) {
|
||||
public void sendMessage(Identity source, Component message, MessageType type) {
|
||||
sendMessage(Chat.chatComponent(message).getLegacyText());
|
||||
}
|
||||
}
|
||||
|
@ -170,13 +170,13 @@ public class CommandAdmin extends CLIBrigadierCommand {
|
||||
}
|
||||
|
||||
|
||||
ChatTreeNode displayTree = new ChatTreeNode(d);
|
||||
ChatTreeNode dispTree = new ChatTreeNode(d);
|
||||
|
||||
for (DisplayCommandNode child : displayNode.children) {
|
||||
displayTree.addChild(buildDisplayTree(child, sender));
|
||||
dispTree.addChild(buildDisplayTree(child, sender));
|
||||
}
|
||||
|
||||
return displayTree;
|
||||
return dispTree;
|
||||
|
||||
}
|
||||
|
||||
@ -257,8 +257,8 @@ public class CommandAdmin extends CLIBrigadierCommand {
|
||||
|
||||
|
||||
private static class DisplayCommandNode {
|
||||
final List<CommandNode<CLICommandSender>> nodes = new ArrayList<>();
|
||||
final List<DisplayCommandNode> children = new ArrayList<>();
|
||||
List<CommandNode<CLICommandSender>> nodes = new ArrayList<>();
|
||||
List<DisplayCommandNode> children = new ArrayList<>();
|
||||
|
||||
void addInline(CommandNode<CLICommandSender> node) {
|
||||
nodes.add(node);
|
||||
|
@ -25,7 +25,7 @@ public class CLILogger {
|
||||
/**
|
||||
* Initialize and return the logger for this application.
|
||||
* @param cli the CLI instance to use
|
||||
* @return the logger for this application.
|
||||
* @return the logger of this application.
|
||||
*/
|
||||
public static synchronized Logger getLogger(CLI cli) {
|
||||
if (logger == null) {
|
||||
|
@ -29,7 +29,7 @@ public abstract class BrigadierCommand<S> {
|
||||
* Returns a builder for this command.
|
||||
* Concrete class should include any element in the builder that is needed to build the command (sub-commands and
|
||||
* arguments, requirements, redirection, ...).
|
||||
* If any of the sub-commands and arguments needs to know the {@link LiteralCommandNode} built from the returned
|
||||
* If any of the sub-commands and arguments needs to know the {@link LiteralCommandNode} builded from the returned
|
||||
* {@link LiteralArgumentBuilder}, this can be done by overriding {@link #postBuildCommand(LiteralCommandNode)}.
|
||||
* @return a builder for this command.
|
||||
*/
|
||||
@ -37,16 +37,16 @@ public abstract class BrigadierCommand<S> {
|
||||
|
||||
/**
|
||||
* Method to override if the reference to the command node has to be known when building the subcommands.
|
||||
* @param commandNode the command node built from {@link #buildCommand()}.
|
||||
* @param commandNode the command node builded from {@link #buildCommand()}.
|
||||
*/
|
||||
protected void postBuildCommand(LiteralCommandNode<S> commandNode) {
|
||||
// default implementation does nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to override if this command has any aliases.
|
||||
* Method to override if this command have any aliases.
|
||||
* @return an array of string corresponding to the aliases. This must not include the orignal command name (that
|
||||
* is the name of the literal command node built from {@link #buildCommand()}).
|
||||
* is the name of the literal command node builded from {@link #buildCommand()}).
|
||||
*/
|
||||
protected String[] getAliases() {
|
||||
return new String[0];
|
||||
|
@ -13,7 +13,7 @@ import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* Abstract class that holds a Brigadier {@link CommandDispatcher} instance.
|
||||
* Subclasses contain logic to integrate this commands dispatcher into their environment (like Bungee or CLI app).
|
||||
* Subclasses contains logic to integrate this commands dispatcher into their environment (like Bungee or CLI app).
|
||||
* @param <S> the command source (or command sender) type.
|
||||
*/
|
||||
public abstract class BrigadierDispatcher<S> {
|
||||
@ -43,7 +43,7 @@ public abstract class BrigadierDispatcher<S> {
|
||||
/**
|
||||
* Executes the provided command as the provided sender.
|
||||
* @param sender the command sender.
|
||||
* @param commandWithoutSlash the command, without the eventual slash at the beginning.
|
||||
* @param commandWithoutSlash the command, without the eventual slash at the begining.
|
||||
* @return the value returned by the executed command.
|
||||
*/
|
||||
public int execute(S sender, String commandWithoutSlash) {
|
||||
|
@ -18,7 +18,7 @@ import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* Utility methods to replace some functionalities of Brigadier, especially suggestion sorting that we don’t like.
|
||||
* Utility methods to replace some functionalities of Brigadier, especialy suggestion sorting that we don’t like.
|
||||
*/
|
||||
public class BrigadierSuggestionsUtil {
|
||||
|
||||
|
@ -14,7 +14,7 @@ import java.util.stream.LongStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Functional interface providing suggestions for an argument of a command.
|
||||
* Functionnal interface providing suggestions for an argument of a command.
|
||||
* @param <S> the type of the command sender.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
@ -66,7 +66,7 @@ public interface SuggestionsSupplier<S> {
|
||||
* Filter the provided {@link Stream} of string according to the provided token, using the filter returned by {@link #filter(String)},
|
||||
* then returns the strings collected into a {@link List}.
|
||||
* <p>
|
||||
* This method consume the provided stream, so will not be usable anymore.
|
||||
* This methods consume the provided stream, so will not be usable anymore.
|
||||
* @param stream the stream to filter and collet.
|
||||
* @param token the token to consider for filtering.
|
||||
* @return the stream, filtered and collected into a {@link List}.
|
||||
@ -505,7 +505,7 @@ public interface SuggestionsSupplier<S> {
|
||||
/**
|
||||
* Creates 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.
|
||||
* @param other another {@link SuggestionsSupplier} to fall back to.
|
||||
* @param other another {@link SuggestionsSupplier} to fallback to.
|
||||
* @return a new {@link SuggestionsSupplier}.
|
||||
*/
|
||||
default SuggestionsSupplier<S> orIfEmpty(SuggestionsSupplier<S> other) {
|
||||
|
@ -18,7 +18,7 @@ import static fr.pandacube.lib.chat.ChatStatic.text;
|
||||
|
||||
/**
|
||||
* Cleanup a backup directory (i.e. removes old backup archives).
|
||||
* It is possible to combine different instances to affect which archive to keep or delete.
|
||||
* It is possible to combine differents instances to affect which archive to keep or delete.
|
||||
*/
|
||||
public abstract class BackupCleaner implements UnaryOperator<TreeSet<LocalDateTime>> {
|
||||
|
||||
@ -48,7 +48,7 @@ public abstract class BackupCleaner implements UnaryOperator<TreeSet<LocalDateTi
|
||||
* formula <code><i>YEAR</i> * (12 / <i>n</i>) + <i>MONTH</i> / <i>n</i></code>. It then keeps the first archive
|
||||
* found in each section.
|
||||
*
|
||||
* @param n the interval in month between each kept archives. Must be a divider of 12 (1, 2, 3, 4, 6 or 12).
|
||||
* @param n the interval in month between each kept archives. Must be a dividor of 12 (1, 2, 3, 4, 6 or 12).
|
||||
* @return a {@link BackupCleaner} that keeps one archive every n month.
|
||||
*/
|
||||
public static BackupCleaner KEEPING_1_EVERY_N_MONTH(int n) {
|
||||
@ -94,13 +94,11 @@ public abstract class BackupCleaner implements UnaryOperator<TreeSet<LocalDateTi
|
||||
|
||||
/**
|
||||
* Performs the cleanup operation on the provided directory.
|
||||
* @param archiveDir the backup directory to clean up.
|
||||
* @param compressDisplayName the display name of the backup process that manages the backup directory. Used for logs.
|
||||
* @param archiveDir the backup directory to cleanup.
|
||||
* @param compressDisplayName the displayname of the backup process that manages the backup directory. Used for logs.
|
||||
*/
|
||||
public void cleanupArchives(File archiveDir, String compressDisplayName) {
|
||||
String[] files = archiveDir.list();
|
||||
if (files == null)
|
||||
return;
|
||||
|
||||
Log.info("[Backup] Cleaning up backup directory " + ChatColor.GRAY + compressDisplayName + ChatColor.RESET + "...");
|
||||
|
||||
|
@ -33,7 +33,7 @@ public class BackupManager extends TimerTask {
|
||||
private final Timer schedulerTimer = new Timer();
|
||||
|
||||
/**
|
||||
* Instantiate a new backup manager.
|
||||
* Instanciate a new backup manager.
|
||||
* @param backupDirectory the root backup directory.
|
||||
*/
|
||||
public BackupManager(File backupDirectory) {
|
||||
|
@ -35,12 +35,12 @@ public abstract class BackupProcess implements Comparable<BackupProcess>, Runnab
|
||||
|
||||
|
||||
private boolean enabled = true;
|
||||
private String scheduling = "0 2 * * *"; // cron format, here is every day at 2am
|
||||
private String scheduling = "0 2 * * *"; // cron format, here is everyday at 2am
|
||||
private BackupCleaner backupCleaner = null;
|
||||
private List<String> ignoreList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Instantiates a new backup process.
|
||||
* Instanciates a new backup process.
|
||||
* @param bm the associated backup manager.
|
||||
* @param n the process identifier.
|
||||
*/
|
||||
@ -66,9 +66,9 @@ public abstract class BackupProcess implements Comparable<BackupProcess>, Runnab
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the display name of this process.
|
||||
* Gets the displayname of this process.
|
||||
* Default implementation returns {@link #getIdentifier()}.
|
||||
* @return the display name of this process.
|
||||
* @return the displayname of this process.
|
||||
*/
|
||||
protected String getDisplayName() {
|
||||
return getIdentifier();
|
||||
@ -105,8 +105,8 @@ public abstract class BackupProcess implements Comparable<BackupProcess>, Runnab
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the source directory to back up.
|
||||
* @return the source directory to back up.
|
||||
* Gets the source directory to backup.
|
||||
* @return the source directory to backup.
|
||||
*/
|
||||
public abstract File getSourceDir();
|
||||
|
||||
@ -123,7 +123,7 @@ public abstract class BackupProcess implements Comparable<BackupProcess>, Runnab
|
||||
|
||||
/**
|
||||
* Called when the backup ends.
|
||||
* @param success true if the backup ended successfully.
|
||||
* @param success true if the backup ended successfuly.
|
||||
*/
|
||||
protected abstract void onBackupEnd(boolean success);
|
||||
|
||||
@ -209,7 +209,7 @@ public abstract class BackupProcess implements Comparable<BackupProcess>, Runnab
|
||||
File sourceDir = getSourceDir();
|
||||
|
||||
if (!sourceDir.exists()) {
|
||||
Log.warning("[Backup] Unable to compress " + ChatColor.GRAY + getDisplayName() + ChatColor.RESET + ": source directory " + sourceDir + " doesn't exist");
|
||||
Log.warning("[Backup] Unable to compress " + ChatColor.GRAY + getDisplayName() + ChatColor.RESET + ": source directory " + sourceDir + " doesn’t exist");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ public class Persist {
|
||||
// private final Set<String> dirtyWorldsSave = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Creates a new instance, immediately loading the data from the file if it exists, or creating an empty one if not.
|
||||
* Creates a new instance, immediatly loading the data from the file if it exists, or creating an empty one if not.
|
||||
* @param bm the associated backup manager.
|
||||
*/
|
||||
public Persist(BackupManager bm) {
|
||||
|
@ -24,8 +24,7 @@ public class RotatedLogsBackupProcess extends BackupProcess {
|
||||
* @param inNewThread tells if this process should be run in a separate thread (true) or in the same thread handling
|
||||
* the backup manager (false).
|
||||
* @param sourceLogDir the directory where the rotated log files are stored, usually {@code ./logs/}.
|
||||
* @param logFileRegexPattern the pattern to match the rotated log files (usually dated log files, excluding the
|
||||
* current log file).
|
||||
* @param logFileRegexPattern the pattern to match the rotated log files (usually dated log files, excuding the current log file).
|
||||
*/
|
||||
public RotatedLogsBackupProcess(BackupManager bm, boolean inNewThread, File sourceLogDir, String logFileRegexPattern) {
|
||||
super(bm, "logs");
|
||||
|
@ -158,8 +158,8 @@ public class ZipCompressor {
|
||||
}
|
||||
|
||||
private class Entry {
|
||||
final File file;
|
||||
final String entry;
|
||||
File file;
|
||||
String entry;
|
||||
Entry(File f, String e) {
|
||||
file = f;
|
||||
entry = e;
|
||||
|
@ -1,22 +1,23 @@
|
||||
package fr.pandacube.lib.core.config;
|
||||
|
||||
import fr.pandacube.lib.chat.ChatColorUtil;
|
||||
import fr.pandacube.lib.util.Log;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import fr.pandacube.lib.chat.ChatColorUtil;
|
||||
import fr.pandacube.lib.util.Log;
|
||||
|
||||
/**
|
||||
* Class that loads a specific config file or directory.
|
||||
*/
|
||||
public abstract class AbstractConfig {
|
||||
|
||||
/**
|
||||
* The {@link File} corresponding to this config file or directory.
|
||||
* The {@link File} corresponging to this config file or directory.
|
||||
*/
|
||||
protected final File configFile;
|
||||
|
||||
@ -93,8 +94,7 @@ public abstract class AbstractConfig {
|
||||
* @return the list of files in the config directory, or null if this config is not a directory.
|
||||
*/
|
||||
protected List<File> getFileList() {
|
||||
File[] arr = configFile.listFiles();
|
||||
return arr != null ? List.of(arr) : null;
|
||||
return configFile.isDirectory() ? Arrays.asList(configFile.listFiles()) : null;
|
||||
}
|
||||
|
||||
|
||||
@ -105,7 +105,7 @@ public abstract class AbstractConfig {
|
||||
* Splits the provided string into a list of permission nodes.
|
||||
* The permission nodes must be separated by {@code ";"}.
|
||||
* @param perms one or more permissions nodes, separated by {@code ";"}.
|
||||
* @return {@code null} if the parameter is null or is equal to {@code "*"}, or the string split using {@code ";"}.
|
||||
* @return {@code null} if the parameter is null or is equal to {@code "*"}, or the string splitted using {@code ";"}.
|
||||
*/
|
||||
public static List<String> splitPermissionsString(String perms) {
|
||||
if (perms == null || perms.equals("*"))
|
||||
@ -115,9 +115,9 @@ public abstract class AbstractConfig {
|
||||
|
||||
|
||||
/**
|
||||
* Utility method to that translate the {@code '&'} formatted string to the legacy format.
|
||||
* Utility method to that translate the {@code '&'} formated string to the legacy format.
|
||||
* @param string the string to convert.
|
||||
* @return a legacy formatted string (using {@code '§'}).
|
||||
* @return a legacy formated string (using {@code '§'}).
|
||||
*/
|
||||
public static String getTranslatedColorCode(String string) {
|
||||
return ChatColorUtil.translateAlternateColorCodes('&', string);
|
||||
|
@ -5,13 +5,13 @@ import java.io.IOException;
|
||||
|
||||
/**
|
||||
* An abstract manager for a set of configuration files and folders.
|
||||
* It's uses to manage the loading/reloading of the configuration of a plugin.
|
||||
* Its uses is to manage the loading/reloading of the configuration of a plugin.
|
||||
*/
|
||||
public abstract class AbstractConfigManager {
|
||||
|
||||
/**
|
||||
* The global configuration directory.
|
||||
* It may be the one provided by the environment API (like Plugin.getPluginFolder() in Bukkit).
|
||||
* May be the one provided by the environmenet API (like Plugin.getPluginFolder() in Bukkit).
|
||||
*/
|
||||
protected final File configDir;
|
||||
|
||||
|
@ -102,7 +102,7 @@ public class CronScheduler {
|
||||
|
||||
/**
|
||||
* Cancel a scheduled task.
|
||||
* Will not stop a current execution of the task. If the task does not exist, it will not do anything.
|
||||
* Will not stop a current execution of the task. If the task does not exists, it will not do anything.
|
||||
* @param taskId the id of the task to cancel.
|
||||
*/
|
||||
public static void unSchedule(String taskId) {
|
||||
|
@ -12,34 +12,34 @@ import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Provides pre-instanced {@link Gson} objects, all with support for Java records and additional
|
||||
* Provides pre-instanciated {@link Gson} instances, all with support for Java records and additionnal
|
||||
* {@link TypeAdapterFactory} provided with {@link #registerTypeAdapterFactory(TypeAdapterFactory)}.
|
||||
*/
|
||||
public class Json {
|
||||
|
||||
/**
|
||||
* {@link Gson} instance with {@link GsonBuilder#setLenient()} and support for Java records and additional
|
||||
* {@link Gson} instance with {@link GsonBuilder#setLenient()} and support for Java records and additionnal
|
||||
* {@link TypeAdapterFactory} provided with {@link #registerTypeAdapterFactory(TypeAdapterFactory)}.
|
||||
*/
|
||||
public static final Gson gson = build(Function.identity());
|
||||
|
||||
/**
|
||||
* {@link Gson} instance with {@link GsonBuilder#setLenient()}, {@link GsonBuilder#setPrettyPrinting()} and support
|
||||
* for Java records and additional {@link TypeAdapterFactory} provided with
|
||||
* for Java records and additionnal {@link TypeAdapterFactory} provided with
|
||||
* {@link #registerTypeAdapterFactory(TypeAdapterFactory)}.
|
||||
*/
|
||||
public static final Gson gsonPrettyPrinting = build(GsonBuilder::setPrettyPrinting);
|
||||
|
||||
/**
|
||||
* {@link Gson} instance with {@link GsonBuilder#setLenient()}, {@link GsonBuilder#serializeNulls()} and support for
|
||||
* Java records and additional {@link TypeAdapterFactory} provided with
|
||||
* Java records and additionnal {@link TypeAdapterFactory} provided with
|
||||
* {@link #registerTypeAdapterFactory(TypeAdapterFactory)}.
|
||||
*/
|
||||
public static final Gson gsonSerializeNulls = build(GsonBuilder::serializeNulls);
|
||||
|
||||
/**
|
||||
* {@link Gson} instance with {@link GsonBuilder#setLenient()}, {@link GsonBuilder#serializeNulls()},
|
||||
* {@link GsonBuilder#setPrettyPrinting()} and support for Java records and additional {@link TypeAdapterFactory}
|
||||
* {@link GsonBuilder#setPrettyPrinting()} and support for Java records and additionnal {@link TypeAdapterFactory}
|
||||
* provided with {@link #registerTypeAdapterFactory(TypeAdapterFactory)}.
|
||||
*/
|
||||
public static final Gson gsonSerializeNullsPrettyPrinting = build(b -> b.serializeNulls().setPrettyPrinting());
|
||||
|
@ -43,7 +43,7 @@ public class ThrowableAdapter implements JsonSerializer<Throwable>, JsonDeserial
|
||||
// handle types
|
||||
Throwable t = null;
|
||||
if (obj.has("types") && obj.get("types").isJsonArray()) {
|
||||
t = instantiate(obj.getAsJsonArray("types"), message, cause);
|
||||
t = instanciate(obj.getAsJsonArray("types"), message, cause);
|
||||
}
|
||||
if (t == null) {
|
||||
t = new Throwable(message, cause);
|
||||
@ -53,8 +53,8 @@ public class ThrowableAdapter implements JsonSerializer<Throwable>, JsonDeserial
|
||||
JsonArray suppressed = obj.has("suppressed") && !obj.get("suppressed").isJsonNull()
|
||||
? obj.get("suppressed").getAsJsonArray() : null;
|
||||
if (suppressed != null) {
|
||||
for (JsonElement jsonEl : suppressed) {
|
||||
t.addSuppressed(context.deserialize(jsonEl, Throwable.class));
|
||||
for (JsonElement jsonel : suppressed) {
|
||||
t.addSuppressed(context.deserialize(jsonel, Throwable.class));
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,8 +63,8 @@ public class ThrowableAdapter implements JsonSerializer<Throwable>, JsonDeserial
|
||||
? obj.get("stacktrace").getAsJsonArray() : null;
|
||||
if (stacktrace != null) {
|
||||
List<StackTraceElement> els = new ArrayList<>();
|
||||
for (JsonElement jsonEl : stacktrace) {
|
||||
els.add(context.deserialize(jsonEl, StackTraceElement.class));
|
||||
for (JsonElement jsonel : stacktrace) {
|
||||
els.add(context.deserialize(jsonel, StackTraceElement.class));
|
||||
}
|
||||
t.setStackTrace(els.toArray(new StackTraceElement[0]));
|
||||
}
|
||||
@ -159,7 +159,7 @@ public class ThrowableAdapter implements JsonSerializer<Throwable>, JsonDeserial
|
||||
}
|
||||
|
||||
|
||||
private Throwable instantiate(JsonArray types, String message, Throwable cause) {
|
||||
private Throwable instanciate(JsonArray types, String message, Throwable cause) {
|
||||
Throwable t = null;
|
||||
for (JsonElement clNameEl : types) {
|
||||
String clName = clNameEl.getAsString();
|
||||
@ -196,7 +196,7 @@ public class ThrowableAdapter implements JsonSerializer<Throwable>, JsonDeserial
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to use on {@link Throwable} class that only have a message (no cause) constructor.
|
||||
* Utiliy method to use on {@link Throwable} class that only have a message (no cause) constructor.
|
||||
* @param constructorWithMessage function that will construct a new throwable, with prefilled message.
|
||||
* @return a function that will construct a throwable using the provided function, then will try to init the cause of the throwable.
|
||||
* @param <T> the type of the constructed {@link Throwable}.
|
||||
|
@ -15,8 +15,8 @@ public class TypeConverter {
|
||||
/**
|
||||
* Converts the provided object to an {@link Integer}.
|
||||
* @param o the object to convert.
|
||||
* @return the object converted to an {@link Integer}.
|
||||
* @throws ConversionException is a conversion error occurs.
|
||||
* @return a the object converted to an {@link Integer}.
|
||||
* @throws ConvertionException is a conversion error occurs.
|
||||
*/
|
||||
public static Integer toInteger(Object o) {
|
||||
if (o == null) {
|
||||
@ -27,7 +27,7 @@ public class TypeConverter {
|
||||
try {
|
||||
return ((JsonElement)o).getAsInt();
|
||||
} catch(UnsupportedOperationException e) {
|
||||
throw new ConversionException(e);
|
||||
throw new ConvertionException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,34 +38,34 @@ public class TypeConverter {
|
||||
try {
|
||||
return Integer.parseInt((String)o);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new ConversionException(e);
|
||||
throw new ConvertionException(e);
|
||||
}
|
||||
}
|
||||
if (o instanceof Boolean) {
|
||||
return ((Boolean)o) ? 1 : 0;
|
||||
}
|
||||
|
||||
throw new ConversionException("No integer conversion available for an instance of "+o.getClass());
|
||||
throw new ConvertionException("No integer convertion available for an instance of "+o.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the provided object to a primitive int.
|
||||
* @param o the object to convert.
|
||||
* @return the object converted to a primitive int.
|
||||
* @throws ConversionException is a conversion error occurs.
|
||||
* @return a the object converted to a primitive int.
|
||||
* @throws ConvertionException is a conversion error occurs.
|
||||
*/
|
||||
public static int toPrimInt(Object o) {
|
||||
Integer val = toInteger(o);
|
||||
if (val == null)
|
||||
throw new ConversionException("null values can't be converted to primitive int");
|
||||
throw new ConvertionException("null values can't be converted to primitive int");
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the provided object to a {@link Double}.
|
||||
* @param o the object to convert.
|
||||
* @return the object converted to a {@link Double}.
|
||||
* @throws ConversionException is a conversion error occurs.
|
||||
* @return a the object converted to a {@link Double}.
|
||||
* @throws ConvertionException is a conversion error occurs.
|
||||
*/
|
||||
public static Double toDouble(Object o) {
|
||||
if (o == null) {
|
||||
@ -76,7 +76,7 @@ public class TypeConverter {
|
||||
try {
|
||||
return ((JsonElement)o).getAsDouble();
|
||||
} catch(UnsupportedOperationException e) {
|
||||
throw new ConversionException(e);
|
||||
throw new ConvertionException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,35 +87,35 @@ public class TypeConverter {
|
||||
try {
|
||||
return Double.parseDouble((String)o);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new ConversionException(e);
|
||||
throw new ConvertionException(e);
|
||||
}
|
||||
}
|
||||
if (o instanceof Boolean) {
|
||||
return ((Boolean)o) ? 1d : 0d;
|
||||
}
|
||||
|
||||
throw new ConversionException("No double conversion available for an instance of "+o.getClass());
|
||||
throw new ConvertionException("No double convertion available for an instance of "+o.getClass());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the provided object to a primitive double.
|
||||
* @param o the object to convert.
|
||||
* @return the object converted to a primitive double.
|
||||
* @throws ConversionException is a conversion error occurs.
|
||||
* @return a the object converted to a primitive double.
|
||||
* @throws ConvertionException is a conversion error occurs.
|
||||
*/
|
||||
public static double toPrimDouble(Object o) {
|
||||
Double val = toDouble(o);
|
||||
if (val == null)
|
||||
throw new ConversionException("null values can't converted to primitive int");
|
||||
throw new ConvertionException("null values can't converted to primitive int");
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the provided object to a {@link String}.
|
||||
* @param o the object to convert.
|
||||
* @return the object converted to a {@link String}.
|
||||
* @throws ConversionException is a conversion error occurs.
|
||||
* @return a the object converted to a {@link String}.
|
||||
* @throws ConvertionException is a conversion error occurs.
|
||||
*/
|
||||
public static String toString(Object o) {
|
||||
if (o == null) {
|
||||
@ -126,7 +126,7 @@ public class TypeConverter {
|
||||
try {
|
||||
return ((JsonElement)o).getAsString();
|
||||
} catch(UnsupportedOperationException e) {
|
||||
throw new ConversionException(e);
|
||||
throw new ConvertionException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,7 +134,7 @@ public class TypeConverter {
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
throw new ConversionException("No string conversion available for an instance of "+o.getClass());
|
||||
throw new ConvertionException("No string convertion available for an instance of "+o.getClass());
|
||||
|
||||
}
|
||||
|
||||
@ -144,8 +144,8 @@ public class TypeConverter {
|
||||
* @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
|
||||
* to the object <i>o</i>, an integer key 12 will be added and map to the same object <i>o</i>.
|
||||
* @return the object converted to a {@link Map}.
|
||||
* @throws ConversionException is a conversion error occurs.
|
||||
* @return a the object converted to a {@link Map}.
|
||||
* @throws ConvertionException is a conversion error occurs.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map<Object, Object> toMap(Object o, boolean mapIntKeys) {
|
||||
@ -186,15 +186,15 @@ public class TypeConverter {
|
||||
return map;
|
||||
}
|
||||
|
||||
throw new ConversionException("No Map conversion available for an instance of "+o.getClass());
|
||||
throw new ConvertionException("No Map convertion available for an instance of "+o.getClass());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts the provided object to a {@link List}.
|
||||
* @param o the object to convert.
|
||||
* @return the object converted to a {@link List}.
|
||||
* @throws ConversionException is a conversion error occurs.
|
||||
* @return a the object converted to a {@link List}.
|
||||
* @throws ConvertionException is a conversion error occurs.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static List<Object> toList(Object o) {
|
||||
@ -217,7 +217,7 @@ public class TypeConverter {
|
||||
}
|
||||
|
||||
|
||||
throw new ConversionException("No Map conversion available for an instance of "+o.getClass());
|
||||
throw new ConvertionException("No Map convertion available for an instance of "+o.getClass());
|
||||
|
||||
|
||||
|
||||
@ -225,14 +225,14 @@ public class TypeConverter {
|
||||
|
||||
|
||||
/**
|
||||
* Thrown when a conversion error occurs.
|
||||
* Thrown when a convertion error occurs.
|
||||
*/
|
||||
public static class ConversionException extends RuntimeException {
|
||||
public static class ConvertionException extends RuntimeException {
|
||||
|
||||
private ConversionException(String m) {
|
||||
private ConvertionException(String m) {
|
||||
super(m);
|
||||
}
|
||||
private ConversionException(Throwable t) {
|
||||
private ConvertionException(Throwable t) {
|
||||
super(t);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
package fr.pandacube.lib.core.mc_version;
|
||||
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
@ -16,7 +16,7 @@ public class MinecraftVersionUtil {
|
||||
|
||||
/**
|
||||
* Compare two Minecraft version strings. It uses the rules of semantic
|
||||
* versioning to compare the versions.
|
||||
* versionning to compare the versions.
|
||||
* @param v1 the first version to compare.
|
||||
* @param v2 the second version to compare.
|
||||
* @return 0 if they are equal, <0 if v1<v2 and vice-versa.
|
||||
@ -49,20 +49,20 @@ public class MinecraftVersionUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if the two provided Minecraft versions are consecutive.
|
||||
* Tells if the two provided Minecraft versions are consecutives.
|
||||
* <p>
|
||||
* Two versions are consecutive if (considering {@code 1.X[.Y]}):
|
||||
* Two versions are consecutives if (considering {@code 1.X[.Y]}):
|
||||
* <ul>
|
||||
* <li>They are part of the same main version (X value)</li>
|
||||
* <li>v1 has no Y value, and v2 has Y = 1 (eg. 1.19 and 1.19.1) OR
|
||||
* both v1 and v2 has a Y value and those values are consecutive.
|
||||
* both v1 and v2 has a Y value and those values are consecutives.
|
||||
* </li>
|
||||
* </ul>
|
||||
* @param v1 the first version.
|
||||
* @param v2 the second version.
|
||||
* @return thue if the second version is consecutive to the first one.
|
||||
*/
|
||||
public static boolean areConsecutive(String v1, String v2) {
|
||||
public static boolean areConsecutives(String v1, String v2) {
|
||||
int[] v1Int = decomposedVersion(v1);
|
||||
int[] v2Int = decomposedVersion(v2);
|
||||
|
||||
@ -105,21 +105,21 @@ public class MinecraftVersionUtil {
|
||||
versions = new ArrayList<>(toOrderedSet(versions));
|
||||
List<String> keptVersions = new ArrayList<>(versions.size());
|
||||
|
||||
for (int i = 0, firstConsecutive = 0; i < versions.size(); i++) {
|
||||
if (i == versions.size() - 1 || !areConsecutive(versions.get(i), versions.get(i + 1))) {
|
||||
if (firstConsecutive == i) {
|
||||
for (int i = 0, firstConsec = 0; i < versions.size(); i++) {
|
||||
if (i == versions.size() - 1 || !areConsecutives(versions.get(i), versions.get(i + 1))) {
|
||||
if (firstConsec == i) {
|
||||
keptVersions.add(versions.get(i));
|
||||
firstConsecutive++;
|
||||
firstConsec++;
|
||||
}
|
||||
else {
|
||||
// merge
|
||||
if (i - firstConsecutive > 1)
|
||||
keptVersions.add(versions.get(firstConsecutive) + "-" + versions.get(i));
|
||||
if (i - firstConsec > 1)
|
||||
keptVersions.add(versions.get(firstConsec) + "-" + versions.get(i));
|
||||
else {
|
||||
keptVersions.add(versions.get(firstConsecutive));
|
||||
keptVersions.add(versions.get(firstConsec));
|
||||
keptVersions.add(versions.get(i));
|
||||
}
|
||||
firstConsecutive = i + 1;
|
||||
firstConsec = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,8 +23,8 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
* The data if fetch updated data from an external API on startup. If it fails,
|
||||
* it uses the data stored in the current package at build time.
|
||||
* <p>
|
||||
* The public static methods are used to fetch an instance of {@link ProtocolVersion}
|
||||
* based on the provided protocol version (e.g. 763) or Minecraft version (e.g. "1.20.1").
|
||||
* The public static methos are used to fetch an instance of {@link ProtocolVersion}
|
||||
* based on the provided protocol version (eg. 763) or Minecraft version (eg. "1.20.1").
|
||||
* An instance of this class provides information related to a protocol version
|
||||
* (the protocol version number and all the corresponding Minecraft versions).
|
||||
*/
|
||||
@ -89,24 +89,15 @@ public class ProtocolVersion implements Comparable<ProtocolVersion> {
|
||||
|
||||
Log.warning("Unable to get minecraft version data from API. Using local data instead.");
|
||||
// try local source
|
||||
try (InputStream is = ProtocolVersion.class.getResourceAsStream("mcversion.json")) {
|
||||
if (is != null) {
|
||||
try (InputStreamReader isr = new InputStreamReader(is)) {
|
||||
MinecraftVersionList data = Json.gson.fromJson(isr, MinecraftVersionList.class);
|
||||
versionList.set(data);
|
||||
}
|
||||
}
|
||||
try (InputStream is = ProtocolVersion.class.getResourceAsStream("mcversion.json");
|
||||
InputStreamReader isr = new InputStreamReader(is)) {
|
||||
MinecraftVersionList data = Json.gson.fromJson(isr, MinecraftVersionList.class);
|
||||
versionList.set(data);
|
||||
} catch (Exception e) {
|
||||
Log.warning(e);
|
||||
Log.severe("Unable to get Minecraft versions data from classpath. Using empty data instead.");
|
||||
versionList.set(new MinecraftVersionList());
|
||||
}
|
||||
|
||||
if (versionList.get() != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Log.severe("Unable to get Minecraft versions data from classpath. Using empty data instead.");
|
||||
|
||||
versionList.set(new MinecraftVersionList());
|
||||
}
|
||||
|
||||
|
||||
|
@ -15,7 +15,7 @@ import java.util.concurrent.ExecutionException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Utility class to manage searching among a set of {@link SearchResult} instances, using case-insensitive keywords.
|
||||
* Utility class to manage searching among a set of {@link SearchResult} instances, using case insensitive keywords.
|
||||
* The search engine is responsible for storing a database of entries ({@link SearchResult}) that can be searched using
|
||||
* keywords. This class provides methods to returns a list of results for provided keywords, a list of keyword
|
||||
* suggestions based on pre-typed keywords.
|
||||
|
@ -52,10 +52,10 @@ public final class DB {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the table represented by the provided class.
|
||||
* Initialialize the table represented by the provided class.
|
||||
* @param elemClass the class representing a table.
|
||||
* @param <E> the type representing the table.
|
||||
* @throws DBInitTableException if the table failed to initialize.
|
||||
* @throws DBInitTableException if the table failed to initialized.
|
||||
*/
|
||||
public static synchronized <E extends SQLElement<E>> void initTable(Class<E> elemClass) throws DBInitTableException {
|
||||
if (connection == null) {
|
||||
@ -111,7 +111,7 @@ public final class DB {
|
||||
* @param elemClass the class representing a table.
|
||||
* @return a table name.
|
||||
* @param <E> the type representing the table.
|
||||
* @throws DBInitTableException if the provided table had to be initialized and failed to do so.
|
||||
* @throws DBInitTableException if the provided table had to be initialized and it failed to do so.
|
||||
*/
|
||||
public static <E extends SQLElement<E>> String getTableName(Class<E> elemClass) throws DBInitTableException {
|
||||
initTable(elemClass);
|
||||
@ -130,7 +130,7 @@ public final class DB {
|
||||
* @param elemClass the class representing a table.
|
||||
* @return the {@code id} field of the provided table.
|
||||
* @param <E> the type representing the table.
|
||||
* @throws DBInitTableException if the provided table had to be initialized and failed to do so.
|
||||
* @throws DBInitTableException if the provided table had to be initialized and it failed to do so.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <E extends SQLElement<E>> SQLField<E, Integer> getSQLIdField(Class<E> elemClass) throws DBInitTableException {
|
||||
@ -226,8 +226,8 @@ public final class DB {
|
||||
* @throws DBException if an error occurs when interacting with the database.
|
||||
*/
|
||||
public static <E extends SQLElement<E>> E getFirst(Class<E> elemClass, SQLWhere<E> where, SQLOrderBy<E> orderBy, Integer offset) throws DBException {
|
||||
SQLElementList<E> elements = getAll(elemClass, where, orderBy, 1, offset);
|
||||
return (elements.size() == 0) ? null : elements.get(0);
|
||||
SQLElementList<E> elts = getAll(elemClass, where, orderBy, 1, offset);
|
||||
return (elts.size() == 0) ? null : elts.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -294,15 +294,15 @@ public final class DB {
|
||||
* @throws DBException if an error occurs when interacting with the database.
|
||||
*/
|
||||
public static <E extends SQLElement<E>> SQLElementList<E> getAll(Class<E> elemClass, SQLWhere<E> where, SQLOrderBy<E> orderBy, Integer limit, Integer offset) throws DBException {
|
||||
SQLElementList<E> elements = new SQLElementList<>();
|
||||
forEach(elemClass, where, orderBy, limit, offset, elements::add);
|
||||
return elements;
|
||||
SQLElementList<E> elmts = new SQLElementList<>();
|
||||
forEach(elemClass, where, orderBy, limit, offset, elmts::add);
|
||||
return elmts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate through all the entries from the provided table.
|
||||
* @param elemClass the class representing a table.
|
||||
* @param action the action to perform on each entry.
|
||||
* @param action the action to perform on each entries.
|
||||
* @param <E> the type representing the table.
|
||||
* @throws DBException if an error occurs when interacting with the database.
|
||||
*/
|
||||
@ -314,7 +314,7 @@ public final class DB {
|
||||
* Iterate through the entries from the provided table, using the provided {@code WHERE} clause.
|
||||
* @param elemClass the class representing a table.
|
||||
* @param where the {@code WHERE} clause of the query.
|
||||
* @param action the action to perform on each entry.
|
||||
* @param action the action to perform on each entries.
|
||||
* @param <E> the type representing the table.
|
||||
* @throws DBException if an error occurs when interacting with the database.
|
||||
*/
|
||||
@ -328,7 +328,7 @@ public final class DB {
|
||||
* @param elemClass the class representing a table.
|
||||
* @param where the {@code WHERE} clause of the query.
|
||||
* @param orderBy the {@code ORDER BY} clause of the query.
|
||||
* @param action the action to perform on each entry.
|
||||
* @param action the action to perform on each entries.
|
||||
* @param <E> the type representing the table.
|
||||
* @throws DBException if an error occurs when interacting with the database.
|
||||
*/
|
||||
@ -343,7 +343,7 @@ public final class DB {
|
||||
* @param where the {@code WHERE} clause of the query.
|
||||
* @param orderBy the {@code ORDER BY} clause of the query.
|
||||
* @param limit the {@code LIMIT} clause of the query.
|
||||
* @param action the action to perform on each entry.
|
||||
* @param action the action to perform on each entries.
|
||||
* @param <E> the type representing the table.
|
||||
* @throws DBException if an error occurs when interacting with the database.
|
||||
*/
|
||||
@ -359,7 +359,7 @@ public final class DB {
|
||||
* @param orderBy the {@code ORDER BY} clause of the query.
|
||||
* @param limit the {@code LIMIT} clause of the query.
|
||||
* @param offset the {@code OFFSET} clause of the query.
|
||||
* @param action the action to perform on each entry.
|
||||
* @param action the action to perform on each entries.
|
||||
* @param <E> the type representing the table.
|
||||
* @throws DBException if an error occurs when interacting with the database.
|
||||
*/
|
||||
@ -577,7 +577,7 @@ public final class DB {
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <E extends SQLElement<E>> E getElementInstance(ResultSet set, Class<E> elemClass) throws DBException {
|
||||
try {
|
||||
E instance = Reflect.ofClass(elemClass).constructor(int.class).instantiate(set.getInt("id"));
|
||||
E instance = Reflect.ofClass(elemClass).constructor(int.class).instanciate(set.getInt("id"));
|
||||
|
||||
int fieldCount = set.getMetaData().getColumnCount();
|
||||
|
||||
@ -623,7 +623,7 @@ public final class DB {
|
||||
|
||||
return instance;
|
||||
} catch (ReflectiveOperationException | IllegalArgumentException | SecurityException | SQLException e) {
|
||||
throw new DBException("Can't instantiate " + elemClass.getName(), e);
|
||||
throw new DBException("Can't instanciate " + elemClass.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
package fr.pandacube.lib.db;
|
||||
|
||||
/**
|
||||
* Exception thrown when something bad happens when using the {@link DB} API.
|
||||
* Exception thrown when something bad happends when using the {@link DB} API.
|
||||
*/
|
||||
public class DBException extends Exception {
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
package fr.pandacube.lib.db;
|
||||
|
||||
/**
|
||||
* Exception thrown when something bad happens when initializing a new table using {@link DB#initTable(Class)}.
|
||||
* Exception thrown when something bad happends when initializing a new table using {@link DB#initTable(Class)}.
|
||||
*/
|
||||
public class DBInitTableException extends DBException {
|
||||
|
||||
|
@ -119,7 +119,7 @@ public abstract class SQLElement<E extends SQLElement<E>> {
|
||||
|
||||
/**
|
||||
* Gets the name of the table in the database, without the prefix defined by {@link DB#init(DBConnection, String)}.
|
||||
* @return The non-prefixed name of the table in the database.
|
||||
* @return The unprefixed name of the table in the database.
|
||||
*/
|
||||
protected abstract String tableName();
|
||||
|
||||
@ -133,7 +133,7 @@ public abstract class SQLElement<E extends SQLElement<E>> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the entries values that are known to be nullable or have a default value.
|
||||
* Fills the values of this entry that are known to be nullable or have a default value.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void initDefaultValues() {
|
||||
@ -193,7 +193,7 @@ public abstract class SQLElement<E extends SQLElement<E>> {
|
||||
/**
|
||||
* Sets a value in this entry.
|
||||
* <p>
|
||||
* This is not good practice to set the {@code id} field of any entry, because it’s a unique auto-incremented
|
||||
* This is not good practice to set the {@code id} field of any entry, because it’s an unique auto-incremented
|
||||
* value. Use {@link #save()} and {@link #delete()} to set or unset the {@code id} instead, in consistence with the
|
||||
* database.
|
||||
* @param field the field to set.
|
||||
@ -255,11 +255,11 @@ public abstract class SQLElement<E extends SQLElement<E>> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the foreign table entry targeted by the provided foreign key of this table.
|
||||
* @param field a foreign key of this table.
|
||||
* @param <T> the type of the foreign key field.
|
||||
* Gets the foreign table entry targeted by the provided foreignkey of this table.
|
||||
* @param field a foreignkey of this table.
|
||||
* @param <T> the type of the foreignkey field.
|
||||
* @param <P> the targeted foreign table type.
|
||||
* @return the foreign table entry targeted by the provided foreign key of this table.
|
||||
* @return the foreign table entry targeted by the provided foreignkey of this table.
|
||||
* @throws DBException if an error occurs when interacting with the database.
|
||||
*/
|
||||
public <T, P extends SQLElement<P>> P getReferencedEntry(SQLFKField<E, T, P> field) throws DBException {
|
||||
@ -271,11 +271,11 @@ public abstract class SQLElement<E extends SQLElement<E>> {
|
||||
/**
|
||||
* Gets the original table entry which the provided foreign key is targeting this entry, and following the provided
|
||||
* {@code ORDER BY}, {@code LIMIT} and {@code OFFSET} clauses.
|
||||
* @param field a foreign key in the original table.
|
||||
* @param field a foreignkey in the original table.
|
||||
* @param orderBy the {@code ORDER BY} clause of the query.
|
||||
* @param limit the {@code LIMIT} clause of the query.
|
||||
* @param offset the {@code OFFSET} clause of the query.
|
||||
* @param <T> the type of the foreign key field.
|
||||
* @param <T> the type of the foreignkey field.
|
||||
* @param <F> the table class of the foreign key that reference a field of this entry.
|
||||
* @return the original table entry which the provided foreign key is targeting this entry.
|
||||
* @throws DBException if an error occurs when interacting with the database.
|
||||
@ -314,7 +314,7 @@ public abstract class SQLElement<E extends SQLElement<E>> {
|
||||
|
||||
/**
|
||||
* Saves this entry into the database, either by updating the already existing entry in it, or by creating a new
|
||||
* entry if it doesn't exist yet.
|
||||
* entry if it doesn’t exist yet.
|
||||
* @return this.
|
||||
* @throws DBException if an error occurs when interacting with the database.
|
||||
*/
|
||||
@ -474,14 +474,14 @@ public abstract class SQLElement<E extends SQLElement<E>> {
|
||||
* Creates a new SQL field.
|
||||
* @param type the type of the field.
|
||||
* @param nullable true if nullable, false if {@code NOT NULL}.
|
||||
* @param autoIncrement if {@code AUTO_INCREMENT}.
|
||||
* @param autoIncr if {@code AUTO_INCREMENT}.
|
||||
* @param deflt a default value for this field. A null value indicate that this has no default value.
|
||||
* @return the new SQL field.
|
||||
* @param <E> the table type.
|
||||
* @param <T> the Java type of this field.
|
||||
*/
|
||||
protected static <E extends SQLElement<E>, T> SQLField<E, T> field(SQLType<T> type, boolean nullable, boolean autoIncrement, T deflt) {
|
||||
return new SQLField<>(type, nullable, autoIncrement, deflt);
|
||||
protected static <E extends SQLElement<E>, T> SQLField<E, T> field(SQLType<T> type, boolean nullable, boolean autoIncr, T deflt) {
|
||||
return new SQLField<>(type, nullable, autoIncr, deflt);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -500,13 +500,13 @@ public abstract class SQLElement<E extends SQLElement<E>> {
|
||||
* Creates a new SQL field.
|
||||
* @param type the type of the field.
|
||||
* @param nullable true if nullable, false if {@code NOT NULL}.
|
||||
* @param autoIncrement if {@code AUTO_INCREMENT}.
|
||||
* @param autoIncr if {@code AUTO_INCREMENT}.
|
||||
* @return the new SQL field.
|
||||
* @param <E> the table type.
|
||||
* @param <T> the Java type of this field.
|
||||
*/
|
||||
protected static <E extends SQLElement<E>, T> SQLField<E, T> field(SQLType<T> type, boolean nullable, boolean autoIncrement) {
|
||||
return new SQLField<>(type, nullable, autoIncrement);
|
||||
protected static <E extends SQLElement<E>, T> SQLField<E, T> field(SQLType<T> type, boolean nullable, boolean autoIncr) {
|
||||
return new SQLField<>(type, nullable, autoIncr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,7 +46,7 @@ public class SQLElementList<E extends SQLElement<E>> extends ArrayList<E> {
|
||||
E emptyElement = elemClass.getConstructor().newInstance();
|
||||
emptyElement.set(field, value, false);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("Illegal field or value or can't instantiate an empty instance of "
|
||||
throw new IllegalArgumentException("Illegal field or value or can't instanciante an empty instance of "
|
||||
+ elemClass.getName() + ". (the instance is only created to test validity of field and value)", e);
|
||||
}
|
||||
|
||||
@ -83,7 +83,7 @@ public class SQLElementList<E extends SQLElement<E>> extends ArrayList<E> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void applyNewValuesToElements(List<E> storedEl) {
|
||||
// applique les valeurs dans chaque objet de la liste
|
||||
// applique les valeurs dans chaques objets de la liste
|
||||
for (E el : storedEl) {
|
||||
for (@SuppressWarnings("rawtypes") SQLField entry : modifiedValues.keySet()) {
|
||||
if (!el.isModified(entry)) {
|
||||
@ -100,7 +100,7 @@ public class SQLElementList<E extends SQLElement<E>> extends ArrayList<E> {
|
||||
/**
|
||||
* Removes all the entries of this list from the database.
|
||||
* This method has the same effect as calling the {@link SQLElement#delete()} method individually on each element,
|
||||
* but with only one SQL query to delete all the entries.
|
||||
* but with only one SQL query to delete all of the entries.
|
||||
* <p>
|
||||
* If you intend to remove the entries from the database just after fetching them, call directly the
|
||||
* {@link DB#delete(Class, SQLWhere)} method instead.
|
||||
@ -124,9 +124,9 @@ public class SQLElementList<E extends SQLElement<E>> extends ArrayList<E> {
|
||||
|
||||
/**
|
||||
* Get all the entries targeted by the foreign key of all the entries in this list.
|
||||
* @param foreignKey a foreign key of this table.
|
||||
* @param foreignKey a foreignkey of this table.
|
||||
* @param orderBy the {@code ORDER BY} clause of the query.
|
||||
* @return a list of foreign table entries targeted by the provided foreign key of this table.
|
||||
* @return a list of foreign table entries targeted by the provided foreignkey of this table.
|
||||
* @param <T> the field’s Java type.
|
||||
* @param <P> the target table type.
|
||||
* @throws DBException if an error occurs when interacting with the database.
|
||||
@ -144,7 +144,7 @@ public class SQLElementList<E extends SQLElement<E>> extends ArrayList<E> {
|
||||
|
||||
/**
|
||||
* Get all the entries targeted by the foreign key of all the entries in this list, mapped from the foreign key value.
|
||||
* @param foreignKey a foreign key of this table.
|
||||
* @param foreignKey a foreignkey of this table.
|
||||
* @return a map of the foreign key values, mapped to the foreign table’s entries.
|
||||
* @param <T> the field’s Java type.
|
||||
* @param <P> the target table type.
|
||||
@ -163,11 +163,11 @@ public class SQLElementList<E extends SQLElement<E>> extends ArrayList<E> {
|
||||
/**
|
||||
* Gets all the original table’s entries which the provided foreign key is targeting the entries of this list, and
|
||||
* following the provided {@code ORDER BY}, {@code LIMIT} and {@code OFFSET} clauses.
|
||||
* @param foreignKey a foreign key in the original table.
|
||||
* @param foreignKey a foreignkey in the original table.
|
||||
* @param orderBy the {@code ORDER BY} clause of the query.
|
||||
* @param limit the {@code LIMIT} clause of the query.
|
||||
* @param offset the {@code OFFSET} clause of the query.
|
||||
* @param <T> the type of the foreign key field.
|
||||
* @param <T> the type of the foreignkey field.
|
||||
* @param <F> the table class of the foreign key that reference a field of this entry.
|
||||
* @return the original table’s entries which the provided foreign key is targeting the entries of this list.
|
||||
* @throws DBException if an error occurs when interacting with the database.
|
||||
@ -187,11 +187,11 @@ public class SQLElementList<E extends SQLElement<E>> extends ArrayList<E> {
|
||||
* Gets all the original table’s entries which the provided foreign key is targeting the entries of this list,
|
||||
* following the provided {@code ORDER BY}, {@code LIMIT} and {@code OFFSET} clauses, and mapped from the foreign
|
||||
* key value.
|
||||
* @param foreignKey a foreign key in the original table.
|
||||
* @param foreignKey a foreignkey in the original table.
|
||||
* @param orderBy the {@code ORDER BY} clause of the query.
|
||||
* @param limit the {@code LIMIT} clause of the query.
|
||||
* @param offset the {@code OFFSET} clause of the query.
|
||||
* @param <T> the type of the foreign key field.
|
||||
* @param <T> the type of the foreignkey field.
|
||||
* @param <F> the table class of the foreign key that reference a field of this entry.
|
||||
* @return a map of the foreign key values, mapped to the orignal table’s entries.
|
||||
* @throws DBException if an error occurs when interacting with the database.
|
||||
|
@ -28,7 +28,7 @@ public class SQLFKField<F extends SQLElement<F>, T, P extends SQLElement<P>> ext
|
||||
SQLField<F, Integer> f = DB.getSQLIdField(fkEl);
|
||||
return new SQLFKField<>(f.type, nul, deflt, fkEl, f);
|
||||
} catch (DBInitTableException e) {
|
||||
Log.severe("Can't create Foreign key Field targeting id field of '"+fkEl+"'", e);
|
||||
Log.severe("Can't create Foreign key Field targetting id field of '"+fkEl+"'", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -51,7 +51,7 @@ public class SQLFKField<F extends SQLElement<F>, T, P extends SQLElement<P>> ext
|
||||
}
|
||||
|
||||
if (fkF.getSQLElementType() == null)
|
||||
throw new RuntimeException("Can't initialize foreign key. The primary key in the table " + fkEl.getName() + " is not properly initialized and can't be targeted by a foreign key");
|
||||
throw new RuntimeException("Can't initialize foreign key. The primary key in the table " + fkEl.getName() + " is not properly initialized and can't be targetted by a forein key");
|
||||
sqlPrimaryKeyField = fkF;
|
||||
sqlForeignKeyElemClass = fkEl;
|
||||
}
|
||||
|
@ -24,10 +24,10 @@ public class SQLField<E extends SQLElement<E>, T> {
|
||||
/* package */ final boolean autoIncrement;
|
||||
/* package */ final T defaultValue;
|
||||
|
||||
/* package */ SQLField(SQLType<T> type, boolean nullable, boolean autoIncrement, T deflt) {
|
||||
/* package */ SQLField(SQLType<T> type, boolean nullable, boolean autoIncr, T deflt) {
|
||||
this.type = type;
|
||||
this.nullable = nullable;
|
||||
this.autoIncrement = autoIncrement;
|
||||
autoIncrement = autoIncr;
|
||||
defaultValue = deflt;
|
||||
}
|
||||
|
||||
@ -35,8 +35,8 @@ public class SQLField<E extends SQLElement<E>, T> {
|
||||
this(type, nullable, false, null);
|
||||
}
|
||||
|
||||
/* package */ SQLField(SQLType<T> type, boolean nullable, boolean autoIncrement) {
|
||||
this(type, nullable, autoIncrement, null);
|
||||
/* package */ SQLField(SQLType<T> type, boolean nullable, boolean autoIncr) {
|
||||
this(type, nullable, autoIncr, null);
|
||||
}
|
||||
|
||||
/* package */ SQLField(SQLType<T> type, boolean nullable, T deflt) {
|
||||
|
12
pandalib-net/Readme.md
Normal file
12
pandalib-net/Readme.md
Normal file
@ -0,0 +1,12 @@
|
||||
# pandalib-net
|
||||
|
||||
A TCP network library that uses the standard Java socket API, to ease the ommunication between the different processes
|
||||
running the server network Pandacube.
|
||||
|
||||
It’s still in development (actually not touched since years), and it’s supposed to be a replacement for the old
|
||||
`pandalib-netapi`. This module is then marked as Beta using the Google Guava annotation.
|
||||
|
||||
- Packet based communication
|
||||
- Supports Request/Answer packets
|
||||
- Uses binary packet id and data
|
||||
* Input streams are handled in separate Threads
|
29
pandalib-net/pom.xml
Normal file
29
pandalib-net/pom.xml
Normal file
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>pandalib-parent</artifactId>
|
||||
<groupId>fr.pandacube.lib</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>pandalib-net</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>fr.pandacube.lib</groupId>
|
||||
<artifactId>pandalib-util</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>31.0.1-jre</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,65 @@
|
||||
package fr.pandacube.lib.net;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
@Beta
|
||||
public class Array8Bit {
|
||||
|
||||
public static final int BIT_COUNT = Byte.SIZE;
|
||||
|
||||
private boolean[] values = new boolean[BIT_COUNT];
|
||||
|
||||
public Array8Bit(byte b) {
|
||||
fromByte(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bits (index 0 is the lowest significant bit)
|
||||
*/
|
||||
public Array8Bit(boolean[] bits) {
|
||||
if (bits == null || bits.length != BIT_COUNT)
|
||||
throw new IllegalArgumentException("bits is null or bits.length != "+BIT_COUNT);
|
||||
values = Arrays.copyOf(bits, BIT_COUNT);
|
||||
}
|
||||
|
||||
/**
|
||||
* i = 0 is the lowest significant bit
|
||||
*/
|
||||
public boolean getBit(int i) {
|
||||
return values[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* i = 0 is the lowest significant bit
|
||||
*/
|
||||
public void setBit(int i, boolean b) {
|
||||
values[i] = b;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void fromByte(byte b) {
|
||||
int mask = 1;
|
||||
for (int i = 0; i < BIT_COUNT; i++) {
|
||||
values[i] = (b & mask) != 0;
|
||||
mask <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public byte toByte() {
|
||||
byte b = 0;
|
||||
for (int i=BIT_COUNT-1; i>=0; i--) {
|
||||
b <<= 1;
|
||||
if (values[i]) b |= 1;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
275
pandalib-net/src/main/java/fr/pandacube/lib/net/ByteBuffer.java
Normal file
275
pandalib-net/src/main/java/fr/pandacube/lib/net/ByteBuffer.java
Normal file
@ -0,0 +1,275 @@
|
||||
package fr.pandacube.lib.net;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
@Beta
|
||||
public final class ByteBuffer implements Cloneable {
|
||||
|
||||
public static final Charset NETWORK_CHARSET = StandardCharsets.UTF_8;
|
||||
|
||||
private java.nio.ByteBuffer buff;
|
||||
|
||||
public ByteBuffer() {
|
||||
this(16);
|
||||
}
|
||||
|
||||
public ByteBuffer(int initSize) {
|
||||
buff = java.nio.ByteBuffer.allocate(initSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ByteBuffer that is initially <b>backed</b> by the provided byte array.
|
||||
* The position of this buffer will be 0.
|
||||
* If this ByteBuffer needs a biffer array, the provided array is replaced by a new one,
|
||||
* making the provided array not related to this ByteBuffer anymore.
|
||||
* @param data array of byte that serve as a backend for this ByteBuffer.
|
||||
*/
|
||||
public ByteBuffer(byte[] data) {
|
||||
buff = java.nio.ByteBuffer.wrap(data);
|
||||
}
|
||||
|
||||
private void askForBufferExtension(int needed) {
|
||||
while (buff.remaining() < needed) {
|
||||
java.nio.ByteBuffer newBuff = java.nio.ByteBuffer.wrap(Arrays.copyOf(buff.array(), buff.array().length * 2));
|
||||
newBuff.position(buff.position());
|
||||
buff = newBuff;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This clone method also clone the underlying array.
|
||||
*/
|
||||
@SuppressWarnings("MethodDoesntCallSuperMethod")
|
||||
@Override
|
||||
public ByteBuffer clone() {
|
||||
return new ByteBuffer(Arrays.copyOf(buff.array(), buff.array().length));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.nio.ByteBuffer#get()
|
||||
*/
|
||||
public byte getByte() {
|
||||
return buff.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.nio.ByteBuffer#get(byte[])
|
||||
*/
|
||||
public byte[] getByteArray(byte[] b) {
|
||||
buff.get(b);
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the next byte array wich is preceded with his size as integer,
|
||||
* or null if the founded size is negative.
|
||||
*/
|
||||
public byte[] getSizedByteArray() {
|
||||
int size = getInt();
|
||||
if (size < 0) return null;
|
||||
return getByteArray(new byte[size]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.nio.ByteBuffer#getChar()
|
||||
*/
|
||||
public char getChar() {
|
||||
return buff.getChar();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.nio.ByteBuffer#getShort()
|
||||
*/
|
||||
public short getShort() {
|
||||
return buff.getShort();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.nio.ByteBuffer#getInt()
|
||||
*/
|
||||
public int getInt() {
|
||||
return buff.getInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.nio.ByteBuffer#getLong()
|
||||
*/
|
||||
public long getLong() {
|
||||
return buff.getLong();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.nio.ByteBuffer#getFloat()
|
||||
*/
|
||||
public float getFloat() {
|
||||
return buff.getFloat();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.nio.ByteBuffer#getDouble()
|
||||
*/
|
||||
public double getDouble() {
|
||||
return buff.getDouble();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.nio.ByteBuffer#put(byte)
|
||||
*/
|
||||
public ByteBuffer putByte(byte b) {
|
||||
askForBufferExtension(Byte.BYTES);
|
||||
buff.put(b);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.nio.ByteBuffer#put(byte[])
|
||||
*/
|
||||
public ByteBuffer putByteArray(byte[] b) {
|
||||
askForBufferExtension(b.length * Byte.BYTES);
|
||||
buff.put(b);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ByteBuffer putSizedByteArray(byte[] b) {
|
||||
if (b == null) {
|
||||
return putInt(-1);
|
||||
}
|
||||
putInt(b.length);
|
||||
return putByteArray(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.nio.ByteBuffer#putChar(char)
|
||||
*/
|
||||
public ByteBuffer putChar(char value) {
|
||||
askForBufferExtension(Character.BYTES);
|
||||
buff.putChar(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.nio.ByteBuffer#putShort(short)
|
||||
*/
|
||||
public ByteBuffer putShort(short value) {
|
||||
askForBufferExtension(Short.BYTES);
|
||||
buff.putShort(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.nio.ByteBuffer#putInt(int)
|
||||
*/
|
||||
public ByteBuffer putInt(int value) {
|
||||
askForBufferExtension(Integer.BYTES);
|
||||
buff.putInt(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.nio.ByteBuffer#putLong(long)
|
||||
*/
|
||||
public ByteBuffer putLong(long value) {
|
||||
askForBufferExtension(Long.BYTES);
|
||||
buff.putLong(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.nio.ByteBuffer#putFloat(float)
|
||||
*/
|
||||
public ByteBuffer putFloat(float value) {
|
||||
askForBufferExtension(Float.BYTES);
|
||||
buff.putFloat(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.nio.ByteBuffer#putDouble(double)
|
||||
*/
|
||||
public ByteBuffer putDouble(double value) {
|
||||
askForBufferExtension(Double.BYTES);
|
||||
buff.putDouble(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.nio.ByteBuffer#position()
|
||||
*/
|
||||
public int getPosition() {
|
||||
return buff.position();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.nio.ByteBuffer#position(int)
|
||||
*/
|
||||
public void setPosition(int p) {
|
||||
buff.position(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.nio.ByteBuffer#capacity()
|
||||
*/
|
||||
public int capacity() {
|
||||
return buff.capacity();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param s null String are supported
|
||||
*/
|
||||
public ByteBuffer putString(String s) {
|
||||
if (s == null) {
|
||||
return putInt(-1);
|
||||
}
|
||||
return putSizedByteArray(s.getBytes(NETWORK_CHARSET));
|
||||
}
|
||||
|
||||
/**
|
||||
* returned string can be null
|
||||
*/
|
||||
public String getString() {
|
||||
byte[] binaryString = getSizedByteArray();
|
||||
return (binaryString == null) ? null : new String(binaryString, NETWORK_CHARSET);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param list The list can be null, and any String can be null too.
|
||||
*/
|
||||
public ByteBuffer putListOfString(List<String> list) {
|
||||
if (list == null) {
|
||||
return putInt(-1);
|
||||
}
|
||||
putInt(list.size());
|
||||
for (String str : list)
|
||||
putString(str);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a List of String. The list can be null, and any element can be null too.
|
||||
*/
|
||||
public List<String> getListOfString() {
|
||||
int size = getInt();
|
||||
if (size < 0)
|
||||
return null;
|
||||
List<String> list = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++)
|
||||
list.add(getString());
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.nio.ByteBuffer#array()
|
||||
*/
|
||||
public byte[] array() {
|
||||
return buff.array();
|
||||
}
|
||||
|
||||
}
|
60
pandalib-net/src/main/java/fr/pandacube/lib/net/PPacket.java
Normal file
60
pandalib-net/src/main/java/fr/pandacube/lib/net/PPacket.java
Normal file
@ -0,0 +1,60 @@
|
||||
package fr.pandacube.lib.net;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
@Beta
|
||||
public class PPacket {
|
||||
public final String name;
|
||||
/* package */ int id;
|
||||
public final byte[] content;
|
||||
|
||||
/**
|
||||
* Construct a new PPacket based on the content of the provided buffer before his position.
|
||||
* @param n the name of the packet.
|
||||
* @param buff the buffer where the data comes from. Only the content before {@link ByteBuffer#getPosition()} is copied.
|
||||
*/
|
||||
public PPacket(String n, ByteBuffer buff) {
|
||||
this(n, Arrays.copyOf(buff.array(), buff.getPosition()));
|
||||
}
|
||||
|
||||
public PPacket(String n, byte[] c) {
|
||||
name = n;
|
||||
content = c;
|
||||
}
|
||||
|
||||
/* package */ PPacket(String n, int i, byte[] c) {
|
||||
this(n, c);
|
||||
id = i;
|
||||
}
|
||||
|
||||
public ByteBuffer getContentAsBuffer() {
|
||||
return new ByteBuffer(content);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static PPacket buildSingleStringContentPacket(String name, String content) {
|
||||
return new PPacket(name, new ByteBuffer().putString(content));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* package */ static PPacket buildLoginPacket(String password) {
|
||||
return buildSingleStringContentPacket("login", password);
|
||||
}
|
||||
/* package */ static PPacket buildBadFormatPacket(String message) {
|
||||
return buildSingleStringContentPacket("bad_format", message);
|
||||
}
|
||||
/* package */ static PPacket buildLoginBadPacket() {
|
||||
return new PPacket("login_bad", new byte[0]);
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package fr.pandacube.lib.net;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
@Beta
|
||||
public class PPacketAnswer extends PPacket {
|
||||
/* package */ final int answer;
|
||||
|
||||
/**
|
||||
* Construct a new PPacketAnswer based on the content of the provided buffer before his position.
|
||||
* @param n the name of the packet.
|
||||
* @param buff the buffer where the data comes from. Only the content before {@link ByteBuffer#getPosition()} is copied.
|
||||
*/
|
||||
public PPacketAnswer(PPacket answered, String n, ByteBuffer buff) {
|
||||
this(answered, n, Arrays.copyOf(buff.array(), buff.getPosition()));
|
||||
}
|
||||
|
||||
public PPacketAnswer(PPacket answered, String n, byte[] c) {
|
||||
super(n, c);
|
||||
answer = answered.id;
|
||||
}
|
||||
|
||||
/* package */ PPacketAnswer(String n, int i, int a, byte[] c) {
|
||||
super(n, i, c);
|
||||
answer = a;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static PPacketAnswer buildSingleStringContentPacketAnswer(PPacket answered, String name, String content) {
|
||||
ByteBuffer pwBuff = new ByteBuffer().putString(content);
|
||||
return new PPacketAnswer(answered, name, Arrays.copyOf(pwBuff.array(), pwBuff.getPosition()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* package */ static PPacketAnswer buildLoginOkPacket(PPacket loginPacket) {
|
||||
return new PPacketAnswer(loginPacket, "login_ok", new byte[0]);
|
||||
}
|
||||
/* package */ static PPacketAnswer buildExceptionPacket(PPacket answered, String message) {
|
||||
return buildSingleStringContentPacketAnswer(answered, "exception", message);
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package fr.pandacube.lib.net;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
@Beta
|
||||
@FunctionalInterface
|
||||
public interface PPacketListener<P extends PPacket> {
|
||||
|
||||
/**
|
||||
* Called when we receive a packet (except responses)
|
||||
* @param connection the connection from where the packet comes
|
||||
* @param packet the received packet
|
||||
*/
|
||||
void onPacketReceive(PSocket connection, P packet);
|
||||
|
||||
}
|
157
pandalib-net/src/main/java/fr/pandacube/lib/net/PServer.java
Normal file
157
pandalib-net/src/main/java/fr/pandacube/lib/net/PServer.java
Normal file
@ -0,0 +1,157 @@
|
||||
package fr.pandacube.lib.net;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
import fr.pandacube.lib.util.Log;
|
||||
|
||||
@Beta
|
||||
public class PServer extends Thread implements Closeable {
|
||||
private static final AtomicInteger connectionCounterId = new AtomicInteger(0);
|
||||
|
||||
private final int port;
|
||||
private ServerSocket socket;
|
||||
private final String socketName;
|
||||
|
||||
private final List<TCPServerClientConnection> clients = Collections.synchronizedList(new ArrayList<>());
|
||||
|
||||
private final AtomicBoolean isClosed = new AtomicBoolean(false);
|
||||
|
||||
|
||||
private final List<PPacketListener<PPacket>> globalPacketListeners = Collections.synchronizedList(new ArrayList<>());
|
||||
private final List<PSocketConnectionListener> clientConnectionListeners = Collections.synchronizedList(new ArrayList<>());
|
||||
|
||||
|
||||
|
||||
private final String password;
|
||||
|
||||
public PServer(int port, String sckName, String password) {
|
||||
super("PServer " + sckName);
|
||||
setDaemon(true);
|
||||
if (port <= 0 || port > 65535) throw new IllegalArgumentException("le numéro de port est invalide");
|
||||
socketName = sckName;
|
||||
this.port = port;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
|
||||
socket = new ServerSocket();
|
||||
socket.setReceiveBufferSize(PSocket.NETWORK_TCP_BUFFER_SIZE);
|
||||
socket.setPerformancePreferences(0, 1, 0);
|
||||
socket.bind(new InetSocketAddress(port));
|
||||
|
||||
while (true) {
|
||||
Socket socketClient = socket.accept();
|
||||
socketClient.setSendBufferSize(PSocket.NETWORK_TCP_BUFFER_SIZE);
|
||||
socketClient.setSoTimeout(PSocket.NETWORK_TIMEOUT);
|
||||
|
||||
TCPServerClientConnection co = new TCPServerClientConnection(socketClient,
|
||||
connectionCounterId.getAndIncrement());
|
||||
co.start();
|
||||
}
|
||||
} catch (SocketException ignored) {
|
||||
} catch (Exception e) {
|
||||
Log.warning("Plus aucune connexion ne peux être acceptée", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void addPacketListener(PPacketListener<PPacket> l) {
|
||||
globalPacketListeners.add(l);
|
||||
}
|
||||
|
||||
public boolean removePacketListener(PPacketListener<PPacket> l) {
|
||||
return globalPacketListeners.remove(l);
|
||||
}
|
||||
|
||||
public void addConnectionListener(PSocketConnectionListener l) {
|
||||
clientConnectionListeners.add(l);
|
||||
}
|
||||
|
||||
public void removeConnectionListener(PSocketConnectionListener l) {
|
||||
clientConnectionListeners.remove(l);
|
||||
}
|
||||
|
||||
protected class TCPServerClientConnection extends PSocket {
|
||||
|
||||
boolean loggedIn;
|
||||
|
||||
private TCPServerClientConnection(Socket s, int coId) {
|
||||
super(s, "Conn#" + coId + " via PServer " + socketName, password);
|
||||
addConnectionListener(new PSocketConnectionListener() {
|
||||
@Override
|
||||
public void onDisconnect(PSocket connection) {
|
||||
try {
|
||||
clientConnectionListeners.forEach(l -> l.onDisconnect(connection));
|
||||
} finally {
|
||||
clients.remove((TCPServerClientConnection)connection);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onConnect(PSocket connection) {
|
||||
clients.add((TCPServerClientConnection)connection);
|
||||
clientConnectionListeners.forEach(l -> l.onConnect(connection));
|
||||
}
|
||||
});
|
||||
addPacketListener((conn, packet) ->
|
||||
globalPacketListeners.forEach(l -> {
|
||||
try {
|
||||
l.onPacketReceive(conn, packet);
|
||||
} catch (Exception e) {
|
||||
Log.severe("Exception while calling PPacketListener.onPacketReceive().", e);
|
||||
sendSilently(PPacketAnswer.buildExceptionPacket(packet, e.toString()));
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
if (isClosed.get()) return;
|
||||
isClosed.set(true);
|
||||
|
||||
clients.forEach(PSocket::close);
|
||||
|
||||
socket.close();
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
|
||||
public boolean isClosed() {
|
||||
return isClosed.get() || socket.isClosed();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public List<PSocket> getClients() {
|
||||
synchronized (clients) {
|
||||
return new ArrayList<>(clients);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getClass().getName() + "{thread=" + getName() + ", socket=" + socket + "}";
|
||||
}
|
||||
|
||||
}
|
350
pandalib-net/src/main/java/fr/pandacube/lib/net/PSocket.java
Normal file
350
pandalib-net/src/main/java/fr/pandacube/lib/net/PSocket.java
Normal file
@ -0,0 +1,350 @@
|
||||
package fr.pandacube.lib.net;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.Closeable;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
import fr.pandacube.lib.util.Log;
|
||||
|
||||
/**
|
||||
* A wrapper for a {@link Socket}. The connection must point to a software using {@link PServer}
|
||||
* as wrapper for the target {@link ServerSocket}.
|
||||
* <br>
|
||||
* This class provides a simple way to exchange data between client and server :
|
||||
* <ul>
|
||||
* <li>Maintained connection with the server</li>
|
||||
* <li>Login with a password (send in the first packet)</li>
|
||||
* <li>Binary packet id</li>
|
||||
* <li>Binary data</li>
|
||||
* <li>Input stream in a separate Thread</li>
|
||||
* </ul>
|
||||
*
|
||||
*/
|
||||
@Beta
|
||||
public class PSocket extends Thread implements Closeable {
|
||||
|
||||
public static final int NETWORK_TCP_BUFFER_SIZE = 1024 * 1024;
|
||||
|
||||
public static final int NETWORK_TIMEOUT = 0; // no timeout (milli-seconds)
|
||||
|
||||
private boolean server = false;
|
||||
private Socket socket;
|
||||
private final SocketAddress addr;
|
||||
private DataInputStream in;
|
||||
private DataOutputStream out;
|
||||
private final Object outSynchronizer = new Object();
|
||||
private String password;
|
||||
|
||||
private final AtomicBoolean isClosed = new AtomicBoolean(false);
|
||||
|
||||
private final List<PPacketListener<PPacket>> packetListeners = Collections.synchronizedList(new ArrayList<>());
|
||||
private final List<PSocketConnectionListener> connectionListeners = Collections.synchronizedList(new ArrayList<>());
|
||||
private final Map<Integer, PPacketListener<PPacketAnswer>> answersCallbacks = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
private int nextSendId = 0;
|
||||
|
||||
/**
|
||||
* Create a new PSocket that will connect to the specified SocketAddress.
|
||||
* @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 pass the password to send to the server.
|
||||
*/
|
||||
public PSocket(SocketAddress a, String connName, String pass) {
|
||||
super("PSocket " + connName);
|
||||
setDaemon(true);
|
||||
if (a == null) throw new IllegalArgumentException("les arguments ne peuvent pas être null");
|
||||
addr = a;
|
||||
}
|
||||
|
||||
|
||||
/* package */ PSocket(Socket s, String connName, String pass) {
|
||||
this(s.getRemoteSocketAddress(), connName, pass);
|
||||
socket = s;
|
||||
server = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
if (socket == null) {
|
||||
socket = new Socket();
|
||||
socket.setReceiveBufferSize(NETWORK_TCP_BUFFER_SIZE);
|
||||
socket.setSendBufferSize(NETWORK_TCP_BUFFER_SIZE);
|
||||
|
||||
socket.setSoTimeout(10000); // initial timeout before login
|
||||
|
||||
socket.connect(addr);
|
||||
|
||||
in = new DataInputStream(socket.getInputStream());
|
||||
out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
|
||||
}
|
||||
|
||||
// password check
|
||||
if (server) {
|
||||
PPacket packet = readPacket();
|
||||
if (packet == null || packet instanceof PPacketAnswer || !"login".equals(packet.name)) {
|
||||
send(PPacket.buildLoginBadPacket());
|
||||
close();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
String receivedPassword = new ByteBuffer(packet.content).getString();
|
||||
if (!Objects.equals(receivedPassword, password)) {
|
||||
send(PPacket.buildLoginBadPacket());
|
||||
close();
|
||||
return;
|
||||
}
|
||||
} catch(Exception e) {
|
||||
send(PPacket.buildLoginBadPacket());
|
||||
close();
|
||||
return;
|
||||
}
|
||||
send(PPacketAnswer.buildLoginOkPacket(packet));
|
||||
// login ok at this point
|
||||
}
|
||||
else {
|
||||
send(PPacket.buildLoginPacket(password));
|
||||
PPacket packet = readPacket();
|
||||
if (packet == null) {
|
||||
Log.severe("bad packet received from server. Disconnecting.");
|
||||
close();
|
||||
return;
|
||||
}
|
||||
if (packet.name.equals("login_bad")) {
|
||||
Log.severe("Wrong password to connect to server. Disconnecting.");
|
||||
close();
|
||||
return;
|
||||
}
|
||||
if (!packet.name.equals("login_ok")) {
|
||||
Log.severe("Unexpected packet from server. Disconnecting.");
|
||||
close();
|
||||
return;
|
||||
}
|
||||
// login ok at this point
|
||||
}
|
||||
password = null;
|
||||
|
||||
socket.setSoTimeout(NETWORK_TIMEOUT);
|
||||
|
||||
Log.info(getName() + " connected.");
|
||||
|
||||
connectionListeners.forEach(l -> {
|
||||
try {
|
||||
l.onConnect(this);
|
||||
} catch (Exception e) {
|
||||
Log.severe("Exception while calling PSocketConnectionListener.onConnect().", e);
|
||||
}
|
||||
});
|
||||
|
||||
while (!socket.isClosed()) {
|
||||
PPacket packet = readPacket();
|
||||
|
||||
if (packet == null) {
|
||||
send(PPacket.buildBadFormatPacket("Bad format for the last packet received. Closing connection."));
|
||||
break;
|
||||
}
|
||||
|
||||
if (packet instanceof PPacketAnswer) {
|
||||
try {
|
||||
answersCallbacks.remove(((PPacketAnswer)packet).answer).onPacketReceive(this, (PPacketAnswer)packet);
|
||||
} catch (Exception e) {
|
||||
Log.severe("Exception while calling PPacketListener.onPacketReceive().", e);
|
||||
send(PPacketAnswer.buildExceptionPacket(packet, e.toString()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
packetListeners.forEach(l -> {
|
||||
try {
|
||||
l.onPacketReceive(this, packet);
|
||||
} catch (Exception e) {
|
||||
Log.severe("Exception while calling PPacketListener.onPacketReceive().", e);
|
||||
sendSilently(PPacketAnswer.buildExceptionPacket(packet, e.toString()));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.severe(e);
|
||||
}
|
||||
close();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the packet read in the socket, or null if the packet is in a bad format.
|
||||
* @return the packet
|
||||
*
|
||||
*/
|
||||
private PPacket readPacket() throws IOException {
|
||||
byte nSize = in.readByte();
|
||||
if (nSize == 0) {
|
||||
return null;
|
||||
}
|
||||
boolean answer = nSize < 0;
|
||||
if (answer)
|
||||
nSize *= -1;
|
||||
|
||||
|
||||
byte[] nBytes = new byte[nSize];
|
||||
in.readFully(nBytes);
|
||||
String name = new String(nBytes, ByteBuffer.NETWORK_CHARSET);
|
||||
|
||||
|
||||
int packetId = in.readInt();
|
||||
|
||||
|
||||
int answerId = (answer) ? in.readInt() : -1;
|
||||
|
||||
|
||||
int cSize = in.readInt();
|
||||
if (cSize < 0 || cSize > 0xFFFFFF) { // can't be more that 16 MiB
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
byte[] content = new byte[cSize];
|
||||
in.readFully(content);
|
||||
|
||||
return answer ? new PPacketAnswer(name, packetId, answerId, content) : new PPacket(name, packetId, content);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Send the provided packet, without waiting for an answer.
|
||||
*/
|
||||
public void send(PPacket packet) throws IOException {
|
||||
if (packet == null)
|
||||
throw new IllegalArgumentException("packet can't be null");
|
||||
if (packet.name == null)
|
||||
throw new IllegalArgumentException("packet.name can't be null");
|
||||
if (packet.content == null)
|
||||
throw new IllegalArgumentException("packet.content can't be null");
|
||||
|
||||
byte[] nameBytes = packet.name.getBytes(ByteBuffer.NETWORK_CHARSET);
|
||||
if (nameBytes.length > 127)
|
||||
throw new IllegalArgumentException("packet.name must take fewer than 128 bytes when converted to UTF-8");
|
||||
byte nameSize = (byte)nameBytes.length;
|
||||
|
||||
boolean answer = packet instanceof PPacketAnswer;
|
||||
|
||||
if (answer) nameSize *= -1;
|
||||
|
||||
synchronized (outSynchronizer) {
|
||||
int packetId = nextSendId++;
|
||||
|
||||
packet.id = packetId;
|
||||
|
||||
out.write(new byte[] {nameSize});
|
||||
out.write(nameBytes);
|
||||
out.write(packetId);
|
||||
if (answer)
|
||||
out.write(((PPacketAnswer)packet).answer);
|
||||
out.write(packet.content.length);
|
||||
out.write(packet.content);
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
|
||||
public void sendSilently(PPacket packet) {
|
||||
try {
|
||||
send(packet);
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void send(PPacket packet, PPacketListener<PPacketAnswer> answerCallback) throws IOException {
|
||||
synchronized (answersCallbacks) {
|
||||
/*
|
||||
* This synch block ensure that the callback will be put in the listeners Map before
|
||||
* we receve the answer (in case this is really really fast)
|
||||
*/
|
||||
send(packet);
|
||||
answersCallbacks.put(packet.id, answerCallback);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public void addPacketListener(PPacketListener<PPacket> l) {
|
||||
packetListeners.add(l);
|
||||
}
|
||||
|
||||
public boolean removePacketListener(PPacketListener<PPacket> l) {
|
||||
return packetListeners.remove(l);
|
||||
}
|
||||
|
||||
|
||||
public void addConnectionListener(PSocketConnectionListener l) {
|
||||
connectionListeners.add(l);
|
||||
}
|
||||
|
||||
public void removeConnectionListener(PSocketConnectionListener l) {
|
||||
connectionListeners.remove(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
synchronized (outSynchronizer) {
|
||||
if (isClosed.get()) return;
|
||||
|
||||
Log.info(getName() + " closing...");
|
||||
|
||||
connectionListeners.forEach(l -> {
|
||||
try {
|
||||
l.onDisconnect(this);
|
||||
} catch (Exception e) {
|
||||
Log.severe("Exception while calling PSocketConnectionListener.onDisconnect().", e);
|
||||
}
|
||||
});
|
||||
|
||||
socket.close();
|
||||
isClosed.set(true);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.warning(e);
|
||||
}
|
||||
}
|
||||
|
||||
public SocketAddress getRemoteAddress() {
|
||||
return addr;
|
||||
}
|
||||
|
||||
public boolean isClosed() {
|
||||
return isClosed.get() || socket.isClosed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getClass().getName() + "{thread=" + getName() + ", socket=" + socket + "}";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package fr.pandacube.lib.net;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
@Beta
|
||||
public interface PSocketConnectionListener {
|
||||
|
||||
/**
|
||||
* Called when a socket is connected
|
||||
* @param connection the connection
|
||||
*/
|
||||
void onConnect(PSocket connection);
|
||||
|
||||
/**
|
||||
* Called just before a socket is disconnected
|
||||
* @param connection the connection
|
||||
*/
|
||||
void onDisconnect(PSocket connection);
|
||||
|
||||
}
|
@ -18,7 +18,7 @@ public class ResponseAnalyser {
|
||||
if (socket == null || socket.isClosed() || socket.isInputShutdown())
|
||||
throw new IllegalArgumentException("le socket doit être non null et doit être ouvert sur le flux d'entrée");
|
||||
|
||||
// on lit la réponse
|
||||
// on lis la réponse
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
|
||||
String line;
|
||||
|
@ -11,9 +11,9 @@ public abstract class AbstractRequestExecutor {
|
||||
|
||||
public final String command;
|
||||
|
||||
public AbstractRequestExecutor(String cmd, NetworkAPIListener nAPIListener) {
|
||||
public AbstractRequestExecutor(String cmd, NetworkAPIListener napiListener) {
|
||||
command = cmd.toLowerCase();
|
||||
nAPIListener.registerRequestExecutor(command, this);
|
||||
napiListener.registerRequestExecutor(command, this);
|
||||
}
|
||||
|
||||
public void execute(String data, Socket socket) throws IOException {
|
||||
@ -34,8 +34,9 @@ public abstract class AbstractRequestExecutor {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param data The String representation of the request data.
|
||||
* @return The response to send back to the client.
|
||||
* @param data La représentation sous forme de String des données envoyés
|
||||
* dans la requête
|
||||
* @return La réponse à retourner au client
|
||||
*/
|
||||
protected abstract Response run(InetAddress source, String data);
|
||||
|
||||
|
@ -18,7 +18,7 @@ public class NetworkAPIListener implements Runnable {
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Instancie le côté serveur du NetworkAPI.
|
||||
* Instencie le côté serveur du NetworkAPI.
|
||||
*
|
||||
* @param n nom du networkAPI (permet l'identification dans les logs)
|
||||
* @param p le port d'écoute
|
||||
@ -29,7 +29,7 @@ public class NetworkAPIListener implements Runnable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Instancie le côté serveur du NetworkAPI.
|
||||
* Instencie le côté serveur du NetworkAPI.
|
||||
*
|
||||
* @param n nom du networkAPI (permet l'identification dans les logs)
|
||||
* @param p le port d'écoute
|
||||
@ -56,6 +56,7 @@ public class NetworkAPIListener implements Runnable {
|
||||
Log.info("NetworkAPI '" + name + "' à l'écoute sur le socket " + serverSocket.getLocalSocketAddress());
|
||||
|
||||
try {
|
||||
// réception des connexion client
|
||||
while (!serverSocket.isClosed()) {
|
||||
Thread t = new Thread(new PacketExecutor(serverSocket.accept(), this));
|
||||
t.setDaemon(true);
|
||||
|
@ -20,9 +20,9 @@ public class PacketExecutor implements Runnable {
|
||||
private final Socket socket;
|
||||
private final NetworkAPIListener networkAPIListener;
|
||||
|
||||
public PacketExecutor(Socket s, NetworkAPIListener nAPIListener) {
|
||||
public PacketExecutor(Socket s, NetworkAPIListener napiListener) {
|
||||
socket = s;
|
||||
networkAPIListener = nAPIListener;
|
||||
networkAPIListener = napiListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -10,23 +10,23 @@ public class RequestAnalyser {
|
||||
public final String command;
|
||||
public final String data;
|
||||
|
||||
public RequestAnalyser(Socket socket, NetworkAPIListener nAPIListener) throws IOException, BadRequestException {
|
||||
if (socket == null || socket.isClosed() || socket.isInputShutdown() || nAPIListener == null)
|
||||
public RequestAnalyser(Socket socket, NetworkAPIListener napiListener) throws IOException, BadRequestException {
|
||||
if (socket == null || socket.isClosed() || socket.isInputShutdown() || napiListener == null)
|
||||
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");
|
||||
|
||||
// on lit la réponse
|
||||
// on lis la réponse
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
|
||||
String line;
|
||||
|
||||
// lecture de la première ligne
|
||||
line = in.readLine();
|
||||
if (line == null || !line.equals(nAPIListener.pass)) throw new BadRequestException("wrong_password");
|
||||
if (line == null || !line.equals(napiListener.pass)) throw new BadRequestException("wrong_password");
|
||||
|
||||
// lecture de la deuxième ligne
|
||||
line = in.readLine();
|
||||
if (line == null || nAPIListener.getRequestExecutor(line) == null)
|
||||
if (line == null || napiListener.getRequestExecutor(line) == null)
|
||||
throw new BadRequestException("command_not_exists");
|
||||
command = line;
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
<url>https://maven.enginehub.org/repo/</url>
|
||||
</repository>
|
||||
|
||||
<!-- Vault and maybe other dependencies -->
|
||||
<!-- Vault and maybe other dependecies -->
|
||||
<repository>
|
||||
<id>jitpack.io</id>
|
||||
<url>https://jitpack.io</url>
|
||||
@ -33,12 +33,12 @@
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<!-- <dependency>
|
||||
<dependency>
|
||||
<groupId>fr.pandacube.lib</groupId>
|
||||
<artifactId>pandalib-players-permissible</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency> -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>fr.pandacube.lib</groupId>
|
||||
<artifactId>pandalib-permissions</artifactId>
|
||||
|
@ -42,7 +42,7 @@ public class PandalibPaperPermissions implements Listener {
|
||||
* Integrates the {@code pandalib-permissions} system into the Bukkit server.
|
||||
* @param plugin a Bukkit plugin.
|
||||
* @param serverName the name of the current server, used to fetch server specific permissions. Cannot be null.
|
||||
* If this server in not in a multiserver configuration, use a dummy server name, like
|
||||
* If this server in not in a multi-server configuration, use a dummy server name, like
|
||||
* {@code ""} (empty string).
|
||||
*/
|
||||
public static void init(JavaPlugin plugin, String serverName) {
|
||||
|
@ -1,23 +1,5 @@
|
||||
package fr.pandacube.lib.paper.permissions;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import fr.pandacube.lib.permissions.Permissions;
|
||||
import fr.pandacube.lib.reflect.Reflect;
|
||||
import fr.pandacube.lib.util.Log;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.Permissible;
|
||||
import org.bukkit.permissions.PermissibleBase;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.permissions.PermissionAttachment;
|
||||
import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
@ -29,6 +11,24 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.Permissible;
|
||||
import org.bukkit.permissions.PermissibleBase;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.permissions.PermissionAttachment;
|
||||
import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import fr.pandacube.lib.permissions.Permissions;
|
||||
import fr.pandacube.lib.reflect.Reflect;
|
||||
import fr.pandacube.lib.util.Log;
|
||||
|
||||
/* package */ class PermissionsInjectorBukkit
|
||||
{
|
||||
|
||||
@ -58,24 +58,26 @@ import java.util.stream.Collectors;
|
||||
}
|
||||
}
|
||||
|
||||
private static void setPermissible(CommandSender sender, Permissible newPermissible)
|
||||
private static void setPermissible(CommandSender sender, Permissible newpermissible)
|
||||
{
|
||||
try {
|
||||
Field perm = getPermField(sender);
|
||||
if (perm == null)
|
||||
return;
|
||||
perm.setAccessible(true);
|
||||
perm.set(sender, newPermissible);
|
||||
perm.set(sender, newpermissible);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
Log.severe(e);
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ static Permissible getPermissible(CommandSender sender)
|
||||
{
|
||||
Field perm = getPermField(sender);
|
||||
if (perm == null)
|
||||
return null;
|
||||
try {
|
||||
Field perm = getPermField(sender);
|
||||
perm.setAccessible(true);
|
||||
Permissible p = (Permissible) perm.get(sender);
|
||||
if (p == null) {
|
||||
@ -84,19 +86,26 @@ import java.util.stream.Collectors;
|
||||
return p;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
Log.severe(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Field getPermField(CommandSender sender) throws NoSuchFieldException {
|
||||
private static Field getPermField(CommandSender sender)
|
||||
{
|
||||
if (sender == null) {
|
||||
throw new IllegalArgumentException("sender cannot be null");
|
||||
}
|
||||
if (sender instanceof Player || sender instanceof ConsoleCommandSender)
|
||||
return Reflect.ofClassOfInstance(sender).field("perm").get();
|
||||
else
|
||||
throw new IllegalArgumentException("Unsupported type for sender: " + sender.getClass());
|
||||
|
||||
try {
|
||||
if (sender instanceof Player || sender instanceof ConsoleCommandSender)
|
||||
return Reflect.ofClassOfInstance(sender).field("perm").get();
|
||||
else
|
||||
throw new IllegalArgumentException("Unsupported type for sender: " + sender.getClass());
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.severe(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* package */ static class PandaPermissible extends PermissibleBase
|
||||
@ -109,7 +118,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
@SuppressWarnings("UnusedAssignment")
|
||||
private boolean init = false;
|
||||
/* assignment to false is necessary because of super class constructor calling the method recalculatePermission()
|
||||
/* assigment to false is necessary because of super class constructor calling the method recalculatePermission()
|
||||
* and we don’t want that.
|
||||
*/
|
||||
|
||||
@ -134,7 +143,7 @@ import java.util.stream.Collectors;
|
||||
public boolean hasPermission(String permission)
|
||||
{
|
||||
/*
|
||||
* WARNING: don’t call PermissibleOnlinePlayer#hasPermission(String) here, or it will result on a stack overflow
|
||||
* WARNING: don’t call PermissibleOnlinePlayer#hasPermission(String) here or it will result on a stack overflow
|
||||
*/
|
||||
|
||||
if (permission.toLowerCase().startsWith("minecraft.command."))
|
||||
@ -171,7 +180,7 @@ import java.util.stream.Collectors;
|
||||
if (res != null)
|
||||
return res;
|
||||
|
||||
return oldPermissible.hasPermission(permission); // doesn't need to manage negative permission (should not happen)
|
||||
return oldPermissible.hasPermission(permission); // doesn’t need to manage negative permission (should not happend)
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -205,34 +214,36 @@ import java.util.stream.Collectors;
|
||||
.build();
|
||||
|
||||
@Override
|
||||
public @NotNull Set<PermissionAttachmentInfo> getEffectivePermissions()
|
||||
public Set<PermissionAttachmentInfo> getEffectivePermissions()
|
||||
{
|
||||
// PlotSquared uses this method to optimize permission range (plots.limit.10 for example)
|
||||
// MobArena uses this method when a player leave the arena
|
||||
// LibsDisguises uses this method (and only this one) to parse all the permissions
|
||||
|
||||
//Log.warning("There is a plugin calling CommandSender#getEffectivePermissions(). See the stacktrace to understand the reason for that.", new Throwable());
|
||||
|
||||
String world = null;
|
||||
if (sender instanceof Player player) {
|
||||
String world = player.getWorld().getName();
|
||||
try {
|
||||
return effectivePermissionsListCache.get(world, () -> {
|
||||
// first get the superperms effective permissions (that take isOp into account)
|
||||
Map<String, PermissionAttachmentInfo> perms = oldPermissible.getEffectivePermissions().stream()
|
||||
.collect(Collectors.toMap(PermissionAttachmentInfo::getPermission, Function.identity()));
|
||||
|
||||
// then override them with the permissions from our permission system (that has priority, and take current world into account)
|
||||
for (Map.Entry<String, Boolean> permE : getEffectivePermissionsOnServerInWorld().entrySet()) {
|
||||
perms.put(permE.getKey(), new PermissionAttachmentInfo(this, permE.getKey(), null, permE.getValue()));
|
||||
}
|
||||
|
||||
return new LinkedHashSet<>(perms.values());
|
||||
});
|
||||
} catch (ExecutionException e) {
|
||||
Log.severe(e);
|
||||
}
|
||||
world = player.getWorld().getName();
|
||||
}
|
||||
|
||||
|
||||
return oldPermissible.getEffectivePermissions();
|
||||
try {
|
||||
return effectivePermissionsListCache.get(world, () -> {
|
||||
// first get the superperms effective permissions (taht take isOp into accound)
|
||||
Map<String, PermissionAttachmentInfo> perms = oldPermissible.getEffectivePermissions().stream()
|
||||
.collect(Collectors.toMap(PermissionAttachmentInfo::getPermission, Function.identity()));
|
||||
|
||||
// then override them with the permissions from our permission system (that has priority, and take current world into account)
|
||||
for (Map.Entry<String, Boolean> permE : getEffectivePermissionsOnServerInWorld().entrySet()) {
|
||||
perms.put(permE.getKey(), new PermissionAttachmentInfo(this, permE.getKey(), null, permE.getValue()));
|
||||
}
|
||||
|
||||
return new LinkedHashSet<>(perms.values());
|
||||
});
|
||||
} catch (ExecutionException e) {
|
||||
Log.severe(e);
|
||||
return oldPermissible.getEffectivePermissions();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -249,7 +260,7 @@ import java.util.stream.Collectors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermissionSet(@NotNull String permission)
|
||||
public boolean isPermissionSet(String permission)
|
||||
{
|
||||
Boolean res = hasPermissionOnServerInWorld(permission);
|
||||
if (res != null)
|
||||
@ -267,31 +278,31 @@ import java.util.stream.Collectors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PermissionAttachment addAttachment(@NotNull Plugin plugin)
|
||||
public PermissionAttachment addAttachment(Plugin plugin)
|
||||
{
|
||||
return oldPermissible.addAttachment(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(@NotNull Plugin plugin, int ticks)
|
||||
public PermissionAttachment addAttachment(Plugin plugin, int ticks)
|
||||
{
|
||||
return oldPermissible.addAttachment(plugin, ticks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PermissionAttachment addAttachment(@NotNull Plugin plugin, @NotNull String name, boolean value)
|
||||
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value)
|
||||
{
|
||||
return oldPermissible.addAttachment(plugin, name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(@NotNull Plugin plugin, @NotNull String name, boolean value, int ticks)
|
||||
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks)
|
||||
{
|
||||
return oldPermissible.addAttachment(plugin, name, value, ticks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttachment(@NotNull PermissionAttachment attachment)
|
||||
public void removeAttachment(PermissionAttachment attachment)
|
||||
{
|
||||
oldPermissible.removeAttachment(attachment);
|
||||
}
|
||||
|
@ -6,12 +6,11 @@ import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("CanBeFinal")
|
||||
public class PaperBackupConfig {
|
||||
public boolean worldBackupEnabled = true;
|
||||
public boolean workdirBackupEnabled = true;
|
||||
public boolean logsBackupEnabled = true;
|
||||
public String scheduling = "0 2 * * *"; // cron format, here is every day at 2am
|
||||
public String scheduling = "0 2 * * *"; // cron format, here is everyday at 2am
|
||||
public File backupDirectory = null;
|
||||
public BackupCleaner worldBackupCleaner = BackupCleaner.KEEPING_1_EVERY_N_MONTH(3).merge(BackupCleaner.KEEPING_N_LAST(5));
|
||||
public BackupCleaner workdirBackupCleaner = BackupCleaner.KEEPING_1_EVERY_N_MONTH(3).merge(BackupCleaner.KEEPING_N_LAST(5));
|
||||
|
@ -1,6 +1,10 @@
|
||||
package fr.pandacube.lib.paper.backup;
|
||||
|
||||
import fr.pandacube.lib.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.function.BiPredicate;
|
||||
|
||||
public class PaperWorkdirProcess extends PaperBackupProcess {
|
||||
@ -11,14 +15,17 @@ public class PaperWorkdirProcess extends PaperBackupProcess {
|
||||
|
||||
|
||||
public BiPredicate<File, String> getFilenameFilter() {
|
||||
return (file, path) -> {
|
||||
if (file.isDirectory() && new File(file, "level.dat").exists())
|
||||
return false;
|
||||
if (new File(getSourceDir(), "logs").equals(file))
|
||||
return false;
|
||||
if (file.isFile() && file.getName().endsWith(".lck"))
|
||||
return false;
|
||||
return PaperWorkdirProcess.super.getFilenameFilter().test(file, path);
|
||||
return new BiPredicate<File, String>() {
|
||||
@Override
|
||||
public boolean test(File file, String path) {
|
||||
if (file.isDirectory() && new File(file, "level.dat").exists())
|
||||
return false;
|
||||
if (new File(getSourceDir(), "logs").equals(file))
|
||||
return false;
|
||||
if (file.isFile() && file.getName().endsWith(".lck"))
|
||||
return false;
|
||||
return PaperWorkdirProcess.super.getFilenameFilter().test(file, path);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ import org.bukkit.World;
|
||||
import java.io.File;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.function.BiPredicate;
|
||||
|
||||
public class PaperWorldProcess extends PaperBackupProcess {
|
||||
private final String worldName;
|
||||
|
@ -77,7 +77,7 @@ public abstract class PaperBrigadierCommand extends BrigadierCommand<BukkitBriga
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a plugin command that overrides a vanilla command, so the vanilla command functionalities are fully
|
||||
* Removes a plugin command that overrides a vanilla command, so the vanilla command functionnalities are fully
|
||||
* restored (so, not only the usage, but also the suggestions and the command structure sent to the client).
|
||||
* @param name the name of the command to restore.
|
||||
*/
|
||||
@ -137,7 +137,7 @@ public abstract class PaperBrigadierCommand extends BrigadierCommand<BukkitBriga
|
||||
private Set<String> registeredAliases;
|
||||
|
||||
/**
|
||||
* Instantiate this command instance.
|
||||
* Instanciate this command instance.
|
||||
*
|
||||
* @param pl the plugin instance.
|
||||
* @param regPolicy the registration policy for this command.
|
||||
@ -155,7 +155,7 @@ public abstract class PaperBrigadierCommand extends BrigadierCommand<BukkitBriga
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate this command instance with a registration policy of {@link RegistrationPolicy#ONLY_BASE_COMMAND}.
|
||||
* Instanciate this command isntance with a registration policy of {@link RegistrationPolicy#ONLY_BASE_COMMAND}.
|
||||
* @param pl the plugin instance.
|
||||
*/
|
||||
public PaperBrigadierCommand(Plugin pl) {
|
||||
@ -206,10 +206,10 @@ public abstract class PaperBrigadierCommand extends BrigadierCommand<BukkitBriga
|
||||
|
||||
// nmsDispatcher integration and conflit resolution
|
||||
boolean nmsRegister = false, nmsRegistered = false;
|
||||
CommandNode<BukkitBrigadierCommandSource> nmsConflicted = root.getChild(name);
|
||||
if (nmsConflicted != null) {
|
||||
CommandNode<BukkitBrigadierCommandSource> nmsConflited = root.getChild(name);
|
||||
if (nmsConflited != null) {
|
||||
|
||||
if (isFromThisCommand(nmsConflicted)) {
|
||||
if (isFromThisCommand(nmsConflited)) {
|
||||
// this command is already registered in NMS. Don’t need to register again
|
||||
nmsRegistered = true;
|
||||
}
|
||||
@ -221,7 +221,7 @@ public abstract class PaperBrigadierCommand extends BrigadierCommand<BukkitBriga
|
||||
Log.severe("/" + name + " already in NMS Brigadier instance."
|
||||
+ " Wont replace it because registration is not forced for prefixed or initial name of a command.");
|
||||
}
|
||||
else { // conflict, won't replace, not forced but only an alias anyway
|
||||
else { // conflict, wont replace, not forced but only an alias anyway
|
||||
Log.info("/" + name + " already in NMS Brigadier instance."
|
||||
+ " Wont replace it because registration is not forced for a non-prefixed alias.");
|
||||
}
|
||||
@ -418,7 +418,7 @@ public abstract class PaperBrigadierCommand extends BrigadierCommand<BukkitBriga
|
||||
|
||||
|
||||
/**
|
||||
* A suggestion supplier that suggests the names of the currently connected players (that the command sender can see).
|
||||
* A suggestions supplier that suggests the names of the currently connected players (that the command sender can see).
|
||||
*/
|
||||
public static final SuggestionsSupplier<CommandSender> TAB_PLAYER_CURRENT_SERVER = (sender, ti, token, a) -> {
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -432,7 +432,7 @@ public abstract class PaperBrigadierCommand extends BrigadierCommand<BukkitBriga
|
||||
};
|
||||
|
||||
/**
|
||||
* A suggestion supplier that suggests the names of the worlds currently loaded on this server.
|
||||
* A suggestions supplier that suggests the names of the worlds currently loaded on this server.
|
||||
*/
|
||||
public static final SuggestionsSupplier<CommandSender> TAB_WORLDS = SuggestionsSupplier.fromStreamSupplier(() -> Bukkit.getWorlds().stream().map(World::getName));
|
||||
|
||||
@ -477,7 +477,7 @@ public abstract class PaperBrigadierCommand extends BrigadierCommand<BukkitBriga
|
||||
|
||||
|
||||
/*
|
||||
* Minecraft's argument type
|
||||
* Minecraft argument type
|
||||
*/
|
||||
|
||||
|
||||
@ -577,13 +577,13 @@ public abstract class PaperBrigadierCommand extends BrigadierCommand<BukkitBriga
|
||||
* Gets the value of the provided argument of type {@code minecraft:block_pos}, from the provided context.
|
||||
* @param context the command execution context.
|
||||
* @param argument the argument name.
|
||||
* @param deflt a default value if the argument is not found.
|
||||
* @param deflt a defualt value if the argument is not found.
|
||||
* @return the value of the argument.
|
||||
*/
|
||||
public BlockVector tryGetMinecraftBlockPositionArgument(CommandContext<BukkitBrigadierCommandSource> context,
|
||||
String argument, BlockVector deflt) {
|
||||
return tryGetArgument(context, argument, Coordinates.MAPPING.runtimeClass(), nmsCoordinate -> {
|
||||
BlockPos bp = ReflectWrapper.wrap(nmsCoordinate, Coordinates.class).getBlockPos(context.getSource());
|
||||
return tryGetArgument(context, argument, Coordinates.MAPPING.runtimeClass(), nmsCoord -> {
|
||||
BlockPos bp = ReflectWrapper.wrap(nmsCoord, Coordinates.class).getBlockPos(context.getSource());
|
||||
return new BlockVector(bp.getX(), bp.getY(), bp.getZ());
|
||||
}, deflt);
|
||||
}
|
||||
@ -603,14 +603,14 @@ public abstract class PaperBrigadierCommand extends BrigadierCommand<BukkitBriga
|
||||
* Gets the value of the provided argument of type {@code minecraft:vec3}, from the provided context.
|
||||
* @param context the command execution context.
|
||||
* @param argument the argument name.
|
||||
* @param deflt a default value if the argument is not found.
|
||||
* @param deflt a defualt value if the argument is not found.
|
||||
* @return the value of the argument.
|
||||
*/
|
||||
public Vector tryGetMinecraftVec3Argument(CommandContext<BukkitBrigadierCommandSource> context, String argument,
|
||||
Vector deflt) {
|
||||
return tryGetArgument(context, argument, Coordinates.MAPPING.runtimeClass(),
|
||||
nmsCoordinate -> CraftVector.toBukkit(
|
||||
ReflectWrapper.wrap(nmsCoordinate, Coordinates.class).getPosition(context.getSource())
|
||||
nmsCoord -> CraftVector.toBukkit(
|
||||
ReflectWrapper.wrap(nmsCoord, Coordinates.class).getPosition(context.getSource())
|
||||
),
|
||||
deflt);
|
||||
}
|
||||
@ -630,7 +630,7 @@ public abstract class PaperBrigadierCommand extends BrigadierCommand<BukkitBriga
|
||||
* Gets the value of the provided argument of type {@code minecraft:component}, from the provided context.
|
||||
* @param context the command execution context.
|
||||
* @param argument the argument name.
|
||||
* @param deflt a default value if the argument is not found.
|
||||
* @param deflt a defualt value if the argument is not found.
|
||||
* @return the value of the argument.
|
||||
*/
|
||||
public Component tryGetMinecraftChatComponentArgument(CommandContext<BukkitBrigadierCommandSource> context,
|
||||
|
@ -24,36 +24,36 @@ import fr.pandacube.lib.util.Log;
|
||||
import fr.pandacube.lib.paper.util.BukkitEvent;
|
||||
|
||||
/**
|
||||
* Managed a "lobby" type hot bar menu/inventory. It represents items in the
|
||||
* player inventory on which you can right-click on it.
|
||||
* Managed a « lobby » type hotbar menu/inventory. It represents items in the player inventory on which you can right click on it.
|
||||
* The player can't move or drop these items.
|
||||
*
|
||||
*/
|
||||
public class GUIHotBar implements Listener {
|
||||
|
||||
private final Map<ItemStack, BiConsumer<PlayerInventory, ItemStack>> itemsAndSetters = new HashMap<>();
|
||||
|
||||
private final Map<ItemStack, Consumer<Player>> itemsAndClickListeners = new HashMap<>();
|
||||
private final Map<ItemStack, Consumer<Player>> itemsAndRunnables = new HashMap<>();
|
||||
|
||||
private final int defaultSlot;
|
||||
private final int defltSlot;
|
||||
|
||||
private final List<Player> currentPlayers = new ArrayList<>();
|
||||
|
||||
public GUIHotBar(int defaultSlot) {
|
||||
this.defaultSlot = Math.max(0, Math.min(8, defaultSlot));
|
||||
defltSlot = Math.max(0, Math.min(8, defaultSlot));
|
||||
|
||||
BukkitEvent.register(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the item to this hot bar menu. if there is already players hooked to this hot bar, the item will be directly added to
|
||||
* Add the item to this hotbar menu. if there is already players hooked to this hotbar, the item will be directly added to
|
||||
* their inventories.
|
||||
* @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 run the Runnable to run when the user right-click on the item in the hot bar.
|
||||
* @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.
|
||||
*/
|
||||
public GUIHotBar addItem(ItemStack i, BiConsumer<PlayerInventory, ItemStack> setter, Consumer<Player> run) {
|
||||
itemsAndSetters.put(i, setter);
|
||||
itemsAndClickListeners.put(i, run);
|
||||
itemsAndRunnables.put(i, run);
|
||||
|
||||
for (Player p : currentPlayers)
|
||||
addItemToPlayer(p, i);
|
||||
@ -62,9 +62,9 @@ public class GUIHotBar implements Listener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the hot bar elements to this player.
|
||||
* Add the hotbar elements to this player.
|
||||
*
|
||||
* The player is automatically removed when they 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)}.
|
||||
*/
|
||||
public void addPlayer(Player p) {
|
||||
if (!currentPlayers.contains(p))
|
||||
@ -74,11 +74,11 @@ public class GUIHotBar implements Listener {
|
||||
addItemToPlayer(p, is);
|
||||
}
|
||||
|
||||
p.getInventory().setHeldItemSlot(defaultSlot);
|
||||
p.getInventory().setHeldItemSlot(defltSlot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detach this player from this hot bar 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.
|
||||
*/
|
||||
public void removePlayer(Player p) {
|
||||
if (!currentPlayers.contains(p))
|
||||
@ -110,9 +110,9 @@ public class GUIHotBar implements Listener {
|
||||
|
||||
public void addItemToPlayer(Player p, ItemStack is) {
|
||||
if (!itemsAndSetters.containsKey(is))
|
||||
throw new IllegalArgumentException("The provided ItemStack is not registered in this GUIHotBar");
|
||||
throw new IllegalArgumentException("The provided ItemStack is not registered in this HotbarMenu");
|
||||
if (!currentPlayers.contains(p))
|
||||
throw new IllegalArgumentException("The provided Player is not registered in this GUIHotBar");
|
||||
throw new IllegalArgumentException("The provided Player is not registered in this HotbarMenu");
|
||||
itemsAndSetters.get(is).accept(p.getInventory(), is.clone());
|
||||
}
|
||||
|
||||
@ -153,10 +153,10 @@ public class GUIHotBar implements Listener {
|
||||
|
||||
Player p = event.getPlayer();
|
||||
|
||||
for (ItemStack is : itemsAndClickListeners.keySet()) {
|
||||
for (ItemStack is : itemsAndRunnables.keySet()) {
|
||||
if (item.isSimilar(is)) {
|
||||
try {
|
||||
itemsAndClickListeners.get(is).accept(p);
|
||||
itemsAndRunnables.get(is).accept(p);
|
||||
} catch (Exception e) {
|
||||
Log.severe(e);
|
||||
}
|
||||
@ -181,7 +181,7 @@ public class GUIHotBar implements Listener {
|
||||
for (ItemStack is : itemsAndSetters.keySet()) {
|
||||
if (item != null && item.isSimilar(is)) {
|
||||
try {
|
||||
itemsAndClickListeners.get(is).accept((Player) inv.getHolder());
|
||||
itemsAndRunnables.get(is).accept((Player) inv.getHolder());
|
||||
} catch (Exception e) {
|
||||
Log.severe(e);
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ public class GUIInventory implements Listener {
|
||||
|
||||
/**
|
||||
* Used as parameter of {@link #buildButton(ItemStack, Integer, ComponentLike, List, Map)} to indicate that a button should
|
||||
* shine like an enchanted object, without showing enchant information in the hover text.
|
||||
* shine like an enchanted object, without showing enchant informations in the hover text.
|
||||
*/
|
||||
public static final Map<Enchantment, Integer> FAKE_ENCHANT = ImmutableMap.of(Enchantment.DURABILITY, 1);
|
||||
|
||||
@ -44,7 +44,7 @@ public class GUIInventory implements Listener {
|
||||
/**
|
||||
* Create a new inventory based GUI.
|
||||
* @param p the player for which to create the GUI.
|
||||
* @param nbLines the number of inventory lines for the interface.
|
||||
* @param nbLines the number of invotory lines for the interface.
|
||||
* @param title the title of the GUI (title of the inventory)
|
||||
* @param closeEventAction the action to perform when the player closes the GUI inventory
|
||||
*/
|
||||
@ -73,7 +73,7 @@ public class GUIInventory implements Listener {
|
||||
* @param p the slot index.
|
||||
* @param iStack the item to put in the slot.
|
||||
* @param clickEventActions the action to perform when the user clicks that button. The event passed as a parameter
|
||||
* is already cancelled. It is possible to un-cancel it if needed.
|
||||
* is already cancelled. It is possible to uncancel it if needed.
|
||||
*/
|
||||
public void setButtonIfEmpty(int p, ItemStack iStack, Consumer<InventoryClickEvent> clickEventActions) {
|
||||
if (inv.getItem(p) == null)
|
||||
@ -85,7 +85,7 @@ public class GUIInventory implements Listener {
|
||||
* @param p the slot index.
|
||||
* @param iStack the item to put in the slot.
|
||||
* @param clickEventActions the action to perform when the user clicks that button. The event passed as a parameter
|
||||
* is already cancelled. It is possible to un-cancel it if needed.
|
||||
* is already cancelled. It is possible to uncancel it if needed.
|
||||
*/
|
||||
public void setButton(int p, ItemStack iStack, Consumer<InventoryClickEvent> clickEventActions) {
|
||||
inv.setItem(p, iStack);
|
||||
@ -96,7 +96,7 @@ public class GUIInventory implements Listener {
|
||||
* Update/replace the action to perform for a specific slot.
|
||||
* @param p the slot index.
|
||||
* @param clickEventActions the action to perform when the user clicks that button. The event passed as a parameter
|
||||
* is already cancelled. It is possible to un-cancel it if needed.
|
||||
* is already cancelled. It is possible to uncancel it if needed.
|
||||
*/
|
||||
public void changeClickEventAction(int p, Consumer<InventoryClickEvent> clickEventActions) {
|
||||
onClickEvents.put(p, clickEventActions);
|
||||
@ -122,7 +122,7 @@ public class GUIInventory implements Listener {
|
||||
|
||||
/**
|
||||
* Force this GUI to be closes, without the intervention of the player.
|
||||
* The bukkit API will call the {@link InventoryCloseEvent}, triggering eventual actions associated with this event.
|
||||
* The bukkit API will call the {@link InventoryCloseEvent}, trigerring eventual actions associated with this event.
|
||||
*/
|
||||
public void forceClose() {
|
||||
if (!isOpened) return;
|
||||
|
@ -28,11 +28,10 @@ import java.util.Map;
|
||||
Map<String, Object> deserializedMap = context.deserialize(json, MAP_STR_OBJ_TYPE.getType());
|
||||
int itemStackVersion = deserializedMap.containsKey("v") ? ((Number)deserializedMap.get("v")).intValue() : -1;
|
||||
if (itemStackVersion >= 0) {
|
||||
@SuppressWarnings("deprecation")
|
||||
int currentDataVersion = Bukkit.getUnsafe().getDataVersion();
|
||||
if (itemStackVersion > currentDataVersion) {
|
||||
/* The itemStack we are deserializing is from a newer MC version, so Bukkit will refuse it.
|
||||
* We decide to ignore the provided version and consider that the received item stack is from current
|
||||
* We decide to ignore the provided version and consider that the received itemstack is from current
|
||||
* version. We let Bukkit handles the deserialization with the data it can interpret, throwing an error
|
||||
* only if it can't.
|
||||
*/
|
||||
|
@ -28,6 +28,7 @@ import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
@ -56,7 +57,7 @@ public class PerformanceAnalysisManager implements Listener {
|
||||
}
|
||||
|
||||
|
||||
private static final int NB_TICK_HISTORY = 20 * 60 * 60; // 60 secondes ;
|
||||
private static final int NB_TICK_HISTORY = 20 * 60 * 60; // 60 secondes;
|
||||
|
||||
private final Plugin plugin = PandaLibPaper.getPlugin();
|
||||
private long firstRecord = 0;
|
||||
@ -291,7 +292,7 @@ public class PerformanceAnalysisManager implements Listener {
|
||||
}
|
||||
else {
|
||||
|
||||
String tps1sDisplay = Double.isNaN(tps1s) ? "N/A" : (Math.round(tps1s)) + "";
|
||||
String tps1sDisp = Double.isNaN(tps1s) ? "N/A" : (Math.round(tps1s)) + "";
|
||||
|
||||
|
||||
int[] tpsHistory = getTPSHistory();
|
||||
@ -318,7 +319,7 @@ public class PerformanceAnalysisManager implements Listener {
|
||||
// we have a lag spike, so we need to display the time since lagging
|
||||
long lagDurationSec = System.nanoTime() - tickEndNanoTime;
|
||||
timings = text("(")
|
||||
.thenFailure("lag:" + displayRound10(lagDurationSec / (double) 1_000_000_000) + "s")
|
||||
.thenFailure("lag:" + dispRound10(lagDurationSec / (double) 1_000_000_000) + "s")
|
||||
.thenText(")");
|
||||
}
|
||||
else {
|
||||
@ -358,7 +359,7 @@ public class PerformanceAnalysisManager implements Listener {
|
||||
title = infoText("TPS [")
|
||||
.thenLegacyText(s.toString())
|
||||
.thenText("] ")
|
||||
.then(text(tps1sDisplay+"/20 ").color(tps1sGradient.pickColorAt(tps1s)))
|
||||
.then(text(tps1sDisp+"/20 ").color(tps1sGradient.pickColorAt(tps1s)))
|
||||
.then(timings);
|
||||
}
|
||||
|
||||
@ -468,7 +469,7 @@ public class PerformanceAnalysisManager implements Listener {
|
||||
Log.info(finalMessage.getLegacyText());
|
||||
}
|
||||
|
||||
public static String displayRound10(double val) {
|
||||
public static String dispRound10(double val) {
|
||||
long v = (long) Math.ceil(val * 10);
|
||||
return "" + (v / 10f);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package fr.pandacube.lib.paper.players;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
import fr.pandacube.lib.paper.reflect.util.PrimaryWorlds;
|
||||
import fr.pandacube.lib.paper.reflect.wrapper.craftbukkit.CraftServer;
|
||||
import fr.pandacube.lib.paper.reflect.wrapper.dataconverter.MCDataConverter;
|
||||
@ -20,7 +21,6 @@ import org.bukkit.scoreboard.Team;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
/**
|
||||
@ -76,7 +76,7 @@ public interface PaperOffPlayer extends AbstractOffPlayer {
|
||||
* @return the display name of the player.
|
||||
*
|
||||
* @implNote This default implementation gets the display name from bukkit (if the player is online).
|
||||
* If it's different to the player name, it returns it. Otherwise, it tries to generate the team display name with {@link #getTeamDisplayName()}.
|
||||
* If its different to the player name, it returns it. Otherwise, it tries to generate the team displayname with {@link #getTeamDisplayName()}.
|
||||
* If the player is not in a team, then the player name is used.
|
||||
*/
|
||||
@Override
|
||||
@ -84,16 +84,16 @@ public interface PaperOffPlayer extends AbstractOffPlayer {
|
||||
String name = getName();
|
||||
Player p = getBukkitPlayer();
|
||||
@SuppressWarnings("deprecation")
|
||||
String bukkitDisplayName = p != null ? p.getDisplayName() : name;
|
||||
if (!name.equals(bukkitDisplayName))
|
||||
return bukkitDisplayName;
|
||||
String teamDisplayName = getTeamDisplayName();
|
||||
return teamDisplayName == null ? name : teamDisplayName;
|
||||
String bukkitDispName = p != null ? p.getDisplayName() : name;
|
||||
if (!name.equals(bukkitDispName))
|
||||
return bukkitDispName;
|
||||
String teamDispName = getTeamDisplayName();
|
||||
return teamDispName == null ? name : teamDispName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes and returns the name of the player with the prefix, suffix and color of the team the player is in.
|
||||
* @return The legacy formatted player display name, if he is in a {@link Team}, or null otherwise.
|
||||
* Computes and returns the the name of the player with the prefix, suffix and color of the team the player is in.
|
||||
* @return The legacy formated player display name, if he is in a {@link Team}, or null otherwise.
|
||||
*/
|
||||
default String getTeamDisplayName() {
|
||||
String name = getName();
|
||||
@ -151,10 +151,10 @@ public interface PaperOffPlayer extends AbstractOffPlayer {
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the NBT data from the player-data file.
|
||||
* Gets the NBT data from the playerdata file.
|
||||
* It will not work if the player is online, because the data on the file are not synchronized with real-time values.
|
||||
* @param convertTag true to convert the data to the current MC version, false to keep the saved version
|
||||
* @return the NBT data from the player-data file.
|
||||
* @return the NBT data from the playerdata file.
|
||||
* @throws IllegalStateException if the player is online.
|
||||
*/
|
||||
default CompoundTag getPlayerData(boolean convertTag) {
|
||||
@ -173,9 +173,9 @@ public interface PaperOffPlayer extends AbstractOffPlayer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a wrapper for the NBT data from the player-data file.
|
||||
* Gets a wrapper for the NBT data from the playerdata file.
|
||||
* It will not work if the player is online, because the data on the file are not synchronized with real-time values.
|
||||
* @return the NBT data from the player-data file.
|
||||
* @return the NBT data from the playerdata file.
|
||||
* @throws IllegalStateException if the player is online.
|
||||
*/
|
||||
default PlayerDataWrapper getPlayerDataWrapper() {
|
||||
@ -183,7 +183,7 @@ public interface PaperOffPlayer extends AbstractOffPlayer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the provided NBT data to the player-data file.
|
||||
* Saves the provided NBT data to the playerdata file.
|
||||
* It will not work if the player is online, because the provided data will be lost when the player disconnects.
|
||||
* @param data the data to save.
|
||||
* @throws IllegalStateException if the player is online.
|
||||
@ -195,14 +195,14 @@ public interface PaperOffPlayer extends AbstractOffPlayer {
|
||||
File file = getPlayerDataFile(false);
|
||||
File old = getPlayerDataFile(true);
|
||||
old.delete();
|
||||
Files.move(file.toPath(), old.toPath());
|
||||
Files.move(file, old);
|
||||
NbtIo.writeCompressed(data.data, file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file where the player-data is stored.
|
||||
* Gets the file where the playerdata is stored.
|
||||
* @param old true to return the path of old data, false to return the actual file.
|
||||
* @return the file where the player-data is stored.
|
||||
* @return the file where the playerdata is stored.
|
||||
*/
|
||||
default File getPlayerDataFile(boolean old) {
|
||||
File playerDataDir = new File(WorldUtil.worldDir(PrimaryWorlds.PRIMARY_WORLDS.get(0)), "playerdata");
|
||||
|
@ -97,7 +97,7 @@ public interface PaperOnlinePlayer extends PaperOffPlayer, AbstractOnlinePlayer
|
||||
* Play a sound on this player’s client, sourced at this player’s location.
|
||||
* @param sound the sound to play
|
||||
* @param volume the volume of the sound.
|
||||
* @param pitch the pitch in which the sound is played.
|
||||
* @param pitch the pich in which the sound is played.
|
||||
*/
|
||||
default void playSound(Sound sound, float volume, float pitch) {
|
||||
playSound(sound, getBukkitPlayer().getLocation(), volume, pitch);
|
||||
@ -108,7 +108,7 @@ public interface PaperOnlinePlayer extends PaperOffPlayer, AbstractOnlinePlayer
|
||||
* @param sound the sound to play
|
||||
* @param location the source location of the sound.
|
||||
* @param volume the volume of the sound.
|
||||
* @param pitch the pitch in which the sound is played.
|
||||
* @param pitch the pich in which the sound is played.
|
||||
*/
|
||||
default void playSound(Sound sound, Location location, float volume, float pitch) {
|
||||
getBukkitPlayer().playSound(location, sound, volume, pitch);
|
||||
|
@ -18,12 +18,12 @@ import java.util.stream.Collectors;
|
||||
|
||||
public class PaperPlayerConfigStorage {
|
||||
|
||||
static final File storageFile = new File(PandaLibPaper.getPlugin().getDataFolder(), "playerdata.yml");
|
||||
static File storageFile = new File(PandaLibPaper.getPlugin().getDataFolder(), "playerdata.yml");
|
||||
static boolean initialized = false;
|
||||
|
||||
static final LinkedHashMap<ConfigKey, ConfigEntry> data = new LinkedHashMap<>();
|
||||
static final LinkedHashMap<UUID, LinkedHashSet<ConfigEntry>> playerSortedData = new LinkedHashMap<>();
|
||||
static final LinkedHashMap<String, LinkedHashSet<ConfigEntry>> keySortedData = new LinkedHashMap<>();
|
||||
static LinkedHashMap<ConfigKey, ConfigEntry> data = new LinkedHashMap<>();
|
||||
static LinkedHashMap<UUID, LinkedHashSet<ConfigEntry>> playerSortedData = new LinkedHashMap<>();
|
||||
static LinkedHashMap<String, LinkedHashSet<ConfigEntry>> keySortedData = new LinkedHashMap<>();
|
||||
static boolean changed = false;
|
||||
|
||||
|
||||
@ -196,6 +196,10 @@ public class PaperPlayerConfigStorage {
|
||||
return value;
|
||||
}
|
||||
|
||||
private void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(playerId, key);
|
||||
|
@ -79,7 +79,7 @@ public class PlayerNonPersistentConfig {
|
||||
}
|
||||
|
||||
public static class ExpiresTick extends Expiration {
|
||||
final long expirationTick;
|
||||
long expirationTick;
|
||||
|
||||
public ExpiresTick(long expirationDelayTick) {
|
||||
expirationTick = tick + expirationDelayTick;
|
||||
|
@ -68,7 +68,7 @@ public class NMSReflect {
|
||||
OBF_NAMESPACE = (String) obfHelperClass.field("SPIGOT_NAMESPACE").getStaticValue();
|
||||
MOJ_NAMESPACE = (String) obfHelperClass.field("MOJANG_PLUS_YARN_NAMESPACE").getStaticValue();
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new ReflectiveOperationException("Unable to find the Paper obfuscation mapping class or class members.", e);
|
||||
throw new ReflectiveOperationException("Unable to find the Paper ofbuscation mapping class or class members.", e);
|
||||
}
|
||||
|
||||
List<ClassMapping> mappings = loadMappings(obfHelperClass);
|
||||
@ -165,7 +165,7 @@ public class NMSReflect {
|
||||
private static List<ClassMapping> loadMappings(ReflectClass<?> obfHelperClass) throws IOException {
|
||||
try (final InputStream mappingsInputStream = obfHelperClass.get().getClassLoader().getResourceAsStream("META-INF/mappings/reobf.tiny")) {
|
||||
if (mappingsInputStream == null) {
|
||||
throw new RuntimeException("Unable to find the obfuscation mapping file in the Paper jar.");
|
||||
throw new RuntimeException("Unable to find the ofbuscation mapping file in the Paper jar.");
|
||||
}
|
||||
|
||||
MemoryMappingTree tree = new MemoryMappingTree();
|
||||
@ -290,7 +290,7 @@ public class NMSReflect {
|
||||
|
||||
|
||||
/**
|
||||
* Represents the mapping between the obfuscated and Mojang names of a class and all its members.
|
||||
* Represents the mapping between the obfuscated and mojang names of a class and all its members.
|
||||
*/
|
||||
public static class ClassMapping {
|
||||
private static int nextID = 0;
|
||||
@ -463,9 +463,9 @@ public class NMSReflect {
|
||||
private List<NMSTypeWrapper> superInterfaces(boolean obf) {
|
||||
Class<?>[] interfaces = runtimeClass().getInterfaces();
|
||||
List<NMSTypeWrapper> types = new ArrayList<>(interfaces.length);
|
||||
for (Class<?> i : interfaces) {
|
||||
ClassMapping cm = (IS_SERVER_OBFUSCATED ? CLASSES_BY_OBF : CLASSES_BY_MOJ).get(i.getName());
|
||||
types.add((cm != null) ? cm.toType(obf) : NMSTypeWrapper.of(i));
|
||||
for (Class<?> interfce : interfaces) {
|
||||
ClassMapping cm = (IS_SERVER_OBFUSCATED ? CLASSES_BY_OBF : CLASSES_BY_MOJ).get(interfce.getName());
|
||||
types.add((cm != null) ? cm.toType(obf) : NMSTypeWrapper.of(interfce));
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ public class OBCReflect {
|
||||
|
||||
/**
|
||||
* Returns the OBC class that has the provided name, wrapped into a {@link ReflectClass}.
|
||||
* @param obcClass the name of the class, including the subpackage in which the requested class is. This parameter
|
||||
* @param obcClass the name of the class, including the subpackage in whitch the requested class is. This parameter
|
||||
* will be prefixed with the {@code OBC} package and the current package version.
|
||||
* @return the OBC class that has the provided name, wrapped into a {@link ReflectClass}.
|
||||
* @throws ClassNotFoundException if the provided class was not found in {@code OBC} package.
|
||||
|
@ -79,14 +79,14 @@ import fr.pandacube.lib.util.ThrowableAccumulator;
|
||||
import static fr.pandacube.lib.reflect.wrapper.WrapperRegistry.initWrapper;
|
||||
|
||||
/**
|
||||
* Initializer for all the reflection tools in {@code pandalib-paper-reflect} module.
|
||||
* Initializer for all the reflect tools in {@code pandalib-paper-reflect} module.
|
||||
*/
|
||||
public class PandalibPaperReflect {
|
||||
|
||||
private static boolean isInit = false;
|
||||
|
||||
/**
|
||||
* Initializes the reflection tools in {@code pandalib-paper-reflect} module.
|
||||
* Initializes the reflect tools in {@code pandalib-paper-reflect} module.
|
||||
* @throws Exception if a problem occurs when initializing wrapper classes.
|
||||
*/
|
||||
public static void init() throws Exception {
|
||||
@ -117,7 +117,7 @@ public class PandalibPaperReflect {
|
||||
thAcc.catchThrowable(() -> initWrapper(RenderData.class, RenderData.REFLECT.get()));
|
||||
thAcc.catchThrowable(() -> initWrapper(VanillaCommandWrapper.class, VanillaCommandWrapper.REFLECT.get()));
|
||||
|
||||
// data-converter
|
||||
// dataconverter
|
||||
thAcc.catchThrowable(() -> initWrapper(MCDataConverter.class, MCDataConverter.REFLECT.get()));
|
||||
thAcc.catchThrowable(() -> initWrapper(MCDataType.class, MCDataType.REFLECT.get()));
|
||||
thAcc.catchThrowable(() -> initWrapper(MCTypeRegistry.class, MCTypeRegistry.REFLECT.get()));
|
||||
@ -204,7 +204,7 @@ public class PandalibPaperReflect {
|
||||
thAcc.catchThrowable(() -> initWrapper(QueuedChangesMapLong2Object.class, QueuedChangesMapLong2Object.REFLECT.get()));
|
||||
|
||||
|
||||
thAcc.throwCaught();
|
||||
thAcc.throwCatched();
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ public final class BedrockBambooCollisionFixer implements Listener {
|
||||
// Make the bamboo block have zero collision.
|
||||
try {
|
||||
BambooStalkBlock.COLLISION_SHAPE(new AABBVoxelShape(new AABB(0.5, 0, 0.5, 0.5, 0, 0.5)));
|
||||
Log.info("Bamboo block collision box removed successfully.");
|
||||
Log.info("Bamboo block collision box removed succesfully.");
|
||||
} catch (Exception e) {
|
||||
Log.severe("Unable to remove the collision box of the Bamboo block.", e);
|
||||
return;
|
||||
|
@ -2,10 +2,14 @@ package fr.pandacube.lib.paper.reflect.wrapper.craftbukkit;
|
||||
|
||||
import fr.pandacube.lib.paper.reflect.OBCReflect;
|
||||
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.CompoundTag;
|
||||
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.MapItemSavedData;
|
||||
import fr.pandacube.lib.reflect.ReflectClass;
|
||||
import fr.pandacube.lib.reflect.ReflectField;
|
||||
import fr.pandacube.lib.reflect.ReflectMethod;
|
||||
import fr.pandacube.lib.reflect.wrapper.ReflectWrapperTyped;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.map.MapView;
|
||||
|
||||
import static fr.pandacube.lib.util.ThrowableUtil.wrapEx;
|
||||
import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx;
|
||||
|
@ -19,12 +19,12 @@ import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx;
|
||||
|
||||
public class VanillaCommandWrapper extends ReflectWrapperTyped<BukkitCommand> {
|
||||
public static final ReflectClass<?> REFLECT = wrapEx(() -> OBCReflect.ofClass("command.VanillaCommandWrapper"));
|
||||
public static final ReflectConstructor<?> CONSTRUCTOR = wrapEx(() -> REFLECT.constructor(Commands.MAPPING.runtimeClass(), CommandNode.class));
|
||||
public static final ReflectConstructor<?> CONSTRUTOR = wrapEx(() -> REFLECT.constructor(Commands.MAPPING.runtimeClass(), CommandNode.class));
|
||||
public static final ReflectField<?> vanillaCommand = wrapEx(() -> REFLECT.field("vanillaCommand"));
|
||||
public static final ReflectMethod<?> getListener = wrapEx(() -> REFLECT.method("getListener", CommandSender.class));
|
||||
|
||||
public VanillaCommandWrapper(Commands dispatcher, CommandNode<BukkitBrigadierCommandSource> vanillaCommand) {
|
||||
this(wrapReflectEx(() -> CONSTRUCTOR.instantiate(unwrap(dispatcher), vanillaCommand)));
|
||||
this(wrapReflectEx(() -> CONSTRUTOR.instanciate(unwrap(dispatcher), vanillaCommand)));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -1,6 +1,7 @@
|
||||
package fr.pandacube.lib.paper.reflect.wrapper.dataconverter;
|
||||
|
||||
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.CompoundTag;
|
||||
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.network.chat.Component;
|
||||
import fr.pandacube.lib.reflect.Reflect;
|
||||
import fr.pandacube.lib.reflect.ReflectClass;
|
||||
import fr.pandacube.lib.reflect.ReflectMethod;
|
||||
|
@ -57,7 +57,7 @@ public class CompoundTag extends ReflectWrapper implements Tag {
|
||||
private static final ReflectMethod<?> containsStringInt = wrapEx(() -> MAPPING.mojMethod("contains", String.class, int.class));
|
||||
|
||||
public CompoundTag() {
|
||||
this(wrapReflectEx(() -> CONSTRUCTOR.instantiate()));
|
||||
this(wrapReflectEx(() -> CONSTRUCTOR.instanciate()));
|
||||
}
|
||||
|
||||
protected CompoundTag(Object nms) {
|
||||
@ -167,7 +167,7 @@ public class CompoundTag extends ReflectWrapper implements Tag {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, ?> entries() {
|
||||
// we cannot easily wrap every value of the map without being able to synchronize the returned map with the wrapped map
|
||||
// we cannot easily wrap every value of the map without being able to synch the returned map with the wrapped map
|
||||
return (Map<String, ?>) wrapReflectEx(() -> entries.invoke(__getRuntimeInstance()));
|
||||
}
|
||||
public int size() {
|
||||
|
@ -4,6 +4,7 @@ import fr.pandacube.lib.paper.reflect.NMSReflect;
|
||||
import fr.pandacube.lib.paper.reflect.NMSReflect.ClassMapping;
|
||||
import fr.pandacube.lib.reflect.ReflectConstructor;
|
||||
import fr.pandacube.lib.reflect.ReflectMethod;
|
||||
import fr.pandacube.lib.reflect.wrapper.ReflectWrapper;
|
||||
|
||||
import static fr.pandacube.lib.util.ThrowableUtil.wrapEx;
|
||||
import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx;
|
||||
@ -18,7 +19,7 @@ public class ListTag extends CollectionTag {
|
||||
}
|
||||
|
||||
public ListTag() {
|
||||
this(wrapReflectEx(() -> CONSTRUCTOR.instantiate()));
|
||||
this(wrapReflectEx(() -> CONSTRUCTOR.instanciate()));
|
||||
}
|
||||
|
||||
protected ListTag(Object nms) {
|
||||
|
@ -14,7 +14,7 @@ public class FriendlyByteBuf extends ByteBuf {
|
||||
private static final ReflectMethod<?> writeUtf = wrapEx(() -> MAPPING.mojMethod("writeUtf", String.class));
|
||||
|
||||
public FriendlyByteBuf(ByteBuf parent) {
|
||||
this(wrapReflectEx(() -> CONSTRUCTOR.instantiate(unwrap(parent))));
|
||||
this(wrapReflectEx(() -> CONSTRUCTOR.instanciate(unwrap(parent))));
|
||||
}
|
||||
|
||||
public FriendlyByteBuf writeUtf(String string) {
|
||||
|
@ -24,6 +24,6 @@ public class ClientboundCustomPayloadPacket extends ReflectWrapper implements Pa
|
||||
}
|
||||
|
||||
public ClientboundCustomPayloadPacket(ResourceLocation res, FriendlyByteBuf buff) {
|
||||
this(wrapReflectEx(() -> CONSTRUCTOR.instantiate(unwrap(res), unwrap(buff))));
|
||||
this(wrapReflectEx(() -> CONSTRUCTOR.instanciate(unwrap(res), unwrap(buff))));
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ public class ClientboundGameEventPacket extends ReflectWrapper implements Packet
|
||||
}
|
||||
|
||||
public ClientboundGameEventPacket(Type type, float value) {
|
||||
this(wrapReflectEx(() -> CONSTRUCTOR.instantiate(unwrap(type), value)));
|
||||
this(wrapReflectEx(() -> CONSTRUCTOR.instanciate(unwrap(type), value)));
|
||||
}
|
||||
|
||||
protected ClientboundGameEventPacket(Object obj) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package fr.pandacube.lib.paper.reflect.wrapper.minecraft.server;
|
||||
|
||||
import fr.pandacube.lib.paper.reflect.NMSReflect;
|
||||
import fr.pandacube.lib.reflect.wrapper.ReflectWrapper;
|
||||
|
||||
import static fr.pandacube.lib.util.ThrowableUtil.wrapEx;
|
||||
|
||||
|
@ -12,7 +12,7 @@ public class AABB extends ReflectWrapper {
|
||||
private static final ReflectConstructor<?> CONSTRUCTOR = wrapEx(() -> MAPPING.runtimeReflect().constructor(double.class, double.class, double.class, double.class, double.class, double.class));
|
||||
|
||||
public AABB(double x1, double y1, double z1, double x2, double y2, double z2) {
|
||||
this(wrapReflectEx(() -> CONSTRUCTOR.instantiate(x1, y1, z1, x2, y2, z2)));
|
||||
this(wrapReflectEx(() -> CONSTRUCTOR.instanciate(x1, y1, z1, x2, y2, z2)));
|
||||
}
|
||||
|
||||
protected AABB(Object obj) {
|
||||
|
@ -12,7 +12,7 @@ public class ChunkPos extends ReflectWrapper {
|
||||
public static final ReflectConstructor<?> CONSTRUCTOR = wrapEx(() -> MAPPING.runtimeReflect().constructor(int.class, int.class));
|
||||
|
||||
public ChunkPos(int x, int z) {
|
||||
this(wrapReflectEx(() -> CONSTRUCTOR.instantiate(x, z)));
|
||||
this(wrapReflectEx(() -> CONSTRUCTOR.instanciate(x, z)));
|
||||
}
|
||||
|
||||
protected ChunkPos(Object obj) {
|
||||
|
@ -2,8 +2,10 @@ package fr.pandacube.lib.paper.reflect.wrapper.minecraft.world;
|
||||
|
||||
import fr.pandacube.lib.paper.reflect.NMSReflect;
|
||||
import fr.pandacube.lib.reflect.wrapper.ReflectWrapper;
|
||||
import fr.pandacube.lib.reflect.ReflectField;
|
||||
|
||||
import static fr.pandacube.lib.util.ThrowableUtil.wrapEx;
|
||||
import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx;
|
||||
|
||||
public class DamageSource extends ReflectWrapper {
|
||||
public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.world.damagesource.DamageSource"));
|
||||
|
@ -1,9 +1,11 @@
|
||||
package fr.pandacube.lib.paper.reflect.wrapper.minecraft.world;
|
||||
|
||||
import fr.pandacube.lib.paper.reflect.NMSReflect;
|
||||
import fr.pandacube.lib.reflect.ReflectField;
|
||||
import fr.pandacube.lib.reflect.wrapper.ReflectWrapper;
|
||||
|
||||
import static fr.pandacube.lib.util.ThrowableUtil.wrapEx;
|
||||
import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx;
|
||||
|
||||
public class DamageSources extends ReflectWrapper {
|
||||
public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.world.damagesource.DamageSources"));
|
||||
|
@ -2,6 +2,8 @@ package fr.pandacube.lib.paper.reflect.wrapper.minecraft.world;
|
||||
|
||||
import fr.pandacube.lib.paper.reflect.NMSReflect;
|
||||
import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.CompoundTag;
|
||||
import fr.pandacube.lib.paper.reflect.wrapper.paper.configuration.WorldConfiguration;
|
||||
import fr.pandacube.lib.reflect.ReflectField;
|
||||
import fr.pandacube.lib.reflect.ReflectMethod;
|
||||
import fr.pandacube.lib.reflect.wrapper.ReflectWrapper;
|
||||
|
||||
|
@ -14,7 +14,7 @@ public class AABBVoxelShape extends VoxelShape {
|
||||
private static final ReflectConstructor<?> CONSTRUCTOR = wrapEx(() -> REFLECT.constructor(AABB.MAPPING.runtimeClass()));
|
||||
|
||||
public AABBVoxelShape(AABB aabb) {
|
||||
this(wrapReflectEx(() -> CONSTRUCTOR.instantiate(unwrap(aabb))));
|
||||
this(wrapReflectEx(() -> CONSTRUCTOR.instanciate(unwrap(aabb))));
|
||||
}
|
||||
|
||||
protected AABBVoxelShape(Object obj) {
|
||||
|
@ -1,11 +1,15 @@
|
||||
package fr.pandacube.lib.paper.scheduler;
|
||||
|
||||
import fr.pandacube.lib.paper.PandaLibPaper;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import java.util.Objects;
|
||||
import fr.pandacube.lib.paper.PandaLibPaper;
|
||||
|
||||
/**
|
||||
* An extension of {@link BukkitRunnable} that already integrates a reference to the Bukkit plugin.
|
||||
@ -17,13 +21,13 @@ public class PandalibRunnable extends BukkitRunnable {
|
||||
|
||||
|
||||
/**
|
||||
* Instantiate a {@link PandalibRunnable}, whose {@link #run()} method will be called by the server scheduler.
|
||||
* When using this default constructor, the {@link #run()} method must be overridden to provide code to run.
|
||||
* Instanciate a {@link PandalibRunnable}, whose {@link #run()} method will be called by the server scheduler.
|
||||
* When using this default constructor, the {@link #run()} method must be override to provides code to run.
|
||||
*/
|
||||
protected PandalibRunnable() { }
|
||||
|
||||
/**
|
||||
* Instantiate a {@link PandalibRunnable}, with an {@code updater} that will be called by the server scheduler.
|
||||
* Instanciate a {@link PandalibRunnable}, with an {@code updater} that will be called by the server scheduler.
|
||||
* @param updater the updater to run when this task is executed.
|
||||
*/
|
||||
public PandalibRunnable(Runnable updater) {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user