diff --git a/api/pom.xml b/api/pom.xml
index cba5ccea..0010a501 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -6,7 +6,7 @@
net.donnypz.displayentityutils
deu
- 3.7.1
+ 3.8.0
api
diff --git a/api/src/main/java/net/donnypz/displayentityutils/database/DisplayStorage.java b/api/src/main/java/net/donnypz/displayentityutils/database/DisplayStorage.java
index 5fb9d079..20870750 100644
--- a/api/src/main/java/net/donnypz/displayentityutils/database/DisplayStorage.java
+++ b/api/src/main/java/net/donnypz/displayentityutils/database/DisplayStorage.java
@@ -10,6 +10,8 @@
public interface DisplayStorage {
+ boolean isEnabled();
+
boolean saveDisplayEntityGroup(@NotNull DisplayEntityGroup group, @Nullable Player saver);
void deleteDisplayEntityGroup(@NotNull String group, @Nullable Player deleter);
@@ -24,5 +26,9 @@ public interface DisplayStorage {
@NotNull List getGroupTags();
+ @NotNull List getGroupTags(int page, int size);
+
@NotNull List getAnimationTags();
+
+ @NotNull List getAnimationTags(int page, int size);
}
diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationManager.java
index c823e2c8..3ca6d6ec 100644
--- a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationManager.java
+++ b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationManager.java
@@ -324,17 +324,6 @@ private static void attemptCacheAnimation(String tag, SpawnedDisplayAnimation an
}
}
-
- /**
- * Get the animation tags of all saved {@link DisplayAnimation}s in a storage location.
- * @param loadMethod of the search location
- * @return a list of all animations by their group tag
- */
- public static @NotNull List getSavedDisplayAnimations(@NotNull LoadMethod loadMethod){
- if (!loadMethod.isEnabled()) return Collections.emptyList();
- return DisplayAPI.getStorage(loadMethod).getAnimationTags();
- }
-
/**
* Get a {@link DisplayAnimation} from a JSON string
* @param json JSON of a saved {@link DisplayAnimation}
diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java
index 4cc55575..133386dc 100644
--- a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java
+++ b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java
@@ -738,19 +738,6 @@ private static DisplayEntityGroup getGroupFromJson(JsonObject jsonObject){
.fromJson(jsonObject, DisplayEntityGroup.class);
}
-
-
- /**
- * Get the group tags of all saved {@link DisplayEntityGroup}s in a storage location.
- * @param loadMethod of the search location
- * @return a list of all groups by their group tag
- */
- @ApiStatus.Internal
- public static @NotNull List getSavedDisplayEntityGroups(@NotNull LoadMethod loadMethod) {
- if (!loadMethod.isEnabled()) return Collections.emptyList();
- return DisplayAPI.getStorage(loadMethod).getGroupTags();
- }
-
@ApiStatus.Internal
public static void addPersistentPacketGroup(@NotNull PacketDisplayEntityGroup group, @NotNull Location location){
if (group.isPersistent()) return;
diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/LoadMethod.java b/api/src/main/java/net/donnypz/displayentityutils/managers/LoadMethod.java
index fbeb8536..215ddabe 100644
--- a/api/src/main/java/net/donnypz/displayentityutils/managers/LoadMethod.java
+++ b/api/src/main/java/net/donnypz/displayentityutils/managers/LoadMethod.java
@@ -1,8 +1,11 @@
package net.donnypz.displayentityutils.managers;
+import net.donnypz.displayentityutils.DisplayAPI;
import net.donnypz.displayentityutils.DisplayConfig;
+import net.donnypz.displayentityutils.database.DisplayStorage;
import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayAnimation;
import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayEntityGroup;
+import org.jetbrains.annotations.NotNull;
/**
* Storage locations for saving, deleting, and retrieving a saved {@link DisplayEntityGroup} or {@link DisplayAnimation}
@@ -44,6 +47,10 @@ public boolean isEnabled(){
}
}
+ public @NotNull DisplayStorage getDisplayStorage(){
+ return DisplayAPI.getStorage(this);
+ }
+
public String getDisplayName() {
return displayName;
}
diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimation.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimation.java
index 7007846b..f829ad7f 100644
--- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimation.java
+++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimation.java
@@ -20,7 +20,7 @@ public final class DisplayAnimation implements Serializable {
@Serial
private static final long serialVersionUID = 99L;
- public static final String fileExtension = ".deanim";
+ public static final String FILE_EXTENSION = ".deanim";
DisplayAnimation(){
diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayEntityGroup.java
index 2962944e..a9c11d6f 100644
--- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayEntityGroup.java
+++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayEntityGroup.java
@@ -26,7 +26,7 @@ public final class DisplayEntityGroup implements Serializable{
@Serial
private static final long serialVersionUID = 99L;
- public static final String fileExtension = ".deg";
+ public static final String FILE_EXTENSION = ".deg";
DisplayEntityGroup(SpawnedDisplayEntityGroup spawnedGroup){
this.tag = spawnedGroup.getTag();
diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java
index 04f2acaa..737b2839 100644
--- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java
+++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java
@@ -371,6 +371,7 @@ public static boolean isInLoadedChunk(@NotNull Entity entity){
/**
* Get the {@link SpawnedDisplayEntityGroup} passengers, with a specific group tag, riding an entity
* @param vehicleEntity the entity
+ * @param groupTag the group tag
* @return a list
*/
public static List getGroupPassengers(@NotNull Entity vehicleEntity, @NotNull String groupTag){
@@ -839,7 +840,8 @@ public static boolean isValidTag(@NotNull String tag){
/**
* Remove a part tag from an entity
- * @param tag the tag to remove from this part
+ * @param entity the entity to remove the tag from
+ * @param tag the tag to remove
*/
public static void removeTag(@NotNull Entity entity, @NotNull String tag){
removeFromPDCList(entity, tag, DisplayKeys.Part.PART_TAGS);
@@ -847,6 +849,7 @@ public static void removeTag(@NotNull Entity entity, @NotNull String tag){
/**
* Remove part tags from an entity
+ * @param entity the entity to remove the tag from
* @param tags the tags to remove from this part
*/
public static void removeTags(@NotNull Entity entity, @NotNull List tags){
@@ -885,6 +888,7 @@ static void removeManyFromPDCList(@NotNull Entity entity, List elements,
/**
* Gets the part tags belonging to an entity
+ * @param entity the entity
* @return The part's part tags.
*/
public static @NotNull List getTags(@NotNull Entity entity){
@@ -902,6 +906,7 @@ static void removeManyFromPDCList(@NotNull Entity entity, List elements,
/**
* Determine whether a part entity has a part tag
+ * @param entity the entity
* @param tag the tag to check for
* @return true if this part has the tag
*/
diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/gizmo/GizmoSession.java b/api/src/main/java/net/donnypz/displayentityutils/utils/gizmo/GizmoSession.java
index 288719b4..70ad6573 100644
--- a/api/src/main/java/net/donnypz/displayentityutils/utils/gizmo/GizmoSession.java
+++ b/api/src/main/java/net/donnypz/displayentityutils/utils/gizmo/GizmoSession.java
@@ -36,6 +36,8 @@ public interface GizmoSession {
void teleport(Vector direction);
+ void teleport(Location location);
+
void deselectHide();
void selectShow(Location spawnLocation);
diff --git a/docs/release-notes/3.8.0.md b/docs/release-notes/3.8.0.md
new file mode 100644
index 00000000..ef47941b
--- /dev/null
+++ b/docs/release-notes/3.8.0.md
@@ -0,0 +1,47 @@
+**Release Highlights**
+- Gizmo Changes 📐
+- New Commands 💻
+- New and Breaking API Changes 🔨
+- Bug Fixes 🐛
+
+## Gizmo Changes
+- Snapped movements can be toggled by using `SNEAK + OFFHAND`
+- The snap value can be changed by `SCROLLING (With selected axis)`
+- A selected group / entity can be cloned by `LEFT CLICKING` the pivot / white cube at the center of the Gizmo
+- Translating in teleport mode snaps to world grid when snapping is enabled
+
+## Command Changes
+
+### New Commands
+- Added `/deu display roundtranslation`
+ - Remove the decimal portion of your selected display's translation.
+ - (Ex: X translation of `12.25` would become `12.0`).
+ - Permission: `deu.display.transform`
+- Added `/deu gizmo snapvalue`
+ - Set the snapping value for a selected Gizmo control
+ - Permission: `deu.gizmo.use`
+- Added `/deu gizmo toggglesnap`
+ - Toggle the snapping of gizmo control movements
+ - Permission: `deu.gizmo.use`
+
+## API Changes
+> [!NOTE]
+>**New Version:** `3.8.0`
+
+### Additions/Changes
+- Added `DisplayStorage#isEnabled` to see if a storage location is enabled
+- Add paginated `#getGroupTags` and `#getAnimationTags` to `DisplayStorage`
+- Added `LoadMethod#getDisplayStorage`
+
+### Breaking Changes
+- Removed `DisplayAnimationManager#getSavedDisplayAnimations` in favor of `DisplayStorage#getAnimationTags`
+- Removed `DisplayGroupManager#getSavedDisplayEntityGroups` in favor of `DisplayStorage#getGroupTags`
+
+
+## Bug Fixes / QOL
+- Fixed an issue where using a `MongoDB` database without passing a `connectionString` in the config
+generated an incorrect connection string
+- Added minor optimization to listing group and animation tags from a database
+- All plugin permissions are now correctly registered
+- Player movement is now stopped after selecting a Gizmo control
+- Fixed `/deu parts clone` requiring a tag to be added to a cloned part, rather than being optional
diff --git a/plugin/pom.xml b/plugin/pom.xml
index 9e57c9c9..83853a76 100644
--- a/plugin/pom.xml
+++ b/plugin/pom.xml
@@ -6,7 +6,7 @@
net.donnypz.displayentityutils
deu
- 3.7.1
+ 3.8.0
plugin
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java b/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java
index 8ddd3113..7086cc09 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java
@@ -5,6 +5,7 @@
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketListenerPriority;
import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand;
+import net.donnypz.displayentityutils.command.Permission;
import net.donnypz.displayentityutils.database.*;
import net.donnypz.displayentityutils.listeners.autogroup.DEULoadingListeners;
import net.donnypz.displayentityutils.listeners.bdengine.BDEngineConversionListener;
@@ -91,6 +92,8 @@ public void onEnable() {
else{
getComponentLogger().warn(Component.text("bStats disabled on server using dev version."));
}
+
+ Permission.registerPermissions();
getServer().getConsoleSender().sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Plugin Enabled!", NamedTextColor.GREEN)));
}
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/ListCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/ListCMD.java
index 6c14e027..b2c63f53 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/command/ListCMD.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/ListCMD.java
@@ -1,8 +1,7 @@
package net.donnypz.displayentityutils.command;
import net.donnypz.displayentityutils.DisplayAPI;
-import net.donnypz.displayentityutils.managers.DisplayAnimationManager;
-import net.donnypz.displayentityutils.managers.DisplayGroupManager;
+import net.donnypz.displayentityutils.database.DisplayStorage;
import net.donnypz.displayentityutils.managers.LoadMethod;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
@@ -19,6 +18,7 @@ public class ListCMD extends ConsoleUsableSubCommand {
int minLength;
private final int STORAGE_INDEX;
private final int PAGE_NUMBER_INDEX;
+ private final int PAGE_SIZE = 6;
boolean listsGroups;
public ListCMD(Component incorrectUsageMessage, int minLength, boolean listsGroups) {
@@ -54,15 +54,29 @@ public void list(CommandSender sender, String[] args) {
return;
}
- List tags = listsGroups ?
- DisplayGroupManager.getSavedDisplayEntityGroups(loadMethod)
- :
- DisplayAnimationManager.getSavedDisplayAnimations(loadMethod);
+ int pageNumber = 1;
+ if (args.length > minLength) {
+ try {
+ pageNumber = Math.max(1, Integer.parseInt(args[PAGE_NUMBER_INDEX]));
+ } catch (NumberFormatException ignored) {
+ }
+ }
+
+ DisplayStorage storage = DisplayAPI.getStorage(loadMethod);
+
+ if (!storage.isEnabled()){
+ sender.sendMessage(DisplayAPI.pluginPrefix
+ .append(Component.text("Storage location is not enabled!", NamedTextColor.RED)));
+ return;
+ }
+ List tags = listsGroups
+ ? storage.getGroupTags(pageNumber, PAGE_SIZE)
+ : storage.getAnimationTags(pageNumber, PAGE_SIZE);
sender.sendMessage(DisplayAPI.pluginPrefixLong);
sender.sendMessage(MiniMessage.miniMessage().deserialize("Storage Location: " + loadMethod.getDisplayName()));
if (tags.isEmpty()) {
- sender.sendMessage(Component.text("That storage location is empty!", NamedTextColor.RED));
+ sender.sendMessage(Component.text("| Nothing to list on this page.", NamedTextColor.GRAY));
return;
}
@@ -70,22 +84,7 @@ public void list(CommandSender sender, String[] args) {
sender.sendMessage(Component.text("Click to a listed item to " + (listsGroups ? "spawn" : "select") + " it", NamedTextColor.GRAY));
}
- int pageNumber = 1;
- if (args.length > minLength) {
- try {
- pageNumber = Math.max(1, Integer.parseInt(args[PAGE_NUMBER_INDEX]));
- } catch (NumberFormatException ignored) {
- }
- }
-
- int end = pageNumber * 6;
- int start = end - 6;
-
- for (int i = start; i < end; i++) {
- if (i >= tags.size()) {
- break;
- }
- String tag = tags.get(i);
+ for (String tag : tags) {
sender.sendMessage(getMessage(tag, loadMethod));
}
sender.sendMessage(Component.text("----------" + "Page " + pageNumber + "----------", NamedTextColor.GRAY));
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java
index c6d2a760..7a4b98f0 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java
@@ -1,5 +1,8 @@
package net.donnypz.displayentityutils.command;
+import net.donnypz.displayentityutils.DisplayAPI;
+import org.bukkit.plugin.PluginManager;
+
public enum Permission {
HELP("deu.help"),
RELOAD("deu.reload"),
@@ -137,6 +140,21 @@ public enum Permission {
BDENGINE_IMPORT("deu.bdengine.import");
+ public static void registerPermissions(){
+ for (Permission permission : Permission.values()){
+ registerPermission(permission);
+ }
+ }
+
+ private static void registerPermission(Permission permission){
+ PluginManager pm = DisplayAPI.getPlugin().getServer().getPluginManager();
+ if (pm.getPermission(permission.getPermission()) == null){
+ pm.addPermission(new org.bukkit.permissions.Permission(permission.getPermission()));
+ }
+ }
+
+
+
private final String permission;
Permission(String permission){
this.permission = permission;
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayCMD.java
index 96671614..0a000fb8 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayCMD.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayCMD.java
@@ -12,6 +12,7 @@ public DisplayCMD(){
new DisplayViewRangeCMD(this);
new DisplayBillboardCMD(this);
new DisplayTranslateCMD(this);
+ new DisplayRoundTranslationCMD(this);
new DisplayResetCMD(this);
new DisplayRotateCMD(this);
new DisplaySetRotationCMD(this);
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayRoundTranslationCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayRoundTranslationCMD.java
new file mode 100644
index 00000000..4f910756
--- /dev/null
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayRoundTranslationCMD.java
@@ -0,0 +1,106 @@
+package net.donnypz.displayentityutils.command.display;
+
+import net.donnypz.displayentityutils.DisplayAPI;
+import net.donnypz.displayentityutils.command.DEUSubCommand;
+import net.donnypz.displayentityutils.command.PartsSubCommand;
+import net.donnypz.displayentityutils.command.Permission;
+import net.donnypz.displayentityutils.managers.DEUUser;
+import net.donnypz.displayentityutils.utils.DisplayEntities.ActiveGroup;
+import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart;
+import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePartSelection;
+import net.donnypz.displayentityutils.utils.DisplayEntities.MultiPartSelection;
+import net.donnypz.displayentityutils.utils.gizmo.GizmoSession;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor;
+import org.bukkit.entity.Player;
+import org.bukkit.util.Vector;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.joml.Vector3f;
+
+import java.util.List;
+
+class DisplayRoundTranslationCMD extends PartsSubCommand {
+ DisplayRoundTranslationCMD(@NotNull DEUSubCommand parentSubCommand) {
+ super("roundtranslation", parentSubCommand, Permission.DISPLAY_TRANSFORM, true);
+ super.cancelIfDraggingGizmo();
+ setTabComplete(2, List.of("x", "y", "z", "all"));
+ addFlag("-resetpivot");
+ }
+
+ @Override
+ protected void sendIncorrectUsage(@NotNull Player player) {
+ super.incorrectUsage(player);
+ }
+
+ @Override
+ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup> group, @NotNull MultiPartSelection> selection, @NotNull String[] args) {
+ String arg = args[2].toLowerCase();
+ if (!isValidArg(player, arg)) return false;
+
+ selection.getParts().forEach(part -> roundTranslation(part, arg));
+ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Translation rounded down for all selected displays!", NamedTextColor.GREEN)));
+ if (getOptionalArguments(player, args).hasFlag("-resetpivot")) resetGizmoPivot(player, selection);
+ return true;
+ }
+
+ @Override
+ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup> group, @NotNull ActivePartSelection> selection, @NotNull ActivePart selectedPart, @NotNull String[] args) {
+ if (isNotDisplay(player, selectedPart)) return false;
+
+ String arg = args[2].toLowerCase();
+ if (!isValidArg(player, arg)) return false;
+
+ roundTranslation(selectedPart, arg);
+ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Rounded down selected display's translation!", NamedTextColor.GREEN)));
+ if (getOptionalArguments(player, args).hasFlag("-resetpivot")) resetGizmoPivot(player, selection);
+ return true;
+ }
+
+ boolean isValidArg(Player player, String arg){
+ switch (arg) {
+ case "x", "y", "z", "all" -> {
+ return true;
+ }
+ default -> {
+ sendIncorrectUsage(player);
+ return false;
+ }
+ }
+ }
+
+ void roundTranslation(ActivePart part, String arg) {
+ if (!part.isDisplay()) return;
+
+ Vector3f translation = part.getTransformation().getTranslation();
+ Vector roundRemove = new Vector(
+ arg.equals("x") || arg.equals("all")
+ ? (int) translation.x - translation.x
+ : 0,
+ arg.equals("y") || arg.equals("all")
+ ? (int) translation.y - translation.y
+ : 0,
+ arg.equals("z") || arg.equals("all")
+ ? (int) translation.z - translation.z
+ : 0);
+ if (roundRemove.isZero()) {
+ return;
+ }
+ part.translate(roundRemove, 0, 0);
+ }
+
+ void resetGizmoPivot(Player player, ActivePartSelection> selection) {
+ GizmoSession gizmo = DEUUser.getOrCreateUser(player).getGizmo();
+
+ if (gizmo != null) {
+ gizmo.teleport(selection.getLocation());
+ player.sendMessage(Component.text("| Gizmo pivot reset", NamedTextColor.GRAY));
+ }
+ }
+
+
+ @Override
+ protected String getDescription() {
+ return "Remove the decimal portion of your selected display's translation. (Ex: 12.25 would become 12.0). Optionally reset gizmo pivot with \"-resetpivot\"";
+ }
+}
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/gizmo/GizmoCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/gizmo/GizmoCMD.java
index 3188bf2e..14f6cdad 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/command/gizmo/GizmoCMD.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/gizmo/GizmoCMD.java
@@ -22,6 +22,8 @@ public GizmoCMD() {
new GizmoToggleCMD(this);
new GizmoMoveHereCMD(this);
new GizmoResetPivotCMD(this);
+ new GizmoSnapValueCMD(this);
+ new GizmoToggleSnapCMD(this);
}
public static GizmoSessionImpl getOrCreateGizmo(Player player, Location spawnLocation) {
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/gizmo/GizmoSnapValueCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/gizmo/GizmoSnapValueCMD.java
new file mode 100644
index 00000000..41ec863b
--- /dev/null
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/gizmo/GizmoSnapValueCMD.java
@@ -0,0 +1,59 @@
+package net.donnypz.displayentityutils.command.gizmo;
+
+import net.donnypz.displayentityutils.DisplayAPI;
+import net.donnypz.displayentityutils.command.DEUSubCommand;
+import net.donnypz.displayentityutils.command.Permission;
+import net.donnypz.displayentityutils.command.PlayerSubCommand;
+import net.donnypz.displayentityutils.utils.gizmo.GizmoSessionImpl;
+import net.donnypz.displayentityutils.utils.gizmo.Snap;
+import net.donnypz.displayentityutils.utils.gizmo.controls.ControlType;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor;
+import net.kyori.adventure.text.minimessage.MiniMessage;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+
+public class GizmoSnapValueCMD extends PlayerSubCommand {
+
+ public GizmoSnapValueCMD(@NotNull DEUSubCommand parentSubCommand) {
+ super("snapvalue", parentSubCommand, Permission.GIZMO_USE);
+ setTabComplete(2, "");
+ }
+
+ @Override
+ public void execute(Player player, String[] args) {
+ GizmoSessionImpl gizmo = GizmoCMD.getOrCreateGizmo(player, null);
+
+
+ if (!gizmo.isScanning() || !gizmo.isDragging()) {
+ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You must have a Gizmo control selected to do this!", NamedTextColor.RED)));
+ return;
+ }
+
+
+ try {
+ Snap snap = gizmo.getSnap();
+ ControlType controlType = gizmo.getDragControl().getControlType();
+ float snapValue = Float.parseFloat(args[2]);
+ if (snapValue <= 0) throw new NumberFormatException();
+ snap.setSnapValue(snapValue);
+ final float trueSnapValue = snap.getSnapValue();
+ player.sendMessage(DisplayAPI.pluginPrefix
+ .append(MiniMessage
+ .miniMessage()
+ .deserialize("Snapping set to " + trueSnapValue + " for " + controlType.name() + " controls"
+ )
+ )
+ );
+ } catch (NumberFormatException e) {
+ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter a number greater than 0 for the snap value!", NamedTextColor.RED)));
+ }
+
+
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Set the snapping value for your selected Gizmo control";
+ }
+}
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/gizmo/GizmoToggleSnapCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/gizmo/GizmoToggleSnapCMD.java
new file mode 100644
index 00000000..d9ca7b6c
--- /dev/null
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/gizmo/GizmoToggleSnapCMD.java
@@ -0,0 +1,40 @@
+package net.donnypz.displayentityutils.command.gizmo;
+
+import net.donnypz.displayentityutils.DisplayAPI;
+import net.donnypz.displayentityutils.command.DEUSubCommand;
+import net.donnypz.displayentityutils.command.Permission;
+import net.donnypz.displayentityutils.command.PlayerSubCommand;
+import net.donnypz.displayentityutils.utils.gizmo.GizmoSessionImpl;
+import net.donnypz.displayentityutils.utils.gizmo.Snap;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+
+public class GizmoToggleSnapCMD extends PlayerSubCommand {
+ public GizmoToggleSnapCMD(@NotNull DEUSubCommand parentSubCommand) {
+ super("togglesnap", parentSubCommand, Permission.GIZMO_USE);
+ }
+
+ @Override
+ public void execute(Player player, String[] args) {
+ if (!hasMinimumArguments(player, args)) return;
+ GizmoSessionImpl gizmo = GizmoCMD.getOrCreateGizmo(player, null);
+
+ Snap snap = gizmo.getSnap();
+ snap.setEnabled(!snap.isEnabled());
+
+ if (snap.isEnabled()){
+ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Snapping enabled", NamedTextColor.GREEN)));
+ }
+ else{
+ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Snapping disabled", NamedTextColor.RED)));
+ }
+
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Toggle snapping of gizmo control movements";
+ }
+}
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCloneCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCloneCMD.java
index eb2b4175..4d598f61 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCloneCMD.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCloneCMD.java
@@ -63,12 +63,14 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti
if (!oArgs.isValidOptions()) return false;
String tag = oArgs.getOption(ADD_TAG);
- if (!DisplayUtils.isValidTag(tag) || tag.isBlank()) {
- DisplayEntityPluginCommand.invalidTag(player, tag);
- return false;
- }
- else{
- clonedPart.addTag(tag);
+ if (!tag.isBlank()){
+ if (!DisplayUtils.isValidTag(tag)){
+ DisplayEntityPluginCommand.invalidTag(player, tag);
+ return false;
+ }
+ else{
+ clonedPart.addTag(tag);
+ }
}
player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Part cloned!", NamedTextColor.GREEN)));
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/database/CommonDisplayStorageUtils.java b/plugin/src/main/java/net/donnypz/displayentityutils/database/CommonDisplayStorageUtils.java
index 4eb94e9b..67106ff7 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/database/CommonDisplayStorageUtils.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/database/CommonDisplayStorageUtils.java
@@ -33,4 +33,8 @@ static byte[] toByteArray(Object entityObject) throws IOException {
byteOut.close();
return data;
}
+
+ static int getPageOffset(int page, int size){
+ return (page - 1) * size;
+ }
}
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/database/LocalDisplayStorage.java b/plugin/src/main/java/net/donnypz/displayentityutils/database/LocalDisplayStorage.java
index 550fdea2..caa21dea 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/database/LocalDisplayStorage.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/database/LocalDisplayStorage.java
@@ -3,6 +3,7 @@
import net.donnypz.displayentityutils.DisplayConfig;
import net.donnypz.displayentityutils.managers.DisplayAnimationManager;
import net.donnypz.displayentityutils.managers.DisplayGroupManager;
+import net.donnypz.displayentityutils.managers.LoadMethod;
import net.donnypz.displayentityutils.managers.PluginFolders;
import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayAnimation;
import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayEntityGroup;
@@ -15,12 +16,21 @@
import org.jetbrains.annotations.Nullable;
import java.io.*;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPOutputStream;
public final class LocalDisplayStorage implements DisplayStorage {
+ @Override
+ public boolean isEnabled() {
+ return LoadMethod.LOCAL.isEnabled();
+ }
+
+ @Override
public boolean saveDisplayEntityGroup(@NotNull DisplayEntityGroup displayEntityGroup, @Nullable Player saver){
try{
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
@@ -33,7 +43,7 @@ public boolean saveDisplayEntityGroup(@NotNull DisplayEntityGroup displayEntityG
byte[] data = byteOut.toByteArray();
- File saveFile = new File(PluginFolders.groupSaveFolder, "/"+displayEntityGroup.getTag()+DisplayEntityGroup.fileExtension);
+ File saveFile = new File(PluginFolders.groupSaveFolder, "/"+displayEntityGroup.getTag()+DisplayEntityGroup.FILE_EXTENSION);
if (saveFile.exists()){
if (!DisplayConfig.overwritexistingSaves()){
if (saver != null){
@@ -62,8 +72,9 @@ public boolean saveDisplayEntityGroup(@NotNull DisplayEntityGroup displayEntityG
}
}
+ @Override
public void deleteDisplayEntityGroup(@NotNull String tag, @Nullable Player deleter){
- File saveFile = new File(PluginFolders.groupSaveFolder, "/"+tag+DisplayEntityGroup.fileExtension);
+ File saveFile = new File(PluginFolders.groupSaveFolder, "/"+tag+DisplayEntityGroup.FILE_EXTENSION);
if (saveFile.exists()){
saveFile.delete();
if (deleter != null){
@@ -76,14 +87,16 @@ public void deleteDisplayEntityGroup(@NotNull String tag, @Nullable Player delet
}
}
+ @Override
public @Nullable DisplayEntityGroup getDisplayEntityGroup(@NotNull String tag){
- File saveFile = new File(PluginFolders.groupSaveFolder, "/"+tag+DisplayEntityGroup.fileExtension);
+ File saveFile = new File(PluginFolders.groupSaveFolder, "/"+tag+DisplayEntityGroup.FILE_EXTENSION);
if (!saveFile.exists()){
return null;
}
return DisplayGroupManager.getGroup(saveFile);
}
+ @Override
public boolean saveDisplayAnimation(@NotNull DisplayAnimation displayAnimation, @Nullable Player saver){
try{
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
@@ -96,7 +109,7 @@ public boolean saveDisplayAnimation(@NotNull DisplayAnimation displayAnimation,
byte[] data = byteOut.toByteArray();
byteOut.close();
- File saveFile = new File(PluginFolders.animSaveFolder, "/"+displayAnimation.getAnimationTag()+DisplayAnimation.fileExtension);
+ File saveFile = new File(PluginFolders.animSaveFolder, "/"+displayAnimation.getAnimationTag()+DisplayAnimation.FILE_EXTENSION);
if (saveFile.exists()){
if (DisplayConfig.overwritexistingSaves()){
saveFile.delete();
@@ -131,8 +144,9 @@ public boolean saveDisplayAnimation(@NotNull DisplayAnimation displayAnimation,
+ @Override
public void deleteDisplayAnimation(@NotNull String tag, @Nullable Player deleter){
- File saveFile = new File(PluginFolders.animSaveFolder, "/"+tag+DisplayAnimation.fileExtension);
+ File saveFile = new File(PluginFolders.animSaveFolder, "/"+tag+DisplayAnimation.FILE_EXTENSION);
if (saveFile.exists()){
saveFile.delete();
if (deleter != null){
@@ -145,41 +159,78 @@ public void deleteDisplayAnimation(@NotNull String tag, @Nullable Player deleter
}
}
+ @Override
public @Nullable DisplayAnimation getDisplayAnimation(@NotNull String tag){
- File saveFile = new File(PluginFolders.animSaveFolder, "/"+tag+DisplayAnimation.fileExtension);
+ File saveFile = new File(PluginFolders.animSaveFolder, "/"+tag+DisplayAnimation.FILE_EXTENSION);
if (!saveFile.exists()){
return null;
}
return DisplayAnimationManager.getAnimation(saveFile);
}
+ @Override
public @NotNull List getGroupTags(){
+ return getTags(PluginFolders.groupSaveFolder, DisplayEntityGroup.FILE_EXTENSION);
+ }
+
+ @Override
+ public @NotNull List getGroupTags(int page, int size) {
+ return getTags(PluginFolders.groupSaveFolder, DisplayEntityGroup.FILE_EXTENSION, page, size);
+ }
+
+ @Override
+ public @NotNull List getAnimationTags(){
+ return getTags(PluginFolders.animSaveFolder, DisplayAnimation.FILE_EXTENSION);
+ }
+
+ @Override
+ public @NotNull List getAnimationTags(int page, int size) {
+ return getTags(PluginFolders.animSaveFolder, DisplayAnimation.FILE_EXTENSION, page, size);
+ }
+
+ private List getTags(File saveFolder, String fileExtension){
List tags = new ArrayList<>();
- File groupFolder = new File(PluginFolders.groupSaveFolder, "/");
- if (!groupFolder.exists() || groupFolder.listFiles() == null){
- return tags;
- }
- for (File file : groupFolder.listFiles()){
- if (file.getName().contains(DisplayEntityGroup.fileExtension)){
- tags.add(file.getName().replace(DisplayEntityGroup.fileExtension, ""));
- }
+ File animFolder = new File(saveFolder, "/");
+ if (!animFolder.exists()) return tags;
+
+ File[] files = animFolder.listFiles();
+ if (files == null) return tags;
+ for (File file : files){
+ String fileName = file.getName();
+ if (fileName.endsWith(fileExtension)){
+ tags.add(fileName.replace(fileExtension, ""));
+ }
}
return tags;
}
- public @NotNull List getAnimationTags(){
+ private List getTags(File saveFolder, String fileExtension, int page, int size){
List tags = new ArrayList<>();
- File animFolder = new File(PluginFolders.animSaveFolder, "/");
- if (!animFolder.exists() || animFolder.listFiles() == null){
- return tags;
- }
- for (File file : animFolder.listFiles()){
- if (file.getName().contains(DisplayAnimation.fileExtension)){
- tags.add(file.getName().replace(DisplayAnimation.fileExtension, ""));
- }
+ int offset = CommonDisplayStorageUtils.getPageOffset(page, size);
+ int skipped = 0;
+ int count = 0;
+
+ try (DirectoryStream stream = Files.newDirectoryStream(saveFolder.toPath())) {
+ for (Path path : stream) {
+ if (!Files.isRegularFile(path)) continue;
+
+ String fileName = path.getFileName().toString();
+ if (!fileName.endsWith(fileExtension)) continue;
+
+ if (skipped++ < offset) continue;
+
+ String tag = fileName.substring(0, fileName.length() - fileExtension.length());
+ tags.add(tag);
+
+ if (++count >= size) {
+ break;
+ }
+ }
+ } catch (IOException e) {
+ return tags;
}
- return tags;
+ return tags;
}
}
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/database/MYSQLDisplayStorage.java b/plugin/src/main/java/net/donnypz/displayentityutils/database/MYSQLDisplayStorage.java
index 0de19e13..4d8247fc 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/database/MYSQLDisplayStorage.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/database/MYSQLDisplayStorage.java
@@ -5,6 +5,7 @@
import net.donnypz.displayentityutils.DisplayConfig;
import net.donnypz.displayentityutils.managers.DisplayAnimationManager;
import net.donnypz.displayentityutils.managers.DisplayGroupManager;
+import net.donnypz.displayentityutils.managers.LoadMethod;
import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayAnimation;
import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayEntityGroup;
import net.kyori.adventure.text.Component;
@@ -132,6 +133,11 @@ private Connection getConnection(){
}
}
+ @Override
+ public boolean isEnabled() {
+ return LoadMethod.MYSQL.isEnabled();
+ }
+
@Override
public boolean saveDisplayEntityGroup(@NotNull DisplayEntityGroup displayEntityGroup, @Nullable Player saver){
String tag = displayEntityGroup.getTag();
@@ -191,11 +197,67 @@ public void deleteDisplayAnimation(@NotNull String tag, @Nullable Player deleter
return getTags(GROUP_TABLE);
}
+ @Override
+ public @NotNull List getGroupTags(int page, int size) {
+ return getTags(GROUP_TABLE, page, size);
+ }
+
@Override
public @NotNull List getAnimationTags(){
return getTags(ANIMATION_TABLE);
}
+ @Override
+ public @NotNull List getAnimationTags(int page, int size) {
+ return getTags(ANIMATION_TABLE, page, size);
+ }
+
+ private List getTags(String tableName){ //internally set table name
+ if (!isConnected()) return Collections.emptyList();
+ List tags = new ArrayList<>();
+ String retrieve = "SELECT "+TAG_COLUMN+" FROM "+tableName+";";
+
+ try(Connection connection = getConnection();
+ Statement statement = connection.createStatement();
+ ResultSet results = statement.executeQuery(retrieve)){
+
+ while(results.next()){
+ tags.add(results.getString(TAG_COLUMN));
+ }
+ }
+ catch(SQLException e){
+ e.printStackTrace();
+ }
+ return tags;
+ }
+
+ private List getTags(String tableName, int page, int size){ //internally set table name
+ if (!isConnected()) return new ArrayList<>();
+ List tags = new ArrayList<>();
+
+ int offset = CommonDisplayStorageUtils.getPageOffset(page, size);
+ String retrieve =
+ """
+ SELECT %s FROM %s
+ ORDER BY %s
+ LIMIT %d
+ OFFSET %d
+ """.formatted(TAG_COLUMN, tableName, TAG_COLUMN, size, offset);
+
+ try(Connection connection = getConnection();
+ Statement statement = connection.createStatement();
+ ResultSet results = statement.executeQuery(retrieve)){
+
+ while(results.next()){
+ tags.add(results.getString(TAG_COLUMN));
+ }
+ }
+ catch(SQLException e){
+ e.printStackTrace();
+ }
+ return tags;
+ }
+
private boolean saveEntity(String tag, Object entity, String tableName, String displayName, Player saver){
if (!isConnected()) return false;
String save = "INSERT INTO "+tableName+" VALUES(?, ?);";
@@ -312,22 +374,5 @@ private boolean hasEntity(String tag, String tableName, Connection connection){
}
}
- private List getTags(String tableName){ //internally set table name
- if (!isConnected()) return Collections.emptyList();
- List tags = new ArrayList<>();
- String retrieve = "SELECT "+TAG_COLUMN+" FROM "+tableName+";";
-
- try(Connection connection = getConnection();
- Statement statement = connection.createStatement();
- ResultSet results = statement.executeQuery(retrieve)){
- while(results.next()){
- tags.add(results.getString(TAG_COLUMN));
- }
- }
- catch(SQLException e){
- e.printStackTrace();
- }
- return tags;
- }
}
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/database/MongoDisplayStorage.java b/plugin/src/main/java/net/donnypz/displayentityutils/database/MongoDisplayStorage.java
index 30b9a1fd..251fd70f 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/database/MongoDisplayStorage.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/database/MongoDisplayStorage.java
@@ -6,10 +6,12 @@
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Projections;
+import com.mongodb.client.model.Sorts;
import net.donnypz.displayentityutils.DisplayAPI;
import net.donnypz.displayentityutils.DisplayConfig;
import net.donnypz.displayentityutils.managers.DisplayAnimationManager;
import net.donnypz.displayentityutils.managers.DisplayGroupManager;
+import net.donnypz.displayentityutils.managers.LoadMethod;
import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayAnimation;
import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayEntityGroup;
import net.kyori.adventure.text.Component;
@@ -54,12 +56,11 @@ public void createConnection(
String animationCollection
){
String connectionString = String.format(
- "mongodb://%s:%s@%s:%d/%s",
+ "mongodb://%s:%s@%s:%d",
username,
password,
host,
- port,
- databaseName
+ port
);
this.createConnection(
@@ -159,6 +160,11 @@ public void closeConnection(){
}
}
+ @Override
+ public boolean isEnabled() {
+ return LoadMethod.MONGODB.isEnabled();
+ }
+
@Override
public boolean saveDisplayEntityGroup(@NotNull DisplayEntityGroup displayEntityGroup, @Nullable Player saver){
String tag = displayEntityGroup.getTag();
@@ -237,11 +243,53 @@ public void deleteDisplayAnimation(@NotNull String tag, @Nullable Player deleter
return getTags(GROUP_COLLECTION);
}
+ @Override
+ public @NotNull List getGroupTags(int page, int size) {
+ return getTags(GROUP_COLLECTION, page, size);
+ }
+
@Override
public @NotNull List getAnimationTags(){
return getTags(ANIMATION_COLLECTION);
}
+ @Override
+ public @NotNull List getAnimationTags(int page, int size) {
+ return getTags(ANIMATION_COLLECTION, page, size);
+ }
+
+ private List getTags(MongoCollection collection){
+ if (!isConnected()) return new ArrayList<>();
+
+ return collection.find()
+ .projection(
+ Projections.fields(
+ Projections.include(TAG_FIELD),
+ Projections.excludeId()
+ )
+ )
+ .map(doc -> doc.getString(TAG_FIELD))
+ .into(new ArrayList<>());
+ }
+
+ private List getTags(MongoCollection collection, int page, int size){
+ if (!isConnected()) return new ArrayList<>();
+ int offset = CommonDisplayStorageUtils.getPageOffset(page, size);
+
+ return collection.find()
+ .skip(offset)
+ .limit(size)
+ .sort(Sorts.ascending(TAG_FIELD))
+ .projection(
+ Projections.fields(
+ Projections.include(TAG_FIELD),
+ Projections.excludeId()
+ )
+ )
+ .map(doc -> doc.getString(TAG_FIELD))
+ .into(new ArrayList<>());
+ }
+
private boolean saveEntity(
String tag,
@@ -312,20 +360,6 @@ private void deleteEntity(
}
}
- private List getTags(MongoCollection collection){
- if (!isConnected()) return new ArrayList<>();
-
- return collection.find()
- .projection(
- Projections.fields(
- Projections.include(TAG_FIELD),
- Projections.excludeId()
- )
- )
- .map(doc -> doc.getString(TAG_FIELD))
- .into(new ArrayList<>());
- }
-
private Document getGroupDocument(String tag){
return GROUP_COLLECTION.find(new Document(TAG_FIELD, tag))
.first();
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/gizmo/DEUGizmoListener.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/gizmo/DEUGizmoListener.java
index 1cb45cc7..5625859d 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/gizmo/DEUGizmoListener.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/gizmo/DEUGizmoListener.java
@@ -63,7 +63,7 @@ public void onSelectControl(PlayerInteractAtEntityEvent e) {
if (!GizmoManager.isGizmoWand(item)) return;
e.setCancelled(true);
- GizmoSessionImpl gizmo = (GizmoSessionImpl) getGizmoSession(player);
+ GizmoSessionImpl gizmo = getGizmoSession(player);
if (gizmo == null) return;
if (gizmo.hasActiveControl()){
@@ -81,7 +81,7 @@ public void onSelectControl(PlayerInteractEvent e) {
if (!player.hasPermission(Permission.GIZMO_USE.getPermission())) return;
if (e.getHand() == EquipmentSlot.OFF_HAND) return;
- GizmoSessionImpl gizmo = (GizmoSessionImpl) getGizmoSession(player);
+ GizmoSessionImpl gizmo = getGizmoSession(player);
if (gizmo == null) return;
if (gizmo.isLastInteractionItemDrop()){
gizmo.setLastInteractionItemDrop(false);
@@ -112,7 +112,15 @@ public void onHeldItem(PlayerItemHeldEvent e) {
int oldSlot = e.getPreviousSlot();
ItemStack newItem = player.getInventory().getItem(newSlot);
ItemStack oldItem = player.getInventory().getItem(oldSlot);
- setGizmoScanning(player, newItem, oldItem);
+
+ boolean cancelEvent = changeGizmoSnapValue(player, newSlot, oldSlot);
+ //Snapping
+ if (cancelEvent){
+ e.setCancelled(true);
+ }
+ else{
+ setGizmoScanning(player, newItem, oldItem);
+ }
}
@EventHandler(priority = EventPriority.LOW)
@@ -121,6 +129,7 @@ public void onSlotChange(PlayerInventorySlotChangeEvent e) {
int slot = e.getSlot();
ItemStack newItem = e.getNewItemStack();
ItemStack oldItem = e.getOldItemStack();
+
if (slot != player.getInventory().getHeldItemSlot()) return;
setGizmoScanning(player, newItem, oldItem);
}
@@ -132,7 +141,13 @@ public void onSwitchItem(PlayerSwapHandItemsEvent e){
if (!GizmoManager.isGizmoWand(toOffhand)) return;
e.setCancelled(true);
- switchSpace(player);
+
+ if (player.isSneaking()){
+ toggleSnapping(player);
+ }
+ else{
+ switchSpace(player);
+ }
}
@EventHandler(priority = EventPriority.LOW)
@@ -144,13 +159,13 @@ public void onDropItem(PlayerDropItemEvent e){
e.setCancelled(true);
switchTranslationMode(player);
- GizmoSessionImpl gizmo = (GizmoSessionImpl) getGizmoSession(player);
+ GizmoSessionImpl gizmo = getGizmoSession(player);
if (gizmo == null) return;
gizmo.setLastInteractionItemDrop(true);
}
private void switchTranslationMode(Player player){
- GizmoSessionImpl gizmo = (GizmoSessionImpl) getGizmoSession(player);
+ GizmoSessionImpl gizmo = getGizmoSession(player);
if (gizmo == null) return;
TranslationMode mode = gizmo.getTranslationMode();
@@ -165,7 +180,7 @@ private void switchTranslationMode(Player player){
}
private void switchSpace(Player player){
- GizmoSessionImpl gizmo = (GizmoSessionImpl) getGizmoSession(player);
+ GizmoSessionImpl gizmo = getGizmoSession(player);
if (gizmo == null) return;
GizmoSpace gizmoSpace = gizmo.getGizmoSpace();
@@ -177,12 +192,24 @@ private void switchSpace(Player player){
player.playSound(player, Sound.BLOCK_NOTE_BLOCK_XYLOPHONE, 1, 1.2f);
}
+ private void toggleSnapping(Player player){
+ GizmoSessionImpl gizmo = getGizmoSession(player);
+ if (gizmo == null) return;
+ Snap snap = gizmo.getSnap();
+
+ snap.setEnabled(!snap.isEnabled());
+ GizmoTitleUtil.showSnapStatus(player, snap.isEnabled());
+ player.playSound(player, Sound.BLOCK_NOTE_BLOCK_HAT, 1, 1.2f);
+ }
+
private void switchSelectionMode(Player player){
DEUUser user = DEUUser.getUser(player);
if (user != null && user.getSelectedPartSelection() instanceof SinglePartSelection){
+ GizmoTitleUtil.showCannotChangeSelectionMode(player);
+ player.playSound(player, Sound.BLOCK_NOTE_BLOCK_COW_BELL, 1, 0.8f);
return;
}
- GizmoSessionImpl gizmo = (GizmoSessionImpl) getGizmoSession(player);
+ GizmoSessionImpl gizmo = getGizmoSession(player);
if (gizmo == null) return;
GizmoSelectionMode mode = gizmo.getSelectionMode();
@@ -195,7 +222,7 @@ private void switchSelectionMode(Player player){
}
private void setGizmoStatus(Player player, boolean leftClick) {
- GizmoSessionImpl gizmo = (GizmoSessionImpl) getGizmoSession(player);
+ GizmoSessionImpl gizmo = getGizmoSession(player);
if (gizmo == null) return;
if (leftClick) {
@@ -238,9 +265,36 @@ private void setGizmoScanning(Player player,
gizmo.setScanning(true);
}
- private GizmoSession getGizmoSession(Player player) {
+ private boolean changeGizmoSnapValue(Player player, int newSlot, int oldSlot){ //boolean = cancel event?
+ GizmoSessionImpl gizmo = getGizmoSession(player);
+ if (gizmo == null) return false;
+
+ if (!gizmo.isScanning() || !gizmo.isDragging()) return false;
+
+ int difference = newSlot - oldSlot;
+
+ boolean isScrollDown;
+ if (difference == 1 || difference == -8) {
+ isScrollDown = true;
+ } else if (difference == -1 || difference == 8) {
+ isScrollDown = false;
+ }
+ else{ //used number keys instead of scroll-wheel
+ return true;
+ }
+
+ Snap snap = gizmo.getSnap();
+ snap.update(isScrollDown);
+
+ Drag drag = gizmo.getDragControl();
+ GizmoTitleUtil.showSnapValue(player, snap, drag.getControlType());
+ player.playSound(player, Sound.BLOCK_NOTE_BLOCK_HAT, 1, 1.2f);
+ return true;
+ }
+
+ private GizmoSessionImpl getGizmoSession(Player player) {
DEUUser user = DEUUser.getUser(player);
if (user == null) return null;
- return user.getGizmo();
+ return (GizmoSessionImpl) user.getGizmo();
}
}
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/GizmoSessionImpl.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/GizmoSessionImpl.java
index 94ec82af..52277bb1 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/GizmoSessionImpl.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/GizmoSessionImpl.java
@@ -1,6 +1,7 @@
package net.donnypz.displayentityutils.utils.gizmo;
import net.donnypz.displayentityutils.DisplayAPI;
+import net.donnypz.displayentityutils.command.group.GroupCMD;
import net.donnypz.displayentityutils.events.GroupSpawnedEvent;
import net.donnypz.displayentityutils.managers.DEUUser;
import net.donnypz.displayentityutils.managers.DisplayGroupManager;
@@ -9,10 +10,7 @@
import net.donnypz.displayentityutils.utils.gizmo.controls.GizmoAxis;
import net.donnypz.displayentityutils.utils.gizmo.controls.Control;
import net.donnypz.displayentityutils.utils.gizmo.controls.drag.Drag;
-import net.donnypz.displayentityutils.utils.gizmo.controls.selector.RotationSelector;
-import net.donnypz.displayentityutils.utils.gizmo.controls.selector.ScaleSelector;
-import net.donnypz.displayentityutils.utils.gizmo.controls.selector.Selector;
-import net.donnypz.displayentityutils.utils.gizmo.controls.selector.AxisSelector;
+import net.donnypz.displayentityutils.utils.gizmo.controls.selector.*;
import net.donnypz.displayentityutils.utils.gizmo.util.GizmoTitleUtil;
import net.donnypz.displayentityutils.utils.relativepoints.RelativePointUtils;
import net.donnypz.displayentityutils.utils.version.folia.Scheduler;
@@ -21,6 +19,8 @@
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit;
import org.bukkit.Location;
+import org.bukkit.Particle;
+import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
@@ -36,6 +36,7 @@ public class GizmoSessionImpl implements GizmoSession {
public static final int SCAN_FREQUENCY = 1;
private final PacketDisplayEntityGroup gizmoModel;
+ private final Snap snap;
private TranslationMode translationMode = TranslationMode.TELEPORT;
private GizmoSpace gizmoSpace = GizmoSpace.LOCAL;
private GizmoSelectionMode selectionMode = GizmoSelectionMode.GROUP;
@@ -63,6 +64,10 @@ public class GizmoSessionImpl implements GizmoSession {
public GizmoSessionImpl(Player player, Location spawnLocation) {
this.playerUUID = player.getUniqueId();
this.deuUser = DEUUser.getOrCreateUser(player);
+ this.snap = new Snap(this);
+
+ //Clone Selector
+ this.selectors.add(new CloneSelector());
//Translate Axis
this.selectors.add(AxisSelector.x());
@@ -115,10 +120,7 @@ public PacketDisplayEntityGroup getGizmoModel() {
return gizmoModel;
}
- public void teleport(Location location) {
- if (!valid) return;
- gizmoModel.teleport(location, true);
- }
+
public void setPitch(float pitch) {
gizmoModel.setPitch(pitch, false);
@@ -136,6 +138,10 @@ public void setLastInteractionItemDrop(boolean lastInteractionItemDrop){
this.lastInteractionItemDrop = lastInteractionItemDrop;
}
+ public Snap getSnap() {
+ return snap;
+ }
+
@Override
public TranslationMode getTranslationMode() {
return translationMode;
@@ -193,6 +199,12 @@ public void teleport(Vector direction) {
gizmoModel.teleport(direction, direction.length());
}
+ @Override
+ public void teleport(Location location) {
+ if (!valid) return;
+ gizmoModel.teleport(location, true);
+ }
+
@Override
public float getScale() {
return scale;
@@ -357,7 +369,32 @@ public Drag selectHovered() {
ActivePartSelection> sel = DEUUser.getOrCreateUser(player).getSelectedPartSelection();
if (sel == null) return null;
+ player.setVelocity(new Vector());
activeDrag = hoveredSelector.getDrag(player, this);
+ if (activeDrag == null && hoveredSelector instanceof CloneSelector) {
+ boolean result;
+ if (sel instanceof MultiPartSelection> m){
+ ActiveGroup> clonedGroup = m.getGroup().clone(m.getLocation());
+ result = GroupCMD.selectGroupSilentSuccess(player, clonedGroup, false, true);
+ }
+ else{
+ ActivePart clonedPart = sel.getSelectedPart().clone();
+ SinglePartSelection newSelection = new SinglePartSelection((SpawnedDisplayEntityPart) clonedPart);
+
+ DEUUser user = DEUUser.getUser(player);
+ user.setSelectedPartSelection(newSelection, false);
+ result = true;
+ }
+
+ if (result) {
+ player.sendMessage(DisplayAPI.pluginPrefix
+ .append(Component.text("Selection cloned!", NamedTextColor.GREEN)));
+ player.playSound(player, Sound.BLOCK_NOTE_BLOCK_CHIME, 1f, 1.25f);
+
+ Location gizmoLoc = gizmoModel.getLocation();
+ gizmoLoc.getWorld().spawnParticle(Particle.END_ROD, gizmoLoc, 10, 0.1,0.1,0.1,0.1f);
+ }
+ }
}
return activeDrag;
}
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/GizmoWand.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/GizmoWand.java
index 63d2984a..a470593b 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/GizmoWand.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/GizmoWand.java
@@ -30,6 +30,7 @@ public static void give(Player player){
player.sendMessage(DisplayAPI.pluginPrefix
.append(Component.text("Gizmo wand added to your inventory!", NamedTextColor.GREEN)));
+ player.sendMessage(Component.text("| Controls in wand's item lore", NamedTextColor.GRAY, TextDecoration.ITALIC));
player.playSound(player, Sound.ENTITY_ITEM_PICKUP, 1, 1);
}
@@ -59,31 +60,57 @@ public static void toggleLink(Player player, GizmoSessionImpl gizmo, boolean eff
}
private static void buildItem() {
- if (gizmoItemStack == null) {
+ //if (gizmoItemStack == null) {
gizmoItemStack = new ItemStack(Material.STICK);
gizmoItemStack.editMeta(meta -> {
- meta.displayName(MiniMessage.miniMessage().deserialize("DEU Gizmo Wand"));
+ meta.displayName(MiniMessage.miniMessage()
+ .deserialize("DEU Gizmo Wand")
+ .decoration(TextDecoration.ITALIC, false));
meta.lore(List.of(
- MiniMessage.miniMessage().deserialize("L-CLICK: Select Axis")
+ MiniMessage.miniMessage().deserialize("<#87e09c>L-CLICK: Select Axis")
.decoration(TextDecoration.ITALIC, false),
- MiniMessage.miniMessage().deserialize("<#b5deb4>L-CLICK (With selected Axis): Unlink Gizmo/Move pivot")
+ MiniMessage.miniMessage().deserialize("<#f07787>R-CLICK (With selected Axis): Deselect Axis")
.decoration(TextDecoration.ITALIC, false),
- MiniMessage.miniMessage().deserialize("R-CLICK : Switch Selection Mode (Group/Filter/Part)")
+ MiniMessage.miniMessage().deserialize("<#dce8e0>L-CLICK (With selected Axis): Unlink Gizmo/Move pivot")
.decoration(TextDecoration.ITALIC, false),
- MiniMessage.miniMessage().deserialize("R-CLICK (With selected Axis): Deselect Axis")
+
+
+ Component.empty(),
+
+ Component.text("Sneak + Offhand (", TextColor.fromHexString("#a3bdd9"))
+ .append(Component.keybind("key.sneak"))
+ .append(Component.text(" + "))
+ .append(Component.keybind("key.swapOffhand"))
+ .append(Component.text(")"))
+ .append(Component.text(": Toggle Snapping", NamedTextColor.GRAY))
+ .decoration(TextDecoration.ITALIC, false),
+ MiniMessage.miniMessage().deserialize("<#966496>Scroll (With selected Axis): Change Snapping Value")
+ .decoration(TextDecoration.ITALIC, false),
+
+ Component.empty(),
+
+ MiniMessage.miniMessage().deserialize("R-CLICK : Switch Selection Mode (Group/Filter/Part)")
.decoration(TextDecoration.ITALIC, false),
Component.text("Offhand (", NamedTextColor.YELLOW)
.append(Component.keybind("key.swapOffhand"))
.append(Component.text(")"))
.append(Component.text(": Toggle Space (Local/World)", NamedTextColor.GRAY))
.decoration(TextDecoration.ITALIC, false),
- Component.text("Drop Item (", TextColor.color(150, 100, 150))
+ Component.text("Drop Item (", TextColor.fromHexString("#c4f054"))
.append(Component.keybind("key.drop"))
.append(Component.text(")"))
.append(Component.text(": Toggle Translation Mode (Translate/Teleport)", NamedTextColor.GRAY))
.decoration(TextDecoration.ITALIC, false),
+
+
+ Component.empty(),
+
+ MiniMessage.miniMessage().deserialize("<#bcf7dd>L-CLICK (Pivot / White Cube<#bcf7dd>): Clone Selection")
+ .decoration(TextDecoration.ITALIC, false),
+
Component.empty(),
- MiniMessage.miniMessage().deserialize("/deu gizmo help - for additional tools")
+
+ MiniMessage.miniMessage().deserialize("/deu gizmo help - for additional tools")
.decoration(TextDecoration.ITALIC, false),
Component.text("Gizmo Model by: illystray", NamedTextColor.DARK_GRAY)
.decoration(TextDecoration.ITALIC, false)
@@ -91,6 +118,6 @@ private static void buildItem() {
PersistentDataContainer pdc = meta.getPersistentDataContainer();
pdc.set(DisplayKeys.Gizmo.WAND, PersistentDataType.BOOLEAN, true);
});
- }
+ // }
}
}
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/Snap.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/Snap.java
new file mode 100644
index 00000000..7188b15a
--- /dev/null
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/Snap.java
@@ -0,0 +1,108 @@
+package net.donnypz.displayentityutils.utils.gizmo;
+
+import net.donnypz.displayentityutils.utils.gizmo.controls.drag.*;
+
+public class Snap {
+
+ private float translationSnap = 0.5f; //in blocks
+ private float rotationSnap = 15.0f; //in deg/rad
+ private float scaleSnap = 0.25f; //in blocks
+
+ public final float TRANSLATION_STEP = 0.05f;
+ public final float ROTATION_STEP = 1f;
+ public final float SCALE_STEP = 0.05f;
+
+ private final float MAX_TRANSLATION_SNAP = 5.0f;
+ private final float MAX_ROTATION_SNAP = 90.0f;
+ private final float MAX_SCALE_SNAP = 1.0f;
+
+
+ private boolean isEnabled;
+
+ private final GizmoSessionImpl gizmo;
+
+ public Snap(GizmoSessionImpl gizmo) {
+ this.gizmo = gizmo;
+ }
+
+ public boolean isEnabled() {
+ return isEnabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ isEnabled = enabled;
+ }
+
+ /**
+ * Set the snap vale of the gizmo's translation, rotation, or scale, based on the gizmo's current selection
+ * @param snapValue
+ */
+ public void setSnapValue(float snapValue){
+ Drag drag = gizmo.getDragControl();
+ if (drag == null) return;
+
+ switch (drag.getControlType()){
+ case TRANSLATION -> {
+ this.translationSnap = Math.clamp(snapValue, TRANSLATION_STEP, MAX_TRANSLATION_SNAP);
+ }
+ case ROTATION -> {
+ this.rotationSnap = Math.clamp(snapValue, ROTATION_STEP, MAX_ROTATION_SNAP);
+ }
+ case SCALE -> {
+ this.scaleSnap = Math.clamp(snapValue, SCALE_STEP, MAX_SCALE_SNAP);
+ }
+ }
+ }
+
+ public float getSnapValue(){
+ Drag drag = gizmo.getDragControl();
+ if (drag == null) return 0;
+
+ switch (drag.getControlType()){
+ case TRANSLATION -> {
+ return translationSnap;
+ }
+ case ROTATION -> {
+ return rotationSnap;
+ }
+ case SCALE -> {
+ return scaleSnap;
+ }
+ default -> {
+ return 0;
+ }
+ }
+ }
+
+ private float getSnapStep(){
+ Drag drag = gizmo.getDragControl();
+ if (drag == null) return 0;
+
+ switch (drag.getControlType()){
+ case TRANSLATION -> {
+ return TRANSLATION_STEP;
+ }
+ case ROTATION -> {
+ return ROTATION_STEP;
+ }
+ case SCALE -> {
+ return SCALE_STEP;
+ }
+ default -> {
+ return 0;
+ }
+ }
+ }
+
+ public void update(boolean isScrollDown){
+ float snapValue;
+ if (isScrollDown){
+ snapValue = getSnapValue() - getSnapStep();
+ }
+ else{
+ snapValue = getSnapValue() + getSnapStep();
+ }
+
+ setSnapValue(snapValue);
+ }
+}
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/Control.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/Control.java
index be262d76..c67878c3 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/Control.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/Control.java
@@ -6,11 +6,13 @@
public abstract class Control {
protected final GizmoAxis axis;
+ private final ControlType controlType;
public static final float MAX_DISTANCE = 15.0f;
public static final float MAX_DISTANCE_SQUARED = MAX_DISTANCE*MAX_DISTANCE;
- protected Control(GizmoAxis axis){
+ protected Control(GizmoAxis axis, ControlType controlType) {
this.axis = axis;
+ this.controlType = controlType;;
}
public void glow(ActiveGroup> gizmo) {
@@ -33,5 +35,9 @@ public GizmoAxis getAxis() {
return axis;
}
+ public ControlType getControlType() {
+ return controlType;
+ }
+
public abstract String getTag();
}
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/ControlType.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/ControlType.java
new file mode 100644
index 00000000..d9e2cdeb
--- /dev/null
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/ControlType.java
@@ -0,0 +1,7 @@
+package net.donnypz.displayentityutils.utils.gizmo.controls;
+
+public enum ControlType {
+ TRANSLATION,
+ ROTATION,
+ SCALE;
+}
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/GizmoAxis.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/GizmoAxis.java
index 5e7ee174..2d656380 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/GizmoAxis.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/GizmoAxis.java
@@ -6,6 +6,8 @@
import java.util.Arrays;
public enum GizmoAxis {
+ CENTER(Color.WHITE, "pivot", new Vector3f(0,0,0)),
+
//axes
X(Color.RED, "move_x", new Vector3f(1, 0, 0)),
Y(Color.LIME, "move_y", new Vector3f(0, 1, 0)),
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/drag/Drag.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/drag/Drag.java
index a37cd652..9d4462fc 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/drag/Drag.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/drag/Drag.java
@@ -1,13 +1,14 @@
package net.donnypz.displayentityutils.utils.gizmo.controls.drag;
+import net.donnypz.displayentityutils.utils.gizmo.controls.ControlType;
import net.donnypz.displayentityutils.utils.gizmo.controls.GizmoAxis;
import net.donnypz.displayentityutils.utils.gizmo.controls.Control;
import org.bukkit.entity.Player;
public abstract class Drag extends Control {
- public Drag(GizmoAxis axis) {
- super(axis);
+ public Drag(GizmoAxis axis, ControlType type) {
+ super(axis, type);
}
public abstract void updatePosition(Player player);
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/drag/RotationDrag.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/drag/RotationDrag.java
index d32d608d..1dc69643 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/drag/RotationDrag.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/drag/RotationDrag.java
@@ -5,9 +5,12 @@
import net.donnypz.displayentityutils.utils.gizmo.GizmoSelectionMode;
import net.donnypz.displayentityutils.utils.gizmo.GizmoSessionImpl;
import net.donnypz.displayentityutils.utils.gizmo.GizmoSpace;
+import net.donnypz.displayentityutils.utils.gizmo.Snap;
+import net.donnypz.displayentityutils.utils.gizmo.controls.ControlType;
import net.donnypz.displayentityutils.utils.gizmo.controls.GizmoAxis;
import net.donnypz.displayentityutils.utils.gizmo.util.GizmoMathUtil;
import org.bukkit.Location;
+import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.joml.Quaternionf;
import org.joml.Vector3f;
@@ -30,8 +33,11 @@ public class RotationDrag extends Drag {
//prev dir from gizmo to player's looking dir
private final Vector3f lastDirection = new Vector3f();
+ private float totalAngleChange;
+ private float appliedSnapAngle;
+
public RotationDrag(Player player, GizmoSessionImpl gizmo, GizmoAxis axis) {
- super(axis);
+ super(axis, ControlType.ROTATION);
this.gizmo = gizmo;
this.originalAxis = axis.getDirections()[0];
this.pivotPoint = gizmo.getGizmoModel().getLocation().toVector().toVector3f();
@@ -67,7 +73,9 @@ public RotationDrag(Player player, GizmoSessionImpl gizmo, GizmoAxis axis) {
@Override
public void updatePosition(Player player) {
+ if (player.isSneaking()) return;
if (!gizmo.isLinked()) return;
+
Vector3f hit = playerRayAndPlaneCollision(player);
if (hit == null) {
return;
@@ -84,11 +92,32 @@ public void updatePosition(Player player) {
lastDirection.set(currentDirection);
- if (Math.abs(angle) < 1e-6f) {
+ if (Math.abs(angle) < 1e-6f) return;
+
+ totalAngleChange += angle;
+
+ Snap snap = gizmo.getSnap();
+ float snapValueDeg = snap.getSnapValue();
+
+ //No snapping
+ if (!snap.isEnabled() || snapValueDeg <= 0){
+ applyToPlayerSelection(angle);
return;
}
- applyToPlayerSelection(angle);
+ float snapValueRad = (float) Math.toRadians(snapValueDeg);
+
+ float snappedAngle = GizmoMathUtil.getSnappedValue(totalAngleChange, snapValueRad);
+
+ float delta = snappedAngle - appliedSnapAngle;
+
+ if (Math.abs(delta) < 1e-6f) return;
+
+ appliedSnapAngle = snappedAngle;
+
+ applyToPlayerSelection(delta);
+ player.playSound(player, Sound.BLOCK_NOTE_BLOCK_HAT, 1, 1);
+
}
private void applyToPlayerSelection(float angle) {
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/drag/ScaleDrag.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/drag/ScaleDrag.java
index 9fef8e65..b223aa53 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/drag/ScaleDrag.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/drag/ScaleDrag.java
@@ -6,13 +6,17 @@
import net.donnypz.displayentityutils.utils.gizmo.GizmoSelectionMode;
import net.donnypz.displayentityutils.utils.gizmo.GizmoSessionImpl;
import net.donnypz.displayentityutils.utils.gizmo.GizmoSpace;
+import net.donnypz.displayentityutils.utils.gizmo.Snap;
+import net.donnypz.displayentityutils.utils.gizmo.controls.ControlType;
import net.donnypz.displayentityutils.utils.gizmo.controls.GizmoAxis;
+import net.donnypz.displayentityutils.utils.gizmo.util.GizmoMathUtil;
import net.donnypz.displayentityutils.utils.gizmo.util.GizmoTitleUtil;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit;
import org.bukkit.Location;
+import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.util.Transformation;
import org.joml.Quaternionf;
@@ -30,8 +34,11 @@ public class ScaleDrag extends Drag {
private final Vector3f lastHitPoint;
+ private float totalScaleChange;
+ private float appliedSnapScale;
+
public ScaleDrag(Player player, GizmoSessionImpl gizmo, GizmoAxis axis) {
- super(axis);
+ super(axis, ControlType.SCALE);
this.gizmo = gizmo;
this.originalAxis = axis.getDirections()[0];
@@ -41,21 +48,45 @@ public ScaleDrag(Player player, GizmoSessionImpl gizmo, GizmoAxis axis) {
@Override
public void updatePosition(Player player) {
- if (lastHitPoint == null)
- return;
+ if (player.isSneaking()) return;
+ if (lastHitPoint == null) return;
Vector3f hit = playerRayAndPlaneCollision(player);
-
Vector3f delta = hit.sub(lastHitPoint, new Vector3f());
lastHitPoint.set(hit);
float movementAmount = delta.dot(currentAxis);
- if (Math.abs(movementAmount) < 1e-6f)
+ if (Math.abs(movementAmount) < 1e-6f) return;
+
+ float scaleDelta = movementAmount * 2f;
+ Snap snap = gizmo.getSnap();
+ float scaleSnapValue = snap.getSnapValue();
+
+ //No snapping
+ if (!snap.isEnabled() || scaleSnapValue <= 0){
+ applyScale(scaleDelta);
return;
+ }
+
+ totalScaleChange += scaleDelta;
+
+ float snappedScale = GizmoMathUtil.getSnappedValue(totalScaleChange, scaleSnapValue);
+
+ float deltaScale = snappedScale - appliedSnapScale;
+
+ if (Math.abs(deltaScale) < 1e-6f) return;
+
+ float lastAppliedSnapScale = appliedSnapScale;
+ appliedSnapScale = snappedScale;
+
+ if (!applyScale(deltaScale)){
+ this.appliedSnapScale = lastAppliedSnapScale;
+ this.totalScaleChange -= scaleDelta;
+ }
+ player.playSound(player, Sound.BLOCK_NOTE_BLOCK_HAT, 1, 1);
- applyScale(movementAmount);
}
private void computeCurrentAxisDirection() {
@@ -119,48 +150,50 @@ private Vector3f createPlaneNormal(Vector3f lookDir) {
.normalize();
}
- private void applyScale(float movementAmount) {
-
- float scaleDelta = movementAmount * 2f;
-
+ private boolean applyScale(float scaleDelta) {
ActivePartSelection> selection =
DEUUser.getOrCreateUser(gizmo.getPlayerUUID())
.getSelectedPartSelection();
if (gizmo.getSelectionMode() == GizmoSelectionMode.PART || selection instanceof SinglePartSelection) {
ActivePart part = selection.getSelectedPart();
- if (part == null) return;
+ if (part == null) return false;
if (part.isDisplay()) {
scaleDisplay(part, scaleDelta);
- } else if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION) {
+ }
+ else if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION) {
if (axis == GizmoAxis.Y) {
part.setInteractionHeight(part.getInteractionHeight() + scaleDelta);
- } else {
+ }
+ else {
part.setInteractionWidth(part.getInteractionWidth() + scaleDelta);
}
- } else if (part.getType() == SpawnedDisplayEntityPart.PartType.MANNEQUIN) {
+ }
+ else if (part.getType() == SpawnedDisplayEntityPart.PartType.MANNEQUIN) {
part.setMannequinScale(part.getMannequinScale() + scaleDelta);
}
- } else if (selection instanceof MultiPartSelection> multi) {
+ }
+ else if (selection instanceof MultiPartSelection> multi) {
ActiveGroup> group = multi.getGroup();
float scale = group.getScaleMultiplier() + scaleDelta;
if (scale < 0.1f) {
- return;
+ return false;
}
if (gizmo.getSelectionMode() == GizmoSelectionMode.FILTER && group.getSize() != multi.getSize()) {
GizmoTitleUtil.show(Bukkit.getPlayer(gizmo.getPlayerUUID()),
Component.text("Scale Failed", NamedTextColor.RED),
MiniMessage.miniMessage().deserialize("⚠ Filtered selection cannot be scaled separately ⚠"));
-
- } else {
+ }
+ else {
GroupTeleportCompletableFuture future = group.scale(scale, GizmoSessionImpl.SCAN_FREQUENCY + 1, true);
//block thread until non-display teleports complete
if (future != null) future.block();
}
}
+ return true;
}
private void scaleDisplay(ActivePart part, float scaleDelta) {
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/drag/TranslationAxisDrag.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/drag/TranslationAxisDrag.java
index 3cde0038..060ea191 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/drag/TranslationAxisDrag.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/drag/TranslationAxisDrag.java
@@ -25,7 +25,6 @@ private void computeCurrentAxisDirection() {
rotation.transform(super.currentAxesDir[0]).normalize();
}
-
}
@Override
@@ -55,12 +54,25 @@ protected Vector3f playerRayAndPlaneCollision(Player player) {
:
new Vector3f(super.lastHitPoint); //behind player camera
- distance = Math.min(distance, MAX_LOOK_DISTANCE*gizmo.getScale());
+ distance = Math.min(distance, MAX_LOOK_DISTANCE * gizmo.getScale());
return new Vector3f(playerEyePos)
.fma(distance, ray);
}
+ @Override
+ protected Vector3f getMovementAmounts(Player player, Vector3f delta) {
+ return new Vector3f(delta.dot(currentAxesDir[0]), 0, 0);
+ }
+
+ @Override
+ protected Vector3f[] getMovementVectors(Vector3f movementAmounts) {
+ float movementAmount = movementAmounts.x;
+ Vector3f movement = super.currentAxesDir[0].mul(movementAmount, new Vector3f());
+ Vector3f movementTranslate = super.originalAxes[0].mul(movementAmount, new Vector3f());
+ return new Vector3f[]{movement, movementTranslate};
+ }
+
//plane's normal, faces the player, but still perpendicular to axis.
private Vector3f createPlaneNormal(Vector3f playerLookDir) {
float dotProduct = playerLookDir.dot(super.currentAxesDir[0]);
@@ -69,14 +81,4 @@ private Vector3f createPlaneNormal(Vector3f playerLookDir) {
.sub(new Vector3f(super.currentAxesDir[0]).mul(dotProduct))
.normalize();
}
-
- @Override
- public Vector3f[] getMovementVectors(Player player, Vector3f delta){
- Vector3f currentAxis = super.currentAxesDir[0];
- float movementAmount = delta.dot(currentAxis);
-
- Vector3f movement = new Vector3f(currentAxis).mul(movementAmount);
- Vector3f movementTranslate = new Vector3f(super.originalAxes[0]).mul(movementAmount);
- return new Vector3f[]{movement, movementTranslate};
- }
}
\ No newline at end of file
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/drag/TranslationDrag.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/drag/TranslationDrag.java
index bdee48b2..e74265aa 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/drag/TranslationDrag.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/drag/TranslationDrag.java
@@ -3,10 +3,8 @@
import net.donnypz.displayentityutils.managers.DEUUser;
import net.donnypz.displayentityutils.utils.DisplayEntities.*;
import net.donnypz.displayentityutils.utils.DisplayEntities.concurrent.GroupTeleportCompletableFuture;
-import net.donnypz.displayentityutils.utils.gizmo.GizmoSelectionMode;
-import net.donnypz.displayentityutils.utils.gizmo.GizmoSessionImpl;
-import net.donnypz.displayentityutils.utils.gizmo.GizmoSpace;
-import net.donnypz.displayentityutils.utils.gizmo.TranslationMode;
+import net.donnypz.displayentityutils.utils.gizmo.*;
+import net.donnypz.displayentityutils.utils.gizmo.controls.ControlType;
import net.donnypz.displayentityutils.utils.gizmo.controls.GizmoAxis;
import net.donnypz.displayentityutils.utils.gizmo.util.GizmoTitleUtil;
import net.kyori.adventure.text.Component;
@@ -14,6 +12,7 @@
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit;
import org.bukkit.Location;
+import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import org.joml.Quaternionf;
@@ -30,17 +29,21 @@ public abstract class TranslationDrag extends Drag {
protected final GizmoSessionImpl gizmo;
protected final Quaternionf rotation = new Quaternionf();
protected final Vector3f lastHitPoint;
+ protected final Vector3f initialHitPoint;
+ private final Vector3f totalMovementAmounts = new Vector3f();
+ private final Vector3f appliedSnappedAmounts = new Vector3f();
protected final Vector3f[] originalAxes;
protected final Vector3f[] currentAxesDir;
public TranslationDrag(Player player, GizmoSessionImpl gizmo, GizmoAxis axis) {
- super(axis);
+ super(axis, ControlType.TRANSLATION);
this.gizmo = gizmo;
this.originalAxes = axis.getDirections();
this.currentAxesDir = IntStream.range(0, 2)
.mapToObj(i -> new Vector3f())
.toArray(Vector3f[]::new);
- this.lastHitPoint = playerRayAndPlaneCollision(player);
+ this.initialHitPoint = playerRayAndPlaneCollision(player);
+ this.lastHitPoint = new Vector3f(initialHitPoint);
}
@@ -57,21 +60,73 @@ public String getTag() {
return axis.getTag();
}
- public abstract Vector3f[] getMovementVectors(Player player, Vector3f delta);
+ protected abstract Vector3f getMovementAmounts(Player player, Vector3f delta);
+
+ protected abstract Vector3f[] getMovementVectors(Vector3f movementAmounts);
private void updateTranslationMovement(Player player) {
+ if (player.isSneaking()) return;
+
Vector3f hit = playerRayAndPlaneCollision(player);
- Vector3f delta = hit.sub(this.lastHitPoint, new Vector3f());
+ Vector3f deltaFromLast = hit.sub(this.lastHitPoint, new Vector3f());
- this.lastHitPoint.set(hit);
+ Vector3f movementAmounts = getMovementAmounts(player, deltaFromLast);
+
+ movementAmounts = applySnapping(player, movementAmounts);
+
+ Vector3f[] movementVectors = getMovementVectors(movementAmounts);
- Vector3f[] movementVectors = getMovementVectors(player, delta);
Vector3f movement = movementVectors[0];
Vector3f movementTranslate = movementVectors[1];
- if (movement.lengthSquared() > 1e-6f) {
- this.applyMovement(movement, movementTranslate);
+ if (movement.lengthSquared() <= 1e-6f) {
+ this.lastHitPoint.set(hit);
+ return;
+ }
+
+ this.lastHitPoint.set(hit);
+ this.applyMovement(movement, movementTranslate);
+ }
+
+ private Vector3f applySnapping(Player player, Vector3f movementAmounts) {
+ Snap snap = gizmo.getSnap();
+
+ if (!snap.isEnabled()) {
+ return movementAmounts;
+ }
+
+ totalMovementAmounts.add(movementAmounts);
+
+ float snapValue = snap.getSnapValue();
+
+ Vector3f snappedAmounts = new Vector3f(
+ snapAmount(totalMovementAmounts.x, snapValue),
+ snapAmount(totalMovementAmounts.y, snapValue),
+ snapAmount(totalMovementAmounts.z, snapValue)
+ );
+
+ Vector3f snappedDelta = snappedAmounts
+ .sub(appliedSnappedAmounts, new Vector3f());
+
+ appliedSnappedAmounts.set(snappedAmounts);
+
+ if (snappedDelta.lengthSquared() > 1e-6f) {
+ if (player != null) {
+ player.playSound(player, Sound.BLOCK_NOTE_BLOCK_HAT, 1, 1);
+ }
}
+
+ return snappedDelta;
+ }
+
+ private float snapAmount(float amount, float snapValue) {
+ float sign = Math.signum(amount);
+
+ return (float) (
+ Math.floor(Math.abs(amount) / snapValue)
+ * snapValue
+ * sign
+ );
}
protected void applyMovement(Vector3f delta, Vector3f translateDelta) {
@@ -81,8 +136,7 @@ protected void applyMovement(Vector3f delta, Vector3f translateDelta) {
protected void applyToGizmo(Vector3f delta) {
Vector bukkitDelta = Vector.fromJOML(delta);
- Location l = gizmo.getGizmoModel()
- .getLocation();
+ Location l = gizmo.getGizmoModel().getLocation();
l.add(bukkitDelta);
gizmo.teleport(l);
}
@@ -97,9 +151,13 @@ protected void applyToPlayerSelection(Vector3f delta, Vector3f translateDelta) {
if (gizmo.getTranslationMode() == TranslationMode.TRANSLATE) {
this.translate(delta, translateDelta, sel);
} else {
- Vector bukkitDelta = Vector.fromJOML(delta);
- Location tpLoc = sel.getLocation();
- tpLoc.add(bukkitDelta);
+ Location tpLoc = sel.getLocation().clone();
+ tpLoc.add(Vector.fromJOML(delta));
+
+ Snap snap = gizmo.getSnap();
+
+ if (snap.isEnabled()) adjustTeleportForSnap(tpLoc, snap);
+
this.teleport(tpLoc, sel);
}
@@ -108,6 +166,34 @@ protected void applyToPlayerSelection(Vector3f delta, Vector3f translateDelta) {
}
}
+ private void adjustTeleportForSnap(Location tpLoc, Snap snap) {
+ float snapValue = snap.getSnapValue();
+
+ switch (axis) {
+ case X -> {
+ tpLoc.setX(Math.round(tpLoc.getX() / snapValue) * snapValue);
+ }
+ case Y -> {
+ tpLoc.setY(Math.round(tpLoc.getY() / snapValue) * snapValue);
+ }
+ case Z -> {
+ tpLoc.setZ(Math.round(tpLoc.getZ() / snapValue) * snapValue);
+ }
+ case XY -> {
+ tpLoc.setX(Math.round(tpLoc.getX() / snapValue) * snapValue);
+ tpLoc.setY(Math.round(tpLoc.getY() / snapValue) * snapValue);
+ }
+ case YZ -> {
+ tpLoc.setY(Math.round(tpLoc.getY() / snapValue) * snapValue);
+ tpLoc.setZ(Math.round(tpLoc.getZ() / snapValue) * snapValue);
+ }
+ case ZX -> {
+ tpLoc.setZ(Math.round(tpLoc.getZ() / snapValue) * snapValue);
+ tpLoc.setX(Math.round(tpLoc.getX() / snapValue) * snapValue);
+ }
+ }
+ }
+
private boolean canTeleport() {
ActivePartSelection> sel = DEUUser
.getOrCreateUser(gizmo.getPlayerUUID())
@@ -120,15 +206,14 @@ private boolean canTeleport() {
Player player = Bukkit.getPlayer(gizmo.getPlayerUUID());
if (sel instanceof MultiPartSelection> mp && gizmo.isLinked()) {
ActiveGroup> group = mp.getGroup();
- if (group != null){
- if (group.isRiding()){
+ if (group != null) {
+ if (group.isRiding()) {
GizmoTitleUtil.show(player,
Component.text("Teleport Failed", NamedTextColor.RED),
MiniMessage.miniMessage().deserialize("⚠ Group cannot be riding an entity ⚠"));
return false;
- }
- else if (group instanceof PacketDisplayEntityGroup pdeg
- && pdeg.isPlaced()){
+ } else if (group instanceof PacketDisplayEntityGroup pdeg
+ && pdeg.isPlaced()) {
GizmoTitleUtil.show(player,
Component.text("Teleport Failed", NamedTextColor.RED),
MiniMessage.miniMessage().deserialize("⚠ Cannot teleport group placed by player w/ item ⚠"));
@@ -139,13 +224,13 @@ else if (group instanceof PacketDisplayEntityGroup pdeg
return true;
}
- private void undoTranslateDeltaRotation(Vector3f translateDelta, ActivePartSelection> sel){
+ private void undoTranslateDeltaRotation(Vector3f translateDelta, ActivePartSelection> sel) {
Location loc = sel.getLocation();
float pitch = loc.getPitch();
float yaw = loc.getYaw();
Quaternionf undoRotation = new Quaternionf()
- .rotateY((float)Math.toRadians(-yaw))
- .rotateX((float)Math.toRadians(pitch))
+ .rotateY((float) Math.toRadians(-yaw))
+ .rotateX((float) Math.toRadians(pitch))
.invert(); //normalize and conjugates (negate imaginary, keep scalar same)
undoRotation.transform(translateDelta);
@@ -153,21 +238,20 @@ private void undoTranslateDeltaRotation(Vector3f translateDelta, ActivePartSelec
private void translate(Vector3f delta, Vector3f translateDelta, ActivePartSelection> sel) {
Vector bukkitTranslateDelta;
- if (gizmo.getGizmoSpace() == GizmoSpace.WORLD){
+ if (gizmo.getGizmoSpace() == GizmoSpace.WORLD) {
undoTranslateDeltaRotation(translateDelta, sel);
}
bukkitTranslateDelta = Vector.fromJOML(translateDelta);
Vector bukkitDelta = Vector.fromJOML(delta);
- if (gizmo.getSelectionMode() == GizmoSelectionMode.PART || sel instanceof SinglePartSelection){
+ if (gizmo.getSelectionMode() == GizmoSelectionMode.PART || sel instanceof SinglePartSelection) {
ActivePart part = sel.getSelectedPart();
if (part == null) return;
part.translate(part.isDisplay()
? bukkitTranslateDelta
: bukkitDelta,
GizmoSessionImpl.SCAN_FREQUENCY, 0);
- }
- else if (sel instanceof MultiPartSelection> mps){
+ } else if (sel instanceof MultiPartSelection> mps) {
for (ActivePart p : getParts(mps)) {
p.translate(p.isDisplay()
? bukkitTranslateDelta
@@ -178,7 +262,7 @@ else if (sel instanceof MultiPartSelection> mps){
}
private void teleport(Location tpLoc, ActivePartSelection> sel) {
- if (sel instanceof SinglePartSelection){
+ if (sel instanceof SinglePartSelection) {
ActivePart part = sel.getSelectedPart();
if (part == null) return;
part.setTeleportDuration(GizmoSessionImpl.SCAN_FREQUENCY);
@@ -190,8 +274,7 @@ private void teleport(Location tpLoc, ActivePartSelection> sel) {
} catch (ExecutionException | InterruptedException e) {
throw new RuntimeException(e);
}
- }
- else if (sel instanceof MultiPartSelection> mps){
+ } else if (sel instanceof MultiPartSelection> mps) {
ActiveGroup> group = mps.getGroup();
if (group != null) {
group.setTeleportDuration(GizmoSessionImpl.SCAN_FREQUENCY);
@@ -205,7 +288,7 @@ else if (sel instanceof MultiPartSelection> mps){
}
}
- private List extends ActivePart> getParts(MultiPartSelection> mps){
+ private List extends ActivePart> getParts(MultiPartSelection> mps) {
return gizmo.getSelectionMode() == GizmoSelectionMode.GROUP
? mps.getGroup().getParts()
: mps.getParts();
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/drag/TranslationPlaneDrag.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/drag/TranslationPlaneDrag.java
index 67342488..5f617214 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/drag/TranslationPlaneDrag.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/drag/TranslationPlaneDrag.java
@@ -57,30 +57,50 @@ protected Vector3f playerRayAndPlaneCollision(Player player) {
:
new Vector3f(super.lastHitPoint); //behind player camera
- distance = Math.min(distance, MAX_LOOK_DISTANCE* gizmo.getScale());
+ distance = Math.min(distance, MAX_LOOK_DISTANCE * gizmo.getScale());
return new Vector3f(playerEyePos)
.fma(distance, ray);
}
- private Vector3f createPlaneNormal(){
- return new Vector3f(super.currentAxesDir[0])
- .cross(super.currentAxesDir[1])
- .normalize();
+ @Override
+ protected Vector3f getMovementAmounts(Player player, Vector3f delta) {
+ return new Vector3f(
+ delta.dot(currentAxesDir[0]), //axis1
+ delta.dot(currentAxesDir[1]), //axis2
+ 0
+ );
}
@Override
- public Vector3f[] getMovementVectors(Player player, Vector3f delta){
- float movementAmountAxis1 = delta.dot(super.currentAxesDir[0]);
- float movementAmountAxis2 = delta.dot(super.currentAxesDir[1]);
-
- Vector3f movement = new Vector3f(super.currentAxesDir[0])
- .mul(movementAmountAxis1)
- .add(new Vector3f(super.currentAxesDir[1]).mul(movementAmountAxis2));
+ protected Vector3f[] getMovementVectors(Vector3f movementAmounts) {
+ float movementAmountAxis1 = movementAmounts.x;
+ float movementAmountAxis2 = movementAmounts.y;
+
+ Vector3f movement =
+ new Vector3f(
+ super.currentAxesDir[0])
+ .mul(movementAmountAxis1)
+ .add(
+ new Vector3f(super.currentAxesDir[1])
+ .mul(movementAmountAxis2)
+ );
Vector3f movementTranslate =
- new Vector3f(super.originalAxes[0]).mul(movementAmountAxis1)
- .add(new Vector3f(super.originalAxes[1]).mul(movementAmountAxis2));
- return new Vector3f[]{movement, new Vector3f(movementTranslate)};
+ new Vector3f(
+ super.originalAxes[0])
+ .mul(movementAmountAxis1)
+ .add(
+ new Vector3f(super.originalAxes[1])
+ .mul(movementAmountAxis2)
+ );
+
+ return new Vector3f[]{movement, movementTranslate};
+ }
+
+ private Vector3f createPlaneNormal() {
+ return new Vector3f(super.currentAxesDir[0])
+ .cross(super.currentAxesDir[1])
+ .normalize();
}
}
\ No newline at end of file
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/AxisSelector.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/AxisSelector.java
index b8a35e6e..83cc569d 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/AxisSelector.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/AxisSelector.java
@@ -1,11 +1,12 @@
package net.donnypz.displayentityutils.utils.gizmo.controls.selector;
+import net.donnypz.displayentityutils.utils.gizmo.controls.ControlType;
import net.donnypz.displayentityutils.utils.gizmo.controls.GizmoAxis;
public abstract class AxisSelector extends Selector{
- AxisSelector(GizmoAxis axis) {
- super(axis);
+ AxisSelector(GizmoAxis axis, ControlType controlType) {
+ super(axis, controlType);
}
public static TranslationAxisSelector x() {
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/CloneSelector.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/CloneSelector.java
new file mode 100644
index 00000000..77154102
--- /dev/null
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/CloneSelector.java
@@ -0,0 +1,22 @@
+package net.donnypz.displayentityutils.utils.gizmo.controls.selector;
+
+import net.donnypz.displayentityutils.utils.gizmo.GizmoSessionImpl;
+import net.donnypz.displayentityutils.utils.gizmo.controls.GizmoAxis;
+import net.donnypz.displayentityutils.utils.gizmo.controls.drag.Drag;
+import org.bukkit.entity.Player;
+
+public class CloneSelector extends CubeSelector {
+ public CloneSelector() {
+ super(GizmoAxis.CENTER);
+ }
+
+ @Override
+ public String getTag() {
+ return axis.getTag();
+ }
+
+ @Override
+ public Drag getDrag(Player player, GizmoSessionImpl gizmo) {
+ return null;
+ }
+}
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/CubeSelector.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/CubeSelector.java
new file mode 100644
index 00000000..c80ed0da
--- /dev/null
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/CubeSelector.java
@@ -0,0 +1,137 @@
+package net.donnypz.displayentityutils.utils.gizmo.controls.selector;
+
+import net.donnypz.displayentityutils.utils.gizmo.GizmoSpace;
+import net.donnypz.displayentityutils.utils.gizmo.controls.ControlType;
+import net.donnypz.displayentityutils.utils.gizmo.controls.GizmoAxis;
+import net.donnypz.displayentityutils.utils.gizmo.util.GizmoMathUtil;
+import org.bukkit.Location;
+import org.bukkit.entity.Player;
+import org.joml.Vector3f;
+
+public abstract class CubeSelector extends AxisSelector {
+
+ protected final Vector3f localStart;
+ protected final Vector3f localEnd;
+ protected float radius = 0.125f;
+
+ public CubeSelector(GizmoAxis axis) {
+ super(axis, ControlType.SCALE);
+ this.localStart = axis.getDirections()[0]
+ .mul(1.2f);
+ this.localEnd = axis.getDirections()[0]
+ .mul(1.40f);
+ }
+
+ @Override
+ public String getTag() {
+ return axis.getScaleTag();
+ }
+
+
+ @Override
+ public float intersect(GizmoSpace gizmoSpace, Player player, Location gizmoLocation) {
+ Location eyeLoc = player.getEyeLocation();
+
+
+ Vector3f rayOrigin = eyeLoc.toVector()
+ .toVector3f()
+ .sub(gizmoLocation.toVector().toVector3f());
+
+ Vector3f ray = eyeLoc.getDirection()
+ .toVector3f()
+ .normalize();
+
+
+ Vector3f axisStart = GizmoMathUtil.rotate(
+ new Vector3f(localStart),
+ gizmoSpace,
+ gizmoLocation
+ );
+
+ Vector3f axisEnd = GizmoMathUtil.rotate(
+ new Vector3f(localEnd),
+ gizmoSpace,
+ gizmoLocation
+ );
+
+
+ Vector3f axisDir = new Vector3f(axisEnd)
+ .sub(axisStart);
+
+ float axisLength = axisDir.length();
+
+ //Point selector
+ if (axisLength < 1e-6f) { // ~ 0
+ // Point selector
+ Vector3f toPoint = new Vector3f(axisStart)
+ .sub(rayOrigin);
+
+ float distanceAlongRay = toPoint.dot(ray);
+
+ if (distanceAlongRay < 0) {
+ return -1;
+ }
+
+ Vector3f closestPointOnRay = new Vector3f(rayOrigin)
+ .fma(distanceAlongRay, ray);
+
+ if (closestPointOnRay.distance(axisStart) > radius) {
+ return -1;
+ }
+
+ return distanceAlongRay;
+ }
+
+ axisDir.normalize();
+
+ Vector3f axisStartToRayOrigin = new Vector3f(rayOrigin)
+ .sub(axisStart);
+
+
+ //see how much player's ray and axis dir point in same dir
+ float rayDotAxis = ray.dot(axisDir);
+
+ //denominator for closest-point calculation.
+ float denom = 1 - rayDotAxis * rayDotAxis;
+
+
+ //parallel or opposite, ray & axis
+ if (denom < 1e-6f) return -1;
+
+ float startDotAxis = axisStartToRayOrigin.dot(axisDir);
+
+ //distance from player eye to closest point on ray
+ float distanceAlongRay =
+ (rayDotAxis * startDotAxis - axisStartToRayOrigin.dot(ray))
+ / denom;
+
+
+ if (distanceAlongRay < 0) return -1;
+
+ Vector3f closestPointOnRay = new Vector3f(rayOrigin)
+ .fma(distanceAlongRay, ray);
+
+
+ float distanceAlongAxis = axisStartToRayOrigin
+ .add(new Vector3f(ray).mul(distanceAlongRay))
+ .dot(axisDir);
+
+
+ if (distanceAlongAxis < 0 || distanceAlongAxis > axisLength) return -1;
+
+
+ Vector3f axisPoint = new Vector3f(axisStart)
+ .fma(distanceAlongAxis, axisDir);
+
+ if (closestPointOnRay.distance(axisPoint) > radius) return -1;
+
+ return distanceAlongRay;
+ }
+
+ @Override
+ public void scale(float oldScale, float scaleMultiplier) {
+ GizmoMathUtil.scale(localStart, oldScale, scaleMultiplier);
+ GizmoMathUtil.scale(localEnd, oldScale, scaleMultiplier);
+ radius = (radius / oldScale) * scaleMultiplier;
+ }
+}
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/RotationSelector.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/RotationSelector.java
index c0c84162..219ea59b 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/RotationSelector.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/RotationSelector.java
@@ -2,6 +2,7 @@
import net.donnypz.displayentityutils.utils.gizmo.GizmoSessionImpl;
import net.donnypz.displayentityutils.utils.gizmo.GizmoSpace;
+import net.donnypz.displayentityutils.utils.gizmo.controls.ControlType;
import net.donnypz.displayentityutils.utils.gizmo.controls.GizmoAxis;
import net.donnypz.displayentityutils.utils.gizmo.controls.drag.Drag;
import net.donnypz.displayentityutils.utils.gizmo.controls.drag.RotationDrag;
@@ -16,7 +17,7 @@ public class RotationSelector extends Selector {
private float ringThickness = 0.075f;
RotationSelector(GizmoAxis axis) {
- super(axis);
+ super(axis, ControlType.ROTATION);
}
public static RotationSelector x() {
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/ScaleSelector.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/ScaleSelector.java
index 71b7218b..719bc495 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/ScaleSelector.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/ScaleSelector.java
@@ -1,122 +1,18 @@
package net.donnypz.displayentityutils.utils.gizmo.controls.selector;
-import net.donnypz.displayentityutils.utils.gizmo.GizmoSpace;
-import net.donnypz.displayentityutils.utils.gizmo.controls.GizmoAxis;
import net.donnypz.displayentityutils.utils.gizmo.GizmoSessionImpl;
+import net.donnypz.displayentityutils.utils.gizmo.controls.GizmoAxis;
import net.donnypz.displayentityutils.utils.gizmo.controls.drag.Drag;
import net.donnypz.displayentityutils.utils.gizmo.controls.drag.ScaleDrag;
-import net.donnypz.displayentityutils.utils.gizmo.util.GizmoMathUtil;
-import org.bukkit.Location;
import org.bukkit.entity.Player;
-import org.joml.Vector3f;
-
-public class ScaleSelector extends AxisSelector {
-
- private final Vector3f localStart;
- private final Vector3f localEnd;
- private float radius = 0.125f;
+public class ScaleSelector extends CubeSelector{
public ScaleSelector(GizmoAxis axis) {
super(axis);
- this.localStart = axis.getDirections()[0]
- .mul(1.2f);
- this.localEnd = axis.getDirections()[0]
- .mul(1.40f);
- }
-
- @Override
- public String getTag() {
- return axis.getScaleTag();
- }
-
-
- @Override
- public float intersect(GizmoSpace gizmoSpace, Player player, Location gizmoLocation) {
- Location eyeLoc = player.getEyeLocation();
-
-
- Vector3f rayOrigin = eyeLoc.toVector()
- .toVector3f()
- .sub(gizmoLocation.toVector().toVector3f());
-
- Vector3f ray = eyeLoc.getDirection()
- .toVector3f()
- .normalize();
-
-
- Vector3f axisStart = GizmoMathUtil.rotate(
- new Vector3f(localStart),
- gizmoSpace,
- gizmoLocation
- );
-
- Vector3f axisEnd = GizmoMathUtil.rotate(
- new Vector3f(localEnd),
- gizmoSpace,
- gizmoLocation
- );
-
-
- Vector3f axisDir = new Vector3f(axisEnd)
- .sub(axisStart);
-
- float axisLength = axisDir.length();
- axisDir.normalize();
-
-
- Vector3f axisStartToRayOrigin = new Vector3f(rayOrigin)
- .sub(axisStart);
-
-
- //see how much player's ray and axis dir point in same dir
- float rayDotAxis = ray.dot(axisDir);
-
- //denominator for closest-point calculation.
- float denom = 1 - rayDotAxis * rayDotAxis;
-
-
- //parallel or opposite, ray & axis
- if (denom < 1e-6f) return -1;
-
- float startDotAxis = axisStartToRayOrigin.dot(axisDir);
-
- //distance from player eye to closest point on ray
- float distanceAlongRay =
- (rayDotAxis * startDotAxis - axisStartToRayOrigin.dot(ray))
- / denom;
-
-
- if (distanceAlongRay < 0) return -1;
-
- Vector3f closestPointOnRay = new Vector3f(rayOrigin)
- .fma(distanceAlongRay, ray);
-
-
- float distanceAlongAxis = axisStartToRayOrigin
- .add(new Vector3f(ray).mul(distanceAlongRay))
- .dot(axisDir);
-
-
- if (distanceAlongAxis < 0 || distanceAlongAxis > axisLength) return -1;
-
-
- Vector3f axisPoint = new Vector3f(axisStart)
- .fma(distanceAlongAxis, axisDir);
-
- if (closestPointOnRay.distance(axisPoint) > radius) return -1;
-
- return distanceAlongRay;
- }
-
- @Override
- public void scale(float oldScale, float scaleMultiplier) {
- GizmoMathUtil.scale(localStart, oldScale, scaleMultiplier);
- GizmoMathUtil.scale(localEnd, oldScale, scaleMultiplier);
- radius = (radius / oldScale) * scaleMultiplier;
}
@Override
public Drag getDrag(Player player, GizmoSessionImpl gizmo) {
return new ScaleDrag(player, gizmo, axis);
}
-}
+}
\ No newline at end of file
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/Selector.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/Selector.java
index 64d29c18..65d81f61 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/Selector.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/Selector.java
@@ -1,6 +1,7 @@
package net.donnypz.displayentityutils.utils.gizmo.controls.selector;
import net.donnypz.displayentityutils.utils.gizmo.GizmoSpace;
+import net.donnypz.displayentityutils.utils.gizmo.controls.ControlType;
import net.donnypz.displayentityutils.utils.gizmo.controls.GizmoAxis;
import net.donnypz.displayentityutils.utils.gizmo.GizmoSessionImpl;
import net.donnypz.displayentityutils.utils.gizmo.controls.Control;
@@ -10,8 +11,8 @@
public abstract class Selector extends Control {
- public Selector(GizmoAxis axis) {
- super(axis);
+ public Selector(GizmoAxis axis, ControlType controlType) {
+ super(axis, controlType);
}
public abstract float intersect(GizmoSpace gizmoSpace, Player player, Location gizmoLocation);
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/TranslationAxisSelector.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/TranslationAxisSelector.java
index cc55c365..e874e8ae 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/TranslationAxisSelector.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/TranslationAxisSelector.java
@@ -1,6 +1,7 @@
package net.donnypz.displayentityutils.utils.gizmo.controls.selector;
import net.donnypz.displayentityutils.utils.gizmo.GizmoSpace;
+import net.donnypz.displayentityutils.utils.gizmo.controls.ControlType;
import net.donnypz.displayentityutils.utils.gizmo.controls.GizmoAxis;
import net.donnypz.displayentityutils.utils.gizmo.GizmoSessionImpl;
import net.donnypz.displayentityutils.utils.gizmo.controls.drag.Drag;
@@ -17,7 +18,7 @@ public class TranslationAxisSelector extends AxisSelector {
private float radius = 0.075f;
TranslationAxisSelector(GizmoAxis axis) {
- super(axis);
+ super(axis, ControlType.TRANSLATION);
this.localStart = axis.getDirections()[0]
.mul(0.1125f);
this.localEnd = axis.getDirections()[0];
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/TranslationPlaneSelector.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/TranslationPlaneSelector.java
index 345cb85c..bc0fb345 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/TranslationPlaneSelector.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/controls/selector/TranslationPlaneSelector.java
@@ -2,6 +2,7 @@
import net.donnypz.displayentityutils.utils.gizmo.GizmoSessionImpl;
import net.donnypz.displayentityutils.utils.gizmo.GizmoSpace;
+import net.donnypz.displayentityutils.utils.gizmo.controls.ControlType;
import net.donnypz.displayentityutils.utils.gizmo.controls.GizmoAxis;
import net.donnypz.displayentityutils.utils.gizmo.controls.drag.Drag;
import net.donnypz.displayentityutils.utils.gizmo.controls.drag.TranslationPlaneDrag;
@@ -17,7 +18,7 @@ public class TranslationPlaneSelector extends Selector {
private float size = 0.25f;
TranslationPlaneSelector(GizmoAxis axis) {
- super(axis);
+ super(axis, ControlType.TRANSLATION);
Vector3f[] axes = axis.getDirections();
Vector3f axis1 = axes[0];
Vector3f axis2 = axes[1];
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/util/GizmoMathUtil.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/util/GizmoMathUtil.java
index 95153af7..9ea6b945 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/util/GizmoMathUtil.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/util/GizmoMathUtil.java
@@ -23,4 +23,8 @@ public static void scale(Vector3f vector3f, float oldScale, float newScale) {
vector3f.y = (vector3f.y / oldScale) * newScale;
vector3f.z = (vector3f.z / oldScale) * newScale;
}
+
+ public static float getSnappedValue(float totalChange, float snapValue){
+ return Math.round(totalChange / snapValue) * snapValue;
+ }
}
diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/util/GizmoTitleUtil.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/util/GizmoTitleUtil.java
index 55a7bc14..bf414806 100644
--- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/util/GizmoTitleUtil.java
+++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/gizmo/util/GizmoTitleUtil.java
@@ -2,8 +2,11 @@
import net.donnypz.displayentityutils.utils.gizmo.GizmoSelectionMode;
import net.donnypz.displayentityutils.utils.gizmo.GizmoSpace;
+import net.donnypz.displayentityutils.utils.gizmo.Snap;
import net.donnypz.displayentityutils.utils.gizmo.TranslationMode;
+import net.donnypz.displayentityutils.utils.gizmo.controls.ControlType;
import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.title.Title;
import org.bukkit.entity.Player;
@@ -41,4 +44,40 @@ public static void showNewSelectionMode(Player player, GizmoSelectionMode select
showSubtitle(player,
MiniMessage.miniMessage().deserialize("Selection Mode: " + selectionMode.name()));
}
+
+ public static void showCannotChangeSelectionMode(Player player){
+ showSubtitle(player,
+ MiniMessage.miniMessage().deserialize("Cannot change selection mode for single entity"));
+ }
+
+ public static void showSnapStatus(Player player, boolean status){
+ showSubtitle(player, MiniMessage.miniMessage().deserialize(
+ "\uD83E\uDDF2 Snapping: "
+ +
+ (
+ status
+ ? "ENABLED"
+ : "DISABLED"
+ )
+ +
+ " \uD83E\uDDF2"
+ ));
+ }
+
+ public static void showSnapValue(Player player, Snap snap, ControlType controlType) {
+ show(
+ player,
+ Component.text(controlType.name(), NamedTextColor.LIGHT_PURPLE),
+ MiniMessage.miniMessage().deserialize(
+ "\uD83E\uDDF2 Snap Value: " + snap.getSnapValue()
+
+ + (
+ controlType == ControlType.ROTATION
+ ? " degrees "
+ : " blocks "
+ )
+ +
+ "\uD83E\uDDF2"
+ ));
+ }
}
diff --git a/plugin/src/main/resources/config.yml b/plugin/src/main/resources/config.yml
index ef6c63c0..0d30e1f5 100644
--- a/plugin/src/main/resources/config.yml
+++ b/plugin/src/main/resources/config.yml
@@ -10,7 +10,7 @@ mongodb:
enabled: false
host: "localhost"
port: 27017
- database: "DisplayEntityUtils"
+ database: "displayentityutils"
username: "user"
password: "password"
groupCollection: "saved_displays"
diff --git a/pom.xml b/pom.xml
index bd44d60e..b00eeb87 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
net.donnypz.displayentityutils
deu
- 3.7.1
+ 3.8.0
pom
DisplayEntityUtils