Compare commits
	
		
			47 Commits
		
	
	
		
			e7b528718c
			...
			medrias
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 27c444f3b4 | |||
| c589da2a14 | |||
| 3fe4a1b244 | |||
| 1925dd9b36 | |||
| d637b92f6c | |||
| af4bab0d12 | |||
| 44dc690736 | |||
| c9af5ad308 | |||
| 27403a6e20 | |||
| 38a42dcca0 | |||
| 5782046b7a | |||
| 2b407d7f27 | |||
| 8f5f880754 | |||
| 3d92c3afb6 | |||
| 5e1f98ab70 | |||
| 276f5b2dc1 | |||
| 9c72b8cda4 | |||
| ee023b5d2c | |||
| 974347cbde | |||
| e6b77bcad6 | |||
| 36eb1227cf | |||
| 4be37945cb | |||
| 3e6cf96040 | |||
| d1a04a7a66 | |||
| fcac9af7d1 | |||
| e16487431d | |||
| 50f5ab671a | |||
| 5a04052f8e | |||
| c86855ac16 | |||
| 001239fe57 | |||
| 0c7fb9b370 | |||
| f416e30d45 | |||
| e271ac2964 | |||
| 2bb09ad42b | |||
| 4f55890092 | |||
| 76470b963e | |||
| 76fc673e98 | |||
| 307b5132df | |||
| ac52e024f3 | |||
| bb6d221ced | |||
| 2acfa53b63 | |||
| 640b255e1d | |||
| ed0db5391d | |||
| cef4af80f0 | |||
| 7f56645ba5 | |||
| 827c13887c | |||
| 0ff2ae1296 | 
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,3 +1,5 @@ | |||||||
| /.idea | /.idea | ||||||
| /*/target | /*/target | ||||||
| dependency-reduced-pom.xml | dependency-reduced-pom.xml | ||||||
|  |  | ||||||
|  | *.iml | ||||||
| @@ -18,8 +18,9 @@ that are detailed in their respective Readme file (if any). | |||||||
| - `pandalib-players` A library to handle classes representing online or offline players; | - `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-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-netapi` A poorly designed, but working TCP network library; | ||||||
|  | - `pandalib-config` Utility and helper classes to handle configuration related files and folders; | ||||||
| - `pandalib-commands` An abstract command manager working on top of [Brigadier](https://github.com/Mojang/brigadier); | - `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-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 | ### Use in your projects | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								pandalib-bungee-chat/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								pandalib-bungee-chat/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | /target/ | ||||||
							
								
								
									
										49
									
								
								pandalib-bungee-chat/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								pandalib-bungee-chat/pom.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | |||||||
|  | <?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 https://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-bungee-chat</artifactId> | ||||||
|  |     <packaging>jar</packaging> | ||||||
|  |  | ||||||
|  |     <repositories> | ||||||
|  |         <repository> | ||||||
|  |             <id>bungeecord-repo</id> | ||||||
|  |             <url>https://oss.sonatype.org/content/repositories/snapshots</url> | ||||||
|  |         </repository> | ||||||
|  |     </repositories> | ||||||
|  |  | ||||||
|  |     <dependencies> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>fr.pandacube.lib</groupId> | ||||||
|  |             <artifactId>pandalib-util</artifactId> | ||||||
|  |             <version>${project.version}</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>fr.pandacube.lib</groupId> | ||||||
|  |             <artifactId>pandalib-chat</artifactId> | ||||||
|  |             <version>${project.version}</version> | ||||||
|  |         </dependency> | ||||||
|  |  | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>net.md-5</groupId> | ||||||
|  |             <artifactId>bungeecord-chat</artifactId> | ||||||
|  |             <version>${bungeecord.version}</version> | ||||||
|  |             <scope>provided</scope> | ||||||
|  |         </dependency> | ||||||
|  |  | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>net.kyori</groupId> | ||||||
|  |             <artifactId>adventure-platform-bungeecord</artifactId> | ||||||
|  |             <version>4.3.0</version> | ||||||
|  |         </dependency> | ||||||
|  |     </dependencies> | ||||||
|  |  | ||||||
|  | </project> | ||||||
| @@ -0,0 +1,77 @@ | |||||||
|  | package fr.pandacube.lib.bungee.chat; | ||||||
|  |  | ||||||
|  | import fr.pandacube.lib.chat.Chat; | ||||||
|  | import fr.pandacube.lib.chat.Chat.FormatableChat; | ||||||
|  | import net.kyori.adventure.text.Component; | ||||||
|  | import net.kyori.adventure.text.ComponentLike; | ||||||
|  | import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; | ||||||
|  | import net.md_5.bungee.api.chat.BaseComponent; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Utility class to ease conversion between our Adventure backed Chat API and BungeeCord chat API. | ||||||
|  |  */ | ||||||
|  | public class ChatBungee { | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Creates a {@link FormatableChat} from the provided Bungee {@link BaseComponent}. | ||||||
|  |      * @param c the {@link BaseComponent}. | ||||||
|  |      * @return a new {@link FormatableChat}. | ||||||
|  |      */ | ||||||
|  |     public static FormatableChat chatComponent(BaseComponent c) { | ||||||
|  |         return Chat.chatComponent(toAdventure(c)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Creates a {@link FormatableChat} from the provided Bungee {@link BaseComponent BaseComponent[]}. | ||||||
|  |      * @param c the array of {@link BaseComponent}. | ||||||
|  |      * @return a new {@link FormatableChat}. | ||||||
|  |      */ | ||||||
|  |     public static FormatableChat chatComponent(BaseComponent[] c) { | ||||||
|  |         return Chat.chatComponent(toAdventure(c)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Converts the Bungee {@link BaseComponent} array into Adventure {@link Component}. | ||||||
|  |      * @param components the Bungee {@link BaseComponent} array. | ||||||
|  |      * @return a {@link Component}. | ||||||
|  |      */ | ||||||
|  |     public static Component toAdventure(BaseComponent[] components) { | ||||||
|  |         return BungeeComponentSerializer.get().deserialize(components); | ||||||
|  |     } | ||||||
|  |     /** | ||||||
|  |      * Converts the Bungee {@link BaseComponent} into Adventure {@link Component}. | ||||||
|  |      * @param component the Bungee {@link BaseComponent}. | ||||||
|  |      * @return a {@link Component}. | ||||||
|  |      */ | ||||||
|  |     public static Component toAdventure(BaseComponent component) { | ||||||
|  |         return toAdventure(new BaseComponent[] { component }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Converts the Adventure {@link Component} into Bungee {@link BaseComponent} array. | ||||||
|  |      * @param component the Adventure {@link Component}. | ||||||
|  |      * @return a {@link BaseComponent} array. | ||||||
|  |      */ | ||||||
|  |     public static BaseComponent[] toBungeeArray(ComponentLike component) { | ||||||
|  |         return BungeeComponentSerializer.get().serialize(component.asComponent()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Converts the Adventure {@link Component} into Bungee {@link BaseComponent}. | ||||||
|  |      * @param component the Adventure {@link Component}. | ||||||
|  |      * @return a {@link BaseComponent}. | ||||||
|  |      */ | ||||||
|  |     public static BaseComponent toBungee(ComponentLike component) { | ||||||
|  |         BaseComponent[] arr = toBungeeArray(component); | ||||||
|  |         return arr.length == 1 ? arr[0] : new net.md_5.bungee.api.chat.TextComponent(arr); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     private ChatBungee() {} | ||||||
|  | } | ||||||
| @@ -33,7 +33,7 @@ | |||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>fr.pandacube.lib</groupId> |             <groupId>fr.pandacube.lib</groupId> | ||||||
|             <artifactId>pandalib-chat</artifactId> |             <artifactId>pandalib-bungee-chat</artifactId> | ||||||
|             <version>${project.version}</version> |             <version>${project.version}</version> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package fr.pandacube.lib.bungee.commands; | package fr.pandacube.lib.bungee.commands; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.chat.Chat; | import fr.pandacube.lib.bungee.chat.ChatBungee; | ||||||
| import fr.pandacube.lib.commands.BrigadierDispatcher; | import fr.pandacube.lib.commands.BrigadierDispatcher; | ||||||
| import net.kyori.adventure.text.ComponentLike; | import net.kyori.adventure.text.ComponentLike; | ||||||
| import net.md_5.bungee.api.CommandSender; | import net.md_5.bungee.api.CommandSender; | ||||||
| @@ -71,6 +71,6 @@ public class BungeeBrigadierDispatcher extends BrigadierDispatcher<CommandSender | |||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	protected void sendSenderMessage(CommandSender sender, ComponentLike message) { | 	protected void sendSenderMessage(CommandSender sender, ComponentLike message) { | ||||||
| 		sender.sendMessage(Chat.toBungee(message.asComponent())); | 		sender.sendMessage(ChatBungee.toBungee(message.asComponent())); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package fr.pandacube.lib.bungee.players; | package fr.pandacube.lib.bungee.players; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.chat.Chat; | import fr.pandacube.lib.bungee.chat.ChatBungee; | ||||||
| import fr.pandacube.lib.core.mc_version.ProtocolVersion; | import fr.pandacube.lib.core.mc_version.ProtocolVersion; | ||||||
| import fr.pandacube.lib.players.standalone.AbstractOnlinePlayer; | import fr.pandacube.lib.players.standalone.AbstractOnlinePlayer; | ||||||
| import fr.pandacube.lib.reflect.Reflect; | import fr.pandacube.lib.reflect.Reflect; | ||||||
| @@ -84,13 +84,13 @@ public interface BungeeOnlinePlayer extends BungeeOffPlayer, AbstractOnlinePlaye | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     default void sendMessage(Component message) { |     default void sendMessage(Component message) { | ||||||
|         getBungeeProxiedPlayer().sendMessage(Chat.toBungee(message)); |         getBungeeProxiedPlayer().sendMessage(ChatBungee.toBungee(message)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     default void sendTitle(Component title, Component subtitle, int fadeIn, int stay, int fadeOut) { |     default void sendTitle(Component title, Component subtitle, int fadeIn, int stay, int fadeOut) { | ||||||
|         ProxyServer.getInstance().createTitle() |         ProxyServer.getInstance().createTitle() | ||||||
|                 .title(Chat.toBungee(title)).subTitle(Chat.toBungee(subtitle)) |                 .title(ChatBungee.toBungee(title)).subTitle(ChatBungee.toBungee(subtitle)) | ||||||
|                 .fadeIn(fadeIn).stay(stay).fadeOut(fadeOut) |                 .fadeIn(fadeIn).stay(stay).fadeOut(fadeOut) | ||||||
|                 .send(getBungeeProxiedPlayer()); |                 .send(getBungeeProxiedPlayer()); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -30,8 +30,13 @@ | |||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>net.kyori</groupId> |             <groupId>net.kyori</groupId> | ||||||
|             <artifactId>adventure-platform-bungeecord</artifactId> |             <artifactId>adventure-text-serializer-gson</artifactId> | ||||||
|             <version>4.3.0</version> |             <version>4.13.0</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>net.kyori</groupId> | ||||||
|  |             <artifactId>adventure-text-serializer-legacy</artifactId> | ||||||
|  |             <version>4.13.0</version> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>net.kyori</groupId> |             <groupId>net.kyori</groupId> | ||||||
| @@ -46,13 +51,6 @@ | |||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         <dependency> |  | ||||||
|             <groupId>net.md-5</groupId> |  | ||||||
|             <artifactId>bungeecord-chat</artifactId> |  | ||||||
|             <version>${bungeecord.version}</version> |  | ||||||
|             <scope>compile</scope> |  | ||||||
|         </dependency> |  | ||||||
|  |  | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>com.google.code.gson</groupId> |             <groupId>com.google.code.gson</groupId> | ||||||
|             <artifactId>gson</artifactId> |             <artifactId>gson</artifactId> | ||||||
|   | |||||||
| @@ -16,15 +16,13 @@ import net.kyori.adventure.text.format.TextColor; | |||||||
| import net.kyori.adventure.text.format.TextDecoration; | import net.kyori.adventure.text.format.TextDecoration; | ||||||
| import net.kyori.adventure.text.format.TextDecoration.State; | import net.kyori.adventure.text.format.TextDecoration.State; | ||||||
| import net.kyori.adventure.text.minimessage.MiniMessage; | import net.kyori.adventure.text.minimessage.MiniMessage; | ||||||
| import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; |  | ||||||
| import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; | import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; | ||||||
| import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; | import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; | ||||||
| import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; | 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; | import org.jetbrains.annotations.NotNull; | ||||||
|  |  | ||||||
| import java.awt.*; | import java.awt.*; | ||||||
|  | import java.util.Locale; | ||||||
| import java.util.Objects; | import java.util.Objects; | ||||||
| import java.util.function.Consumer; | import java.util.function.Consumer; | ||||||
| import java.util.function.UnaryOperator; | import java.util.function.UnaryOperator; | ||||||
| @@ -67,26 +65,10 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource | |||||||
|      * Builds the component into Adventure Component instance. |      * Builds the component into Adventure Component instance. | ||||||
|      * @return the {@link Component} built from this {@link Chat} component. |      * @return the {@link Component} built from this {@link Chat} component. | ||||||
|      */ |      */ | ||||||
|     public Component getAdv() { |     public Component get() { | ||||||
|         return builder.build(); |         return builder.build(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Builds the component into BungeeCord {@link BaseComponent} instance. |  | ||||||
|      * @return the {@link BaseComponent} built from this {@link Chat} component. |  | ||||||
|      */ |  | ||||||
|     public BaseComponent get() { |  | ||||||
|         return toBungee(getAdv()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Builds the component into BungeeCord {@link BaseComponent} array. |  | ||||||
|      * @return the {@link BaseComponent} array built 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_FRIENDLY = LegacyComponentSerializer.builder() | ||||||
|             .hexColors() |             .hexColors() | ||||||
|             .useUnusualXRepeatedCharacterHexFormat() |             .useUnusualXRepeatedCharacterHexFormat() | ||||||
| @@ -97,7 +79,7 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource | |||||||
|      * @return the legacy text. RGB colors are in BungeeCord format. |      * @return the legacy text. RGB colors are in BungeeCord format. | ||||||
|      */ |      */ | ||||||
|     public String getLegacyText() { |     public String getLegacyText() { | ||||||
|         return LEGACY_SERIALIZER_BUNGEE_FRIENDLY.serialize(getAdv()); |         return LEGACY_SERIALIZER_BUNGEE_FRIENDLY.serialize(get()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -105,12 +87,12 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource | |||||||
|      * @return the plain text of this component. |      * @return the plain text of this component. | ||||||
|      */ |      */ | ||||||
|     public String getPlainText() { |     public String getPlainText() { | ||||||
|         return PlainTextComponentSerializer.plainText().serializeOr(getAdv(), ""); |         return PlainTextComponentSerializer.plainText().serializeOr(get(), ""); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public @NotNull HoverEvent<Component> asHoverEvent(@NotNull UnaryOperator<Component> op) { |     public @NotNull HoverEvent<Component> asHoverEvent(@NotNull UnaryOperator<Component> op) { | ||||||
|         return HoverEvent.showText(op.apply(getAdv())); |         return HoverEvent.showText(op.apply(get())); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -119,7 +101,7 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource | |||||||
|      */ |      */ | ||||||
|     @Override |     @Override | ||||||
|     public @NotNull Component asComponent() { |     public @NotNull Component asComponent() { | ||||||
|         return getAdv(); |         return get(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -127,7 +109,7 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource | |||||||
|      * @return the {@link Component} built from this {@link Chat} component, with down-sampled colors. |      * @return the {@link Component} built from this {@link Chat} component, with down-sampled colors. | ||||||
|      */ |      */ | ||||||
|     public Component getAsDownSampledColorsComponent() { |     public Component getAsDownSampledColorsComponent() { | ||||||
|         String json = GsonComponentSerializer.colorDownsamplingGson().serialize(getAdv()); |         String json = GsonComponentSerializer.colorDownsamplingGson().serialize(get()); | ||||||
|         return GsonComponentSerializer.gson().deserialize(json); |         return GsonComponentSerializer.gson().deserialize(json); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -144,7 +126,7 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource | |||||||
|      * @return the MiniMessage representation if this {@link Chat} component. |      * @return the MiniMessage representation if this {@link Chat} component. | ||||||
|      */ |      */ | ||||||
|     public String getMiniMessage() { |     public String getMiniMessage() { | ||||||
|         return MiniMessage.miniMessage().serialize(getAdv()); |         return MiniMessage.miniMessage().serialize(get()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -184,15 +166,6 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource | |||||||
|         return this; |         return this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Appends a BungeeCord {@link BaseComponent} to this component. |  | ||||||
|      * @param comp the component to append. |  | ||||||
|      * @return this. |  | ||||||
|      */ |  | ||||||
|     public Chat then(BaseComponent comp) { |  | ||||||
|         return then(toAdventure(comp)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Appends a component to this component. |      * Appends a component to this component. | ||||||
|      * @param comp the component to append. |      * @param comp the component to append. | ||||||
| @@ -207,15 +180,6 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource | |||||||
|         return then(comp.asComponent()); |         return then(comp.asComponent()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Appends a BungeeCord {@link BaseComponent} array to this component. |  | ||||||
|      * @param comp the components to append. |  | ||||||
|      * @return this. |  | ||||||
|      */ |  | ||||||
|     public Chat then(BaseComponent[] comp) { |  | ||||||
|         return then(toAdventure(comp)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -495,17 +459,6 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource | |||||||
|      */ |      */ | ||||||
|     public Chat thenLeftText(ComponentLike leftText) { return then(leftText(leftText, console)); } |     public Chat thenLeftText(ComponentLike leftText) { return then(leftText(leftText, console)); } | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Appends a component filling a chat line 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 |  | ||||||
|      *         and color and a left-aligned text. |  | ||||||
|      * @deprecated uses Bungeecord chat API. |  | ||||||
|      */ |  | ||||||
|     @Deprecated |  | ||||||
|     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 chat line with the configured decoration character and | ||||||
|      * color and a right-aligned text. |      * color and a right-aligned text. | ||||||
| @@ -515,17 +468,6 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource | |||||||
|      */ |      */ | ||||||
|     public Chat thenRightText(ComponentLike rightText) { return then(rightText(rightText, console)); } |     public Chat thenRightText(ComponentLike rightText) { return then(rightText(rightText, console)); } | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Appends a component filling a chat line 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 |  | ||||||
|      *         and color and a right-aligned text. |  | ||||||
|      * @deprecated uses Bungeecord chat API. |  | ||||||
|      */ |  | ||||||
|     @Deprecated |  | ||||||
|     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 chat line with the configured decoration character and | ||||||
|      * color and a centered text. |      * color and a centered text. | ||||||
| @@ -537,19 +479,6 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource | |||||||
|         return then(centerText(centerText, console)); |         return then(centerText(centerText, console)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Appends a component filling a chat line 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 |  | ||||||
|      *         and color and a centered text. |  | ||||||
|      * @deprecated uses Bungeecord chat API. |  | ||||||
|      */ |  | ||||||
|     @Deprecated |  | ||||||
|     public Chat thenCenterText(BaseComponent centerText) { |  | ||||||
|         return thenCenterText(chatComponent(centerText)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Appends a component filling a chat line with the configured decoration character and color. |      * 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. |      * @return a new {@link FormatableChat} filling a chat line with a decoration character and color. | ||||||
| @@ -629,12 +558,6 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource | |||||||
|          * @return this. |          * @return this. | ||||||
|          */ |          */ | ||||||
|         public FormatableChat color(TextColor c) { builder.color(c); return this; } |         public FormatableChat color(TextColor c) { builder.color(c); return this; } | ||||||
|         /** |  | ||||||
|          * Sets the color of this component. |  | ||||||
|          * @param c the color. |  | ||||||
|          * @return this. |  | ||||||
|          */ |  | ||||||
|         public FormatableChat color(ChatColor c) { return color(c == null ? null : TextColor.color(c.getColor().getRGB())); } |  | ||||||
|         /** |         /** | ||||||
|          * Sets the color of this component. |          * Sets the color of this component. | ||||||
|          * @param c the color. |          * @param c the color. | ||||||
| @@ -646,7 +569,16 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource | |||||||
|          * @param c the color. |          * @param c the color. | ||||||
|          * @return this. |          * @return this. | ||||||
|          */ |          */ | ||||||
|         public FormatableChat color(String c) { return color(c == null ? null : ChatColor.of(c)); } |         public FormatableChat color(String c) { | ||||||
|  |             if (c == null) | ||||||
|  |                 return color((TextColor) null); | ||||||
|  |             TextColor tc = c.startsWith("#") | ||||||
|  |                     ? TextColor.fromCSSHexString(c) | ||||||
|  |                     : NamedTextColor.NAMES.value(c.toLowerCase(Locale.ROOT)); | ||||||
|  |             if (tc == null) | ||||||
|  |                 throw new IllegalArgumentException("Invalid color string '" + c + "'."); | ||||||
|  |             return color(tc); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|         /** |         /** | ||||||
| @@ -924,18 +856,6 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource | |||||||
|          * @return this. |          * @return this. | ||||||
|          */ |          */ | ||||||
|         public FormatableChat hover(ComponentLike v) { return hover(v.asComponent()); } |         public FormatableChat hover(ComponentLike v) { return hover(v.asComponent()); } | ||||||
|         /** |  | ||||||
|          * Configure this component to show the provided component when hovered. |  | ||||||
|          * @param v the component to show. |  | ||||||
|          * @return this. |  | ||||||
|          */ |  | ||||||
|         public FormatableChat hover(BaseComponent v) { return hover(toAdventure(v)); } |  | ||||||
|         /** |  | ||||||
|          * Configure this component to show the provided component when hovered. |  | ||||||
|          * @param v the component to show. |  | ||||||
|          * @return this. |  | ||||||
|          */ |  | ||||||
|         public FormatableChat hover(BaseComponent[] v) { return hover(toAdventure(v)); } |  | ||||||
|         /** |         /** | ||||||
|          * Configure this component to show the provided legacy text when hovered. |          * Configure this component to show the provided legacy text when hovered. | ||||||
|          * @param legacyText the legacy text to show. |          * @param legacyText the legacy text to show. | ||||||
| @@ -963,7 +883,7 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public int hashCode() { |     public int hashCode() { | ||||||
|         return getAdv().hashCode(); |         return get().hashCode(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -976,8 +896,6 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource | |||||||
|  |  | ||||||
|     /* package */ static ComponentLike filterObjToComponentLike(Object v) { |     /* package */ static ComponentLike filterObjToComponentLike(Object v) { | ||||||
|         return switch (v) { |         return switch (v) { | ||||||
|             case BaseComponent[] baseComponents -> toAdventure(baseComponents); |  | ||||||
|             case BaseComponent baseComponent -> toAdventure(baseComponent); |  | ||||||
|             case ComponentLike componentLike -> componentLike; |             case ComponentLike componentLike -> componentLike; | ||||||
|             case null, default -> Component.text(Objects.toString(v)); |             case null, default -> Component.text(Objects.toString(v)); | ||||||
|         }; |         }; | ||||||
| @@ -1011,40 +929,6 @@ public abstract sealed class Chat extends ChatStatic implements HoverEventSource | |||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Converts the Bungee {@link BaseComponent} array into Adventure {@link Component}. |  | ||||||
|      * @param components the Bungee {@link BaseComponent} array. |  | ||||||
|      * @return a {@link Component}. |  | ||||||
|      */ |  | ||||||
|     public static Component toAdventure(BaseComponent[] components) { |  | ||||||
|         return BungeeComponentSerializer.get().deserialize(components); |  | ||||||
|     } |  | ||||||
|     /** |  | ||||||
|      * Converts the Bungee {@link BaseComponent} into Adventure {@link Component}. |  | ||||||
|      * @param component the Bungee {@link BaseComponent}. |  | ||||||
|      * @return a {@link Component}. |  | ||||||
|      */ |  | ||||||
|     public static Component toAdventure(BaseComponent component) { |  | ||||||
|         return toAdventure(new BaseComponent[] { component }); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Converts the Adventure {@link Component} into Bungee {@link BaseComponent} array. |  | ||||||
|      * @param component the Adventure {@link Component}. |  | ||||||
|      * @return a {@link BaseComponent} array. |  | ||||||
|      */ |  | ||||||
|     public static BaseComponent[] toBungeeArray(Component component) { |  | ||||||
|         return BungeeComponentSerializer.get().serialize(component); |  | ||||||
|     } |  | ||||||
|     /** |  | ||||||
|      * Converts the Adventure {@link Component} into Bungee {@link BaseComponent}. |  | ||||||
|      * @param component the Adventure {@link Component}. |  | ||||||
|      * @return a {@link BaseComponent}. |  | ||||||
|      */ |  | ||||||
|     public static BaseComponent toBungee(Component component) { |  | ||||||
|         BaseComponent[] arr = toBungeeArray(component); |  | ||||||
|         return arr.length == 1 ? arr[0] : new net.md_5.bungee.api.chat.TextComponent(arr); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Force the italic formatting to be set to false if it is not explicitly set in the component. |      * Force the italic formatting to be set to false if it is not explicitly set in the component. | ||||||
|   | |||||||
| @@ -1,14 +1,14 @@ | |||||||
| package fr.pandacube.lib.chat; | package fr.pandacube.lib.chat; | ||||||
|  |  | ||||||
|  | import net.kyori.adventure.text.format.TextColor; | ||||||
|  | import net.kyori.adventure.text.format.TextDecoration; | ||||||
|  | import net.kyori.adventure.text.format.TextFormat; | ||||||
|  | import net.kyori.adventure.util.RGBLike; | ||||||
|  |  | ||||||
| import java.util.regex.Pattern; | import java.util.regex.Pattern; | ||||||
|  |  | ||||||
| import net.kyori.adventure.text.format.NamedTextColor; |  | ||||||
| import net.kyori.adventure.text.format.TextColor; |  | ||||||
| import net.kyori.adventure.util.RGBLike; |  | ||||||
| import net.md_5.bungee.api.ChatColor; |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Provides methods to manipulate legacy colors and {@link ChatColor} class. |  * Provides methods to manipulate legacy colors. | ||||||
|  */ |  */ | ||||||
| public class ChatColorUtil { | public class ChatColorUtil { | ||||||
|  |  | ||||||
| @@ -38,12 +38,12 @@ public class ChatColorUtil { | |||||||
|         int length = legacyText.length(); |         int length = legacyText.length(); | ||||||
|  |  | ||||||
|         for (int index = length - 2; index >= 0; index--) { |         for (int index = length - 2; index >= 0; index--) { | ||||||
|             if (legacyText.charAt(index) == ChatColor.COLOR_CHAR) { |             if (legacyText.charAt(index) == LegacyChatFormat.COLOR_CHAR) { | ||||||
|  |  | ||||||
|                 // detection of rgb color §x§0§1§2§3§4§5 |                 // detection of rgb color §x§0§1§2§3§4§5 | ||||||
|                 String rgb; |                 String rgb; | ||||||
|                 if (index > 11 |                 if (index > 11 | ||||||
|                         && legacyText.charAt(index - 12) == ChatColor.COLOR_CHAR |                         && legacyText.charAt(index - 12) == LegacyChatFormat.COLOR_CHAR | ||||||
|                         && (legacyText.charAt(index - 11) == 'x' |                         && (legacyText.charAt(index - 11) == 'x' | ||||||
|                         || legacyText.charAt(index - 11) == 'X') |                         || legacyText.charAt(index - 11) == 'X') | ||||||
|                         && HEX_COLOR_PATTERN.matcher(rgb = legacyText.substring(index - 12, index + 2)).matches()) { |                         && HEX_COLOR_PATTERN.matcher(rgb = legacyText.substring(index - 12, index + 2)).matches()) { | ||||||
| @@ -64,7 +64,7 @@ public class ChatColorUtil { | |||||||
|  |  | ||||||
|                 // try detect non-rgb format |                 // try detect non-rgb format | ||||||
|                 char colorChar = legacyText.charAt(index + 1); |                 char colorChar = legacyText.charAt(index + 1); | ||||||
|                 ChatColor legacyColor = getChatColorByChar(colorChar); |                 LegacyChatFormat legacyColor = LegacyChatFormat.of(colorChar); | ||||||
|  |  | ||||||
|                 if (legacyColor != null) { |                 if (legacyColor != null) { | ||||||
|                     result.insert(0, legacyColor); |                     result.insert(0, legacyColor); | ||||||
| @@ -83,15 +83,6 @@ public class ChatColorUtil { | |||||||
|         return result.toString(); |         return result.toString(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 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) { |  | ||||||
|         return ChatColor.getByChar(Character.toLowerCase(code)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -99,7 +90,7 @@ public class ChatColorUtil { | |||||||
|      * Translate the color code of the provided string, that uses the alt color char, to the {@code §} color code |      * Translate the color code of the provided string, that uses the alt color char, to the {@code §} color code | ||||||
|      * format. |      * format. | ||||||
|      * <p> |      * <p> | ||||||
|      * This method is the improved version of {@link ChatColor#translateAlternateColorCodes(char, String)}, |      * This method is the improved version of Bukkit’s {@code ChatColor.translateAlternateColorCodes(char, String)}, | ||||||
|      * because it takes into account essentials RGB color code, and {@code altColorChar} escaping (by doubling it). |      * because it takes into account essentials RGB color code, and {@code altColorChar} escaping (by doubling it). | ||||||
|      * Essentials RGB color code are converted to Bungee chat RGB format, so the returned string can be converted |      * Essentials RGB color code are converted to Bungee chat RGB format, so the returned string can be converted | ||||||
|      * to component (see {@link Chat#legacyText(Object)}). |      * to component (see {@link Chat#legacyText(Object)}). | ||||||
| @@ -112,7 +103,7 @@ public class ChatColorUtil { | |||||||
|      */ |      */ | ||||||
|     public static String translateAlternateColorCodes(char altColorChar, String textToTranslate) |     public static String translateAlternateColorCodes(char altColorChar, String textToTranslate) | ||||||
|     { |     { | ||||||
|         char colorChar = ChatColor.COLOR_CHAR; |         char colorChar = LegacyChatFormat.COLOR_CHAR; | ||||||
|         StringBuilder acc = new StringBuilder(); |         StringBuilder acc = new StringBuilder(); | ||||||
|         char[] b = textToTranslate.toCharArray(); |         char[] b = textToTranslate.toCharArray(); | ||||||
|         for ( int i = 0; i < b.length; i++ ) |         for ( int i = 0; i < b.length; i++ ) | ||||||
| @@ -180,7 +171,7 @@ public class ChatColorUtil { | |||||||
|      * @return the text fully italic. |      * @return the text fully italic. | ||||||
|      */ |      */ | ||||||
|     public static String forceItalic(String legacyText) { |     public static String forceItalic(String legacyText) { | ||||||
|         return forceFormat(legacyText, ChatColor.ITALIC); |         return forceFormat(legacyText, TextDecoration.ITALIC); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -190,7 +181,7 @@ public class ChatColorUtil { | |||||||
|      * @return the text fully bold. |      * @return the text fully bold. | ||||||
|      */ |      */ | ||||||
|     public static String forceBold(String legacyText) { |     public static String forceBold(String legacyText) { | ||||||
|         return forceFormat(legacyText, ChatColor.BOLD); |         return forceFormat(legacyText, TextDecoration.BOLD); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -200,7 +191,7 @@ public class ChatColorUtil { | |||||||
|      * @return the text fully underlined. |      * @return the text fully underlined. | ||||||
|      */ |      */ | ||||||
|     public static String forceUnderline(String legacyText) { |     public static String forceUnderline(String legacyText) { | ||||||
|         return forceFormat(legacyText, ChatColor.UNDERLINE); |         return forceFormat(legacyText, TextDecoration.UNDERLINED); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -210,7 +201,7 @@ public class ChatColorUtil { | |||||||
|      * @return the text fully stroked through. |      * @return the text fully stroked through. | ||||||
|      */ |      */ | ||||||
|     public static String forceStrikethrough(String legacyText) { |     public static String forceStrikethrough(String legacyText) { | ||||||
|         return forceFormat(legacyText, ChatColor.STRIKETHROUGH); |         return forceFormat(legacyText, TextDecoration.STRIKETHROUGH); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -220,15 +211,16 @@ public class ChatColorUtil { | |||||||
|      * @return the text fully obfuscated. |      * @return the text fully obfuscated. | ||||||
|      */ |      */ | ||||||
|     public static String forceObfuscated(String legacyText) { |     public static String forceObfuscated(String legacyText) { | ||||||
|         return forceFormat(legacyText, ChatColor.MAGIC); |         return forceFormat(legacyText, TextDecoration.OBFUSCATED); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     private static String forceFormat(String legacyText, ChatColor format) { |     private static String forceFormat(String legacyText, TextFormat format) { | ||||||
|  |         String formatStr = LegacyChatFormat.of(format).toString(); | ||||||
|         return format + legacyText |         return format + legacyText | ||||||
|                 .replace(format.toString(), "") // remove previous tag to make the result cleaner |                 .replace(formatStr, "") // remove previous tag to make the result cleaner | ||||||
|                 .replaceAll("§([a-frA-FR\\d])", "§$1" + format); |                 .replaceAll("§([a-frA-FR\\d])", "§$1" + formatStr); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -243,40 +235,12 @@ public class ChatColorUtil { | |||||||
|      * @return the resulting text. |      * @return the resulting text. | ||||||
|      */ |      */ | ||||||
|     public static String resetToColor(String legacyText, String color) { |     public static String resetToColor(String legacyText, String color) { | ||||||
|         return legacyText.replace(ChatColor.RESET.toString(), color); |         return legacyText.replace(LegacyChatFormat.RESET.toString(), color); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Converts the provided {@link ChatColor} to its Adventure counterpart. |  | ||||||
|      * @param bungee a BungeeCord {@link ChatColor} instance. |  | ||||||
|      * @return the {@link TextColor} equivalent to the provided {@link ChatColor}. |  | ||||||
|      */ |  | ||||||
|     public static TextColor toAdventure(ChatColor bungee) { |  | ||||||
|         if (bungee == null) |  | ||||||
|             return null; |  | ||||||
|         if (bungee.getColor() == null) |  | ||||||
|             throw new IllegalArgumentException("The provided Bungee ChatColor must be an actual color (not format nor reset)."); |  | ||||||
|         return TextColor.color(bungee.getColor().getRGB()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Converts the provided {@link TextColor} to its BungeeCord counterpart. |  | ||||||
|      * @param col a Adventure {@link TextColor} instance. |  | ||||||
|      * @return the {@link ChatColor} equivalent to the provided {@link TextColor}. |  | ||||||
|      */ |  | ||||||
|     public static ChatColor toBungee(TextColor col) { |  | ||||||
|         if (col == null) |  | ||||||
|             return null; |  | ||||||
|         if (col instanceof NamedTextColor) { |  | ||||||
|             return ChatColor.of(((NamedTextColor) col).toString()); |  | ||||||
|         } |  | ||||||
|         return ChatColor.of(col.asHexString()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Create a color, interpolating between 2 colors. |      * Create a color, interpolating between 2 colors. | ||||||
|      * @param v0 the value corresponding to color {@code cc0}. |      * @param v0 the value corresponding to color {@code cc0}. | ||||||
|   | |||||||
| @@ -87,7 +87,7 @@ public class ChatConfig { | |||||||
|      */ |      */ | ||||||
|     public static int getPrefixWidth(boolean console) { |     public static int getPrefixWidth(boolean console) { | ||||||
|         Chat c; |         Chat c; | ||||||
|         return prefix == null ? 0 : (c = prefix.get()) == null ? 0 : ChatUtil.componentWidth(c.getAdv(), console); |         return prefix == null ? 0 : (c = prefix.get()) == null ? 0 : ChatUtil.componentWidth(c.get(), console); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,7 +1,6 @@ | |||||||
| package fr.pandacube.lib.chat; | package fr.pandacube.lib.chat; | ||||||
|  |  | ||||||
| import java.util.Objects; | import fr.pandacube.lib.chat.Chat.FormatableChat; | ||||||
|  |  | ||||||
| import net.kyori.adventure.text.BlockNBTComponent; | import net.kyori.adventure.text.BlockNBTComponent; | ||||||
| import net.kyori.adventure.text.Component; | import net.kyori.adventure.text.Component; | ||||||
| import net.kyori.adventure.text.ComponentBuilder; | import net.kyori.adventure.text.ComponentBuilder; | ||||||
| @@ -18,9 +17,8 @@ import net.kyori.adventure.text.format.NamedTextColor; | |||||||
| import net.kyori.adventure.text.format.TextColor; | import net.kyori.adventure.text.format.TextColor; | ||||||
| import net.kyori.adventure.text.minimessage.MiniMessage; | import net.kyori.adventure.text.minimessage.MiniMessage; | ||||||
| import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; | import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; | ||||||
| import net.md_5.bungee.api.chat.BaseComponent; |  | ||||||
|  |  | ||||||
| import fr.pandacube.lib.chat.Chat.FormatableChat; | import java.util.Objects; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Abstract class holding the publicly accessible methods to create an instance of {@link Chat} component. |  * Abstract class holding the publicly accessible methods to create an instance of {@link Chat} component. | ||||||
| @@ -33,15 +31,6 @@ public abstract class ChatStatic { | |||||||
|         return new FormatableChat(componentToBuilder(c)); |         return new FormatableChat(componentToBuilder(c)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Creates a {@link FormatableChat} from the provided Bungee {@link BaseComponent}. |  | ||||||
|      * @param c the {@link BaseComponent}. |  | ||||||
|      * @return a new {@link FormatableChat}. |  | ||||||
|      */ |  | ||||||
|     public static FormatableChat chatComponent(BaseComponent c) { |  | ||||||
|         return new FormatableChat(componentToBuilder(Chat.toAdventure(c))); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Creates a {@link FormatableChat} from the provided {@link ComponentLike}. |      * Creates a {@link FormatableChat} from the provided {@link ComponentLike}. | ||||||
|      * If the provided component is an instance of {@link Chat}, its content will be duplicated, and the provided one |      * If the provided component is an instance of {@link Chat}, its content will be duplicated, and the provided one | ||||||
| @@ -61,15 +50,6 @@ public abstract class ChatStatic { | |||||||
|         return new FormatableChat(Component.text()); |         return new FormatableChat(Component.text()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Creates a {@link FormatableChat} from the provided Bungee {@link BaseComponent BaseComponent[]}. |  | ||||||
|      * @param c the array of {@link BaseComponent}. |  | ||||||
|      * @return a new {@link FormatableChat}. |  | ||||||
|      */ |  | ||||||
|     public static FormatableChat chatComponent(BaseComponent[] c) { |  | ||||||
|         return chatComponent(Chat.toAdventure(c)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,5 +1,17 @@ | |||||||
| package fr.pandacube.lib.chat; | package fr.pandacube.lib.chat; | ||||||
|  |  | ||||||
|  | import fr.pandacube.lib.chat.Chat.FormatableChat; | ||||||
|  | import net.kyori.adventure.text.Component; | ||||||
|  | import net.kyori.adventure.text.ComponentLike; | ||||||
|  | import net.kyori.adventure.text.TextComponent; | ||||||
|  | import net.kyori.adventure.text.TranslatableComponent; | ||||||
|  | import net.kyori.adventure.text.TranslationArgument; | ||||||
|  | import net.kyori.adventure.text.format.NamedTextColor; | ||||||
|  | import net.kyori.adventure.text.format.TextColor; | ||||||
|  | import net.kyori.adventure.text.format.TextDecoration; | ||||||
|  | import net.kyori.adventure.text.format.TextDecoration.State; | ||||||
|  | import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; | ||||||
|  |  | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.Arrays; | import java.util.Arrays; | ||||||
| import java.util.Collections; | import java.util.Collections; | ||||||
| @@ -10,19 +22,6 @@ import java.util.Set; | |||||||
| import java.util.TreeSet; | import java.util.TreeSet; | ||||||
| import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||||
|  |  | ||||||
| import net.kyori.adventure.text.Component; |  | ||||||
| import net.kyori.adventure.text.ComponentLike; |  | ||||||
| import net.kyori.adventure.text.TextComponent; |  | ||||||
| import net.kyori.adventure.text.TranslatableComponent; |  | ||||||
| import net.kyori.adventure.text.TranslationArgument; |  | ||||||
| import net.kyori.adventure.text.format.NamedTextColor; |  | ||||||
| import net.kyori.adventure.text.format.TextColor; |  | ||||||
| import net.kyori.adventure.text.format.TextDecoration; |  | ||||||
| import net.kyori.adventure.text.format.TextDecoration.State; |  | ||||||
| import net.md_5.bungee.api.ChatColor; |  | ||||||
|  |  | ||||||
| import fr.pandacube.lib.chat.Chat.FormatableChat; |  | ||||||
|  |  | ||||||
| import static fr.pandacube.lib.chat.ChatStatic.chat; | import static fr.pandacube.lib.chat.ChatStatic.chat; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -351,7 +350,7 @@ public class ChatUtil { | |||||||
|  |  | ||||||
|         do { |         do { | ||||||
|             char c = legacyText.charAt(index); |             char c = legacyText.charAt(index); | ||||||
|             if (c == ChatColor.COLOR_CHAR && index < legacyText.length() - 1) { |             if (c == LegacyComponentSerializer.SECTION_CHAR && index < legacyText.length() - 1) { | ||||||
|                 currentWord.append(c); |                 currentWord.append(c); | ||||||
|                 c = legacyText.charAt(++index); |                 c = legacyText.charAt(++index); | ||||||
|                 currentWord.append(c); |                 currentWord.append(c); | ||||||
| @@ -482,7 +481,7 @@ public class ChatUtil { | |||||||
|             } |             } | ||||||
|             if (!row.isEmpty()) |             if (!row.isEmpty()) | ||||||
|                 spacedRow.then(row.getLast()); |                 spacedRow.then(row.getLast()); | ||||||
|             spacedRows.add(spacedRow.getAdv()); |             spacedRows.add(spacedRow.get()); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return spacedRows; |         return spacedRows; | ||||||
| @@ -504,14 +503,14 @@ public class ChatUtil { | |||||||
|      */ |      */ | ||||||
|     public static Component customWidthSpace(int width, boolean console) { |     public static Component customWidthSpace(int width, boolean console) { | ||||||
|         if (console) |         if (console) | ||||||
|             return Chat.text(" ".repeat(width)).getAdv(); |             return Chat.text(" ".repeat(width)).get(); | ||||||
|         return switch (width) { |         return switch (width) { | ||||||
|             case 0, 1 -> Component.empty(); |             case 0, 1 -> Component.empty(); | ||||||
|             case 2 -> Chat.text(".").black().getAdv(); |             case 2 -> Chat.text(".").black().get(); | ||||||
|             case 3 -> Chat.text("`").black().getAdv(); |             case 3 -> Chat.text("`").black().get(); | ||||||
|             case 6 -> Chat.text(". ").black().getAdv(); |             case 6 -> Chat.text(". ").black().get(); | ||||||
|             case 7 -> Chat.text("` ").black().getAdv(); |             case 7 -> Chat.text("` ").black().get(); | ||||||
|             case 11 -> Chat.text("`  ").black().getAdv(); |             case 11 -> Chat.text("`  ").black().get(); | ||||||
|             default -> { |             default -> { | ||||||
|                 int nbSpace = width / 4; |                 int nbSpace = width / 4; | ||||||
|                 int nbBold = width % 4; |                 int nbBold = width % 4; | ||||||
| @@ -520,13 +519,13 @@ public class ChatUtil { | |||||||
|                     if (nbBold > 0) { |                     if (nbBold > 0) { | ||||||
|                         yield Chat.text(" ".repeat(nbNotBold)).bold(false) |                         yield Chat.text(" ".repeat(nbNotBold)).bold(false) | ||||||
|                                 .then(Chat.text(" ".repeat(nbBold)).bold(true)) |                                 .then(Chat.text(" ".repeat(nbBold)).bold(true)) | ||||||
|                                 .getAdv(); |                                 .get(); | ||||||
|                     } |                     } | ||||||
|                     else |                     else | ||||||
|                         yield Chat.text(" ".repeat(nbNotBold)).bold(false).getAdv(); |                         yield Chat.text(" ".repeat(nbNotBold)).bold(false).get(); | ||||||
|                 } |                 } | ||||||
|                 else if (nbBold > 0) { |                 else if (nbBold > 0) { | ||||||
|                     yield Chat.text(" ".repeat(nbBold)).bold(true).getAdv(); |                     yield Chat.text(" ".repeat(nbBold)).bold(true).get(); | ||||||
|                 } |                 } | ||||||
|                 throw new IllegalStateException("Should not be here (width=" + width + "; nbSpace=" + nbSpace + "; nbBold=" + nbBold + "; nbNotBold=" + nbNotBold + ")"); |                 throw new IllegalStateException("Should not be here (width=" + width + "; nbSpace=" + nbSpace + "; nbBold=" + nbBold + "; nbNotBold=" + nbNotBold + ")"); | ||||||
|             } |             } | ||||||
|   | |||||||
| @@ -0,0 +1,230 @@ | |||||||
|  | package fr.pandacube.lib.chat; | ||||||
|  |  | ||||||
|  | import net.kyori.adventure.text.format.TextColor; | ||||||
|  | import net.kyori.adventure.text.format.TextDecoration; | ||||||
|  | import net.kyori.adventure.text.format.TextFormat; | ||||||
|  | import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; | ||||||
|  | import net.kyori.adventure.text.serializer.legacy.LegacyFormat; | ||||||
|  |  | ||||||
|  | import java.util.Arrays; | ||||||
|  | import java.util.LinkedHashMap; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Convenient enum to uses legacy format while keeping compatibility with modern chat format and API (Adventure, ...) | ||||||
|  |  */ | ||||||
|  | public enum LegacyChatFormat { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Black (0) color format code. | ||||||
|  |      */ | ||||||
|  |     BLACK('0'), | ||||||
|  |     /** | ||||||
|  |      * Dark blue (1) color format code. | ||||||
|  |      */ | ||||||
|  |     DARK_BLUE('1'), | ||||||
|  |     /** | ||||||
|  |      * Dark green (2) color format code. | ||||||
|  |      */ | ||||||
|  |     DARK_GREEN('2'), | ||||||
|  |     /** | ||||||
|  |      * Dark aqua (3) color format code. | ||||||
|  |      */ | ||||||
|  |     DARK_AQUA('3'), | ||||||
|  |     /** | ||||||
|  |      * Dark red (4) color format code. | ||||||
|  |      */ | ||||||
|  |     DARK_RED('4'), | ||||||
|  |     /** | ||||||
|  |      * Dark purple (5) color format code. | ||||||
|  |      */ | ||||||
|  |     DARK_PURPLE('5'), | ||||||
|  |     /** | ||||||
|  |      * Gold (6) color format code. | ||||||
|  |      */ | ||||||
|  |     GOLD('6'), | ||||||
|  |     /** | ||||||
|  |      * Gray (7) color format code. | ||||||
|  |      */ | ||||||
|  |     GRAY('7'), | ||||||
|  |     /** | ||||||
|  |      * Dark gray (8) color format code. | ||||||
|  |      */ | ||||||
|  |     DARK_GRAY('8'), | ||||||
|  |     /** | ||||||
|  |      * Blue (9) color format code. | ||||||
|  |      */ | ||||||
|  |     BLUE('9'), | ||||||
|  |     /** | ||||||
|  |      * Green (A) color format code. | ||||||
|  |      */ | ||||||
|  |     GREEN('a'), | ||||||
|  |     /** | ||||||
|  |      * Aqua (B) color format code. | ||||||
|  |      */ | ||||||
|  |     AQUA('b'), | ||||||
|  |     /** | ||||||
|  |      * Red (C) color format code. | ||||||
|  |      */ | ||||||
|  |     RED('c'), | ||||||
|  |     /** | ||||||
|  |      * Light purple (D) color format code. | ||||||
|  |      */ | ||||||
|  |     LIGHT_PURPLE('d'), | ||||||
|  |     /** | ||||||
|  |      * Yellow (E) color format code. | ||||||
|  |      */ | ||||||
|  |     YELLOW('e'), | ||||||
|  |     /** | ||||||
|  |      * White (F) color format code. | ||||||
|  |      */ | ||||||
|  |     WHITE('f'), | ||||||
|  |     /** | ||||||
|  |      * Obfuscated (K) decoration format code. | ||||||
|  |      */ | ||||||
|  |     OBFUSCATED('k'), | ||||||
|  |     /** | ||||||
|  |      * Bold (L) decoration format code. | ||||||
|  |      */ | ||||||
|  |     BOLD('l'), | ||||||
|  |     /** | ||||||
|  |      * Strikethrough (M) decoration format code. | ||||||
|  |      */ | ||||||
|  |     STRIKETHROUGH('m'), | ||||||
|  |     /** | ||||||
|  |      * Underlined (N) decoration format code. | ||||||
|  |      */ | ||||||
|  |     UNDERLINED('n'), | ||||||
|  |     /** | ||||||
|  |      * Italic (O) decoration format code. | ||||||
|  |      */ | ||||||
|  |     ITALIC('o'), | ||||||
|  |     /** | ||||||
|  |      * Reset (R) format code. | ||||||
|  |      */ | ||||||
|  |     RESET('r'); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The character used by Minecraft for legacy chat format. | ||||||
|  |      */ | ||||||
|  |     public static final char COLOR_CHAR = LegacyComponentSerializer.SECTION_CHAR; | ||||||
|  |  | ||||||
|  |     /** {@link #COLOR_CHAR} but as a String! */ | ||||||
|  |     public static final String COLOR_STR_PREFIX = Character.toString(COLOR_CHAR); | ||||||
|  |  | ||||||
|  |     private static final Map<Character, LegacyChatFormat> BY_CHAR; | ||||||
|  |     private static final Map<TextFormat, LegacyChatFormat> BY_FORMAT; | ||||||
|  |     private static final Map<LegacyFormat, LegacyChatFormat> BY_LEGACY; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets the {@link LegacyChatFormat} from the provided chat color code. | ||||||
|  |      * @param code the character code from [0-9A-Fa-fK-Ok-oRr]. | ||||||
|  |      * @return the {@link LegacyChatFormat} related to the provided code. | ||||||
|  |      */ | ||||||
|  |     public static LegacyChatFormat of(char code) { | ||||||
|  |         return BY_CHAR.get(Character.toLowerCase(code)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets the {@link LegacyChatFormat} from the provided {@link TextFormat} instance. | ||||||
|  |      * @param format the {@link TextFormat} instance. | ||||||
|  |      * @return the {@link LegacyChatFormat} related to the provided format. | ||||||
|  |      */ | ||||||
|  |     public static LegacyChatFormat of(TextFormat format) { | ||||||
|  |         LegacyChatFormat colorOrDecoration = BY_FORMAT.get(format); | ||||||
|  |         if (colorOrDecoration != null) | ||||||
|  |             return colorOrDecoration; | ||||||
|  |         if (format.getClass().getSimpleName().equals("Reset")) // an internal class of legacy serializer library | ||||||
|  |             return RESET; | ||||||
|  |         throw new IllegalArgumentException("Unsupported format of type " + format.getClass()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets the {@link LegacyChatFormat} from the provided {@link LegacyFormat} instance. | ||||||
|  |      * @param advLegacy the {@link LegacyFormat} instance. | ||||||
|  |      * @return the {@link LegacyChatFormat} related to the provided format. | ||||||
|  |      */ | ||||||
|  |     public static LegacyChatFormat of(LegacyFormat advLegacy) { | ||||||
|  |         return BY_LEGACY.get(advLegacy); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The format code of this chat format. | ||||||
|  |      */ | ||||||
|  |     public final char code; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The Adventure legacy format instance related to this chat format. | ||||||
|  |      */ | ||||||
|  |     public final LegacyFormat advLegacyFormat; | ||||||
|  |  | ||||||
|  |     LegacyChatFormat(char code) { | ||||||
|  |         this.code = code; | ||||||
|  |         advLegacyFormat = LegacyComponentSerializer.parseChar(code); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets the related {@link TextColor}, or null if it's not a color. | ||||||
|  |      * @return the related {@link TextColor}, or null if it's not a color. | ||||||
|  |      */ | ||||||
|  |     public TextColor getTextColor() { | ||||||
|  |         return advLegacyFormat.color(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Tells if this format is a color. | ||||||
|  |      * @return true if this format is a color, false otherwise. | ||||||
|  |      */ | ||||||
|  |     public boolean isColor() { | ||||||
|  |         return getTextColor() != null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets the related {@link TextDecoration}, or null if it's not a decoration. | ||||||
|  |      * @return the related {@link TextDecoration}, or null if it's not a decoration. | ||||||
|  |      */ | ||||||
|  |     public TextDecoration getTextDecoration() { | ||||||
|  |         return advLegacyFormat.decoration(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Tells if this format is a decoration (bold, italic, ...). | ||||||
|  |      * @return true if this format is a decoration, false otherwise. | ||||||
|  |      */ | ||||||
|  |     public boolean isDecoration() { | ||||||
|  |         return getTextDecoration() != null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Tells if this format is the reset. | ||||||
|  |      * @return true if this format is the reset, false otherwise. | ||||||
|  |      */ | ||||||
|  |     public boolean isReset() { | ||||||
|  |         return this == RESET; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public String toString() { | ||||||
|  |         return COLOR_STR_PREFIX + code; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     static { | ||||||
|  |         BY_CHAR = Arrays.stream(values()).sequential() | ||||||
|  |                 .collect(Collectors.toMap(e -> e.code, e -> e, (e1, e2) -> e1, LinkedHashMap::new)); | ||||||
|  |         BY_FORMAT = Arrays.stream(values()).sequential() | ||||||
|  |                 .filter(e -> e.isColor() || e.isDecoration()) | ||||||
|  |                 .collect(Collectors.toMap(e -> { | ||||||
|  |                     if (e.isColor()) | ||||||
|  |                         return e.getTextColor(); | ||||||
|  |                     return e.getTextDecoration(); | ||||||
|  |                 }, e -> e, (e1, e2) -> e1, LinkedHashMap::new)); | ||||||
|  |         BY_LEGACY = Arrays.stream(values()).sequential() | ||||||
|  |                 .collect(Collectors.toMap(e -> e.advLegacyFormat, e -> e, (e1, e2) -> e1, LinkedHashMap::new)); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -15,42 +15,36 @@ | |||||||
|     <packaging>jar</packaging> |     <packaging>jar</packaging> | ||||||
|      |      | ||||||
| 	<repositories> | 	<repositories> | ||||||
| 		<repository> |  | ||||||
| 			<id>minecraft-libraries</id> |  | ||||||
| 			<name>Minecraft Libraries</name> |  | ||||||
| 			<url>https://libraries.minecraft.net</url> |  | ||||||
| 		</repository> |  | ||||||
|         <repository> |         <repository> | ||||||
|             <id>bungeecord-repo</id> |             <id>bungeecord-repo</id> | ||||||
|             <url>https://oss.sonatype.org/content/repositories/snapshots</url> |             <url>https://oss.sonatype.org/content/repositories/snapshots</url> | ||||||
|         </repository> |         </repository> | ||||||
|     </repositories> |     </repositories> | ||||||
|  |  | ||||||
|   <dependencies> |     <dependencies> | ||||||
|       <dependency> |  | ||||||
|           <groupId>fr.pandacube.lib</groupId> |  | ||||||
|           <artifactId>pandalib-core</artifactId> |  | ||||||
|           <version>${project.version}</version> |  | ||||||
|       </dependency> |  | ||||||
|       <dependency> |  | ||||||
|           <groupId>fr.pandacube.lib</groupId> |  | ||||||
|           <artifactId>pandalib-reflect</artifactId> |  | ||||||
|           <version>${project.version}</version> |  | ||||||
|       </dependency> |  | ||||||
|       <dependency> |  | ||||||
|           <groupId>fr.pandacube.lib</groupId> |  | ||||||
|           <artifactId>pandalib-commands</artifactId> |  | ||||||
|           <version>${project.version}</version> |  | ||||||
|       </dependency> |  | ||||||
|  |  | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>net.md-5</groupId> |             <groupId>fr.pandacube.lib</groupId> | ||||||
|             <artifactId>bungeecord-log</artifactId> |             <artifactId>pandalib-core</artifactId> | ||||||
|             <version>${bungeecord.version}</version> |             <version>${project.version}</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>fr.pandacube.lib</groupId> | ||||||
|  |             <artifactId>pandalib-reflect</artifactId> | ||||||
|  |             <version>${project.version}</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>fr.pandacube.lib</groupId> | ||||||
|  |             <artifactId>pandalib-commands</artifactId> | ||||||
|  |             <version>${project.version}</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>fr.pandacube.lib</groupId> | ||||||
|  |             <artifactId>pandalib-config</artifactId> | ||||||
|  |             <version>${project.version}</version> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>net.md-5</groupId> |             <groupId>net.md-5</groupId> | ||||||
|             <artifactId>bungeecord-config</artifactId> |             <artifactId>bungeecord-log</artifactId> | ||||||
|             <version>${bungeecord.version}</version> |             <version>${bungeecord.version}</version> | ||||||
|         </dependency> |         </dependency> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -18,7 +18,7 @@ import fr.pandacube.lib.chat.Chat.FormatableChat; | |||||||
| import fr.pandacube.lib.chat.ChatTreeNode; | import fr.pandacube.lib.chat.ChatTreeNode; | ||||||
| import fr.pandacube.lib.cli.CLIApplication; | import fr.pandacube.lib.cli.CLIApplication; | ||||||
| import fr.pandacube.lib.util.log.Log; | import fr.pandacube.lib.util.log.Log; | ||||||
| import net.md_5.bungee.api.chat.BaseComponent; | import net.kyori.adventure.text.Component; | ||||||
|  |  | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.Arrays; | import java.util.Arrays; | ||||||
| @@ -192,7 +192,7 @@ public class CommandAdmin extends CLIBrigadierCommand { | |||||||
| 	 | 	 | ||||||
| 	 | 	 | ||||||
| 	 | 	 | ||||||
| 	private BaseComponent displayCurrentNode(CommandNode<CLICommandSender> node, boolean redirectTarget, CLICommandSender sender) { | 	private Component displayCurrentNode(CommandNode<CLICommandSender> node, boolean redirectTarget, CLICommandSender sender) { | ||||||
| 		if (node == null) | 		if (node == null) | ||||||
| 			throw new IllegalArgumentException("node must not be null"); | 			throw new IllegalArgumentException("node must not be null"); | ||||||
| 		FormatableChat d; | 		FormatableChat d; | ||||||
|   | |||||||
| @@ -11,27 +11,31 @@ import java.util.logging.Logger; | |||||||
|  */ |  */ | ||||||
| public class BadCommandUsage extends RuntimeException { | public class BadCommandUsage extends RuntimeException { | ||||||
|  |  | ||||||
| 	/** Constructs a new runtime exception with no message or cause. | 	/** | ||||||
|  | 	 * Constructs a new runtime exception with no message or cause. | ||||||
| 	 */ | 	 */ | ||||||
| 	public BadCommandUsage() { | 	public BadCommandUsage() { | ||||||
| 		super(); | 		super(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** Constructs a new runtime exception with the specified cause. | 	/** | ||||||
|  | 	 * Constructs a new runtime exception with the specified cause. | ||||||
| 	 * @param cause the cause. | 	 * @param cause the cause. | ||||||
| 	 */ | 	 */ | ||||||
| 	public BadCommandUsage(Throwable cause) { | 	public BadCommandUsage(Throwable cause) { | ||||||
| 		super(cause); | 		super(cause); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** Constructs a new runtime exception with the specified message. | 	/** | ||||||
|  | 	 * Constructs a new runtime exception with the specified message. | ||||||
| 	 * @param message the message. | 	 * @param message the message. | ||||||
| 	 */ | 	 */ | ||||||
| 	public BadCommandUsage(String message) { | 	public BadCommandUsage(String message) { | ||||||
| 		super(message); | 		super(message); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** Constructs a new runtime exception with the specified message and cause. | 	/** | ||||||
|  | 	 * Constructs a new runtime exception with the specified message and cause. | ||||||
| 	 * @param message the message. | 	 * @param message the message. | ||||||
| 	 * @param cause the cause. | 	 * @param cause the cause. | ||||||
| 	 */ | 	 */ | ||||||
|   | |||||||
							
								
								
									
										33
									
								
								pandalib-config/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								pandalib-config/pom.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | |||||||
|  | <?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-config</artifactId> | ||||||
|  |     <packaging>jar</packaging> | ||||||
|  |  | ||||||
|  |     <repositories> | ||||||
|  |         <repository> | ||||||
|  |             <id>bungeecord-repo</id> | ||||||
|  |             <url>https://oss.sonatype.org/content/repositories/snapshots</url> | ||||||
|  |         </repository> | ||||||
|  |     </repositories> | ||||||
|  |  | ||||||
|  |     <dependencies> | ||||||
|  |  | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>net.md-5</groupId> | ||||||
|  |             <artifactId>bungeecord-config</artifactId> | ||||||
|  |             <version>${bungeecord.version}</version> | ||||||
|  |         </dependency> | ||||||
|  |  | ||||||
|  |     </dependencies> | ||||||
|  |  | ||||||
|  | </project> | ||||||
| @@ -1,7 +1,4 @@ | |||||||
| package fr.pandacube.lib.core.config; | package fr.pandacube.lib.config; | ||||||
| 
 |  | ||||||
| import fr.pandacube.lib.chat.ChatColorUtil; |  | ||||||
| import fr.pandacube.lib.util.log.Log; |  | ||||||
| 
 | 
 | ||||||
| import java.io.BufferedReader; | import java.io.BufferedReader; | ||||||
| import java.io.File; | import java.io.File; | ||||||
| @@ -56,7 +53,7 @@ public abstract class AbstractConfig { | |||||||
| 		while ((line = reader.readLine()) != null) { | 		while ((line = reader.readLine()) != null) { | ||||||
| 			String trimmedLine = line.trim(); | 			String trimmedLine = line.trim(); | ||||||
| 			 | 			 | ||||||
| 			if (ignoreEmpty && trimmedLine.equals("")) | 			if (ignoreEmpty && trimmedLine.isEmpty()) | ||||||
| 				continue; | 				continue; | ||||||
| 			 | 			 | ||||||
| 			if (ignoreHashtagComment && trimmedLine.startsWith("#")) | 			if (ignoreHashtagComment && trimmedLine.startsWith("#")) | ||||||
| @@ -114,25 +111,6 @@ public abstract class AbstractConfig { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 	/** |  | ||||||
| 	 * Utility method to that translate the {@code '&'} formatted string to the legacy format. |  | ||||||
| 	 * @param string the string to convert. |  | ||||||
| 	 * @return a legacy formatted string (using {@code '§'}). |  | ||||||
| 	 */ |  | ||||||
| 	public static String getTranslatedColorCode(String string) { |  | ||||||
| 		return ChatColorUtil.translateAlternateColorCodes('&', string); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Logs the message as a warning into console, prefixed with the context of this config. |  | ||||||
| 	 * @param message the message to log. |  | ||||||
| 	 */ |  | ||||||
| 	protected void warning(String message) { |  | ||||||
| 		Log.warning("Error in configuration '"+configFile.getName()+"': " + message); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 	/** | 	/** | ||||||
| 	 * The type of config. | 	 * The type of config. | ||||||
| 	 */ | 	 */ | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| package fr.pandacube.lib.core.config; | package fr.pandacube.lib.config; | ||||||
| 
 | 
 | ||||||
| import java.io.File; | import java.io.File; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| @@ -37,6 +37,12 @@ | |||||||
|             <version>${project.version}</version> |             <version>${project.version}</version> | ||||||
|         </dependency> |         </dependency> | ||||||
|  |  | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>com.google.guava</groupId> | ||||||
|  |             <artifactId>guava</artifactId> | ||||||
|  |             <version>${guava.version}</version> | ||||||
|  |         </dependency> | ||||||
|  |  | ||||||
|         <!-- Cron expression interpreter --> |         <!-- Cron expression interpreter --> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>ch.eitchnet</groupId> |             <groupId>ch.eitchnet</groupId> | ||||||
|   | |||||||
| @@ -1,8 +1,8 @@ | |||||||
| package fr.pandacube.lib.core.backup; | package fr.pandacube.lib.core.backup; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.chat.Chat; | import fr.pandacube.lib.chat.Chat; | ||||||
|  | import fr.pandacube.lib.chat.LegacyChatFormat; | ||||||
| import fr.pandacube.lib.util.log.Log; | import fr.pandacube.lib.util.log.Log; | ||||||
| import net.md_5.bungee.api.ChatColor; |  | ||||||
|  |  | ||||||
| import java.io.File; | import java.io.File; | ||||||
| import java.time.LocalDateTime; | import java.time.LocalDateTime; | ||||||
| @@ -107,14 +107,14 @@ public abstract class BackupCleaner implements UnaryOperator<TreeSet<LocalDateTi | |||||||
|         if (files == null) |         if (files == null) | ||||||
|             return; |             return; | ||||||
|  |  | ||||||
|         Log.info("[Backup] Cleaning up backup directory " + ChatColor.GRAY + compressDisplayName + ChatColor.RESET + "..."); |         Log.info("[Backup] Cleaning up backup directory " + LegacyChatFormat.GRAY + compressDisplayName + LegacyChatFormat.RESET + "..."); | ||||||
|  |  | ||||||
|         TreeMap<LocalDateTime, File> datedFiles = new TreeMap<>(); |         TreeMap<LocalDateTime, File> datedFiles = new TreeMap<>(); | ||||||
|  |  | ||||||
|         for (String filename : files) { |         for (String filename : files) { | ||||||
|             File file = new File(archiveDir, filename); |             File file = new File(archiveDir, filename); | ||||||
|             if (!filename.matches("\\d{8}-\\d{6}\\.zip")) { |             if (!filename.matches("\\d{8}-\\d{6}\\.zip")) { | ||||||
|                 Log.warning("[Backup] " + ChatColor.GRAY + compressDisplayName + ChatColor.RESET + " Invalid file in backup directory: " + filename); |                 Log.warning("[Backup] " + LegacyChatFormat.GRAY + compressDisplayName + LegacyChatFormat.RESET + " Invalid file in backup directory: " + filename); | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -123,7 +123,7 @@ public abstract class BackupCleaner implements UnaryOperator<TreeSet<LocalDateTi | |||||||
|             try { |             try { | ||||||
|                 ldt = LocalDateTime.parse(dateTimeStr, BackupProcess.dateFileNameFormatter); |                 ldt = LocalDateTime.parse(dateTimeStr, BackupProcess.dateFileNameFormatter); | ||||||
|             } catch (DateTimeParseException e) { |             } catch (DateTimeParseException e) { | ||||||
|                 Log.warning("[Backup] " + ChatColor.GRAY + compressDisplayName + ChatColor.RESET + " Unable to parse file name to a date-time: " + filename, e); |                 Log.warning("[Backup] " + LegacyChatFormat.GRAY + compressDisplayName + LegacyChatFormat.RESET + " Unable to parse file name to a date-time: " + filename, e); | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -156,7 +156,7 @@ public abstract class BackupCleaner implements UnaryOperator<TreeSet<LocalDateTi | |||||||
|         if (testOnly || oneDeleted) |         if (testOnly || oneDeleted) | ||||||
|             Log.warning(c.getLegacyText()); |             Log.warning(c.getLegacyText()); | ||||||
|  |  | ||||||
|         Log.info("[Backup] Backup directory " + ChatColor.GRAY + compressDisplayName + ChatColor.RESET + " cleaned."); |         Log.info("[Backup] Backup directory " + LegacyChatFormat.GRAY + compressDisplayName + LegacyChatFormat.RESET + " cleaned."); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,10 +1,10 @@ | |||||||
| package fr.pandacube.lib.core.backup; | package fr.pandacube.lib.core.backup; | ||||||
|  |  | ||||||
| import fc.cron.CronExpression; | import fc.cron.CronExpression; | ||||||
|  | import fr.pandacube.lib.chat.LegacyChatFormat; | ||||||
| import fr.pandacube.lib.core.cron.CronScheduler; | import fr.pandacube.lib.core.cron.CronScheduler; | ||||||
| import fr.pandacube.lib.util.FileUtils; | import fr.pandacube.lib.util.FileUtils; | ||||||
| import fr.pandacube.lib.util.log.Log; | import fr.pandacube.lib.util.log.Log; | ||||||
| import net.md_5.bungee.api.ChatColor; |  | ||||||
|  |  | ||||||
| import java.io.File; | import java.io.File; | ||||||
| import java.text.DateFormat; | import java.text.DateFormat; | ||||||
| @@ -209,7 +209,7 @@ public abstract class BackupProcess implements Comparable<BackupProcess>, Runnab | |||||||
|             File sourceDir = getSourceDir(); |             File sourceDir = getSourceDir(); | ||||||
|  |  | ||||||
|             if (!sourceDir.exists()) { |             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 " + LegacyChatFormat.GRAY + getDisplayName() + LegacyChatFormat.RESET + ": source directory " + sourceDir + " doesn't exist"); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -219,7 +219,7 @@ public abstract class BackupProcess implements Comparable<BackupProcess>, Runnab | |||||||
|             onBackupStart(); |             onBackupStart(); | ||||||
|  |  | ||||||
|             new Thread(() -> { |             new Thread(() -> { | ||||||
|                 Log.info("[Backup] Starting for " + ChatColor.GRAY + getDisplayName() + ChatColor.RESET + " ..."); |                 Log.info("[Backup] Starting for " + LegacyChatFormat.GRAY + getDisplayName() + LegacyChatFormat.RESET + " ..."); | ||||||
|  |  | ||||||
|                 compressor = new ZipCompressor(sourceDir, target, 9, filter); |                 compressor = new ZipCompressor(sourceDir, target, 9, filter); | ||||||
|  |  | ||||||
| @@ -229,7 +229,7 @@ public abstract class BackupProcess implements Comparable<BackupProcess>, Runnab | |||||||
|  |  | ||||||
|                     success = true; |                     success = true; | ||||||
|  |  | ||||||
|                     Log.info("[Backup] Finished for " + ChatColor.GRAY + getDisplayName() + ChatColor.RESET); |                     Log.info("[Backup] Finished for " + LegacyChatFormat.GRAY + getDisplayName() + LegacyChatFormat.RESET); | ||||||
|  |  | ||||||
|                     try { |                     try { | ||||||
|                         BackupCleaner cleaner = getBackupCleaner(); |                         BackupCleaner cleaner = getBackupCleaner(); | ||||||
| @@ -267,7 +267,7 @@ public abstract class BackupProcess implements Comparable<BackupProcess>, Runnab | |||||||
|      * Logs the scheduling status of this backup process. |      * Logs the scheduling status of this backup process. | ||||||
|      */ |      */ | ||||||
|     public void displayNextSchedule() { |     public void displayNextSchedule() { | ||||||
|         Log.info("[Backup] " + ChatColor.GRAY + getDisplayName() + ChatColor.RESET + " next backup on " |         Log.info("[Backup] " + LegacyChatFormat.GRAY + getDisplayName() + LegacyChatFormat.RESET + " next backup on " | ||||||
|                 + DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG).format(new Date(getNext()))); |                 + DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG).format(new Date(getNext()))); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -297,7 +297,7 @@ public abstract class BackupProcess implements Comparable<BackupProcess>, Runnab | |||||||
|     public void logProgress() { |     public void logProgress() { | ||||||
|         if (compressor == null) |         if (compressor == null) | ||||||
|             return; |             return; | ||||||
|         Log.info("[Backup] " + ChatColor.GRAY + getDisplayName() + ChatColor.RESET + ": " + compressor.getState().getLegacyText()); |         Log.info("[Backup] " + LegacyChatFormat.GRAY + getDisplayName() + LegacyChatFormat.RESET + ": " + compressor.getState().getLegacyText()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,8 +1,8 @@ | |||||||
| package fr.pandacube.lib.core.backup; | package fr.pandacube.lib.core.backup; | ||||||
|  |  | ||||||
| import com.google.common.io.Files; | import com.google.common.io.Files; | ||||||
|  | import fr.pandacube.lib.chat.LegacyChatFormat; | ||||||
| import fr.pandacube.lib.util.log.Log; | import fr.pandacube.lib.util.log.Log; | ||||||
| import net.md_5.bungee.api.ChatColor; |  | ||||||
|  |  | ||||||
| import java.io.File; | import java.io.File; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| @@ -53,7 +53,7 @@ public class RotatedLogsBackupProcess extends BackupProcess { | |||||||
|         if (!getSourceDir().isDirectory()) |         if (!getSourceDir().isDirectory()) | ||||||
|             return; |             return; | ||||||
|  |  | ||||||
|         Log.info("[Backup] Starting for " + ChatColor.GRAY + getDisplayName() + ChatColor.RESET + " ..."); |         Log.info("[Backup] Starting for " + LegacyChatFormat.GRAY + getDisplayName() + LegacyChatFormat.RESET + " ..."); | ||||||
|  |  | ||||||
|         try { |         try { | ||||||
|             // wait a little after the log message above, in case the log file rotation has to be performed. |             // wait a little after the log message above, in case the log file rotation has to be performed. | ||||||
| @@ -82,9 +82,9 @@ public class RotatedLogsBackupProcess extends BackupProcess { | |||||||
|  |  | ||||||
|             success = true; |             success = true; | ||||||
|  |  | ||||||
|             Log.info("[Backup] Finished for " + ChatColor.GRAY + getDisplayName() + ChatColor.RESET); |             Log.info("[Backup] Finished for " + LegacyChatFormat.GRAY + getDisplayName() + LegacyChatFormat.RESET); | ||||||
|         } catch (Exception e) { |         } catch (Exception e) { | ||||||
|             Log.severe("[Backup] Failed for : " + ChatColor.GRAY + getDisplayName() + ChatColor.RESET, e); |             Log.severe("[Backup] Failed for : " + LegacyChatFormat.GRAY + getDisplayName() + LegacyChatFormat.RESET, e); | ||||||
|         } finally { |         } finally { | ||||||
|             onBackupEnd(success); |             onBackupEnd(success); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ import java.io.File; | |||||||
| import java.io.FileOutputStream; | import java.io.FileOutputStream; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| import java.nio.file.Files; | import java.nio.file.Files; | ||||||
|  | import java.nio.file.NoSuchFileException; | ||||||
| import java.nio.file.attribute.BasicFileAttributes; | import java.nio.file.attribute.BasicFileAttributes; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| @@ -117,7 +118,11 @@ public class ZipCompressor { | |||||||
| 			} | 			} | ||||||
| 			 | 			 | ||||||
| 			for (Entry entry : entriesToCompress) { | 			for (Entry entry : entriesToCompress) { | ||||||
| 				entry.zip(); | 				try { | ||||||
|  | 					entry.zip(); | ||||||
|  | 				} catch (NoSuchFileException ignored) { | ||||||
|  | 					// file has been deleted since | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
| 			 | 			 | ||||||
| 			synchronized (stateLock) { | 			synchronized (stateLock) { | ||||||
|   | |||||||
| @@ -66,7 +66,12 @@ | |||||||
|     "1.20.3": 765, |     "1.20.3": 765, | ||||||
|     "1.20.4": 765, |     "1.20.4": 765, | ||||||
|     "1.20.5": 766, |     "1.20.5": 766, | ||||||
|     "1.20.6": 766 |     "1.20.6": 766, | ||||||
|  |     "1.21": 767, | ||||||
|  |     "1.21.1": 767, | ||||||
|  |     "1.21.2": 768, | ||||||
|  |     "1.21.3": 768, | ||||||
|  |     "1.21.4": 769 | ||||||
|   }, |   }, | ||||||
|   "versionsOfProtocol": { |   "versionsOfProtocol": { | ||||||
|     "4": [ |     "4": [ | ||||||
| @@ -217,6 +222,17 @@ | |||||||
|     "766": [ |     "766": [ | ||||||
|       "1.20.5", |       "1.20.5", | ||||||
|       "1.20.6" |       "1.20.6" | ||||||
|  |     ], | ||||||
|  |     "767": [ | ||||||
|  |       "1.21", | ||||||
|  |       "1.21.1" | ||||||
|  |     ], | ||||||
|  |     "768": [ | ||||||
|  |       "1.21.2", | ||||||
|  |       "1.21.3" | ||||||
|  |     ], | ||||||
|  |     "769": [ | ||||||
|  |       "1.21.4" | ||||||
|     ] |     ] | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @@ -23,7 +23,8 @@ public class DBConnection { | |||||||
|     public DBConnection(String host, int port, String dbname, String login, String password) { |     public DBConnection(String host, int port, String dbname, String login, String password) { | ||||||
|         this("jdbc:mysql://" + host + ":" + port + "/" + dbname |         this("jdbc:mysql://" + host + ":" + port + "/" + dbname | ||||||
|                         + "?useUnicode=true" |                         + "?useUnicode=true" | ||||||
|                         + "&useSSL=false" |                         + "&sslMode=DISABLED" | ||||||
|  |                         + "&allowPublicKeyRetrieval=true" | ||||||
|                         + "&characterEncoding=utf8" |                         + "&characterEncoding=utf8" | ||||||
|                         + "&characterSetResults=utf8" |                         + "&characterSetResults=utf8" | ||||||
|                         + "&character_set_server=utf8mb4" |                         + "&character_set_server=utf8mb4" | ||||||
|   | |||||||
| @@ -16,7 +16,7 @@ | |||||||
|     <repositories> |     <repositories> | ||||||
|         <repository> |         <repository> | ||||||
|             <id>papermc</id> |             <id>papermc</id> | ||||||
|             <url>https://papermc.io/repo/repository/maven-public/</url> |             <url>https://repo.papermc.io/repository/maven-public/</url> | ||||||
|         </repository> |         </repository> | ||||||
|  |  | ||||||
|         <!-- WorldEdit --> |         <!-- WorldEdit --> | ||||||
|   | |||||||
| @@ -16,7 +16,7 @@ | |||||||
|     <repositories> |     <repositories> | ||||||
|         <repository> |         <repository> | ||||||
|             <id>papermc</id> |             <id>papermc</id> | ||||||
|             <url>https://papermc.io/repo/repository/maven-public/</url> |             <url>https://repo.papermc.io/repository/maven-public/</url> | ||||||
|         </repository> |         </repository> | ||||||
|         <repository> |         <repository> | ||||||
|             <id>fabricmc</id> |             <id>fabricmc</id> | ||||||
| @@ -71,6 +71,12 @@ | |||||||
|             <version>${project.version}</version> |             <version>${project.version}</version> | ||||||
|         </dependency> |         </dependency> | ||||||
|  |  | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>fr.pandacube.lib</groupId> | ||||||
|  |             <artifactId>pandalib-bungee-chat</artifactId> | ||||||
|  |             <version>${project.version}</version> | ||||||
|  |         </dependency> | ||||||
|  |  | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>fr.pandacube.lib</groupId> |             <groupId>fr.pandacube.lib</groupId> | ||||||
|             <artifactId>pandalib-paper-permissions</artifactId> |             <artifactId>pandalib-paper-permissions</artifactId> | ||||||
| @@ -84,19 +90,6 @@ | |||||||
|             <artifactId>paper-api</artifactId> |             <artifactId>paper-api</artifactId> | ||||||
|             <version>${paper.version}-SNAPSHOT</version> |             <version>${paper.version}-SNAPSHOT</version> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |  | ||||||
|             <groupId>io.papermc.paper</groupId> |  | ||||||
|             <artifactId>paper-mojangapi</artifactId> |  | ||||||
|             <version>${paper.version}-SNAPSHOT</version> |  | ||||||
|         </dependency> |  | ||||||
|  |  | ||||||
|         <!-- Needed to read obfuscation mapping file. Already included in Paper --> |  | ||||||
|         <dependency> |  | ||||||
|             <groupId>net.fabricmc</groupId> |  | ||||||
|             <artifactId>mapping-io</artifactId> |  | ||||||
|             <version>0.5.0</version> |  | ||||||
|             <scope>provided</scope> |  | ||||||
|         </dependency> |  | ||||||
|     </dependencies> |     </dependencies> | ||||||
|  |  | ||||||
|     <build> |     <build> | ||||||
|   | |||||||
| @@ -5,27 +5,47 @@ import fr.pandacube.lib.paper.json.PaperJson; | |||||||
| import fr.pandacube.lib.paper.modules.PerformanceAnalysisManager; | import fr.pandacube.lib.paper.modules.PerformanceAnalysisManager; | ||||||
| import org.bukkit.plugin.Plugin; | import org.bukkit.plugin.Plugin; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Main class for pandalib-paper. | ||||||
|  |  */ | ||||||
| public class PandaLibPaper { | public class PandaLibPaper { | ||||||
| 	 | 	 | ||||||
| 	private static Plugin plugin; | 	private static Plugin plugin; | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Method to call in plugin's {@link Plugin#onLoad()} method. | ||||||
|  | 	 * @param plugin the plugin instance. | ||||||
|  | 	 */ | ||||||
| 	public static void onLoad(Plugin plugin) { | 	public static void onLoad(Plugin plugin) { | ||||||
| 		PandaLibPaper.plugin = plugin; | 		PandaLibPaper.plugin = plugin; | ||||||
| 		PaperJson.init(); | 		PaperJson.init(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Method to call in plugin's {@link Plugin#onEnable()} method. | ||||||
|  | 	 */ | ||||||
| 	public static void onEnable() { | 	public static void onEnable() { | ||||||
| 		PerformanceAnalysisManager.getInstance(); // initialize | 		PerformanceAnalysisManager.getInstance(); // initialize | ||||||
| 		ServerStopEvent.init(); | 		ServerStopEvent.init(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Method to call in plugin's {@link Plugin#onDisable()} method. | ||||||
|  | 	 */ | ||||||
| 	public static void disable() { | 	public static void disable() { | ||||||
| 		PerformanceAnalysisManager.getInstance().cancelInternalBossBar(); | 		PerformanceAnalysisManager.getInstance().deinit(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Gets the plugin instance. | ||||||
|  | 	 * @return the plugin instance provided with {@link #onLoad(Plugin)}. | ||||||
|  | 	 */ | ||||||
| 	public static Plugin getPlugin() { | 	public static Plugin getPlugin() { | ||||||
| 		return plugin; | 		return plugin; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	private PandaLibPaper() {} | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -6,14 +6,65 @@ import java.io.File; | |||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * A basic class holding configuration for {@link PaperBackupManager}. | ||||||
|  |  */ | ||||||
| @SuppressWarnings("CanBeFinal") | @SuppressWarnings("CanBeFinal") | ||||||
| public class PaperBackupConfig { | public class PaperBackupConfig { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Creates a new Paper backup config. | ||||||
|  |      */ | ||||||
|  |     public PaperBackupConfig() {} | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set to true to enable worlds backup. | ||||||
|  |      * Defaults to true. | ||||||
|  |      */ | ||||||
|     public boolean worldBackupEnabled = true; |     public boolean worldBackupEnabled = true; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set to true to enable the backup of the working directory. | ||||||
|  |      * The workdir backup will already ignore the logs directory and any world folder (folder with a level.dat file in it). | ||||||
|  |      * Defaults to true. | ||||||
|  |      */ | ||||||
|     public boolean workdirBackupEnabled = true; |     public boolean workdirBackupEnabled = true; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set to true to enable the backup of logs. | ||||||
|  |      * Defaults to true. | ||||||
|  |      */ | ||||||
|     public boolean logsBackupEnabled = true; |     public boolean logsBackupEnabled = true; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The cron-formatted scheduling of the worlds and workdir backups. | ||||||
|  |      * The default value is {@code "0 2 * * *"}, that is every day at 2am. | ||||||
|  |      */ | ||||||
|     public String scheduling = "0 2 * * *"; // cron format, here is every day at 2am |     public String scheduling = "0 2 * * *"; // cron format, here is every day at 2am | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The backup target directory. | ||||||
|  |      * Must be set (defaults to null). | ||||||
|  |      */ | ||||||
|     public File backupDirectory = null; |     public File backupDirectory = null; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The backup cleaner for the worlds backup. | ||||||
|  |      * Defaults to keep 1 backup every 3 month + the last 5 backups. | ||||||
|  |      */ | ||||||
|     public BackupCleaner worldBackupCleaner = BackupCleaner.KEEPING_1_EVERY_N_MONTH(3).merge(BackupCleaner.KEEPING_N_LAST(5)); |     public BackupCleaner worldBackupCleaner = BackupCleaner.KEEPING_1_EVERY_N_MONTH(3).merge(BackupCleaner.KEEPING_N_LAST(5)); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The backup cleaner for the workdir backup. | ||||||
|  |      * Defaults to keep 1 backup every 3 month + the last 5 backups. | ||||||
|  |      */ | ||||||
|     public BackupCleaner workdirBackupCleaner = 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)); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The list of files or directory to ignore. | ||||||
|  |      * Defaults to none. | ||||||
|  |      * The workdir backup will already ignore the logs directory and any world folder (folder with a level.dat file in it). | ||||||
|  |      */ | ||||||
|     public List<String> workdirIgnoreList = new ArrayList<>(); |     public List<String> workdirIgnoreList = new ArrayList<>(); | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -23,12 +23,19 @@ import java.util.Map; | |||||||
| import java.util.Set; | import java.util.Set; | ||||||
| import java.util.concurrent.CancellationException; | import java.util.concurrent.CancellationException; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * The backup manager for Paper servers. | ||||||
|  |  */ | ||||||
| public class PaperBackupManager extends BackupManager implements Listener { | public class PaperBackupManager extends BackupManager implements Listener { | ||||||
|  |  | ||||||
| 	private final Map<String, PaperWorldProcess> compressWorlds = new HashMap<>(); | 	private final Map<String, PaperWorldProcess> compressWorlds = new HashMap<>(); | ||||||
|  |  | ||||||
| 	PaperBackupConfig config; | 	PaperBackupConfig config; | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Instantiate a new backup manager. | ||||||
|  | 	 * @param config the configuration of the backups. | ||||||
|  | 	 */ | ||||||
| 	public PaperBackupManager(PaperBackupConfig config) { | 	public PaperBackupManager(PaperBackupConfig config) { | ||||||
| 		super(config.backupDirectory); | 		super(config.backupDirectory); | ||||||
| 		setConfig(config); | 		setConfig(config); | ||||||
| @@ -49,13 +56,17 @@ public class PaperBackupManager extends BackupManager implements Listener { | |||||||
| 		super.addProcess(process); | 		super.addProcess(process); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Updates the backups config | ||||||
|  | 	 * @param config the new config. | ||||||
|  | 	 */ | ||||||
| 	public void setConfig(PaperBackupConfig config) { | 	public void setConfig(PaperBackupConfig config) { | ||||||
| 		this.config = config; | 		this.config = config; | ||||||
| 		backupQueue.forEach(this::updateProcessConfig); | 		backupQueue.forEach(this::updateProcessConfig); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
| 	public void updateProcessConfig(BackupProcess process) { | 	private void updateProcessConfig(BackupProcess process) { | ||||||
| 		if (process instanceof PaperWorkdirProcess) { | 		if (process instanceof PaperWorkdirProcess) { | ||||||
| 			process.setEnabled(config.workdirBackupEnabled); | 			process.setEnabled(config.workdirBackupEnabled); | ||||||
| 			process.setBackupCleaner(config.workdirBackupCleaner); | 			process.setBackupCleaner(config.workdirBackupCleaner); | ||||||
| @@ -119,12 +130,12 @@ public class PaperBackupManager extends BackupManager implements Listener { | |||||||
| 	private final Set<String> dirtyForSave = new HashSet<>(); | 	private final Set<String> dirtyForSave = new HashSet<>(); | ||||||
|  |  | ||||||
| 	@EventHandler(priority = EventPriority.MONITOR) | 	@EventHandler(priority = EventPriority.MONITOR) | ||||||
| 	public void onWorldLoad(WorldLoadEvent event) { | 	void onWorldLoad(WorldLoadEvent event) { | ||||||
| 		initWorldProcess(event.getWorld().getName()); | 		initWorldProcess(event.getWorld().getName()); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@EventHandler(priority = EventPriority.MONITOR) | 	@EventHandler(priority = EventPriority.MONITOR) | ||||||
| 	public void onWorldSave(WorldSaveEvent event) { | 	void onWorldSave(WorldSaveEvent event) { | ||||||
| 		if (event.getWorld().getLoadedChunks().length > 0 | 		if (event.getWorld().getLoadedChunks().length > 0 | ||||||
| 				|| dirtyForSave.contains(event.getWorld().getName())) { | 				|| dirtyForSave.contains(event.getWorld().getName())) { | ||||||
| 			compressWorlds.get(event.getWorld().getName()).setDirtyAfterSave(); | 			compressWorlds.get(event.getWorld().getName()).setDirtyAfterSave(); | ||||||
| @@ -137,18 +148,18 @@ public class PaperBackupManager extends BackupManager implements Listener { | |||||||
|  |  | ||||||
|  |  | ||||||
| 	@EventHandler(priority = EventPriority.MONITOR) | 	@EventHandler(priority = EventPriority.MONITOR) | ||||||
| 	public void onPlayerChangeWorldEvent(PlayerChangedWorldEvent event) { | 	void onPlayerChangeWorldEvent(PlayerChangedWorldEvent event) { | ||||||
| 		dirtyForSave.add(event.getFrom().getName()); | 		dirtyForSave.add(event.getFrom().getName()); | ||||||
| 		dirtyForSave.add(event.getPlayer().getWorld().getName()); | 		dirtyForSave.add(event.getPlayer().getWorld().getName()); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@EventHandler(priority = EventPriority.MONITOR) | 	@EventHandler(priority = EventPriority.MONITOR) | ||||||
| 	public void onPlayerJoin(PlayerJoinEvent event) { | 	void onPlayerJoin(PlayerJoinEvent event) { | ||||||
| 		dirtyForSave.add(event.getPlayer().getWorld().getName()); | 		dirtyForSave.add(event.getPlayer().getWorld().getName()); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@EventHandler(priority = EventPriority.MONITOR) | 	@EventHandler(priority = EventPriority.MONITOR) | ||||||
| 	public void onPlayerQuit(PlayerQuitEvent event) { | 	void onPlayerQuit(PlayerQuitEvent event) { | ||||||
| 		dirtyForSave.add(event.getPlayer().getWorld().getName()); | 		dirtyForSave.add(event.getPlayer().getWorld().getName()); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -10,11 +10,19 @@ import net.kyori.adventure.bossbar.BossBar.Color; | |||||||
| import net.kyori.adventure.bossbar.BossBar.Overlay; | import net.kyori.adventure.bossbar.BossBar.Overlay; | ||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * A backup process with specific logic around Paper server. | ||||||
|  |  */ | ||||||
| public abstract class PaperBackupProcess extends BackupProcess { | public abstract class PaperBackupProcess extends BackupProcess { | ||||||
|  |  | ||||||
|  |  | ||||||
| 	private BossBar bossBar; | 	private BossBar bossBar; | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Instantiates a new backup process. | ||||||
|  | 	 * @param bm the associated backup manager. | ||||||
|  | 	 * @param id the process identifier. | ||||||
|  | 	 */ | ||||||
| 	protected PaperBackupProcess(PaperBackupManager bm, String id) { | 	protected PaperBackupProcess(PaperBackupManager bm, String id) { | ||||||
| 		super(bm, id); | 		super(bm, id); | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -3,8 +3,15 @@ package fr.pandacube.lib.paper.backup; | |||||||
| import java.io.File; | import java.io.File; | ||||||
| import java.util.function.BiPredicate; | import java.util.function.BiPredicate; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * A backup process with specific logic around Paper server working directory. | ||||||
|  |  */ | ||||||
| public class PaperWorkdirProcess extends PaperBackupProcess { | public class PaperWorkdirProcess extends PaperBackupProcess { | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Instantiates a new backup process for the paper server working directory. | ||||||
|  | 	 * @param bm the associated backup manager. | ||||||
|  | 	 */ | ||||||
| 	protected PaperWorkdirProcess(PaperBackupManager bm) { | 	protected PaperWorkdirProcess(PaperBackupManager bm) { | ||||||
| 		super(bm, "workdir"); | 		super(bm, "workdir"); | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -1,9 +1,9 @@ | |||||||
| package fr.pandacube.lib.paper.backup; | package fr.pandacube.lib.paper.backup; | ||||||
|  |  | ||||||
|  | import fr.pandacube.lib.chat.LegacyChatFormat; | ||||||
| import fr.pandacube.lib.paper.scheduler.SchedulerUtil; | import fr.pandacube.lib.paper.scheduler.SchedulerUtil; | ||||||
| import fr.pandacube.lib.paper.world.WorldUtil; | import fr.pandacube.lib.paper.world.WorldUtil; | ||||||
| import fr.pandacube.lib.util.log.Log; | import fr.pandacube.lib.util.log.Log; | ||||||
| import net.md_5.bungee.api.ChatColor; |  | ||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
| import org.bukkit.World; | import org.bukkit.World; | ||||||
|  |  | ||||||
| @@ -11,14 +11,22 @@ import java.io.File; | |||||||
| import java.text.DateFormat; | import java.text.DateFormat; | ||||||
| import java.util.Date; | import java.util.Date; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * A backup process with specific logic around Paper server world. | ||||||
|  |  */ | ||||||
| public class PaperWorldProcess extends PaperBackupProcess { | public class PaperWorldProcess extends PaperBackupProcess { | ||||||
| 	private final String worldName; | 	private final String worldName; | ||||||
| 	 | 	 | ||||||
| 	private boolean autoSave = true; | 	private boolean autoSave = true; | ||||||
|  |  | ||||||
| 	protected PaperWorldProcess(PaperBackupManager bm, final String n) { | 	/** | ||||||
| 		super(bm, "worlds/" + n); | 	 * Instantiates a new backup process for a world. | ||||||
| 		worldName = n; | 	 * @param bm the associated backup manager. | ||||||
|  | 	 * @param worldName the name of the world. | ||||||
|  | 	 */ | ||||||
|  | 	protected PaperWorldProcess(PaperBackupManager bm, final String worldName) { | ||||||
|  | 		super(bm, "worlds/" + worldName); | ||||||
|  | 		this.worldName = worldName; | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	private World getWorld() { | 	private World getWorld() { | ||||||
| @@ -62,11 +70,11 @@ public class PaperWorldProcess extends PaperBackupProcess { | |||||||
|  |  | ||||||
| 	public void displayNextSchedule() { | 	public void displayNextSchedule() { | ||||||
| 		if (hasNextScheduled()) { | 		if (hasNextScheduled()) { | ||||||
| 			Log.info("[Backup] " + ChatColor.GRAY + getDisplayName() + ChatColor.RESET + " is dirty. Next backup on " | 			Log.info("[Backup] " + LegacyChatFormat.GRAY + getDisplayName() + LegacyChatFormat.RESET + " is dirty. Next backup on " | ||||||
| 					+ DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG).format(new Date(getNext()))); | 					+ DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG).format(new Date(getNext()))); | ||||||
| 		} | 		} | ||||||
| 		else { | 		else { | ||||||
| 			Log.info("[Backup] " + ChatColor.GRAY + getDisplayName() + ChatColor.RESET + " is clean. Next backup not scheduled."); | 			Log.info("[Backup] " + LegacyChatFormat.GRAY + getDisplayName() + LegacyChatFormat.RESET + " is clean. Next backup not scheduled."); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -80,7 +88,7 @@ public class PaperWorldProcess extends PaperBackupProcess { | |||||||
| 	public void setDirtyAfterSave() { | 	public void setDirtyAfterSave() { | ||||||
| 		if (!isDirty()) { // don't set dirty if it is already | 		if (!isDirty()) { // don't set dirty if it is already | ||||||
| 			setDirtySinceNow(); | 			setDirtySinceNow(); | ||||||
| 			Log.info("[Backup] " + ChatColor.GRAY + getDisplayName() + ChatColor.RESET + " was saved and is now dirty. Next backup on " | 			Log.info("[Backup] " + LegacyChatFormat.GRAY + getDisplayName() + LegacyChatFormat.RESET + " was saved and is now dirty. Next backup on " | ||||||
| 					+ DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG) | 					+ DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG) | ||||||
| 					.format(new Date(getNext())) | 					.format(new Date(getNext())) | ||||||
| 			); | 			); | ||||||
|   | |||||||
| @@ -1,45 +1,53 @@ | |||||||
| package fr.pandacube.lib.paper.commands; | package fr.pandacube.lib.paper.commands; | ||||||
|  |  | ||||||
| import com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource; |  | ||||||
| import com.mojang.brigadier.CommandDispatcher; | import com.mojang.brigadier.CommandDispatcher; | ||||||
|  | import com.mojang.brigadier.arguments.ArgumentType; | ||||||
|  | import com.mojang.brigadier.builder.LiteralArgumentBuilder; | ||||||
| import com.mojang.brigadier.context.CommandContext; | import com.mojang.brigadier.context.CommandContext; | ||||||
| import com.mojang.brigadier.exceptions.CommandSyntaxException; | import com.mojang.brigadier.exceptions.CommandSyntaxException; | ||||||
| import com.mojang.brigadier.suggestion.SuggestionProvider; | import com.mojang.brigadier.suggestion.SuggestionProvider; | ||||||
|  | import com.mojang.brigadier.tree.CommandNode; | ||||||
| import com.mojang.brigadier.tree.LiteralCommandNode; | import com.mojang.brigadier.tree.LiteralCommandNode; | ||||||
| import com.mojang.brigadier.tree.RootCommandNode; | import com.mojang.brigadier.tree.RootCommandNode; | ||||||
| import fr.pandacube.lib.chat.Chat; | import fr.pandacube.lib.chat.Chat; | ||||||
| import fr.pandacube.lib.commands.BadCommandUsage; | import fr.pandacube.lib.commands.BadCommandUsage; | ||||||
| import fr.pandacube.lib.commands.BrigadierCommand; | import fr.pandacube.lib.commands.BrigadierCommand; | ||||||
| import fr.pandacube.lib.commands.SuggestionsSupplier; | import fr.pandacube.lib.commands.SuggestionsSupplier; | ||||||
| import fr.pandacube.lib.paper.reflect.PandalibPaperReflect; | import fr.pandacube.lib.paper.PandaLibPaper; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.craftbukkit.CraftServer; | import fr.pandacube.lib.paper.reflect.wrapper.craftbukkit.CraftVector; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.craftbukkit.VanillaCommandWrapper; | import fr.pandacube.lib.paper.reflect.wrapper.craftbukkit.VanillaCommandWrapper; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.Commands; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.Coordinates; | ||||||
|  | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.Vec3Argument; | ||||||
|  | import fr.pandacube.lib.paper.reflect.wrapper.paper.commands.BukkitCommandNode; | ||||||
|  | import fr.pandacube.lib.paper.reflect.wrapper.paper.commands.PluginCommandNode; | ||||||
| import fr.pandacube.lib.players.standalone.AbstractOffPlayer; | import fr.pandacube.lib.players.standalone.AbstractOffPlayer; | ||||||
| import fr.pandacube.lib.players.standalone.AbstractOnlinePlayer; | import fr.pandacube.lib.players.standalone.AbstractOnlinePlayer; | ||||||
| import fr.pandacube.lib.players.standalone.AbstractPlayerManager; | import fr.pandacube.lib.players.standalone.AbstractPlayerManager; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | import fr.pandacube.lib.reflect.Reflect; | ||||||
|  | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
| import fr.pandacube.lib.util.log.Log; | import fr.pandacube.lib.util.log.Log; | ||||||
| import io.papermc.paper.command.brigadier.CommandSourceStack; | import io.papermc.paper.command.brigadier.CommandSourceStack; | ||||||
| import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents; | import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents; | ||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
| import org.bukkit.World; | import org.bukkit.World; | ||||||
| import org.bukkit.command.Command; | import org.bukkit.command.Command; | ||||||
| import org.bukkit.command.CommandMap; |  | ||||||
| import org.bukkit.command.CommandSender; | import org.bukkit.command.CommandSender; | ||||||
| import org.bukkit.command.ConsoleCommandSender; | import org.bukkit.command.ConsoleCommandSender; | ||||||
| import org.bukkit.command.PluginCommand; | import org.bukkit.command.PluginCommand; | ||||||
| import org.bukkit.entity.Player; | import org.bukkit.entity.Player; | ||||||
| import org.bukkit.event.Listener; | import org.bukkit.event.Listener; | ||||||
| import org.bukkit.plugin.Plugin; | import org.bukkit.plugin.Plugin; | ||||||
|  | import org.bukkit.util.Vector; | ||||||
|  |  | ||||||
|  | import java.lang.reflect.InvocationTargetException; | ||||||
| import java.util.HashSet; | import java.util.HashSet; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Set; | import java.util.Set; | ||||||
| import java.util.function.Predicate; | import java.util.function.Predicate; | ||||||
| import java.util.stream.Stream; | import java.util.stream.Stream; | ||||||
|  |  | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | import static fr.pandacube.lib.reflect.wrapper.ReflectWrapper.unwrap; | ||||||
|  | import static fr.pandacube.lib.reflect.wrapper.ReflectWrapper.wrap; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Abstract class to hold a command to be integrated into a Paper server vanilla command dispatcher. |  * Abstract class to hold a command to be integrated into a Paper server vanilla command dispatcher. | ||||||
| @@ -47,65 +55,83 @@ import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | |||||||
| @SuppressWarnings("UnstableApiUsage") | @SuppressWarnings("UnstableApiUsage") | ||||||
| public abstract class PaperBrigadierCommand extends BrigadierCommand<CommandSourceStack> implements Listener { | public abstract class PaperBrigadierCommand extends BrigadierCommand<CommandSourceStack> implements Listener { | ||||||
|  |  | ||||||
|  |     private static CommandDispatcher<CommandSourceStack> vanillaPaperDispatcher = null; | ||||||
|  |  | ||||||
|     private static final Commands vanillaCommandDispatcher; |     /** | ||||||
|     private static final CommandDispatcher<BukkitBrigadierCommandSource> nmsDispatcher; |      * Gets the Brigadier dispatcher provided by paper API during {@link LifecycleEvents#COMMANDS}. | ||||||
|  |      * <p> | ||||||
|     static { |      * This Dispatcher is not the vanilla one. Instead, Paper implementation wraps the vanilla one to handle proper registration | ||||||
|         wrapEx(PandalibPaperReflect::init); |      * of commands from plugins. | ||||||
|         vanillaCommandDispatcher = ReflectWrapper.wrapTyped(Bukkit.getServer(), CraftServer.class) |      * @return the Brigadier dispatcher. | ||||||
|                 .getServer() |      */ | ||||||
|                 .vanillaCommandDispatcher(); |     public static CommandDispatcher<CommandSourceStack> getVanillaPaperDispatcher() { | ||||||
|         nmsDispatcher = vanillaCommandDispatcher.dispatcher(); |         return vanillaPaperDispatcher; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets the root node of the dispatcher from {@link #getVanillaPaperDispatcher()}. | ||||||
|  |      * @return the root node, or null if {@link #getVanillaPaperDispatcher()} is also null. | ||||||
|  |      */ | ||||||
|  |     public static RootCommandNode<CommandSourceStack> getRootNode() { | ||||||
|  |         return vanillaPaperDispatcher == null ? null : vanillaPaperDispatcher.getRoot(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private static void updateVanillaPaperDispatcher(CommandDispatcher<CommandSourceStack> newDispatcher) { | ||||||
|  |         if (vanillaPaperDispatcher == null || newDispatcher != vanillaPaperDispatcher) { | ||||||
|  |             vanillaPaperDispatcher = newDispatcher; | ||||||
|  |  | ||||||
|  |             // vanillaPaperDispatcher.getRoot() is not the real root but a wrapped root. Trying to map the fake root with the real one to trick the Paper/Brigadier (un)wrapper | ||||||
|  |             RootCommandNode<CommandSourceStack> wrappedRoot = vanillaPaperDispatcher.getRoot(); | ||||||
|  |             ReflectClass<?> apiMirrorRootNodeClass = Reflect.ofClassOfInstance(wrappedRoot); | ||||||
|  |             try { | ||||||
|  |                 RootCommandNode<?> unwrappedRoot = ((CommandDispatcher<?>) apiMirrorRootNodeClass.method("getDispatcher").invoke(wrappedRoot)).getRoot(); | ||||||
|  |  | ||||||
|  |                 Reflect.ofClass(CommandNode.class).field("unwrappedCached").setValue(wrappedRoot, unwrappedRoot); | ||||||
|  |                 Reflect.ofClass(CommandNode.class).field("wrappedCached").setValue(unwrappedRoot, wrappedRoot); | ||||||
|  |  | ||||||
|  |             } catch (InvocationTargetException|IllegalAccessException|NoSuchMethodException|NoSuchFieldException e) { | ||||||
|  |                 Log.severe("Unable to trick the Paper/Brigadier unwrapper to properly handle commands redirecting to root command node.", e); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 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 functionalities are fully | ||||||
|      * restored (so, not only the usage, but also the suggestions and the command structure sent to the client). |      * 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. |      * @param name the name of the command to restore. | ||||||
|      */ |      */ | ||||||
|     public static void restoreVanillaCommand(String name) { |     public static void restoreVanillaCommand(String name) { | ||||||
|         CommandMap bukkitCmdMap = Bukkit.getCommandMap(); |  | ||||||
|         Command bukkitCommand = bukkitCmdMap.getCommand(name); |         PandaLibPaper.getPlugin().getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS, | ||||||
|         if (bukkitCommand != null) { |                 event -> updateVanillaPaperDispatcher(event.registrar().getDispatcher())); | ||||||
|             if (VanillaCommandWrapper.REFLECT.get().isInstance(bukkitCommand)) { |  | ||||||
|                 //Log.info("Command /" + name + " is already a vanilla command."); |  | ||||||
|  |         Bukkit.getServer().getScheduler().runTask(PandaLibPaper.getPlugin(), () -> { | ||||||
|  |             if (vanillaPaperDispatcher == null) | ||||||
|  |                 return; | ||||||
|  |  | ||||||
|  |             CommandNode<CommandSourceStack> targetCommand = vanillaPaperDispatcher.getRoot().getChild("minecraft:" + name); | ||||||
|  |             if (targetCommand == null) { | ||||||
|  |                 Log.warning("There is no vanilla command '" + name + "' to restore."); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             Log.info("Removing Bukkit command /" + name + " (" + getCommandIdentity(bukkitCommand) + ")"); |  | ||||||
|             Log.warning("[1.20.6 update] Please test that the bukkit command removal is actually working."); |  | ||||||
|             bukkitCmdMap.getKnownCommands().remove(name.toLowerCase(java.util.Locale.ENGLISH)); |  | ||||||
|             bukkitCommand.unregister(bukkitCmdMap); |  | ||||||
|  |  | ||||||
|             LiteralCommandNode<BukkitBrigadierCommandSource> node = (LiteralCommandNode<BukkitBrigadierCommandSource>) getRootNode().getChild(name); |             CommandNode<CommandSourceStack> eventuallyBadCommandToReplace = vanillaPaperDispatcher.getRoot().getChild(name); | ||||||
|             Command newCommand = new VanillaCommandWrapper(vanillaCommandDispatcher, node).__getRuntimeInstance(); |             Boolean isPluginCommand = isPluginCommand(eventuallyBadCommandToReplace); | ||||||
|             bukkitCmdMap.getKnownCommands().put(name.toLowerCase(), newCommand); |             if (isPluginCommand != null && isPluginCommand) { | ||||||
|             newCommand.register(bukkitCmdMap); |                 Log.info(getCommandIdentity(eventuallyBadCommandToReplace) + " found in the dispatcher. Restoring the vanilla command."); | ||||||
|         } |                 vanillaPaperDispatcher.getRoot().getChildren().removeIf(c -> c.getName().equals(name)); | ||||||
|  |                 vanillaPaperDispatcher.getRoot().addChild(getAliasNode(targetCommand, name)); | ||||||
|  |             } | ||||||
|  |             /*else if (isPluginCommand == null) { | ||||||
|  |                 Log.info(getCommandIdentity(eventuallyBadCommandToReplace) + " found in the dispatcher. Unsure if we restore the vanilla command."); | ||||||
|  |             }*/ | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Returns the vanilla instance of the Brigadier dispatcher. |  | ||||||
|      * @return the vanilla instance of the Brigadier dispatcher. |  | ||||||
|      */ |  | ||||||
|     public static CommandDispatcher<BukkitBrigadierCommandSource> getNMSDispatcher() { |  | ||||||
|         return nmsDispatcher; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Returns the root command node of the Brigadier dispatcher. |  | ||||||
|      * @return the root command node of the Brigadier dispatcher. |  | ||||||
|      */ |  | ||||||
|     protected static RootCommandNode<BukkitBrigadierCommandSource> getRootNode() { |  | ||||||
|         return nmsDispatcher.getRoot(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -114,12 +140,15 @@ public abstract class PaperBrigadierCommand extends BrigadierCommand<CommandSour | |||||||
|     /** |     /** | ||||||
|      * The command node of this command. |      * The command node of this command. | ||||||
|      */ |      */ | ||||||
|     protected final LiteralCommandNode<CommandSourceStack> commandNode; |     protected LiteralCommandNode<CommandSourceStack> commandNode; | ||||||
|     /** |     /** | ||||||
|      * The command requested aliases. |      * The command requested aliases. | ||||||
|      */ |      */ | ||||||
|     protected final String[] aliases; |     protected final String[] aliases; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The command description. | ||||||
|  |      */ | ||||||
|     protected final String description; |     protected final String description; | ||||||
|  |  | ||||||
|     private final RegistrationPolicy registrationPolicy; |     private final RegistrationPolicy registrationPolicy; | ||||||
| @@ -135,11 +164,9 @@ public abstract class PaperBrigadierCommand extends BrigadierCommand<CommandSour | |||||||
|     public PaperBrigadierCommand(Plugin pl, RegistrationPolicy regPolicy) { |     public PaperBrigadierCommand(Plugin pl, RegistrationPolicy regPolicy) { | ||||||
|         plugin = pl; |         plugin = pl; | ||||||
|         registrationPolicy = regPolicy; |         registrationPolicy = regPolicy; | ||||||
|         commandNode = buildCommand().build(); |  | ||||||
|         String[] aliasesTmp = getAliases(); |         String[] aliasesTmp = getAliases(); | ||||||
|         aliases = aliasesTmp == null ? new String[0] : aliasesTmp; |         aliases = aliasesTmp == null ? new String[0] : aliasesTmp; | ||||||
|         description = getDescription(); |         description = getDescription(); | ||||||
|         postBuildCommand(commandNode); |  | ||||||
|         register(); |         register(); | ||||||
|         //try { |         //try { | ||||||
|         //    PandalibPaperPermissions.addPermissionMapping("minecraft.command." + commandNode.getLiteral().toLowerCase(), getTargetPermission().toLowerCase()); |         //    PandalibPaperPermissions.addPermissionMapping("minecraft.command." + commandNode.getLiteral().toLowerCase(), getTargetPermission().toLowerCase()); | ||||||
| @@ -159,38 +186,175 @@ public abstract class PaperBrigadierCommand extends BrigadierCommand<CommandSour | |||||||
|  |  | ||||||
|     private void register() { |     private void register() { | ||||||
|         plugin.getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS, event -> { |         plugin.getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS, event -> { | ||||||
|  |             updateVanillaPaperDispatcher(event.registrar().getDispatcher()); | ||||||
|  |  | ||||||
|  |             commandNode = buildCommand().build(); | ||||||
|  |             postBuildCommand(commandNode); | ||||||
|  |  | ||||||
|  |             if (vanillaPaperDispatcher.getRoot().getChild(commandNode.getName()) != null) { | ||||||
|  |                 Log.info("Command /" + commandNode.getName() + " found in the vanilla dispatcher during initial command registration. Replacing it by force."); | ||||||
|  |                 vanillaPaperDispatcher.getRoot().getChildren().removeIf(c -> c.getName().equals(commandNode.getName())); | ||||||
|  |             } | ||||||
|  |  | ||||||
|             registeredAliases = new HashSet<>(event.registrar().register(commandNode, description, List.of(aliases))); |             registeredAliases = new HashSet<>(event.registrar().register(commandNode, description, List.of(aliases))); | ||||||
|  |             doPostRegistrationFixes(); | ||||||
|  |  | ||||||
|             if (registrationPolicy == RegistrationPolicy.ALL) { |             if (registrationPolicy == RegistrationPolicy.ALL) { | ||||||
|                 // enforce registration of aliases |                 // enforce registration of aliases | ||||||
|                 for (String alias : aliases) { |                 for (String alias : aliases) { | ||||||
|                     if (!registeredAliases.contains(alias)) |                     if (!registeredAliases.contains(alias)) { | ||||||
|                         registeredAliases.addAll(event.registrar().register(getAliasNode(alias), description)); |                         Log.info("Command /" + commandNode.getName() + ": forcing registration of alias " + alias); | ||||||
|  |                         registeredAliases.addAll(event.registrar().register(getAliasNode(commandNode, alias), description)); | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |             Bukkit.getServer().getScheduler().runTask(plugin, () -> { | ||||||
|  |                 if (vanillaPaperDispatcher == null) | ||||||
|  |                     return; | ||||||
|  |  | ||||||
|  |                 Set<String> forceRegistrationAgain = new HashSet<>(); | ||||||
|  |                 forceRegistrationAgain.add(commandNode.getName()); | ||||||
|  |                 if (registrationPolicy == RegistrationPolicy.ALL) | ||||||
|  |                     forceRegistrationAgain.addAll(List.of(aliases)); | ||||||
|  |  | ||||||
|  |                 for (String aliasToForce : forceRegistrationAgain) { | ||||||
|  |                     CommandNode<CommandSourceStack> actualNode = vanillaPaperDispatcher.getRoot().getChild(aliasToForce); | ||||||
|  |                     if (actualNode != null) { | ||||||
|  |                         //Log.info("Forcing registration of alias /" + aliasToForce + " for command /" + commandNode.getName() + ": replacing " + getCommandIdentity(actualNode) + "?"); | ||||||
|  |                         if (PluginCommandNode.REFLECT.get().isInstance(actualNode)) { | ||||||
|  |                             PluginCommandNode pcn = wrap(actualNode, PluginCommandNode.class); | ||||||
|  |                             if (pcn.getPlugin().equals(plugin)) | ||||||
|  |                                 return; | ||||||
|  |                         } | ||||||
|  |                         else if (BukkitCommandNode.REFLECT.get().isInstance(actualNode)) { | ||||||
|  |                             BukkitCommandNode bcn = wrap(actualNode, BukkitCommandNode.class); | ||||||
|  |                             if (bcn.getBukkitCommand() instanceof PluginCommand pc && pc.getPlugin().equals(plugin)) | ||||||
|  |                                 return; | ||||||
|  |                         } | ||||||
|  |                         vanillaPaperDispatcher.getRoot().getChildren().removeIf(c -> c.getName().equals(aliasToForce)); | ||||||
|  |                     } | ||||||
|  |                 /*else { | ||||||
|  |                     Log.info("Forcing registration of alias /" + aliasToForce + " for command /" + commandNode.getName() + ": no command found for alias. Adding alias."); | ||||||
|  |                 }*/ | ||||||
|  |                     LiteralCommandNode<CommandSourceStack> newPCN = unwrap(new PluginCommandNode(aliasToForce, plugin.getPluginMeta(), commandNode, description)); | ||||||
|  |                     vanillaPaperDispatcher.getRoot().addChild(newPCN); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |  | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     private LiteralCommandNode<CommandSourceStack> getAliasNode(String alias) { |  | ||||||
|          return literal(alias) |  | ||||||
|  |     private void doPostRegistrationFixes() { | ||||||
|  |         postRegistrationFixNode(new HashSet<>(), commandNode); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void postRegistrationFixNode(Set<CommandNode<CommandSourceStack>> fixedNodes, CommandNode<CommandSourceStack> originalNode) { | ||||||
|  |         if (originalNode instanceof RootCommandNode) | ||||||
|  |             return; | ||||||
|  |         if (fixedNodes.contains(originalNode)) | ||||||
|  |             return; | ||||||
|  |         fixedNodes.add(originalNode); | ||||||
|  |         if (originalNode.getRedirect() != null) { | ||||||
|  |             try { | ||||||
|  |                 @SuppressWarnings("rawtypes") | ||||||
|  |                 ReflectClass<CommandNode> cmdNodeClass = Reflect.ofClass(CommandNode.class); | ||||||
|  |                 @SuppressWarnings("unchecked") | ||||||
|  |                 CommandNode<CommandSourceStack> unwrappedNode = (CommandNode<CommandSourceStack>) cmdNodeClass.field("unwrappedCached").getValue(originalNode); | ||||||
|  |                 if (unwrappedNode != null) { | ||||||
|  |                     cmdNodeClass.field("modifier").setValue(unwrappedNode, cmdNodeClass.field("modifier").getValue(originalNode)); | ||||||
|  |                     cmdNodeClass.field("forks").setValue(unwrappedNode, cmdNodeClass.field("forks").getValue(originalNode)); | ||||||
|  |                 } | ||||||
|  |             } catch (IllegalAccessException | NoSuchFieldException e) { | ||||||
|  |                 throw new RuntimeException(e); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             postRegistrationFixNode(fixedNodes, originalNode.getRedirect()); | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |             try { | ||||||
|  |                 for (CommandNode<CommandSourceStack> child : originalNode.getChildren()) | ||||||
|  |                     postRegistrationFixNode(fixedNodes, child); | ||||||
|  |             } catch (UnsupportedOperationException ignored) { | ||||||
|  |                 // in case getChildren is not possible (vanilla commands are wrapped by Paper API) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     private static LiteralCommandNode<CommandSourceStack> getAliasNode(CommandNode<CommandSourceStack> commandNode, String alias) { | ||||||
|  |          return LiteralArgumentBuilder.<CommandSourceStack>literal(alias) | ||||||
|                 .requires(commandNode.getRequirement()) |                 .requires(commandNode.getRequirement()) | ||||||
|                 .executes(commandNode.getCommand()) |                 .executes(commandNode.getCommand()) | ||||||
|                 .redirect(commandNode) |                 .redirect(commandNode) | ||||||
|                 .build(); |                 .build(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private static String getCommandIdentity(Command bukkitCmd) { |     private static String getCommandIdentity(CommandNode<CommandSourceStack> command) { | ||||||
|         if (bukkitCmd instanceof PluginCommand cmd) { |         if (PluginCommandNode.REFLECT.get().isInstance(command)) { | ||||||
|             return "Bukkit command: /" + cmd.getName() + " from plugin " + cmd.getPlugin().getName(); |             PluginCommandNode wrappedPCN = wrap(command, PluginCommandNode.class); | ||||||
|  |             return "Node /" + command.getName() + " from plugin " + wrappedPCN.getPlugin().getName(); | ||||||
|         } |         } | ||||||
|         else if (VanillaCommandWrapper.REFLECT.get().isInstance(bukkitCmd)) { |         else if (BukkitCommandNode.REFLECT.get().isInstance(command)) { | ||||||
|             return "Vanilla command: /" + bukkitCmd.getName(); |             BukkitCommandNode wrappedBCN = wrap(command, BukkitCommandNode.class); | ||||||
|  |             Command bukkitCmd = wrappedBCN.getBukkitCommand(); | ||||||
|  |             if (bukkitCmd instanceof PluginCommand cmd) { | ||||||
|  |                 return "Node /" + command.getName() + " wrapping Bukkit command /" + bukkitCmd.getName() + " from plugin " + cmd.getPlugin().getName(); | ||||||
|  |             } | ||||||
|  |             else if (VanillaCommandWrapper.REFLECT.get().isInstance(bukkitCmd)) { | ||||||
|  |                 VanillaCommandWrapper vcw = wrap(bukkitCmd, VanillaCommandWrapper.class); | ||||||
|  |                 CommandNode<CommandSourceStack> vanillaCmd = vcw.vanillaCommand(); | ||||||
|  |                 if (vanillaCmd != command) | ||||||
|  |                     return "Node /" + command.getName() + " wrapping non-plugin command /" + bukkitCmd.getName() + " wrapping: " + getCommandIdentity(vcw.vanillaCommand()); | ||||||
|  |                 else | ||||||
|  |                     return "Node /" + command.getName() + " wrapping non-plugin command /" + bukkitCmd.getName() + " wrapping back the node (risk of StackOverflow?)"; | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |                 return "Node /" + command.getName() + " wrapping " + bukkitCmd.getClass().getName() + " /" + bukkitCmd.getName(); | ||||||
|         } |         } | ||||||
|         else |         else { | ||||||
|             return bukkitCmd.getClass().getName() + ": /" + bukkitCmd.getName(); |             return "Node /" + command.getName() + " (unspecific)"; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     private static Boolean isPluginCommand(CommandNode<CommandSourceStack> command) { | ||||||
|  |         if (PluginCommandNode.REFLECT.get().isInstance(command)) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         else if (BukkitCommandNode.REFLECT.get().isInstance(command)) { | ||||||
|  |             BukkitCommandNode wrappedBCN = wrap(command, BukkitCommandNode.class); | ||||||
|  |             Command bukkitCmd = wrappedBCN.getBukkitCommand(); | ||||||
|  |             if (bukkitCmd instanceof PluginCommand) { | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |             else if (VanillaCommandWrapper.REFLECT.get().isInstance(bukkitCmd)) { | ||||||
|  |                 VanillaCommandWrapper vcw = wrap(bukkitCmd, VanillaCommandWrapper.class); | ||||||
|  |                 CommandNode<CommandSourceStack> vanillaCmd = vcw.vanillaCommand(); | ||||||
|  |                 if (vanillaCmd != command) | ||||||
|  |                     return isPluginCommand(vcw.vanillaCommand()); | ||||||
|  |                 else | ||||||
|  |                     return false; | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |                 return null; | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets the aliases that are actually registered in the server. | ||||||
|  |      * @return the actually registered aliases. | ||||||
|  |      */ | ||||||
|  |     protected Set<String> getRegisteredAliases() { | ||||||
|  |         return Set.copyOf(registeredAliases); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -235,12 +399,15 @@ public abstract class PaperBrigadierCommand extends BrigadierCommand<CommandSour | |||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|     public boolean isConsole(CommandSourceStack wrapper) { |     public boolean isConsole(CommandSourceStack wrapper) { | ||||||
|         return isConsole(getCommandSender(wrapper)); |         return isConsole(getCommandSender(wrapper)); | ||||||
|     } |     } | ||||||
|  |     @Override | ||||||
|     public boolean isPlayer(CommandSourceStack wrapper) { |     public boolean isPlayer(CommandSourceStack wrapper) { | ||||||
|         return isPlayer(getCommandSender(wrapper)); |         return isPlayer(getCommandSender(wrapper)); | ||||||
|     } |     } | ||||||
|  |     @Override | ||||||
|     public Predicate<CommandSourceStack> hasPermission(String permission) { |     public Predicate<CommandSourceStack> hasPermission(String permission) { | ||||||
|         return wrapper -> getCommandSender(wrapper).hasPermission(permission); |         return wrapper -> getCommandSender(wrapper).hasPermission(permission); | ||||||
|     } |     } | ||||||
| @@ -364,6 +531,30 @@ public abstract class PaperBrigadierCommand extends BrigadierCommand<CommandSour | |||||||
|      * Minecraft's argument type |      * Minecraft's argument type | ||||||
|      */ |      */ | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Creates a new instance of the Brigadier argument type {@code minecraft:vec3}. | ||||||
|  |      * @return the {@code minecraft:vec3} argument type. | ||||||
|  |      */ | ||||||
|  |     public static ArgumentType<Object> argumentMinecraftVec3() { | ||||||
|  |         return Vec3Argument.vec3(true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 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. | ||||||
|  |      * @return the value of the argument. | ||||||
|  |      */ | ||||||
|  |     public Vector tryGetMinecraftVec3Argument(CommandContext<CommandSourceStack> context, String argument, | ||||||
|  |                                               Vector deflt) { | ||||||
|  |         return tryGetArgument(context, argument, Coordinates.REFLECT.get(), | ||||||
|  |                 nmsCoordinate -> CraftVector.toBukkit( | ||||||
|  |                         wrap(nmsCoordinate, Coordinates.class).getPosition(context.getSource()) | ||||||
|  |                 ), | ||||||
|  |                 deflt); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -10,28 +10,38 @@ import org.bukkit.event.server.PluginDisableEvent; | |||||||
| import org.bukkit.event.server.ServerEvent; | import org.bukkit.event.server.ServerEvent; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Fired at the beginning of the server stop process. | ||||||
|  |  * More specifically, this event is called when the first plugin is disabling ({@link PluginDisableEvent}) while | ||||||
|  |  * {@link Bukkit#isStopping()} returns true. | ||||||
|  |  * <p> | ||||||
|  |  * This event can be useful when a plugin want to execute stuff on server stop as soon as possible in the process, | ||||||
|  |  * but not when the plugin itself is disabling (because some part of the Bukkit API is not usable at that moment). | ||||||
|  |  */ | ||||||
| public class ServerStopEvent extends ServerEvent { | public class ServerStopEvent extends ServerEvent { | ||||||
|  |  | ||||||
|  |  | ||||||
|     private static final HandlerList handlers = new HandlerList(); |     private static final HandlerList handlers = new HandlerList(); | ||||||
|  |  | ||||||
|     @NotNull |     /** | ||||||
|     @Override |      * Gets the handler list of the event. | ||||||
|     public HandlerList getHandlers() { |      * @return the handler list of the event. | ||||||
|         return handlers; |      */ | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @NotNull |     @NotNull | ||||||
|     public static HandlerList getHandlerList() { |     public static HandlerList getHandlerList() { | ||||||
|         return handlers; |         return handlers; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     private static boolean hasTriggered = false; |     private static boolean hasTriggered = false; | ||||||
|  |     private static boolean isInit = false; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Register the event used to detect the server stop. | ||||||
|  |      */ | ||||||
|     public static void init() { |     public static void init() { | ||||||
|  |         if (isInit) | ||||||
|  |             return; | ||||||
|  |  | ||||||
|         BukkitEvent.register(new Listener() { |         BukkitEvent.register(new Listener() { | ||||||
|  |  | ||||||
|             @EventHandler(priority = EventPriority.LOWEST) |             @EventHandler(priority = EventPriority.LOWEST) | ||||||
| @@ -45,7 +55,25 @@ public class ServerStopEvent extends ServerEvent { | |||||||
|             } |             } | ||||||
|  |  | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|  |         isInit = true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     private ServerStopEvent() {} | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     @NotNull | ||||||
|  |     @Override | ||||||
|  |     public HandlerList getHandlers() { | ||||||
|  |         return handlers; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -63,6 +63,7 @@ public class DirectionalVector { | |||||||
|      * contained in the provided {@link Location}. |      * contained in the provided {@link Location}. | ||||||
|      * {@link Location#getYaw()} and {@link Location#getPitch()} values are automatically |      * {@link Location#getYaw()} and {@link Location#getPitch()} values are automatically | ||||||
|      * converted to conform {@link #yaw} and {@link #pitch} specification. |      * converted to conform {@link #yaw} and {@link #pitch} specification. | ||||||
|  |      * @param l the location. | ||||||
|      */ |      */ | ||||||
|     public DirectionalVector(Location l) { |     public DirectionalVector(Location l) { | ||||||
|         this( |         this( | ||||||
| @@ -79,6 +80,7 @@ public class DirectionalVector { | |||||||
|  |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|  |      * Creates a new {@link DirectionalVector} from a simple {@link Vector}. | ||||||
|      * @param v the vector representing the direction. If v.getX() and v.getZ() are 0, |      * @param v the vector representing the direction. If v.getX() and v.getZ() are 0, | ||||||
|      *          the yaw will be 0. This may have inconsistency if the vector is calculated |      *          the yaw will be 0. This may have inconsistency if the vector is calculated | ||||||
|      *          from a {@link Location}'s yaw and pitch. In this case, prefer using |      *          from a {@link Location}'s yaw and pitch. In this case, prefer using | ||||||
| @@ -126,7 +128,10 @@ public class DirectionalVector { | |||||||
|  |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets a Vector using the internal X, Y and Z values, that is a simple directional 3D vector. | ||||||
|  |      * @return this vector as a simple 3D {@link Vector}. | ||||||
|  |      */ | ||||||
|     public Vector toVector() { |     public Vector toVector() { | ||||||
|         return new Vector(x, y, z); |         return new Vector(x, y, z); | ||||||
|     } |     } | ||||||
| @@ -135,7 +140,8 @@ public class DirectionalVector { | |||||||
|     /** |     /** | ||||||
|      * Set the yaw and the pitch of the provided {@link Location} |      * Set the yaw and the pitch of the provided {@link Location} | ||||||
|      * with the values inside the current {@link DirectionalVector} |      * with the values inside the current {@link DirectionalVector} | ||||||
|      * after conversion of these values |      * after conversion of these values. | ||||||
|  |      * @param l the location. | ||||||
|      */ |      */ | ||||||
|     public void putIntoLocation(Location l) { |     public void putIntoLocation(Location l) { | ||||||
|         /*              std   : -PI/2         : <0 ? +2PI : MC |         /*              std   : -PI/2         : <0 ? +2PI : MC | ||||||
| @@ -148,7 +154,10 @@ public class DirectionalVector { | |||||||
|         l.setPitch((float) Math.toDegrees(-pitch)); |         l.setPitch((float) Math.toDegrees(-pitch)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets the vector pointing to the opposite direction. | ||||||
|  |      * @return the opposite vector. | ||||||
|  |      */ | ||||||
|     public DirectionalVector getOpposite() { |     public DirectionalVector getOpposite() { | ||||||
|         return new DirectionalVector( |         return new DirectionalVector( | ||||||
|                 -x, |                 -x, | ||||||
| @@ -163,6 +172,7 @@ public class DirectionalVector { | |||||||
|      * If the current direction is the player face direction, |      * If the current direction is the player face direction, | ||||||
|      * this method return the direction of the back of the head. |      * this method return the direction of the back of the head. | ||||||
|      * This is an alias of {@link #getOpposite()} |      * This is an alias of {@link #getOpposite()} | ||||||
|  |      * @return the opposite of this vector. | ||||||
|      */ |      */ | ||||||
|     public DirectionalVector getBackDirection() { |     public DirectionalVector getBackDirection() { | ||||||
|         return getOpposite(); |         return getOpposite(); | ||||||
| @@ -171,6 +181,7 @@ public class DirectionalVector { | |||||||
|     /** |     /** | ||||||
|      * If the current direction is the player face direction, |      * If the current direction is the player face direction, | ||||||
|      * this method return the direction of the bottom of the head. |      * this method return the direction of the bottom of the head. | ||||||
|  |      * @return the vector pointing on the bottom, as if this vector was the front orientation of a player head. | ||||||
|      */ |      */ | ||||||
|     public DirectionalVector getBottomDirection() { |     public DirectionalVector getBottomDirection() { | ||||||
|         return new DirectionalVector( |         return new DirectionalVector( | ||||||
| @@ -182,6 +193,7 @@ public class DirectionalVector { | |||||||
|     /** |     /** | ||||||
|      * If the current direction is the player face direction, |      * If the current direction is the player face direction, | ||||||
|      * this method return the direction of the top of the head. |      * this method return the direction of the top of the head. | ||||||
|  |      * @return the vector pointing on the top, as if this vector was the front orientation of a player head. | ||||||
|      */ |      */ | ||||||
|     public DirectionalVector getTopDirection() { |     public DirectionalVector getTopDirection() { | ||||||
|         return new DirectionalVector( |         return new DirectionalVector( | ||||||
| @@ -194,6 +206,7 @@ public class DirectionalVector { | |||||||
|     /** |     /** | ||||||
|      * If the current direction is the player face direction, |      * If the current direction is the player face direction, | ||||||
|      * this method return the direction of the left of the head. |      * this method return the direction of the left of the head. | ||||||
|  |      * @return the vector pointing on the left, as if this vector was the front orientation of a player head. | ||||||
|      */ |      */ | ||||||
|     public DirectionalVector getLeftDirection() { |     public DirectionalVector getLeftDirection() { | ||||||
|         return new DirectionalVector( |         return new DirectionalVector( | ||||||
| @@ -206,6 +219,7 @@ public class DirectionalVector { | |||||||
|     /** |     /** | ||||||
|      * If the current direction is the player face direction, |      * If the current direction is the player face direction, | ||||||
|      * this method return the direction of the right of the head. |      * this method return the direction of the right of the head. | ||||||
|  |      * @return the vector pointing on the right, as if this vector was the front orientation of a player head. | ||||||
|      */ |      */ | ||||||
|     public DirectionalVector getRightDirection() { |     public DirectionalVector getRightDirection() { | ||||||
|         return new DirectionalVector( |         return new DirectionalVector( | ||||||
|   | |||||||
| @@ -2,24 +2,29 @@ package fr.pandacube.lib.paper.geometry; | |||||||
|  |  | ||||||
| import org.bukkit.Location; | import org.bukkit.Location; | ||||||
| import org.bukkit.entity.Player; | import org.bukkit.entity.Player; | ||||||
|  | import org.bukkit.util.BoundingBox; | ||||||
|  | import org.bukkit.util.RayTraceResult; | ||||||
| import org.bukkit.util.Vector; | import org.bukkit.util.Vector; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Utility class related to geometry and Minecraft. | ||||||
|  |  */ | ||||||
| public class GeometryUtil { | public class GeometryUtil { | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Value equal to <code>{@link Math#PI}</code>. | 	 * Value equal to <code>{@link Math#PI}</code>. | ||||||
| 	 */ | 	 */ | ||||||
| 	public static final double PI   = Math.PI; | 	static final double PI   = Math.PI; | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Value equal to <code>{@link Math#PI} / 2</code>. | 	 * Value equal to <code>{@link Math#PI} / 2</code>. | ||||||
| 	 */ | 	 */ | ||||||
| 	public static final double PId2 = PI/2; | 	static final double PId2 = PI/2; | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Value equal to <code>{@link Math#PI} * 2</code>. | 	 * Value equal to <code>{@link Math#PI} * 2</code>. | ||||||
| 	 */ | 	 */ | ||||||
| 	public static final double PIx2 = PI*2; | 	static final double PIx2 = PI*2; | ||||||
| 	 | 	 | ||||||
| 	 | 	 | ||||||
| 	 | 	 | ||||||
| @@ -55,9 +60,21 @@ public class GeometryUtil { | |||||||
| 	 * Value provided by net.minecraft.world.entity.player.Player#getStandingEyeHeight | 	 * Value provided by net.minecraft.world.entity.player.Player#getStandingEyeHeight | ||||||
| 	 */ | 	 */ | ||||||
| 	public static final double PLAYER_EYE_HEIGHT_SNEAK = 1.27; | 	public static final double PLAYER_EYE_HEIGHT_SNEAK = 1.27; | ||||||
|  | 	/** | ||||||
|  | 	 * The size of a skin pixel. | ||||||
|  | 	 */ | ||||||
| 	public static final double PLAYER_SKIN_PIXEL_SIZE = PLAYER_SKIN_HEIGHT / 32; | 	public static final double PLAYER_SKIN_PIXEL_SIZE = PLAYER_SKIN_HEIGHT / 32; | ||||||
|  | 	/** | ||||||
|  | 	 * The height of the center of rotation of the head, that is the distance between neck and the player's foot. | ||||||
|  | 	 */ | ||||||
| 	public static final double PLAYER_HEAD_ROTATION_HEIGHT = PLAYER_SKIN_PIXEL_SIZE * 24; | 	public static final double PLAYER_HEAD_ROTATION_HEIGHT = PLAYER_SKIN_PIXEL_SIZE * 24; | ||||||
|  | 	/** | ||||||
|  | 	 * The height of the center of rotation of the head, that is the distance between neck and the player's foot, but when the player is sneaking. | ||||||
|  | 	 */ | ||||||
| 	public static final double PLAYER_HEAD_ROTATION_HEIGHT_SNEAK = PLAYER_HEAD_ROTATION_HEIGHT - (PLAYER_SKIN_HEIGHT - PLAYER_SKIN_HEIGHT_SNEAK); | 	public static final double PLAYER_HEAD_ROTATION_HEIGHT_SNEAK = PLAYER_HEAD_ROTATION_HEIGHT - (PLAYER_SKIN_HEIGHT - PLAYER_SKIN_HEIGHT_SNEAK); | ||||||
|  | 	/** | ||||||
|  | 	 * The size of the first layer of the players head. | ||||||
|  | 	 */ | ||||||
| 	public static final double PLAYER_HEAD_SIZE = PLAYER_SKIN_PIXEL_SIZE * 8; | 	public static final double PLAYER_HEAD_SIZE = PLAYER_SKIN_PIXEL_SIZE * 8; | ||||||
| 	 | 	 | ||||||
| 	 | 	 | ||||||
| @@ -72,11 +89,10 @@ public class GeometryUtil { | |||||||
| 	 | 	 | ||||||
| 	 | 	 | ||||||
| 	 | 	 | ||||||
| 	 |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Get the {@link Location}s of the 8 vertex of the player head<br/> | 	 * Get the {@link Location}s of the 8 vertex of the player head<br/> | ||||||
| 	 * This method only work if the player is standing up | 	 * This method only work if the player is standing up | ||||||
| 	 * (not dead, not gliding, not sleeping). | 	 * (not dead, not gliding, not sleeping, not swimming). | ||||||
| 	 * @param playerLocation the location of the player, generally provided by {@link Player#getLocation()} | 	 * @param playerLocation the location of the player, generally provided by {@link Player#getLocation()} | ||||||
| 	 * @param isSneaking if the player is sneaking. Generally {@link Player#isSneaking()} | 	 * @param isSneaking if the player is sneaking. Generally {@link Player#isSneaking()} | ||||||
| 	 * @return an array of 8 {@link Location}s with x, y, and z values filled (yaw and pitch are ignored). | 	 * @return an array of 8 {@link Location}s with x, y, and z values filled (yaw and pitch are ignored). | ||||||
| @@ -129,27 +145,22 @@ public class GeometryUtil { | |||||||
| 	/** | 	/** | ||||||
| 	 * Check if the path from <i>start</i> location to <i>end</i> pass through | 	 * Check if the path from <i>start</i> location to <i>end</i> pass through | ||||||
| 	 * the axis aligned bounding box defined by <i>min</i> and <i>max</i>. | 	 * the axis aligned bounding box defined by <i>min</i> and <i>max</i>. | ||||||
|  | 	 * @param start the start of the path. | ||||||
|  | 	 * @param end the end of the path. | ||||||
|  | 	 * @param min the min of the bounding box. | ||||||
|  | 	 * @param max the max of the bounding box. | ||||||
|  | 	 * @return true if the path intersects the bounding box. | ||||||
|  | 	 * @deprecated use {@link BoundingBox#rayTrace(Vector, Vector, double)} instead. | ||||||
| 	 */ | 	 */ | ||||||
|  | 	@Deprecated | ||||||
|     public static boolean hasIntersection(Vector start, Vector end, Vector min, Vector max) { |     public static boolean hasIntersection(Vector start, Vector end, Vector min, Vector max) { | ||||||
|         final double epsilon = 0.0001f; |         RayTraceResult res = BoundingBox.of(min, max).rayTrace(start, end.clone().subtract(start), end.distance(start)); | ||||||
|   | 		return res != null; | ||||||
|         Vector d = end.clone().subtract(start).multiply(0.5); |  | ||||||
|         Vector e = max.clone().subtract(min).multiply(0.5); |  | ||||||
|         Vector c = start.clone().add(d).subtract(min.clone().add(max).multiply(0.5)); |  | ||||||
|         Vector ad = d.clone(); |  | ||||||
|         ad.setX(Math.abs(ad.getX())); |  | ||||||
|         ad.setY(Math.abs(ad.getY())); |  | ||||||
|         ad.setZ(Math.abs(ad.getZ())); |  | ||||||
|  |  | ||||||
|         return !( |  | ||||||
| 				Math.abs(c.getX()) > e.getX() + ad.getX() |  | ||||||
| 				|| Math.abs(c.getY()) > e.getY() + ad.getY() |  | ||||||
| 				|| Math.abs(c.getZ()) > e.getX() + ad.getZ() |  | ||||||
| 				|| Math.abs(d.getY() * c.getZ() - d.getZ() * c.getY()) > e.getY() * ad.getZ() + e.getZ() * ad.getY() + epsilon |  | ||||||
| 				|| Math.abs(d.getZ() * c.getX() - d.getX() * c.getZ()) > e.getZ() * ad.getX() + e.getX() * ad.getZ() + epsilon |  | ||||||
| 				|| Math.abs(d.getX() * c.getY() - d.getY() * c.getX()) > e.getX() * ad.getY() + e.getY() * ad.getX() + epsilon |  | ||||||
| 		); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	private GeometryUtil() {} | ||||||
|  |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,11 +2,10 @@ package fr.pandacube.lib.paper.geometry.blocks; | |||||||
|  |  | ||||||
| import fr.pandacube.lib.util.RandomUtil; | import fr.pandacube.lib.util.RandomUtil; | ||||||
| import org.bukkit.Location; | import org.bukkit.Location; | ||||||
| import org.bukkit.World; |  | ||||||
| import org.bukkit.block.Block; |  | ||||||
| import org.bukkit.util.BlockVector; | import org.bukkit.util.BlockVector; | ||||||
| import org.bukkit.util.BoundingBox; | import org.bukkit.util.BoundingBox; | ||||||
| import org.bukkit.util.Vector; | import org.bukkit.util.Vector; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  |  | ||||||
| import java.util.Iterator; | import java.util.Iterator; | ||||||
|  |  | ||||||
| @@ -30,10 +29,19 @@ public class AABBBlock implements BlockSet, Cloneable { | |||||||
| 		volume = original.volume; | 		volume = original.volume; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Construct a {@link AABBBlock} based on the two provided Bukkit's {@link Vector}. | ||||||
|  | 	 * @param p1 the first vector. | ||||||
|  | 	 * @param p2 the second vector. | ||||||
|  | 	 */ | ||||||
| 	public AABBBlock(Vector p1, Vector p2) { | 	public AABBBlock(Vector p1, Vector p2) { | ||||||
| 		this(p1.getBlockX(), p1.getBlockY(), p1.getBlockZ(), p2.getBlockX(), p2.getBlockY(), p2.getBlockZ()); | 		this(p1.getBlockX(), p1.getBlockY(), p1.getBlockZ(), p2.getBlockX(), p2.getBlockY(), p2.getBlockZ()); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Construct a {@link AABBBlock} based on the provided Bukkit's {@link BoundingBox}. | ||||||
|  | 	 * @param bb the bounding box. | ||||||
|  | 	 */ | ||||||
| 	public AABBBlock(BoundingBox bb) { | 	public AABBBlock(BoundingBox bb) { | ||||||
| 		pos1 = bb.getMin(); | 		pos1 = bb.getMin(); | ||||||
| 		pos2 = bb.getMax(); | 		pos2 = bb.getMax(); | ||||||
| @@ -42,14 +50,34 @@ public class AABBBlock implements BlockSet, Cloneable { | |||||||
| 		bukkitBoundingBox = bb; | 		bukkitBoundingBox = bb; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Construct a {@link AABBBlock} based on the two provided Bukkit's {@link Location}. | ||||||
|  | 	 * The worlds defined in the provided locations are ignored. | ||||||
|  | 	 * @param l1 the first location. | ||||||
|  | 	 * @param l2 the second location. | ||||||
|  | 	 */ | ||||||
| 	public AABBBlock(Location l1, Location l2) { | 	public AABBBlock(Location l1, Location l2) { | ||||||
| 		this(l1.getBlockX(), l1.getBlockY(), l1.getBlockZ(), l2.getBlockX(), l2.getBlockY(), l2.getBlockZ()); | 		this(l1.getBlockX(), l1.getBlockY(), l1.getBlockZ(), l2.getBlockX(), l2.getBlockY(), l2.getBlockZ()); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Construct a {@link AABBBlock} based on the two provided Bukkit's {@link BlockVector}. | ||||||
|  | 	 * @param l1 the first block vector. | ||||||
|  | 	 * @param l2 the second block vector. | ||||||
|  | 	 */ | ||||||
| 	public AABBBlock(BlockVector l1, BlockVector l2) { | 	public AABBBlock(BlockVector l1, BlockVector l2) { | ||||||
| 		this(l1.getBlockX(), l1.getBlockY(), l1.getBlockZ(), l2.getBlockX(), l2.getBlockY(), l2.getBlockZ()); | 		this(l1.getBlockX(), l1.getBlockY(), l1.getBlockZ(), l2.getBlockX(), l2.getBlockY(), l2.getBlockZ()); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Construct a {@link AABBBlock} based on the individual coordinates of the 2 vectors. | ||||||
|  | 	 * @param p1x the x value of the first vector. | ||||||
|  | 	 * @param p1y the y value of the first vector. | ||||||
|  | 	 * @param p1z the z value of the first vector. | ||||||
|  | 	 * @param p2x the x value of the second vector. | ||||||
|  | 	 * @param p2y the y value of the second vector. | ||||||
|  | 	 * @param p2z the z value of the second vector. | ||||||
|  | 	 */ | ||||||
| 	public AABBBlock(int p1x, int p1y, int p1z, int p2x, int p2y, int p2z) { | 	public AABBBlock(int p1x, int p1y, int p1z, int p2x, int p2y, int p2z) { | ||||||
| 		/* | 		/* | ||||||
| 		 * Prends les points extérieurs permettant de former un bounding box englobant | 		 * Prends les points extérieurs permettant de former un bounding box englobant | ||||||
| @@ -74,22 +102,45 @@ public class AABBBlock implements BlockSet, Cloneable { | |||||||
| 		return this; | 		return this; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Gets the value of the "minimum" {@link Vector}, that is the vector with the lowest coordinates that is inside this bounding box. | ||||||
|  | 	 * @return the minimum vector. | ||||||
|  | 	 */ | ||||||
| 	public Vector getMin() { | 	public Vector getMin() { | ||||||
| 		return pos1.clone(); | 		return pos1.clone(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Gets the value of the "maximum" {@link Vector}, that is the vector with the highest coordinates that is inside this bounding box. | ||||||
|  | 	 * @return the maximum vector. | ||||||
|  | 	 */ | ||||||
| 	public Vector getMax() { | 	public Vector getMax() { | ||||||
| 		return pos2.clone(); | 		return pos2.clone(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Gets the {@link BlockVector} with the lowest coordinates in this bounding box. | ||||||
|  | 	 * @return the minimum block vector. | ||||||
|  | 	 */ | ||||||
| 	public BlockVector getMinBlock() { | 	public BlockVector getMinBlock() { | ||||||
| 		return pos1.toBlockVector(); | 		return pos1.toBlockVector(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Gets the {@link BlockVector} with the highest coordinates in this bounding box. | ||||||
|  | 	 * @return the maximum block vector. | ||||||
|  | 	 */ | ||||||
| 	public BlockVector getMaxBlock() { | 	public BlockVector getMaxBlock() { | ||||||
| 		return pos2.clone().add(new Vector(-1, -1, -1)).toBlockVector(); | 		return pos2.clone().add(new Vector(-1, -1, -1)).toBlockVector(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Gets a new {@link AABBBlock} with its coordinates shifted by the provided amount. | ||||||
|  | 	 * @param x the x shift. | ||||||
|  | 	 * @param y the y shift. | ||||||
|  | 	 * @param z the z shift. | ||||||
|  | 	 * @return a shifted bounding box. | ||||||
|  | 	 */ | ||||||
| 	public AABBBlock shift(int x, int y, int z) { | 	public AABBBlock shift(int x, int y, int z) { | ||||||
| 		return new AABBBlock(this, x, y, z); | 		return new AABBBlock(this, x, y, z); | ||||||
| 	} | 	} | ||||||
| @@ -101,7 +152,6 @@ public class AABBBlock implements BlockSet, Cloneable { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
| 	 |  | ||||||
| 	public boolean overlaps(BoundingBox bb) { | 	public boolean overlaps(BoundingBox bb) { | ||||||
| 		return asBukkitBoundingBox().overlaps(bb); | 		return asBukkitBoundingBox().overlaps(bb); | ||||||
| 	} | 	} | ||||||
| @@ -110,6 +160,10 @@ public class AABBBlock implements BlockSet, Cloneable { | |||||||
| 		return asBukkitBoundingBox().contains(v); | 		return asBukkitBoundingBox().contains(v); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Gets the coordinate of the center of this bounding box. | ||||||
|  | 	 * @return the center of this bounding box. | ||||||
|  | 	 */ | ||||||
| 	public Vector getCenter() { | 	public Vector getCenter() { | ||||||
| 		return center.clone(); | 		return center.clone(); | ||||||
| 	} | 	} | ||||||
| @@ -118,6 +172,10 @@ public class AABBBlock implements BlockSet, Cloneable { | |||||||
| 		return volume; | 		return volume; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Gets the Bukkit equivalent of this bounding box. | ||||||
|  | 	 * @return a {@link BoundingBox} corresponding to this {@link AABBBlock}. | ||||||
|  | 	 */ | ||||||
| 	public BoundingBox asBukkitBoundingBox() { | 	public BoundingBox asBukkitBoundingBox() { | ||||||
| 		if (bukkitBoundingBox == null) { | 		if (bukkitBoundingBox == null) { | ||||||
| 			bukkitBoundingBox = new BoundingBox(pos1.getX(), pos1.getY(), pos1.getZ(), | 			bukkitBoundingBox = new BoundingBox(pos1.getX(), pos1.getY(), pos1.getZ(), | ||||||
| @@ -134,7 +192,7 @@ public class AABBBlock implements BlockSet, Cloneable { | |||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	@Override | 	@Override | ||||||
| 	public Iterator<BlockVector> iterator() { | 	public @NotNull Iterator<BlockVector> iterator() { | ||||||
| 		return new Iterator<>() { | 		return new Iterator<>() { | ||||||
| 			private int x = pos1.getBlockX(), | 			private int x = pos1.getBlockX(), | ||||||
| 					y = pos1.getBlockY(), | 					y = pos1.getBlockY(), | ||||||
| @@ -164,22 +222,6 @@ public class AABBBlock implements BlockSet, Cloneable { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
| 	public Iterable<Block> asBlockIterable(World w) { |  | ||||||
| 		return () -> new Iterator<>() { |  | ||||||
| 			final Iterator<BlockVector> nested = AABBBlock.this.iterator(); |  | ||||||
| 			@Override |  | ||||||
| 			public boolean hasNext() { |  | ||||||
| 				return nested.hasNext(); |  | ||||||
| 			} |  | ||||||
| 			@Override |  | ||||||
| 			public Block next() { |  | ||||||
| 				BlockVector bv = nested.next(); |  | ||||||
| 				return w.getBlockAt(bv.getBlockX(), bv.getBlockY(), bv.getBlockZ()); |  | ||||||
| 			} |  | ||||||
| 		}; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public String toString() { | 	public String toString() { | ||||||
| 		return "{(" + pos1.getBlockX() + | 		return "{(" + pos1.getBlockX() + | ||||||
|   | |||||||
| @@ -12,12 +12,22 @@ import java.util.Collection; | |||||||
| import java.util.Iterator; | import java.util.Iterator; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * A group of {@link AABBBlock}. | ||||||
|  |  */ | ||||||
| public class AABBBlockGroup implements BlockSet { | public class AABBBlockGroup implements BlockSet { | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * The list of {@link AABBBlock} contained in this group. This list is unmodifiable. | ||||||
|  | 	 */ | ||||||
| 	public final List<AABBBlock> subAABB; | 	public final List<AABBBlock> subAABB; | ||||||
|  |  | ||||||
| 	private final AABBBlock englobingAABB; | 	private final AABBBlock englobingAABB; | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Creates a new {@link AABBBlockGroup}. | ||||||
|  | 	 * @param in the list of {@link AABBBlock} that will be contained in this group. | ||||||
|  | 	 */ | ||||||
| 	public AABBBlockGroup(Collection<AABBBlock> in) { | 	public AABBBlockGroup(Collection<AABBBlock> in) { | ||||||
| 		if (in.isEmpty()) | 		if (in.isEmpty()) | ||||||
| 			throw new IllegalArgumentException("Provided collection must not be empty."); | 			throw new IllegalArgumentException("Provided collection must not be empty."); | ||||||
| @@ -25,6 +35,10 @@ public class AABBBlockGroup implements BlockSet { | |||||||
| 		englobingAABB = initEnglobingAABB(); | 		englobingAABB = initEnglobingAABB(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Creates a new {@link AABBBlockGroup}. | ||||||
|  | 	 * @param in an array of {@link AABBBlock} that will be contained in this group. | ||||||
|  | 	 */ | ||||||
| 	public AABBBlockGroup(AABBBlock... in) { | 	public AABBBlockGroup(AABBBlock... in) { | ||||||
| 		this(Arrays.asList(in)); | 		this(Arrays.asList(in)); | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -1,23 +1,58 @@ | |||||||
| package fr.pandacube.lib.paper.geometry.blocks; | package fr.pandacube.lib.paper.geometry.blocks; | ||||||
|  |  | ||||||
| import org.bukkit.Location; | import org.bukkit.Location; | ||||||
|  | import org.bukkit.World; | ||||||
| import org.bukkit.block.Block; | import org.bukkit.block.Block; | ||||||
| import org.bukkit.entity.Entity; | import org.bukkit.entity.Entity; | ||||||
| import org.bukkit.util.BlockVector; | import org.bukkit.util.BlockVector; | ||||||
| import org.bukkit.util.BoundingBox; | import org.bukkit.util.BoundingBox; | ||||||
| import org.bukkit.util.Vector; | import org.bukkit.util.Vector; | ||||||
|  |  | ||||||
|  | import java.util.Iterator; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Represents a set of blocks in a world. | ||||||
|  |  */ | ||||||
| public interface BlockSet extends Iterable<BlockVector> { | public interface BlockSet extends Iterable<BlockVector> { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets a random coordinate that is inside this block set. | ||||||
|  |      * @return a random coordinate inside this block set. | ||||||
|  |      */ | ||||||
|     Vector getRandomPosition(); |     Vector getRandomPosition(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets the volume, in blocks (or cubic meters), of this block set. | ||||||
|  |      * @return the volume of this block set. | ||||||
|  |      */ | ||||||
|     long getVolume(); |     long getVolume(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets the englobing bounding box if this block set. | ||||||
|  |      * @return the englobing bounding box if this block set. | ||||||
|  |      */ | ||||||
|     AABBBlock getEnglobingAABB(); |     AABBBlock getEnglobingAABB(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Tells if this block set overlaps the provided bounding box. | ||||||
|  |      * @param bb the provided bounding box | ||||||
|  |      * @return true if its overlaps, false otherwise. | ||||||
|  |      */ | ||||||
|     boolean overlaps(BoundingBox bb); |     boolean overlaps(BoundingBox bb); | ||||||
|  |     /** | ||||||
|  |      * Tells if this block set overlaps the bounding box of the provided entity. | ||||||
|  |      * @param e the provided entity. | ||||||
|  |      * @return true if its overlaps, false otherwise. | ||||||
|  |      */ | ||||||
|     default boolean overlaps(Entity e) { |     default boolean overlaps(Entity e) { | ||||||
|         return overlaps(e.getBoundingBox()); |         return overlaps(e.getBoundingBox()); | ||||||
|     } |     } | ||||||
|  |     /** | ||||||
|  |      * Tells if this block set overlaps the provided one. that is there is at least one block in common. | ||||||
|  |      * @param bs the provided block set. | ||||||
|  |      * @return true if its overlaps, false otherwise. | ||||||
|  |      */ | ||||||
|     default boolean overlaps(BlockSet bs) { |     default boolean overlaps(BlockSet bs) { | ||||||
|         if (this instanceof AABBBlock b1) { |         if (this instanceof AABBBlock b1) { | ||||||
|             if (bs instanceof AABBBlock b2) |             if (bs instanceof AABBBlock b2) | ||||||
| @@ -37,20 +72,78 @@ public interface BlockSet extends Iterable<BlockVector> { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Tells if the provided vector is inside this bounding box. | ||||||
|  |      * @param v the vector. | ||||||
|  |      * @return true if its inside, false otherwise. | ||||||
|  |      */ | ||||||
|     boolean isInside(Vector v); |     boolean isInside(Vector v); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Tells if the provided location is inside this bounding box. | ||||||
|  |      * The world of the location is ignored. | ||||||
|  |      * @param l the location. | ||||||
|  |      * @return true if its inside, false otherwise. | ||||||
|  |      */ | ||||||
|     default boolean isInside(Location l) { |     default boolean isInside(Location l) { | ||||||
|         return isInside(l.toVector()); |         return isInside(l.toVector()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Tells if the provided block is inside this bounding box. | ||||||
|  |      * The world of the block is ignored. | ||||||
|  |      * @param b the block. | ||||||
|  |      * @return true if its inside, false otherwise. | ||||||
|  |      */ | ||||||
|     default boolean isInside(Block b) { |     default boolean isInside(Block b) { | ||||||
|         return isInside(b.getLocation().add(.5, .5, .5)); |         return isInside(b.getLocation().add(.5, .5, .5)); | ||||||
|     } |     } | ||||||
|     default boolean isInside(Entity p) { |  | ||||||
|         return isInside(p.getLocation()); |     /** | ||||||
|  |      * Tells if the provided entity is inside this bounding box. | ||||||
|  |      * It calls {@link #isInside(Location)} using the returned value of {@link Entity#getLocation()}. | ||||||
|  |      * The world of the entity is ignored. | ||||||
|  |      * @param e the entity. | ||||||
|  |      * @return true if its inside, false otherwise. | ||||||
|  |      */ | ||||||
|  |     default boolean isInside(Entity e) { | ||||||
|  |         return isInside(e.getLocation()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets an iterator iterating through all the blocks of this block set. | ||||||
|  |      * @param w the world of the blocks. | ||||||
|  |      * @return a new iterator. | ||||||
|  |      */ | ||||||
|  |     default Iterable<Block> asBlockIterable(World w) { | ||||||
|  |         return () -> new Iterator<>() { | ||||||
|  |             final Iterator<BlockVector> nested = BlockSet.this.iterator(); | ||||||
|  |             @Override | ||||||
|  |             public boolean hasNext() { | ||||||
|  |                 return nested.hasNext(); | ||||||
|  |             } | ||||||
|  |             @Override | ||||||
|  |             public Block next() { | ||||||
|  |                 BlockVector bv = nested.next(); | ||||||
|  |                 return w.getBlockAt(bv.getBlockX(), bv.getBlockY(), bv.getBlockZ()); | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Tests the two block set overlap each other. | ||||||
|  |      * This method works on any implementation of this interface, but they should override the | ||||||
|  |      * {@link #overlaps(BlockSet)} method to provide a more optimized code. | ||||||
|  |      * @param bs1 the first block set. | ||||||
|  |      * @param bs2 the second block set. | ||||||
|  |      * @return true if the two block set overlap, false otherwise. | ||||||
|  |      */ | ||||||
|     static boolean overlap(BlockSet bs1, BlockSet bs2) { |     static boolean overlap(BlockSet bs1, BlockSet bs2) { | ||||||
|         if (!bs1.getEnglobingAABB().overlaps(bs2.getEnglobingAABB())) |         if (!bs1.getEnglobingAABB().overlaps(bs2.getEnglobingAABB())) | ||||||
|             return false; |             return false; | ||||||
|   | |||||||
| @@ -38,12 +38,20 @@ public class GUIHotBar implements Listener { | |||||||
| 	 | 	 | ||||||
| 	private final List<Player> currentPlayers = new ArrayList<>(); | 	private final List<Player> currentPlayers = new ArrayList<>(); | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Setup a new gui hot  bar. You should not instantiate more than one hot bar. | ||||||
|  | 	 * @param defaultSlot the default slot (currently held item) when the player joins the hot bar. | ||||||
|  | 	 */ | ||||||
| 	public GUIHotBar(int defaultSlot) { | 	public GUIHotBar(int defaultSlot) { | ||||||
| 		this.defaultSlot = Math.max(0, Math.min(8, defaultSlot)); | 		this.defaultSlot = Math.max(0, Math.min(8, defaultSlot)); | ||||||
| 		 | 		 | ||||||
| 		BukkitEvent.register(this); | 		BukkitEvent.register(this); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Disables this hot bar. | ||||||
|  | 	 * @param clearPlayerMenuItems if the items of this hot bar should be removed from the players inventories. | ||||||
|  | 	 */ | ||||||
| 	public void disable(boolean clearPlayerMenuItems) { | 	public void disable(boolean clearPlayerMenuItems) { | ||||||
| 		removeAllPlayers(clearPlayerMenuItems); | 		removeAllPlayers(clearPlayerMenuItems); | ||||||
|  |  | ||||||
| @@ -53,9 +61,10 @@ public class GUIHotBar implements Listener { | |||||||
| 	/** | 	/** | ||||||
| 	 * 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 hot bar menu. if there is already players hooked to this hot bar, the item will be directly added to | ||||||
| 	 * their inventories. | 	 * their inventories. | ||||||
| 	 * @param i the item stack | 	 * @param i the item stack. | ||||||
| 	 * @param setter code executed to put the item in the inventory. Additionally, check for permission before doing the addition. | 	 * @param setter code executed to put the item in the inventory. Additionally, check for permission before doing the addition. | ||||||
| 	 * @param run the Runnable to run when the user right-click on the item in the hot bar. | 	 * @param run the Runnable to run when the user right-click on the item in the hot bar. | ||||||
|  | 	 * @return itself for daisy-chaining. | ||||||
| 	 */ | 	 */ | ||||||
| 	public GUIHotBar addItem(ItemStack i, BiConsumer<PlayerInventory, ItemStack> setter, Consumer<Player> run) { | 	public GUIHotBar addItem(ItemStack i, BiConsumer<PlayerInventory, ItemStack> setter, Consumer<Player> run) { | ||||||
| 		itemsAndSetters.put(i, setter); | 		itemsAndSetters.put(i, setter); | ||||||
| @@ -69,8 +78,9 @@ public class GUIHotBar implements Listener { | |||||||
| 	 | 	 | ||||||
| 	/** | 	/** | ||||||
| 	 * Add the hot bar elements to this player, or update them if applicable. | 	 * Add the hot bar elements to this player, or update them if applicable. | ||||||
| 	 *  | 	 * <br> | ||||||
| 	 * The player is automatically removed when they quit. You can remove it before by calling {@link #removePlayer(Player, boolean)}. | 	 * The player is automatically removed when they quit. You can remove it before by calling {@link #removePlayer(Player, boolean)}. | ||||||
|  | 	 * @param p the player to add. | ||||||
| 	 */ | 	 */ | ||||||
| 	public void addPlayer(Player p) { | 	public void addPlayer(Player p) { | ||||||
| 		if (!currentPlayers.contains(p)) | 		if (!currentPlayers.contains(p)) | ||||||
| @@ -85,6 +95,7 @@ public class GUIHotBar implements Listener { | |||||||
| 	 | 	 | ||||||
| 	/** | 	/** | ||||||
| 	 * Detach this player from this hot bar manager and removes the managed items from the players inventory. | 	 * Detach this player from this hot bar manager and removes the managed items from the players inventory. | ||||||
|  | 	 * @param p the player to remove. | ||||||
| 	 */ | 	 */ | ||||||
| 	public void removePlayer(Player p) { | 	public void removePlayer(Player p) { | ||||||
| 		removePlayer(p, true); | 		removePlayer(p, true); | ||||||
| @@ -92,6 +103,8 @@ public class GUIHotBar implements Listener { | |||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Detach this player from this hot bar manager and optionally removes the managed items from the players inventory. | 	 * Detach this player from this hot bar manager and optionally removes the managed items from the players inventory. | ||||||
|  | 	 * @param p the player to remove. | ||||||
|  | 	 * @param clearMenuItems if the items from this hot bar should be removed from the player inventory. | ||||||
| 	 */ | 	 */ | ||||||
| 	public void removePlayer(Player p, boolean clearMenuItems) { | 	public void removePlayer(Player p, boolean clearMenuItems) { | ||||||
| 		if (!currentPlayers.contains(p)) | 		if (!currentPlayers.contains(p)) | ||||||
| @@ -107,17 +120,27 @@ public class GUIHotBar implements Listener { | |||||||
|  |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	 | 	/** | ||||||
|  | 	 * Tells if the provided player is attached to this hot bar. | ||||||
|  | 	 * @param p the player to check. | ||||||
|  | 	 * @return true if the player is attached, false otherwise. | ||||||
|  | 	 */ | ||||||
| 	public boolean containsPlayer(Player p) { | 	public boolean containsPlayer(Player p) { | ||||||
| 		return currentPlayers.contains(p); | 		return currentPlayers.contains(p); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
| 	 | 	/** | ||||||
|  | 	 * Detach all players from this hot bar. | ||||||
|  | 	 */ | ||||||
| 	public void removeAllPlayers() { | 	public void removeAllPlayers() { | ||||||
| 		removeAllPlayers(true); | 		removeAllPlayers(true); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Detach all players from this hot bar. | ||||||
|  | 	 * @param clearMenuItems if the items from this hot bar should be removed from the player inventory. | ||||||
|  | 	 */ | ||||||
| 	public void removeAllPlayers(boolean clearMenuItems) { | 	public void removeAllPlayers(boolean clearMenuItems) { | ||||||
| 		for (Player p : new ArrayList<>(currentPlayers)) | 		for (Player p : new ArrayList<>(currentPlayers)) | ||||||
| 			removePlayer(p, clearMenuItems); | 			removePlayer(p, clearMenuItems); | ||||||
| @@ -127,7 +150,7 @@ public class GUIHotBar implements Listener { | |||||||
| 	 | 	 | ||||||
| 	 | 	 | ||||||
| 	 | 	 | ||||||
| 	public void addItemToPlayer(Player p, ItemStack is) { | 	private void addItemToPlayer(Player p, ItemStack is) { | ||||||
| 		if (!itemsAndSetters.containsKey(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 GUIHotBar"); | ||||||
| 		if (!currentPlayers.contains(p)) | 		if (!currentPlayers.contains(p)) | ||||||
| @@ -135,7 +158,7 @@ public class GUIHotBar implements Listener { | |||||||
| 		itemsAndSetters.get(is).accept(p.getInventory(), is.clone()); | 		itemsAndSetters.get(is).accept(p.getInventory(), is.clone()); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	public void removeItemFromPlayer(Player p, ItemStack is) { | 	private void removeItemFromPlayer(Player p, ItemStack is) { | ||||||
| 		p.getInventory().remove(is); | 		p.getInventory().remove(is); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| @@ -144,7 +167,7 @@ public class GUIHotBar implements Listener { | |||||||
| 	 | 	 | ||||||
|  |  | ||||||
| 	@EventHandler | 	@EventHandler | ||||||
| 	public void onPlayerDropItem(PlayerDropItemEvent event) { | 	void onPlayerDropItem(PlayerDropItemEvent event) { | ||||||
| 		if (!currentPlayers.contains(event.getPlayer())) | 		if (!currentPlayers.contains(event.getPlayer())) | ||||||
| 			return; | 			return; | ||||||
| 		 | 		 | ||||||
| @@ -159,7 +182,7 @@ public class GUIHotBar implements Listener { | |||||||
| 	 | 	 | ||||||
| 	 | 	 | ||||||
| 	@EventHandler | 	@EventHandler | ||||||
| 	public void onPlayerInteract(PlayerInteractEvent event) { | 	void onPlayerInteract(PlayerInteractEvent event) { | ||||||
| 		if (!currentPlayers.contains(event.getPlayer())) | 		if (!currentPlayers.contains(event.getPlayer())) | ||||||
| 			return; | 			return; | ||||||
| 		 | 		 | ||||||
| @@ -188,7 +211,7 @@ public class GUIHotBar implements Listener { | |||||||
| 	 | 	 | ||||||
| 	 | 	 | ||||||
| 	@EventHandler | 	@EventHandler | ||||||
| 	public void onInventoryClick(InventoryClickEvent event) { | 	void onInventoryClick(InventoryClickEvent event) { | ||||||
| 		if (event.getClickedInventory() == null || !(event.getClickedInventory() instanceof PlayerInventory inv)) | 		if (event.getClickedInventory() == null || !(event.getClickedInventory() instanceof PlayerInventory inv)) | ||||||
| 			return; | 			return; | ||||||
|  |  | ||||||
| @@ -213,20 +236,20 @@ public class GUIHotBar implements Listener { | |||||||
|  |  | ||||||
| 	 | 	 | ||||||
| 	@EventHandler | 	@EventHandler | ||||||
| 	public void onPlayerQuit(PlayerQuitEvent event) { | 	void onPlayerQuit(PlayerQuitEvent event) { | ||||||
| 		removePlayer(event.getPlayer()); | 		removePlayer(event.getPlayer()); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	 | 	 | ||||||
| 	@EventHandler | 	@EventHandler | ||||||
| 	public void onPlayerDeath(PlayerDeathEvent event) { | 	void onPlayerDeath(PlayerDeathEvent event) { | ||||||
| 		if (!currentPlayers.contains(event.getEntity())) | 		if (!currentPlayers.contains(event.getEntity())) | ||||||
| 			return; | 			return; | ||||||
| 		event.getDrops().removeAll(itemsAndSetters.keySet()); | 		event.getDrops().removeAll(itemsAndSetters.keySet()); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	@EventHandler | 	@EventHandler | ||||||
| 	public void onPlayerRespawn(PlayerRespawnEvent event) { | 	void onPlayerRespawn(PlayerRespawnEvent event) { | ||||||
| 		if (!currentPlayers.contains(event.getPlayer())) | 		if (!currentPlayers.contains(event.getPlayer())) | ||||||
| 			return; | 			return; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -38,7 +38,7 @@ public class GUIInventory implements Listener { | |||||||
| 		if (title == null) | 		if (title == null) | ||||||
| 			inv = Bukkit.createInventory(null, nbLines * 9); | 			inv = Bukkit.createInventory(null, nbLines * 9); | ||||||
| 		else | 		else | ||||||
| 			inv = Bukkit.createInventory(null, nbLines * 9, title.getAdv()); | 			inv = Bukkit.createInventory(null, nbLines * 9, title.get()); | ||||||
|  |  | ||||||
| 		setCloseEvent(closeEventAction); | 		setCloseEvent(closeEventAction); | ||||||
|  |  | ||||||
| @@ -50,6 +50,10 @@ public class GUIInventory implements Listener { | |||||||
|  |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Sets the action when the player closes the inventory window. | ||||||
|  | 	 * @param closeEventAction the action to run. | ||||||
|  | 	 */ | ||||||
| 	protected void setCloseEvent(Consumer<InventoryCloseEvent> closeEventAction) { | 	protected void setCloseEvent(Consumer<InventoryCloseEvent> closeEventAction) { | ||||||
| 		onCloseEvent = closeEventAction; | 		onCloseEvent = closeEventAction; | ||||||
| 	} | 	} | ||||||
| @@ -190,11 +194,11 @@ public class GUIInventory implements Listener { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	/** | ||||||
| 	 | 	 * Tells the number of inventory line needed to show the provided number of slot. | ||||||
|  | 	 * @param nb the number of slot. | ||||||
| 	 | 	 * @return the number of line. | ||||||
| 	 | 	 */ | ||||||
| 	public static int nbLineForNbElements(int nb) { | 	public static int nbLineForNbElements(int nb) { | ||||||
| 		return nb / 9 + ((nb % 9 == 0) ? 0 : 1); | 		return nb / 9 + ((nb % 9 == 0) ? 0 : 1); | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -0,0 +1,191 @@ | |||||||
|  | package fr.pandacube.lib.paper.inventory; | ||||||
|  |  | ||||||
|  | import com.google.common.base.Preconditions; | ||||||
|  | import org.bukkit.Material; | ||||||
|  | import org.bukkit.entity.HumanEntity; | ||||||
|  | import org.bukkit.inventory.EquipmentSlot; | ||||||
|  | import org.bukkit.inventory.Inventory; | ||||||
|  | import org.bukkit.inventory.ItemStack; | ||||||
|  | import org.bukkit.inventory.PlayerInventory; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  | import org.jetbrains.annotations.Nullable; | ||||||
|  |  | ||||||
|  | import java.util.Arrays; | ||||||
|  | import java.util.Objects; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Dummy implementation of a player inventory. | ||||||
|  |  */ | ||||||
|  | public class DummyPlayerInventory extends InventoryWrapper implements PlayerInventory { | ||||||
|  |  | ||||||
|  |     private int heldItemSlot; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Creates a dummy player inventory. | ||||||
|  |      * @param base the inventory itself. | ||||||
|  |      * @param heldItemSlot the currently held item slot, from 0 to 8. | ||||||
|  |      */ | ||||||
|  |     public DummyPlayerInventory(Inventory base, int heldItemSlot) { | ||||||
|  |         super(base); | ||||||
|  |         if (base.getSize() < 41) | ||||||
|  |             throw new IllegalArgumentException("base inventory should have a size of 41 (" + base.getSize() + " given)."); | ||||||
|  |         if (heldItemSlot < 0 || heldItemSlot > 8) | ||||||
|  |             throw new IllegalArgumentException("heldItemSlot should be between 0 and 8 inclusive."); | ||||||
|  |         this.heldItemSlot = heldItemSlot; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public @Nullable ItemStack @NotNull [] getStorageContents() { | ||||||
|  |         return Arrays.copyOfRange(getContents(), 0, 36); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public @Nullable ItemStack @NotNull [] getArmorContents() { | ||||||
|  |         return Arrays.copyOfRange(getContents(), 36, 40); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void setArmorContents(@Nullable ItemStack[] items) { | ||||||
|  |         this.setSlots(items, 36, 4); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public @Nullable ItemStack @NotNull [] getExtraContents() { | ||||||
|  |         return Arrays.copyOfRange(getContents(), 40, getSize()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void setExtraContents(@Nullable ItemStack[] items) { | ||||||
|  |         this.setSlots(items, 40, getSize() - 40); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void setSlots(ItemStack[] items, int baseSlot, int length) { | ||||||
|  |         if (items == null) { | ||||||
|  |             items = new ItemStack[length]; | ||||||
|  |         } | ||||||
|  |         Preconditions.checkArgument(items.length <= length, "items.length must be < %s", length); | ||||||
|  |  | ||||||
|  |         for (int i = 0; i < length; i++) { | ||||||
|  |             if (i >= items.length) { | ||||||
|  |                 this.setItem(baseSlot + i, null); | ||||||
|  |             } else { | ||||||
|  |                 this.setItem(baseSlot + i, items[i]); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public ItemStack getHelmet() { | ||||||
|  |         return getItem(39); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void setHelmet(@Nullable ItemStack helmet) { | ||||||
|  |         setItem(39, helmet); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public ItemStack getChestplate() { | ||||||
|  |         return getItem(38); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void setChestplate(@Nullable ItemStack chestplate) { | ||||||
|  |         setItem(38, chestplate); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public ItemStack getLeggings() { | ||||||
|  |         return getItem(37); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void setLeggings(@Nullable ItemStack leggings) { | ||||||
|  |         setItem(37, leggings); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public ItemStack getBoots() { | ||||||
|  |         return getItem(36); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void setBoots(@Nullable ItemStack boots) { | ||||||
|  |         setItem(36, boots); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void setItem(EquipmentSlot slot, ItemStack item) { | ||||||
|  |         Preconditions.checkArgument(slot != null, "slot must not be null"); | ||||||
|  |  | ||||||
|  |         switch (slot) { | ||||||
|  |             case HAND -> this.setItemInMainHand(item); | ||||||
|  |             case OFF_HAND -> this.setItemInOffHand(item); | ||||||
|  |             case FEET -> this.setBoots(item); | ||||||
|  |             case LEGS -> this.setLeggings(item); | ||||||
|  |             case CHEST -> this.setChestplate(item); | ||||||
|  |             case HEAD -> this.setHelmet(item); | ||||||
|  |             default -> throw new IllegalArgumentException("Not implemented. This is a bug"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public @NotNull ItemStack getItem(@NotNull EquipmentSlot slot) { | ||||||
|  |         return switch (slot) { | ||||||
|  |             case HAND -> this.getItemInMainHand(); | ||||||
|  |             case OFF_HAND -> this.getItemInOffHand(); | ||||||
|  |             case FEET -> Objects.requireNonNullElseGet(this.getBoots(), () -> new ItemStack(Material.AIR)); | ||||||
|  |             case LEGS -> Objects.requireNonNullElseGet(this.getLeggings(), () -> new ItemStack(Material.AIR)); | ||||||
|  |             case CHEST -> Objects.requireNonNullElseGet(this.getChestplate(), () -> new ItemStack(Material.AIR)); | ||||||
|  |             case HEAD -> Objects.requireNonNullElseGet(this.getHelmet(), () -> new ItemStack(Material.AIR)); | ||||||
|  |             case BODY -> new ItemStack(Material.AIR); // for horses/wolves armor | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public @NotNull ItemStack getItemInMainHand() { | ||||||
|  |         return Objects.requireNonNullElse(getItem(heldItemSlot), new ItemStack(Material.AIR)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void setItemInMainHand(@Nullable ItemStack item) { | ||||||
|  |         setItem(heldItemSlot, item); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public @NotNull ItemStack getItemInOffHand() { | ||||||
|  |         return Objects.requireNonNullElse(getItem(40), new ItemStack(Material.AIR)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void setItemInOffHand(@Nullable ItemStack item) { | ||||||
|  |         setItem(40, item); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public @NotNull ItemStack getItemInHand() { | ||||||
|  |         return getItemInMainHand(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void setItemInHand(@Nullable ItemStack stack) { | ||||||
|  |         setItemInMainHand(stack); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public int getHeldItemSlot() { | ||||||
|  |         return heldItemSlot; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void setHeldItemSlot(int slot) { | ||||||
|  |         if (slot < 0 || slot > 8) | ||||||
|  |             throw new IllegalArgumentException("Slot is not between 0 and 8 inclusive"); | ||||||
|  |         heldItemSlot = slot; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public @Nullable HumanEntity getHolder() { | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| package fr.pandacube.lib.paper.util; | package fr.pandacube.lib.paper.inventory; | ||||||
| 
 | 
 | ||||||
| import org.bukkit.Location; | import org.bukkit.Location; | ||||||
| import org.bukkit.Material; | import org.bukkit.Material; | ||||||
| @@ -13,12 +13,22 @@ import org.jetbrains.annotations.Nullable; | |||||||
| import java.util.HashMap; | import java.util.HashMap; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.ListIterator; | import java.util.ListIterator; | ||||||
|  | import java.util.Objects; | ||||||
| 
 | 
 | ||||||
|  | /** | ||||||
|  |  * Wrapper for an {@link Inventory}. | ||||||
|  |  * Can be overridden to add specific behaviour to some methods. | ||||||
|  |  */ | ||||||
| public class InventoryWrapper implements Inventory { | public class InventoryWrapper implements Inventory { | ||||||
|     private final Inventory base; |     private final Inventory base; | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * Creates a wrapper for the provided inventory. | ||||||
|  |      * @param base the wrapped inventory. Cannot be null. | ||||||
|  |      * @throws NullPointerException if the base inventory is null. | ||||||
|  |      */ | ||||||
|     public InventoryWrapper(Inventory base) { |     public InventoryWrapper(Inventory base) { | ||||||
|         this.base = base; |         this.base = Objects.requireNonNull(base, "base inventory cannot be null."); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| package fr.pandacube.lib.paper.util; | package fr.pandacube.lib.paper.inventory; | ||||||
| 
 | 
 | ||||||
| import com.google.common.collect.Streams; | import com.google.common.collect.Streams; | ||||||
| import fr.pandacube.lib.chat.Chat; | import fr.pandacube.lib.chat.Chat; | ||||||
| @@ -18,6 +18,9 @@ import java.util.function.Consumer; | |||||||
| 
 | 
 | ||||||
| import static fr.pandacube.lib.chat.ChatStatic.chatComponent; | import static fr.pandacube.lib.chat.ChatStatic.chatComponent; | ||||||
| 
 | 
 | ||||||
|  | /** | ||||||
|  |  * A builder for {@link ItemStack}. | ||||||
|  |  */ | ||||||
| public class ItemStackBuilder { | public class ItemStackBuilder { | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| @@ -77,10 +80,22 @@ public class ItemStackBuilder { | |||||||
| 		return (cachedMeta != null) ? cachedMeta : (cachedMeta = stack.getItemMeta()); | 		return (cachedMeta != null) ? cachedMeta : (cachedMeta = stack.getItemMeta()); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Runs the provided updater on the {@link ItemMeta} instance of the built stack. | ||||||
|  | 	 * @param metaUpdater the updater that will modify the meta. | ||||||
|  | 	 * @return itself. | ||||||
|  | 	 */ | ||||||
| 	public ItemStackBuilder meta(Consumer<ItemMeta> metaUpdater) { | 	public ItemStackBuilder meta(Consumer<ItemMeta> metaUpdater) { | ||||||
| 		return meta(metaUpdater, ItemMeta.class); | 		return meta(metaUpdater, ItemMeta.class); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Runs the provided updater on the {@link ItemMeta} instance of the built stack. | ||||||
|  | 	 * @param metaUpdater the updater that will modify the meta. | ||||||
|  | 	 * @param metaType the type of the meta instance. | ||||||
|  | 	 * @param <T> the type of item meta. | ||||||
|  | 	 * @return itself. | ||||||
|  | 	 */ | ||||||
| 	public <T extends ItemMeta> ItemStackBuilder meta(Consumer<T> metaUpdater, Class<T> metaType) { | 	public <T extends ItemMeta> ItemStackBuilder meta(Consumer<T> metaUpdater, Class<T> metaType) { | ||||||
| 		stack.editMeta(metaType, m -> { | 		stack.editMeta(metaType, m -> { | ||||||
| 			metaUpdater.accept(m); | 			metaUpdater.accept(m); | ||||||
| @@ -89,37 +104,66 @@ public class ItemStackBuilder { | |||||||
| 		return this; | 		return this; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Sets the amount of the built stack. | ||||||
|  | 	 * @param a the new amount. | ||||||
|  | 	 * @return itself. | ||||||
|  | 	 */ | ||||||
| 	public ItemStackBuilder amount(int a) { | 	public ItemStackBuilder amount(int a) { | ||||||
| 		stack.setAmount(a); | 		stack.setAmount(a); | ||||||
| 		return this; | 		return this; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Sets the display name of the item, directly passing to {@link ItemMeta#displayName(Component)}. | ||||||
|  | 	 * @param displayName the new display name. Can be null to unset. | ||||||
|  | 	 * @return itself. | ||||||
|  | 	 */ | ||||||
| 	public ItemStackBuilder rawDisplayName(Component displayName) { | 	public ItemStackBuilder rawDisplayName(Component displayName) { | ||||||
| 		return meta(m -> m.displayName(displayName)); | 		return meta(m -> m.displayName(displayName)); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Sets the display name of the item, filtering to make default italic to false. | ||||||
|  | 	 * @param displayName the new display name. Can be null to unset. | ||||||
|  | 	 * @return itself. | ||||||
|  | 	 */ | ||||||
| 	public ItemStackBuilder displayName(ComponentLike displayName) { | 	public ItemStackBuilder displayName(ComponentLike displayName) { | ||||||
| 		if (displayName != null) { | 		return rawDisplayName(displayName != null | ||||||
| 			return rawDisplayName(Chat.italicFalseIfNotSet(chatComponent(displayName)).asComponent()); | 				? Chat.italicFalseIfNotSet(chatComponent(displayName)).asComponent() | ||||||
| 		} | 				: null); | ||||||
| 		else |  | ||||||
| 			return rawDisplayName(null); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Sets the lore of the item, directly passing to {@link ItemMeta#lore(List)}. | ||||||
|  | 	 * @param lore the new lore. Can be null to unset. | ||||||
|  | 	 * @return itself. | ||||||
|  | 	 */ | ||||||
| 	public ItemStackBuilder rawLore(List<Component> lore) { | 	public ItemStackBuilder rawLore(List<Component> lore) { | ||||||
| 		return meta(m -> m.lore(lore)); | 		return meta(m -> m.lore(lore)); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Sets the lore of the item, filtering to make default italic to false. | ||||||
|  | 	 * @param lore the new lore. Can be null to unset. | ||||||
|  | 	 * @return itself. | ||||||
|  | 	 */ | ||||||
| 	public ItemStackBuilder lore(List<? extends ComponentLike> lore) { | 	public ItemStackBuilder lore(List<? extends ComponentLike> lore) { | ||||||
| 		if (lore != null) { | 		if (lore != null) { | ||||||
| 			return rawLore(lore.stream() | 			return rawLore(lore.stream() | ||||||
| 					.map(line -> Chat.italicFalseIfNotSet(chatComponent(line)).getAdv()) | 					.map(line -> Chat.italicFalseIfNotSet(chatComponent(line)).get()) | ||||||
| 					.toList()); | 					.toList()); | ||||||
| 		} | 		} | ||||||
| 		else | 		else | ||||||
| 			return rawLore(Collections.emptyList()); | 			return rawLore(Collections.emptyList()); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Adds new lore lines to the existing lore of the item. | ||||||
|  | 	 * @param lores the added lore lines. | ||||||
|  | 	 * @return itself. | ||||||
|  | 	 */ | ||||||
| 	public ItemStackBuilder addLoreAfter(List<? extends ComponentLike> lores) { | 	public ItemStackBuilder addLoreAfter(List<? extends ComponentLike> lores) { | ||||||
| 		if (lores != null) { | 		if (lores != null) { | ||||||
| 			List<Component> baseLore = getOrInitMeta().lore(); | 			List<Component> baseLore = getOrInitMeta().lore(); | ||||||
| @@ -128,7 +172,7 @@ public class ItemStackBuilder { | |||||||
| 					Streams.concat( | 					Streams.concat( | ||||||
| 							baseLore.stream(), | 							baseLore.stream(), | ||||||
| 							lores.stream() | 							lores.stream() | ||||||
| 							.map(line -> Chat.italicFalseIfNotSet(chatComponent(line)).getAdv()) | 							.map(line -> Chat.italicFalseIfNotSet(chatComponent(line)).get()) | ||||||
| 					) | 					) | ||||||
| 					.toList()); | 					.toList()); | ||||||
| 		} | 		} | ||||||
| @@ -136,6 +180,11 @@ public class ItemStackBuilder { | |||||||
| 			return this; | 			return this; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Adds new lore lines to the existing lore of the item. | ||||||
|  | 	 * @param lores the added lore lines. | ||||||
|  | 	 * @return itself. | ||||||
|  | 	 */ | ||||||
| 	public ItemStackBuilder addLoreAfter(ComponentLike... lores) { | 	public ItemStackBuilder addLoreAfter(ComponentLike... lores) { | ||||||
| 		if (lores == null || lores.length == 0) | 		if (lores == null || lores.length == 0) | ||||||
| 			return this; | 			return this; | ||||||
| @@ -143,69 +192,120 @@ public class ItemStackBuilder { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | 	 * Enchant the item. | ||||||
| 	 * Supports unsafe enchants. | 	 * Supports unsafe enchants. | ||||||
|  | 	 * @param enchantment the enchantment. | ||||||
|  | 	 * @param level the enchant level. | ||||||
|  | 	 * @return itself. | ||||||
| 	 */ | 	 */ | ||||||
| 	public ItemStackBuilder enchant(Enchantment enchantment, int level) { | 	public ItemStackBuilder enchant(Enchantment enchantment, int level) { | ||||||
| 		return meta(m -> m.addEnchant(enchantment, level, true)); | 		return meta(m -> m.addEnchant(enchantment, level, true)); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Adds the provided flags to the item. | ||||||
|  | 	 * @param flags he flags to add. | ||||||
|  | 	 * @return itself. | ||||||
|  | 	 */ | ||||||
| 	public ItemStackBuilder flags(ItemFlag... flags) { | 	public ItemStackBuilder flags(ItemFlag... flags) { | ||||||
| 		return flags(true, flags); | 		return flags(true, flags); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Adds or removes the provided flags to the item. | ||||||
|  | 	 * @param add true to add, false to remove. | ||||||
|  | 	 * @param flags he flags to add. | ||||||
|  | 	 * @return itself. | ||||||
|  | 	 */ | ||||||
| 	public ItemStackBuilder flags(boolean add, ItemFlag... flags) { | 	public ItemStackBuilder flags(boolean add, ItemFlag... flags) { | ||||||
| 		return add ? meta(m -> m.addItemFlags(flags)) | 		return add ? meta(m -> m.addItemFlags(flags)) | ||||||
| 				: meta(m -> m.removeItemFlags(flags)); | 				: meta(m -> m.removeItemFlags(flags)); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Hides the enchants from the tooltip of the item. | ||||||
|  | 	 * Will set the {@link ItemFlag#HIDE_ENCHANTS} flag of the item. | ||||||
|  | 	 * @return itself. | ||||||
|  | 	 */ | ||||||
| 	public ItemStackBuilder hideEnchants() { | 	public ItemStackBuilder hideEnchants() { | ||||||
| 		return hideEnchants(true); | 		return hideEnchants(true); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Sets or unsets the {@link ItemFlag#HIDE_ENCHANTS} flag of the item. | ||||||
|  | 	 * @param hide true to hide, false to show. | ||||||
|  | 	 * @return itself. | ||||||
|  | 	 */ | ||||||
| 	public ItemStackBuilder hideEnchants(boolean hide) { | 	public ItemStackBuilder hideEnchants(boolean hide) { | ||||||
| 		return flags(hide, ItemFlag.HIDE_ENCHANTS); | 		return flags(hide, ItemFlag.HIDE_ENCHANTS); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Hides the attributes from the tooltip of the item. | ||||||
|  | 	 * Will set the {@link ItemFlag#HIDE_ATTRIBUTES} flag of the item. | ||||||
|  | 	 * @return itself. | ||||||
|  | 	 */ | ||||||
| 	public ItemStackBuilder hideAttributes() { | 	public ItemStackBuilder hideAttributes() { | ||||||
| 		return hideAttributes(true); | 		return hideAttributes(true); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Sets or unsets the {@link ItemFlag#HIDE_ATTRIBUTES} flag of the item. | ||||||
|  | 	 * @param hide true to hide, false to show. | ||||||
|  | 	 * @return itself. | ||||||
|  | 	 */ | ||||||
| 	public ItemStackBuilder hideAttributes(boolean hide) { | 	public ItemStackBuilder hideAttributes(boolean hide) { | ||||||
| 		return flags(hide, ItemFlag.HIDE_ATTRIBUTES); | 		return flags(hide, ItemFlag.HIDE_ATTRIBUTES); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Apply the enchantment glint to the item, event if it's not enchant. | ||||||
|  | 	 * @return itself. | ||||||
|  | 	 */ | ||||||
| 	public ItemStackBuilder fakeEnchant() { | 	public ItemStackBuilder fakeEnchant() { | ||||||
| 		return fakeEnchant(true); | 		return fakeEnchant(true); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Sets the enchantment glint override to the item. | ||||||
|  | 	 * @param apply true to enforce the enchantment glint, false to set to default. | ||||||
|  | 	 * @return itself. | ||||||
|  | 	 */ | ||||||
| 	public ItemStackBuilder fakeEnchant(boolean apply) { | 	public ItemStackBuilder fakeEnchant(boolean apply) { | ||||||
| 		if (apply) { | 		return meta(m -> m.setEnchantmentGlintOverride(apply ? true : null)); | ||||||
| 			enchant(Enchantment.UNBREAKING, 1); |  | ||||||
| 			return hideEnchants(); |  | ||||||
| 		} |  | ||||||
| 		return this; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Sets this item as unbreakable. | ||||||
|  | 	 * @return itself. | ||||||
|  | 	 */ | ||||||
| 	public ItemStackBuilder unbreakable() { | 	public ItemStackBuilder unbreakable() { | ||||||
| 		return unbreakable(true); | 		return unbreakable(true); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Sets the unbreakable status of this item. | ||||||
|  | 	 * @param unbreakable the unbreakable status. | ||||||
|  | 	 * @return itself. | ||||||
|  | 	 */ | ||||||
| 	public ItemStackBuilder unbreakable(boolean unbreakable) { | 	public ItemStackBuilder unbreakable(boolean unbreakable) { | ||||||
| 		return meta(m -> m.setUnbreakable(unbreakable)); | 		return meta(m -> m.setUnbreakable(unbreakable)); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Sets the damage value of this item. | ||||||
|  | 	 * @param d the new damage value. | ||||||
|  | 	 * @return itself. | ||||||
|  | 	 */ | ||||||
| 	public ItemStackBuilder damage(int d) { | 	public ItemStackBuilder damage(int d) { | ||||||
| 		return meta(m -> m.setDamage(d), Damageable.class); | 		return meta(m -> m.setDamage(d), Damageable.class); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 	 | 	/** | ||||||
| 	 | 	 * Build the {@link ItemStack}. | ||||||
| 	 | 	 * @return the build item stack. | ||||||
| 	 | 	 */ | ||||||
| 	 |  | ||||||
| 	 |  | ||||||
| 	 |  | ||||||
| 	public ItemStack build() { | 	public ItemStack build() { | ||||||
| 		return stack; | 		return stack; | ||||||
| 	} | 	} | ||||||
| @@ -14,4 +14,7 @@ public class PaperJson { | |||||||
|         Json.registerTypeAdapterFactory(ItemStackAdapter.FACTORY); |         Json.registerTypeAdapterFactory(ItemStackAdapter.FACTORY); | ||||||
|         Json.registerTypeAdapterFactory(ConfigurationSerializableAdapter.FACTORY); |         Json.registerTypeAdapterFactory(ConfigurationSerializableAdapter.FACTORY); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     private PaperJson() {} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -4,7 +4,6 @@ import com.destroystokyo.paper.event.server.ServerTickEndEvent; | |||||||
| import com.destroystokyo.paper.event.server.ServerTickStartEvent; | import com.destroystokyo.paper.event.server.ServerTickStartEvent; | ||||||
| import fr.pandacube.lib.chat.Chat; | import fr.pandacube.lib.chat.Chat; | ||||||
| import fr.pandacube.lib.chat.ChatColorGradient; | import fr.pandacube.lib.chat.ChatColorGradient; | ||||||
| import fr.pandacube.lib.chat.ChatColorUtil; |  | ||||||
| import fr.pandacube.lib.chat.ChatConfig.PandaTheme; | import fr.pandacube.lib.chat.ChatConfig.PandaTheme; | ||||||
| import fr.pandacube.lib.paper.PandaLibPaper; | import fr.pandacube.lib.paper.PandaLibPaper; | ||||||
| import fr.pandacube.lib.paper.players.PaperOffPlayer; | import fr.pandacube.lib.paper.players.PaperOffPlayer; | ||||||
| @@ -13,16 +12,15 @@ import fr.pandacube.lib.paper.scheduler.SchedulerUtil; | |||||||
| import fr.pandacube.lib.paper.util.AutoUpdatedBossBar; | import fr.pandacube.lib.paper.util.AutoUpdatedBossBar; | ||||||
| import fr.pandacube.lib.paper.util.AutoUpdatedBossBar.BarUpdater; | import fr.pandacube.lib.paper.util.AutoUpdatedBossBar.BarUpdater; | ||||||
| import fr.pandacube.lib.players.standalone.AbstractPlayerManager; | import fr.pandacube.lib.players.standalone.AbstractPlayerManager; | ||||||
| import fr.pandacube.lib.util.log.Log; |  | ||||||
| import fr.pandacube.lib.util.MemoryUtil; | import fr.pandacube.lib.util.MemoryUtil; | ||||||
| import fr.pandacube.lib.util.MemoryUtil.MemoryUnit; | import fr.pandacube.lib.util.MemoryUtil.MemoryUnit; | ||||||
| import fr.pandacube.lib.util.TimeUtil; | import fr.pandacube.lib.util.TimeUtil; | ||||||
|  | import fr.pandacube.lib.util.log.Log; | ||||||
| import net.kyori.adventure.bossbar.BossBar; | import net.kyori.adventure.bossbar.BossBar; | ||||||
| import net.kyori.adventure.bossbar.BossBar.Color; | import net.kyori.adventure.bossbar.BossBar.Color; | ||||||
| import net.kyori.adventure.bossbar.BossBar.Overlay; | import net.kyori.adventure.bossbar.BossBar.Overlay; | ||||||
| import net.kyori.adventure.text.format.NamedTextColor; | import net.kyori.adventure.text.format.NamedTextColor; | ||||||
| import net.kyori.adventure.text.format.TextColor; | import net.kyori.adventure.text.format.TextColor; | ||||||
| import net.md_5.bungee.api.ChatColor; |  | ||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
| import org.bukkit.command.CommandSender; | import org.bukkit.command.CommandSender; | ||||||
| import org.bukkit.command.ConsoleCommandSender; | import org.bukkit.command.ConsoleCommandSender; | ||||||
| @@ -45,10 +43,17 @@ import static fr.pandacube.lib.chat.ChatStatic.infoText; | |||||||
| import static fr.pandacube.lib.chat.ChatStatic.successText; | import static fr.pandacube.lib.chat.ChatStatic.successText; | ||||||
| import static fr.pandacube.lib.chat.ChatStatic.text; | import static fr.pandacube.lib.chat.ChatStatic.text; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Various tools to supervise the JVM RAM and the CPU usage of the main server thread. | ||||||
|  |  */ | ||||||
| public class PerformanceAnalysisManager implements Listener { | public class PerformanceAnalysisManager implements Listener { | ||||||
|  |  | ||||||
| 	private static PerformanceAnalysisManager instance; | 	private static PerformanceAnalysisManager instance; | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Gets the instance of {@link PerformanceAnalysisManager}. | ||||||
|  | 	 * @return the instance of {@link PerformanceAnalysisManager}. | ||||||
|  | 	 */ | ||||||
| 	public static synchronized PerformanceAnalysisManager getInstance() { | 	public static synchronized PerformanceAnalysisManager getInstance() { | ||||||
| 		if (instance == null) | 		if (instance == null) | ||||||
| 			instance = new PerformanceAnalysisManager(); | 			instance = new PerformanceAnalysisManager(); | ||||||
| @@ -77,14 +82,22 @@ public class PerformanceAnalysisManager implements Listener { | |||||||
| 	private final LinkedList<Long> interTPSDurations = new LinkedList<>(); | 	private final LinkedList<Long> interTPSDurations = new LinkedList<>(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * The boss bar that shows in real time the CPU performance of the main server thread. | ||||||
|  | 	 */ | ||||||
| 	public final AutoUpdatedBossBar tpsBar; | 	public final AutoUpdatedBossBar tpsBar; | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * The boss bar that shows in real time the JVM RAM usage. | ||||||
|  | 	 */ | ||||||
| 	public final AutoUpdatedBossBar memoryBar; | 	public final AutoUpdatedBossBar memoryBar; | ||||||
| 	private final List<Player> barPlayers = new ArrayList<>(); | 	private final List<Player> barPlayers = new ArrayList<>(); | ||||||
| 	private final List<BossBar> relatedBossBars = new ArrayList<>(); | 	private final List<BossBar> relatedBossBars = new ArrayList<>(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * The gradient of color covering the common range of TPS values. | ||||||
|  | 	 */ | ||||||
| 	public final ChatColorGradient tps1sGradient = new ChatColorGradient() | 	public final ChatColorGradient tps1sGradient = new ChatColorGradient() | ||||||
| 			.add(0, NamedTextColor.BLACK) | 			.add(0, NamedTextColor.BLACK) | ||||||
| 			.add(1, NamedTextColor.DARK_RED) | 			.add(1, NamedTextColor.DARK_RED) | ||||||
| @@ -95,23 +108,7 @@ public class PerformanceAnalysisManager implements Listener { | |||||||
| 			.add(21, PandaTheme.CHAT_GREEN_1_NORMAL) | 			.add(21, PandaTheme.CHAT_GREEN_1_NORMAL) | ||||||
| 			.add(26, NamedTextColor.BLUE); | 			.add(26, NamedTextColor.BLUE); | ||||||
|  |  | ||||||
|  | 	private final ChatColorGradient memoryUsageGradient = new ChatColorGradient() | ||||||
| 	public final ChatColorGradient tps10sGradient = new ChatColorGradient() |  | ||||||
| 			.add(0, NamedTextColor.DARK_RED) |  | ||||||
| 			.add(5, NamedTextColor.RED) |  | ||||||
| 			.add(10, NamedTextColor.GOLD) |  | ||||||
| 			.add(14, NamedTextColor.YELLOW) |  | ||||||
| 			.add(19, PandaTheme.CHAT_GREEN_1_NORMAL); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	public final ChatColorGradient tps1mGradient = new ChatColorGradient() |  | ||||||
| 			.add(0, NamedTextColor.DARK_RED) |  | ||||||
| 			.add(8, NamedTextColor.RED) |  | ||||||
| 			.add(14, NamedTextColor.GOLD) |  | ||||||
| 			.add(17, NamedTextColor.YELLOW) |  | ||||||
| 			.add(19, PandaTheme.CHAT_GREEN_1_NORMAL); |  | ||||||
|  |  | ||||||
| 	public final ChatColorGradient memoryUsageGradient = new ChatColorGradient() |  | ||||||
| 			.add(.60f, PandaTheme.CHAT_GREEN_1_NORMAL) | 			.add(.60f, PandaTheme.CHAT_GREEN_1_NORMAL) | ||||||
| 			.add(.70f, NamedTextColor.YELLOW) | 			.add(.70f, NamedTextColor.YELLOW) | ||||||
| 			.add(.80f, NamedTextColor.GOLD) | 			.add(.80f, NamedTextColor.GOLD) | ||||||
| @@ -133,10 +130,19 @@ public class PerformanceAnalysisManager implements Listener { | |||||||
| 		 | 		 | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Tells if the provided players is seeing the performance boss bars. | ||||||
|  | 	 * @param p the player to verify. | ||||||
|  | 	 * @return true if the provided players is seeing the performance boss bars, false otherwise. | ||||||
|  | 	 */ | ||||||
| 	public boolean barsContainsPlayer(Player p) { | 	public boolean barsContainsPlayer(Player p) { | ||||||
| 		return barPlayers.contains(p); | 		return barPlayers.contains(p); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Shows the performance boss bars to the provided player. | ||||||
|  | 	 * @param p the player. | ||||||
|  | 	 */ | ||||||
| 	public synchronized void addPlayerToBars(Player p) { | 	public synchronized void addPlayerToBars(Player p) { | ||||||
| 		barPlayers.add(p); | 		barPlayers.add(p); | ||||||
| 		p.showBossBar(tpsBar.bar); | 		p.showBossBar(tpsBar.bar); | ||||||
| @@ -145,6 +151,10 @@ public class PerformanceAnalysisManager implements Listener { | |||||||
| 			p.showBossBar(bar); | 			p.showBossBar(bar); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Hides the performance boss bars from the provided player. | ||||||
|  | 	 * @param p the player. | ||||||
|  | 	 */ | ||||||
| 	public synchronized void removePlayerToBars(Player p) { | 	public synchronized void removePlayerToBars(Player p) { | ||||||
| 		p.hideBossBar(tpsBar.bar); | 		p.hideBossBar(tpsBar.bar); | ||||||
| 		p.hideBossBar(memoryBar.bar); | 		p.hideBossBar(memoryBar.bar); | ||||||
| @@ -153,6 +163,10 @@ public class PerformanceAnalysisManager implements Listener { | |||||||
| 		barPlayers.remove(p); | 		barPlayers.remove(p); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Show an additional boss bar to the players currently seeing the performance ones. | ||||||
|  | 	 * @param bar the new bar to show. | ||||||
|  | 	 */ | ||||||
| 	public synchronized void addBossBar(BossBar bar) { | 	public synchronized void addBossBar(BossBar bar) { | ||||||
| 		if (relatedBossBars.contains(bar)) | 		if (relatedBossBars.contains(bar)) | ||||||
| 			return; | 			return; | ||||||
| @@ -161,6 +175,10 @@ public class PerformanceAnalysisManager implements Listener { | |||||||
| 			p.showBossBar(bar); | 			p.showBossBar(bar); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Hides an additional boss bar from the players currently seeing the performance ones. | ||||||
|  | 	 * @param bar the additional bar to hide. | ||||||
|  | 	 */ | ||||||
| 	public synchronized void removeBossBar(BossBar bar) { | 	public synchronized void removeBossBar(BossBar bar) { | ||||||
| 		if (!relatedBossBars.contains(bar)) | 		if (!relatedBossBars.contains(bar)) | ||||||
| 			return; | 			return; | ||||||
| @@ -169,7 +187,10 @@ public class PerformanceAnalysisManager implements Listener { | |||||||
| 			p.hideBossBar(bar); | 			p.hideBossBar(bar); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public synchronized void cancelInternalBossBar() { | 	/** | ||||||
|  | 	 * De-initialize the performance analyzer. | ||||||
|  | 	 */ | ||||||
|  | 	public synchronized void deinit() { | ||||||
| 		tpsBar.cancel(); | 		tpsBar.cancel(); | ||||||
| 		memoryBar.cancel(); | 		memoryBar.cancel(); | ||||||
| 	} | 	} | ||||||
| @@ -179,7 +200,7 @@ public class PerformanceAnalysisManager implements Listener { | |||||||
| 	 | 	 | ||||||
| 	 | 	 | ||||||
| 	@EventHandler | 	@EventHandler | ||||||
| 	public synchronized void onTickStart(ServerTickStartEvent event) { | 	synchronized void onTickStart(ServerTickStartEvent event) { | ||||||
| 		tickStartNanoTime = System.nanoTime(); | 		tickStartNanoTime = System.nanoTime(); | ||||||
| 		tickStartCPUTime = threadMXBean.isThreadCpuTimeSupported() ? threadMXBean.getCurrentThreadCpuTime() : 0; | 		tickStartCPUTime = threadMXBean.isThreadCpuTimeSupported() ? threadMXBean.getCurrentThreadCpuTime() : 0; | ||||||
| 		 | 		 | ||||||
| @@ -187,7 +208,7 @@ public class PerformanceAnalysisManager implements Listener { | |||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	@EventHandler | 	@EventHandler | ||||||
| 	public synchronized void onTickEnd(ServerTickEndEvent event) { | 	synchronized void onTickEnd(ServerTickEndEvent event) { | ||||||
| 		tickEndNanoTime = System.nanoTime(); | 		tickEndNanoTime = System.nanoTime(); | ||||||
| 		long tickEndCPUTime = threadMXBean.isThreadCpuTimeSupported() ? threadMXBean.getCurrentThreadCpuTime() : 0; | 		long tickEndCPUTime = threadMXBean.isThreadCpuTimeSupported() ? threadMXBean.getCurrentThreadCpuTime() : 0; | ||||||
| 		 | 		 | ||||||
| @@ -214,7 +235,7 @@ public class PerformanceAnalysisManager implements Listener { | |||||||
|  |  | ||||||
| 	 | 	 | ||||||
| 	@EventHandler | 	@EventHandler | ||||||
| 	public void onPlayerJoin(PlayerJoinEvent event) { | 	void onPlayerJoin(PlayerJoinEvent event) { | ||||||
| 		plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> { | 		plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> { | ||||||
| 			@SuppressWarnings("unchecked") | 			@SuppressWarnings("unchecked") | ||||||
| 			AbstractPlayerManager<PaperOnlinePlayer, PaperOffPlayer> playerManager = (AbstractPlayerManager<PaperOnlinePlayer, PaperOffPlayer>) AbstractPlayerManager.getInstance(); | 			AbstractPlayerManager<PaperOnlinePlayer, PaperOffPlayer> playerManager = (AbstractPlayerManager<PaperOnlinePlayer, PaperOffPlayer>) AbstractPlayerManager.getInstance(); | ||||||
| @@ -234,7 +255,7 @@ public class PerformanceAnalysisManager implements Listener { | |||||||
|  |  | ||||||
|  |  | ||||||
| 	@EventHandler | 	@EventHandler | ||||||
| 	public void onPlayerQuit(PlayerQuitEvent event) { | 	void onPlayerQuit(PlayerQuitEvent event) { | ||||||
| 		removePlayerToBars(event.getPlayer()); | 		removePlayerToBars(event.getPlayer()); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -299,15 +320,17 @@ public class PerformanceAnalysisManager implements Listener { | |||||||
| 					 | 					 | ||||||
| 					// keep the legacy text when generating the bar to save space when converting to component | 					// keep the legacy text when generating the bar to save space when converting to component | ||||||
| 					StringBuilder s = new StringBuilder(); | 					StringBuilder s = new StringBuilder(); | ||||||
| 					ChatColor prevC = ChatColor.RESET; | 					TextColor prevC = null; | ||||||
| 					for (int i = 58; i >= 0; i--) { | 					for (int i = 58; i >= 0; i--) { | ||||||
| 						int t = tpsHistory[i]; | 						int t = tpsHistory[i]; | ||||||
| 						ChatColor newC = ChatColorUtil.toBungee(tps1sGradient.pickColorAt(t)); | 						TextColor newC = tps1sGradient.pickColorAt(t); | ||||||
| 						if (!newC.equals(prevC)) { | 						if (!newC.equals(prevC)) { | ||||||
| 							s.append(newC); | 							s.append(text("|").color(newC).getLegacyText()); | ||||||
| 							prevC = newC; | 							prevC = newC; | ||||||
| 						} | 						} | ||||||
| 						s.append("|"); | 						else { | ||||||
|  | 							s.append("|"); | ||||||
|  | 						} | ||||||
| 					} | 					} | ||||||
| 					 | 					 | ||||||
| 					 | 					 | ||||||
| @@ -375,6 +398,10 @@ public class PerformanceAnalysisManager implements Listener { | |||||||
| 	 | 	 | ||||||
| 	private Chat alteredTPSTitle = null; | 	private Chat alteredTPSTitle = null; | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Temporary change the title of the TPS boss bar. | ||||||
|  | 	 * @param title the title override. null to restore to the normal TPS title. | ||||||
|  | 	 */ | ||||||
| 	public synchronized void setAlteredTPSTitle(Chat title) { | 	public synchronized void setAlteredTPSTitle(Chat title) { | ||||||
| 		alteredTPSTitle = title; | 		alteredTPSTitle = title; | ||||||
| 	} | 	} | ||||||
| @@ -385,17 +412,19 @@ public class PerformanceAnalysisManager implements Listener { | |||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	// special case where the getTPS method always returns a whole number when retrieving the TPS for 1 sec | 	/** | ||||||
|  | 	 * Gets the number of tick in the last second. | ||||||
|  | 	 * @return the number of tick in the last second. | ||||||
|  | 	 */ | ||||||
| 	public int getTPS1s() { | 	public int getTPS1s() { | ||||||
| 		return (int) getTPS(1_000); | 		return (int) getTPS(1_000); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 *  |  | ||||||
| 	 * @param nbTicks number of ticks when the avg value is computed from history | 	 * @param nbTicks number of ticks when the avg value is computed from history | ||||||
| 	 * @return the avg number of TPS in the interval | 	 * @return the avg number of TPS in the interval | ||||||
| 	 */ | 	 */ | ||||||
| 	public synchronized float getAvgNano(List<Long> data, int nbTicks) { | 	private synchronized float getAvgNano(List<Long> data, int nbTicks) { | ||||||
| 		if (data.isEmpty()) | 		if (data.isEmpty()) | ||||||
| 			return 0; | 			return 0; | ||||||
|  |  | ||||||
| @@ -409,7 +438,7 @@ public class PerformanceAnalysisManager implements Listener { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 *  | 	 * Gets the average number of tick per second in the n last milliseconds. | ||||||
| 	 * @param nbMillis number of milliseconds when the avg TPS is computed from history | 	 * @param nbMillis number of milliseconds when the avg TPS is computed from history | ||||||
| 	 * @return the avg number of TPS in the interval | 	 * @return the avg number of TPS in the interval | ||||||
| 	 */ | 	 */ | ||||||
| @@ -430,6 +459,10 @@ public class PerformanceAnalysisManager implements Listener { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Gets the history of TPS performance. | ||||||
|  | 	 * @return an array of TPS values from the last minute. The value at 0 is in the last second (current second on the clock - 1), the value at index 1 is now - 2, ... | ||||||
|  | 	 */ | ||||||
| 	public synchronized int[] getTPSHistory() { | 	public synchronized int[] getTPSHistory() { | ||||||
| 		int[] history = new int[60]; | 		int[] history = new int[60]; | ||||||
|  |  | ||||||
| @@ -447,15 +480,22 @@ public class PerformanceAnalysisManager implements Listener { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Gets the current server's target tick rate. | ||||||
|  | 	 * Usually 20 but the server can be configured to tick at a different rate. | ||||||
|  | 	 * @return the current server's target tick rate. | ||||||
|  | 	 */ | ||||||
| 	public static int getTargetTickRate() { | 	public static int getTargetTickRate() { | ||||||
| 		return Math.round(Bukkit.getServerTickManager().getTickRate()); | 		return Math.round(Bukkit.getServerTickManager().getTickRate()); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
| 	 | 	/** | ||||||
| 	 | 	 * Runs the garbage collector on the server. | ||||||
| 	 | 	 * Depending on the server load and the used memory, this can freeze the server for a second. | ||||||
|  | 	 * @param sender the command sender that triggers the garbase collector. Can be null (the report will be sent to the | ||||||
|  | 	 *               console) | ||||||
|  | 	 */ | ||||||
| 	public static void gc(CommandSender sender) { | 	public static void gc(CommandSender sender) { | ||||||
| 		long t1 = System.currentTimeMillis(); | 		long t1 = System.currentTimeMillis(); | ||||||
| 		long alloc1 = Runtime.getRuntime().totalMemory(); | 		long alloc1 = Runtime.getRuntime().totalMemory(); | ||||||
| @@ -477,7 +517,7 @@ public class PerformanceAnalysisManager implements Listener { | |||||||
| 			Log.info(finalMessage.getLegacyText()); | 			Log.info(finalMessage.getLegacyText()); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public static String displayRound10(double val) { | 	private static String displayRound10(double val) { | ||||||
| 		long v = (long) Math.ceil(val * 10); | 		long v = (long) Math.ceil(val * 10); | ||||||
| 		return "" + (v / 10f); | 		return "" + (v / 10f); | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -1,14 +1,10 @@ | |||||||
| package fr.pandacube.lib.paper.players; | package fr.pandacube.lib.paper.players; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.util.PrimaryWorlds; | import fr.pandacube.lib.paper.world.PrimaryWorlds; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.craftbukkit.CraftServer; | import fr.pandacube.lib.paper.reflect.wrapper.craftbukkit.CraftServer; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.dataconverter.MCDataConverter; |  | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.dataconverter.MCTypeRegistry; |  | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.SharedConstants; |  | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.CompoundTag; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.CompoundTag; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.NbtIo; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.NbtIo; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.Tag; | import fr.pandacube.lib.paper.players.PlayerDataWrapper.PlayerDataLoadException; | ||||||
| import fr.pandacube.lib.paper.util.PlayerDataWrapper; |  | ||||||
| import fr.pandacube.lib.paper.world.WorldUtil; | import fr.pandacube.lib.paper.world.WorldUtil; | ||||||
| import fr.pandacube.lib.players.standalone.AbstractOffPlayer; | import fr.pandacube.lib.players.standalone.AbstractOffPlayer; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | ||||||
| @@ -119,26 +115,31 @@ public interface PaperOffPlayer extends AbstractOffPlayer { | |||||||
|      * Player config |      * Player config | ||||||
|      */ |      */ | ||||||
|  |  | ||||||
|  |     @SuppressWarnings("RedundantThrows") // may be thrown by concrete implementation | ||||||
|     @Override |     @Override | ||||||
|     default String getConfig(String key) throws Exception { |     default String getConfig(String key) throws Exception { | ||||||
|         return PaperPlayerConfigStorage.get(getUniqueId(), key); |         return PaperPlayerConfigStorage.get(getUniqueId(), key); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @SuppressWarnings("RedundantThrows") // may be thrown by concrete implementation | ||||||
|     @Override |     @Override | ||||||
|     default String getConfig(String key, String deflt) throws Exception { |     default String getConfig(String key, String deflt) throws Exception { | ||||||
|         return PaperPlayerConfigStorage.get(getUniqueId(), key, deflt); |         return PaperPlayerConfigStorage.get(getUniqueId(), key, deflt); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @SuppressWarnings("RedundantThrows") // may be thrown by concrete implementation | ||||||
|     @Override |     @Override | ||||||
|     default void setConfig(String key, String value) throws Exception { |     default void setConfig(String key, String value) throws Exception { | ||||||
|         PaperPlayerConfigStorage.set(getUniqueId(), key, value); |         PaperPlayerConfigStorage.set(getUniqueId(), key, value); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @SuppressWarnings("RedundantThrows") // may be thrown by concrete implementation | ||||||
|     @Override |     @Override | ||||||
|     default void updateConfig(String key, String deflt, UnaryOperator<String> updater) throws Exception { |     default void updateConfig(String key, String deflt, UnaryOperator<String> updater) throws Exception { | ||||||
|         PaperPlayerConfigStorage.update(getUniqueId(), key, deflt, updater); |         PaperPlayerConfigStorage.update(getUniqueId(), key, deflt, updater); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @SuppressWarnings("RedundantThrows") // may be thrown by concrete implementation | ||||||
|     @Override |     @Override | ||||||
|     default void unsetConfig(String key) throws Exception { |     default void unsetConfig(String key) throws Exception { | ||||||
|         PaperPlayerConfigStorage.unset(getUniqueId(), key); |         PaperPlayerConfigStorage.unset(getUniqueId(), key); | ||||||
| @@ -154,29 +155,21 @@ public interface PaperOffPlayer extends AbstractOffPlayer { | |||||||
|     /** |     /** | ||||||
|      * Gets the NBT data from the player-data file. |      * Gets the NBT data from the player-data file. | ||||||
|      * It will not work if the player is online, because the data on the file are not synchronized with real-time values. |      * 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, or null if the file does not exist. | ||||||
|      * @return the NBT data from the player-data file, or null if the file does not exists. |  | ||||||
|      * @throws IllegalStateException if the player is online. |      * @throws IllegalStateException if the player is online. | ||||||
|      * @throws IOException if an error occurs reading the data. |  | ||||||
|      */ |      */ | ||||||
|     default CompoundTag getPlayerData(boolean convertTag) throws IOException { |     default CompoundTag getPlayerData() { | ||||||
|         if (isOnline()) |         if (isOnline()) | ||||||
|             throw new IllegalStateException("Cannot access data file of " + getName() + " because they’re online."); |             throw new IllegalStateException("Cannot access data file of " + getName() + " because they're online."); | ||||||
|         CompoundTag data = ReflectWrapper.wrapTyped(Bukkit.getServer(), CraftServer.class) |         try { | ||||||
|                 .getServer() |             return ReflectWrapper.wrapTyped(Bukkit.getServer(), CraftServer.class) | ||||||
|                 .getPlayerList() |                     .getServer() | ||||||
|                 .playerIo() |                     .getPlayerList() | ||||||
|                 .getPlayerData(getUniqueId().toString()); |                     .playerIo() | ||||||
|         if (data != null && convertTag) { |                     .load(getName(), getUniqueId().toString()).orElse(null); | ||||||
|             int srcVersion = data.contains("DataVersion", Tag.TAG_ANY_NUMERIC()) ? data.getInt("DataVersion") : -1; |         } catch (Exception|LinkageError e) { | ||||||
|             int destVersion = SharedConstants.getCurrentVersion().getDataVersion().getVersion(); |             throw new PlayerDataLoadException(getName(), getUniqueId(), e); | ||||||
|             try { |  | ||||||
|                 data = MCDataConverter.convertTag(MCTypeRegistry.PLAYER(), data, srcVersion, destVersion); |  | ||||||
|             } catch (Exception e) { |  | ||||||
|                 throw new IOException("Unable to upgrade data format of player " + getName() + " (" + getUniqueId() + ") from version " + destVersion + " to " + destVersion); |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|         return data; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -184,10 +177,9 @@ public interface PaperOffPlayer extends AbstractOffPlayer { | |||||||
|      * It will not work if the player is online, because the data on the file are not synchronized with real-time values. |      * 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 player-data file. | ||||||
|      * @throws IllegalStateException if the player is online. |      * @throws IllegalStateException if the player is online. | ||||||
|      * @throws IOException if an error occurs reading the data. |  | ||||||
|      */ |      */ | ||||||
|     default PlayerDataWrapper getPlayerDataWrapper() throws IOException { |     default PlayerDataWrapper getPlayerDataWrapper() { | ||||||
|         return new PlayerDataWrapper(getPlayerData(true)); |         return new PlayerDataWrapper(getPlayerData()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -213,25 +205,23 @@ public interface PaperOffPlayer extends AbstractOffPlayer { | |||||||
|      * @return the file where the player-data is stored. |      * @return the file where the player-data is stored. | ||||||
|      */ |      */ | ||||||
|     default File getPlayerDataFile(boolean old) { |     default File getPlayerDataFile(boolean old) { | ||||||
|         File playerDataDir = new File(WorldUtil.worldDir(PrimaryWorlds.PRIMARY_WORLDS.get(0)), "playerdata"); |         File playerDataDir = new File(WorldUtil.worldDir(PrimaryWorlds.PRIMARY_WORLDS.getFirst()), "playerdata"); | ||||||
|         return new File(playerDataDir, getUniqueId() + (old ? ".dat_old" : ".dat")); |         return new File(playerDataDir, getUniqueId() + (old ? ".dat_old" : ".dat")); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Gets the player’s inventory. |      * Gets the player’s inventory. | ||||||
|      * @return the player’s inventory. |      * @return the player’s inventory. | ||||||
|      * @throws IOException if an error occurs reading the data. |  | ||||||
|      */ |      */ | ||||||
|     default PlayerInventory getInventory() throws IOException { |     default PlayerInventory getInventory() { | ||||||
|         return getPlayerDataWrapper().getInventory(); |         return getPlayerDataWrapper().getInventory(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Gets the player’s enderchest. |      * Gets the player’s enderchest. | ||||||
|      * @return the player’s enderchest. |      * @return the player’s enderchest. | ||||||
|      * @throws IOException if an error occurs reading the data. |  | ||||||
|      */ |      */ | ||||||
|     default Inventory getEnderChest() throws IOException { |     default Inventory getEnderChest() { | ||||||
|         return getPlayerDataWrapper().getEnderChest(); |         return getPlayerDataWrapper().getEnderChest(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ package fr.pandacube.lib.paper.players; | |||||||
| import com.destroystokyo.paper.ClientOption; | import com.destroystokyo.paper.ClientOption; | ||||||
| import com.destroystokyo.paper.ClientOption.ChatVisibility; | import com.destroystokyo.paper.ClientOption.ChatVisibility; | ||||||
| import com.destroystokyo.paper.SkinParts; | import com.destroystokyo.paper.SkinParts; | ||||||
| import fr.pandacube.lib.paper.players.PlayerNonPersistentConfig.Expiration; | import fr.pandacube.lib.paper.players.PlayerNonPersistentConfig.ExpirationPolicy; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.craftbukkit.CraftPlayer; | import fr.pandacube.lib.paper.reflect.wrapper.craftbukkit.CraftPlayer; | ||||||
| import fr.pandacube.lib.players.standalone.AbstractOnlinePlayer; | import fr.pandacube.lib.players.standalone.AbstractOnlinePlayer; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | ||||||
| @@ -170,7 +170,7 @@ public interface PaperOnlinePlayer extends PaperOffPlayer, AbstractOnlinePlayer | |||||||
|         @Override |         @Override | ||||||
|         public boolean isChatFullyVisible() { |         public boolean isChatFullyVisible() { | ||||||
|             ChatVisibility v = getChatVisibility(); |             ChatVisibility v = getChatVisibility(); | ||||||
|             return v == ChatVisibility.FULL || v == ChatVisibility.UNKNOWN; |             return v == ChatVisibility.FULL; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         @Override |         @Override | ||||||
| @@ -283,7 +283,7 @@ public interface PaperOnlinePlayer extends PaperOffPlayer, AbstractOnlinePlayer | |||||||
|      * @param relZ the relative z coordinate. |      * @param relZ the relative z coordinate. | ||||||
|      */ |      */ | ||||||
|     default void teleportRelatively(float relX, float relY, float relZ) { |     default void teleportRelatively(float relX, float relY, float relZ) { | ||||||
|         getBukkitPlayer().teleport(getBukkitPlayer().getLocation().add(relX, relY, relZ), Relative.X, Relative.Y, Relative.Z, Relative.YAW, Relative.PITCH); |         getBukkitPlayer().teleport(getBukkitPlayer().getLocation().add(relX, relY, relZ), Relative.VELOCITY_X, Relative.VELOCITY_Y, Relative.VELOCITY_Z, Relative.VELOCITY_ROTATION); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -291,7 +291,7 @@ public interface PaperOnlinePlayer extends PaperOffPlayer, AbstractOnlinePlayer | |||||||
|      * @param destination the destination. |      * @param destination the destination. | ||||||
|      */ |      */ | ||||||
|     default void teleportRelatively(Location destination) { |     default void teleportRelatively(Location destination) { | ||||||
|         getBukkitPlayer().teleport(destination, Relative.X, Relative.Y, Relative.Z, Relative.YAW, Relative.PITCH); |         getBukkitPlayer().teleport(destination, Relative.VELOCITY_X, Relative.VELOCITY_Y, Relative.VELOCITY_Z, Relative.VELOCITY_ROTATION); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -304,18 +304,39 @@ public interface PaperOnlinePlayer extends PaperOffPlayer, AbstractOnlinePlayer | |||||||
|      * Player config |      * Player config | ||||||
|      */ |      */ | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets the non-persistent value of the provided configuration key of this player. | ||||||
|  |      * @param key the configuration key. | ||||||
|  |      * @return the value of the configuration, or null if the configuration is not set. | ||||||
|  |      */ | ||||||
|     default String getNonPersistentConfig(String key) { |     default String getNonPersistentConfig(String key) { | ||||||
|         return PlayerNonPersistentConfig.getData(getUniqueId(), key); |         return PlayerNonPersistentConfig.getData(getUniqueId(), key); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets the non-persistent value of the provided configuration key of this player. | ||||||
|  |      * @param key the configuration key. | ||||||
|  |      * @param deflt the default value if the configuration is not set. | ||||||
|  |      * @return the value of the configuration, or {@code deflt} if the configuration is not set. | ||||||
|  |      */ | ||||||
|     default String getNonPersistentConfig(String key, String deflt) { |     default String getNonPersistentConfig(String key, String deflt) { | ||||||
|         return PlayerNonPersistentConfig.getData(getUniqueId(), key); |         return PlayerNonPersistentConfig.getData(getUniqueId(), key); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     default void setNonPersistentConfig(String key, String value, Expiration expiration) { |     /** | ||||||
|         PlayerNonPersistentConfig.setData(getUniqueId(), key, value, expiration); |      * Sets the non-persistent value of the provided configuration key for this player. | ||||||
|  |      * @param key the configuration key to set. | ||||||
|  |      * @param value the new value. | ||||||
|  |      * @param expirationPolicy the expiration policy. | ||||||
|  |      */ | ||||||
|  |     default void setNonPersistentConfig(String key, String value, ExpirationPolicy expirationPolicy) { | ||||||
|  |         PlayerNonPersistentConfig.setData(getUniqueId(), key, value, expirationPolicy); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Unsets the non-persistent value of the provided configuration key for this player. | ||||||
|  |      * @param key the configuration key to update. | ||||||
|  |      */ | ||||||
|     default void unsetNonPersistentConfig(String key) { |     default void unsetNonPersistentConfig(String key) { | ||||||
|         PlayerNonPersistentConfig.unsetData(getUniqueId(), key); |         PlayerNonPersistentConfig.unsetData(getUniqueId(), key); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -16,6 +16,10 @@ import java.util.UUID; | |||||||
| import java.util.function.UnaryOperator; | import java.util.function.UnaryOperator; | ||||||
| import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Provides rudimentary player data storage using a file in the plugin configuration. | ||||||
|  |  * The file is loaded on the first access, and is auto-saved if needed every 30 seconds. | ||||||
|  |  */ | ||||||
| public class PaperPlayerConfigStorage { | public class PaperPlayerConfigStorage { | ||||||
|  |  | ||||||
|     static final File storageFile = new File(PandaLibPaper.getPlugin().getDataFolder(), "playerdata.yml"); |     static final File storageFile = new File(PandaLibPaper.getPlugin().getDataFolder(), "playerdata.yml"); | ||||||
| @@ -77,6 +81,8 @@ public class PaperPlayerConfigStorage { | |||||||
|  |  | ||||||
|  |  | ||||||
|     private static synchronized void save() { |     private static synchronized void save() { | ||||||
|  |         if (!changed) | ||||||
|  |             return; | ||||||
|         YamlConfiguration config = new YamlConfiguration(); |         YamlConfiguration config = new YamlConfiguration(); | ||||||
|         for (UUID pId : playerSortedData.keySet()) { |         for (UUID pId : playerSortedData.keySet()) { | ||||||
|             String pIdStr = pId.toString(); |             String pIdStr = pId.toString(); | ||||||
| @@ -109,11 +115,17 @@ public class PaperPlayerConfigStorage { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     public static synchronized void set(UUID player, String key, String newValue) { |     /** | ||||||
|  |      * Sets the value of the provided configuration key for the player. | ||||||
|  |      * @param player the player. | ||||||
|  |      * @param key the configuration key to set. | ||||||
|  |      * @param value the new value. | ||||||
|  |      */ | ||||||
|  |     public static synchronized void set(UUID player, String key, String value) { | ||||||
|         initIfNeeded(); |         initIfNeeded(); | ||||||
|         ConfigKey cKey = new ConfigKey(player, key); |         ConfigKey cKey = new ConfigKey(player, key); | ||||||
|         ConfigEntry e = data.get(cKey); |         ConfigEntry e = data.get(cKey); | ||||||
|         if (e != null && newValue == null) { // delete |         if (e != null && value == null) { // delete | ||||||
|             data.remove(cKey); |             data.remove(cKey); | ||||||
|             if (playerSortedData.containsKey(player)) |             if (playerSortedData.containsKey(player)) | ||||||
|                 playerSortedData.get(player).remove(e); |                 playerSortedData.get(player).remove(e); | ||||||
| @@ -121,50 +133,91 @@ public class PaperPlayerConfigStorage { | |||||||
|                 keySortedData.get(key).remove(e); |                 keySortedData.get(key).remove(e); | ||||||
|             changed = true; |             changed = true; | ||||||
|         } |         } | ||||||
|         else if (e == null && newValue != null) { // create |         else if (e == null && value != null) { // create | ||||||
|             create(player, key, newValue); |             create(player, key, value); | ||||||
|             changed = true; |             changed = true; | ||||||
|         } |         } | ||||||
|         else if (e != null && !newValue.equals(e.value)) { // update |         else if (e != null && !value.equals(e.value)) { // update | ||||||
|             e.value = newValue; |             e.value = value; | ||||||
|             changed = true; |             changed = true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets the value of the provided configuration key of the player. | ||||||
|  |      * @param player the player. | ||||||
|  |      * @param key the configuration key. | ||||||
|  |      * @return the value of the configuration, or null if the configuration is not set. | ||||||
|  |      */ | ||||||
|     public static synchronized String get(UUID player, String key) { |     public static synchronized String get(UUID player, String key) { | ||||||
|         initIfNeeded(); |         initIfNeeded(); | ||||||
|         ConfigEntry e = data.get(new ConfigKey(player, key)); |         ConfigEntry e = data.get(new ConfigKey(player, key)); | ||||||
|         return e != null ? e.value : null; |         return e != null ? e.value : null; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static String get(UUID p, String k, String deflt) { |     /** | ||||||
|         String value = get(p, k); |      * Gets the value of the provided configuration key of the player. | ||||||
|  |      * @param player the player. | ||||||
|  |      * @param key the configuration key. | ||||||
|  |      * @param deflt the default value if the configuration is not set. | ||||||
|  |      * @return the value of the configuration, or {@code deflt} if the configuration is not set. | ||||||
|  |      */ | ||||||
|  |     public static String get(UUID player, String key, String deflt) { | ||||||
|  |         String value = get(player, key); | ||||||
|         return value == null ? deflt : value; |         return value == null ? deflt : value; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static synchronized void update(UUID p, String k, String deflt, UnaryOperator<String> updater) { |     /** | ||||||
|         String oldValue = get(p, k, deflt); |      * Updates the value of the provided configuration key for the player, using the provided updater. | ||||||
|         set(p, k, updater.apply(oldValue)); |      * @param player the player. | ||||||
|  |      * @param key the configuration key to update. | ||||||
|  |      * @param deflt the default value to use if the configuration is not already set. | ||||||
|  |      * @param updater the unary operator to use to update th value. The old value is used as the parameter of the updater, | ||||||
|  |      *                and it returns the new value of the configuration. | ||||||
|  |      */ | ||||||
|  |     public static synchronized void update(UUID player, String key, String deflt, UnaryOperator<String> updater) { | ||||||
|  |         String oldValue = get(player, key, deflt); | ||||||
|  |         set(player, key, updater.apply(oldValue)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static void unset(UUID p, String k) { |     /** | ||||||
|         set(p, k, null); |      * Unsets the value of the provided configuration key for the player. | ||||||
|  |      * @param player the player. | ||||||
|  |      * @param key the configuration key to update. | ||||||
|  |      */ | ||||||
|  |     public static void unset(UUID player, String key) { | ||||||
|  |         set(player, key, null); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|     public static LinkedHashSet<ConfigEntry> getAllFromPlayer(UUID p) { |      * Gets all the config key-value pairs of the provided player. | ||||||
|  |      * @param player the player. | ||||||
|  |      * @return all the config key-value pairs of the provided player. | ||||||
|  |      */ | ||||||
|  |     public static LinkedHashSet<ConfigEntry> getAllFromPlayer(UUID player) { | ||||||
|         initIfNeeded(); |         initIfNeeded(); | ||||||
|         return new LinkedHashSet<>(playerSortedData.getOrDefault(p, new LinkedHashSet<>())); |         return new LinkedHashSet<>(playerSortedData.getOrDefault(player, new LinkedHashSet<>())); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets all the config key-value pairs of all players that have the provided key. | ||||||
|  |      * @param key the key. | ||||||
|  |      * @return all the config key-value pairs of all players that have the provided key. | ||||||
|  |      */ | ||||||
|     public static LinkedHashSet<ConfigEntry> getAllWithKeys(String key) { |     public static LinkedHashSet<ConfigEntry> getAllWithKeys(String key) { | ||||||
|         initIfNeeded(); |         initIfNeeded(); | ||||||
|         return new LinkedHashSet<>(keySortedData.getOrDefault(key, new LinkedHashSet<>())); |         return new LinkedHashSet<>(keySortedData.getOrDefault(key, new LinkedHashSet<>())); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static LinkedHashSet<ConfigEntry> getAllWithKeyValue(String k, String v) { |     /** | ||||||
|  |      * Gets all the config key-value pairs of all players that have the provided key AND value. | ||||||
|  |      * @param key the key. | ||||||
|  |      * @param v the value. | ||||||
|  |      * @return all the config key-value pairs of all players that have the provided key AND value. | ||||||
|  |      */ | ||||||
|  |     public static LinkedHashSet<ConfigEntry> getAllWithKeyValue(String key, String v) { | ||||||
|         initIfNeeded(); |         initIfNeeded(); | ||||||
|         return getAllWithKeys(k).stream() |         return getAllWithKeys(key).stream() | ||||||
|                 .filter(c -> c.value.equals(v)) |                 .filter(c -> c.value.equals(v)) | ||||||
|                 .collect(Collectors.toCollection(LinkedHashSet::new)); |                 .collect(Collectors.toCollection(LinkedHashSet::new)); | ||||||
|     } |     } | ||||||
| @@ -173,25 +226,46 @@ public class PaperPlayerConfigStorage { | |||||||
|  |  | ||||||
|     private record ConfigKey(UUID playerId, String key) { } |     private record ConfigKey(UUID playerId, String key) { } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Class holding the playerId-key-value triplet. | ||||||
|  |      */ | ||||||
|     public static class ConfigEntry { |     public static class ConfigEntry { | ||||||
|         private final UUID playerId; |         private final UUID playerId; | ||||||
|         private final String key; |         private final String key; | ||||||
|         private String value; |         private String value; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Creates a new {@link ConfigEntry}. | ||||||
|  |          * @param playerId the player id. | ||||||
|  |          * @param key the key. | ||||||
|  |          * @param value the value. | ||||||
|  |          */ | ||||||
|         private ConfigEntry(UUID playerId, String key, String value) { |         private ConfigEntry(UUID playerId, String key, String value) { | ||||||
|             this.playerId = playerId; |             this.playerId = playerId; | ||||||
|             this.key = key; |             this.key = key; | ||||||
|             this.value = value; |             this.value = value; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Gets the player id. | ||||||
|  |          * @return the player id. | ||||||
|  |          */ | ||||||
|         public UUID getPlayerId() { |         public UUID getPlayerId() { | ||||||
|             return playerId; |             return playerId; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Gets the config key. | ||||||
|  |          * @return the config key. | ||||||
|  |          */ | ||||||
|         public String getKey() { |         public String getKey() { | ||||||
|             return key; |             return key; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Gets the config value. | ||||||
|  |          * @return the config value. | ||||||
|  |          */ | ||||||
|         public String getValue() { |         public String getValue() { | ||||||
|             return value; |             return value; | ||||||
|         } |         } | ||||||
| @@ -208,4 +282,7 @@ public class PaperPlayerConfigStorage { | |||||||
|                     && Objects.equals(key, o.key); |                     && Objects.equals(key, o.key); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     private PaperPlayerConfigStorage() {} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,236 @@ | |||||||
|  | package fr.pandacube.lib.paper.players; | ||||||
|  |  | ||||||
|  | import fr.pandacube.lib.paper.inventory.DummyPlayerInventory; | ||||||
|  | import fr.pandacube.lib.paper.reflect.wrapper.craftbukkit.CraftItemStack; | ||||||
|  | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.CompoundTag; | ||||||
|  | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.ListTag; | ||||||
|  | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.Tag; | ||||||
|  | import fr.pandacube.lib.paper.util.ExperienceUtil; | ||||||
|  | import org.bukkit.Bukkit; | ||||||
|  | import org.bukkit.event.inventory.InventoryType; | ||||||
|  | import org.bukkit.inventory.Inventory; | ||||||
|  | import org.bukkit.inventory.ItemStack; | ||||||
|  | import org.bukkit.inventory.PlayerInventory; | ||||||
|  |  | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.Map.Entry; | ||||||
|  | import java.util.TreeMap; | ||||||
|  | import java.util.UUID; | ||||||
|  | import java.util.function.IntUnaryOperator; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * A wrapper to easily manipulate the player data file. | ||||||
|  |  * | ||||||
|  |  * @param data The NBT data structure as it is stored in the player file. | ||||||
|  |  */ | ||||||
|  | public record PlayerDataWrapper(CompoundTag data) { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Creates a new wrapper for the provided player data. | ||||||
|  |      * @param data the NBT data to wrap. | ||||||
|  |      */ | ||||||
|  |     public PlayerDataWrapper(CompoundTag data) { | ||||||
|  |         this.data = data == null ? new CompoundTag() : data; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets a snapshot of the inventory of this player. | ||||||
|  |      * If the inventory is modified, the {@link #setInventory(PlayerInventory)} method should be called to update the | ||||||
|  |      * data in this wrapper. | ||||||
|  |      * @return the player inventory. | ||||||
|  |      */ | ||||||
|  |     public PlayerInventory getInventory() { | ||||||
|  |         return new DummyPlayerInventory( | ||||||
|  |                 getBukkitInventory("Inventory", InventoryType.PLAYER, this::fromNBTtoBukkitInventorySlot), | ||||||
|  |                 getHeldItemSlot()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private int fromNBTtoBukkitInventorySlot(int nbtSlot) { | ||||||
|  |         // cat   nbEl    NBTSlot      bukkitSlot  NBT->Bukkit | ||||||
|  |         // items   36                    0-35     == | ||||||
|  |         // armor    4  starts at 100    36-39     -100 + 36 | ||||||
|  |         // offhand  1  starts at 150      40      -150 + 40 | ||||||
|  |         if (nbtSlot >= 0 && nbtSlot < 36) { // regular inventory slots | ||||||
|  |             return nbtSlot; | ||||||
|  |         } | ||||||
|  |         if (nbtSlot >= 100 && nbtSlot < 104) { // armor slots | ||||||
|  |             return nbtSlot - 100 + 36; | ||||||
|  |         } | ||||||
|  |         if (nbtSlot == 150) { // second hand | ||||||
|  |             return 40; | ||||||
|  |         } | ||||||
|  |         throw new IllegalArgumentException("Unrecognized NBT player inventory slot " + nbtSlot); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Sets the player inventory to the content of the provided one. | ||||||
|  |      * The internal data of this wrapper will be updated. | ||||||
|  |      * @param inv the inventory to store in this player data in place of the old one. | ||||||
|  |      */ | ||||||
|  |     public void setInventory(PlayerInventory inv) { | ||||||
|  |         setBukkitInventory("Inventory", inv, this::fromBukkitToNBTInventorySlot); | ||||||
|  |         setHeldItemSlot(inv.getHeldItemSlot()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private int fromBukkitToNBTInventorySlot(int bukkitSlot) { | ||||||
|  |         if (bukkitSlot >= 0 && bukkitSlot < 36) { // regular inventory slots | ||||||
|  |             return bukkitSlot; | ||||||
|  |         } | ||||||
|  |         if (bukkitSlot >= 36 && bukkitSlot < 40) { // armor slots | ||||||
|  |             return bukkitSlot + 100 - 36; | ||||||
|  |         } | ||||||
|  |         if (bukkitSlot == 40) { // second hand | ||||||
|  |             return 150; | ||||||
|  |         } | ||||||
|  |         throw new IllegalArgumentException("Unrecognized Bukkit player inventory slot " + bukkitSlot); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets a snapshot of the enderchest of this player. | ||||||
|  |      * If the enderchest is modified, the {@link #setEnderChest(Inventory)} method should be called to update the | ||||||
|  |      * data in this wrapper. | ||||||
|  |      * @return the player enderchest. | ||||||
|  |      */ | ||||||
|  |     public Inventory getEnderChest() { | ||||||
|  |         return getBukkitInventory("EnderItems", InventoryType.ENDER_CHEST, IntUnaryOperator.identity()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Sets the player enderchest to the content of the provided one. | ||||||
|  |      * The internal data of this wrapper will be updated. | ||||||
|  |      * @param inv the enderchest content to store in this player data in place of the old enderchest. | ||||||
|  |      */ | ||||||
|  |     public void setEnderChest(Inventory inv) { | ||||||
|  |         setBukkitInventory("EnderItems", inv, IntUnaryOperator.identity()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     private Inventory getBukkitInventory(String nbtKey, InventoryType bukkitType, IntUnaryOperator nbtToBukkitSlotConverter) { | ||||||
|  |         Map<Integer, ItemStack> stacks = getRawInventoryContent(nbtKey); | ||||||
|  |         Inventory inv = Bukkit.createInventory(null, bukkitType); | ||||||
|  |         if (stacks.isEmpty()) | ||||||
|  |             return inv; | ||||||
|  |         for (Entry<Integer, ItemStack> is : stacks.entrySet()) { | ||||||
|  |             inv.setItem(nbtToBukkitSlotConverter.applyAsInt(is.getKey()), is.getValue()); | ||||||
|  |         } | ||||||
|  |         return inv; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private Map<Integer, ItemStack> getRawInventoryContent(String key) { | ||||||
|  |         if (!data.contains(key, Tag.TAG_LIST())) | ||||||
|  |             return Map.of(); | ||||||
|  |         ListTag list = data.getList(key, Tag.TAG_COMPOUND()); | ||||||
|  |         if (list == null) | ||||||
|  |             return Map.of(); | ||||||
|  |  | ||||||
|  |         Map<Integer, ItemStack> stacks = new TreeMap<>(); | ||||||
|  |         for (int i = 0; i < list.size(); i++) { | ||||||
|  |             CompoundTag itemTag = list.getCompound(i); | ||||||
|  |             int nbtSlot = itemTag.getByte("Slot") & 255; | ||||||
|  |             fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.ItemStack.parse(itemTag) | ||||||
|  |                     .map(nms -> filterStack(CraftItemStack.asCraftMirror(nms))) | ||||||
|  |                     .ifPresent(is -> stacks.put(nbtSlot, is)); | ||||||
|  |         } | ||||||
|  |         return stacks; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     private void setBukkitInventory(String nbtKey, Inventory inv, IntUnaryOperator bukkitToNBTSlotConverter) { | ||||||
|  |         Map<Integer, ItemStack> stacks = new TreeMap<>(); | ||||||
|  |         if (inv == null) { | ||||||
|  |             setRawInventoryContent(nbtKey, stacks); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         for (int bukkitSlot = 0; bukkitSlot < inv.getSize(); bukkitSlot++) { | ||||||
|  |             ItemStack is = filterStack(inv.getItem(bukkitSlot)); | ||||||
|  |             if (is == null) | ||||||
|  |                 continue; | ||||||
|  |             int nbtSlot = bukkitToNBTSlotConverter.applyAsInt(bukkitSlot); | ||||||
|  |             stacks.put(nbtSlot, is); | ||||||
|  |         } | ||||||
|  |         setRawInventoryContent(nbtKey, stacks); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void setRawInventoryContent(String key, Map<Integer, ItemStack> stacks) { | ||||||
|  |         ListTag list = new ListTag(); | ||||||
|  |         for (Entry<Integer, ItemStack> is : stacks.entrySet()) { | ||||||
|  |             ItemStack stack = filterStack(is.getValue()); | ||||||
|  |             if (stack == null) | ||||||
|  |                 continue; | ||||||
|  |             CompoundTag itemTag = new CompoundTag(); | ||||||
|  |             itemTag.putByte("Slot", is.getKey().byteValue()); | ||||||
|  |             list.add(list.size(), CraftItemStack.asNMSCopy(is.getValue()).save(itemTag)); | ||||||
|  |         } | ||||||
|  |         data.put(key, list); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     private ItemStack filterStack(ItemStack is) { | ||||||
|  |         return is == null || is.getType().isEmpty() || is.getAmount() == 0 ? null : is; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     private int getHeldItemSlot() { | ||||||
|  |         if (!data.contains("SelectedItemSlot")) | ||||||
|  |             return 0; | ||||||
|  |         return data.getInt("SelectedItemSlot"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void setHeldItemSlot(int slot) { | ||||||
|  |         data.putInt("SelectedItemSlot", slot); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets the score of the player, as stored in the data with the key {@code Score}. | ||||||
|  |      * @return the value of Score. | ||||||
|  |      */ | ||||||
|  |     public int getScore() { | ||||||
|  |         if (!data.contains("Score")) | ||||||
|  |             return 0; | ||||||
|  |         return data.getInt("Score"); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Sets the score of the player, as stored in the data with the key {@code Score}. | ||||||
|  |      * @param score the value of Score to set. | ||||||
|  |      */ | ||||||
|  |     public void setScore(int score) { | ||||||
|  |         data.putInt("Score", score); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets the total experience of the player, as stored in the data with the key {@code XpTotal}. | ||||||
|  |      * @return the value of XpTotal. | ||||||
|  |      */ | ||||||
|  |     public int getTotalExperience() { | ||||||
|  |         if (!data.contains("XpTotal")) | ||||||
|  |             return 0; | ||||||
|  |         return data.getInt("XpTotal"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Sets the total experience of the player, as stored in the data with the key {@code XpTotal}. | ||||||
|  |      * @param xp the value of XpTotal to set. | ||||||
|  |      */ | ||||||
|  |     public void setTotalExperience(int xp) { | ||||||
|  |         data.putInt("XpTotal", xp); | ||||||
|  |         double levelAndExp = ExperienceUtil.getLevelFromExp(xp); | ||||||
|  |         int level = (int) levelAndExp; | ||||||
|  |         double expProgress = levelAndExp - level; | ||||||
|  |         data.putInt("XpLevel", level); | ||||||
|  |         data.putFloat("XpP", (float) expProgress); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Thrown to indicate that an error occurred while loading the data of the player from the file. | ||||||
|  |      */ | ||||||
|  |     public static class PlayerDataLoadException extends RuntimeException { | ||||||
|  |         /* package */ PlayerDataLoadException(String playerName,  UUID playerId, Throwable cause) { | ||||||
|  |             super("Unable to load data of player " + playerName + " (" + playerId + ")", cause); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -12,6 +12,9 @@ import java.util.Map; | |||||||
| import java.util.Objects; | import java.util.Objects; | ||||||
| import java.util.UUID; | import java.util.UUID; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Handles the player related configuration that is not persisted to disk. | ||||||
|  |  */ | ||||||
| public class PlayerNonPersistentConfig { | public class PlayerNonPersistentConfig { | ||||||
|     private static final Map<UUID, Map<String, ConfigEntry>> data = new HashMap<>(); |     private static final Map<UUID, Map<String, ConfigEntry>> data = new HashMap<>(); | ||||||
|  |  | ||||||
| @@ -22,34 +25,58 @@ public class PlayerNonPersistentConfig { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     public static void setData(UUID playerId, String key, String value, Expiration expiration) { |     /** | ||||||
|         data.computeIfAbsent(Objects.requireNonNull(playerId, "playerId"), pp -> new HashMap<>()) |      * Sets the value of the provided configuration key for the player. | ||||||
|  |      * @param player the player. | ||||||
|  |      * @param key the configuration key to set. | ||||||
|  |      * @param value the new value. | ||||||
|  |      * @param expirationPolicy the expiration policy for this config. If the config key already exists for this player. the expiration will be overridden. | ||||||
|  |      */ | ||||||
|  |     public static void setData(UUID player, String key, String value, ExpirationPolicy expirationPolicy) { | ||||||
|  |         data.computeIfAbsent(Objects.requireNonNull(player, "playerId"), pp -> new HashMap<>()) | ||||||
|                 .put(Objects.requireNonNull(key, "key"), |                 .put(Objects.requireNonNull(key, "key"), | ||||||
|                         new ConfigEntry(Objects.requireNonNull(value, "value"), |                         new ConfigEntry(Objects.requireNonNull(value, "value"), | ||||||
|                                 Objects.requireNonNull(expiration, "expiration") |                                 Objects.requireNonNull(expirationPolicy, "expiration") | ||||||
|                         ) |                         ) | ||||||
|                 ); |                 ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static void unsetData(UUID playerId, String key) { |     /** | ||||||
|         data.getOrDefault(Objects.requireNonNull(playerId, "playerId"), new HashMap<>()) |      * Unsets the value of the provided configuration key for the player. | ||||||
|  |      * @param player the player. | ||||||
|  |      * @param key the configuration key to update. | ||||||
|  |      */ | ||||||
|  |     public static void unsetData(UUID player, String key) { | ||||||
|  |         data.getOrDefault(Objects.requireNonNull(player, "playerId"), new HashMap<>()) | ||||||
|                 .remove(Objects.requireNonNull(key, "key")); |                 .remove(Objects.requireNonNull(key, "key")); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static String getData(UUID playerId, String key) { |     /** | ||||||
|         Map<String, ConfigEntry> playerData = data.getOrDefault(Objects.requireNonNull(playerId, "playerId"), new HashMap<>()); |      * Gets the value of the provided configuration key of the player. | ||||||
|  |      * @param player the player. | ||||||
|  |      * @param key the configuration key. | ||||||
|  |      * @return the value of the configuration, or {@code deflt} if the configuration is not set. | ||||||
|  |      */ | ||||||
|  |     public static String getData(UUID player, String key) { | ||||||
|  |         Map<String, ConfigEntry> playerData = data.getOrDefault(Objects.requireNonNull(player, "playerId"), new HashMap<>()); | ||||||
|         ConfigEntry ce = playerData.get(Objects.requireNonNull(key, "key")); |         ConfigEntry ce = playerData.get(Objects.requireNonNull(key, "key")); | ||||||
|         if (ce == null) |         if (ce == null) | ||||||
|             return null; |             return null; | ||||||
|         if (!ce.expiration.valid(playerId, key)) { |         if (!ce.expirationPolicy.valid(player, key)) { | ||||||
|             playerData.remove(key); |             playerData.remove(key); | ||||||
|             return null; |             return null; | ||||||
|         } |         } | ||||||
|         return ce.value; |         return ce.value; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static boolean isDataSet(UUID playerId, String key) { |     /** | ||||||
|         return getData(playerId, key) != null; |      * Tells if the provided config key is set for the player. | ||||||
|  |      * @param player the player. | ||||||
|  |      * @param key the configuration key. | ||||||
|  |      * @return true if the value is set, false otherwise. | ||||||
|  |      */ | ||||||
|  |     public static boolean isDataSet(UUID player, String key) { | ||||||
|  |         return getData(player, key) != null; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -63,34 +90,76 @@ public class PlayerNonPersistentConfig { | |||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     private record ConfigEntry(String value, Expiration expiration) { } |     private record ConfigEntry(String value, ExpirationPolicy expirationPolicy) { } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Super class for all expiration policies. | ||||||
|  |      */ | ||||||
|  |     public static abstract class ExpirationPolicy { | ||||||
|  |         /** | ||||||
|  |          * Creates an expiration policy. | ||||||
|  |          */ | ||||||
|  |         public ExpirationPolicy() {} | ||||||
|  |  | ||||||
|  |         /** | ||||||
|     public static abstract class Expiration { |          * Tests if the associated configuration is still valid (not expired). | ||||||
|  |          * @param player the player. | ||||||
|  |          * @param key the configuration key. | ||||||
|  |          * @return true if the associated configuration is still valid, false otherwise. | ||||||
|  |          */ | ||||||
|         abstract boolean valid(UUID player, String key); |         abstract boolean valid(UUID player, String key); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static class ExpiresLogout extends Expiration { |     /** | ||||||
|  |      * Expiration policy for a config that expires when the player logs out. | ||||||
|  |      */ | ||||||
|  |     public static class ExpiresLogout extends ExpirationPolicy { | ||||||
|  |         /** | ||||||
|  |          * Creates a logout expiration policy. | ||||||
|  |          */ | ||||||
|  |         public ExpiresLogout() { | ||||||
|  |             super(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|         protected boolean valid(UUID player, String key) { |         protected boolean valid(UUID player, String key) { | ||||||
|             return Bukkit.getPlayer(player) != null; // should not be call if player reconnects because it is removed on player quit |             return Bukkit.getPlayer(player) != null; // should not be call if player reconnects because it is removed on player quit | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static class ExpiresTick extends Expiration { |     /** | ||||||
|  |      * Expiration policy for a config that expires after a certain amount of game tick. | ||||||
|  |      */ | ||||||
|  |     public static class ExpiresTick extends ExpirationPolicy { | ||||||
|         final long expirationTick; |         final long expirationTick; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Creates a delay expiration policy. | ||||||
|  |          * @param expirationDelayTick the number of tick after which the config will expire. If 0, will expire immediately ; 1 to expire on the next tick. | ||||||
|  |          */ | ||||||
|         public ExpiresTick(long expirationDelayTick) { |         public ExpiresTick(long expirationDelayTick) { | ||||||
|             expirationTick = tick + expirationDelayTick; |             expirationTick = tick + expirationDelayTick; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|         protected boolean valid(UUID player, String key) { |         protected boolean valid(UUID player, String key) { | ||||||
|             return tick < expirationTick; |             return tick < expirationTick; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static class ExpiresServerStop extends Expiration { |     /** | ||||||
|  |      * Expiration policy for a config that expires when the server stops. | ||||||
|  |      */ | ||||||
|  |     public static class ExpiresServerStop extends ExpirationPolicy { | ||||||
|  |         /** | ||||||
|  |          * Creates a server stop expiration policy. | ||||||
|  |          */ | ||||||
|  |         public ExpiresServerStop() { | ||||||
|  |             super(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|         protected boolean valid(UUID player, String key) { |         protected boolean valid(UUID player, String key) { | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
| @@ -103,7 +172,7 @@ public class PlayerNonPersistentConfig { | |||||||
|  |  | ||||||
|  |  | ||||||
|     private static class ConfigListeners implements Listener { |     private static class ConfigListeners implements Listener { | ||||||
|         public ConfigListeners() { |         private ConfigListeners() { | ||||||
|             Bukkit.getPluginManager().registerEvents(this, PandaLibPaper.getPlugin()); |             Bukkit.getPluginManager().registerEvents(this, PandaLibPaper.getPlugin()); | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -111,7 +180,7 @@ public class PlayerNonPersistentConfig { | |||||||
|         public void onPlayerQuit(PlayerQuitEvent event) { |         public void onPlayerQuit(PlayerQuitEvent event) { | ||||||
|             data.getOrDefault(event.getPlayer().getUniqueId(), new HashMap<>()) |             data.getOrDefault(event.getPlayer().getUniqueId(), new HashMap<>()) | ||||||
|                     .entrySet() |                     .entrySet() | ||||||
|                     .removeIf(e -> e.getValue().expiration instanceof ExpiresLogout); |                     .removeIf(e -> e.getValue().expirationPolicy instanceof ExpiresLogout); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         @EventHandler |         @EventHandler | ||||||
| @@ -119,4 +188,9 @@ public class PlayerNonPersistentConfig { | |||||||
|             tick++; |             tick++; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     private PlayerNonPersistentConfig() {} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,716 +0,0 @@ | |||||||
| package fr.pandacube.lib.paper.reflect; |  | ||||||
|  |  | ||||||
| import java.io.IOException; |  | ||||||
| import java.io.InputStream; |  | ||||||
| import java.io.InputStreamReader; |  | ||||||
| import java.io.PrintStream; |  | ||||||
| import java.io.StringReader; |  | ||||||
| import java.lang.reflect.Constructor; |  | ||||||
| import java.lang.reflect.Modifier; |  | ||||||
| import java.nio.charset.StandardCharsets; |  | ||||||
| import java.util.ArrayList; |  | ||||||
| import java.util.Arrays; |  | ||||||
| import java.util.Collections; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Map; |  | ||||||
| import java.util.Objects; |  | ||||||
| import java.util.TreeMap; |  | ||||||
| import java.util.stream.Collectors; |  | ||||||
|  |  | ||||||
| import org.bukkit.Bukkit; |  | ||||||
|  |  | ||||||
| import fr.pandacube.lib.util.log.Log; |  | ||||||
| import fr.pandacube.lib.reflect.Reflect; |  | ||||||
| import fr.pandacube.lib.reflect.ReflectClass; |  | ||||||
| import fr.pandacube.lib.reflect.ReflectField; |  | ||||||
| import fr.pandacube.lib.reflect.ReflectMember; |  | ||||||
| import fr.pandacube.lib.reflect.ReflectMethod; |  | ||||||
| import net.fabricmc.mappingio.MappingReader; |  | ||||||
| import net.fabricmc.mappingio.format.MappingFormat; |  | ||||||
| import net.fabricmc.mappingio.tree.MappingTree; |  | ||||||
| import net.fabricmc.mappingio.tree.MemoryMappingTree; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Provides reflection tools related to Minecraft servers internals. |  | ||||||
|  * It automatically deals with the obfuscated classes and methods. |  | ||||||
|  */ |  | ||||||
| public class NMSReflect { |  | ||||||
| 	 |  | ||||||
|  |  | ||||||
| 	private static String OBF_NAMESPACE; |  | ||||||
| 	private static String MOJ_NAMESPACE; |  | ||||||
|  |  | ||||||
| 	/* package */ static final Map<String, ClassMapping> CLASSES_BY_OBF = new TreeMap<>(); |  | ||||||
| 	/* package */ static final Map<String, ClassMapping> CLASSES_BY_MOJ = new TreeMap<>(); |  | ||||||
| 	 |  | ||||||
| 	private static Boolean IS_SERVER_OBFUSCATED; |  | ||||||
| 	 |  | ||||||
| 	private static boolean isInit = false; |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * Initialize all the obfuscation mapping data. |  | ||||||
| 	 */ |  | ||||||
| 	public static void init() { |  | ||||||
| 		 |  | ||||||
| 		synchronized (NMSReflect.class) { |  | ||||||
| 			if (isInit) |  | ||||||
| 				return; |  | ||||||
| 			isInit = true; |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		Log.info("[NMSReflect] Initializing NMS obfuscation mapping..."); |  | ||||||
| 		 |  | ||||||
| 		try { |  | ||||||
| 			ReflectClass<?> obfHelperClass; |  | ||||||
| 			try { |  | ||||||
| 				obfHelperClass = Reflect.ofClass("io.papermc.paper.util.ObfHelper"); |  | ||||||
| 	 |  | ||||||
| 				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); |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			List<ClassMapping> mappings = loadMappings(obfHelperClass); |  | ||||||
| 			for (ClassMapping clazz : mappings) { |  | ||||||
| 				CLASSES_BY_OBF.put(clazz.obfName, clazz); |  | ||||||
| 				CLASSES_BY_MOJ.put(clazz.mojName, clazz); |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			// determine if the runtime server is obfuscated |  | ||||||
| 			ClassNotFoundException exIfUnableToDetermine = null; |  | ||||||
| 			for (ClassMapping clazz : CLASSES_BY_OBF.values()) { |  | ||||||
| 				if (clazz.obfName.equals(clazz.mojName) // avoid direct collision between obf and unobf class names |  | ||||||
| 						|| CLASSES_BY_MOJ.containsKey(clazz.obfName) // avoid indirect collision |  | ||||||
| 						|| CLASSES_BY_OBF.containsKey(clazz.mojName))// avoid indirect collision |  | ||||||
| 					continue; |  | ||||||
| 				 |  | ||||||
| 				try { |  | ||||||
| 					Class.forName(clazz.obfName); |  | ||||||
| 					IS_SERVER_OBFUSCATED = true; |  | ||||||
| 					break; |  | ||||||
| 				} catch (ClassNotFoundException e) { |  | ||||||
| 					try { |  | ||||||
| 						Class.forName(clazz.mojName); |  | ||||||
| 						IS_SERVER_OBFUSCATED = false; |  | ||||||
| 						break; |  | ||||||
| 					} catch (ClassNotFoundException ee) { |  | ||||||
| 						ee.addSuppressed(e); |  | ||||||
| 						if (exIfUnableToDetermine == null) |  | ||||||
| 							exIfUnableToDetermine = ee; |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			if (IS_SERVER_OBFUSCATED == null) { |  | ||||||
| 				throw new IllegalStateException("Unable to determine if this server is obfuscated or not", exIfUnableToDetermine); |  | ||||||
| 			} |  | ||||||
| 			if (IS_SERVER_OBFUSCATED) { |  | ||||||
| 				Log.info("[NMSReflect] NMS runtime classes are obfuscated."); |  | ||||||
| 			} |  | ||||||
| 			else { |  | ||||||
| 				Log.info("[NMSReflect] NMS runtime classes are mojang mapped."); |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			int missingRuntimeClasses = 0; |  | ||||||
| 			for (ClassMapping clazz : mappings) { |  | ||||||
| 				try { |  | ||||||
| 					clazz.cacheReflectClass(); |  | ||||||
| 				} catch (Throwable e) { |  | ||||||
| 					missingRuntimeClasses++; |  | ||||||
| 					if (e instanceof ClassNotFoundException cnfe) { |  | ||||||
| 						Log.warning("[NMSReflect] Missing runtime class " + cnfe.getMessage() + (IS_SERVER_OBFUSCATED ? (" (moj class: " + clazz.mojName + ")") : "")); |  | ||||||
| 					} |  | ||||||
| 					else { |  | ||||||
| 						Log.warning("[NMSReflect] Unable to load runtime class " + (IS_SERVER_OBFUSCATED ? (clazz.obfName + " (moj class: " + clazz.mojName + ")") : clazz.mojName)); |  | ||||||
| 						Log.warning(e); // throwable on separate log message due to sometimes the message not showing at all because of this exception |  | ||||||
| 					} |  | ||||||
| 					CLASSES_BY_OBF.remove(clazz.obfName); |  | ||||||
| 					CLASSES_BY_MOJ.remove(clazz.mojName); |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 			if (missingRuntimeClasses > 0) { |  | ||||||
| 				Log.warning("[NMSReflect] " + missingRuntimeClasses + " class have been removed from the mapping data due to the previously stated errors."); |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 		} catch (Throwable t) { |  | ||||||
| 			CLASSES_BY_OBF.clear(); |  | ||||||
| 			CLASSES_BY_MOJ.clear(); |  | ||||||
| 			Log.severe("[NMSReflect] The plugin will not have access to NMS stuff due to an error while loading the obfuscation mapping.", t); |  | ||||||
| 		} |  | ||||||
| 		Log.info("[NMSReflect] Obfuscation mapping loaded for " + CLASSES_BY_OBF.size() + " classes."); |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	 |  | ||||||
| 	/** |  | ||||||
| 	 * Returns the class mapping instance for the provided class. |  | ||||||
| 	 * @param mojName the binary name of the desired class, on the mojang mapping. |  | ||||||
| 	 * @return the class mapping instance for the provided class. |  | ||||||
| 	 * @throws NullPointerException if there is no mapping for the provided Mojang mapped class. |  | ||||||
| 	 */ |  | ||||||
| 	public static ClassMapping mojClass(String mojName) { |  | ||||||
| 		return Objects.requireNonNull(CLASSES_BY_MOJ.get(mojName), "Unable to find the Mojang mapped class '" + mojName + "'"); |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	 |  | ||||||
| 	 |  | ||||||
| 	 |  | ||||||
| 	 |  | ||||||
| 	 |  | ||||||
| 	 |  | ||||||
| 	 |  | ||||||
| 	 |  | ||||||
| 	 |  | ||||||
|     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."); |  | ||||||
|             } |  | ||||||
|              |  | ||||||
|             MemoryMappingTree tree = new MemoryMappingTree(); |  | ||||||
|             MappingReader.read(new InputStreamReader(mappingsInputStream, StandardCharsets.UTF_8), MappingFormat.TINY_2_FILE, tree); |  | ||||||
|              |  | ||||||
|             List<ClassMapping> classes = new ArrayList<>(); |  | ||||||
|             for (MappingTree.ClassMapping cls : tree.getClasses()) { |  | ||||||
|                 classes.add(new ClassMapping(cls)); |  | ||||||
|             } |  | ||||||
|             return classes; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * Prints an HTML rendering of the currently loaded obfuscation mapping, into the provided {@link PrintStream}. |  | ||||||
| 	 * @param out the stream in which to print the HTML content. |  | ||||||
| 	 */ |  | ||||||
| 	public static void printHTMLMapping(PrintStream out) { |  | ||||||
| 		String title = "Obfuscation mapping - " + Bukkit.getName() + " version " + Bukkit.getVersion(); |  | ||||||
| 		out.println("<!DOCTYPE html><html><head>\n" |  | ||||||
| 				+ "<title>" + title + "</title>\n" |  | ||||||
| 				+ """ |  | ||||||
| 				<style> |  | ||||||
| 					html { |  | ||||||
| 						background-color: #2F2F2F; |  | ||||||
| 						color: white; |  | ||||||
| 						font-size: 14px; |  | ||||||
| 						font-family: Consolas, monospace; |  | ||||||
| 					} |  | ||||||
| 					a:not(.cl) { |  | ||||||
| 						color: #1290C3; |  | ||||||
| 					} |  | ||||||
| 					table { |  | ||||||
| 						border-collapse: collapse; |  | ||||||
| 						width: 100%; |  | ||||||
| 						margin: auto; |  | ||||||
| 					} |  | ||||||
| 					tr:nth-child(2n) { |  | ||||||
| 						background-color: #373737; |  | ||||||
| 					} |  | ||||||
| 					tr:hover { |  | ||||||
| 						background-color: #555; |  | ||||||
| 					} |  | ||||||
| 					tr > *:first-child { |  | ||||||
| 						padding-right: .5em; |  | ||||||
| 						white-space: nowrap; |  | ||||||
| 					} |  | ||||||
| 					 |  | ||||||
| 					b.pu { |  | ||||||
| 						color: #0C0; |  | ||||||
| 					} |  | ||||||
| 					b.pt { |  | ||||||
| 						color: #FC0; |  | ||||||
| 					} |  | ||||||
| 					b.pv { |  | ||||||
| 						color: #F00; |  | ||||||
| 					} |  | ||||||
| 					b.pk { |  | ||||||
| 						color: #66F; |  | ||||||
| 					} |  | ||||||
| 					td { |  | ||||||
| 						padding-top: 0; |  | ||||||
| 						padding-bottom: 0; |  | ||||||
| 					} |  | ||||||
| 					th { |  | ||||||
| 						text-align: left; |  | ||||||
| 						font-size: 1.1em; |  | ||||||
| 						border-top: solid 1px white; |  | ||||||
| 					} |  | ||||||
| 					.kw { |  | ||||||
| 						color: #CC6C1D; |  | ||||||
| 					} |  | ||||||
| 					.cl { |  | ||||||
| 						color: #1290C3; |  | ||||||
| 					} |  | ||||||
| 					.mtd { |  | ||||||
| 						color: #1EB540; |  | ||||||
| 					} |  | ||||||
| 					.fld { |  | ||||||
| 						color: #8DDAF8; |  | ||||||
| 					} |  | ||||||
| 					.st { |  | ||||||
| 						font-style: italic; |  | ||||||
| 					} |  | ||||||
| 					.st.fn { |  | ||||||
| 						font-weight: bold; |  | ||||||
| 					} |  | ||||||
| 				</style> |  | ||||||
| 				</head><body> |  | ||||||
| 				""" |  | ||||||
| 				+ "<h1>" + title + "</h1>\n" |  | ||||||
| 				+ """ |  | ||||||
| 				<p> |  | ||||||
| 					<b>C</b>: <span class='kw'>class</span>   |  | ||||||
| 					<b>E</b>: <span class='kw'>enum</span>   |  | ||||||
| 					<b>I</b>: <span class='kw'>interface</span>   |  | ||||||
| 					<b>@</b>: <span class='kw'>@interface</span>   |  | ||||||
| 					<b>R</b>: <span class='kw'>record</span><br> |  | ||||||
| 					<b>●</b>: field   |  | ||||||
| 					<b>c</b>: constructor   |  | ||||||
| 					<b>⬤</b>: method<br> |  | ||||||
| 					<b class='pu'>⬤</b>: <span class='kw'>public</span>   |  | ||||||
| 					<b class='pt'>⬤</b>: <span class='kw'>protected</span>   |  | ||||||
| 					<b class='pk'>⬤</b>: package   |  | ||||||
| 					<b class='pv'>⬤</b>: <span class='kw'>private</span><br> |  | ||||||
| 					<sup>S</sup>: <span class='kw'>static</span>   |  | ||||||
| 					<sup>A</sup>: <span class='kw'>abstract</span>   |  | ||||||
| 					<sup>F</sup>: <span class='kw'>final</span> |  | ||||||
| 				</p> |  | ||||||
| 				<table> |  | ||||||
| 				"""); |  | ||||||
| 		out.println("<tr><th>ns</th><th>" + OBF_NAMESPACE + "</th><th>" + MOJ_NAMESPACE + "</th></tr>"); |  | ||||||
| 		for (ClassMapping clazz : CLASSES_BY_OBF.values()) { |  | ||||||
| 			clazz.printHTML(out); |  | ||||||
| 		} |  | ||||||
| 		out.println("</table><p>Generated by <a href='https://github.com/marcbal'>marcbal</a>" |  | ||||||
| 				+ " using <a href='https://github.com/PandacubeFr/PandaLib/blob/master/Paper/src/main/java/fr/pandacube/lib/paper/reflect/NMSReflect.java'>this tool</a>" |  | ||||||
| 				+ " running on <a href='https://papermc.io/'>" + Bukkit.getName() + "</a> version " + Bukkit.getVersion() + "</p>" |  | ||||||
| 				+ "</body></html>"); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * 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; |  | ||||||
|     	 |  | ||||||
|     	/* package */ final int id = nextID++; |  | ||||||
| 		/* package */ final String obfName; |  | ||||||
| 		/* package */ final String mojName; |  | ||||||
|  |  | ||||||
| 		private final Map<MethodId, MemberMapping<MethodId, ReflectMethod<?>>> methodsByObf = new TreeMap<>(); |  | ||||||
| 		private final Map<MethodId, MemberMapping<MethodId, ReflectMethod<?>>> methodsByMoj = new TreeMap<>(); |  | ||||||
| 		private final Map<String, MemberMapping<String, ReflectField<?>>> fieldsByObf = new TreeMap<>(); |  | ||||||
| 		private final Map<String, MemberMapping<String, ReflectField<?>>> fieldsByMoj = new TreeMap<>(); |  | ||||||
| 		 |  | ||||||
| 		private ReflectClass<?> runtimeReflectClass = null; |  | ||||||
| 		 |  | ||||||
| 		private ClassMapping(MappingTree.ClassMapping cls) { |  | ||||||
|             obfName = binaryClassName(cls.getName(OBF_NAMESPACE)); |  | ||||||
|             mojName = binaryClassName(cls.getName(MOJ_NAMESPACE)); |  | ||||||
| 			 |  | ||||||
| 			cls.getMethods().stream().map(MemberMapping::of).forEach(method -> { |  | ||||||
| 				method.declaringClass = this; |  | ||||||
| 				methodsByObf.put(method.obfDesc.identifier, method); |  | ||||||
| 				methodsByMoj.put(method.mojDesc.identifier, method); |  | ||||||
| 			}); |  | ||||||
|             cls.getFields().stream().map(MemberMapping::of).forEach(field -> { |  | ||||||
|             	field.declaringClass = this; |  | ||||||
| 				fieldsByObf.put(field.obfDesc.identifier, field); |  | ||||||
| 				fieldsByMoj.put(field.mojDesc.identifier, field); |  | ||||||
|             }); |  | ||||||
| 			 |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
|  |  | ||||||
| 		 |  | ||||||
| 		private synchronized void cacheReflectClass() throws ClassNotFoundException { |  | ||||||
| 			if (runtimeReflectClass == null) |  | ||||||
| 				runtimeReflectClass = Reflect.ofClass(IS_SERVER_OBFUSCATED ? obfName : mojName); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 		/** |  | ||||||
| 		 * Returns the actual runtime {@link Class} represented by this {@link ClassMapping}, wrapped into a |  | ||||||
| 		 * {@link ReflectClass}. |  | ||||||
| 		 * @return the actual runtime {@link Class} represented by this {@link ClassMapping}, wrapped into a |  | ||||||
| 		 * 		 * {@link ReflectClass}. |  | ||||||
| 		 */ |  | ||||||
| 		public ReflectClass<?> runtimeReflect() { |  | ||||||
| 			return runtimeReflectClass; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		/** |  | ||||||
| 		 * Returns the actual runtime Class represented by this {@link ClassMapping}. |  | ||||||
| 		 * @return the actual runtime Class represented by this {@link ClassMapping}. |  | ||||||
| 		 */ |  | ||||||
| 		public Class<?> runtimeClass() { |  | ||||||
| 			return runtimeReflectClass.get(); |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		 |  | ||||||
| 		 |  | ||||||
| 		 |  | ||||||
| 		/** |  | ||||||
| 		 * Returns the actual runtime Method that has the provided mojang name and parameter types, wrapped into a |  | ||||||
| 		 * {@link ReflectMethod}. |  | ||||||
| 		 * @param mojName the Mojang mapped name of the method. |  | ||||||
| 		 * @param mojParametersType the list of parameters of the method. |  | ||||||
| 		 * Each parameter type must be an instance of one of the following type: |  | ||||||
| 		 * {@link NMSTypeWrapper}, {@link Class}, {@link ReflectClass} or {@link ClassMapping}. |  | ||||||
| 		 * @return the actual runtime Method that has the provided mojang name and parameter types, wrapped into a |  | ||||||
| 		 *         {@link ReflectMethod}. |  | ||||||
| 		 * @throws IllegalArgumentException if one of the parameter has an invalid type |  | ||||||
| 		 * @throws NullPointerException if one of the parameter is null, or if there is no mapping for the provided Mojang mapped method. |  | ||||||
| 		 * @throws ClassNotFoundException if there is no runtime class to represent one of the provided parametersType. |  | ||||||
| 		 * @throws NoSuchMethodException if there is no runtime method to represent the provided method. |  | ||||||
| 		 */ |  | ||||||
| 		public ReflectMethod<?> mojMethod(String mojName, Object... mojParametersType) throws ClassNotFoundException, NoSuchMethodException { |  | ||||||
| 			MethodId mId = new MethodId(mojName, NMSTypeWrapper.toTypeList(Arrays.asList(mojParametersType))); |  | ||||||
| 			MemberMapping<MethodId, ReflectMethod<?>> mm = methodsByMoj.get(mId); |  | ||||||
| 			Objects.requireNonNull(mm, "Unable to find the Mojang mapped method " + mId); |  | ||||||
| 			 |  | ||||||
| 			try { |  | ||||||
| 				return mm.getReflectMember(); |  | ||||||
| 			} catch (ReflectiveOperationException e) { |  | ||||||
| 				if (e instanceof ClassNotFoundException cnfe) |  | ||||||
| 					throw cnfe; |  | ||||||
| 				if (e instanceof NoSuchMethodException nsme) |  | ||||||
| 					throw nsme; |  | ||||||
| 				// should not have another exception |  | ||||||
| 				throw new RuntimeException(e); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		 |  | ||||||
| 		 |  | ||||||
|  |  | ||||||
| 		/** |  | ||||||
| 		 * Returns the actual runtime Field that has the provided mojang name, wrapped into a {@link ReflectField}. |  | ||||||
| 		 * @param mojName the Mojang mapped name of the field. |  | ||||||
| 		 * @return the actual runtime Field that has the provided mojang name, wrapped into a {@link ReflectField}. |  | ||||||
| 		 * @throws NullPointerException if there is no mapping for the provided Mojang mapped field. |  | ||||||
| 		 * @throws NoSuchFieldException if there is no runtime field to represent the provided mojang field. |  | ||||||
| 		 */ |  | ||||||
| 		public ReflectField<?> mojField(String mojName) throws NoSuchFieldException { |  | ||||||
| 			MemberMapping<String, ReflectField<?>> fm = fieldsByMoj.get(mojName); |  | ||||||
| 			Objects.requireNonNull(fm, "Unable to find the Mojang mapped field '" + mojName + "'"); |  | ||||||
| 			try { |  | ||||||
| 				return fm.getReflectMember(); |  | ||||||
| 			} catch (ReflectiveOperationException e) { |  | ||||||
| 				if (e instanceof NoSuchFieldException nsfe) |  | ||||||
| 					throw nsfe; |  | ||||||
| 				// should not have another exception |  | ||||||
| 				throw new RuntimeException(e); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		 |  | ||||||
| 		 |  | ||||||
|  |  | ||||||
| 		 |  | ||||||
| 		/* package */ String toClickableHTML(boolean isObfClass) { |  | ||||||
| 	    	String classToPrint = isObfClass ? obfName : mojName; |  | ||||||
| 	    	String classSimpleName = classToPrint.substring(classToPrint.lastIndexOf('.') + 1); |  | ||||||
| 	    	String htmlTitle = classSimpleName.equals(classToPrint) ? "" : (" title='" + classToPrint + "'"); |  | ||||||
| 			return "<a href='#c" + id + "'" + htmlTitle + " class='cl'>" + classSimpleName + "</a>"; |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		 |  | ||||||
| 		 |  | ||||||
| 		 |  | ||||||
| 		/* package */ NMSTypeWrapper toType(boolean obf) { |  | ||||||
| 			return new NMSTypeWrapper(obf ? obfName : mojName, 0); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 		private void printHTML(PrintStream out) { |  | ||||||
| 			String modifiersHTML = classModifiersToHTML(runtimeClass()); |  | ||||||
| 			out.println("<tr id='c" + id + "'><th>" + modifiersHTML + "</th><th>" + nameToHTML(true) + "</th><th>" + nameToHTML(false) + "</th></tr>"); |  | ||||||
| 			fieldsByObf.values().stream().filter(MemberMapping::isStatic).forEach(f -> f.printHTML(out)); |  | ||||||
| 			methodsByObf.values().stream().filter(MemberMapping::isStatic).forEach(m -> m.printHTML(out)); |  | ||||||
| 			printConstructorsHTML(out); |  | ||||||
| 			fieldsByObf.values().stream().filter(mm -> !mm.isStatic()).forEach(f -> f.printHTML(out)); |  | ||||||
| 			methodsByObf.values().stream().filter(mm -> !mm.isStatic()).forEach(m -> m.printHTML(out)); |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		private String nameToHTML(boolean obf) { |  | ||||||
| 			String classToPrint = obf ? obfName : mojName; |  | ||||||
| 			int packageSep = classToPrint.lastIndexOf('.'); |  | ||||||
| 	    	String classSimpleName = classToPrint.substring(packageSep + 1); |  | ||||||
| 	    	String classPackages = classToPrint.substring(0, Math.max(packageSep, 0)); |  | ||||||
| 	    	String classHTML = (packageSep >= 0 ? (classPackages + ".") : "") + "<b class='cl'>" + classSimpleName + "</b>"; |  | ||||||
| 			 |  | ||||||
| 			NMSTypeWrapper superClass = superClass(obf); |  | ||||||
| 			String superClassHTML = superClass == null ? "" : (" <span class='kw'>extends</span> " + superClass.toHTML(obf)); |  | ||||||
| 			 |  | ||||||
| 			List<NMSTypeWrapper> superInterfaces = superInterfaces(obf); |  | ||||||
| 			String superInterfacesHTML = superInterfaces.isEmpty() ? "" |  | ||||||
| 					: (" <span class='kw'>implements</span> " + superInterfaces.stream().map(t -> t.toHTML(obf)).collect(Collectors.joining(", "))); |  | ||||||
| 			 |  | ||||||
| 			return classHTML + superClassHTML + superInterfacesHTML; |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		private NMSTypeWrapper superClass(boolean obf) { |  | ||||||
| 			Class<?> superClass = runtimeClass().getSuperclass(); |  | ||||||
| 			if (superClass == null || superClass.equals(Object.class) || superClass.equals(Enum.class) || superClass.equals(Record.class)) |  | ||||||
| 				return null; |  | ||||||
| 			ClassMapping cm = (IS_SERVER_OBFUSCATED ? CLASSES_BY_OBF : CLASSES_BY_MOJ).get(superClass.getName()); |  | ||||||
| 			return (cm != null) ? cm.toType(obf) : NMSTypeWrapper.of(superClass); |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		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)); |  | ||||||
| 			} |  | ||||||
| 			return types; |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 	     |  | ||||||
| 	    private void printConstructorsHTML(PrintStream out) { |  | ||||||
| 	    	String classObfSimpleName = obfName.substring(obfName.lastIndexOf('.') + 1); |  | ||||||
| 	    	String classMojSimpleName = mojName.substring(mojName.lastIndexOf('.') + 1); |  | ||||||
| 			for (Constructor<?> ct : runtimeClass().getDeclaredConstructors()) { |  | ||||||
| 				List<NMSTypeWrapper> obfParams = new ArrayList<>(); |  | ||||||
| 				List<NMSTypeWrapper> mojParams = new ArrayList<>(); |  | ||||||
| 				for (Class<?> param : ct.getParameterTypes()) { |  | ||||||
| 					ClassMapping cm = (IS_SERVER_OBFUSCATED ? CLASSES_BY_OBF : CLASSES_BY_MOJ).get(param.getName()); |  | ||||||
| 					if (cm == null) { |  | ||||||
| 						NMSTypeWrapper t = NMSTypeWrapper.of(param); |  | ||||||
| 						obfParams.add(t); |  | ||||||
| 						mojParams.add(t); |  | ||||||
| 					} |  | ||||||
| 					else { |  | ||||||
| 						obfParams.add(cm.toType(true)); |  | ||||||
| 						mojParams.add(cm.toType(false)); |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 				out.println("<tr>" |  | ||||||
| 						+ "<td>" + elementModifiersToHTML("c", ct.getModifiers()) + "</td>" |  | ||||||
| 						+ "<td><b class='mtd'>" + classObfSimpleName + "</b>(" + obfParams.stream().map(t -> t.toHTML(true)).collect(Collectors.joining(", ")) + ")</td>" |  | ||||||
| 						+ "<td><b class='mtd'>" + classMojSimpleName + "</b>(" + mojParams.stream().map(t -> t.toHTML(false)).collect(Collectors.joining(", ")) + ")</td>" |  | ||||||
| 						+ "</tr>"); |  | ||||||
| 			} |  | ||||||
| 	    	 |  | ||||||
| 	    } |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|      |  | ||||||
|      |  | ||||||
|      |  | ||||||
|      |  | ||||||
|      |  | ||||||
|      |  | ||||||
|      |  | ||||||
|     private record MethodId(String name, List<NMSTypeWrapper> parametersType) implements Comparable<MethodId> { |  | ||||||
|     	@Override |  | ||||||
|     	public int compareTo(MethodId o) { |  | ||||||
|     		int cmp = name.compareTo(o.name); |  | ||||||
|     		if (cmp != 0) |  | ||||||
|     			return cmp; |  | ||||||
|     		return toString().compareTo(o.toString()); |  | ||||||
|     	} |  | ||||||
|     	 |  | ||||||
| 		private String toHTML(boolean isObfClass, boolean isStatic, boolean isFinal) { |  | ||||||
| 			String paramsHTML = parametersType.stream().map(p -> p.toHTML(isObfClass)).collect(Collectors.joining(", ")); |  | ||||||
| 			String cl = "mtd"; |  | ||||||
| 			if (isStatic) |  | ||||||
| 				cl += " st"; |  | ||||||
| 			if (isFinal) |  | ||||||
| 				cl += " fn"; |  | ||||||
| 			return "<span class='" + cl + "'>" + name + "</span>(" + paramsHTML + ")"; |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		public String toString() { |  | ||||||
| 			String paramsStr = parametersType.stream().map(NMSTypeWrapper::toString).collect(Collectors.joining(", ")); |  | ||||||
| 			return name + "(" + paramsStr + ")"; |  | ||||||
| 		} |  | ||||||
|     	 |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|      |  | ||||||
|     private record MemberDesc<I extends Comparable<I>>(I identifier, NMSTypeWrapper returnType) { |  | ||||||
| 		private String toHTML(boolean isObfClass, boolean isStatic, boolean isFinal) { |  | ||||||
| 			String identifierHTML = ""; |  | ||||||
| 			if (identifier instanceof MethodId mId) |  | ||||||
| 				identifierHTML = mId.toHTML(isObfClass, isStatic, isFinal); |  | ||||||
| 			else if (identifier instanceof String n) { |  | ||||||
| 				String cl = "fld"; |  | ||||||
| 				if (isStatic) |  | ||||||
| 					cl += " st"; |  | ||||||
| 				if (isFinal) |  | ||||||
| 					cl += " fn"; |  | ||||||
| 				identifierHTML = "<span class='" + cl + "'>" + n + "</span>"; |  | ||||||
| 			} |  | ||||||
| 			return returnType.toHTML(isObfClass) + " " + identifierHTML; |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		private static MemberDesc<MethodId> of(MappingTree.MethodMapping member, String namespace) { |  | ||||||
| 			String desc = member.getDesc(namespace); |  | ||||||
| 			try (StringReader descReader = new StringReader(desc)) { |  | ||||||
| 				char r = (char) descReader.read(); |  | ||||||
| 				if (r != '(') |  | ||||||
| 					throw new IllegalArgumentException("Invalid method description '" + desc + "'. Must start with '('."); |  | ||||||
| 				 |  | ||||||
| 				List<NMSTypeWrapper> paramsType = new ArrayList<>(); |  | ||||||
| 				 |  | ||||||
| 				while (((char) descReader.read()) != ')') { |  | ||||||
| 					descReader.skip(-1); |  | ||||||
| 					paramsType.add(NMSTypeWrapper.parse(descReader)); |  | ||||||
| 				} |  | ||||||
| 				 |  | ||||||
| 				NMSTypeWrapper retType = NMSTypeWrapper.parse(descReader); |  | ||||||
| 				return new MemberDesc<>(new MethodId(member.getName(namespace), Collections.unmodifiableList(paramsType)), retType); |  | ||||||
| 			} catch (IOException e) { |  | ||||||
| 				throw new RuntimeException("StringReader read error", e); |  | ||||||
| 			} |  | ||||||
| 			 |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		 |  | ||||||
| 		private static MemberDesc<String> of(MappingTree.FieldMapping member, String namespace) { |  | ||||||
| 			StringReader descReader = new StringReader(member.getDesc(namespace)); |  | ||||||
| 			return new MemberDesc<>(member.getName(namespace), NMSTypeWrapper.parse(descReader)); |  | ||||||
| 		} |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|      |  | ||||||
|      |  | ||||||
|      |  | ||||||
|     private static abstract class MemberMapping<I extends Comparable<I>, R extends ReflectMember<?, ?, ?, ?>> { |  | ||||||
|     	private final String htmlTypeChar; |  | ||||||
|     	/* package */ final MemberDesc<I> obfDesc, mojDesc; |  | ||||||
|     	/* package */ ClassMapping declaringClass; |  | ||||||
|     	private MemberMapping(String htmlType, MemberDesc<I> obfDesc, MemberDesc<I> mojDesc) { |  | ||||||
|     		htmlTypeChar = htmlType; |  | ||||||
|     		this.obfDesc = obfDesc; |  | ||||||
|     		this.mojDesc = mojDesc; |  | ||||||
| 		} |  | ||||||
|     	 |  | ||||||
| 		/* package */ void printHTML(PrintStream out) { |  | ||||||
| 			int mod = 0; |  | ||||||
| 			try { |  | ||||||
| 				mod = getReflectMember().getModifiers(); |  | ||||||
| 			} catch (ReflectiveOperationException e) { |  | ||||||
| 				// ignore |  | ||||||
| 			} |  | ||||||
| 			boolean isStatic = Modifier.isStatic(mod); |  | ||||||
| 			boolean isFinal = Modifier.isFinal(mod); |  | ||||||
| 			out.println("<tr>" |  | ||||||
| 					+ "<td>" + elementModifiersToHTML(htmlTypeChar, mod) + "</td>" |  | ||||||
| 					+ "<td>" + obfDesc.toHTML(true, isStatic, isFinal) + "</td>" |  | ||||||
| 					+ "<td>" + mojDesc.toHTML(false, isStatic, isFinal) + "</td>" |  | ||||||
| 					+ "</tr>"); |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		/* package */ MemberDesc<I> getReflectDesc() { |  | ||||||
| 			return (IS_SERVER_OBFUSCATED ? obfDesc : mojDesc); |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		/* package */ abstract R getReflectMember() throws ReflectiveOperationException; |  | ||||||
| 		 |  | ||||||
| 		/* package */ boolean isStatic() { |  | ||||||
| 			try { |  | ||||||
| 				return Modifier.isStatic(getReflectMember().getModifiers()); |  | ||||||
| 			} catch (ReflectiveOperationException e) { |  | ||||||
| 				Log.severe(e); |  | ||||||
| 				return false; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		private static MemberMapping<MethodId, ReflectMethod<?>> of(MappingTree.MethodMapping mioMapping) { |  | ||||||
|     		return new MemberMapping<>("⬤", MemberDesc.of(mioMapping, OBF_NAMESPACE), MemberDesc.of(mioMapping, MOJ_NAMESPACE)) { |  | ||||||
| 				@Override |  | ||||||
| 				ReflectMethod<?> getReflectMember() throws ClassNotFoundException, NoSuchMethodException { |  | ||||||
| 					MethodId id = getReflectDesc().identifier; |  | ||||||
| 					return declaringClass.runtimeReflectClass.method(id.name, NMSTypeWrapper.toClassArray(id.parametersType)); |  | ||||||
| 				} |  | ||||||
|     		}; |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		private static MemberMapping<String, ReflectField<?>> of(MappingTree.FieldMapping mioMapping) { |  | ||||||
|     		return new MemberMapping<>("●", MemberDesc.of(mioMapping, OBF_NAMESPACE), MemberDesc.of(mioMapping, MOJ_NAMESPACE)) { |  | ||||||
| 				@Override |  | ||||||
| 				ReflectField<?> getReflectMember() throws NoSuchFieldException { |  | ||||||
| 					String id = getReflectDesc().identifier; |  | ||||||
| 					return declaringClass.runtimeReflectClass.field(id); |  | ||||||
| 				} |  | ||||||
|     		}; |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		 |  | ||||||
|     	 |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|      |  | ||||||
|      |  | ||||||
|      |  | ||||||
|      |  | ||||||
|     /* package */ static String binaryClassName(String cl) { |  | ||||||
|     	return cl.replace('/', '.'); |  | ||||||
|     } |  | ||||||
|      |  | ||||||
| 	 |  | ||||||
| 	 |  | ||||||
| 	private static String classModifiersToHTML(Class<?> clazz) { |  | ||||||
| 		String elementHTMLType; |  | ||||||
|  |  | ||||||
| 		if (clazz.isEnum()) |  | ||||||
| 			elementHTMLType = "E"; |  | ||||||
| 		else if (clazz.isAnnotation()) |  | ||||||
| 			elementHTMLType = "@"; |  | ||||||
| 		else if (clazz.isInterface()) |  | ||||||
| 			elementHTMLType = "I"; |  | ||||||
| 		else if (clazz.isRecord()) |  | ||||||
| 			elementHTMLType = "R"; |  | ||||||
| 		else if (clazz.isPrimitive()) |  | ||||||
| 			elementHTMLType = ""; |  | ||||||
| 		else  |  | ||||||
| 			elementHTMLType = "C"; |  | ||||||
| 		 |  | ||||||
| 		return elementModifiersToHTML(elementHTMLType, clazz.getModifiers()); |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
|  |  | ||||||
| 	 |  | ||||||
| 	private static String elementModifiersToHTML(String elementHTMLType, int elModifiers) { |  | ||||||
| 		String html = "<b class='"; |  | ||||||
| 		 |  | ||||||
| 		if (Modifier.isPublic(elModifiers)) |  | ||||||
| 			html += "pu"; |  | ||||||
| 		else if (Modifier.isProtected(elModifiers)) |  | ||||||
| 			html += "pt"; |  | ||||||
| 		else if (Modifier.isPrivate(elModifiers)) |  | ||||||
| 			html += "pv"; |  | ||||||
| 		else |  | ||||||
| 			html += "pk"; |  | ||||||
| 		 |  | ||||||
| 		html += "'>" + elementHTMLType + "</b>"; |  | ||||||
|  |  | ||||||
| 		boolean isStatic = Modifier.isStatic(elModifiers); |  | ||||||
| 		boolean isAbstract = Modifier.isAbstract(elModifiers); |  | ||||||
| 		boolean isFinal = Modifier.isFinal(elModifiers); |  | ||||||
|  |  | ||||||
| 		if (isStatic || isAbstract || isFinal) { |  | ||||||
| 			html += "<sup>"; |  | ||||||
| 			if (isStatic) |  | ||||||
| 				html += "S"; |  | ||||||
| 			if (isAbstract) |  | ||||||
| 				html += "A"; |  | ||||||
| 			if (isFinal) |  | ||||||
| 				html += "F"; |  | ||||||
| 			html += "</sup>"; |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		return html; |  | ||||||
| 	} |  | ||||||
|      |  | ||||||
|     // ● (field) |  | ||||||
| 	// ⬤ (method) |  | ||||||
|      |  | ||||||
| } |  | ||||||
| @@ -1,194 +0,0 @@ | |||||||
| package fr.pandacube.lib.paper.reflect; |  | ||||||
|  |  | ||||||
| import java.io.IOException; |  | ||||||
| import java.io.StringReader; |  | ||||||
| import java.util.ArrayList; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Objects; |  | ||||||
|  |  | ||||||
| import fr.pandacube.lib.reflect.ReflectClass; |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect.ClassMapping; |  | ||||||
|  |  | ||||||
| /* package */ class NMSTypeWrapper implements Comparable<NMSTypeWrapper> { |  | ||||||
| 	private final String type; |  | ||||||
| 	private final int arrayDepth; |  | ||||||
| 	 |  | ||||||
| 	/* package */ NMSTypeWrapper(String type, int arrayDepth) { |  | ||||||
| 		this.type = type; |  | ||||||
| 		this.arrayDepth = arrayDepth; |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	@Override |  | ||||||
| 	public boolean equals(Object obj) { |  | ||||||
| 		return obj instanceof NMSTypeWrapper ot && type.equals(ot.type) && arrayDepth == ot.arrayDepth; |  | ||||||
| 	} |  | ||||||
| 	@Override |  | ||||||
| 	public int hashCode() { |  | ||||||
| 		return type.hashCode() ^ arrayDepth; |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	@Override |  | ||||||
| 	public int compareTo(NMSTypeWrapper o) { |  | ||||||
| 		return toString().compareTo(o.toString()); |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	Class<?> toClass() throws ClassNotFoundException { |  | ||||||
| 		 |  | ||||||
| 		Class<?> cl = switch(type) { |  | ||||||
| 		case "boolean" -> boolean.class; |  | ||||||
| 		case "byte" -> byte.class; |  | ||||||
| 		case "char" -> char.class; |  | ||||||
| 		case "double" -> double.class; |  | ||||||
| 		case "float" -> float.class; |  | ||||||
| 		case "int" -> int.class; |  | ||||||
| 		case "long" -> long.class; |  | ||||||
| 		case "short" -> short.class; |  | ||||||
| 		case "void" -> void.class; |  | ||||||
| 		default -> Class.forName(type); |  | ||||||
| 		}; |  | ||||||
| 		 |  | ||||||
| 		for (int i = 0; i < arrayDepth; i++) { |  | ||||||
| 			cl = cl.arrayType(); |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		return cl; |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	/* package */ static NMSTypeWrapper of(Class<?> cl) { |  | ||||||
| 		int arrayDepth = 0; |  | ||||||
| 		while (cl.isArray()) { |  | ||||||
| 			cl = cl.getComponentType(); |  | ||||||
| 			arrayDepth++; |  | ||||||
| 		} |  | ||||||
| 		return new NMSTypeWrapper(cl.getName(), arrayDepth); |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	public static NMSTypeWrapper of(ReflectClass<?> rc) { |  | ||||||
| 		return arrayOf(rc, 0); |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	public static NMSTypeWrapper arrayOf(ReflectClass<?> rc, int arrayDepth) { |  | ||||||
| 		return new NMSTypeWrapper(rc.get().getName(), arrayDepth); |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	public static NMSTypeWrapper mojOf(ClassMapping cm) { |  | ||||||
| 		return arrayMojOf(cm, 0); |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	public static NMSTypeWrapper arrayMojOf(ClassMapping cm, int arrayDepth) { |  | ||||||
| 		return new NMSTypeWrapper(cm.mojName, arrayDepth); |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	/* package */ static NMSTypeWrapper toType(Object typeObj) { |  | ||||||
| 		Objects.requireNonNull(typeObj, "typeObj cannot be null"); |  | ||||||
| 		if (typeObj instanceof Class<?> cl) { |  | ||||||
| 			return of(cl); |  | ||||||
| 		} |  | ||||||
| 		else if (typeObj instanceof ClassMapping cm) { |  | ||||||
| 			return mojOf(cm); |  | ||||||
| 		} |  | ||||||
| 		else if (typeObj instanceof ReflectClass<?> rc) { |  | ||||||
| 			return of(rc); |  | ||||||
| 		} |  | ||||||
| 		else if (typeObj instanceof NMSTypeWrapper t) { |  | ||||||
| 			return t; |  | ||||||
| 		} |  | ||||||
| 		else |  | ||||||
| 			throw new IllegalArgumentException("Unsupported object of type " + typeObj.getClass()); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* package */ String toHTML(boolean isObfClass) { |  | ||||||
| 		ClassMapping clMapping = (isObfClass ? NMSReflect.CLASSES_BY_OBF : NMSReflect.CLASSES_BY_MOJ).get(type); |  | ||||||
|     	String typeHTML; |  | ||||||
|     	if (clMapping != null) { |  | ||||||
|     		typeHTML = clMapping.toClickableHTML(isObfClass); |  | ||||||
|     	} |  | ||||||
|     	else { |  | ||||||
| 	    	String classToPrint = type; |  | ||||||
| 	    	String classSimpleName = classToPrint.substring(classToPrint.lastIndexOf('.') + 1); |  | ||||||
| 	    	String htmlTitle = classSimpleName.equals(classToPrint) ? "" : (" title='" + classToPrint + "'"); |  | ||||||
|     		if (!htmlTitle.isEmpty()) { |  | ||||||
|     			typeHTML = "<span" + htmlTitle + " class='cl'>" + classSimpleName + "</span>"; |  | ||||||
|         	} |  | ||||||
|         	else { |  | ||||||
|         		typeHTML = "<span class='" + (isPrimitive() ? "kw" : "cl") + "'>" + classSimpleName + "</span>"; |  | ||||||
|         	} |  | ||||||
|     	} |  | ||||||
|     	 |  | ||||||
| 		 |  | ||||||
| 		return typeHTML + "[]".repeat(arrayDepth); |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	public String toString() { |  | ||||||
| 		return type + "[]".repeat(arrayDepth); |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	 |  | ||||||
| 	public boolean isPrimitive() { |  | ||||||
| 		try { |  | ||||||
| 			return toClass().isPrimitive(); |  | ||||||
| 		} catch (ClassNotFoundException e) { |  | ||||||
| 			return false; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	 |  | ||||||
| 	 |  | ||||||
| 	 |  | ||||||
| 	/* package */ static NMSTypeWrapper parse(StringReader desc) { |  | ||||||
| 		try { |  | ||||||
| 			int arrayDepth = 0; |  | ||||||
| 			char c; |  | ||||||
| 			while ((c = (char) desc.read()) == '[') { |  | ||||||
| 				arrayDepth++; |  | ||||||
| 			} |  | ||||||
| 			String type = switch(c) { |  | ||||||
| 			case 'Z' -> "boolean"; |  | ||||||
| 			case 'B' -> "byte"; |  | ||||||
| 			case 'C' -> "char"; |  | ||||||
| 			case 'D' -> "double"; |  | ||||||
| 			case 'F' -> "float"; |  | ||||||
| 			case 'I' -> "int"; |  | ||||||
| 			case 'J' -> "long"; |  | ||||||
| 			case 'S' -> "short"; |  | ||||||
| 			case 'L' -> { |  | ||||||
| 				StringBuilder sbClass = new StringBuilder(); |  | ||||||
| 				char r; |  | ||||||
| 				while ((r = (char) desc.read()) != ';') { |  | ||||||
|     				sbClass.append(r); |  | ||||||
| 				} |  | ||||||
| 				yield NMSReflect.binaryClassName(sbClass.toString()); |  | ||||||
| 			} |  | ||||||
| 			default -> "void"; |  | ||||||
| 			}; |  | ||||||
| 			return new NMSTypeWrapper(type, arrayDepth); |  | ||||||
| 		} catch (IOException e) { |  | ||||||
| 			throw new RuntimeException("StringReader read error", e); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	 |  | ||||||
|  |  | ||||||
| 	 |  | ||||||
| 	/* package */ static List<NMSTypeWrapper> toTypeList(List<Object> paramsType) { |  | ||||||
| 		List<NMSTypeWrapper> types = new ArrayList<>(paramsType.size()); |  | ||||||
| 		for (int i = 0; i < paramsType.size(); i++) { |  | ||||||
| 			Object param = paramsType.get(i); |  | ||||||
| 			try { |  | ||||||
| 				types.add(NMSTypeWrapper.toType(param)); |  | ||||||
| 			} catch (NullPointerException|IllegalArgumentException e) { |  | ||||||
| 				throw new IllegalArgumentException("Invalid parameterType at index " + i, e); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		return types; |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	/* package */ static Class<?>[] toClassArray(List<NMSTypeWrapper> types) throws ClassNotFoundException { |  | ||||||
| 		Class<?>[] classes = new Class<?>[types.size()]; |  | ||||||
| 		for (int i = 0; i < types.size(); i++) { |  | ||||||
| 			classes[i] = types.get(i).toClass(); |  | ||||||
| 		} |  | ||||||
| 		return classes; |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| } |  | ||||||
| @@ -23,4 +23,6 @@ public class OBCReflect { | |||||||
| 		return Reflect.ofClass(CRAFTBUKKIT_PACKAGE + "." + obcClass); | 		return Reflect.ofClass(CRAFTBUKKIT_PACKAGE + "." + obcClass); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	private OBCReflect() { } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -17,17 +17,15 @@ import fr.pandacube.lib.paper.reflect.wrapper.dataconverter.MCTypeRegistry; | |||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.DetectedVersion; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.DetectedVersion; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.SharedConstants; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.SharedConstants; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.WorldVersion; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.WorldVersion; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.BlockPosArgument; |  | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.CommandSourceStack; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.CommandSourceStack; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.Commands; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.Commands; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.ComponentArgument; |  | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.Coordinates; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.Coordinates; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.EntityArgument; |  | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.EntitySelector; |  | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.GameProfileArgument; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.GameProfileArgument; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.ResourceLocationArgument; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.ResourceLocationArgument; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.Vec3Argument; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.Vec3Argument; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.core.BlockPos; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.core.BlockPos; | ||||||
|  | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.core.HolderLookupProvider; | ||||||
|  | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.core.RegistryAccess; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.core.Vec3i; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.core.Vec3i; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.CollectionTag; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.CollectionTag; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.CompoundTag; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.CompoundTag; | ||||||
| @@ -66,6 +64,7 @@ import fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.ItemStack; | |||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.Level; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.Level; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.MapItemSavedData; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.MapItemSavedData; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.PlayerDataStorage; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.PlayerDataStorage; | ||||||
|  | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.RegionFileStorage; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.SavedData; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.SavedData; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.Vec3; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.Vec3; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.VoxelShape; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.VoxelShape; | ||||||
| @@ -74,9 +73,14 @@ import fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.block.Block; | |||||||
| import fr.pandacube.lib.paper.reflect.wrapper.netty.ByteBuf; | import fr.pandacube.lib.paper.reflect.wrapper.netty.ByteBuf; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.netty.Unpooled; | import fr.pandacube.lib.paper.reflect.wrapper.netty.Unpooled; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.paper.PaperAdventure; | import fr.pandacube.lib.paper.reflect.wrapper.paper.PaperAdventure; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.paper.QueuedChangesMapLong2Object; | import fr.pandacube.lib.paper.reflect.wrapper.paper.commands.BukkitCommandNode; | ||||||
|  | import fr.pandacube.lib.paper.reflect.wrapper.paper.commands.PaperBrigadier; | ||||||
|  | import fr.pandacube.lib.paper.reflect.wrapper.paper.commands.PluginCommandNode; | ||||||
|  | import fr.pandacube.lib.paper.reflect.wrapper.paper.commands.ShadowBrigNode; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.paper.configuration.FallbackValue_Int; | import fr.pandacube.lib.paper.reflect.wrapper.paper.configuration.FallbackValue_Int; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.paper.configuration.WorldConfiguration; | import fr.pandacube.lib.paper.reflect.wrapper.paper.configuration.WorldConfiguration; | ||||||
|  | import fr.pandacube.lib.paper.reflect.wrapper.spottedleaf.moonrise.ChunkSystemChunkStorage; | ||||||
|  | import fr.pandacube.lib.reflect.ReflectionWrapperBypass; | ||||||
| import fr.pandacube.lib.util.ThrowableAccumulator; | import fr.pandacube.lib.util.ThrowableAccumulator; | ||||||
|  |  | ||||||
| import static fr.pandacube.lib.reflect.wrapper.WrapperRegistry.initWrapper; | import static fr.pandacube.lib.reflect.wrapper.WrapperRegistry.initWrapper; | ||||||
| @@ -93,12 +97,14 @@ public class PandalibPaperReflect { | |||||||
|      * @throws Exception if a problem occurs when initializing wrapper classes. |      * @throws Exception if a problem occurs when initializing wrapper classes. | ||||||
|      */ |      */ | ||||||
|     public static void init() throws Exception { |     public static void init() throws Exception { | ||||||
|         NMSReflect.init(); |  | ||||||
|         synchronized (PandalibPaperReflect.class) { |         synchronized (PandalibPaperReflect.class) { | ||||||
|             if (isInit) |             if (isInit) | ||||||
|                 return; |                 return; | ||||||
|             isInit = true; |             isInit = true; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         ReflectionWrapperBypass.enable(); | ||||||
|  |  | ||||||
|         initWrapperClasses(); |         initWrapperClasses(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -127,91 +133,99 @@ public class PandalibPaperReflect { | |||||||
|         thAcc.catchThrowable(() -> initWrapper(MCTypeRegistry.class, MCTypeRegistry.REFLECT.get())); |         thAcc.catchThrowable(() -> initWrapper(MCTypeRegistry.class, MCTypeRegistry.REFLECT.get())); | ||||||
|  |  | ||||||
|         // minecraft.commands |         // minecraft.commands | ||||||
|         thAcc.catchThrowable(() -> initWrapper(BlockPosArgument.class, BlockPosArgument.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(Commands.class, Commands.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(Commands.class, Commands.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(CommandSourceStack.class, CommandSourceStack.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(CommandSourceStack.class, CommandSourceStack.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(Coordinates.class, Coordinates.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(ComponentArgument.class, ComponentArgument.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(GameProfileArgument.class, GameProfileArgument.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(Coordinates.class, Coordinates.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(ResourceLocationArgument.class, ResourceLocationArgument.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(EntityArgument.class, EntityArgument.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(Vec3Argument.class, Vec3Argument.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(EntitySelector.class, EntitySelector.MAPPING.runtimeClass())); |  | ||||||
|         thAcc.catchThrowable(() -> initWrapper(GameProfileArgument.class, GameProfileArgument.MAPPING.runtimeClass())); |  | ||||||
|         thAcc.catchThrowable(() -> initWrapper(ResourceLocationArgument.class, ResourceLocationArgument.MAPPING.runtimeClass())); |  | ||||||
|         thAcc.catchThrowable(() -> initWrapper(Vec3Argument.class, Vec3Argument.MAPPING.runtimeClass())); |  | ||||||
|         // minecraft.core |         // minecraft.core | ||||||
|         thAcc.catchThrowable(() -> initWrapper(BlockPos.class, BlockPos.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(BlockPos.class, BlockPos.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(Vec3i.class, Vec3i.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(HolderLookupProvider.class, HolderLookupProvider.REFLECT.get())); | ||||||
|  |         thAcc.catchThrowable(() -> initWrapper(RegistryAccess.class, RegistryAccess.REFLECT.get())); | ||||||
|  |         thAcc.catchThrowable(() -> initWrapper(Vec3i.class, Vec3i.REFLECT.get())); | ||||||
|         // minecraft.nbt |         // minecraft.nbt | ||||||
|         thAcc.catchThrowable(() -> initWrapper(CollectionTag.class, CollectionTag.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(CollectionTag.class, CollectionTag.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(CompoundTag.class, CompoundTag.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(CompoundTag.class, CompoundTag.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(ListTag.class, ListTag.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(ListTag.class, ListTag.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(NbtAccounter.class, NbtAccounter.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(NbtAccounter.class, NbtAccounter.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(NbtIo.class, NbtIo.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(NbtIo.class, NbtIo.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(StringTag.class, StringTag.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(StringTag.class, StringTag.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(Tag.class, Tag.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(Tag.class, Tag.REFLECT.get())); | ||||||
|         // minecraft.network.chat |         // minecraft.network.chat | ||||||
|         thAcc.catchThrowable(() -> initWrapper(Component.class, Component.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(Component.class, Component.REFLECT.get())); | ||||||
|         // minecraft.network.protocol.custom |         // minecraft.network.protocol.custom | ||||||
|         thAcc.catchThrowable(() -> initWrapper(BrandPayload.class, BrandPayload.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(BrandPayload.class, BrandPayload.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(CustomPacketPayload.class, CustomPacketPayload.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(CustomPacketPayload.class, CustomPacketPayload.REFLECT.get())); | ||||||
|         // minecraft.network.protocol |         // minecraft.network.protocol | ||||||
|         thAcc.catchThrowable(() -> initWrapper(ClientboundCustomPayloadPacket.class, ClientboundCustomPayloadPacket.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(ClientboundCustomPayloadPacket.class, ClientboundCustomPayloadPacket.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(ClientboundGameEventPacket.class, ClientboundGameEventPacket.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(ClientboundGameEventPacket.class, ClientboundGameEventPacket.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(ClientboundGameEventPacket.Type.class, ClientboundGameEventPacket.Type.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(ClientboundGameEventPacket.Type.class, ClientboundGameEventPacket.Type.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(Packet.class, Packet.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(Packet.class, Packet.REFLECT.get())); | ||||||
|         // minecraft.network |         // minecraft.network | ||||||
|         thAcc.catchThrowable(() -> initWrapper(FriendlyByteBuf.class, FriendlyByteBuf.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(FriendlyByteBuf.class, FriendlyByteBuf.REFLECT.get())); | ||||||
|         // minecraft.resources |         // minecraft.resources | ||||||
|         thAcc.catchThrowable(() -> initWrapper(ResourceLocation.class, ResourceLocation.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(ResourceLocation.class, ResourceLocation.REFLECT.get())); | ||||||
|         // minecraft.server |         // minecraft.server | ||||||
|         thAcc.catchThrowable(() -> initWrapper(ChunkMap.class, ChunkMap.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(ChunkMap.class, ChunkMap.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(DedicatedPlayerList.class, DedicatedPlayerList.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(DedicatedPlayerList.class, DedicatedPlayerList.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(DedicatedServer.class, DedicatedServer.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(DedicatedServer.class, DedicatedServer.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(DedicatedServerProperties.class, DedicatedServerProperties.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(DedicatedServerProperties.class, DedicatedServerProperties.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(MinecraftServer.class, MinecraftServer.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(MinecraftServer.class, MinecraftServer.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(PlayerList.class, PlayerList.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(PlayerList.class, PlayerList.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(ServerChunkCache.class, ServerChunkCache.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(ServerChunkCache.class, ServerChunkCache.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(ServerCommonPacketListenerImpl.class, ServerCommonPacketListenerImpl.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(ServerCommonPacketListenerImpl.class, ServerCommonPacketListenerImpl.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(ServerGamePacketListenerImpl.class, ServerGamePacketListenerImpl.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(ServerGamePacketListenerImpl.class, ServerGamePacketListenerImpl.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(ServerLevel.class, ServerLevel.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(ServerLevel.class, ServerLevel.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(ServerPlayer.class, ServerPlayer.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(ServerPlayer.class, ServerPlayer.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(Settings.class, Settings.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(Settings.class, Settings.REFLECT.get())); | ||||||
|         // minecraft.util |         // minecraft.util | ||||||
|         thAcc.catchThrowable(() -> initWrapper(ProgressListener.class, ProgressListener.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(ProgressListener.class, ProgressListener.REFLECT.get())); | ||||||
|         // minecraft.world.block |         // minecraft.world.block | ||||||
|         thAcc.catchThrowable(() -> initWrapper(Block.class, Block.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(Block.class, Block.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(BambooStalkBlock.class, BambooStalkBlock.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(BambooStalkBlock.class, BambooStalkBlock.REFLECT.get())); | ||||||
|         // minecraft.world |         // minecraft.world | ||||||
|         thAcc.catchThrowable(() -> initWrapper(AABB.class, AABB.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(AABB.class, AABB.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(ChunkPos.class, ChunkPos.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(ChunkPos.class, ChunkPos.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(ChunkStorage.class, ChunkStorage.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(ChunkStorage.class, ChunkStorage.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(DataVersion.class, DataVersion.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(DataVersion.class, DataVersion.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(Entity.class, Entity.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(Entity.class, Entity.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(ItemStack.class, ItemStack.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(ItemStack.class, ItemStack.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(Level.class, Level.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(Level.class, Level.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(MapItemSavedData.class, MapItemSavedData.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(MapItemSavedData.class, MapItemSavedData.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(PlayerDataStorage.class, PlayerDataStorage.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(PlayerDataStorage.class, PlayerDataStorage.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(SavedData.class, SavedData.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(RegionFileStorage.class, RegionFileStorage.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(Vec3.class, Vec3.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(SavedData.class, SavedData.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(VoxelShape.class, VoxelShape.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(Vec3.class, Vec3.REFLECT.get())); | ||||||
|  |         thAcc.catchThrowable(() -> initWrapper(VoxelShape.class, VoxelShape.REFLECT.get())); | ||||||
|         // minecraft |         // minecraft | ||||||
|         thAcc.catchThrowable(() -> initWrapper(DetectedVersion.class, DetectedVersion.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(DetectedVersion.class, DetectedVersion.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(SharedConstants.class, SharedConstants.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(SharedConstants.class, SharedConstants.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(WorldVersion.class, WorldVersion.MAPPING.runtimeClass())); |         thAcc.catchThrowable(() -> initWrapper(WorldVersion.class, WorldVersion.REFLECT.get())); | ||||||
|  |  | ||||||
|         // netty |         // netty | ||||||
|         thAcc.catchThrowable(() -> initWrapper(ByteBuf.class, ByteBuf.REFLECT.get())); |         thAcc.catchThrowable(() -> initWrapper(ByteBuf.class, ByteBuf.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(Unpooled.class, Unpooled.REFLECT.get())); |         thAcc.catchThrowable(() -> initWrapper(Unpooled.class, Unpooled.REFLECT.get())); | ||||||
|  |  | ||||||
|  |         // paper.commands | ||||||
|  |         thAcc.catchThrowable(() -> initWrapper(BukkitCommandNode.class, BukkitCommandNode.REFLECT.get())); | ||||||
|  |         thAcc.catchThrowable(() -> initWrapper(PaperBrigadier.class, PaperBrigadier.REFLECT.get())); | ||||||
|  |         thAcc.catchThrowable(() -> initWrapper(PluginCommandNode.class, PluginCommandNode.REFLECT.get())); | ||||||
|  |         thAcc.catchThrowable(() -> initWrapper(ShadowBrigNode.class, ShadowBrigNode.REFLECT.get())); | ||||||
|         // paper.configuration |         // paper.configuration | ||||||
|         thAcc.catchThrowable(() -> initWrapper(FallbackValue_Int.class, FallbackValue_Int.REFLECT.get())); |         thAcc.catchThrowable(() -> initWrapper(FallbackValue_Int.class, FallbackValue_Int.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(WorldConfiguration.class, WorldConfiguration.REFLECT.get())); |         thAcc.catchThrowable(() -> initWrapper(WorldConfiguration.class, WorldConfiguration.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(WorldConfiguration.Chunks.class, WorldConfiguration.Chunks.REFLECT.get())); |         thAcc.catchThrowable(() -> initWrapper(WorldConfiguration.Chunks.class, WorldConfiguration.Chunks.REFLECT.get())); | ||||||
|         // paper |         // paper | ||||||
|         thAcc.catchThrowable(() -> initWrapper(PaperAdventure.class, PaperAdventure.REFLECT.get())); |         thAcc.catchThrowable(() -> initWrapper(PaperAdventure.class, PaperAdventure.REFLECT.get())); | ||||||
|         thAcc.catchThrowable(() -> initWrapper(QueuedChangesMapLong2Object.class, QueuedChangesMapLong2Object.REFLECT.get())); |  | ||||||
|  |         // spottedleaf | ||||||
|  |         thAcc.catchThrowable(() -> initWrapper(ChunkSystemChunkStorage.class, ChunkSystemChunkStorage.REFLECT.get())); | ||||||
|  |  | ||||||
|  |  | ||||||
|         thAcc.throwCaught(); |         thAcc.throwCaught(); | ||||||
|  |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private PandalibPaperReflect() {} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -12,11 +12,25 @@ import org.bukkit.event.Listener; | |||||||
| import org.bukkit.event.block.BlockPlaceEvent; | import org.bukkit.event.block.BlockPlaceEvent; | ||||||
| import org.bukkit.util.BoundingBox; | import org.bukkit.util.BoundingBox; | ||||||
|  |  | ||||||
| // simplified version of https://github.com/Camotoy/BambooCollisionFix/tree/c7d7d5327791cbb416d106de0b9eb0bf2461acbd/src/main/java/net/camotoy/bamboocollisionfix | // simplified version of | ||||||
| // we remove the bamboo bounding box due to bedrock clients not having the same placement for bamboos |  | ||||||
|  | /** | ||||||
|  |  * Disables the server-side bounding box of the bamboo stalk blocks. | ||||||
|  |  * Bamboo stalks are the thin bamboo plants that are shifted differently, depending on the X and Z coordinate. | ||||||
|  |  * This X/Z dependent shift is different between Java and Bedrock implementation. | ||||||
|  |  * But since this block as a collision box and players cannot go through them, Bedrock players are often rolled back | ||||||
|  |  * when they are walking around bamboo stalk due to the server being in Java Edition and thinking the player tries to | ||||||
|  |  * move through the bamboo. | ||||||
|  |  * To avoid this issue, we reduce to 0 the size of the bounding box on the server. | ||||||
|  |  * <br> | ||||||
|  |  * See <a href="https://github.com/Camotoy/BambooCollisionFix/tree/c7d7d5327791cbb416d106de0b9eb0bf2461acbd/src/main/java/net/camotoy/bamboocollisionfix">the original implementation</a>. | ||||||
|  |  */ | ||||||
| public final class BedrockBambooCollisionFixer implements Listener { | public final class BedrockBambooCollisionFixer implements Listener { | ||||||
|     private final BoundingBox originalBambooBoundingBox = new BoundingBox(6.5D / 16D, 0.0D, 6.5D / 16.0D, 9.5D / 16.0D, 1D, 9.5D / 16.0D); |     private final BoundingBox originalBambooBoundingBox = new BoundingBox(6.5D / 16D, 0.0D, 6.5D / 16.0D, 9.5D / 16.0D, 1D, 9.5D / 16.0D); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Creates a new {@link BedrockBambooCollisionFixer}. There is no need for multiple instances. | ||||||
|  |      */ | ||||||
|     public BedrockBambooCollisionFixer() { |     public BedrockBambooCollisionFixer() { | ||||||
|         // Make the bamboo block have zero collision. |         // Make the bamboo block have zero collision. | ||||||
|         try { |         try { | ||||||
| @@ -34,7 +48,7 @@ public final class BedrockBambooCollisionFixer implements Listener { | |||||||
|      * our ability. |      * our ability. | ||||||
|      */ |      */ | ||||||
|     @EventHandler |     @EventHandler | ||||||
|     public void onBlockPlace(BlockPlaceEvent event) { |     void onBlockPlace(BlockPlaceEvent event) { | ||||||
|         if (event.getBlockPlaced().getBlockData().getMaterial().equals(Material.BAMBOO)) { |         if (event.getBlockPlaced().getBlockData().getMaterial().equals(Material.BAMBOO)) { | ||||||
|             BoundingBox currentBambooBoundingBox = originalBambooBoundingBox.clone().shift(event.getBlockPlaced().getLocation()); |             BoundingBox currentBambooBoundingBox = originalBambooBoundingBox.clone().shift(event.getBlockPlaced().getLocation()); | ||||||
|             for (LivingEntity e : event.getBlock().getLocation().getNearbyLivingEntities(5)) { |             for (LivingEntity e : event.getBlock().getLocation().getNearbyLivingEntities(5)) { | ||||||
|   | |||||||
| @@ -1,21 +1,24 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.util; | package fr.pandacube.lib.paper.reflect.util; | ||||||
|  |  | ||||||
| import org.bukkit.Bukkit; |  | ||||||
| import org.bukkit.World; |  | ||||||
|  |  | ||||||
| import fr.pandacube.lib.chat.Chat; | import fr.pandacube.lib.chat.Chat; | ||||||
| import fr.pandacube.lib.chat.ChatConfig.PandaTheme; | import fr.pandacube.lib.chat.ChatConfig.PandaTheme; | ||||||
| import fr.pandacube.lib.paper.modules.PerformanceAnalysisManager; | import fr.pandacube.lib.paper.modules.PerformanceAnalysisManager; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.craftbukkit.CraftWorld; | import fr.pandacube.lib.paper.reflect.wrapper.craftbukkit.CraftWorld; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.server.ChunkMap; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.server.ServerLevel; | ||||||
|  | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.util.ProgressListener; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | ||||||
|  | import org.bukkit.Bukkit; | ||||||
|  | import org.bukkit.World; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Provides static methods to save worlds presumably in a better way than Bukkit provides (better flushing, more released RAM). | ||||||
|  |  */ | ||||||
| public class WorldSaveUtil { | public class WorldSaveUtil { | ||||||
|  |  | ||||||
| 	private static ChunkMap getChunkMap(World w) { | 	/** | ||||||
| 		return ReflectWrapper.wrapTyped(w, CraftWorld.class).getHandle().getChunkSource().chunkMap; | 	 * Save the provided world using the NMS {@link ServerLevel#save(ProgressListener, boolean, boolean)} method. | ||||||
| 	} | 	 * @param w the world to save. | ||||||
| 	 | 	 */ | ||||||
| 	public static void nmsSaveFlush(World w) { | 	public static void nmsSaveFlush(World w) { | ||||||
| 		PerformanceAnalysisManager.getInstance().setAlteredTPSTitle( | 		PerformanceAnalysisManager.getInstance().setAlteredTPSTitle( | ||||||
| 				Chat.text("Sauvegarde map ").color(PandaTheme.CHAT_BROWN_2_SAT).thenData(w.getName()).thenText(" ...") | 				Chat.text("Sauvegarde map ").color(PandaTheme.CHAT_BROWN_2_SAT).thenData(w.getName()).thenText(" ...") | ||||||
| @@ -28,8 +31,13 @@ public class WorldSaveUtil { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Save all the loaded worlds, using {@link #nmsSaveFlush(World)}. | ||||||
|  | 	 */ | ||||||
| 	public static void nmsSaveAllFlush() { | 	public static void nmsSaveAllFlush() { | ||||||
| 		Bukkit.getWorlds().forEach(WorldSaveUtil::nmsSaveFlush); | 		Bukkit.getWorlds().forEach(WorldSaveUtil::nmsSaveFlush); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	private WorldSaveUtil() {} | ||||||
|  | 	 | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,7 +1,6 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.craftbukkit; | package fr.pandacube.lib.paper.reflect.wrapper.craftbukkit; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.OBCReflect; | import fr.pandacube.lib.paper.reflect.OBCReflect; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt.CompoundTag; |  | ||||||
| import fr.pandacube.lib.reflect.ReflectClass; | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
| import fr.pandacube.lib.reflect.ReflectMethod; | import fr.pandacube.lib.reflect.ReflectMethod; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapperTyped; | import fr.pandacube.lib.reflect.wrapper.ReflectWrapperTyped; | ||||||
| @@ -12,7 +11,7 @@ import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | |||||||
|  |  | ||||||
| public class CraftItemStack extends ReflectWrapperTyped<ItemStack> { | public class CraftItemStack extends ReflectWrapperTyped<ItemStack> { | ||||||
|     public static final ReflectClass<?> REFLECT = wrapEx(() -> OBCReflect.ofClass("inventory.CraftItemStack")); |     public static final ReflectClass<?> REFLECT = wrapEx(() -> OBCReflect.ofClass("inventory.CraftItemStack")); | ||||||
|     public static final ReflectMethod<?> asCraftMirror = wrapEx(() -> REFLECT.method("asCraftMirror", fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.ItemStack.MAPPING.runtimeClass())); |     public static final ReflectMethod<?> asCraftMirror = wrapEx(() -> REFLECT.method("asCraftMirror", fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.ItemStack.REFLECT.get())); | ||||||
|     public static final ReflectMethod<?> asNMSCopy = wrapEx(() -> REFLECT.method("asNMSCopy", ItemStack.class)); |     public static final ReflectMethod<?> asNMSCopy = wrapEx(() -> REFLECT.method("asNMSCopy", ItemStack.class)); | ||||||
|  |  | ||||||
|     public static ItemStack asCraftMirror(fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.ItemStack original) { |     public static ItemStack asCraftMirror(fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.ItemStack original) { | ||||||
| @@ -20,11 +19,6 @@ public class CraftItemStack extends ReflectWrapperTyped<ItemStack> { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     public static ItemStack asCraftMirror(CompoundTag nbt) { |  | ||||||
|         return asCraftMirror(fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.ItemStack.of(nbt)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     public static fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.ItemStack asNMSCopy(ItemStack original) { |     public static fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.ItemStack asNMSCopy(ItemStack original) { | ||||||
|         return wrap(wrapReflectEx(() -> asNMSCopy.invokeStatic(original)), fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.ItemStack.class); |         return wrap(wrapReflectEx(() -> asNMSCopy.invokeStatic(original)), fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.ItemStack.class); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -15,7 +15,7 @@ import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | |||||||
| public class CraftNamespacedKey extends ReflectWrapper { | public class CraftNamespacedKey extends ReflectWrapper { | ||||||
|     public static final ReflectClass<?> REFLECT = wrapEx(() -> OBCReflect.ofClass("util.CraftNamespacedKey")); |     public static final ReflectClass<?> REFLECT = wrapEx(() -> OBCReflect.ofClass("util.CraftNamespacedKey")); | ||||||
|     public static final ReflectMethod<?> toMinecraft = wrapEx(() -> REFLECT.method("toMinecraft", NamespacedKey.class)); |     public static final ReflectMethod<?> toMinecraft = wrapEx(() -> REFLECT.method("toMinecraft", NamespacedKey.class)); | ||||||
|     public static final ReflectMethod<?> fromMinecraft = ThrowableUtil.wrapEx(() -> REFLECT.method("fromMinecraft", ResourceLocation.MAPPING.runtimeClass())); |     public static final ReflectMethod<?> fromMinecraft = ThrowableUtil.wrapEx(() -> REFLECT.method("fromMinecraft", ResourceLocation.REFLECT.get())); | ||||||
|  |  | ||||||
|     public static ResourceLocation toMinecraft(NamespacedKey key) { |     public static ResourceLocation toMinecraft(NamespacedKey key) { | ||||||
|         return wrap(wrapReflectEx(() -> toMinecraft.invokeStatic(key)), ResourceLocation.class); |         return wrap(wrapReflectEx(() -> toMinecraft.invokeStatic(key)), ResourceLocation.class); | ||||||
|   | |||||||
| @@ -15,8 +15,8 @@ import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | |||||||
|  |  | ||||||
| public class CraftVector extends ReflectWrapper { | public class CraftVector extends ReflectWrapper { | ||||||
|     public static final ReflectClass<?> REFLECT = wrapEx(() -> OBCReflect.ofClass("util.CraftVector")); |     public static final ReflectClass<?> REFLECT = wrapEx(() -> OBCReflect.ofClass("util.CraftVector")); | ||||||
|     public static final ReflectMethod<?> toBukkit_Vec3 = ThrowableUtil.wrapEx(() -> REFLECT.method("toBukkit", Vec3.MAPPING.runtimeClass())); |     public static final ReflectMethod<?> toBukkit_Vec3 = ThrowableUtil.wrapEx(() -> REFLECT.method("toBukkit", Vec3.REFLECT.get())); | ||||||
|     public static final ReflectMethod<?> toBukkit_BlockPos = ThrowableUtil.wrapEx(() -> REFLECT.method("toBukkit", BlockPos.MAPPING.runtimeClass())); |     public static final ReflectMethod<?> toBukkit_BlockPos = ThrowableUtil.wrapEx(() -> REFLECT.method("toBukkit", BlockPos.REFLECT.get())); | ||||||
|     public static final ReflectMethod<?> toNMS = wrapEx(() -> REFLECT.method("toNMS", Vector.class)); |     public static final ReflectMethod<?> toNMS = wrapEx(() -> REFLECT.method("toNMS", Vector.class)); | ||||||
|     public static final ReflectMethod<?> toBlockPos = wrapEx(() -> REFLECT.method("toNMS", Vector.class)); |     public static final ReflectMethod<?> toBlockPos = wrapEx(() -> REFLECT.method("toNMS", Vector.class)); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,16 +1,14 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.craftbukkit; | package fr.pandacube.lib.paper.reflect.wrapper.craftbukkit; | ||||||
|  |  | ||||||
| import com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource; |  | ||||||
| import com.mojang.brigadier.tree.CommandNode; | import com.mojang.brigadier.tree.CommandNode; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.OBCReflect; | import fr.pandacube.lib.paper.reflect.OBCReflect; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapperTyped; |  | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.Commands; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands.Commands; | ||||||
| import fr.pandacube.lib.reflect.ReflectClass; | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
| import fr.pandacube.lib.reflect.ReflectConstructor; | import fr.pandacube.lib.reflect.ReflectConstructor; | ||||||
| import fr.pandacube.lib.reflect.ReflectField; | import fr.pandacube.lib.reflect.ReflectField; | ||||||
| import fr.pandacube.lib.reflect.ReflectMethod; | import fr.pandacube.lib.reflect.ReflectMethod; | ||||||
|  | import fr.pandacube.lib.reflect.wrapper.ReflectWrapperTyped; | ||||||
|  | import io.papermc.paper.command.brigadier.CommandSourceStack; | ||||||
| import org.bukkit.command.CommandSender; | import org.bukkit.command.CommandSender; | ||||||
| import org.bukkit.command.defaults.BukkitCommand; | import org.bukkit.command.defaults.BukkitCommand; | ||||||
|  |  | ||||||
| @@ -19,21 +17,21 @@ import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | |||||||
|  |  | ||||||
| public class VanillaCommandWrapper extends ReflectWrapperTyped<BukkitCommand> { | public class VanillaCommandWrapper extends ReflectWrapperTyped<BukkitCommand> { | ||||||
|     public static final ReflectClass<?> REFLECT = wrapEx(() -> OBCReflect.ofClass("command.VanillaCommandWrapper")); |     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<?> CONSTRUCTOR = wrapEx(() -> REFLECT.constructor(Commands.REFLECT.get(), CommandNode.class)); | ||||||
|     public static final ReflectField<?> vanillaCommand = wrapEx(() -> REFLECT.field("vanillaCommand")); |     public static final ReflectField<?> vanillaCommand = wrapEx(() -> REFLECT.field("vanillaCommand")); | ||||||
|     public static final ReflectMethod<?> getListener = wrapEx(() -> REFLECT.method("getListener", CommandSender.class)); |     public static final ReflectMethod<?> getListener = wrapEx(() -> REFLECT.method("getListener", CommandSender.class)); | ||||||
|  |  | ||||||
|     public VanillaCommandWrapper(Commands dispatcher, CommandNode<BukkitBrigadierCommandSource> vanillaCommand) { |     public VanillaCommandWrapper(Commands dispatcher, CommandNode<CommandSourceStack> vanillaCommand) { | ||||||
|         this(wrapReflectEx(() -> CONSTRUCTOR.instantiate(unwrap(dispatcher), vanillaCommand))); |         this(wrapReflectEx(() -> CONSTRUCTOR.instantiate(unwrap(dispatcher), vanillaCommand))); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @SuppressWarnings("unchecked") |     @SuppressWarnings("unchecked") | ||||||
|     public CommandNode<BukkitBrigadierCommandSource> vanillaCommand() { |     public CommandNode<CommandSourceStack> vanillaCommand() { | ||||||
|         return (CommandNode<BukkitBrigadierCommandSource>) wrapReflectEx(() -> vanillaCommand.getValue(__getRuntimeInstance())); |         return (CommandNode<CommandSourceStack>) wrapReflectEx(() -> vanillaCommand.getValue(__getRuntimeInstance())); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static BukkitBrigadierCommandSource getListener(CommandSender sender) { |     public static CommandSourceStack getListener(CommandSender sender) { | ||||||
|         return (BukkitBrigadierCommandSource) wrapReflectEx(() -> getListener.invokeStatic(sender)); |         return (CommandSourceStack) wrapReflectEx(() -> getListener.invokeStatic(sender)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     protected VanillaCommandWrapper(Object obj) { |     protected VanillaCommandWrapper(Object obj) { | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | |||||||
|  |  | ||||||
| public class MCDataConverter extends ReflectWrapper { | public class MCDataConverter extends ReflectWrapper { | ||||||
|     public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("ca.spottedleaf.dataconverter.minecraft.MCDataConverter")); |     public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("ca.spottedleaf.dataconverter.minecraft.MCDataConverter")); | ||||||
|     private static final ReflectMethod<?> convertTag = wrapEx(() -> REFLECT.method("convertTag", MCDataType.REFLECT.get(), CompoundTag.MAPPING.runtimeClass(), int.class, int.class)); |     private static final ReflectMethod<?> convertTag = wrapEx(() -> REFLECT.method("convertTag", MCDataType.REFLECT.get(), CompoundTag.REFLECT.get(), int.class, int.class)); | ||||||
|  |  | ||||||
|     public static CompoundTag convertTag(MCDataType type, CompoundTag data, int fromVersion, int toVersion) { |     public static CompoundTag convertTag(MCDataType type, CompoundTag data, int fromVersion, int toVersion) { | ||||||
|         return wrap(wrapReflectEx(() -> convertTag.invokeStatic(unwrap(type), unwrap(data), fromVersion, toVersion)), CompoundTag.class); |         return wrap(wrapReflectEx(() -> convertTag.invokeStatic(unwrap(type), unwrap(data), fromVersion, toVersion)), CompoundTag.class); | ||||||
|   | |||||||
| @@ -1,12 +1,13 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; | import fr.pandacube.lib.reflect.Reflect; | ||||||
|  | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | ||||||
|  |  | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | ||||||
|  |  | ||||||
| public class DetectedVersion extends ReflectWrapper implements WorldVersion { | public class DetectedVersion extends ReflectWrapper implements WorldVersion { | ||||||
|     public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.DetectedVersion")); |     public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.DetectedVersion")); | ||||||
|  |  | ||||||
|     protected DetectedVersion(Object obj) { |     protected DetectedVersion(Object obj) { | ||||||
|         super(obj); |         super(obj); | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; | import fr.pandacube.lib.reflect.Reflect; | ||||||
|  | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
| import fr.pandacube.lib.reflect.ReflectMethod; | import fr.pandacube.lib.reflect.ReflectMethod; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | ||||||
|  |  | ||||||
| @@ -8,9 +9,9 @@ import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | |||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | ||||||
|  |  | ||||||
| public class SharedConstants extends ReflectWrapper { | public class SharedConstants extends ReflectWrapper { | ||||||
|     public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.SharedConstants")); |     public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.SharedConstants")); | ||||||
|     private static final ReflectMethod<?> getCurrentVersion = wrapEx(() -> MAPPING.mojMethod("getCurrentVersion")); |     private static final ReflectMethod<?> getCurrentVersion = wrapEx(() -> REFLECT.method("getCurrentVersion")); | ||||||
|     private static final ReflectMethod<?> getProtocolVersion = wrapEx(() -> MAPPING.mojMethod("getProtocolVersion")); |     private static final ReflectMethod<?> getProtocolVersion = wrapEx(() -> REFLECT.method("getProtocolVersion")); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,8 +1,8 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect.ClassMapping; |  | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.DataVersion; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.DataVersion; | ||||||
|  | import fr.pandacube.lib.reflect.Reflect; | ||||||
|  | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
| import fr.pandacube.lib.reflect.ReflectMethod; | import fr.pandacube.lib.reflect.ReflectMethod; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ConcreteWrapper; | import fr.pandacube.lib.reflect.wrapper.ConcreteWrapper; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | ||||||
| @@ -14,8 +14,8 @@ import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | |||||||
|  |  | ||||||
| @ConcreteWrapper(WorldVersion.__concrete.class) | @ConcreteWrapper(WorldVersion.__concrete.class) | ||||||
| public interface WorldVersion extends ReflectWrapperI { | public interface WorldVersion extends ReflectWrapperI { | ||||||
|     ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.WorldVersion")); |     ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.WorldVersion")); | ||||||
|     ReflectMethod<?> getDataVersion = wrapEx(() -> MAPPING.mojMethod("getDataVersion")); |     ReflectMethod<?> getDataVersion = wrapEx(() -> REFLECT.method("getDataVersion")); | ||||||
|  |  | ||||||
|     default DataVersion getDataVersion() { |     default DataVersion getDataVersion() { | ||||||
|         return wrap(wrapReflectEx(() -> getDataVersion.invoke(__getRuntimeInstance())), DataVersion.class); |         return wrap(wrapReflectEx(() -> getDataVersion.invoke(__getRuntimeInstance())), DataVersion.class); | ||||||
|   | |||||||
| @@ -1,24 +0,0 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands; |  | ||||||
|  |  | ||||||
| import com.mojang.brigadier.arguments.ArgumentType; |  | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; |  | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapperTyped; |  | ||||||
| import fr.pandacube.lib.reflect.ReflectMethod; |  | ||||||
|  |  | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; |  | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; |  | ||||||
|  |  | ||||||
| public class BlockPosArgument extends ReflectWrapperTyped<ArgumentType<?>> { |  | ||||||
|     public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.commands.arguments.coordinates.BlockPosArgument")); |  | ||||||
|     private static final ReflectMethod<?> blockPos = wrapEx(() -> MAPPING.mojMethod("blockPos")); |  | ||||||
|  |  | ||||||
|     @SuppressWarnings("unchecked") |  | ||||||
|     public static ArgumentType<Object> blockPos() { |  | ||||||
|         return (ArgumentType<Object>) wrapReflectEx(() -> blockPos.invokeStatic()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     protected BlockPosArgument(Object obj) { |  | ||||||
|         super(obj); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,13 +1,13 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands; | ||||||
|  |  | ||||||
| import com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource; | import fr.pandacube.lib.reflect.Reflect; | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapperTyped; | import fr.pandacube.lib.reflect.wrapper.ReflectWrapperTyped; | ||||||
|  |  | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | ||||||
|  |  | ||||||
| public class CommandSourceStack extends ReflectWrapperTyped<BukkitBrigadierCommandSource> { | public class CommandSourceStack extends ReflectWrapperTyped<io.papermc.paper.command.brigadier.CommandSourceStack> { | ||||||
|     public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.commands.CommandSourceStack")); |     public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.commands.CommandSourceStack")); | ||||||
|  |  | ||||||
|     protected CommandSourceStack(Object obj) { |     protected CommandSourceStack(Object obj) { | ||||||
|         super(obj); |         super(obj); | ||||||
|   | |||||||
| @@ -1,22 +1,21 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands; | ||||||
|  |  | ||||||
| import com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource; |  | ||||||
| import com.mojang.brigadier.CommandDispatcher; | import com.mojang.brigadier.CommandDispatcher; | ||||||
|  | import fr.pandacube.lib.reflect.Reflect; | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; |  | ||||||
| import fr.pandacube.lib.reflect.ReflectField; | 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.wrapEx; | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | ||||||
|  |  | ||||||
| public class Commands extends ReflectWrapper { | public class Commands extends ReflectWrapper { | ||||||
|     public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.commands.Commands")); |     public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.commands.Commands")); | ||||||
|     public static final ReflectField<?> dispatcher = wrapEx(() -> MAPPING.mojField("dispatcher")); |     public static final ReflectField<?> dispatcher = wrapEx(() -> REFLECT.field("dispatcher")); | ||||||
|  |  | ||||||
|     @SuppressWarnings("unchecked") |     @SuppressWarnings("unchecked") | ||||||
|     public CommandDispatcher<BukkitBrigadierCommandSource> dispatcher() { |     public CommandDispatcher<CommandSourceStack> dispatcher() { | ||||||
|         return (CommandDispatcher<BukkitBrigadierCommandSource>) wrapReflectEx(() -> dispatcher.getValue(__getRuntimeInstance())); |         return (CommandDispatcher<CommandSourceStack>) wrapReflectEx(() -> dispatcher.getValue(__getRuntimeInstance())); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     protected Commands(Object obj) { |     protected Commands(Object obj) { | ||||||
|   | |||||||
| @@ -1,24 +0,0 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands; |  | ||||||
|  |  | ||||||
| import com.mojang.brigadier.arguments.ArgumentType; |  | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; |  | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapperTyped; |  | ||||||
| import fr.pandacube.lib.reflect.ReflectMethod; |  | ||||||
|  |  | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; |  | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; |  | ||||||
|  |  | ||||||
| public class ComponentArgument extends ReflectWrapperTyped<ArgumentType<?>> { |  | ||||||
|     public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.commands.arguments.ComponentArgument")); |  | ||||||
|     private static final ReflectMethod<?> textComponent = wrapEx(() -> MAPPING.mojMethod("textComponent")); |  | ||||||
|  |  | ||||||
|     @SuppressWarnings("unchecked") |  | ||||||
|     public static ArgumentType<Object> textComponent() { |  | ||||||
|         return (ArgumentType<Object>) wrapReflectEx(() -> textComponent.invokeStatic()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     protected ComponentArgument(Object obj) { |  | ||||||
|         super(obj); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,33 +1,26 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands; | ||||||
|  |  | ||||||
| import com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.Vec3; | ||||||
|  | import fr.pandacube.lib.reflect.Reflect; | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
|  | import fr.pandacube.lib.reflect.ReflectMethod; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ConcreteWrapper; | import fr.pandacube.lib.reflect.wrapper.ConcreteWrapper; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapperI; | import fr.pandacube.lib.reflect.wrapper.ReflectWrapperI; | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.core.BlockPos; |  | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.Vec3; |  | ||||||
| import fr.pandacube.lib.reflect.ReflectMethod; |  | ||||||
|  |  | ||||||
|  | import static fr.pandacube.lib.reflect.wrapper.ReflectWrapper.wrap; | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | ||||||
| import static fr.pandacube.lib.reflect.wrapper.ReflectWrapper.wrap; |  | ||||||
|  |  | ||||||
| @ConcreteWrapper(Coordinates.__concrete.class) | @ConcreteWrapper(Coordinates.__concrete.class) | ||||||
| public interface Coordinates extends ReflectWrapperI { | public interface Coordinates extends ReflectWrapperI { | ||||||
|     NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.commands.arguments.coordinates.Coordinates")); |     public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.commands.arguments.coordinates.Coordinates")); | ||||||
|     ReflectMethod<?> getPosition = wrapEx(() -> MAPPING.mojMethod("getPosition", CommandSourceStack.MAPPING)); |     ReflectMethod<?> getPosition = wrapEx(() -> REFLECT.method("getPosition", CommandSourceStack.REFLECT.get())); | ||||||
|     ReflectMethod<?> getBlockPos = wrapEx(() -> MAPPING.mojMethod("getBlockPos", CommandSourceStack.MAPPING)); |  | ||||||
|  |  | ||||||
|     default Vec3 getPosition(BukkitBrigadierCommandSource source) { |     default Vec3 getPosition(io.papermc.paper.command.brigadier.CommandSourceStack source) { | ||||||
|         return wrap(wrapReflectEx(() -> getPosition.invoke(__getRuntimeInstance(), source)), Vec3.class); |         return wrap(wrapReflectEx(() -> getPosition.invoke(__getRuntimeInstance(), source)), Vec3.class); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     default BlockPos getBlockPos(BukkitBrigadierCommandSource source) { |  | ||||||
|         return wrap(wrapReflectEx(() -> getBlockPos.invoke(__getRuntimeInstance(), source)), BlockPos.class); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     class __concrete extends ReflectWrapper implements Coordinates { |     class __concrete extends ReflectWrapper implements Coordinates { | ||||||
|         protected __concrete(Object obj) { |         protected __concrete(Object obj) { | ||||||
|             super(obj); |             super(obj); | ||||||
|   | |||||||
| @@ -1,43 +0,0 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands; |  | ||||||
|  |  | ||||||
| import com.mojang.brigadier.arguments.ArgumentType; |  | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; |  | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapperTyped; |  | ||||||
| import fr.pandacube.lib.reflect.ReflectMethod; |  | ||||||
|  |  | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; |  | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; |  | ||||||
|  |  | ||||||
| public class EntityArgument extends ReflectWrapperTyped<ArgumentType<?>> { |  | ||||||
|     public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.commands.arguments.EntityArgument")); |  | ||||||
|     private static final ReflectMethod<?> entity = wrapEx(() -> MAPPING.mojMethod("entity")); |  | ||||||
|     private static final ReflectMethod<?> entities = wrapEx(() -> MAPPING.mojMethod("entities")); |  | ||||||
|     private static final ReflectMethod<?> player = wrapEx(() -> MAPPING.mojMethod("player")); |  | ||||||
|     private static final ReflectMethod<?> players = wrapEx(() -> MAPPING.mojMethod("players")); |  | ||||||
|  |  | ||||||
|     @SuppressWarnings("unchecked") |  | ||||||
|     public static ArgumentType<Object> entity() { |  | ||||||
|         return (ArgumentType<Object>) wrapReflectEx(() -> entity.invokeStatic()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @SuppressWarnings("unchecked") |  | ||||||
|     public static ArgumentType<Object> entities() { |  | ||||||
|         return (ArgumentType<Object>) wrapReflectEx(() -> entities.invokeStatic()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @SuppressWarnings("unchecked") |  | ||||||
|     public static ArgumentType<Object> player() { |  | ||||||
|         return (ArgumentType<Object>) wrapReflectEx(() -> player.invokeStatic()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @SuppressWarnings("unchecked") |  | ||||||
|     public static ArgumentType<Object> players() { |  | ||||||
|         return (ArgumentType<Object>) wrapReflectEx(() -> players.invokeStatic()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     protected EntityArgument(Object obj) { |  | ||||||
|         super(obj); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,46 +0,0 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands; |  | ||||||
|  |  | ||||||
| import com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource; |  | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; |  | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectListWrapper; |  | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; |  | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.server.ServerPlayer; |  | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.Entity; |  | ||||||
| import fr.pandacube.lib.reflect.ReflectMethod; |  | ||||||
|  |  | ||||||
| import java.util.List; |  | ||||||
|  |  | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; |  | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; |  | ||||||
|  |  | ||||||
| public class EntitySelector extends ReflectWrapper { |  | ||||||
|     public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.commands.arguments.selector.EntitySelector")); |  | ||||||
|     private static final ReflectMethod<?> findEntities = wrapEx(() -> MAPPING.mojMethod("findEntities", CommandSourceStack.MAPPING)); |  | ||||||
|     private static final ReflectMethod<?> findPlayers = wrapEx(() -> MAPPING.mojMethod("findPlayers", CommandSourceStack.MAPPING)); |  | ||||||
|     private static final ReflectMethod<?> findSingleEntity = wrapEx(() -> MAPPING.mojMethod("findSingleEntity", CommandSourceStack.MAPPING)); |  | ||||||
|     private static final ReflectMethod<?> findSinglePlayer = wrapEx(() -> MAPPING.mojMethod("findSinglePlayer", CommandSourceStack.MAPPING)); |  | ||||||
|  |  | ||||||
|     @SuppressWarnings("unchecked") |  | ||||||
|     public ReflectListWrapper<Entity> findEntities(BukkitBrigadierCommandSource source) { |  | ||||||
|         return wrapList((List<Object>) wrapReflectEx(() -> findEntities.invoke(__getRuntimeInstance(), source)), Entity.class); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public Entity findSingleEntity(BukkitBrigadierCommandSource source) { |  | ||||||
|         return wrap(wrapReflectEx(() -> findSingleEntity.invoke(__getRuntimeInstance(), source)), Entity.class); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @SuppressWarnings("unchecked") |  | ||||||
|     public ReflectListWrapper<ServerPlayer> findPlayers(BukkitBrigadierCommandSource source) { |  | ||||||
|         return wrapList((List<Object>) wrapReflectEx(() -> findPlayers.invoke(__getRuntimeInstance(), source)), ServerPlayer.class); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public ServerPlayer findSinglePlayer(BukkitBrigadierCommandSource source) { |  | ||||||
|         return wrap(wrapReflectEx(() -> findSinglePlayer.invoke(__getRuntimeInstance(), source)), ServerPlayer.class); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     protected EntitySelector(Object obj) { |  | ||||||
|         super(obj); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,17 +1,17 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands; | ||||||
|  |  | ||||||
| import com.mojang.brigadier.arguments.ArgumentType; | import com.mojang.brigadier.arguments.ArgumentType; | ||||||
|  | import fr.pandacube.lib.reflect.Reflect; | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapperTyped; |  | ||||||
| import fr.pandacube.lib.reflect.ReflectMethod; | import fr.pandacube.lib.reflect.ReflectMethod; | ||||||
|  | import fr.pandacube.lib.reflect.wrapper.ReflectWrapperTyped; | ||||||
|  |  | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | ||||||
|  |  | ||||||
| public class GameProfileArgument extends ReflectWrapperTyped<ArgumentType<?>> { | public class GameProfileArgument extends ReflectWrapperTyped<ArgumentType<?>> { | ||||||
|     public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.commands.arguments.GameProfileArgument")); |     public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.commands.arguments.GameProfileArgument")); | ||||||
|     private static final ReflectMethod<?> gameProfile = wrapEx(() -> MAPPING.mojMethod("gameProfile")); |     private static final ReflectMethod<?> gameProfile = wrapEx(() -> REFLECT.method("gameProfile")); | ||||||
|  |  | ||||||
|     @SuppressWarnings("unchecked") |     @SuppressWarnings("unchecked") | ||||||
|     public static ArgumentType<Object> gameProfile() { |     public static ArgumentType<Object> gameProfile() { | ||||||
|   | |||||||
| @@ -1,17 +1,17 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands; | ||||||
|  |  | ||||||
| import com.mojang.brigadier.arguments.ArgumentType; | import com.mojang.brigadier.arguments.ArgumentType; | ||||||
|  | import fr.pandacube.lib.reflect.Reflect; | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapperTyped; |  | ||||||
| import fr.pandacube.lib.reflect.ReflectMethod; | import fr.pandacube.lib.reflect.ReflectMethod; | ||||||
|  | import fr.pandacube.lib.reflect.wrapper.ReflectWrapperTyped; | ||||||
|  |  | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | ||||||
|  |  | ||||||
| public class ResourceLocationArgument extends ReflectWrapperTyped<ArgumentType<?>> { | public class ResourceLocationArgument extends ReflectWrapperTyped<ArgumentType<?>> { | ||||||
|     public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.commands.arguments.ResourceLocationArgument")); |     public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.commands.arguments.ResourceLocationArgument")); | ||||||
|     private static final ReflectMethod<?> id = wrapEx(() -> MAPPING.mojMethod("id")); |     private static final ReflectMethod<?> id = wrapEx(() -> REFLECT.method("id")); | ||||||
|  |  | ||||||
|     @SuppressWarnings("unchecked") |     @SuppressWarnings("unchecked") | ||||||
|     public static ArgumentType<Object> id() { |     public static ArgumentType<Object> id() { | ||||||
|   | |||||||
| @@ -1,17 +1,17 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.commands; | ||||||
|  |  | ||||||
| import com.mojang.brigadier.arguments.ArgumentType; | import com.mojang.brigadier.arguments.ArgumentType; | ||||||
|  | import fr.pandacube.lib.reflect.Reflect; | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapperTyped; |  | ||||||
| import fr.pandacube.lib.reflect.ReflectMethod; | import fr.pandacube.lib.reflect.ReflectMethod; | ||||||
|  | import fr.pandacube.lib.reflect.wrapper.ReflectWrapperTyped; | ||||||
|  |  | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | ||||||
|  |  | ||||||
| public class Vec3Argument extends ReflectWrapperTyped<ArgumentType<?>> { | public class Vec3Argument extends ReflectWrapperTyped<ArgumentType<?>> { | ||||||
|     public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.commands.arguments.coordinates.Vec3Argument")); |     public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.commands.arguments.coordinates.Vec3Argument")); | ||||||
|     private static final ReflectMethod<?> vec3 = wrapEx(() -> MAPPING.mojMethod("vec3", boolean.class)); |     private static final ReflectMethod<?> vec3 = wrapEx(() -> REFLECT.method("vec3", boolean.class)); | ||||||
|  |  | ||||||
|     @SuppressWarnings("unchecked") |     @SuppressWarnings("unchecked") | ||||||
|     public static ArgumentType<Object> vec3(boolean centerIntegers) { |     public static ArgumentType<Object> vec3(boolean centerIntegers) { | ||||||
|   | |||||||
| @@ -1,11 +1,12 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.core; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.core; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; | import fr.pandacube.lib.reflect.Reflect; | ||||||
|  | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
|  |  | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | ||||||
|  |  | ||||||
| public class BlockPos extends Vec3i { | public class BlockPos extends Vec3i { | ||||||
|     public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.core.BlockPos")); |     public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.core.BlockPos")); | ||||||
|  |  | ||||||
|     protected BlockPos(Object obj) { |     protected BlockPos(Object obj) { | ||||||
|         super(obj); |         super(obj); | ||||||
|   | |||||||
| @@ -0,0 +1,20 @@ | |||||||
|  | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.core; | ||||||
|  |  | ||||||
|  | import fr.pandacube.lib.reflect.Reflect; | ||||||
|  | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
|  | import fr.pandacube.lib.reflect.wrapper.ConcreteWrapper; | ||||||
|  | import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | ||||||
|  | import fr.pandacube.lib.reflect.wrapper.ReflectWrapperI; | ||||||
|  |  | ||||||
|  | import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | ||||||
|  |  | ||||||
|  | @ConcreteWrapper(HolderLookupProvider.__concrete.class) | ||||||
|  | public interface HolderLookupProvider extends ReflectWrapperI { | ||||||
|  |     ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.core.HolderLookup$Provider")); | ||||||
|  |  | ||||||
|  |     class __concrete extends ReflectWrapper implements HolderLookupProvider { | ||||||
|  |         protected __concrete(Object obj) { | ||||||
|  |             super(obj); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,19 @@ | |||||||
|  | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.core; | ||||||
|  |  | ||||||
|  | import fr.pandacube.lib.reflect.Reflect; | ||||||
|  | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
|  | import fr.pandacube.lib.reflect.wrapper.ConcreteWrapper; | ||||||
|  | import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | ||||||
|  |  | ||||||
|  | import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | ||||||
|  |  | ||||||
|  | @ConcreteWrapper(RegistryAccess.__concrete.class) | ||||||
|  | public interface RegistryAccess extends HolderLookupProvider { | ||||||
|  |     ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.core.RegistryAccess")); | ||||||
|  |  | ||||||
|  |     class __concrete extends ReflectWrapper implements RegistryAccess { | ||||||
|  |         protected __concrete(Object obj) { | ||||||
|  |             super(obj); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,17 +1,18 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.core; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.core; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; | import fr.pandacube.lib.reflect.Reflect; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
| import fr.pandacube.lib.reflect.ReflectMethod; | 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.wrapEx; | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | ||||||
|  |  | ||||||
| public class Vec3i extends ReflectWrapper { | public class Vec3i extends ReflectWrapper { | ||||||
|     public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.core.Vec3i")); |     public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.core.Vec3i")); | ||||||
|     public static final ReflectMethod<?> getX = wrapEx(() -> MAPPING.mojMethod("getX")); |     public static final ReflectMethod<?> getX = wrapEx(() -> REFLECT.method("getX")); | ||||||
|     public static final ReflectMethod<?> getY = wrapEx(() -> MAPPING.mojMethod("getY")); |     public static final ReflectMethod<?> getY = wrapEx(() -> REFLECT.method("getY")); | ||||||
|     public static final ReflectMethod<?> getZ = wrapEx(() -> MAPPING.mojMethod("getZ")); |     public static final ReflectMethod<?> getZ = wrapEx(() -> REFLECT.method("getZ")); | ||||||
|  |  | ||||||
|     public int getX() { |     public int getX() { | ||||||
|         return (int) wrapReflectEx(() -> getX.invoke(__getRuntimeInstance())); |         return (int) wrapReflectEx(() -> getX.invoke(__getRuntimeInstance())); | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; | import fr.pandacube.lib.reflect.Reflect; | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect.ClassMapping; | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapperTyped; | import fr.pandacube.lib.reflect.wrapper.ReflectWrapperTyped; | ||||||
|  |  | ||||||
| import java.util.AbstractList; | import java.util.AbstractList; | ||||||
| @@ -9,7 +9,7 @@ import java.util.AbstractList; | |||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | ||||||
|  |  | ||||||
| public class CollectionTag extends ReflectWrapperTyped<AbstractList<?>> implements Tag { | public class CollectionTag extends ReflectWrapperTyped<AbstractList<?>> implements Tag { | ||||||
| 	public static final ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.nbt.CollectionTag")); | 	public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.nbt.CollectionTag")); | ||||||
|  |  | ||||||
|  |  | ||||||
| 	public int size() { | 	public int size() { | ||||||
|   | |||||||
| @@ -1,60 +1,60 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt; | ||||||
|  |  | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | import fr.pandacube.lib.reflect.Reflect; | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
|  | import fr.pandacube.lib.reflect.ReflectConstructor; | ||||||
|  | import fr.pandacube.lib.reflect.ReflectMethod; | ||||||
|  | import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | ||||||
|  |  | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import java.util.Set; | import java.util.Set; | ||||||
| import java.util.UUID; | import java.util.UUID; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.reflect.ReflectConstructor; | import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | ||||||
| import fr.pandacube.lib.reflect.ReflectMethod; | import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect.ClassMapping; |  | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; |  | ||||||
|  |  | ||||||
| public class CompoundTag extends ReflectWrapper implements Tag { | public class CompoundTag extends ReflectWrapper implements Tag { | ||||||
| 	public static final ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.nbt.CompoundTag")); | 	public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.nbt.CompoundTag")); | ||||||
| 	public static final ReflectConstructor<?> CONSTRUCTOR = wrapEx(() -> MAPPING.runtimeReflect().constructor()); | 	public static final ReflectConstructor<?> CONSTRUCTOR = wrapEx(() -> REFLECT.constructor()); | ||||||
| 	private static final ReflectMethod<?> putBoolean = wrapEx(() -> MAPPING.mojMethod("putBoolean", String.class, boolean.class)); | 	private static final ReflectMethod<?> putBoolean = wrapEx(() -> REFLECT.method("putBoolean", String.class, boolean.class)); | ||||||
| 	private static final ReflectMethod<?> putByte = wrapEx(() -> MAPPING.mojMethod("putByte", String.class, byte.class)); | 	private static final ReflectMethod<?> putByte = wrapEx(() -> REFLECT.method("putByte", String.class, byte.class)); | ||||||
| 	private static final ReflectMethod<?> putByteArray = wrapEx(() -> MAPPING.mojMethod("putByteArray", String.class, byte[].class)); | 	private static final ReflectMethod<?> putByteArray = wrapEx(() -> REFLECT.method("putByteArray", String.class, byte[].class)); | ||||||
| 	private static final ReflectMethod<?> putByteArray_List = wrapEx(() -> MAPPING.mojMethod("putByteArray", String.class, List.class)); | 	private static final ReflectMethod<?> putByteArray_List = wrapEx(() -> REFLECT.method("putByteArray", String.class, List.class)); | ||||||
| 	private static final ReflectMethod<?> putDouble = wrapEx(() -> MAPPING.mojMethod("putDouble", String.class, double.class)); | 	private static final ReflectMethod<?> putDouble = wrapEx(() -> REFLECT.method("putDouble", String.class, double.class)); | ||||||
| 	private static final ReflectMethod<?> putFloat = wrapEx(() -> MAPPING.mojMethod("putFloat", String.class, float.class)); | 	private static final ReflectMethod<?> putFloat = wrapEx(() -> REFLECT.method("putFloat", String.class, float.class)); | ||||||
| 	private static final ReflectMethod<?> putInt = wrapEx(() -> MAPPING.mojMethod("putInt", String.class, int.class)); | 	private static final ReflectMethod<?> putInt = wrapEx(() -> REFLECT.method("putInt", String.class, int.class)); | ||||||
| 	private static final ReflectMethod<?> putIntArray = wrapEx(() -> MAPPING.mojMethod("putIntArray", String.class, int[].class)); | 	private static final ReflectMethod<?> putIntArray = wrapEx(() -> REFLECT.method("putIntArray", String.class, int[].class)); | ||||||
| 	private static final ReflectMethod<?> putIntArray_List = wrapEx(() -> MAPPING.mojMethod("putIntArray", String.class, List.class)); | 	private static final ReflectMethod<?> putIntArray_List = wrapEx(() -> REFLECT.method("putIntArray", String.class, List.class)); | ||||||
| 	private static final ReflectMethod<?> putString = wrapEx(() -> MAPPING.mojMethod("putString", String.class, String.class)); | 	private static final ReflectMethod<?> putString = wrapEx(() -> REFLECT.method("putString", String.class, String.class)); | ||||||
| 	private static final ReflectMethod<?> putUUID = wrapEx(() -> MAPPING.mojMethod("putUUID", String.class, UUID.class)); | 	private static final ReflectMethod<?> putUUID = wrapEx(() -> REFLECT.method("putUUID", String.class, UUID.class)); | ||||||
| 	private static final ReflectMethod<?> putLong = wrapEx(() -> MAPPING.mojMethod("putLong", String.class, long.class)); | 	private static final ReflectMethod<?> putLong = wrapEx(() -> REFLECT.method("putLong", String.class, long.class)); | ||||||
| 	private static final ReflectMethod<?> putLongArray = wrapEx(() -> MAPPING.mojMethod("putLongArray", String.class, long[].class)); | 	private static final ReflectMethod<?> putLongArray = wrapEx(() -> REFLECT.method("putLongArray", String.class, long[].class)); | ||||||
| 	private static final ReflectMethod<?> putLongArray_List = wrapEx(() -> MAPPING.mojMethod("putLongArray", String.class, List.class)); | 	private static final ReflectMethod<?> putLongArray_List = wrapEx(() -> REFLECT.method("putLongArray", String.class, List.class)); | ||||||
| 	private static final ReflectMethod<?> putShort = wrapEx(() -> MAPPING.mojMethod("putShort", String.class, short.class)); | 	private static final ReflectMethod<?> putShort = wrapEx(() -> REFLECT.method("putShort", String.class, short.class)); | ||||||
| 	private static final ReflectMethod<?> put = wrapEx(() -> MAPPING.mojMethod("put", String.class, Tag.MAPPING)); | 	private static final ReflectMethod<?> put = wrapEx(() -> REFLECT.method("put", String.class, Tag.REFLECT.get())); | ||||||
|  |  | ||||||
| 	private static final ReflectMethod<?> getTagType = wrapEx(() -> MAPPING.mojMethod("getTagType", String.class)); | 	private static final ReflectMethod<?> getTagType = wrapEx(() -> REFLECT.method("getTagType", String.class)); | ||||||
| 	private static final ReflectMethod<?> getByte = wrapEx(() -> MAPPING.mojMethod("getByte", String.class)); | 	private static final ReflectMethod<?> getByte = wrapEx(() -> REFLECT.method("getByte", String.class)); | ||||||
| 	private static final ReflectMethod<?> getShort = wrapEx(() -> MAPPING.mojMethod("getShort", String.class)); | 	private static final ReflectMethod<?> getShort = wrapEx(() -> REFLECT.method("getShort", String.class)); | ||||||
| 	private static final ReflectMethod<?> getInt = wrapEx(() -> MAPPING.mojMethod("getInt", String.class)); | 	private static final ReflectMethod<?> getInt = wrapEx(() -> REFLECT.method("getInt", String.class)); | ||||||
| 	private static final ReflectMethod<?> getLong = wrapEx(() -> MAPPING.mojMethod("getLong", String.class)); | 	private static final ReflectMethod<?> getLong = wrapEx(() -> REFLECT.method("getLong", String.class)); | ||||||
| 	private static final ReflectMethod<?> getFloat = wrapEx(() -> MAPPING.mojMethod("getFloat", String.class)); | 	private static final ReflectMethod<?> getFloat = wrapEx(() -> REFLECT.method("getFloat", String.class)); | ||||||
| 	private static final ReflectMethod<?> getDouble = wrapEx(() -> MAPPING.mojMethod("getDouble", String.class)); | 	private static final ReflectMethod<?> getDouble = wrapEx(() -> REFLECT.method("getDouble", String.class)); | ||||||
| 	private static final ReflectMethod<?> getString = wrapEx(() -> MAPPING.mojMethod("getString", String.class)); | 	private static final ReflectMethod<?> getString = wrapEx(() -> REFLECT.method("getString", String.class)); | ||||||
| 	private static final ReflectMethod<?> getByteArray = wrapEx(() -> MAPPING.mojMethod("getByteArray", String.class)); | 	private static final ReflectMethod<?> getByteArray = wrapEx(() -> REFLECT.method("getByteArray", String.class)); | ||||||
| 	private static final ReflectMethod<?> getIntArray = wrapEx(() -> MAPPING.mojMethod("getIntArray", String.class)); | 	private static final ReflectMethod<?> getIntArray = wrapEx(() -> REFLECT.method("getIntArray", String.class)); | ||||||
| 	private static final ReflectMethod<?> getLongArray = wrapEx(() -> MAPPING.mojMethod("getLongArray", String.class)); | 	private static final ReflectMethod<?> getLongArray = wrapEx(() -> REFLECT.method("getLongArray", String.class)); | ||||||
| 	private static final ReflectMethod<?> getCompound = wrapEx(() -> MAPPING.mojMethod("getCompound", String.class)); | 	private static final ReflectMethod<?> getCompound = wrapEx(() -> REFLECT.method("getCompound", String.class)); | ||||||
| 	private static final ReflectMethod<?> getBoolean = wrapEx(() -> MAPPING.mojMethod("getBoolean", String.class)); | 	private static final ReflectMethod<?> getBoolean = wrapEx(() -> REFLECT.method("getBoolean", String.class)); | ||||||
| 	private static final ReflectMethod<?> getList = wrapEx(() -> MAPPING.mojMethod("getList", String.class, int.class)); | 	private static final ReflectMethod<?> getList = wrapEx(() -> REFLECT.method("getList", String.class, int.class)); | ||||||
|  |  | ||||||
| 	private static final ReflectMethod<?> get = wrapEx(() -> MAPPING.mojMethod("get", String.class)); | 	private static final ReflectMethod<?> get = wrapEx(() -> REFLECT.method("get", String.class)); | ||||||
| 	private static final ReflectMethod<?> getAllKeys = wrapEx(() -> MAPPING.mojMethod("getAllKeys")); | 	private static final ReflectMethod<?> getAllKeys = wrapEx(() -> REFLECT.method("getAllKeys")); | ||||||
| 	private static final ReflectMethod<?> entries = wrapEx(() -> MAPPING.mojMethod("entries")); | 	private static final ReflectMethod<?> entrySet = wrapEx(() -> REFLECT.method("entrySet")); | ||||||
| 	private static final ReflectMethod<?> size = wrapEx(() -> MAPPING.mojMethod("size")); | 	private static final ReflectMethod<?> size = wrapEx(() -> REFLECT.method("size")); | ||||||
| 	private static final ReflectMethod<?> contains = wrapEx(() -> MAPPING.mojMethod("contains", String.class)); | 	private static final ReflectMethod<?> contains = wrapEx(() -> REFLECT.method("contains", String.class)); | ||||||
| 	private static final ReflectMethod<?> containsStringInt = wrapEx(() -> MAPPING.mojMethod("contains", String.class, int.class)); | 	private static final ReflectMethod<?> containsStringInt = wrapEx(() -> REFLECT.method("contains", String.class, int.class)); | ||||||
|  |  | ||||||
| 	public CompoundTag() { | 	public CompoundTag() { | ||||||
| 		this(wrapReflectEx(() -> CONSTRUCTOR.instantiate())); | 		this(wrapReflectEx(() -> CONSTRUCTOR.instantiate())); | ||||||
| @@ -166,9 +166,9 @@ public class CompoundTag extends ReflectWrapper implements Tag { | |||||||
| 	 * The values in the returned Map are not wrapped. | 	 * The values in the returned Map are not wrapped. | ||||||
| 	 */ | 	 */ | ||||||
| 	@SuppressWarnings("unchecked") | 	@SuppressWarnings("unchecked") | ||||||
| 	public Map<String, ?> entries() { | 	public Set<Map.Entry<String, ?>> entrySet() { | ||||||
| 		// 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 synchronize the returned map with the wrapped map | ||||||
| 		return (Map<String, ?>) wrapReflectEx(() -> entries.invoke(__getRuntimeInstance())); | 		return (Set<Map.Entry<String, ?>>) wrapReflectEx(() -> entrySet.invoke(__getRuntimeInstance())); | ||||||
| 	} | 	} | ||||||
| 	public int size() { | 	public int size() { | ||||||
| 		return (int) wrapReflectEx(() -> size.invoke(__getRuntimeInstance())); | 		return (int) wrapReflectEx(() -> size.invoke(__getRuntimeInstance())); | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; | import fr.pandacube.lib.reflect.Reflect; | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect.ClassMapping; | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
| import fr.pandacube.lib.reflect.ReflectConstructor; | import fr.pandacube.lib.reflect.ReflectConstructor; | ||||||
| import fr.pandacube.lib.reflect.ReflectMethod; | import fr.pandacube.lib.reflect.ReflectMethod; | ||||||
|  |  | ||||||
| @@ -9,9 +9,9 @@ import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | |||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | ||||||
|  |  | ||||||
| public class ListTag extends CollectionTag { | public class ListTag extends CollectionTag { | ||||||
| 	public static final ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.nbt.ListTag")); | 	public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.nbt.ListTag")); | ||||||
| 	public static final ReflectConstructor<?> CONSTRUCTOR = wrapEx(() -> MAPPING.runtimeReflect().constructor()); | 	public static final ReflectConstructor<?> CONSTRUCTOR = wrapEx(() -> REFLECT.constructor()); | ||||||
| 	private static final ReflectMethod<?> getCompound = wrapEx(() -> MAPPING.mojMethod("getCompound", int.class)); | 	private static final ReflectMethod<?> getCompound = wrapEx(() -> REFLECT.method("getCompound", int.class)); | ||||||
|  |  | ||||||
| 	public CompoundTag getCompound(int index) { | 	public CompoundTag getCompound(int index) { | ||||||
| 		return wrap(wrapReflectEx(() -> getCompound.invoke(__getRuntimeInstance(), index)), CompoundTag.class); | 		return wrap(wrapReflectEx(() -> getCompound.invoke(__getRuntimeInstance(), index)), CompoundTag.class); | ||||||
|   | |||||||
| @@ -1,18 +1,15 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; | import fr.pandacube.lib.reflect.Reflect; | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect.ClassMapping; | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
| import fr.pandacube.lib.reflect.ReflectMethod; | import fr.pandacube.lib.reflect.ReflectMethod; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | ||||||
|  |  | ||||||
| import java.io.File; |  | ||||||
| import java.nio.file.Path; |  | ||||||
|  |  | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | ||||||
|  |  | ||||||
| public class NbtAccounter extends ReflectWrapper { | public class NbtAccounter extends ReflectWrapper { | ||||||
| 	public static final ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.nbt.NbtAccounter")); | 	public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.nbt.NbtAccounter")); | ||||||
| 	private static final ReflectMethod<?> unlimitedHeap = wrapEx(() -> MAPPING.mojMethod("unlimitedHeap")); | 	private static final ReflectMethod<?> unlimitedHeap = wrapEx(() -> REFLECT.method("unlimitedHeap")); | ||||||
|  |  | ||||||
| 	private NbtAccounter(Object obj) { | 	private NbtAccounter(Object obj) { | ||||||
| 		super(obj); | 		super(obj); | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; | import fr.pandacube.lib.reflect.Reflect; | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect.ClassMapping; | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
| import fr.pandacube.lib.reflect.ReflectMethod; | import fr.pandacube.lib.reflect.ReflectMethod; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | ||||||
|  |  | ||||||
| @@ -10,9 +10,9 @@ import java.nio.file.Path; | |||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | ||||||
|  |  | ||||||
| public class NbtIo extends ReflectWrapper { | public class NbtIo extends ReflectWrapper { | ||||||
| 	public static final ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.nbt.NbtIo")); | 	public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.nbt.NbtIo")); | ||||||
| 	private static final ReflectMethod<?> readCompressed = wrapEx(() -> MAPPING.mojMethod("readCompressed", Path.class, NbtAccounter.MAPPING)); | 	private static final ReflectMethod<?> readCompressed = wrapEx(() -> REFLECT.method("readCompressed", Path.class, NbtAccounter.REFLECT.get())); | ||||||
| 	private static final ReflectMethod<?> writeCompressed = wrapEx(() -> MAPPING.mojMethod("writeCompressed", CompoundTag.MAPPING, Path.class)); | 	private static final ReflectMethod<?> writeCompressed = wrapEx(() -> REFLECT.method("writeCompressed", CompoundTag.REFLECT.get(), Path.class)); | ||||||
| 	 | 	 | ||||||
| 	private NbtIo(Object obj) { | 	private NbtIo(Object obj) { | ||||||
| 		super(obj); | 		super(obj); | ||||||
|   | |||||||
| @@ -1,13 +1,13 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt; | ||||||
|  |  | ||||||
|  | import fr.pandacube.lib.reflect.Reflect; | ||||||
|  | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
|  | import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | ||||||
|  |  | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect.ClassMapping; |  | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; |  | ||||||
|  |  | ||||||
| public class StringTag extends ReflectWrapper implements Tag { | public class StringTag extends ReflectWrapper implements Tag { | ||||||
| 	public static final ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.nbt.StringTag")); | 	public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.nbt.StringTag")); | ||||||
|  |  | ||||||
|  |  | ||||||
| 	protected StringTag(Object nms) { | 	protected StringTag(Object nms) { | ||||||
|   | |||||||
| @@ -1,23 +1,23 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.nbt; | ||||||
|  |  | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | import fr.pandacube.lib.reflect.Reflect; | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.reflect.ReflectField; | import fr.pandacube.lib.reflect.ReflectField; | ||||||
| import fr.pandacube.lib.reflect.ReflectMethod; | import fr.pandacube.lib.reflect.ReflectMethod; | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect.ClassMapping; |  | ||||||
| import fr.pandacube.lib.reflect.wrapper.ConcreteWrapper; | import fr.pandacube.lib.reflect.wrapper.ConcreteWrapper; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapperI; | import fr.pandacube.lib.reflect.wrapper.ReflectWrapperI; | ||||||
|  |  | ||||||
|  | import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | ||||||
|  | import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | ||||||
|  |  | ||||||
| @ConcreteWrapper(Tag.__concrete.class) | @ConcreteWrapper(Tag.__concrete.class) | ||||||
| public interface Tag extends ReflectWrapperI { | public interface Tag extends ReflectWrapperI { | ||||||
| 	ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.nbt.Tag")); | 	ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.nbt.Tag")); | ||||||
| 	ReflectMethod<?> getAsString = wrapEx(() -> MAPPING.mojMethod("getAsString")); | 	ReflectMethod<?> getAsString = wrapEx(() -> REFLECT.method("getAsString")); | ||||||
| 	ReflectField<?> TAG_LIST = wrapEx(() -> MAPPING.mojField("TAG_LIST")); | 	ReflectField<?> TAG_LIST = wrapEx(() -> REFLECT.field("TAG_LIST")); | ||||||
| 	ReflectField<?> TAG_COMPOUND = wrapEx(() -> MAPPING.mojField("TAG_COMPOUND")); | 	ReflectField<?> TAG_COMPOUND = wrapEx(() -> REFLECT.field("TAG_COMPOUND")); | ||||||
| 	ReflectField<?> TAG_ANY_NUMERIC = wrapEx(() -> MAPPING.mojField("TAG_ANY_NUMERIC")); | 	ReflectField<?> TAG_ANY_NUMERIC = wrapEx(() -> REFLECT.field("TAG_ANY_NUMERIC")); | ||||||
|  |  | ||||||
| 	 | 	 | ||||||
| 	default String getAsString() { | 	default String getAsString() { | ||||||
|   | |||||||
| @@ -1,7 +1,8 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.network; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.network; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; |  | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.netty.ByteBuf; | import fr.pandacube.lib.paper.reflect.wrapper.netty.ByteBuf; | ||||||
|  | import fr.pandacube.lib.reflect.Reflect; | ||||||
|  | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
| import fr.pandacube.lib.reflect.ReflectConstructor; | import fr.pandacube.lib.reflect.ReflectConstructor; | ||||||
| import fr.pandacube.lib.reflect.ReflectMethod; | import fr.pandacube.lib.reflect.ReflectMethod; | ||||||
|  |  | ||||||
| @@ -9,9 +10,9 @@ import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | |||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | ||||||
|  |  | ||||||
| public class FriendlyByteBuf extends ByteBuf { | public class FriendlyByteBuf extends ByteBuf { | ||||||
|     public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.network.FriendlyByteBuf")); |     public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.network.FriendlyByteBuf")); | ||||||
|     private static final ReflectConstructor<?> CONSTRUCTOR = wrapEx(() -> MAPPING.runtimeReflect().constructor(ByteBuf.REFLECT.get())); |     private static final ReflectConstructor<?> CONSTRUCTOR = wrapEx(() -> REFLECT.constructor(ByteBuf.REFLECT.get())); | ||||||
|     private static final ReflectMethod<?> writeUtf = wrapEx(() -> MAPPING.mojMethod("writeUtf", String.class)); |     private static final ReflectMethod<?> writeUtf = wrapEx(() -> REFLECT.method("writeUtf", String.class)); | ||||||
|  |  | ||||||
|     public FriendlyByteBuf(ByteBuf parent) { |     public FriendlyByteBuf(ByteBuf parent) { | ||||||
|         this(wrapReflectEx(() -> CONSTRUCTOR.instantiate(unwrap(parent)))); |         this(wrapReflectEx(() -> CONSTRUCTOR.instantiate(unwrap(parent)))); | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.network.chat; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.network.chat; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; | import fr.pandacube.lib.reflect.Reflect; | ||||||
|  | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ConcreteWrapper; | import fr.pandacube.lib.reflect.wrapper.ConcreteWrapper; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapperI; | import fr.pandacube.lib.reflect.wrapper.ReflectWrapperI; | ||||||
| @@ -9,7 +10,7 @@ import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | |||||||
|  |  | ||||||
| @ConcreteWrapper(Component.__concrete.class) | @ConcreteWrapper(Component.__concrete.class) | ||||||
| public interface Component extends ReflectWrapperI { | public interface Component extends ReflectWrapperI { | ||||||
|     NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.network.chat.Component")); |     ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.network.chat.Component")); | ||||||
|  |  | ||||||
|  |  | ||||||
|     class __concrete extends ReflectWrapper implements Component { |     class __concrete extends ReflectWrapper implements Component { | ||||||
|   | |||||||
| @@ -1,7 +1,8 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.network.protocol; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.network.protocol; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; |  | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.network.protocol.custom.CustomPacketPayload; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.network.protocol.custom.CustomPacketPayload; | ||||||
|  | import fr.pandacube.lib.reflect.Reflect; | ||||||
|  | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
| import fr.pandacube.lib.reflect.ReflectConstructor; | import fr.pandacube.lib.reflect.ReflectConstructor; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | ||||||
|  |  | ||||||
| @@ -9,8 +10,8 @@ import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | |||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | ||||||
|  |  | ||||||
| public class ClientboundCustomPayloadPacket extends ReflectWrapper implements Packet { | public class ClientboundCustomPayloadPacket extends ReflectWrapper implements Packet { | ||||||
|     public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket")); |     public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket")); | ||||||
|     private static final ReflectConstructor<?> CONSTRUCTOR = wrapEx(() -> MAPPING.runtimeReflect().constructor(CustomPacketPayload.MAPPING.runtimeClass())); |     private static final ReflectConstructor<?> CONSTRUCTOR = wrapEx(() -> REFLECT.constructor(CustomPacketPayload.REFLECT.get())); | ||||||
|  |  | ||||||
|     protected ClientboundCustomPayloadPacket(Object obj) { |     protected ClientboundCustomPayloadPacket(Object obj) { | ||||||
|         super(obj); |         super(obj); | ||||||
|   | |||||||
| @@ -1,18 +1,19 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.network.protocol; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.network.protocol; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; | import fr.pandacube.lib.reflect.Reflect; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
| import fr.pandacube.lib.reflect.ReflectConstructor; | import fr.pandacube.lib.reflect.ReflectConstructor; | ||||||
| import fr.pandacube.lib.reflect.ReflectField; | 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.wrapEx; | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | ||||||
|  |  | ||||||
| public class ClientboundGameEventPacket extends ReflectWrapper implements Packet { | public class ClientboundGameEventPacket extends ReflectWrapper implements Packet { | ||||||
|     public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.network.protocol.game.ClientboundGameEventPacket")); |     public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.network.protocol.game.ClientboundGameEventPacket")); | ||||||
|     private static final ReflectConstructor<?> CONSTRUCTOR = wrapEx(() -> MAPPING.runtimeReflect().constructor(Type.MAPPING.runtimeClass(), float.class)); |     private static final ReflectConstructor<?> CONSTRUCTOR = wrapEx(() -> REFLECT.constructor(Type.REFLECT.get(), float.class)); | ||||||
|     private static final ReflectField<?> FIELD_RAIN_LEVEL_CHANGE = wrapEx(() -> MAPPING.mojField("RAIN_LEVEL_CHANGE")); |     private static final ReflectField<?> FIELD_RAIN_LEVEL_CHANGE = wrapEx(() -> REFLECT.field("RAIN_LEVEL_CHANGE")); | ||||||
|     private static final ReflectField<?> FIELD_THUNDER_LEVEL_CHANGE = wrapEx(() -> MAPPING.mojField("THUNDER_LEVEL_CHANGE")); |     private static final ReflectField<?> FIELD_THUNDER_LEVEL_CHANGE = wrapEx(() -> REFLECT.field("THUNDER_LEVEL_CHANGE")); | ||||||
|  |  | ||||||
|     public static Type RAIN_LEVEL_CHANGE() { |     public static Type RAIN_LEVEL_CHANGE() { | ||||||
|         return wrap(wrapReflectEx(FIELD_RAIN_LEVEL_CHANGE::getStaticValue), Type.class); |         return wrap(wrapReflectEx(FIELD_RAIN_LEVEL_CHANGE::getStaticValue), Type.class); | ||||||
| @@ -31,7 +32,7 @@ public class ClientboundGameEventPacket extends ReflectWrapper implements Packet | |||||||
|  |  | ||||||
|  |  | ||||||
|     public static class Type extends ReflectWrapper { |     public static class Type extends ReflectWrapper { | ||||||
|         public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.network.protocol.game.ClientboundGameEventPacket$Type")); |         public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.network.protocol.game.ClientboundGameEventPacket$Type")); | ||||||
|  |  | ||||||
|         protected Type(Object obj) { |         protected Type(Object obj) { | ||||||
|             super(obj); |             super(obj); | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.network.protocol; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.network.protocol; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; | import fr.pandacube.lib.reflect.Reflect; | ||||||
|  | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ConcreteWrapper; | import fr.pandacube.lib.reflect.wrapper.ConcreteWrapper; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapperI; | import fr.pandacube.lib.reflect.wrapper.ReflectWrapperI; | ||||||
| @@ -9,7 +10,7 @@ import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | |||||||
|  |  | ||||||
| @ConcreteWrapper(Packet.__concrete.class) | @ConcreteWrapper(Packet.__concrete.class) | ||||||
| public interface Packet extends ReflectWrapperI { | public interface Packet extends ReflectWrapperI { | ||||||
|     NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.network.protocol.Packet")); |     ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.network.protocol.Packet")); | ||||||
|  |  | ||||||
|     class __concrete extends ReflectWrapper implements Packet { |     class __concrete extends ReflectWrapper implements Packet { | ||||||
|         protected __concrete(Object obj) { |         protected __concrete(Object obj) { | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.network.protocol.custom; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.network.protocol.custom; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; | import fr.pandacube.lib.reflect.Reflect; | ||||||
|  | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
| import fr.pandacube.lib.reflect.ReflectConstructor; | import fr.pandacube.lib.reflect.ReflectConstructor; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | ||||||
|  |  | ||||||
| @@ -8,8 +9,8 @@ import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | |||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | ||||||
|  |  | ||||||
| public class BrandPayload extends ReflectWrapper implements CustomPacketPayload { | public class BrandPayload extends ReflectWrapper implements CustomPacketPayload { | ||||||
|     public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.network.protocol.common.custom.BrandPayload")); |     public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.network.protocol.common.custom.BrandPayload")); | ||||||
|     private static final ReflectConstructor<?> CONSTRUCTOR = wrapEx(() -> MAPPING.runtimeReflect().constructor(String.class)); |     private static final ReflectConstructor<?> CONSTRUCTOR = wrapEx(() -> REFLECT.constructor(String.class)); | ||||||
|  |  | ||||||
|     public BrandPayload(String brand) { |     public BrandPayload(String brand) { | ||||||
|         this(wrapReflectEx(() -> CONSTRUCTOR.instantiate(brand))); |         this(wrapReflectEx(() -> CONSTRUCTOR.instantiate(brand))); | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.network.protocol.custom; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.network.protocol.custom; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; | import fr.pandacube.lib.reflect.Reflect; | ||||||
|  | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ConcreteWrapper; | import fr.pandacube.lib.reflect.wrapper.ConcreteWrapper; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapperI; | import fr.pandacube.lib.reflect.wrapper.ReflectWrapperI; | ||||||
| @@ -9,7 +10,7 @@ import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | |||||||
|  |  | ||||||
| @ConcreteWrapper(CustomPacketPayload.__concrete.class) | @ConcreteWrapper(CustomPacketPayload.__concrete.class) | ||||||
| public interface CustomPacketPayload extends ReflectWrapperI { | public interface CustomPacketPayload extends ReflectWrapperI { | ||||||
|     NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.network.protocol.common.custom.CustomPacketPayload")); |     ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.network.protocol.common.custom.CustomPacketPayload")); | ||||||
|  |  | ||||||
|     class __concrete extends ReflectWrapper implements CustomPacketPayload { |     class __concrete extends ReflectWrapper implements CustomPacketPayload { | ||||||
|         protected __concrete(Object obj) { |         protected __concrete(Object obj) { | ||||||
|   | |||||||
| @@ -1,12 +1,13 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.resources; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.resources; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; | import fr.pandacube.lib.reflect.Reflect; | ||||||
|  | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
| import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | import fr.pandacube.lib.reflect.wrapper.ReflectWrapper; | ||||||
|  |  | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | ||||||
|  |  | ||||||
| public class ResourceLocation extends ReflectWrapper { | public class ResourceLocation extends ReflectWrapper { | ||||||
|     public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.resources.ResourceLocation")); |     public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.resources.ResourceLocation")); | ||||||
|  |  | ||||||
|  |  | ||||||
|     protected ResourceLocation(Object obj) { |     protected ResourceLocation(Object obj) { | ||||||
|   | |||||||
| @@ -1,15 +1,16 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.server; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.server; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; |  | ||||||
| import fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.ChunkStorage; | import fr.pandacube.lib.paper.reflect.wrapper.minecraft.world.ChunkStorage; | ||||||
|  | import fr.pandacube.lib.reflect.Reflect; | ||||||
|  | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
| import fr.pandacube.lib.reflect.ReflectField; | import fr.pandacube.lib.reflect.ReflectField; | ||||||
|  |  | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapReflectEx; | ||||||
|  |  | ||||||
| public class ChunkMap extends ChunkStorage { | public class ChunkMap extends ChunkStorage { | ||||||
|     public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.server.level.ChunkMap")); |     public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.server.level.ChunkMap")); | ||||||
|     private static final ReflectField<?> FIELD_level = wrapEx(() -> MAPPING.mojField("level")); |     private static final ReflectField<?> FIELD_level = wrapEx(() -> REFLECT.field("level")); | ||||||
|  |  | ||||||
|     public final ServerLevel level; |     public final ServerLevel level; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,11 +1,12 @@ | |||||||
| package fr.pandacube.lib.paper.reflect.wrapper.minecraft.server; | package fr.pandacube.lib.paper.reflect.wrapper.minecraft.server; | ||||||
|  |  | ||||||
| import fr.pandacube.lib.paper.reflect.NMSReflect; | import fr.pandacube.lib.reflect.Reflect; | ||||||
|  | import fr.pandacube.lib.reflect.ReflectClass; | ||||||
|  |  | ||||||
| import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | import static fr.pandacube.lib.util.ThrowableUtil.wrapEx; | ||||||
|  |  | ||||||
| public class DedicatedPlayerList extends PlayerList { | public class DedicatedPlayerList extends PlayerList { | ||||||
|     public static final NMSReflect.ClassMapping MAPPING = wrapEx(() -> NMSReflect.mojClass("net.minecraft.server.dedicated.DedicatedPlayerList")); |     public static final ReflectClass<?> REFLECT = wrapEx(() -> Reflect.ofClass("net.minecraft.server.dedicated.DedicatedPlayerList")); | ||||||
|  |  | ||||||
|     protected DedicatedPlayerList(Object obj) { |     protected DedicatedPlayerList(Object obj) { | ||||||
|         super(obj); |         super(obj); | ||||||
|   | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user