null
+ */
+ ItemFrame getItemFrameById(World world, int entityId);
}
diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapManager.java b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapManager.java
similarity index 84%
rename from src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapManager.java
rename to API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapManager.java
index 8b05f72..00b906d 100644
--- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapManager.java
+++ b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapManager.java
@@ -1,6 +1,6 @@
/*
* This file is part of MapReflectionAPI.
- * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
+ * Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,29 +18,47 @@
package tech.sbdevelopment.mapreflectionapi.api;
+import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
-import org.bukkit.World;
-import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.Player;
+import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.Nullable;
+import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
import tech.sbdevelopment.mapreflectionapi.api.exceptions.MapLimitExceededException;
import tech.sbdevelopment.mapreflectionapi.managers.Configuration;
-import tech.sbdevelopment.mapreflectionapi.utils.ReflectionUtil;
import java.awt.image.BufferedImage;
+import java.lang.reflect.InvocationTargetException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
-import static com.cryptomorin.xseries.reflection.XReflection.*;
-
/**
* The {@link MapManager} manages all the maps. It also contains functions for wrapping.
*/
public class MapManager {
protected final Setnull
- */
- public ItemFrame getItemFrameById(World world, int entityId) {
- Object worldHandle = ReflectionUtil.getHandle(world);
- Object nmsEntity = ReflectionUtil.callMethod(worldHandle, supports(18) ? "a" : "getEntity", entityId);
- if (nmsEntity == null) return null;
-
- Object craftEntity = ReflectionUtil.callMethod(nmsEntity, "getBukkitEntity");
- if (craftEntity == null) return null;
-
- Class> itemFrameClass = getNMSClass("world.entity.decoration", "EntityItemFrame");
- if (itemFrameClass == null) return null;
-
- if (craftEntity.getClass().isAssignableFrom(itemFrameClass))
- return (ItemFrame) itemFrameClass.cast(craftEntity);
-
- return null;
- }
-
/**
* Register an occupied map ID
*
diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/types/Event.java b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java
similarity index 57%
rename from src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/types/Event.java
rename to API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java
index fac8c14..2d7f9cb 100644
--- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/types/Event.java
+++ b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java
@@ -16,31 +16,27 @@
* along with this program. If not, see int[rows][columns]
)
+ * @param entityIdMatrix 2D-Array of entity-IDs of the {@link ItemFrame}s (int[width][height]
)
* @see MapController#showInFrame(Player, int)
*/
void showInFrames(Player player, Integer[][] entityIdMatrix);
@@ -95,7 +95,7 @@ public interface MultiMapController extends IMapController {
* Show this {@link MultiMapController} in {@link ItemFrame}s
*
* @param player {@link Player} that will be able to see the maps
- * @param entityIdMatrix 2D-Array of entity-IDs of the {@link ItemFrame}s (int[rows][columns]
)
+ * @param entityIdMatrix 2D-Array of entity-IDs of the {@link ItemFrame}s (int[width][height]
)
* @param callable {@link DebugCallable} which will be called to display debug information, or null
* @see MapController#showInFrame(Player, int, String)
*/
@@ -105,7 +105,7 @@ public interface MultiMapController extends IMapController {
* Show this {@link MultiMapController} in {@link ItemFrame}s
*
* @param player {@link Player} that will be able to see the maps
- * @param itemFrameMatrix 2D-Array of {@link ItemFrame}s (ItemFrame[rows][columns]
)
+ * @param itemFrameMatrix 2D-Array of {@link ItemFrame}s (ItemFrame[width][height]
)
* @param force if false
, the map will not be shown if there is not Map-Item in the ItemFrames
* @see MapController#showInFrame(Player, ItemFrame, boolean)
*/
@@ -115,7 +115,7 @@ public interface MultiMapController extends IMapController {
* Show this {@link MultiMapController} in {@link ItemFrame}s
*
* @param player {@link Player} that will be able to see the maps
- * @param itemFrameMatrix 2D-Array of {@link ItemFrame}s (ItemFrame[rows][columns]
)
+ * @param itemFrameMatrix 2D-Array of {@link ItemFrame}s (ItemFrame[width][height]
)
* @see MapController#showInFrame(Player, ItemFrame)
*/
void showInFrames(Player player, ItemFrame[][] itemFrameMatrix);
@@ -124,7 +124,7 @@ public interface MultiMapController extends IMapController {
* Clear the frames
*
* @param player {@link Player} that will be able to see the cleared frames
- * @param entityIdMatrix 2D-Array of entity-IDs of the {@link ItemFrame}s (int[rows][columns]
)
+ * @param entityIdMatrix 2D-Array of entity-IDs of the {@link ItemFrame}s (int[width][height]
)
*/
void clearFrames(Player player, Integer[][] entityIdMatrix);
@@ -132,7 +132,7 @@ public interface MultiMapController extends IMapController {
* Clear the frames
*
* @param player {@link Player} that will be able to see the cleared frames
- * @param itemFrameMatrix 2D-Array of {@link ItemFrame}s (ItemFrame[rows][columns]
)
+ * @param itemFrameMatrix 2D-Array of {@link ItemFrame}s (ItemFrame[width][height]
)
*/
void clearFrames(Player player, ItemFrame[][] itemFrameMatrix);
@@ -144,11 +144,11 @@ public interface MultiMapController extends IMapController {
* Called to get debug information for a frame
*
* @param controller the {@link MapController}
- * @param row Row of the current frame
- * @param column Column of the current frame
+ * @param x X-Position of the current frame
+ * @param y Y-Position of the current frame
* @return {@link String} to show when a player looks at the map, or null
* @see MapController#showInFrame(Player, int, String)
*/
- String call(MapController controller, int row, int column);
+ String call(MapController controller, int x, int y);
}
}
diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MultiMapWrapper.java b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MultiMapWrapper.java
similarity index 58%
rename from src/main/java/tech/sbdevelopment/mapreflectionapi/api/MultiMapWrapper.java
rename to API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MultiMapWrapper.java
index be6efd7..7d22541 100644
--- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MultiMapWrapper.java
+++ b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MultiMapWrapper.java
@@ -25,75 +25,52 @@ import org.jetbrains.annotations.NotNull;
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
import tech.sbdevelopment.mapreflectionapi.api.exceptions.MapLimitExceededException;
+import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
+import static tech.sbdevelopment.mapreflectionapi.utils.MainUtil.validateArrayDimensions;
+
/**
* A {@link MultiMapWrapper} wraps one image split in pieces.
*/
public class MultiMapWrapper extends AbstractMapWrapper {
private final MapWrapper[][] wrapperMatrix;
- /**
- * Creates a new {@link MultiMapWrapper} from the given image.
- * The image will be split into the given amount of rows and columns.
- *
- * @param image The image to wrap
- * @param rows The amount of rows
- * @param columns The amount of columns
- */
public MultiMapWrapper(BufferedImage image, int rows, int columns) {
- this(splitImage(image, rows, columns));
+ this(splitImage(image, columns, rows));
}
- /**
- * Creates a new {@link MultiMapWrapper} from the given image.
- * The image will be split into the given amount of rows and columns.
- *
- * @param image The image to wrap
- * @param rows The amount of rows
- * @param columns The amount of columns
- */
public MultiMapWrapper(ArrayImage image, int rows, int columns) {
- this(splitImage(image.toBuffered(), rows, columns));
+ this(splitImage(image.toBuffered(), columns, rows));
}
- /**
- * Creates a new {@link MultiMapWrapper} from the given image.
- *
- * @param imageMatrix The image matrix to wrap
- */
- protected MultiMapWrapper(ArrayImage[][] imageMatrix) {
+ public MultiMapWrapper(ArrayImage[][] imageMatrix) {
wrapperMatrix = new MapWrapper[imageMatrix.length][imageMatrix[0].length];
- for (int row = 0; row < imageMatrix.length; row++) {
- if (imageMatrix[row].length != imageMatrix[0].length) {
+ for (int x = 0; x < imageMatrix.length; x++) {
+ if (imageMatrix[x].length != imageMatrix[0].length) {
throw new IllegalArgumentException("An image in a MultiMapWrapper is not rectangular!");
}
- for (int column = 0; column < imageMatrix[row].length; column++) {
- wrapperMatrix[row][column] = MapReflectionAPI.getMapManager().wrapImage(imageMatrix[row][column]);
+ for (int y = 0; y < imageMatrix[x].length; y++) {
+ wrapperMatrix[x][y] = MapReflectionAPI.getMapManager().wrapImage(imageMatrix[x][y]);
}
}
}
- /**
- * Creates a new {@link MultiMapWrapper} from the given image.
- *
- * @param imageMatrix The image matrix to wrap
- */
- protected MultiMapWrapper(BufferedImage[][] imageMatrix) {
+ public MultiMapWrapper(BufferedImage[][] imageMatrix) {
wrapperMatrix = new MapWrapper[imageMatrix.length][imageMatrix[0].length];
- for (int row = 0; row < imageMatrix.length; row++) {
- if (imageMatrix[row].length != imageMatrix[0].length) {
+ for (int x = 0; x < imageMatrix.length; x++) {
+ if (imageMatrix[x].length != imageMatrix[0].length) {
throw new IllegalArgumentException("An image in a MultiMapWrapper is not rectangular!");
}
- for (int column = 0; column < imageMatrix[row].length; column++) {
- wrapperMatrix[row][column] = MapReflectionAPI.getMapManager().wrapImage(imageMatrix[row][column]);
+ for (int y = 0; y < imageMatrix[x].length; y++) {
+ wrapperMatrix[x][y] = MapReflectionAPI.getMapManager().wrapImage(imageMatrix[x][y]);
}
}
}
@@ -140,10 +117,10 @@ public class MultiMapWrapper extends AbstractMapWrapper {
@Override
public void update(@NotNull ArrayImage content) {
- ArrayImage[][] split = splitImage(content.toBuffered(), wrapperMatrix.length, wrapperMatrix[0].length);
- for (int row = 0; row < wrapperMatrix.length; row++) {
- for (int column = 0; column < wrapperMatrix[row].length; column++) {
- wrapperMatrix[row][column].getController().update(split[row][column]);
+ ArrayImage[][] split = splitImage(content.toBuffered(), wrapperMatrix[0].length, wrapperMatrix.length);
+ for (int x = 0; x < wrapperMatrix.length; x++) {
+ for (int y = 0; y < wrapperMatrix[x].length; y++) {
+ wrapperMatrix[x][y].getController().update(split[x][y]);
}
}
}
@@ -173,27 +150,33 @@ public class MultiMapWrapper extends AbstractMapWrapper {
@Override
public void showInFrames(Player player, Integer[][] entityIdMatrix) {
- for (int row = 0; row < entityIdMatrix.length; row++) {
- for (int column = 0; column < entityIdMatrix[row].length; column++) {
- wrapperMatrix[row][column].getController().showInFrame(player, entityIdMatrix[row][column]);
+ validateArrayDimensions(wrapperMatrix, entityIdMatrix);
+
+ for (int x = 0; x < entityIdMatrix.length; x++) {
+ for (int y = 0; y < entityIdMatrix[x].length; y++) {
+ wrapperMatrix[y][x].getController().showInFrame(player, entityIdMatrix[x][wrapperMatrix.length - 1 - y]);
}
}
}
@Override
public void showInFrames(Player player, Integer[][] entityIdMatrix, DebugCallable callable) {
- for (int row = 0; row < entityIdMatrix.length; row++) {
- for (int column = 0; column < entityIdMatrix[row].length; column++) {
- wrapperMatrix[row][column].getController().showInFrame(player, entityIdMatrix[row][column], callable.call(wrapperMatrix[row][column].getController(), row, column));
+ validateArrayDimensions(wrapperMatrix, entityIdMatrix);
+
+ for (int x = 0; x < entityIdMatrix.length; x++) {
+ for (int y = 0; y < entityIdMatrix[x].length; y++) {
+ wrapperMatrix[y][x].getController().showInFrame(player, entityIdMatrix[x][wrapperMatrix.length - 1 - y], callable.call(wrapperMatrix[y][x].getController(), x, y));
}
}
}
@Override
public void showInFrames(Player player, ItemFrame[][] itemFrameMatrix, boolean force) {
- for (int row = 0; row < itemFrameMatrix.length; row++) {
- for (int column = 0; column < itemFrameMatrix[row].length; column++) {
- wrapperMatrix[row][column].getController().showInFrame(player, itemFrameMatrix[row][column], force);
+ validateArrayDimensions(wrapperMatrix, itemFrameMatrix);
+
+ for (int x = 0; x < itemFrameMatrix.length; x++) {
+ for (int y = 0; y < itemFrameMatrix[x].length; y++) {
+ wrapperMatrix[y][x].getController().showInFrame(player, itemFrameMatrix[x][wrapperMatrix.length - 1 - y], force);
}
}
}
@@ -205,47 +188,47 @@ public class MultiMapWrapper extends AbstractMapWrapper {
@Override
public void clearFrames(Player player, Integer[][] entityIdMatrix) {
- for (int row = 0; row < entityIdMatrix.length; row++) {
- for (int column = 0; column < entityIdMatrix[row].length; column++) {
- wrapperMatrix[row][column].getController().clearFrame(player, entityIdMatrix[row][column]);
+ validateArrayDimensions(wrapperMatrix, entityIdMatrix);
+
+ for (int x = 0; x < entityIdMatrix.length; x++) {
+ for (int y = 0; y < entityIdMatrix[x].length; y++) {
+ wrapperMatrix[y][x].getController().clearFrame(player, entityIdMatrix[x][y]);
}
}
}
@Override
public void clearFrames(Player player, ItemFrame[][] itemFrameMatrix) {
- for (int row = 0; row < itemFrameMatrix.length; row++) {
- for (int column = 0; column < itemFrameMatrix[row].length; column++) {
- wrapperMatrix[row][column].getController().clearFrame(player, itemFrameMatrix[row][column]);
+ validateArrayDimensions(wrapperMatrix, itemFrameMatrix);
+
+ for (int x = 0; x < itemFrameMatrix.length; x++) {
+ for (int y = 0; y < itemFrameMatrix[x].length; y++) {
+ wrapperMatrix[y][x].getController().clearFrame(player, itemFrameMatrix[x][y]);
}
}
}
};
- /**
- * Splits a BufferedImage into a matrix of ArrayImages.
- *
- * @param image The image to split
- * @param rows The number of rows
- * @param columns The number of columns
- * @return The matrix of ArrayImages
+ /*
+ * Modified Method from http://kalanir.blogspot.de/2010/02/how-to-split-image-into-chunks-java.html
*/
- private static ArrayImage[][] splitImage(final BufferedImage image, final int rows, final int columns) {
+ private static ArrayImage[][] splitImage(final BufferedImage image, final int columns, final int rows) {
int chunkWidth = image.getWidth() / columns;
int chunkHeight = image.getHeight() / rows;
ArrayImage[][] images = new ArrayImage[rows][columns];
+ for (int x = 0; x < rows; x++) {
+ for (int y = 0; y < columns; y++) {
+ BufferedImage raw = new BufferedImage(chunkWidth, chunkHeight, image.getType());
- for (int i = 0; i < rows; i++) {
- for (int j = 0; j < columns; j++) {
- int x = j * chunkWidth;
- int y = i * chunkHeight;
+ Graphics2D gr = raw.createGraphics();
+ gr.drawImage(image, 0, 0, chunkWidth, chunkHeight, chunkWidth * y, chunkHeight * x, chunkWidth * y + chunkWidth, chunkHeight * x + chunkHeight, null);
+ gr.dispose();
- BufferedImage raw = image.getSubimage(x, y, chunkWidth, chunkHeight);
- images[i][j] = new ArrayImage(raw);
+ images[x][y] = new ArrayImage(raw);
+ raw.flush();
}
}
-
return images;
}
diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/CreativeInventoryMapUpdateEvent.java b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/CreateInventoryMapUpdateEvent.java
similarity index 74%
rename from src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/CreativeInventoryMapUpdateEvent.java
rename to API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/CreateInventoryMapUpdateEvent.java
index e2f4334..a003ddc 100644
--- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/CreativeInventoryMapUpdateEvent.java
+++ b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/CreateInventoryMapUpdateEvent.java
@@ -20,40 +20,53 @@ package tech.sbdevelopment.mapreflectionapi.api.events;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+import org.bukkit.Material;
import org.bukkit.entity.Player;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
import tech.sbdevelopment.mapreflectionapi.api.MapWrapper;
-import tech.sbdevelopment.mapreflectionapi.api.events.types.CancellableEvent;
-import tech.sbdevelopment.mapreflectionapi.utils.XMaterial;
/**
* This event gets fired when a map in the creative inventory gets updated
*/
@RequiredArgsConstructor
@Getter
-public class CreativeInventoryMapUpdateEvent extends CancellableEvent {
+public class CreateInventoryMapUpdateEvent extends Event implements Cancellable {
+ private static final HandlerList handlerList = new HandlerList();
+ @Setter
+ private boolean cancelled;
+
private final Player player;
private final int slot;
private final ItemStack item;
private MapWrapper mapWrapper;
/**
- * Construct a new {@link CreativeInventoryMapUpdateEvent}
+ * Construct a new {@link CreateInventoryMapUpdateEvent}
*
* @param player The player whose inventory is updated
* @param slot The new slot
* @param item The item in the new slot
* @param isAsync Is this event called async?
*/
- public CreativeInventoryMapUpdateEvent(Player player, int slot, ItemStack item, boolean isAsync) {
+ public CreateInventoryMapUpdateEvent(Player player, int slot, ItemStack item, boolean isAsync) {
super(isAsync);
this.player = player;
this.slot = slot;
this.item = item;
}
+ @Override
+ public @NotNull HandlerList getHandlers() {
+ return handlerList;
+ }
+
/**
* Get the {@link MapWrapper} of the map of this event
*
@@ -63,7 +76,7 @@ public class CreativeInventoryMapUpdateEvent extends CancellableEvent {
public MapWrapper getMapWrapper() {
if (mapWrapper == null) {
if (item == null) return null;
- if (!XMaterial.FILLED_MAP.isSimilar(item)) return null;
+ if (item.getType() != Material.MAP) return null;
mapWrapper = MapReflectionAPI.getMapManager().getWrapperForId(player, item.getDurability());
}
diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapCancelEvent.java b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapCancelEvent.java
similarity index 76%
rename from src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapCancelEvent.java
rename to API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapCancelEvent.java
index 5fe3ac1..b7aa6c9 100644
--- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapCancelEvent.java
+++ b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapCancelEvent.java
@@ -20,15 +20,23 @@ package tech.sbdevelopment.mapreflectionapi.api.events;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
+import lombok.Setter;
import org.bukkit.entity.Player;
-import tech.sbdevelopment.mapreflectionapi.api.events.types.CancellableEvent;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.NotNull;
/**
* This event gets fired when a map creation is cancelled
*/
@RequiredArgsConstructor
@Getter
-public class MapCancelEvent extends CancellableEvent {
+public class MapCancelEvent extends Event implements Cancellable {
+ private static final HandlerList handlerList = new HandlerList();
+ @Setter
+ private boolean cancelled;
+
private final Player player;
private final int id;
@@ -44,4 +52,9 @@ public class MapCancelEvent extends CancellableEvent {
this.player = player;
this.id = id;
}
+
+ @Override
+ public @NotNull HandlerList getHandlers() {
+ return handlerList;
+ }
}
diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapContentUpdateEvent.java b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapContentUpdateEvent.java
similarity index 86%
rename from src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapContentUpdateEvent.java
rename to API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapContentUpdateEvent.java
index ce3f59d..65b9a6e 100644
--- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapContentUpdateEvent.java
+++ b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapContentUpdateEvent.java
@@ -21,9 +21,11 @@ package tech.sbdevelopment.mapreflectionapi.api.events;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.NotNull;
import tech.sbdevelopment.mapreflectionapi.api.ArrayImage;
import tech.sbdevelopment.mapreflectionapi.api.MapWrapper;
-import tech.sbdevelopment.mapreflectionapi.api.events.types.Event;
/**
* This event gets fired when the content of a {@link MapWrapper} is updated
@@ -31,6 +33,8 @@ import tech.sbdevelopment.mapreflectionapi.api.events.types.Event;
@RequiredArgsConstructor
@Getter
public class MapContentUpdateEvent extends Event {
+ private static final HandlerList handlerList = new HandlerList();
+
private final MapWrapper wrapper;
private final ArrayImage content;
@Setter
@@ -48,4 +52,9 @@ public class MapContentUpdateEvent extends Event {
this.wrapper = wrapper;
this.content = content;
}
+
+ @Override
+ public @NotNull HandlerList getHandlers() {
+ return handlerList;
+ }
}
diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapInteractEvent.java b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapInteractEvent.java
similarity index 79%
rename from src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapInteractEvent.java
rename to API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapInteractEvent.java
index 99fc4ab..6bbcb4a 100644
--- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapInteractEvent.java
+++ b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/MapInteractEvent.java
@@ -20,20 +20,28 @@ package tech.sbdevelopment.mapreflectionapi.api.events;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
+import lombok.Setter;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.Player;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
import org.bukkit.util.Vector;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import tech.sbdevelopment.mapreflectionapi.MapReflectionAPI;
import tech.sbdevelopment.mapreflectionapi.api.MapWrapper;
-import tech.sbdevelopment.mapreflectionapi.api.events.types.CancellableEvent;
/**
* This event gets fired when a player interact with a map
*/
@RequiredArgsConstructor
@Getter
-public class MapInteractEvent extends CancellableEvent {
+public class MapInteractEvent extends Event implements Cancellable {
+ private static final HandlerList handlerList = new HandlerList();
+ @Setter
+ private boolean cancelled;
+
private final Player player;
private final int entityID;
private final int action;
@@ -61,6 +69,11 @@ public class MapInteractEvent extends CancellableEvent {
this.hand = hand;
}
+ @Override
+ public @NotNull HandlerList getHandlers() {
+ return handlerList;
+ }
+
/**
* Get the {@link ItemFrame} the map is in
*
@@ -68,8 +81,10 @@ public class MapInteractEvent extends CancellableEvent {
*/
@Nullable
public ItemFrame getFrame() {
+ if (getMapWrapper() == null) return null;
+
if (frame == null) {
- frame = MapReflectionAPI.getMapManager().getItemFrameById(player.getWorld(), entityID);
+ frame = getMapWrapper().getController().getItemFrameById(player.getWorld(), entityID);
}
return frame;
}
@@ -81,11 +96,10 @@ public class MapInteractEvent extends CancellableEvent {
*/
@Nullable
public MapWrapper getMapWrapper() {
- if (getFrame() == null) return null;
if (mapWrapper == null) {
- if (!frame.hasMetadata(MapWrapper.REFERENCE_METADATA)) return null;
- mapWrapper = (MapWrapper) frame.getMetadata(MapWrapper.REFERENCE_METADATA).get(0).value();
+ mapWrapper = MapReflectionAPI.getMapManager().getWrapperForId(player, entityID);
}
+
return mapWrapper;
}
}
diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/package-info.java b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/package-info.java
similarity index 91%
rename from src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/package-info.java
rename to API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/package-info.java
index 96733cc..56c07cd 100644
--- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/package-info.java
+++ b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/events/package-info.java
@@ -1,6 +1,6 @@
/*
* This file is part of MapReflectionAPI.
- * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
+ * Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/exceptions/MapLimitExceededException.java b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/exceptions/MapLimitExceededException.java
similarity index 92%
rename from src/main/java/tech/sbdevelopment/mapreflectionapi/api/exceptions/MapLimitExceededException.java
rename to API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/exceptions/MapLimitExceededException.java
index 55a2cc7..9aa6672 100644
--- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/exceptions/MapLimitExceededException.java
+++ b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/exceptions/MapLimitExceededException.java
@@ -1,6 +1,6 @@
/*
* This file is part of MapReflectionAPI.
- * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
+ * Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/exceptions/package-info.java b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/exceptions/package-info.java
similarity index 91%
rename from src/main/java/tech/sbdevelopment/mapreflectionapi/api/exceptions/package-info.java
rename to API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/exceptions/package-info.java
index bff336f..7fb11d0 100644
--- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/exceptions/package-info.java
+++ b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/exceptions/package-info.java
@@ -1,6 +1,6 @@
/*
* This file is part of MapReflectionAPI.
- * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
+ * Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/package-info.java b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/package-info.java
similarity index 91%
rename from src/main/java/tech/sbdevelopment/mapreflectionapi/api/package-info.java
rename to API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/package-info.java
index b3d3b45..6c697b6 100644
--- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/package-info.java
+++ b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/api/package-info.java
@@ -1,6 +1,6 @@
/*
* This file is part of MapReflectionAPI.
- * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
+ * Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/cmd/MapManagerCMD.java b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/cmd/MapManagerCMD.java
similarity index 96%
rename from src/main/java/tech/sbdevelopment/mapreflectionapi/cmd/MapManagerCMD.java
rename to API/src/main/java/tech/sbdevelopment/mapreflectionapi/cmd/MapManagerCMD.java
index 4284c2a..5fe9c42 100644
--- a/src/main/java/tech/sbdevelopment/mapreflectionapi/cmd/MapManagerCMD.java
+++ b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/cmd/MapManagerCMD.java
@@ -1,6 +1,6 @@
/*
* This file is part of MapReflectionAPI.
- * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
+ * Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/MapListener.java b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/MapListener.java
similarity index 95%
rename from src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/MapListener.java
rename to API/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/MapListener.java
index 33ee0b3..4c8729e 100644
--- a/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/MapListener.java
+++ b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/MapListener.java
@@ -1,6 +1,6 @@
/*
* This file is part of MapReflectionAPI.
- * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
+ * Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/API/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java
new file mode 100644
index 0000000..d56a89e
--- /dev/null
+++ b/API/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java
@@ -0,0 +1,80 @@
+/*
+ * This file is part of MapReflectionAPI.
+ * Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see + * This class does not handle null checks as most of the requests are from the + * other utility classes that already handle null checks. + *
+ * Clientbound Packets are considered fake + * updates to the client without changing the actual data. Since all the data is handled + * by the server. + * + * @author Crypto Morin, Stijn Bannink + * @version 2.1 + */ +public class ReflectionUtil { + /** + * We use reflection mainly to avoid writing a new class for version barrier. + * The version barrier is for NMS that uses the Minecraft version as the main package name. + *
+ * E.g. EntityPlayer in 1.15 is in the class {@code net.minecraft.server.v1_15_R1} + * but in 1.14 it's in {@code net.minecraft.server.v1_14_R1} + * In order to maintain cross-version compatibility we cannot import these classes. + *
+ * Performance is not a concern for these specific statically initialized values. + */ + public static final String VERSION; + + static { // This needs to be right below VERSION because of initialization order. + // This package loop is used to avoid implementation-dependant strings like Bukkit.getVersion() or Bukkit.getBukkitVersion() + // which allows easier testing as well. + String found = null; + for (Package pack : Package.getPackages()) { + String name = pack.getName(); + + // .v because there are other packages. + if (name.startsWith("org.bukkit.craftbukkit.v")) { + found = pack.getName().split("\\.")[3]; + + // Just a final guard to make sure it finds this important class. + // As a protection for forge+bukkit implementation that tend to mix versions. + // The real CraftPlayer should exist in the package. + // Note: Doesn't seem to function properly. Will need to separate the version + // handler for NMS and CraftBukkit for softwares like catmc. + try { + Class.forName("org.bukkit.craftbukkit." + found + ".entity.CraftPlayer"); + break; + } catch (ClassNotFoundException e) { + found = null; + } + } + } + if (found == null) + throw new IllegalArgumentException("Failed to parse server version. Could not find any package starting with name: 'org.bukkit.craftbukkit.v'"); + VERSION = found; + } + + /** + * The raw minor version number. + * E.g. {@code v1_17_R1} to {@code 17} + * + * @since 4.0.0 + */ + public static final int VER = Integer.parseInt(VERSION.substring(1).split("_")[1]); + /** + * The raw minor version number. + * E.g. {@code v1_18_R2} to {@code 2} + * + * @since 4.0.0 + */ + public static final int VER_MINOR = toInt(VERSION.substring(1).split("_")[2].substring(1), 0); + /** + * Mojang remapped their NMS in 1.17 https://www.spigotmc.org/threads/spigot-bungeecord-1-17.510208/#post-4184317 + */ + public static final String + CRAFTBUKKIT = "org.bukkit.craftbukkit." + VERSION + '.', + NMS = v(17, "net.minecraft.").orElse("net.minecraft.server." + VERSION + '.'); + /** + * A nullable public accessible field only available in {@code EntityPlayer}. + * This can be null if the player is offline. + */ + private static final MethodHandle PLAYER_CONNECTION; + /** + * Responsible for getting the NMS handler {@code EntityPlayer} object for the player. + * {@code CraftPlayer} is simply a wrapper for {@code EntityPlayer}. + * Used mainly for handling packet related operations. + *
+ * This is also where the famous player {@code ping} field comes from!
+ */
+ private static final MethodHandle GET_HANDLE;
+ private static final MethodHandle GET_HANDLE_WORLD;
+ /**
+ * Sends a packet to the player's client through a {@code NetworkManager} which
+ * is where {@code ProtocolLib} controls packets by injecting channels!
+ */
+ private static final MethodHandle SEND_PACKET;
+
+ static {
+ Class> entityPlayer = getNMSClass("server.level", "EntityPlayer");
+ Class> worldServer = getNMSClass("server.level", "WorldServer");
+ Class> craftPlayer = getCraftClass("entity.CraftPlayer");
+ Class> craftWorld = getCraftClass("CraftWorld");
+ Class> playerConnection = getNMSClass("server.network", "PlayerConnection");
+
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+ MethodHandle sendPacket = null;
+ MethodHandle getHandle = null;
+ MethodHandle getHandleWorld = null;
+ MethodHandle connection = null;
+
+ try {
+ connection = lookup.findGetter(entityPlayer,
+ supports(20) ? "c" : supports(17) ? "b" : "playerConnection", playerConnection);
+ getHandle = lookup.findVirtual(craftPlayer, "getHandle", MethodType.methodType(entityPlayer));
+ getHandleWorld = lookup.findVirtual(craftWorld, "getHandle", MethodType.methodType(worldServer));
+ sendPacket = lookup.findVirtual(playerConnection,
+ v(18, "a").orElse("sendPacket"),
+ MethodType.methodType(void.class, getNMSClass("network.protocol", "Packet")));
+ } catch (NoSuchMethodException | NoSuchFieldException | IllegalAccessException ex) {
+ ex.printStackTrace();
+ }
+
+ PLAYER_CONNECTION = connection;
+ SEND_PACKET = sendPacket;
+ GET_HANDLE = getHandle;
+ GET_HANDLE_WORLD = getHandleWorld;
+ }
+
+ private ReflectionUtil() {
+ }
+
+ /**
+ * This method is purely for readability.
+ * No performance is gained.
+ *
+ * @since 5.0.0
+ */
+ public static
+ * PAY ATTENTION! The minor version is based on the NMS version.
+ * This means that v1_19_R3 has major version 19 and minor version 3.
+ *
+ * @param major the major version to compare the server version with.
+ * @param minor the minor version to compare the server version with.
+ * @return true if the version is equal or newer, otherwise false.
+ * @since 4.0.0
+ */
+ public static boolean supports(int major, int minor) {
+ return VER >= major && VER_MINOR >= minor;
+ }
+
+ /**
+ * Helper class converted to {@link List}
+ *
+ * @param