From 2fd69de12dade907bcc2232e62735d559cbca87d Mon Sep 17 00:00:00 2001
From: Stijn Bannink <stijnbannink40@gmail.com>
Date: Thu, 16 Mar 2023 19:24:31 +0100
Subject: [PATCH 1/3] Added 1.19.4 support

---
 pom.xml                                       |   4 +-
 .../com/bergerkiller/bukkit/common/README.md  |   4 +-
 .../common/map/color/MCSDBubbleFormat.java    | 168 ++++++++++++------
 .../mapreflectionapi/MapReflectionAPI.java    |   8 +-
 .../mapreflectionapi/api/MapWrapper.java      |   8 +-
 .../listeners/PacketListener.java             |   4 +-
 6 files changed, 128 insertions(+), 68 deletions(-)

diff --git a/pom.xml b/pom.xml
index c3b7699..8ef8ea4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
   ~ This file is part of MapReflectionAPI.
-  ~ Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
+  ~ Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
   ~
   ~ This program is free software: you can redistribute it and/or modify
   ~ it under the terms of the GNU General Public License as published by
@@ -161,7 +161,7 @@
         <dependency>
             <groupId>org.spigotmc</groupId>
             <artifactId>spigot-api</artifactId>
-            <version>1.19.3-R0.1-SNAPSHOT</version>
+            <version>1.19.4-R0.1-SNAPSHOT</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
diff --git a/src/main/java/com/bergerkiller/bukkit/common/README.md b/src/main/java/com/bergerkiller/bukkit/common/README.md
index ce9a09c..f64c20c 100644
--- a/src/main/java/com/bergerkiller/bukkit/common/README.md
+++ b/src/main/java/com/bergerkiller/bukkit/common/README.md
@@ -3,4 +3,6 @@
 These classes are from [BKCommonLib](https://github.com/bergerhealer/BKCommonLib). Only the required classes and methods
 are extracted.
 
-Current version: master#25ad90b702cabbbf632c40f6ed209241aee38a41 (1.19.1-v1 release)
\ No newline at end of file
+**Current version:** master#3fc97d5981742f43348cac1f752404f95daa6c07
+
+_Last update: 16-03-2023_
\ No newline at end of file
diff --git a/src/main/java/com/bergerkiller/bukkit/common/map/color/MCSDBubbleFormat.java b/src/main/java/com/bergerkiller/bukkit/common/map/color/MCSDBubbleFormat.java
index 663d18d..f011dcf 100644
--- a/src/main/java/com/bergerkiller/bukkit/common/map/color/MCSDBubbleFormat.java
+++ b/src/main/java/com/bergerkiller/bukkit/common/map/color/MCSDBubbleFormat.java
@@ -1,6 +1,6 @@
 /*
  * This file is part of MapReflectionAPI.
- * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
+ * Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -26,6 +26,7 @@ import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.function.IntPredicate;
 import java.util.zip.InflaterInputStream;
 
 /**
@@ -99,7 +100,7 @@ public class MCSDBubbleFormat extends MapColorSpaceData {
     private void initColors() {
         // Set initial cell colors
         this.clearRGBData();
-        for (Bubble cell : bubbles) {
+        for (MCSDBubbleFormat.Bubble cell : bubbles) {
             for (int z = cell.z_min; z <= cell.z_max; z++) {
                 this.set(cell.x, cell.y, z, cell.color);
             }
@@ -108,63 +109,120 @@ public class MCSDBubbleFormat extends MapColorSpaceData {
     }
 
     private void spreadColors() {
-        final boolean[] all_strands = new boolean[1 << 24];
-        for (int z = 0; z < 256; z++) {
-            System.arraycopy(this.strands[z], 0, all_strands, z << 16, 1 << 16);
-        }
-
-        boolean mode = false;
-        boolean hasChanges;
-        do {
-            hasChanges = false;
-
-            // Alternate the direction in which we process every step
-            // This prevents really slow filling when the direction is 'wrong'
-            // The below logic is partially based on the light fixing algorithm in Light Cleaner
-            final int index_end, index_delta;
-            int index;
-            byte color;
-            if (mode = !mode) {
-                index_delta = 1;
-                index = 0;
-                index_end = (1 << 24);
-            } else {
-                index_delta = -1;
-                index = (1 << 24) - 1;
-                index_end = 0;
-            }
-            do {
-                if (!all_strands[index]) {
-                    all_strands[index] = true;
-
-                    if ((index & 0xFF) < 0xFF) {
-                        if ((color = this.get(index + 1)) != 0) {
-                            this.set(index, color);
-                            hasChanges = true;
-                        } else if ((color = this.get(index)) != 0) {
-                            this.set(index + 1, color);
-                            hasChanges = true;
-                        } else {
-                            all_strands[index] = false; // retry
-                        }
-                    }
-
-                    if ((index & 0xFF00) < 0xFF00) {
-                        if ((color = this.get(index + 256)) != 0) {
-                            this.set(index, color);
-                            hasChanges = true;
-                        } else if ((color = this.get(index)) != 0) {
-                            this.set(index + 256, color);
-                            hasChanges = true;
-                        } else {
-                            all_strands[index] = false; // retry
-                        }
+        // As we'll be processing pretty much every element, allocate the full space (60MB)
+        // The range of the buffer we process shrinks as we spread
+        StrandBuffer buf;
+        {
+            final int[] buffer = new int[1 << 24];
+            int count = -1;
+            for (int z = 0; z < 256; z++) {
+                boolean[] layerStrands = this.strands[z];
+                int indexOffset = z << 16;
+                for (int i = 0; i < (1 << 16); i++) {
+                    if (!layerStrands[i]) {
+                        buffer[++count] = indexOffset + i;
                     }
                 }
-            } while ((index += index_delta) != index_end);
-        } while (hasChanges);
+            }
+            count++;
+            buf = new StrandBuffer(buffer, count);
+        }
+
+        // Process all until no more changes remain
+        buf.process(index -> {
+            byte color;
+
+            boolean col = ((index & 0xFF) < 0xFF);
+            boolean row = ((index & 0xFF00) < 0xFF00);
+
+            if (col && row) {
+                if ((color = this.get(index)) != 0) {
+                    this.set(index + 1, color);
+                    this.set(index + 256, color);
+                    return true;
+                } else if ((color = this.get(index + 1)) != 0) {
+                    this.set(index, color);
+                    this.set(index + 256, color);
+                    return true;
+                } else if ((color = this.get(index + 256)) != 0) {
+                    this.set(index, color);
+                    this.set(index + 1, color);
+                    return true;
+                }
+            } else if (col) {
+                if ((color = this.get(index)) != 0) {
+                    this.set(index + 1, color);
+                    return true;
+                } else if ((color = this.get(index + 1)) != 0) {
+                    this.set(index, color);
+                    return true;
+                }
+            } else if (row) {
+                if ((color = this.get(index)) != 0) {
+                    this.set(index + 256, color);
+                    return true;
+                } else if ((color = this.get(index + 256)) != 0) {
+                    this.set(index, color);
+                    return true;
+                }
+            }
+
+            return false;
+        });
     }
 
+    private static class StrandBuffer {
+        private final int[] buf;
+        private int start, end;
+
+        public StrandBuffer(int[] buffer, int count) {
+            this.buf = buffer;
+            this.start = 0;
+            this.end = count - 1;
+        }
+
+        public void process(IntPredicate strandIndexProc) {
+            while (forward(strandIndexProc) && reverse(strandIndexProc)) {
+                // Process alternating over and over until there are no more changes
+            }
+        }
+
+        public boolean forward(IntPredicate strandIndexProc) {
+            int[] buf = this.buf;
+            int writeIdx = start - 1;
+            int endIdx = end;
+            boolean changed = false;
+            for (int i = start; i <= endIdx; ++i) {
+                int strandIndex = buf[i];
+                if (strandIndexProc.test(strandIndex)) {
+                    changed = true;
+                } else {
+                    buf[++writeIdx] = strandIndex;
+                }
+            }
+            this.end = writeIdx;
+            return changed;
+        }
+
+        public boolean reverse(IntPredicate strandIndexProc) {
+            int[] buf = this.buf;
+            int writeIdx = end + 1;
+            int startIdx = start;
+            boolean changed = false;
+            for (int i = end; i >= startIdx; --i) {
+                int strandIndex = buf[i];
+                if (strandIndexProc.test(strandIndex)) {
+                    changed = true;
+                } else {
+                    buf[--writeIdx] = strandIndex;
+                }
+            }
+            this.start = writeIdx;
+            return changed;
+        }
+    }
+
+
     @Override
     public boolean equals(Object o) {
         if (o == this) {
diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/MapReflectionAPI.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/MapReflectionAPI.java
index 053b7f7..70b7368 100644
--- a/src/main/java/tech/sbdevelopment/mapreflectionapi/MapReflectionAPI.java
+++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/MapReflectionAPI.java
@@ -1,6 +1,6 @@
 /*
  * This file is part of MapReflectionAPI.
- * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
+ * Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -64,11 +64,11 @@ public class MapReflectionAPI extends JavaPlugin {
         instance = this;
 
         getLogger().info("----------------");
-        getLogger().info("MapReflectionAPI v" + getDescription().getVersion() + "");
-        getLogger().info("Made by © Copyright SBDevelopment 2022");
+        getLogger().info("MapReflectionAPI v" + getDescription().getVersion());
+        getLogger().info("Made by © Copyright SBDevelopment 2023");
 
         if (!ReflectionUtil.supports(12)) {
-            getLogger().severe("MapReflectionAPI only supports Minecraft 1.12.x - 1.19.x!");
+            getLogger().severe("MapReflectionAPI only supports Minecraft 1.12 - 1.19.4!");
             Bukkit.getPluginManager().disablePlugin(this);
             return;
         }
diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java
index d572ec4..8f7c270 100644
--- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java
+++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java
@@ -1,6 +1,6 @@
 /*
  * This file is part of MapReflectionAPI.
- * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
+ * Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -168,7 +168,7 @@ public class MapWrapper extends AbstractMapWrapper {
 
             String inventoryMenuName;
             if (ReflectionUtil.supports(19)) { //1.19
-                inventoryMenuName = "bT";
+                inventoryMenuName = ReflectionUtil.VER_MINOR == 4 ? "bO" : "bT"; //1.19.4 = bO, >= 1.19.3 = bT
             } else if (ReflectionUtil.supports(18)) { //1.18
                 inventoryMenuName = ReflectionUtil.VER_MINOR == 1 ? "bV" : "bU"; //1.18.1 = ap, 1.18(.2) = ao
             } else if (ReflectionUtil.supports(17)) { //1.17, same as 1.18(.2)
@@ -322,8 +322,8 @@ public class MapWrapper extends AbstractMapWrapper {
             Object nmsStack = createCraftItemStack(stack, mapId);
 
             String dataWatcherObjectName;
-            if (ReflectionUtil.supports(19)) { //1.19, same as 1.17 and 1.18(.2)
-                dataWatcherObjectName = "ao";
+            if (ReflectionUtil.supports(19)) { //1.19
+                dataWatcherObjectName = ReflectionUtil.VER_MINOR == 4 ? "g" : "ao"; //1.19.4 = g, >= 1.19.3 = ao
             } else if (ReflectionUtil.supports(18)) { //1.18
                 dataWatcherObjectName = ReflectionUtil.VER_MINOR == 1 ? "ap" : "ao"; //1.18.1 = ap, 1.18(.2) = ao
             } else if (ReflectionUtil.supports(17)) { //1.17
diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java
index c26be7c..44a92b5 100644
--- a/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java
+++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java
@@ -1,6 +1,6 @@
 /*
  * This file is part of MapReflectionAPI.
- * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
+ * Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -144,7 +144,7 @@ public class PacketListener implements Listener {
         Object playerHandle = getHandle(player);
         Object playerConnection = getDeclaredField(playerHandle, ReflectionUtil.supports(17) ? "b" : "playerConnection"); //1.17 = b, 1.16 = playerConnection
         Object networkManager = getDeclaredField(playerConnection, ReflectionUtil.supports(19) ? "b" : ReflectionUtil.supports(17) ? "a" : "networkManager"); //1.19 = b, 1.18 = a, 1.16 = networkManager
-        return (Channel) getDeclaredField(networkManager, ReflectionUtil.supports(18) ? "m" : ReflectionUtil.supports(17) ? "k" : "channel"); //1.18 = m, 1.17 = k, 1.16 = channel
+        return (Channel) getDeclaredField(networkManager, ReflectionUtil.supports(19, 4) ? "h" : ReflectionUtil.supports(18) ? "m" : ReflectionUtil.supports(17) ? "k" : "channel"); //1.19.4 = h, >= 1.19.3 & 1.18 = m, 1.17 = k, 1.16 = channel
     }
 
     private Vector vec3DToVector(Object vec3d) {
-- 
2.45.3


From 9e614af2fbbce017e552da284d3eba01d1f79f4a Mon Sep 17 00:00:00 2001
From: Stijn Bannink <stijnbannink40@gmail.com>
Date: Thu, 16 Mar 2023 19:38:43 +0100
Subject: [PATCH 2/3] Small fixes

---
 .../tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java | 4 ++--
 .../mapreflectionapi/listeners/PacketListener.java          | 6 +++---
 .../mapreflectionapi/utils/ReflectionUtil.java              | 5 ++++-
 3 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java
index 8f7c270..d3c6ad8 100644
--- a/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java
+++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/api/MapWrapper.java
@@ -168,7 +168,7 @@ public class MapWrapper extends AbstractMapWrapper {
 
             String inventoryMenuName;
             if (ReflectionUtil.supports(19)) { //1.19
-                inventoryMenuName = ReflectionUtil.VER_MINOR == 4 ? "bO" : "bT"; //1.19.4 = bO, >= 1.19.3 = bT
+                inventoryMenuName = ReflectionUtil.VER_MINOR == 3 ? "bO" : "bT"; //1.19.4 = bO, >= 1.19.3 = bT
             } else if (ReflectionUtil.supports(18)) { //1.18
                 inventoryMenuName = ReflectionUtil.VER_MINOR == 1 ? "bV" : "bU"; //1.18.1 = ap, 1.18(.2) = ao
             } else if (ReflectionUtil.supports(17)) { //1.17, same as 1.18(.2)
@@ -323,7 +323,7 @@ public class MapWrapper extends AbstractMapWrapper {
 
             String dataWatcherObjectName;
             if (ReflectionUtil.supports(19)) { //1.19
-                dataWatcherObjectName = ReflectionUtil.VER_MINOR == 4 ? "g" : "ao"; //1.19.4 = g, >= 1.19.3 = ao
+                dataWatcherObjectName = ReflectionUtil.VER_MINOR == 3 ? "g" : "ao"; //1.19.4 = g, >= 1.19.3 = ao
             } else if (ReflectionUtil.supports(18)) { //1.18
                 dataWatcherObjectName = ReflectionUtil.VER_MINOR == 1 ? "ap" : "ao"; //1.18.1 = ap, 1.18(.2) = ao
             } else if (ReflectionUtil.supports(17)) { //1.17
diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java
index 44a92b5..3c872c4 100644
--- a/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java
+++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/listeners/PacketListener.java
@@ -115,7 +115,7 @@ public class PacketListener implements Listener {
                 } else if (packet.getClass().isAssignableFrom(packetPlayInSetCreativeSlotClass)) {
                     Object packetPlayInSetCreativeSlot = packetPlayInSetCreativeSlotClass.cast(packet);
 
-                    int slot = (int) ReflectionUtil.callDeclaredMethod(packetPlayInSetCreativeSlot, ReflectionUtil.supports(13) ? "b" : "a"); //1.13 = b, 1.12 = a
+                    int slot = (int) ReflectionUtil.callDeclaredMethod(packetPlayInSetCreativeSlot, ReflectionUtil.supports(19, 3) ? "a" : ReflectionUtil.supports(13) ? "b" : "a"); //1.19.4 = a, 1.19.3 - 1.13 = b, 1.12 = a
                     Object nmsStack = ReflectionUtil.callDeclaredMethod(packetPlayInSetCreativeSlot, ReflectionUtil.supports(18) ? "c" : "getItemStack"); //1.18 = c, 1.17 = getItemStack
                     ItemStack craftStack = (ItemStack) ReflectionUtil.callMethod(craftStackClass, "asBukkitCopy", nmsStack);
 
@@ -143,8 +143,8 @@ public class PacketListener implements Listener {
     private Channel getChannel(Player player) {
         Object playerHandle = getHandle(player);
         Object playerConnection = getDeclaredField(playerHandle, ReflectionUtil.supports(17) ? "b" : "playerConnection"); //1.17 = b, 1.16 = playerConnection
-        Object networkManager = getDeclaredField(playerConnection, ReflectionUtil.supports(19) ? "b" : ReflectionUtil.supports(17) ? "a" : "networkManager"); //1.19 = b, 1.18 = a, 1.16 = networkManager
-        return (Channel) getDeclaredField(networkManager, ReflectionUtil.supports(19, 4) ? "h" : ReflectionUtil.supports(18) ? "m" : ReflectionUtil.supports(17) ? "k" : "channel"); //1.19.4 = h, >= 1.19.3 & 1.18 = m, 1.17 = k, 1.16 = channel
+        Object networkManager = getDeclaredField(playerConnection, ReflectionUtil.supports(19, 3) ? "h" : ReflectionUtil.supports(19) ? "b" : ReflectionUtil.supports(17) ? "a" : "networkManager"); //1.19.4 = h, >= 1.19.3 = b, 1.18 = a, 1.16 = networkManager
+        return (Channel) getDeclaredField(networkManager, ReflectionUtil.supports(18) ? "m" : ReflectionUtil.supports(17) ? "k" : "channel"); //1.19 & 1.18 = m, 1.17 = k, 1.16 = channel
     }
 
     private Vector vec3DToVector(Object vec3d) {
diff --git a/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtil.java b/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtil.java
index 324a27f..109687b 100644
--- a/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtil.java
+++ b/src/main/java/tech/sbdevelopment/mapreflectionapi/utils/ReflectionUtil.java
@@ -1,6 +1,6 @@
 /*
  * This file is part of MapReflectionAPI.
- * Copyright (c) 2022 inventivetalent / SBDevelopment - All Rights Reserved
+ * Copyright (c) 2022-2023 inventivetalent / SBDevelopment - All Rights Reserved
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -187,6 +187,9 @@ public class ReflectionUtil {
 
     /**
      * Checks whether the server version is equal or greater than the given version.
+     * <p>
+     * PAY ATTENTION! The minor version is based on the NMS version.
+     * This means that v1_19_R3 has major version 19 and minor version 3.
      *
      * @param major the major version to compare the server version with.
      * @param minor the minor version to compare the server version with.
-- 
2.45.3


From 03c487532e0fadb215b57d315cd9a7f9f394da6a Mon Sep 17 00:00:00 2001
From: Stijn Bannink <stijnbannink40@gmail.com>
Date: Thu, 16 Mar 2023 19:39:08 +0100
Subject: [PATCH 3/3] v1.4.3 Release

---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 8ef8ea4..d8c536a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,7 +24,7 @@
 
     <groupId>tech.sbdevelopment</groupId>
     <artifactId>MapReflectionAPI</artifactId>
-    <version>1.4.2</version>
+    <version>1.4.3</version>
     <packaging>jar</packaging>
 
     <name>MapReflectionAPI</name>
-- 
2.45.3