├── .gitignore ├── API ├── pom.xml └── src │ └── main │ └── java │ └── be4rjp │ └── parallel │ ├── ParallelAPI.java │ ├── ParallelChunk.java │ ├── ParallelUniverse.java │ ├── ParallelWorld.java │ ├── nms │ ├── INMSHandler.java │ └── IPacketHandler.java │ ├── player │ └── ParallelPlayer.java │ ├── structure │ └── StructureData.java │ └── util │ ├── BlockPosition3i.java │ ├── ChunkPosition.java │ ├── SectionLevelArray.java │ ├── SectionTypeArray.java │ └── ThreadsafeIteration.java ├── Plugin ├── pom.xml └── src │ └── main │ ├── java │ └── be4rjp │ │ └── parallel │ │ ├── Config.java │ │ ├── EventListener.java │ │ ├── Parallel.java │ │ ├── chiyogami │ │ ├── ChiyogamiBridge.java │ │ └── ChiyogamiManager.java │ │ ├── cinema4c │ │ ├── BridgeManager.java │ │ └── C4CBridge.java │ │ ├── command │ │ └── parallelCommandExecutor.java │ │ ├── enums │ │ └── UpdatePacketType.java │ │ ├── gui │ │ └── UniverseGUI.java │ │ ├── impl │ │ ├── ImplParallelAPI.java │ │ ├── ImplParallelChunk.java │ │ ├── ImplParallelPlayer.java │ │ ├── ImplParallelUniverse.java │ │ └── ImplParallelWorld.java │ │ ├── nms │ │ ├── NMSManager.java │ │ └── PacketHandler.java │ │ ├── structure │ │ ├── ImplStructureData.java │ │ └── ParallelStructure.java │ │ └── util │ │ ├── ChunkUtil.java │ │ ├── RegionBlocks.java │ │ └── TaskHandler.java │ └── resources │ ├── config.yml │ └── plugin.yml ├── README.md ├── pom.xml ├── v1_15_R1 ├── pom.xml └── src │ └── main │ └── java │ └── be4rjp │ └── parallel │ └── v1_15_R1 │ ├── BlockChangePacketHandler.java │ ├── FlyPacketHandler.java │ ├── LightUpdatePacketHandler.java │ ├── MapChunkPacketHandler.java │ ├── MultiBlockChangePacketHandler.java │ └── NMSHandler.java └── v1_16_R3 ├── pom.xml └── src └── main └── java └── be4rjp └── parallel └── v1_16_R3 ├── BlockChangePacketHandler.java ├── FlyPacketHandler.java ├── LightUpdatePacketHandler.java ├── MapChunkPacketHandler.java ├── MultiBlockChangePacketHandler.java └── NMSHandler.java /.gitignore: -------------------------------------------------------------------------------- 1 | # User-specific stuff 2 | .idea/ 3 | 4 | *.iml 5 | *.ipr 6 | *.iws 7 | 8 | # IntelliJ 9 | out/ 10 | 11 | # Compiled class file 12 | *.class 13 | 14 | # Log file 15 | *.log 16 | 17 | # BlueJ files 18 | *.ctxt 19 | 20 | # Package Files # 21 | *.jar 22 | *.war 23 | *.nar 24 | *.ear 25 | *.zip 26 | *.tar.gz 27 | *.rar 28 | 29 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 30 | hs_err_pid* 31 | 32 | *~ 33 | 34 | # temporary files which can be created if a process still has a handle open of a deleted file 35 | .fuse_hidden* 36 | 37 | # KDE directory preferences 38 | .directory 39 | 40 | # Linux trash folder which might appear on any partition or disk 41 | .Trash-* 42 | 43 | # .nfs files are created when an open file is removed but is still being accessed 44 | .nfs* 45 | 46 | # General 47 | .DS_Store 48 | .AppleDouble 49 | .LSOverride 50 | 51 | # Icon must end with two \r 52 | Icon 53 | 54 | # Thumbnails 55 | ._* 56 | 57 | # Files that might appear in the root of a volume 58 | .DocumentRevisions-V100 59 | .fseventsd 60 | .Spotlight-V100 61 | .TemporaryItems 62 | .Trashes 63 | .VolumeIcon.icns 64 | .com.apple.timemachine.donotpresent 65 | 66 | # Directories potentially created on remote AFP share 67 | .AppleDB 68 | .AppleDesktop 69 | Network Trash Folder 70 | Temporary Items 71 | .apdisk 72 | 73 | # Windows thumbnail cache files 74 | Thumbs.db 75 | Thumbs.db:encryptable 76 | ehthumbs.db 77 | ehthumbs_vista.db 78 | 79 | # Dump file 80 | *.stackdump 81 | 82 | # Folder config file 83 | [Dd]esktop.ini 84 | 85 | # Recycle Bin used on file shares 86 | $RECYCLE.BIN/ 87 | 88 | # Windows Installer files 89 | *.cab 90 | *.msi 91 | *.msix 92 | *.msm 93 | *.msp 94 | 95 | # Windows shortcuts 96 | *.lnk 97 | 98 | target/ 99 | 100 | pom.xml.tag 101 | pom.xml.releaseBackup 102 | pom.xml.versionsBackup 103 | pom.xml.next 104 | 105 | release.properties 106 | dependency-reduced-pom.xml 107 | buildNumber.properties 108 | .mvn/timing.properties 109 | .mvn/wrapper/maven-wrapper.jar 110 | .flattened-pom.xml 111 | 112 | # Common working directory 113 | run/ 114 | -------------------------------------------------------------------------------- /API/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | parallel_api 5 | jar 6 | 2.0.3 7 | be4rjp 8 | 9 | 10 | 11 | internal.repo 12 | Temporary Staging Repository 13 | file://${project.build.directory}/mvn-repo 14 | 15 | 16 | 17 | 18 | 1.8 19 | UTF-8 20 | github 21 | 22 | 23 | 24 | 25 | 26 | org.apache.maven.plugins 27 | maven-compiler-plugin 28 | 3.8.1 29 | 30 | ${java.version} 31 | ${java.version} 32 | 33 | 34 | 35 | org.apache.maven.plugins 36 | maven-javadoc-plugin 37 | 38 | 39 | package 40 | 41 | jar 42 | 43 | 44 | 45 | 46 | 47 | maven-deploy-plugin 48 | 2.8.2 49 | 50 | internal.repo::default::file://${project.build.directory}/mvn-repo 51 | 52 | 53 | 54 | com.github.github 55 | site-maven-plugin 56 | 0.12 57 | 58 | Maven artifacts for ${project.version} 59 | true 60 | true 61 | ${project.build.directory}/mvn-repo 62 | refs/heads/mvn-repo 63 | **/* 64 | Parallel 65 | Be4rJP 66 | Be4rJP 67 | 68 | 69 | 70 | 71 | site 72 | 73 | deploy 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | spigotmc-repo 83 | https://hub.spigotmc.org/nexus/content/repositories/snapshots/ 84 | 85 | 86 | sonatype 87 | https://oss.sonatype.org/content/groups/public/ 88 | 89 | 90 | minecraft-libraries 91 | Minecraft Libraries 92 | https://libraries.minecraft.net 93 | 94 | 95 | enginehub-maven 96 | https://maven.enginehub.org/repo/ 97 | 98 | 99 | jitpack.io 100 | https://jitpack.io 101 | 102 | 103 | 104 | 105 | 106 | org.spigotmc 107 | spigot-api 108 | 1.15.2-R0.1-SNAPSHOT 109 | provided 110 | 111 | 112 | io.netty 113 | netty-all 114 | 4.1.59.Final 115 | provided 116 | 117 | 118 | com.mojang 119 | datafixerupper 120 | 1.0.20 121 | provided 122 | 123 | 124 | org.jetbrains 125 | annotations 126 | RELEASE 127 | compile 128 | 129 | 130 | fastutil 131 | fastutil 132 | 5.0.9 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /API/src/main/java/be4rjp/parallel/ParallelAPI.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel; 2 | 3 | import be4rjp.parallel.player.ParallelPlayer; 4 | import org.bukkit.entity.Player; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | import java.util.Collection; 9 | import java.util.Set; 10 | 11 | public abstract class ParallelAPI { 12 | 13 | //API instance 14 | private static ParallelAPI instance; 15 | 16 | /** 17 | * Get api instance. 18 | * @return ParallelAPI 19 | */ 20 | public static @NotNull ParallelAPI getInstance() {return instance;} 21 | 22 | /** 23 | * Create universe if absent. 24 | * @param universeName Name of a universe 25 | * @return ParallelUniverse 26 | */ 27 | public abstract @NotNull ParallelUniverse createUniverse(String universeName); 28 | 29 | /** 30 | * Get universe. 31 | * @param universeName Name of a universe 32 | * @return If the Universe with the specified name does not exist, return null. 33 | */ 34 | public abstract @Nullable ParallelUniverse getUniverse(String universeName); 35 | 36 | /** 37 | * Remove universe with the specified name. 38 | * @param universeName Name of a universe. 39 | */ 40 | public abstract void removeUniverse(String universeName); 41 | 42 | /** 43 | * Get all universe name. 44 | * @return All universe name 45 | */ 46 | public abstract Set getAllUniverseName(); 47 | 48 | /** 49 | * Get all universe. 50 | * @return All universe 51 | */ 52 | public abstract Collection getAllUniverse(); 53 | 54 | /** 55 | * Get ParallelPlayer 56 | * @return ParallelPlayer 57 | */ 58 | public @Nullable ParallelPlayer getParallelPlayer(Player player){return ParallelPlayer.getParallelPlayer(player);} 59 | 60 | } 61 | -------------------------------------------------------------------------------- /API/src/main/java/be4rjp/parallel/ParallelChunk.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel; 2 | 3 | import be4rjp.parallel.util.SectionLevelArray; 4 | import be4rjp.parallel.util.SectionTypeArray; 5 | import org.bukkit.Material; 6 | import org.bukkit.block.data.BlockData; 7 | import org.bukkit.entity.Player; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | public interface ParallelChunk { 12 | 13 | /** 14 | * Get the ParallelWorld in which this chunk is stored. 15 | * @return ParallelWorld 16 | */ 17 | @NotNull ParallelWorld getWorld(); 18 | 19 | /** 20 | * Get coordinate(Chunk X) 21 | * @return chunkX 22 | */ 23 | int getChunkX(); 24 | 25 | /** 26 | * Get coordinate(Chunk Z) 27 | * @return chunkZ 28 | */ 29 | int getChunkZ(); 30 | 31 | /** 32 | * Set the material for a block in this chunk. 33 | * @param blockX Block coordinate X 34 | * @param blockY Block coordinate Y 35 | * @param blockZ Block coordinate Z 36 | * @param material Bukkit material 37 | */ 38 | void setType(int blockX, int blockY, int blockZ, Material material); 39 | 40 | /** 41 | * Get the material for a block in this chunk. 42 | * @param blockX Block coordinate X 43 | * @param blockY Block coordinate Y 44 | * @param blockZ Block coordinate Z 45 | * @return Material for the block 46 | */ 47 | @Nullable Material getType(int blockX, int blockY, int blockZ); 48 | 49 | /** 50 | * Set the data for a block in this chunk. 51 | * @param blockX Block coordinate X 52 | * @param blockY Block coordinate Y 53 | * @param blockZ Block coordinate Z 54 | * @param blockData Bukkit BlockData 55 | */ 56 | void setBlockData(int blockX, int blockY, int blockZ, BlockData blockData); 57 | 58 | /** 59 | * Get the data for a block in this chunk. 60 | * @param blockX Block coordinate X 61 | * @param blockY Block coordinate Y 62 | * @param blockZ Block coordinate Z 63 | * @return BlockData for the block 64 | */ 65 | @Nullable BlockData getBlockData(int blockX, int blockY, int blockZ); 66 | 67 | /** 68 | * Get the nms IBlockData for a block in this chunk. 69 | * @param blockX Block coordinate X 70 | * @param blockY Block coordinate Y 71 | * @param blockZ Block coordinate Z 72 | * @return BlockData for the block 73 | */ 74 | @Nullable Object getNMSBlockData(int blockX, int blockY, int blockZ); 75 | 76 | /** 77 | * Remove the data for a block in this chunk. 78 | * @param blockX Block coordinate X 79 | * @param blockY Block coordinate Y 80 | * @param blockZ Block coordinate Z 81 | */ 82 | void removeBlockData(int blockX, int blockY, int blockZ); 83 | 84 | /** 85 | * Set block light level for a block in this chunk. 86 | * @param blockX Block coordinate X 87 | * @param blockY Block coordinate Y 88 | * @param blockZ Block coordinate Z 89 | * @param level Light level 90 | */ 91 | void setBlockLightLevel(int blockX, int blockY, int blockZ, int level); 92 | 93 | /** 94 | * Set block light level for a block in this chunk. 95 | * @param blockX Block coordinate X 96 | * @param blockY Block coordinate Y 97 | * @param blockZ Block coordinate Z 98 | * @return Block light 99 | */ 100 | int getBlockLightLevel(int blockX, int blockY, int blockZ); 101 | 102 | /** 103 | * Remove block light level for a block in this chunk. 104 | * @param blockX Block coordinate X 105 | * @param blockY Block coordinate Y 106 | * @param blockZ Block coordinate Z 107 | */ 108 | void removeBlockLight(int blockX, int blockY, int blockZ); 109 | 110 | /** 111 | * Set sky light level for a block in this chunk. 112 | * @param blockX Block coordinate X 113 | * @param blockY Block coordinate Y 114 | * @param blockZ Block coordinate Z 115 | * @param level Light level 116 | */ 117 | void setSkyLightLevel(int blockX, int blockY, int blockZ, int level); 118 | 119 | /** 120 | * Set sky light level for a block in this chunk. 121 | * @param blockX Block coordinate X 122 | * @param blockY Block coordinate Y 123 | * @param blockZ Block coordinate Z 124 | * @return Sky light 125 | */ 126 | int getSkyLightLevel(int blockX, int blockY, int blockZ); 127 | 128 | /** 129 | * Remove sky light level for a block in this chunk. 130 | * @param blockX Block coordinate X 131 | * @param blockY Block coordinate Y 132 | * @param blockZ Block coordinate Z 133 | */ 134 | void removeSkyLight(int blockX, int blockY, int blockZ); 135 | 136 | /** 137 | * Get block light nibble array. 138 | * @param sectionY Chunk section index. 139 | * @return SectionLevelArray 140 | */ 141 | @Nullable SectionLevelArray getBlockLightSectionLevelArray(int sectionY); 142 | 143 | /** 144 | * Get sky light nibble array. 145 | * @param sectionY Chunk section index. 146 | * @return SectionLevelArray 147 | */ 148 | @Nullable SectionLevelArray getSkyLightSectionLevelArray(int sectionY); 149 | 150 | /** 151 | * Get all block data. 152 | * @param sectionY Chunk section index. 153 | * @return SectionTypeArray 154 | */ 155 | @Nullable SectionTypeArray getSectionTypeArray(int sectionY); 156 | 157 | /** 158 | * Gets whether the specified block is set with data. 159 | * @param blockX Block coordinate X 160 | * @param blockY Block coordinate Y 161 | * @param blockZ Block coordinate Z 162 | * @return Whether the specified block is set with data. 163 | */ 164 | boolean hasBlockData(int blockX, int blockY, int blockZ); 165 | 166 | /** 167 | * Gets whether the specified block is set with block light. 168 | * @param blockX Block coordinate X 169 | * @param blockY Block coordinate Y 170 | * @param blockZ Block coordinate Z 171 | * @return Whether the specified block is set with block light. 172 | */ 173 | boolean hasBlockLight(int blockX, int blockY, int blockZ); 174 | 175 | /** 176 | * Gets whether the specified block is set with sky light. 177 | * @param blockX Block coordinate X 178 | * @param blockY Block coordinate Y 179 | * @param blockZ Block coordinate Z 180 | * @return Whether the specified block is set with sky light. 181 | */ 182 | boolean hasSkyLight(int blockX, int blockY, int blockZ); 183 | 184 | /** 185 | * Sends the data of all blocks set in this chunk to the players. 186 | * @param player Player to sen 187 | */ 188 | void sendUpdate(Player player); 189 | 190 | @Nullable Object getCachedMapChunkPacket(); 191 | 192 | @Nullable Object getCachedLightUpdatePacket(); 193 | 194 | void setMapChunkPacketCache(Object packet); 195 | 196 | void setLightUpdatePacketCache(Object packet); 197 | } 198 | -------------------------------------------------------------------------------- /API/src/main/java/be4rjp/parallel/ParallelUniverse.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel; 2 | 3 | import be4rjp.parallel.player.ParallelPlayer; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.Collection; 7 | import java.util.Set; 8 | 9 | /** 10 | * If you set an instance of a class that implements this interface as a player, the block changes will be applied. 11 | */ 12 | public interface ParallelUniverse { 13 | 14 | /** 15 | * Get name of this universe. 16 | * @return Universe name. 17 | */ 18 | @NotNull String getName(); 19 | 20 | /** 21 | * Get ParallelWorld from the world name. 22 | * @param worldName Name of the world. 23 | * @return ParallelWorld 24 | */ 25 | @NotNull ParallelWorld getWorld(String worldName); 26 | 27 | /** 28 | * Add a player to this universe. 29 | * @param player Player to add 30 | */ 31 | void addPlayer(@NotNull ParallelPlayer player); 32 | 33 | /** 34 | * Remove a player to this universe. 35 | * @param player A player to remove 36 | */ 37 | void removePlayer(@NotNull ParallelPlayer player); 38 | 39 | /** 40 | * Get all players in this universe. 41 | * @return All players in this universe 42 | */ 43 | Set getResidents(); 44 | 45 | /** 46 | * Get all world in this universe. 47 | * @return All world. 48 | */ 49 | Collection getAllWorld(); 50 | 51 | /** 52 | * Add a diff for the specified universe. 53 | * @param universe Universe 54 | */ 55 | void addDiffs(ParallelUniverse universe); 56 | } 57 | -------------------------------------------------------------------------------- /API/src/main/java/be4rjp/parallel/ParallelWorld.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel; 2 | 3 | import be4rjp.parallel.util.BlockPosition3i; 4 | import org.bukkit.Material; 5 | import org.bukkit.block.data.BlockData; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | import java.util.Collection; 10 | import java.util.Set; 11 | 12 | public interface ParallelWorld { 13 | 14 | /** 15 | * Get name of this world. 16 | * @return World name. 17 | */ 18 | String getName(); 19 | 20 | /** 21 | * Get the ParallelUniverse in which this world is stored. 22 | * @return ParallelUniverse 23 | */ 24 | @NotNull ParallelUniverse getParallelUniverse(); 25 | 26 | /** 27 | * Set the material for a block in this world. 28 | * @param blockX Block coordinate X 29 | * @param blockY Block coordinate Y 30 | * @param blockZ Block coordinate Z 31 | * @param material Bukkit material 32 | */ 33 | void setType(int blockX, int blockY, int blockZ, Material material); 34 | 35 | /** 36 | * Get the material for a block in this world. 37 | * @param blockX Block coordinate X 38 | * @param blockY Block coordinate Y 39 | * @param blockZ Block coordinate Z 40 | * @return Material for the block 41 | */ 42 | @Nullable Material getType(int blockX, int blockY, int blockZ); 43 | 44 | /** 45 | * Set the data for a block in this world. 46 | * @param blockX Block coordinate X 47 | * @param blockY Block coordinate Y 48 | * @param blockZ Block coordinate Z 49 | * @param blockData Bukkit BlockData 50 | */ 51 | void setBlockData(int blockX, int blockY, int blockZ, BlockData blockData); 52 | 53 | /** 54 | * Get the data for a block in this world. 55 | * @param blockX Block coordinate X 56 | * @param blockY Block coordinate Y 57 | * @param blockZ Block coordinate Z 58 | * @return BlockData for the block 59 | */ 60 | @Nullable BlockData getBlockData(int blockX, int blockY, int blockZ); 61 | 62 | /** 63 | * Get the nms IBlockData for a block in this world. 64 | * @param blockX Block coordinate X 65 | * @param blockY Block coordinate Y 66 | * @param blockZ Block coordinate Z 67 | * @return BlockData for the block 68 | */ 69 | @Nullable Object getNMSBlockData(int blockX, int blockY, int blockZ); 70 | 71 | /** 72 | * Remove the data for a block in this world. 73 | * @param blockX Block coordinate X 74 | * @param blockY Block coordinate Y 75 | * @param blockZ Block coordinate Z 76 | */ 77 | void removeBlockData(int blockX, int blockY, int blockZ); 78 | 79 | /** 80 | * Set block light level for a block in this world. 81 | * @param blockX Block coordinate X 82 | * @param blockY Block coordinate Y 83 | * @param blockZ Block coordinate Z 84 | * @param level Light level 85 | */ 86 | void setBlockLightLevel(int blockX, int blockY, int blockZ, int level); 87 | 88 | /** 89 | * Get block light level for a block in this world. 90 | * @param blockX Block coordinate X 91 | * @param blockY Block coordinate Y 92 | * @param blockZ Block coordinate Z 93 | * @return Block light level for a block in this world. 94 | */ 95 | int getBlockLightLevel(int blockX, int blockY, int blockZ); 96 | 97 | /** 98 | * Remove block light level for a block in this world. 99 | * @param blockX Block coordinate X 100 | * @param blockY Block coordinate Y 101 | * @param blockZ Block coordinate Z 102 | */ 103 | void removeBlockLight(int blockX, int blockY, int blockZ); 104 | 105 | /** 106 | * Set sky light level for a block in this world. 107 | * @param blockX Block coordinate X 108 | * @param blockY Block coordinate Y 109 | * @param blockZ Block coordinate Z 110 | * @param level Light level 111 | */ 112 | void setSkyLightLevel(int blockX, int blockY, int blockZ, int level); 113 | 114 | /** 115 | * Get sky light level for a block in this world. 116 | * @param blockX Block coordinate X 117 | * @param blockY Block coordinate Y 118 | * @param blockZ Block coordinate Z 119 | * @return Sky light level for a block in this world. 120 | */ 121 | int getSkyLightLevel(int blockX, int blockY, int blockZ); 122 | 123 | /** 124 | * Remove sky light level for a block in this world. 125 | * @param blockX Block coordinate X 126 | * @param blockY Block coordinate Y 127 | * @param blockZ Block coordinate Z 128 | */ 129 | void removeSkyLight(int blockX, int blockY, int blockZ); 130 | 131 | /** 132 | * Gets whether the specified block is set with data. 133 | * @param blockX Block coordinate X 134 | * @param blockY Block coordinate Y 135 | * @param blockZ Block coordinate Z 136 | * @return Whether the specified block is set with data. 137 | */ 138 | boolean hasBlockData(int blockX, int blockY, int blockZ); 139 | 140 | /** 141 | * Gets whether the specified block is set with block light. 142 | * @param blockX Block coordinate X 143 | * @param blockY Block coordinate Y 144 | * @param blockZ Block coordinate Z 145 | * @return Whether the specified block is set with block light. 146 | */ 147 | boolean hasBlockLight(int blockX, int blockY, int blockZ); 148 | 149 | /** 150 | * Gets whether the specified block is set with sky light. 151 | * @param blockX Block coordinate X 152 | * @param blockY Block coordinate Y 153 | * @param blockZ Block coordinate Z 154 | * @return Whether the specified block is set with sky light. 155 | */ 156 | boolean hasSkyLight(int blockX, int blockY, int blockZ); 157 | 158 | /** 159 | * Get a chunk that exist in this world. 160 | * @param chunkX Chunk coordinate X 161 | * @param chunkZ Chunk coordinate Z 162 | * @return ParallelChunk 163 | */ 164 | @Nullable ParallelChunk getChunk(int chunkX, int chunkZ); 165 | 166 | /** 167 | * Send block update packet. 168 | * @param blockX Block coordinate X 169 | * @param blockY Block coordinate Y 170 | * @param blockZ Block coordinate Z 171 | */ 172 | void sendBlockUpdate(int blockX, int blockY, int blockZ); 173 | 174 | /** 175 | * Send multi block change packet to the players. 176 | * @param blocks Update block positions 177 | */ 178 | void sendMultiBlockUpdate(Set blocks); 179 | 180 | /** 181 | * Get all chunks in this world. 182 | * @return All chunks 183 | */ 184 | Collection getAllChunk(); 185 | 186 | } 187 | -------------------------------------------------------------------------------- /API/src/main/java/be4rjp/parallel/nms/INMSHandler.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.nms; 2 | 3 | import be4rjp.parallel.ParallelChunk; 4 | import be4rjp.parallel.ParallelWorld; 5 | import be4rjp.parallel.util.BlockPosition3i; 6 | import io.netty.channel.Channel; 7 | import org.bukkit.block.data.BlockData; 8 | import org.bukkit.entity.Player; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | import java.util.Set; 12 | 13 | public interface INMSHandler { 14 | 15 | Channel getChannel(Player player); 16 | 17 | void sendPacket(Player player, Object packet); 18 | 19 | Object getIBlockDataByCombinedId(int id); 20 | 21 | int getCombinedIdByIBlockData(Object iBlockData); 22 | 23 | Object getIBlockData(BlockData blockData); 24 | 25 | BlockData getBukkitBlockData(Object iBlockData); 26 | 27 | Object[] createIBlockDataArray(int length); 28 | 29 | boolean isMapChunkPacket(Object packet); 30 | 31 | boolean isMultiBlockChangePacket(Object packet); 32 | 33 | boolean isBlockChangePacket(Object packet); 34 | 35 | boolean isLightUpdatePacket(Object packet); 36 | 37 | boolean isFlyPacket(Object packet); 38 | 39 | @Nullable Object createBlockChangePacket(ParallelWorld parallelWorld, int blockX, int blockY, int blockZ); 40 | 41 | Set createMultiBlockChangePacket(ParallelWorld parallelWorld, Set blocks); 42 | 43 | void sendChunkMultiBlockChangeUpdatePacket(Player player, ParallelChunk parallelChunk); 44 | 45 | @Nullable Object createLightUpdatePacketAtPrimaryThread(ParallelChunk parallelChunk); 46 | 47 | void sendClearChunkMultiBlockChangePacketAtPrimaryThread(Player player, ParallelChunk parallelChunk); 48 | 49 | } 50 | -------------------------------------------------------------------------------- /API/src/main/java/be4rjp/parallel/nms/IPacketHandler.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.nms; 2 | 3 | import be4rjp.parallel.player.ParallelPlayer; 4 | 5 | public interface IPacketHandler { 6 | 7 | Object rewrite(Object packet, ParallelPlayer parallelPlayer, boolean cacheSetting); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /API/src/main/java/be4rjp/parallel/player/ParallelPlayer.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.player; 2 | 3 | import be4rjp.parallel.ParallelUniverse; 4 | import org.bukkit.entity.Player; 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | import java.util.Map; 8 | import java.util.concurrent.ConcurrentHashMap; 9 | 10 | public abstract class ParallelPlayer { 11 | 12 | protected static final Map playerMap = new ConcurrentHashMap<>(); 13 | 14 | public static @Nullable ParallelPlayer getParallelPlayer(Player player){return playerMap.get(player);} 15 | 16 | 17 | protected final Player player; 18 | 19 | protected ParallelUniverse currentUniverse = null; 20 | 21 | protected ParallelPlayer(Player player){ 22 | this.player = player; 23 | } 24 | 25 | public Player getBukkitPlayer() {return player;} 26 | 27 | public abstract @Nullable ParallelUniverse getUniverse(); 28 | 29 | public abstract void setUniverse(@Nullable ParallelUniverse parallelUniverse); 30 | } 31 | -------------------------------------------------------------------------------- /API/src/main/java/be4rjp/parallel/structure/StructureData.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.structure; 2 | 3 | import be4rjp.parallel.util.BlockPosition3i; 4 | import org.bukkit.Location; 5 | import org.bukkit.block.Block; 6 | import org.bukkit.block.data.BlockData; 7 | 8 | import java.util.HashMap; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | public abstract class StructureData { 13 | 14 | protected static Map structureDataMap; 15 | 16 | static { 17 | initialize(); 18 | } 19 | 20 | public static void initialize(){ 21 | structureDataMap = new HashMap<>(); 22 | } 23 | 24 | public static StructureData getStructureData(String name){ 25 | return structureDataMap.get(name); 26 | } 27 | 28 | public static Map getStructureDataMap() {return structureDataMap;} 29 | 30 | 31 | 32 | protected final String name; 33 | protected final Map blockDataMap = new HashMap<>(); 34 | protected final Map blockLightLevelMap = new HashMap<>(); 35 | 36 | public StructureData(String name){ 37 | this.name = name; 38 | structureDataMap.put(name, this); 39 | } 40 | 41 | public Map getBlockDataMap() {return blockDataMap;} 42 | 43 | public Map getBlockLightLevelMap() {return blockLightLevelMap;} 44 | 45 | /** 46 | * ブロックの状態を記録 47 | * @param baseLocation 48 | * @param blocks 49 | */ 50 | public void setBlockData(Location baseLocation, List blocks){ 51 | for(Block block : blocks) { 52 | BlockPosition3i relative = new BlockPosition3i(block.getX() - baseLocation.getBlockX(), block.getY() - baseLocation.getBlockY(), block.getZ() - baseLocation.getBlockZ()); 53 | BlockData blockData = block.getBlockData(); 54 | int blockLightLevel = block.getLightFromBlocks(); 55 | 56 | this.blockDataMap.put(relative, blockData); 57 | this.blockLightLevelMap.put(relative, blockLightLevel); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /API/src/main/java/be4rjp/parallel/util/BlockPosition3i.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.util; 2 | 3 | import java.util.Objects; 4 | 5 | public class BlockPosition3i { 6 | 7 | protected final int x; 8 | protected final int y; 9 | protected final int z; 10 | 11 | public BlockPosition3i(int x, int y, int z){ 12 | this.x = x; 13 | this.y = y; 14 | this.z = z; 15 | } 16 | 17 | public int getX() {return x;} 18 | 19 | public int getY() {return y;} 20 | 21 | public int getZ() {return z;} 22 | 23 | 24 | @Override 25 | public boolean equals(Object o) { 26 | if (this == o) return true; 27 | if (o == null || getClass() != o.getClass()) return false; 28 | BlockPosition3i that = (BlockPosition3i) o; 29 | return x == that.x && y == that.y && z == that.z; 30 | } 31 | 32 | @Override 33 | public int hashCode() { 34 | return Objects.hash(x, y, z); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /API/src/main/java/be4rjp/parallel/util/ChunkPosition.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.util; 2 | 3 | import java.util.Objects; 4 | 5 | public class ChunkPosition { 6 | 7 | public final int x; 8 | public final int z; 9 | 10 | public ChunkPosition(int blockX, int blockZ){ 11 | this.x = blockX >> 4; 12 | this.z = blockZ >> 4; 13 | } 14 | 15 | @Override 16 | public boolean equals(Object o) { 17 | if (this == o) return true; 18 | if (o == null || getClass() != o.getClass()) return false; 19 | ChunkPosition that = (ChunkPosition) o; 20 | return x == that.x && z == that.z; 21 | } 22 | 23 | @Override 24 | public int hashCode() { 25 | return Objects.hash(x, z); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /API/src/main/java/be4rjp/parallel/util/SectionLevelArray.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.util; 2 | 3 | import it.unimi.dsi.fastutil.shorts.Short2ByteArrayMap; 4 | 5 | import java.util.Map; 6 | import java.util.concurrent.locks.ReentrantLock; 7 | 8 | public class SectionLevelArray { 9 | 10 | private final Short2ByteArrayMap arrayMap = new Short2ByteArrayMap(); 11 | 12 | private final ReentrantLock LOCK = new ReentrantLock(true); 13 | 14 | 15 | public int getSize(){ 16 | try{ 17 | LOCK.lock(); 18 | return arrayMap.size(); 19 | }finally { 20 | LOCK.unlock(); 21 | } 22 | } 23 | 24 | public void setLevel(int sectionX, int sectionY, int sectionZ, byte level){ 25 | short serialIndex = getSerialIndex(sectionX, sectionY, sectionZ); 26 | try { 27 | LOCK.lock(); 28 | arrayMap.put(serialIndex, level); 29 | }finally { 30 | LOCK.unlock(); 31 | } 32 | } 33 | 34 | public byte getLevel(int sectionX, int sectionY, int sectionZ){ 35 | short serialIndex = getSerialIndex(sectionX, sectionY, sectionZ); 36 | try { 37 | LOCK.lock(); 38 | return arrayMap.get(serialIndex); 39 | }finally { 40 | LOCK.unlock(); 41 | } 42 | } 43 | 44 | public void removeLevel(int sectionX, int sectionY, int sectionZ){ 45 | short serialIndex = getSerialIndex(sectionX, sectionY, sectionZ); 46 | try { 47 | LOCK.lock(); 48 | arrayMap.remove(serialIndex); 49 | }finally { 50 | LOCK.unlock(); 51 | } 52 | } 53 | 54 | public boolean contains(int sectionX, int sectionY, int sectionZ){ 55 | short serialIndex = getSerialIndex(sectionX, sectionY, sectionZ); 56 | try { 57 | LOCK.lock(); 58 | return arrayMap.containsKey(serialIndex); 59 | }finally { 60 | LOCK.unlock(); 61 | } 62 | } 63 | 64 | public void remove(int sectionX, int sectionY, int sectionZ){ 65 | short serialIndex = getSerialIndex(sectionX, sectionY, sectionZ); 66 | try { 67 | LOCK.lock(); 68 | arrayMap.remove(serialIndex); 69 | }finally { 70 | LOCK.unlock(); 71 | } 72 | } 73 | 74 | public boolean threadsafeIteration(ThreadsafeIteration iteration) { 75 | 76 | boolean notEmpty; 77 | 78 | try { 79 | LOCK.lock(); 80 | for (Map.Entry entry : arrayMap.entrySet()) { 81 | short serialIndex = entry.getKey(); 82 | byte level = entry.getValue(); 83 | 84 | int x = serialIndex & 0xF; 85 | int y = (serialIndex >> 8) & 0xF; 86 | int z = (serialIndex >> 4) & 0xF; 87 | 88 | iteration.accept(x, y, z, level); 89 | } 90 | notEmpty = arrayMap.size() != 0; 91 | }finally { 92 | LOCK.unlock(); 93 | } 94 | 95 | return notEmpty; 96 | } 97 | 98 | private short getSerialIndex(int x, int y, int z){return (short) (y << 8 | z << 4 | x);} 99 | 100 | } 101 | 102 | -------------------------------------------------------------------------------- /API/src/main/java/be4rjp/parallel/util/SectionTypeArray.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.util; 2 | 3 | import it.unimi.dsi.fastutil.shorts.Short2ObjectArrayMap; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | import java.util.Map; 7 | import java.util.concurrent.locks.ReentrantLock; 8 | 9 | public class SectionTypeArray { 10 | 11 | private final Short2ObjectArrayMap arrayMap = new Short2ObjectArrayMap<>(); 12 | 13 | private final ReentrantLock LOCK = new ReentrantLock(true); 14 | 15 | public ReentrantLock getLOCK() {return LOCK;} 16 | 17 | public int getSize(){ 18 | try{ 19 | LOCK.lock(); 20 | return arrayMap.size(); 21 | }finally { 22 | LOCK.unlock(); 23 | } 24 | } 25 | 26 | public void setType(int sectionX, int sectionY, int sectionZ, @Nullable Object iBlockData){ 27 | short serialIndex = getSerialIndex(sectionX, sectionY, sectionZ); 28 | try { 29 | LOCK.lock(); 30 | if(iBlockData != null){ 31 | arrayMap.put(serialIndex, iBlockData); 32 | }else{ 33 | arrayMap.remove(serialIndex); 34 | } 35 | }finally { 36 | LOCK.unlock(); 37 | } 38 | } 39 | 40 | public @Nullable Object getType(int sectionX, int sectionY, int sectionZ){ 41 | short serialIndex = getSerialIndex(sectionX, sectionY, sectionZ); 42 | try { 43 | LOCK.lock(); 44 | return arrayMap.get(serialIndex); 45 | }finally { 46 | LOCK.unlock(); 47 | } 48 | } 49 | 50 | public boolean contains(int sectionX, int sectionY, int sectionZ){ 51 | short serialIndex = getSerialIndex(sectionX, sectionY, sectionZ); 52 | try { 53 | LOCK.lock(); 54 | return arrayMap.containsKey(serialIndex); 55 | }finally { 56 | LOCK.unlock(); 57 | } 58 | } 59 | 60 | public void remove(int sectionX, int sectionY, int sectionZ){ 61 | short serialIndex = getSerialIndex(sectionX, sectionY, sectionZ); 62 | try { 63 | LOCK.lock(); 64 | arrayMap.remove(serialIndex); 65 | }finally { 66 | LOCK.unlock(); 67 | } 68 | } 69 | 70 | public boolean threadsafeIteration(ThreadsafeIteration iteration) { 71 | 72 | boolean notEmpty; 73 | 74 | try { 75 | LOCK.lock(); 76 | for (Map.Entry entry : arrayMap.entrySet()) { 77 | short serialIndex = entry.getKey(); 78 | Object iBlockData = entry.getValue(); 79 | 80 | int x = serialIndex & 0xF; 81 | int y = (serialIndex >> 8) & 0xF; 82 | int z = (serialIndex >> 4) & 0xF; 83 | 84 | iteration.accept(x, y, z, iBlockData); 85 | } 86 | notEmpty = arrayMap.size() != 0; 87 | }finally { 88 | LOCK.unlock(); 89 | } 90 | 91 | return notEmpty; 92 | } 93 | 94 | private short getSerialIndex(int x, int y, int z){return (short) (y << 8 | z << 4 | x);} 95 | 96 | } 97 | -------------------------------------------------------------------------------- /API/src/main/java/be4rjp/parallel/util/ThreadsafeIteration.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.util; 2 | 3 | @FunctionalInterface 4 | public interface ThreadsafeIteration { 5 | 6 | void accept(int x, int y, int z, V value); 7 | 8 | } 9 | -------------------------------------------------------------------------------- /Plugin/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | parallel_plugin 8 | jar 9 | ${revision} 10 | 11 | 12 | be4rjp 13 | parallel_parent 14 | ${revision} 15 | 16 | 17 | 18 | 1.8 19 | UTF-8 20 | 21 | 22 | Parallel 23 | 24 | 25 | 26 | 27 | org.apache.maven.plugins 28 | maven-compiler-plugin 29 | 3.8.1 30 | 31 | ${java.version} 32 | ${java.version} 33 | 34 | 35 | 36 | org.apache.maven.plugins 37 | maven-shade-plugin 38 | 3.2.4 39 | 40 | 41 | package 42 | 43 | shade 44 | 45 | 46 | false 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | src/main/resources 55 | true 56 | 57 | 58 | 59 | 60 | 61 | 62 | spigotmc-repo 63 | https://hub.spigotmc.org/nexus/content/repositories/snapshots/ 64 | 65 | 66 | sonatype 67 | https://oss.sonatype.org/content/groups/public/ 68 | 69 | 70 | minecraft-libraries 71 | Minecraft Libraries 72 | https://libraries.minecraft.net 73 | 74 | 75 | enginehub-maven 76 | https://maven.enginehub.org/repo/ 77 | 78 | 79 | jitpack.io 80 | https://jitpack.io 81 | 82 | 83 | 84 | 85 | 86 | org.spigotmc 87 | spigot-api 88 | 1.15.2-R0.1-SNAPSHOT 89 | provided 90 | 91 | 92 | io.netty 93 | netty-all 94 | 4.1.59.Final 95 | provided 96 | 97 | 98 | com.mojang 99 | datafixerupper 100 | 1.0.20 101 | provided 102 | 103 | 104 | com.sk89q.worldedit 105 | worldedit-bukkit 106 | 7.2.9 107 | provided 108 | 109 | 110 | com.github.Be4rJP 111 | Cinema4C 112 | e1a2df2c89 113 | provided 114 | 115 | 116 | com.github.Be4rJP 117 | ChiyogamiLib 118 | 71d7778b4c 119 | compile 120 | 121 | 122 | fastutil 123 | fastutil 124 | 5.0.9 125 | 126 | 127 | com.github.Be4rJP 128 | ArtGUI 129 | 3146ff51b7 130 | compile 131 | 132 | 133 | be4rjp 134 | parallel_api 135 | jar 136 | ${revision} 137 | compile 138 | true 139 | 140 | 141 | be4rjp 142 | parallel_v1_15_R1 143 | jar 144 | ${revision} 145 | compile 146 | true 147 | 148 | 149 | be4rjp 150 | parallel_v1_16_R3 151 | jar 152 | ${revision} 153 | compile 154 | true 155 | 156 | 157 | org.bstats 158 | bstats-bukkit 159 | 2.2.1 160 | compile 161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /Plugin/src/main/java/be4rjp/parallel/Config.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel; 2 | 3 | import org.bukkit.configuration.file.YamlConfiguration; 4 | 5 | import java.io.File; 6 | 7 | public class Config { 8 | 9 | private static WorkType workType = WorkType.NORMAL; 10 | 11 | private static boolean performanceMode = false; 12 | 13 | private static boolean rewriteLightPacket = true; 14 | 15 | private static boolean showChunkPacketWarning = true; 16 | 17 | public static WorkType getWorkType() {return workType;} 18 | 19 | public static boolean isPerformanceMode() {return performanceMode;} 20 | 21 | public static boolean isRewriteLightPacket() {return rewriteLightPacket;} 22 | 23 | public static boolean isShowChunkPacketWarning() {return showChunkPacketWarning;} 24 | 25 | public static void load(){ 26 | File file = new File("plugins/Parallel", "config.yml"); 27 | file.getParentFile().mkdirs(); 28 | 29 | if(!file.exists()){ 30 | Parallel.getPlugin().saveResource("config.yml", false); 31 | } 32 | 33 | //ロードと値の保持 34 | YamlConfiguration yml = YamlConfiguration.loadConfiguration(file); 35 | 36 | if(yml.contains("work-type")) workType = WorkType.valueOf(yml.getString("work-type")); 37 | if(yml.contains("performance-mode")) performanceMode = yml.getBoolean("performance-mode"); 38 | if(yml.contains("rewrite-light-packet")) rewriteLightPacket = yml.getBoolean("rewrite-light-packet"); 39 | if(yml.contains("show-chunk-packet-warning")) showChunkPacketWarning = yml.getBoolean("show-chunk-packet-warning"); 40 | } 41 | 42 | public enum WorkType{ 43 | NORMAL, 44 | ONLY_ONE 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Plugin/src/main/java/be4rjp/parallel/EventListener.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel; 2 | 3 | import be4rjp.parallel.chiyogami.ChiyogamiManager; 4 | import be4rjp.parallel.impl.ImplParallelPlayer; 5 | import be4rjp.parallel.nms.NMSManager; 6 | import be4rjp.parallel.nms.PacketHandler; 7 | import be4rjp.parallel.player.ParallelPlayer; 8 | import io.netty.channel.Channel; 9 | import io.netty.channel.ChannelPipeline; 10 | import org.bukkit.Material; 11 | import org.bukkit.block.Block; 12 | import org.bukkit.entity.Player; 13 | import org.bukkit.event.EventHandler; 14 | import org.bukkit.event.Listener; 15 | import org.bukkit.event.block.BlockBreakEvent; 16 | import org.bukkit.event.player.PlayerAnimationEvent; 17 | import org.bukkit.event.player.PlayerJoinEvent; 18 | import org.bukkit.event.player.PlayerQuitEvent; 19 | 20 | 21 | public class EventListener implements Listener { 22 | 23 | @EventHandler 24 | public void onjoin(PlayerJoinEvent event){ 25 | //Inject packet handler 26 | Player player = event.getPlayer(); 27 | ParallelPlayer parallelPlayer = ImplParallelPlayer.onPlayerJoin(player); 28 | 29 | ParallelUniverse universe = ParallelAPI.getInstance().createUniverse(player.getUniqueId().toString()); 30 | universe.addPlayer(parallelPlayer); 31 | 32 | Object wrappedParallelPlayer = ChiyogamiManager.getWrappedParallelPlayer(player); 33 | if(wrappedParallelPlayer != null) ChiyogamiManager.setCheckFunction(parallelPlayer, wrappedParallelPlayer); 34 | 35 | PacketHandler packetHandler = new PacketHandler(parallelPlayer); 36 | 37 | try { 38 | ChannelPipeline pipeline = NMSManager.getNmsHandler().getChannel(player).pipeline(); 39 | pipeline.addBefore("packet_handler", Parallel.getPlugin().getName() + "PacketInjector:" + player.getName(), packetHandler); 40 | } catch (Exception e) { 41 | e.printStackTrace(); 42 | } 43 | } 44 | 45 | /*-----------------------TEST CODE-------------------------- 46 | @EventHandler 47 | public void onClick(PlayerAnimationEvent event){ 48 | Player player = event.getPlayer(); 49 | if(!player.isSneaking()) return; 50 | 51 | ParallelAPI api = ParallelAPI.getInstance(); 52 | ParallelPlayer parallelPlayer = api.getParallelPlayer(player); 53 | if(parallelPlayer == null) return; 54 | 55 | ParallelUniverse universe = parallelPlayer.getUniverse(); 56 | if(universe == null) return; 57 | 58 | for(ParallelUniverse otherUniverse : api.getAllUniverse()){ 59 | if(otherUniverse != universe) universe.addDiffs(otherUniverse); 60 | } 61 | } 62 | 63 | 64 | @EventHandler 65 | public void onBlockBreak(BlockBreakEvent event){ 66 | Player player = event.getPlayer(); 67 | 68 | ParallelPlayer parallelPlayer = ParallelPlayer.getParallelPlayer(player); 69 | if(parallelPlayer == null) return; 70 | 71 | ParallelUniverse universe = parallelPlayer.getUniverse(); 72 | if(universe == null){ 73 | player.sendMessage("NULL!"); 74 | return; 75 | } 76 | 77 | ParallelWorld parallelWorld = universe.getWorld(player.getWorld().getName()); 78 | 79 | Block block = event.getBlock(); 80 | parallelWorld.setType(block.getX(), block.getY(), block.getZ(), Material.AIR); 81 | parallelWorld.sendBlockUpdate(block.getX(), block.getY(), block.getZ()); 82 | 83 | if(parallelWorld.getType(block.getX(), block.getY(), block.getZ()) != Material.AIR){ 84 | player.sendMessage("NOT EQUAL!"); 85 | } 86 | 87 | event.setCancelled(true); 88 | }*/ 89 | 90 | 91 | @EventHandler 92 | public void onleave(PlayerQuitEvent event){ 93 | Player player = event.getPlayer(); 94 | ImplParallelPlayer.onPlayerQuit(player); 95 | 96 | ChiyogamiManager.removeWrappedParallelPlayer(player); 97 | 98 | try { 99 | Channel channel = NMSManager.getNmsHandler().getChannel(player); 100 | 101 | channel.eventLoop().submit(() -> { 102 | channel.pipeline().remove(Parallel.getPlugin().getName() + "PacketInjector:" + player.getName()); 103 | return null; 104 | }); 105 | } catch (Exception e) { 106 | e.printStackTrace(); 107 | } 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /Plugin/src/main/java/be4rjp/parallel/Parallel.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel; 2 | 3 | import be4rjp.artgui.ArtGUI; 4 | import be4rjp.parallel.cinema4c.BridgeManager; 5 | import be4rjp.parallel.command.parallelCommandExecutor; 6 | import be4rjp.parallel.impl.ImplParallelAPI; 7 | import be4rjp.parallel.nms.NMSManager; 8 | import be4rjp.parallel.structure.ParallelStructure; 9 | import be4rjp.parallel.structure.ImplStructureData; 10 | import org.bukkit.Bukkit; 11 | import org.bukkit.plugin.PluginManager; 12 | import org.bukkit.plugin.java.JavaPlugin; 13 | 14 | import java.lang.reflect.Field; 15 | 16 | 17 | public final class Parallel extends JavaPlugin { 18 | 19 | private static Parallel plugin; 20 | 21 | private static ArtGUI artGUI; 22 | 23 | @Override 24 | public void onEnable() { 25 | // Plugin startup logic 26 | plugin = this; 27 | 28 | createAPIInstance(); 29 | 30 | artGUI = new ArtGUI(this); 31 | 32 | NMSManager.setup(); 33 | 34 | //Load config 35 | Config.load(); 36 | 37 | //Register event listeners 38 | getLogger().info("Registering event listeners..."); 39 | PluginManager pluginManager = getServer().getPluginManager(); 40 | pluginManager.registerEvents(new EventListener(), this); 41 | 42 | 43 | if(Bukkit.getPluginManager().getPlugin("WorldEdit") != null) { 44 | //Register command executors 45 | getLogger().info("Registering command executors..."); 46 | getCommand("parallel").setExecutor(new parallelCommandExecutor()); 47 | getCommand("parallel").setTabCompleter(new parallelCommandExecutor()); 48 | } 49 | 50 | 51 | //For cinema4c extensions 52 | 53 | if(getServer().getPluginManager().getPlugin("Cinema4C") != null){ 54 | getLogger().info("Registering cinema4c extensions..."); 55 | BridgeManager.registerPluginBridge(this.getName()); 56 | } 57 | 58 | ImplStructureData.loadAllStructureData(); 59 | ParallelStructure.loadAllParallelStructure(); 60 | } 61 | 62 | @Override 63 | public void onDisable() { 64 | // Plugin shutdown logic 65 | } 66 | 67 | public void createAPIInstance(){ 68 | try { 69 | Field instance = ParallelAPI.class.getDeclaredField("instance"); 70 | instance.setAccessible(true); 71 | instance.set(null, new ImplParallelAPI()); 72 | }catch (Exception e){ 73 | e.printStackTrace(); 74 | throw new IllegalStateException("Failed to instantiate the API."); 75 | } 76 | } 77 | 78 | 79 | public static Parallel getPlugin(){ 80 | return plugin; 81 | } 82 | 83 | public ArtGUI getArtGUI() {return artGUI;} 84 | 85 | } 86 | -------------------------------------------------------------------------------- /Plugin/src/main/java/be4rjp/parallel/chiyogami/ChiyogamiBridge.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.chiyogami; 2 | 3 | import be4rjp.parallel.ParallelUniverse; 4 | import be4rjp.parallel.ParallelWorld; 5 | import be4rjp.parallel.player.ParallelPlayer; 6 | import org.bukkit.block.Block; 7 | import org.bukkit.entity.Player; 8 | import world.chiyogami.chiyogamilib.ChiyogamiLib; 9 | import world.chiyogami.chiyogamilib.ServerType; 10 | 11 | import java.lang.reflect.Field; 12 | import java.lang.reflect.Method; 13 | import java.util.function.Function; 14 | 15 | public class ChiyogamiBridge { 16 | 17 | private static Field hasBlockCheckFunction; 18 | 19 | static { 20 | if(ChiyogamiLib.getServerType() == ServerType.CHIYOGAMI){ 21 | try{ 22 | Class wrappedParallelPlayer = Class.forName("world.chiyogami.bridge.WrappedParallelPlayer"); 23 | hasBlockCheckFunction = wrappedParallelPlayer.getField("hasBlockCheckFunction"); 24 | }catch (Exception e){e.printStackTrace();} 25 | } 26 | } 27 | 28 | public static void setCheckFunction(ParallelPlayer parallelPlayer, Object wrappedParallelPlayerObject){ 29 | try { 30 | hasBlockCheckFunction.set(wrappedParallelPlayerObject, (Function) block -> { 31 | ParallelUniverse universe = parallelPlayer.getUniverse(); 32 | if(universe == null) return false; 33 | 34 | ParallelWorld parallelWorld = universe.getWorld(block.getWorld().getName()); 35 | return parallelWorld.hasBlockData(block.getX(), block.getY(), block.getZ()); 36 | }); 37 | } catch (Exception e) { 38 | e.printStackTrace(); 39 | } 40 | } 41 | 42 | public static void removeWrappedParallelPlayer(Player player){ 43 | try { 44 | Class ParallelWorldBridge = Class.forName("world.chiyogami.bridge.ParallelBridge"); 45 | Method method = ParallelWorldBridge.getMethod("removeWrappedParallelPlayer", Player.class); 46 | method.invoke(null, player); 47 | } catch (Exception e) { 48 | e.printStackTrace(); 49 | } 50 | } 51 | 52 | public static Object getWrappedParallelPlayer(Player player){ 53 | try { 54 | Class ParallelWorldBridge = Class.forName("world.chiyogami.bridge.ParallelBridge"); 55 | Method method = ParallelWorldBridge.getMethod("getWrappedParallelPlayer", Player.class); 56 | return method.invoke(null, player); 57 | } catch (Exception e) { 58 | e.printStackTrace(); 59 | } 60 | 61 | return null; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /Plugin/src/main/java/be4rjp/parallel/chiyogami/ChiyogamiManager.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.chiyogami; 2 | 3 | import be4rjp.parallel.player.ParallelPlayer; 4 | import org.bukkit.entity.Player; 5 | import world.chiyogami.chiyogamilib.ChiyogamiLib; 6 | import world.chiyogami.chiyogamilib.ServerType; 7 | 8 | public class ChiyogamiManager { 9 | 10 | public static void setCheckFunction(ParallelPlayer parallelPlayer, Object wrappedParallelPlayer){ 11 | if(ChiyogamiLib.getServerType() == ServerType.CHIYOGAMI && wrappedParallelPlayer != null){ 12 | ChiyogamiBridge.setCheckFunction(parallelPlayer, wrappedParallelPlayer); 13 | } 14 | } 15 | 16 | 17 | public static void removeWrappedParallelPlayer(Player player){ 18 | if(ChiyogamiLib.getServerType() == ServerType.CHIYOGAMI){ 19 | ChiyogamiBridge.removeWrappedParallelPlayer(player); 20 | } 21 | } 22 | 23 | public static Object getWrappedParallelPlayer(Player player){ 24 | if(ChiyogamiLib.getServerType() == ServerType.CHIYOGAMI){ 25 | return ChiyogamiBridge.getWrappedParallelPlayer(player); 26 | } 27 | return null; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /Plugin/src/main/java/be4rjp/parallel/cinema4c/BridgeManager.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.cinema4c; 2 | 3 | import be4rjp.cinema4c.bridge.Cinema4CBridge; 4 | 5 | public class BridgeManager { 6 | public static void registerPluginBridge(String name){ 7 | Cinema4CBridge.registerPluginBridge(name, new C4CBridge()); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Plugin/src/main/java/be4rjp/parallel/cinema4c/C4CBridge.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.cinema4c; 2 | 3 | import be4rjp.cinema4c.bridge.PluginBridge; 4 | import be4rjp.cinema4c.player.ScenePlayer; 5 | import be4rjp.parallel.Parallel; 6 | import be4rjp.parallel.structure.ParallelStructure; 7 | import be4rjp.parallel.structure.ImplStructureData; 8 | import be4rjp.parallel.structure.StructureData; 9 | import org.bukkit.ChatColor; 10 | 11 | public class C4CBridge implements PluginBridge { 12 | 13 | @Override 14 | public void executeCommand(ScenePlayer scenePlayer, String command) { 15 | 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Plugin/src/main/java/be4rjp/parallel/command/parallelCommandExecutor.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.command; 2 | 3 | import be4rjp.parallel.ParallelAPI; 4 | import be4rjp.parallel.ParallelUniverse; 5 | import be4rjp.parallel.gui.UniverseGUI; 6 | import be4rjp.parallel.player.ParallelPlayer; 7 | import be4rjp.parallel.structure.ParallelStructure; 8 | import be4rjp.parallel.structure.ImplStructureData; 9 | import be4rjp.parallel.structure.StructureData; 10 | import be4rjp.parallel.util.RegionBlocks; 11 | import com.sk89q.worldedit.IncompleteRegionException; 12 | import com.sk89q.worldedit.LocalSession; 13 | import com.sk89q.worldedit.WorldEdit; 14 | import com.sk89q.worldedit.bukkit.BukkitAdapter; 15 | import com.sk89q.worldedit.math.BlockVector3; 16 | import com.sk89q.worldedit.regions.Region; 17 | import com.sk89q.worldedit.session.SessionManager; 18 | import org.bukkit.Bukkit; 19 | import org.bukkit.ChatColor; 20 | import org.bukkit.World; 21 | import org.bukkit.command.Command; 22 | import org.bukkit.command.CommandExecutor; 23 | import org.bukkit.command.CommandSender; 24 | import org.bukkit.command.TabExecutor; 25 | import org.bukkit.entity.Player; 26 | import org.bukkit.util.Vector; 27 | 28 | import java.io.File; 29 | import java.util.ArrayList; 30 | import java.util.List; 31 | 32 | public class parallelCommandExecutor implements CommandExecutor, TabExecutor { 33 | 34 | @Override 35 | public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) { 36 | if (args == null) return false; 37 | if (args.length == 0) return false; 38 | 39 | if(args[0].equals("structure")){ 40 | if(args.length < 3){ 41 | return false; 42 | } 43 | 44 | //parallel structure set-data [structure-name] [data-name] [player] 45 | if(args[1].equals("set-data")) { 46 | if(args.length < 5){ 47 | return false; 48 | } 49 | 50 | ParallelStructure parallelStructure = ParallelStructure.getParallelStructure(args[2]); 51 | if (parallelStructure == null) { 52 | sender.sendMessage(ChatColor.RED + "指定された名前の構造体は存在しません。"); 53 | return true; 54 | } 55 | 56 | ImplStructureData implStructureData = (ImplStructureData) ImplStructureData.getStructureData(args[3]); 57 | if (implStructureData == null) { 58 | sender.sendMessage(ChatColor.RED + "指定された名前の構造データは存在しません。"); 59 | return true; 60 | } 61 | 62 | Player player = Bukkit.getPlayer(args[4]); 63 | if(player == null){ 64 | sender.sendMessage(ChatColor.RED + "指定されたプレイヤーが見つかりませんでした。"); 65 | return true; 66 | } 67 | 68 | parallelStructure.setStructureData(player, implStructureData); 69 | sender.sendMessage(ChatColor.GREEN + "適用しました。"); 70 | return true; 71 | } 72 | 73 | //parallel structure remove-data [structure-name] [player] 74 | if(args[1].equals("remove-data")) { 75 | if (args.length < 4) { 76 | return false; 77 | } 78 | 79 | ParallelStructure parallelStructure = ParallelStructure.getParallelStructure(args[2]); 80 | if (parallelStructure == null) { 81 | sender.sendMessage(ChatColor.RED + "指定された名前の構造体は存在しません。"); 82 | return true; 83 | } 84 | 85 | Player player = Bukkit.getPlayer(args[3]); 86 | if(player == null){ 87 | sender.sendMessage(ChatColor.RED + "指定されたプレイヤーが見つかりませんでした。"); 88 | return true; 89 | } 90 | 91 | parallelStructure.clearStructureData(player, true); 92 | sender.sendMessage(ChatColor.GREEN + "適用しました。"); 93 | return true; 94 | } 95 | 96 | //parallel structure remove [structure-name] 97 | if(args[1].equals("remove")) { 98 | if (args.length < 3) { 99 | return false; 100 | } 101 | 102 | ParallelStructure parallelStructure = ParallelStructure.getParallelStructure(args[2]); 103 | if (parallelStructure == null) { 104 | sender.sendMessage(ChatColor.RED + "指定された名前の構造体は存在しません。"); 105 | return true; 106 | } 107 | 108 | ParallelStructure.getStructureMap().remove(args[2]); 109 | File file = new File("plugins/Parallel/structures", args[2] + ".yml"); 110 | file.delete(); 111 | 112 | sender.sendMessage(ChatColor.GREEN + "削除しました。"); 113 | return true; 114 | } 115 | } 116 | 117 | if (!(sender instanceof Player)) { 118 | sender.sendMessage(ChatColor.RED + "このコマンドはコンソールから実行できません。"); 119 | return true; 120 | } 121 | 122 | if(args[0].equals("menu")){ 123 | Player player = (Player) sender; 124 | UniverseGUI.openUniverseGUI(player); 125 | 126 | return true; 127 | } 128 | 129 | if(args[0].equals("join-universe")){ 130 | if(args.length != 2) return false; 131 | 132 | String universeName = args[1]; 133 | ParallelUniverse universe = ParallelAPI.getInstance().getUniverse(universeName); 134 | 135 | if(universe == null){ 136 | sender.sendMessage("§aThe universe is not found."); 137 | return true; 138 | } 139 | 140 | ParallelPlayer parallelPlayer = ParallelPlayer.getParallelPlayer((Player) sender); 141 | if(parallelPlayer == null) return false; 142 | 143 | parallelPlayer.setUniverse(universe); 144 | parallelPlayer.getBukkitPlayer().sendMessage("§7Switched to §r" + universe.getName()); 145 | } 146 | 147 | if(args[0].equals("leave-universe")){ 148 | ParallelPlayer parallelPlayer = ParallelPlayer.getParallelPlayer((Player) sender); 149 | if(parallelPlayer == null) return false; 150 | 151 | parallelPlayer.setUniverse(null); 152 | } 153 | 154 | //parallel structure-data create [name] 155 | if(args[0].equals("structure-data")){ 156 | if(args.length < 3){ 157 | return false; 158 | } 159 | if(args[1].equals("create")) { 160 | Player player = (Player) sender; 161 | com.sk89q.worldedit.entity.Player wePlayer = BukkitAdapter.adapt(player); 162 | SessionManager sessionManager = WorldEdit.getInstance().getSessionManager(); 163 | LocalSession localSession = sessionManager.get(wePlayer); 164 | 165 | com.sk89q.worldedit.world.World selectionWorld = localSession.getSelectionWorld(); 166 | Region region; 167 | try { 168 | if (selectionWorld == null) throw new IncompleteRegionException(); 169 | region = localSession.getSelection(selectionWorld); 170 | } catch (IncompleteRegionException ex) { 171 | sender.sendMessage(ChatColor.GREEN + "範囲が選択されていません。"); 172 | return true; 173 | } 174 | 175 | BlockVector3 max = region.getMaximumPoint(); 176 | BlockVector3 min = region.getMinimumPoint(); 177 | 178 | World world = BukkitAdapter.adapt(region.getWorld()); 179 | 180 | Vector maxLocation = new Vector(max.getX(), max.getY(), max.getZ()); 181 | Vector minLocation = new Vector(min.getX(), min.getY(), min.getZ()); 182 | 183 | RegionBlocks regionBlocks = new RegionBlocks(minLocation.toLocation(world), maxLocation.toLocation(world)); 184 | 185 | ImplStructureData implStructureData = (ImplStructureData) StructureData.getStructureData(args[2]); 186 | if (implStructureData != null) { 187 | sender.sendMessage(ChatColor.RED + "指定された名前の構造データは既に存在しています。"); 188 | return true; 189 | } 190 | implStructureData = new ImplStructureData(args[2]); 191 | 192 | implStructureData.setBlockData(minLocation.toLocation(world), regionBlocks.getBlocks()); 193 | sender.sendMessage(ChatColor.GREEN + "作成しました。"); 194 | return true; 195 | } 196 | 197 | if(args[1].equals("save")) { 198 | ImplStructureData implStructureData = (ImplStructureData) ImplStructureData.getStructureData(args[2]); 199 | if (implStructureData == null) { 200 | sender.sendMessage(ChatColor.RED + "指定された名前の構造データは存在しません。"); 201 | return true; 202 | } 203 | 204 | implStructureData.saveData(); 205 | sender.sendMessage(ChatColor.GREEN + "保存しました。"); 206 | return true; 207 | } 208 | 209 | if(args[1].equals("remove")) { 210 | ImplStructureData implStructureData = (ImplStructureData) ImplStructureData.getStructureData(args[2]); 211 | if (implStructureData == null) { 212 | sender.sendMessage(ChatColor.RED + "指定された名前の構造データは存在しません。"); 213 | return true; 214 | } 215 | 216 | ImplStructureData.getStructureDataMap().remove(args[2]); 217 | File file = new File("plugins/Parallel/structure_data", args[2] + ".yml"); 218 | file.delete(); 219 | 220 | sender.sendMessage(ChatColor.GREEN + "削除しました。"); 221 | return true; 222 | } 223 | } 224 | 225 | 226 | if(args[0].equals("structure")){ 227 | if(args.length < 3){ 228 | return false; 229 | } 230 | //parallel structure create [name] 231 | if(args[1].equals("create")) { 232 | Player player = (Player) sender; 233 | com.sk89q.worldedit.entity.Player wePlayer = BukkitAdapter.adapt(player); 234 | SessionManager sessionManager = WorldEdit.getInstance().getSessionManager(); 235 | LocalSession localSession = sessionManager.get(wePlayer); 236 | 237 | com.sk89q.worldedit.world.World selectionWorld = localSession.getSelectionWorld(); 238 | Region region; 239 | try { 240 | if (selectionWorld == null) throw new IncompleteRegionException(); 241 | region = localSession.getSelection(selectionWorld); 242 | } catch (IncompleteRegionException ex) { 243 | sender.sendMessage(ChatColor.GREEN + "範囲が選択されていません。"); 244 | return true; 245 | } 246 | 247 | BlockVector3 min = region.getMinimumPoint(); 248 | 249 | World world = BukkitAdapter.adapt(region.getWorld()); 250 | 251 | Vector minLocation = new Vector(min.getX(), min.getY(), min.getZ()); 252 | 253 | ParallelStructure parallelStructure = ParallelStructure.getParallelStructure(args[2]); 254 | if (parallelStructure != null) { 255 | sender.sendMessage(ChatColor.RED + "指定された名前の構造体は既に存在しています。"); 256 | return true; 257 | } 258 | parallelStructure = new ParallelStructure(args[2]); 259 | parallelStructure.setBaseLocation(minLocation.toLocation(world)); 260 | 261 | sender.sendMessage(ChatColor.GREEN + "作成しました。"); 262 | return true; 263 | } 264 | 265 | //parallel structure save [name] 266 | if(args[1].equals("save")) { 267 | ParallelStructure parallelStructure = ParallelStructure.getParallelStructure(args[2]); 268 | if (parallelStructure == null) { 269 | sender.sendMessage(ChatColor.RED + "指定された名前の構造体は存在しません。"); 270 | return true; 271 | } 272 | 273 | parallelStructure.saveData(); 274 | sender.sendMessage(ChatColor.GREEN + "保存しました。"); 275 | return true; 276 | } 277 | } 278 | 279 | return true; 280 | } 281 | 282 | 283 | @Override 284 | public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) { 285 | 286 | List list = new ArrayList<>(); 287 | 288 | if (args.length == 1) { 289 | list.add("structure-data"); 290 | list.add("structure"); 291 | list.add("menu"); 292 | list.add("join-universe"); 293 | list.add("leave-universe"); 294 | 295 | return list; 296 | } 297 | 298 | if (args.length == 2) { 299 | if(args[0].equals("structure")){ 300 | list.add("set-data"); 301 | list.add("remove-data"); 302 | list.add("create"); 303 | list.add("save"); 304 | list.add("remove"); 305 | } 306 | 307 | if(args[0].equals("structure-data")){ 308 | list.add("create"); 309 | list.add("save"); 310 | list.add("remove"); 311 | } 312 | 313 | if(args[0].equals("join-universe")){ 314 | list.addAll(ParallelAPI.getInstance().getAllUniverseName()); 315 | } 316 | 317 | return list; 318 | } 319 | 320 | if (args.length == 3) { 321 | if(args[0].equals("structure")){ 322 | if(args[1].equals("create")) { 323 | list.add("[structure-name]"); 324 | }else{ 325 | list = new ArrayList<>(ParallelStructure.getStructureMap().keySet()); 326 | } 327 | }else{ 328 | if(args[1].equals("create")) { 329 | list.add("[data-name]"); 330 | }else{ 331 | list = new ArrayList<>(ImplStructureData.getStructureDataMap().keySet()); 332 | } 333 | } 334 | 335 | return list; 336 | } 337 | 338 | if (args.length == 4) { 339 | if(args[1].equals("set-data")){ 340 | list = new ArrayList<>(ImplStructureData.getStructureDataMap().keySet()); 341 | return list; 342 | } 343 | } 344 | 345 | return null; 346 | } 347 | 348 | } 349 | -------------------------------------------------------------------------------- /Plugin/src/main/java/be4rjp/parallel/enums/UpdatePacketType.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.enums; 2 | 3 | public enum UpdatePacketType { 4 | NO_UPDATE, 5 | MULTI_BLOCK_CHANGE, 6 | CHUNK_MAP 7 | } 8 | -------------------------------------------------------------------------------- /Plugin/src/main/java/be4rjp/parallel/gui/UniverseGUI.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.gui; 2 | 3 | import be4rjp.artgui.button.*; 4 | import be4rjp.artgui.frame.Artist; 5 | import be4rjp.artgui.menu.ArtMenu; 6 | import be4rjp.parallel.Parallel; 7 | import be4rjp.parallel.ParallelAPI; 8 | import be4rjp.parallel.ParallelUniverse; 9 | import be4rjp.parallel.player.ParallelPlayer; 10 | import org.bukkit.Material; 11 | import org.bukkit.entity.Player; 12 | 13 | public class UniverseGUI { 14 | 15 | public static void openUniverseGUI(Player player){ 16 | 17 | ParallelPlayer parallelPlayer = ParallelPlayer.getParallelPlayer(player); 18 | if(parallelPlayer == null) return; 19 | 20 | Artist artist = new Artist(() -> { 21 | 22 | ArtButton V = null; 23 | 24 | ArtButton G = new ArtButton(new ItemBuilder(Material.GRAY_STAINED_GLASS_PANE).name("&a").build()); 25 | 26 | PageNextButton N = new PageNextButton(new ItemBuilder(Material.ARROW).name("&rNext page &7[{NextPage}/{MaxPage}]").build()); 27 | 28 | PageBackButton P = new PageBackButton(new ItemBuilder(Material.ARROW).name("&rPrevious page &7[{PreviousPage}/{MaxPage}]").build()); 29 | 30 | MenuBackButton B = new MenuBackButton(new ItemBuilder(Material.OAK_DOOR).name("&7Back to &r{PreviousName}").build()); 31 | 32 | ArtButton L = new ArtButton(new ItemBuilder(Material.BARRIER).name("&b&nLeave from current universe").build()) 33 | .listener((inventoryClickEvent, menu) -> { 34 | parallelPlayer.setUniverse(null); 35 | player.closeInventory(); 36 | }); 37 | 38 | return new ArtButton[]{ 39 | V, V, V, V, V, V, V, G, G, 40 | V, V, V, V, V, V, V, G, N, 41 | V, V, V, V, V, V, V, G, P, 42 | V, V, V, V, V, V, V, G, G, 43 | V, V, V, V, V, V, V, G, L, 44 | V, V, V, V, V, V, V, G, B, 45 | }; 46 | }); 47 | 48 | ArtMenu artMenu = artist.createMenu(Parallel.getPlugin().getArtGUI(), "&nUniverse list"); 49 | artMenu.asyncCreate(menu -> { 50 | 51 | for(ParallelUniverse universe : ParallelAPI.getInstance().getAllUniverse()){ 52 | menu.addButton(new ArtButton(new ItemBuilder(Material.END_PORTAL_FRAME).name(universe.getName()).lore("&7Click to join.").build()).listener((inventoryClickEvent, menu1) -> { 53 | parallelPlayer.setUniverse(universe); 54 | player.closeInventory(); 55 | player.sendMessage("§7Switched to §r" + universe.getName()); 56 | })); 57 | } 58 | 59 | }); 60 | 61 | artMenu.open(player); 62 | 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /Plugin/src/main/java/be4rjp/parallel/impl/ImplParallelAPI.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.impl; 2 | 3 | import be4rjp.parallel.ParallelAPI; 4 | import be4rjp.parallel.ParallelUniverse; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | import java.util.Collection; 9 | import java.util.Map; 10 | import java.util.Set; 11 | import java.util.concurrent.ConcurrentHashMap; 12 | 13 | public class ImplParallelAPI extends ParallelAPI { 14 | 15 | //All universes 16 | private static final Map universeMap = new ConcurrentHashMap<>(); 17 | 18 | @Override 19 | public @NotNull ParallelUniverse createUniverse(String universeName) { 20 | return universeMap.computeIfAbsent(universeName, ImplParallelUniverse::new); 21 | } 22 | 23 | @Override 24 | public @Nullable ParallelUniverse getUniverse(String universeName) {return universeMap.get(universeName);} 25 | 26 | @Override 27 | public void removeUniverse(String universeName) { 28 | ParallelUniverse universe = getUniverse(universeName); 29 | if(universe != null) ((ImplParallelUniverse) universe).getPlayers().forEach(player -> player.setUniverse(null)); 30 | 31 | universeMap.remove(universeName); 32 | } 33 | 34 | @Override 35 | public Set getAllUniverseName() {return universeMap.keySet();} 36 | 37 | @Override 38 | public Collection getAllUniverse() {return universeMap.values();} 39 | } 40 | -------------------------------------------------------------------------------- /Plugin/src/main/java/be4rjp/parallel/impl/ImplParallelChunk.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.impl; 2 | 3 | import be4rjp.parallel.ParallelChunk; 4 | import be4rjp.parallel.ParallelWorld; 5 | import be4rjp.parallel.nms.INMSHandler; 6 | import be4rjp.parallel.nms.NMSManager; 7 | import be4rjp.parallel.util.SectionLevelArray; 8 | import be4rjp.parallel.util.SectionTypeArray; 9 | import be4rjp.parallel.util.TaskHandler; 10 | import org.bukkit.Bukkit; 11 | import org.bukkit.Material; 12 | import org.bukkit.World; 13 | import org.bukkit.block.data.BlockData; 14 | import org.bukkit.entity.Player; 15 | import org.jetbrains.annotations.NotNull; 16 | import org.jetbrains.annotations.Nullable; 17 | 18 | public class ImplParallelChunk implements ParallelChunk { 19 | 20 | private final ParallelWorld parallelWorld; 21 | 22 | private final int chunkX; 23 | 24 | private final int chunkZ; 25 | 26 | private final SectionLevelArray[] blockLightArrays; 27 | 28 | private final SectionLevelArray[] skyLightArrays; 29 | 30 | private final SectionTypeArray[] sectionTypeArrays; 31 | 32 | 33 | private Object mapChunkPacketCache; 34 | 35 | private Object lightUpdatePacketCache; 36 | 37 | 38 | public ImplParallelChunk(ParallelWorld parallelWorld, int chunkX, int chunkZ){ 39 | this.parallelWorld = parallelWorld; 40 | this.chunkX = chunkX; 41 | this.chunkZ = chunkZ; 42 | 43 | this.blockLightArrays = new SectionLevelArray[NMSManager.isHigher_v1_18_R1() ? 24 : 16]; 44 | this.skyLightArrays = new SectionLevelArray[NMSManager.isHigher_v1_18_R1() ? 24 : 16]; 45 | this.sectionTypeArrays = new SectionTypeArray[NMSManager.isHigher_v1_18_R1() ? 24 : 16]; 46 | } 47 | 48 | @Override 49 | public @NotNull ParallelWorld getWorld() { 50 | return parallelWorld; 51 | } 52 | 53 | @Override 54 | public int getChunkX() {return chunkX;} 55 | 56 | @Override 57 | public int getChunkZ() {return chunkZ;} 58 | 59 | 60 | public SectionLevelArray createBlockLightSectionLevelArrayIfAbsent(int sectionY) { 61 | int sectionIndex = getSectionIndexAligned(sectionY << 4); 62 | SectionLevelArray sectionLevelArray = blockLightArrays[sectionIndex]; 63 | if(sectionLevelArray == null) { 64 | sectionLevelArray = new SectionLevelArray(); 65 | blockLightArrays[sectionIndex] = sectionLevelArray; 66 | } 67 | 68 | return sectionLevelArray; 69 | } 70 | 71 | public SectionLevelArray createSkyLightSectionLevelArrayIfAbsent(int sectionY) { 72 | int sectionIndex = getSectionIndexAligned(sectionY << 4); 73 | SectionLevelArray sectionLevelArray = skyLightArrays[sectionIndex]; 74 | if(sectionLevelArray == null) { 75 | sectionLevelArray = new SectionLevelArray(); 76 | skyLightArrays[sectionIndex] = sectionLevelArray; 77 | } 78 | 79 | return sectionLevelArray; 80 | } 81 | 82 | public SectionTypeArray createSectionTypeArrayIfAbsent(int sectionY) { 83 | int sectionIndex = getSectionIndexAligned(sectionY << 4); 84 | SectionTypeArray sectionTypeArray = sectionTypeArrays[sectionIndex]; 85 | if(sectionTypeArray == null) { 86 | sectionTypeArray = new SectionTypeArray(); 87 | sectionTypeArrays[sectionIndex] = sectionTypeArray; 88 | } 89 | 90 | return sectionTypeArray; 91 | } 92 | 93 | 94 | private int getSectionIndexAligned(int blockY){ 95 | int section; 96 | if(NMSManager.isHigher_v1_18_R1()){ 97 | section = (blockY + 64) >> 4; 98 | section = Math.min(23, section); 99 | }else{ 100 | section = blockY >> 4; 101 | section = Math.min(15, section); 102 | } 103 | section = Math.max(0, section); 104 | return section; 105 | } 106 | 107 | @Override 108 | public void setType(int blockX, int blockY, int blockZ, Material material) { 109 | int sectionIndex = getSectionIndexAligned(blockY); 110 | 111 | SectionTypeArray sectionTypeArray = sectionTypeArrays[sectionIndex]; 112 | if(sectionTypeArray == null){ 113 | sectionTypeArray = new SectionTypeArray(); 114 | sectionTypeArrays[sectionIndex] = sectionTypeArray; 115 | } 116 | 117 | Object iBlockData = NMSManager.getNmsHandler().getIBlockData(material.createBlockData()); 118 | sectionTypeArray.setType(blockX & 0xF, blockY & 0xF, blockZ & 0xF, iBlockData); 119 | mapChunkPacketCache = null; 120 | } 121 | 122 | @Override 123 | public @Nullable Material getType(int blockX, int blockY, int blockZ) { 124 | int sectionIndex = getSectionIndexAligned(blockY); 125 | 126 | SectionTypeArray sectionTypeArray = sectionTypeArrays[sectionIndex]; 127 | if(sectionTypeArray == null) return null; 128 | 129 | Object iBlockData = sectionTypeArray.getType(blockX & 0xF, blockY & 0xF, blockZ & 0xF); 130 | if(iBlockData == null) return null; 131 | 132 | return NMSManager.getNmsHandler().getBukkitBlockData(iBlockData).getMaterial(); 133 | } 134 | 135 | @Override 136 | public void setBlockData(int blockX, int blockY, int blockZ, BlockData blockData) { 137 | int sectionIndex = getSectionIndexAligned(blockY); 138 | 139 | SectionTypeArray sectionTypeArray = sectionTypeArrays[sectionIndex]; 140 | if(sectionTypeArray == null){ 141 | sectionTypeArray = new SectionTypeArray(); 142 | sectionTypeArrays[sectionIndex] = sectionTypeArray; 143 | } 144 | 145 | Object iBlockData = NMSManager.getNmsHandler().getIBlockData(blockData); 146 | sectionTypeArray.setType(blockX & 0xF, blockY & 0xF, blockZ & 0xF, iBlockData); 147 | mapChunkPacketCache = null; 148 | } 149 | 150 | @Override 151 | public @Nullable BlockData getBlockData(int blockX, int blockY, int blockZ) { 152 | int sectionIndex = getSectionIndexAligned(blockY); 153 | 154 | SectionTypeArray sectionTypeArray = sectionTypeArrays[sectionIndex]; 155 | if(sectionTypeArray == null) return null; 156 | 157 | Object iBlockData = sectionTypeArray.getType(blockX & 0xF, blockY & 0xF, blockZ & 0xF); 158 | if(iBlockData == null) return null; 159 | 160 | return NMSManager.getNmsHandler().getBukkitBlockData(iBlockData); 161 | } 162 | 163 | @Override 164 | public @Nullable Object getNMSBlockData(int blockX, int blockY, int blockZ) { 165 | int sectionIndex = getSectionIndexAligned(blockY); 166 | 167 | SectionTypeArray sectionTypeArray = sectionTypeArrays[sectionIndex]; 168 | if(sectionTypeArray == null) return null; 169 | 170 | return sectionTypeArray.getType(blockX & 0xF, blockY & 0xF, blockZ & 0xF); 171 | } 172 | 173 | @Override 174 | public void removeBlockData(int blockX, int blockY, int blockZ) { 175 | int sectionIndex = getSectionIndexAligned(blockY); 176 | 177 | SectionTypeArray sectionTypeArray = sectionTypeArrays[sectionIndex]; 178 | if(sectionTypeArray == null) return; 179 | 180 | sectionTypeArray.remove(blockX, blockY, blockZ); 181 | mapChunkPacketCache = null; 182 | } 183 | 184 | @Override 185 | public void setBlockLightLevel(int blockX, int blockY, int blockZ, int level) { 186 | int sectionIndex = getSectionIndexAligned(blockY); 187 | 188 | SectionLevelArray sectionLevelArray = blockLightArrays[sectionIndex]; 189 | if(sectionLevelArray == null){ 190 | sectionLevelArray = new SectionLevelArray(); 191 | blockLightArrays[sectionIndex] = sectionLevelArray; 192 | } 193 | 194 | sectionLevelArray.setLevel(blockX & 0xF, blockY & 0xF, blockZ & 0xF, (byte) level); 195 | lightUpdatePacketCache = null; 196 | } 197 | 198 | @Override 199 | public int getBlockLightLevel(int blockX, int blockY, int blockZ) { 200 | int sectionIndex = getSectionIndexAligned(blockY); 201 | 202 | SectionLevelArray sectionLevelArray = blockLightArrays[sectionIndex]; 203 | if(sectionLevelArray == null) return 0; 204 | 205 | return sectionLevelArray.getLevel(blockX & 0xF, blockY & 0xF, blockZ & 0xF); 206 | } 207 | 208 | @Override 209 | public void removeBlockLight(int blockX, int blockY, int blockZ) { 210 | int sectionIndex = getSectionIndexAligned(blockY); 211 | 212 | SectionLevelArray sectionLevelArray = blockLightArrays[sectionIndex]; 213 | if(sectionLevelArray == null) return; 214 | 215 | sectionLevelArray.remove(blockX, blockY, blockZ); 216 | lightUpdatePacketCache = null; 217 | } 218 | 219 | @Override 220 | public void setSkyLightLevel(int blockX, int blockY, int blockZ, int level) { 221 | int sectionIndex = getSectionIndexAligned(blockY); 222 | 223 | SectionLevelArray sectionLevelArray = skyLightArrays[sectionIndex]; 224 | if(sectionLevelArray == null){ 225 | sectionLevelArray = new SectionLevelArray(); 226 | skyLightArrays[sectionIndex] = sectionLevelArray; 227 | } 228 | 229 | sectionLevelArray.setLevel(blockX & 0xF, blockY & 0xF, blockZ & 0xF, (byte) level); 230 | lightUpdatePacketCache = null; 231 | } 232 | 233 | @Override 234 | public int getSkyLightLevel(int blockX, int blockY, int blockZ) { 235 | int sectionIndex = getSectionIndexAligned(blockY); 236 | 237 | SectionLevelArray sectionLevelArray = skyLightArrays[sectionIndex]; 238 | if(sectionLevelArray == null) return 0; 239 | 240 | return sectionLevelArray.getLevel(blockX & 0xF, blockY & 0xF, blockZ & 0xF); 241 | } 242 | 243 | @Override 244 | public void removeSkyLight(int blockX, int blockY, int blockZ) { 245 | int sectionIndex = getSectionIndexAligned(blockY); 246 | 247 | SectionLevelArray sectionLevelArray = skyLightArrays[sectionIndex]; 248 | if(sectionLevelArray == null) return; 249 | 250 | sectionLevelArray.remove(blockX, blockY, blockZ); 251 | lightUpdatePacketCache = null; 252 | } 253 | 254 | @Override 255 | public @Nullable SectionLevelArray getBlockLightSectionLevelArray(int sectionY) { 256 | int sectionIndex = getSectionIndexAligned(sectionY << 4); 257 | return blockLightArrays[sectionIndex]; 258 | } 259 | 260 | @Override 261 | public @Nullable SectionLevelArray getSkyLightSectionLevelArray(int sectionY) { 262 | int sectionIndex = getSectionIndexAligned(sectionY << 4); 263 | return skyLightArrays[sectionIndex]; 264 | } 265 | 266 | @Override 267 | public @Nullable SectionTypeArray getSectionTypeArray(int sectionY) { 268 | int sectionIndex = getSectionIndexAligned(sectionY << 4); 269 | return sectionTypeArrays[sectionIndex]; 270 | } 271 | 272 | @Override 273 | public boolean hasBlockData(int blockX, int blockY, int blockZ) { 274 | int sectionIndex = getSectionIndexAligned(blockY); 275 | 276 | SectionTypeArray sectionTypeArray = sectionTypeArrays[sectionIndex]; 277 | if(sectionTypeArray == null) return false; 278 | 279 | return sectionTypeArray.contains(blockX & 0xF, blockY & 0xF, blockZ & 0xF); 280 | } 281 | 282 | @Override 283 | public boolean hasBlockLight(int blockX, int blockY, int blockZ) { 284 | int sectionIndex = getSectionIndexAligned(blockY); 285 | 286 | SectionLevelArray sectionLevelArray = blockLightArrays[sectionIndex]; 287 | if(sectionLevelArray == null) return false; 288 | 289 | return sectionLevelArray.contains(blockX & 0xF, blockY & 0xF, blockZ & 0xF); 290 | } 291 | 292 | @Override 293 | public boolean hasSkyLight(int blockX, int blockY, int blockZ) { 294 | int sectionIndex = getSectionIndexAligned(blockY); 295 | 296 | SectionLevelArray sectionLevelArray = skyLightArrays[sectionIndex]; 297 | if(sectionLevelArray == null) return false; 298 | 299 | return sectionLevelArray.contains(blockX & 0xF, blockY & 0xF, blockZ & 0xF); 300 | } 301 | 302 | @Override 303 | public void sendUpdate(Player player) { 304 | INMSHandler nmsHandler = NMSManager.getNmsHandler(); 305 | 306 | nmsHandler.sendChunkMultiBlockChangeUpdatePacket(player, this); 307 | 308 | TaskHandler.runSync(() -> { 309 | World world = Bukkit.getWorld(getWorld().getName()); 310 | if(world == null) return; 311 | 312 | TaskHandler.runWorldSync(world, () -> { 313 | Object lightUpdatePacket = nmsHandler.createLightUpdatePacketAtPrimaryThread(this); 314 | if(lightUpdatePacket != null) nmsHandler.sendPacket(player, lightUpdatePacket); 315 | }); 316 | }); 317 | } 318 | 319 | public void sendClearPacket(Player player){ 320 | INMSHandler nmsHandler = NMSManager.getNmsHandler(); 321 | 322 | TaskHandler.runSync(() -> { 323 | World world = Bukkit.getWorld(getWorld().getName()); 324 | if(world == null) return; 325 | 326 | TaskHandler.runWorldSync(world, () -> { 327 | nmsHandler.sendClearChunkMultiBlockChangePacketAtPrimaryThread(player, this); 328 | }); 329 | }); 330 | } 331 | 332 | @Override 333 | public @Nullable Object getCachedMapChunkPacket() { 334 | return mapChunkPacketCache; 335 | } 336 | 337 | @Override 338 | public @Nullable Object getCachedLightUpdatePacket() { 339 | return lightUpdatePacketCache; 340 | } 341 | 342 | @Override 343 | public void setMapChunkPacketCache(Object packet) { 344 | this.mapChunkPacketCache = packet; 345 | } 346 | 347 | @Override 348 | public void setLightUpdatePacketCache(Object packet) { 349 | this.lightUpdatePacketCache = packet; 350 | } 351 | 352 | } 353 | -------------------------------------------------------------------------------- /Plugin/src/main/java/be4rjp/parallel/impl/ImplParallelPlayer.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.impl; 2 | 3 | import be4rjp.parallel.ParallelChunk; 4 | import be4rjp.parallel.ParallelUniverse; 5 | import be4rjp.parallel.ParallelWorld; 6 | import be4rjp.parallel.player.ParallelPlayer; 7 | import org.bukkit.Bukkit; 8 | import org.bukkit.entity.Player; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | public class ImplParallelPlayer extends ParallelPlayer { 12 | 13 | public static ParallelPlayer onPlayerJoin(Player player){ 14 | return playerMap.computeIfAbsent(player, ImplParallelPlayer::new); 15 | } 16 | 17 | public static void onPlayerQuit(Player player){ 18 | ParallelPlayer parallelPlayer = playerMap.get(player); 19 | parallelPlayer.setUniverse(null); 20 | playerMap.remove(player); 21 | } 22 | 23 | 24 | 25 | private ImplParallelPlayer(Player player) { 26 | super(player); 27 | } 28 | 29 | @Override 30 | public synchronized @Nullable ParallelUniverse getUniverse() {return currentUniverse;} 31 | 32 | @Override 33 | public synchronized void setUniverse(@Nullable ParallelUniverse parallelUniverse) { 34 | if(currentUniverse == parallelUniverse) return; 35 | 36 | if(currentUniverse != null){ 37 | ((ImplParallelUniverse) currentUniverse).getPlayers().remove(this); 38 | 39 | ParallelWorld currentWorld = currentUniverse.getWorld(player.getWorld().getName()); 40 | this.currentUniverse = parallelUniverse; 41 | 42 | int range = Bukkit.getViewDistance(); 43 | 44 | int chunkX = player.getLocation().getBlockX() >> 4; 45 | int chunkZ = player.getLocation().getBlockZ() >> 4; 46 | 47 | for(int x = -range; x < range; x++){ 48 | for(int z = -range; z < range; z++){ 49 | ParallelChunk chunk = currentWorld.getChunk(chunkX + x, chunkZ + z); 50 | if(chunk == null) continue; 51 | 52 | ((ImplParallelChunk) chunk).sendClearPacket(player); 53 | } 54 | } 55 | } 56 | if(parallelUniverse != null){ 57 | ((ImplParallelUniverse) parallelUniverse).getPlayers().add(this); 58 | 59 | ParallelWorld nextWorld = parallelUniverse.getWorld(player.getWorld().getName()); 60 | this.currentUniverse = parallelUniverse; 61 | 62 | int range = Bukkit.getViewDistance(); 63 | 64 | int chunkX = player.getLocation().getBlockX() >> 4; 65 | int chunkZ = player.getLocation().getBlockZ() >> 4; 66 | 67 | for(int x = -range; x < range; x++){ 68 | for(int z = -range; z < range; z++){ 69 | ParallelChunk chunk = nextWorld.getChunk(chunkX + x, chunkZ + z); 70 | if(chunk == null) continue; 71 | 72 | chunk.sendUpdate(player); 73 | } 74 | } 75 | } 76 | 77 | this.currentUniverse = parallelUniverse; 78 | } 79 | 80 | public void setUniverseRaw(ParallelUniverse universe){this.currentUniverse = universe;} 81 | 82 | } 83 | -------------------------------------------------------------------------------- /Plugin/src/main/java/be4rjp/parallel/impl/ImplParallelUniverse.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.impl; 2 | 3 | import be4rjp.parallel.ParallelChunk; 4 | import be4rjp.parallel.ParallelUniverse; 5 | import be4rjp.parallel.ParallelWorld; 6 | import be4rjp.parallel.nms.NMSManager; 7 | import be4rjp.parallel.player.ParallelPlayer; 8 | import be4rjp.parallel.util.SectionLevelArray; 9 | import be4rjp.parallel.util.SectionTypeArray; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | import java.util.Collection; 13 | import java.util.HashSet; 14 | import java.util.Map; 15 | import java.util.Set; 16 | import java.util.concurrent.ConcurrentHashMap; 17 | 18 | public class ImplParallelUniverse implements ParallelUniverse { 19 | 20 | private final String universeName; 21 | 22 | private final Set players = ConcurrentHashMap.newKeySet(); 23 | 24 | public ImplParallelUniverse(String universeName){ 25 | this.universeName = universeName; 26 | } 27 | 28 | @Override 29 | public @NotNull String getName() {return universeName;} 30 | 31 | 32 | private final Map parallelWorldMap = new ConcurrentHashMap<>(); 33 | 34 | @Override 35 | public @NotNull ParallelWorld getWorld(String worldName) { 36 | return parallelWorldMap.computeIfAbsent(worldName, name -> new ImplParallelWorld(this, worldName)); 37 | } 38 | 39 | @Override 40 | public void addPlayer(@NotNull ParallelPlayer player) {player.setUniverse(this);} 41 | 42 | @Override 43 | public void removePlayer(@NotNull ParallelPlayer player) {player.setUniverse(null);} 44 | 45 | @Override 46 | public Set getResidents() {return new HashSet<>(players);} 47 | 48 | @Override 49 | public Collection getAllWorld() {return parallelWorldMap.values();} 50 | 51 | @Override 52 | public void addDiffs(ParallelUniverse universe) { 53 | int indexStart = NMSManager.isHigher_v1_18_R1() ? -4 : 0; 54 | int indexEnd = NMSManager.isHigher_v1_18_R1() ? 20 : 16; 55 | 56 | for(ParallelWorld diffWorld : universe.getAllWorld()){ 57 | for(ParallelChunk diffChunk : diffWorld.getAllChunk()){ 58 | for(int i = indexStart; i < indexEnd; i++){ 59 | ParallelWorld thisWorld = null; 60 | ParallelChunk thisChunk = null; 61 | 62 | SectionTypeArray sectionTypeArray = diffChunk.getSectionTypeArray(i); 63 | if(sectionTypeArray != null) { 64 | thisWorld = this.getWorld(diffWorld.getName()); 65 | thisChunk = ((ImplParallelWorld) thisWorld).createChunkIfAbsent(diffChunk.getChunkX(), diffChunk.getChunkZ()); 66 | SectionTypeArray thisType = ((ImplParallelChunk) thisChunk).createSectionTypeArrayIfAbsent(i); 67 | 68 | sectionTypeArray.threadsafeIteration(thisType::setType); 69 | } 70 | 71 | SectionLevelArray blockLightLevelArray = diffChunk.getBlockLightSectionLevelArray(i); 72 | if(blockLightLevelArray != null){ 73 | if(thisWorld == null) thisWorld = this.getWorld(diffWorld.getName()); 74 | if(thisChunk == null) thisChunk = ((ImplParallelWorld) thisWorld).createChunkIfAbsent(diffChunk.getChunkX(), diffChunk.getChunkZ()); 75 | SectionLevelArray thisLevel = ((ImplParallelChunk) thisChunk).createBlockLightSectionLevelArrayIfAbsent(i); 76 | 77 | blockLightLevelArray.threadsafeIteration(thisLevel::setLevel); 78 | } 79 | 80 | SectionLevelArray skyLightLevelArray = diffChunk.getSkyLightSectionLevelArray(i); 81 | if(skyLightLevelArray != null){ 82 | if(thisWorld == null) thisWorld = this.getWorld(diffWorld.getName()); 83 | if(thisChunk == null) thisChunk = ((ImplParallelWorld) thisWorld).createChunkIfAbsent(diffChunk.getChunkX(), diffChunk.getChunkZ()); 84 | SectionLevelArray thisLevel = ((ImplParallelChunk) thisChunk).createSkyLightSectionLevelArrayIfAbsent(i); 85 | 86 | skyLightLevelArray.threadsafeIteration(thisLevel::setLevel); 87 | } 88 | } 89 | } 90 | } 91 | 92 | 93 | for(ParallelPlayer parallelPlayer : this.getResidents()){ 94 | ((ImplParallelPlayer) parallelPlayer).setUniverseRaw(null); 95 | parallelPlayer.setUniverse(this); 96 | } 97 | } 98 | 99 | public Set getPlayers() {return players;} 100 | } 101 | -------------------------------------------------------------------------------- /Plugin/src/main/java/be4rjp/parallel/impl/ImplParallelWorld.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.impl; 2 | 3 | import be4rjp.parallel.ParallelChunk; 4 | import be4rjp.parallel.ParallelUniverse; 5 | import be4rjp.parallel.ParallelWorld; 6 | import be4rjp.parallel.nms.INMSHandler; 7 | import be4rjp.parallel.nms.NMSManager; 8 | import be4rjp.parallel.util.BlockPosition3i; 9 | import be4rjp.parallel.util.ChunkUtil; 10 | import org.bukkit.Material; 11 | import org.bukkit.block.data.BlockData; 12 | import org.jetbrains.annotations.NotNull; 13 | import org.jetbrains.annotations.Nullable; 14 | 15 | import java.util.Collection; 16 | import java.util.Map; 17 | import java.util.Set; 18 | import java.util.concurrent.ConcurrentHashMap; 19 | 20 | public class ImplParallelWorld implements ParallelWorld { 21 | 22 | private final ParallelUniverse parallelUniverse; 23 | 24 | private final String worldName; 25 | 26 | public ImplParallelWorld(ParallelUniverse parallelUniverse, String worldName){ 27 | this.parallelUniverse = parallelUniverse; 28 | this.worldName = worldName; 29 | } 30 | 31 | public String getWorldName() {return worldName;} 32 | 33 | 34 | 35 | private final Map chunkMap = new ConcurrentHashMap<>(); 36 | 37 | public ParallelChunk createChunkIfAbsent(int chunkX, int chunkZ){ 38 | return chunkMap.computeIfAbsent(ChunkUtil.getCoordinateKey(chunkX, chunkZ), key -> new ImplParallelChunk(this, chunkX, chunkZ)); 39 | } 40 | 41 | @Override 42 | public String getName() { 43 | return worldName; 44 | } 45 | 46 | @Override 47 | public @NotNull ParallelUniverse getParallelUniverse() { 48 | return parallelUniverse; 49 | } 50 | 51 | @Override 52 | public void setType(int blockX, int blockY, int blockZ, Material material) { 53 | int chunkX = blockX >> 4; 54 | int chunkZ = blockZ >> 4; 55 | long coord = ChunkUtil.getCoordinateKey(chunkX, chunkZ); 56 | 57 | ParallelChunk parallelChunk = chunkMap.computeIfAbsent(coord, c -> new ImplParallelChunk(this, chunkX, chunkZ)); 58 | parallelChunk.setType(blockX, blockY, blockZ, material); 59 | } 60 | 61 | @Override 62 | public @Nullable Material getType(int blockX, int blockY, int blockZ) { 63 | int chunkX = blockX >> 4; 64 | int chunkZ = blockZ >> 4; 65 | long coord = ChunkUtil.getCoordinateKey(chunkX, chunkZ); 66 | 67 | ParallelChunk parallelChunk = chunkMap.get(coord); 68 | if(parallelChunk == null) return null; 69 | 70 | return parallelChunk.getType(blockX, blockY, blockZ); 71 | } 72 | 73 | @Override 74 | public void setBlockData(int blockX, int blockY, int blockZ, BlockData blockData) { 75 | int chunkX = blockX >> 4; 76 | int chunkZ = blockZ >> 4; 77 | long coord = ChunkUtil.getCoordinateKey(chunkX, chunkZ); 78 | 79 | ParallelChunk parallelChunk = chunkMap.computeIfAbsent(coord, c -> new ImplParallelChunk(this, chunkX, chunkZ)); 80 | parallelChunk.setBlockData(blockX, blockY, blockZ, blockData); 81 | } 82 | 83 | @Override 84 | public @Nullable BlockData getBlockData(int blockX, int blockY, int blockZ) { 85 | int chunkX = blockX >> 4; 86 | int chunkZ = blockZ >> 4; 87 | long coord = ChunkUtil.getCoordinateKey(chunkX, chunkZ); 88 | 89 | ParallelChunk parallelChunk = chunkMap.get(coord); 90 | if(parallelChunk == null) return null; 91 | 92 | return parallelChunk.getBlockData(blockX, blockY, blockZ); 93 | } 94 | 95 | @Override 96 | public @Nullable Object getNMSBlockData(int blockX, int blockY, int blockZ) { 97 | int chunkX = blockX >> 4; 98 | int chunkZ = blockZ >> 4; 99 | long coord = ChunkUtil.getCoordinateKey(chunkX, chunkZ); 100 | 101 | ParallelChunk parallelChunk = chunkMap.get(coord); 102 | if(parallelChunk == null) return null; 103 | 104 | return parallelChunk.getNMSBlockData(blockX, blockY, blockZ); 105 | } 106 | 107 | @Override 108 | public void removeBlockData(int blockX, int blockY, int blockZ) { 109 | int chunkX = blockX >> 4; 110 | int chunkZ = blockZ >> 4; 111 | long coord = ChunkUtil.getCoordinateKey(chunkX, chunkZ); 112 | 113 | ParallelChunk parallelChunk = chunkMap.get(coord); 114 | if(parallelChunk == null) return; 115 | 116 | parallelChunk.removeBlockData(blockX, blockY, blockZ); 117 | } 118 | 119 | @Override 120 | public void setBlockLightLevel(int blockX, int blockY, int blockZ, int level) { 121 | int chunkX = blockX >> 4; 122 | int chunkZ = blockZ >> 4; 123 | long coord = ChunkUtil.getCoordinateKey(chunkX, chunkZ); 124 | 125 | ParallelChunk parallelChunk = chunkMap.computeIfAbsent(coord, c -> new ImplParallelChunk(this, chunkX, chunkZ)); 126 | parallelChunk.setBlockLightLevel(blockX, blockY, blockZ, level); 127 | } 128 | 129 | @Override 130 | public int getBlockLightLevel(int blockX, int blockY, int blockZ) { 131 | int chunkX = blockX >> 4; 132 | int chunkZ = blockZ >> 4; 133 | long coord = ChunkUtil.getCoordinateKey(chunkX, chunkZ); 134 | 135 | ParallelChunk parallelChunk = chunkMap.get(coord); 136 | if(parallelChunk == null) return 0; 137 | 138 | return parallelChunk.getBlockLightLevel(blockX, blockY, blockZ); 139 | } 140 | 141 | @Override 142 | public void removeBlockLight(int blockX, int blockY, int blockZ) { 143 | int chunkX = blockX >> 4; 144 | int chunkZ = blockZ >> 4; 145 | long coord = ChunkUtil.getCoordinateKey(chunkX, chunkZ); 146 | 147 | ParallelChunk parallelChunk = chunkMap.get(coord); 148 | if(parallelChunk == null) return; 149 | 150 | parallelChunk.removeBlockLight(blockX, blockY, blockZ); 151 | } 152 | 153 | @Override 154 | public void setSkyLightLevel(int blockX, int blockY, int blockZ, int level) { 155 | int chunkX = blockX >> 4; 156 | int chunkZ = blockZ >> 4; 157 | long coord = ChunkUtil.getCoordinateKey(chunkX, chunkZ); 158 | 159 | ParallelChunk parallelChunk = chunkMap.computeIfAbsent(coord, c -> new ImplParallelChunk(this, chunkX, chunkZ)); 160 | parallelChunk.setSkyLightLevel(blockX, blockY, blockZ, level); 161 | } 162 | 163 | @Override 164 | public int getSkyLightLevel(int blockX, int blockY, int blockZ) { 165 | int chunkX = blockX >> 4; 166 | int chunkZ = blockZ >> 4; 167 | long coord = ChunkUtil.getCoordinateKey(chunkX, chunkZ); 168 | 169 | ParallelChunk parallelChunk = chunkMap.get(coord); 170 | if(parallelChunk == null) return 0; 171 | 172 | return parallelChunk.getSkyLightLevel(blockX, blockY, blockZ); 173 | } 174 | 175 | @Override 176 | public void removeSkyLight(int blockX, int blockY, int blockZ) { 177 | int chunkX = blockX >> 4; 178 | int chunkZ = blockZ >> 4; 179 | long coord = ChunkUtil.getCoordinateKey(chunkX, chunkZ); 180 | 181 | ParallelChunk parallelChunk = chunkMap.get(coord); 182 | if(parallelChunk == null) return; 183 | 184 | parallelChunk.removeSkyLight(blockX, blockY, blockZ); 185 | } 186 | 187 | @Override 188 | public boolean hasBlockData(int blockX, int blockY, int blockZ) { 189 | int chunkX = blockX >> 4; 190 | int chunkZ = blockZ >> 4; 191 | long coord = ChunkUtil.getCoordinateKey(chunkX, chunkZ); 192 | 193 | ParallelChunk parallelChunk = chunkMap.get(coord); 194 | if(parallelChunk == null) return false; 195 | 196 | return parallelChunk.hasBlockData(blockX, blockY, blockZ); 197 | } 198 | 199 | @Override 200 | public boolean hasBlockLight(int blockX, int blockY, int blockZ) { 201 | int chunkX = blockX >> 4; 202 | int chunkZ = blockZ >> 4; 203 | long coord = ChunkUtil.getCoordinateKey(chunkX, chunkZ); 204 | 205 | ParallelChunk parallelChunk = chunkMap.get(coord); 206 | if(parallelChunk == null) return false; 207 | 208 | return parallelChunk.hasBlockLight(blockX, blockY, blockZ); 209 | } 210 | 211 | @Override 212 | public boolean hasSkyLight(int blockX, int blockY, int blockZ) { 213 | int chunkX = blockX >> 4; 214 | int chunkZ = blockZ >> 4; 215 | long coord = ChunkUtil.getCoordinateKey(chunkX, chunkZ); 216 | 217 | ParallelChunk parallelChunk = chunkMap.get(coord); 218 | if(parallelChunk == null) return false; 219 | 220 | return parallelChunk.hasSkyLight(blockX, blockY, blockZ); 221 | } 222 | 223 | @Override 224 | public ParallelChunk getChunk(int chunkX, int chunkZ){return chunkMap.get(ChunkUtil.getCoordinateKey(chunkX, chunkZ));} 225 | 226 | @Override 227 | public void sendBlockUpdate(int blockX, int blockY, int blockZ) { 228 | INMSHandler nmsHandler = NMSManager.getNmsHandler(); 229 | Object packet = nmsHandler.createBlockChangePacket(this, blockX, blockY, blockZ); 230 | if(packet != null){ 231 | parallelUniverse.getResidents().forEach(player -> { 232 | if(worldName.equals(player.getBukkitPlayer().getWorld().getName())) nmsHandler.sendPacket(player.getBukkitPlayer(), packet); 233 | }); 234 | } 235 | } 236 | 237 | @Override 238 | public void sendMultiBlockUpdate(Set blocks) { 239 | INMSHandler nmsHandler = NMSManager.getNmsHandler(); 240 | Set packets = nmsHandler.createMultiBlockChangePacket(this, blocks); 241 | for(Object packet : packets){ 242 | parallelUniverse.getResidents().forEach(player -> { 243 | if(worldName.equals(player.getBukkitPlayer().getWorld().getName())) nmsHandler.sendPacket(player.getBukkitPlayer(), packet); 244 | }); 245 | } 246 | } 247 | 248 | @Override 249 | public Collection getAllChunk() {return chunkMap.values();} 250 | 251 | } 252 | -------------------------------------------------------------------------------- /Plugin/src/main/java/be4rjp/parallel/nms/NMSManager.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.nms; 2 | 3 | import org.bukkit.Bukkit; 4 | 5 | import java.lang.reflect.InvocationTargetException; 6 | 7 | public class NMSManager { 8 | 9 | private static String version; 10 | 11 | private static boolean isHigher_v1_18_R1; 12 | 13 | private static Class getImplClass(String className) 14 | throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException{ 15 | return Class.forName("be4rjp.parallel." + version + "." + className); 16 | } 17 | 18 | public static String getVersion() {return version;} 19 | 20 | public static boolean isHigher_v1_18_R1() {return isHigher_v1_18_R1;} 21 | 22 | 23 | private static INMSHandler nmsHandler; 24 | 25 | public static INMSHandler getNmsHandler() {return nmsHandler;} 26 | 27 | 28 | private static IPacketHandler mapChunkPacketHandler; 29 | private static IPacketHandler blockChangePacketHandler; 30 | private static IPacketHandler multiBlockChangePacketHandler; 31 | private static IPacketHandler lightUpdatePacketHandler; 32 | private static IPacketHandler flyPacketHandler; 33 | 34 | 35 | public static IPacketHandler getBlockChangePacketHandler() {return blockChangePacketHandler;} 36 | 37 | public static IPacketHandler getMapChunkPacketHandler() {return mapChunkPacketHandler;} 38 | 39 | public static IPacketHandler getFlyPacketHandler() {return flyPacketHandler;} 40 | 41 | public static IPacketHandler getMultiBlockChangePacketHandler() {return multiBlockChangePacketHandler;} 42 | 43 | public static IPacketHandler getLightUpdatePacketHandler() {return lightUpdatePacketHandler;} 44 | 45 | 46 | public static void setup(){ 47 | String packageName = Bukkit.getServer().getClass().getPackage().getName(); 48 | version = packageName.substring(packageName.lastIndexOf('.') + 1); 49 | 50 | isHigher_v1_18_R1 = Integer.parseInt(version.split("_")[1]) >= 18; 51 | 52 | try{ 53 | Class nmsHandlerClass = getImplClass("NMSHandler"); 54 | nmsHandler = (INMSHandler) nmsHandlerClass.getConstructor().newInstance(); 55 | 56 | Class MapChunkPacketHandler = getImplClass("MapChunkPacketHandler"); 57 | Class BlockChangePacketHandler = getImplClass("BlockChangePacketHandler"); 58 | Class MultiBlockChangePacketHandler = getImplClass("MultiBlockChangePacketHandler"); 59 | Class LightUpdatePacketHandler = getImplClass("LightUpdatePacketHandler"); 60 | Class FlyPacketHandler = getImplClass("FlyPacketHandler"); 61 | 62 | mapChunkPacketHandler = (IPacketHandler) MapChunkPacketHandler.getConstructor().newInstance(); 63 | blockChangePacketHandler = (IPacketHandler) BlockChangePacketHandler.getConstructor().newInstance(); 64 | multiBlockChangePacketHandler = (IPacketHandler) MultiBlockChangePacketHandler.getConstructor().newInstance(); 65 | lightUpdatePacketHandler = (IPacketHandler) LightUpdatePacketHandler.getConstructor().newInstance(); 66 | flyPacketHandler = (IPacketHandler) FlyPacketHandler.getConstructor().newInstance(); 67 | 68 | }catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e){ 69 | e.printStackTrace(); 70 | 71 | throw new IllegalStateException("This version is not supported!" 72 | + System.lineSeparator() + "Server version : " + version); 73 | } 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /Plugin/src/main/java/be4rjp/parallel/nms/PacketHandler.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.nms; 2 | 3 | import be4rjp.parallel.Config; 4 | import be4rjp.parallel.player.ParallelPlayer; 5 | import io.netty.channel.*; 6 | 7 | 8 | public class PacketHandler extends ChannelDuplexHandler{ 9 | 10 | private final ParallelPlayer parallelPlayer; 11 | 12 | public PacketHandler(ParallelPlayer parallelPlayer){this.parallelPlayer = parallelPlayer;} 13 | 14 | @Override 15 | public void channelRead(ChannelHandlerContext channelHandlerContext, Object packet) throws Exception { 16 | 17 | INMSHandler nmsHandler = NMSManager.getNmsHandler(); 18 | 19 | if(nmsHandler.isFlyPacket(packet)){ 20 | super.channelRead(channelHandlerContext, NMSManager.getFlyPacketHandler().rewrite(packet, parallelPlayer, Config.isPerformanceMode())); 21 | return; 22 | } 23 | 24 | super.channelRead(channelHandlerContext, packet); 25 | } 26 | 27 | @Override 28 | public void write(ChannelHandlerContext channelHandlerContext, Object packet, ChannelPromise channelPromise) throws Exception { 29 | 30 | INMSHandler nmsHandler = NMSManager.getNmsHandler(); 31 | 32 | if(nmsHandler.isMapChunkPacket(packet)){ 33 | super.write(channelHandlerContext, NMSManager.getMapChunkPacketHandler().rewrite(packet, parallelPlayer, Config.isPerformanceMode()), channelPromise); 34 | return; 35 | } 36 | 37 | if(nmsHandler.isLightUpdatePacket(packet) && Config.isRewriteLightPacket()){ 38 | super.write(channelHandlerContext, NMSManager.getLightUpdatePacketHandler().rewrite(packet, parallelPlayer, Config.isPerformanceMode()), channelPromise); 39 | return; 40 | } 41 | 42 | if(nmsHandler.isBlockChangePacket(packet)){ 43 | super.write(channelHandlerContext, NMSManager.getBlockChangePacketHandler().rewrite(packet, parallelPlayer, Config.isPerformanceMode()), channelPromise); 44 | return; 45 | } 46 | 47 | if(nmsHandler.isMultiBlockChangePacket(packet)){ 48 | super.write(channelHandlerContext, NMSManager.getMultiBlockChangePacketHandler().rewrite(packet, parallelPlayer, Config.isPerformanceMode()), channelPromise); 49 | return; 50 | } 51 | 52 | super.write(channelHandlerContext, packet, channelPromise); 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /Plugin/src/main/java/be4rjp/parallel/structure/ImplStructureData.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.structure; 2 | 3 | import be4rjp.parallel.Parallel; 4 | import be4rjp.parallel.nms.NMSManager; 5 | import be4rjp.parallel.util.BlockPosition3i; 6 | import org.bukkit.Location; 7 | import org.bukkit.block.Block; 8 | import org.bukkit.block.data.BlockData; 9 | import org.bukkit.configuration.file.FileConfiguration; 10 | import org.bukkit.configuration.file.YamlConfiguration; 11 | 12 | import java.io.File; 13 | import java.io.IOException; 14 | import java.util.ArrayList; 15 | import java.util.HashMap; 16 | import java.util.List; 17 | import java.util.Map; 18 | 19 | public class ImplStructureData extends StructureData{ 20 | 21 | public ImplStructureData(String name) { 22 | super(name); 23 | } 24 | 25 | /** 26 | * 全ての構造物データを読み込む 27 | */ 28 | public static void loadAllStructureData() { 29 | initialize(); 30 | 31 | Parallel.getPlugin().getLogger().info("Loading structure data..."); 32 | File dir = new File("plugins/Parallel/structure_data"); 33 | 34 | dir.getParentFile().mkdir(); 35 | dir.mkdir(); 36 | File[] files = dir.listFiles(); 37 | if (files.length == 0) { 38 | //Parallel.getPlugin().saveResource("structure_data/sample-data.yml", false); 39 | files = dir.listFiles(); 40 | } 41 | 42 | if (files != null) { 43 | for (File file : files) { 44 | Parallel.getPlugin().getLogger().info(file.getName()); 45 | String name = file.getName().replace(".yml", ""); 46 | 47 | ImplStructureData data = new ImplStructureData(name); 48 | data.loadData(); 49 | } 50 | } 51 | } 52 | 53 | 54 | /** 55 | * ymlファイルから読み込み 56 | */ 57 | public void loadData(){ 58 | this.blockDataMap.clear(); 59 | 60 | File file = new File("plugins/Parallel/structure_data", name + ".yml"); 61 | createFile(file); 62 | 63 | FileConfiguration yml = YamlConfiguration.loadConfiguration(file); 64 | List lines = yml.getStringList("blocks"); 65 | //x, y, z, CombinedId 66 | for(String line : lines){ 67 | line = line.replace(" ", ""); 68 | String[] args = line.split(","); 69 | 70 | int x = Integer.parseInt(args[0]); 71 | int y = Integer.parseInt(args[1]); 72 | int z = Integer.parseInt(args[2]); 73 | 74 | BlockPosition3i relative = new BlockPosition3i(x, y, z); 75 | int id = Integer.parseInt(args[3]); 76 | Object iBlockData = NMSManager.getNmsHandler().getIBlockDataByCombinedId(id); 77 | this.blockDataMap.put(relative, NMSManager.getNmsHandler().getBukkitBlockData(iBlockData)); 78 | } 79 | 80 | if(yml.contains("block-lights")) { 81 | lines = yml.getStringList("block-lights"); 82 | //x, y, z, lightLevel 83 | for (String line : lines) { 84 | line = line.replace(" ", ""); 85 | String[] args = line.split(","); 86 | 87 | int x = Integer.parseInt(args[0]); 88 | int y = Integer.parseInt(args[1]); 89 | int z = Integer.parseInt(args[2]); 90 | 91 | BlockPosition3i relative = new BlockPosition3i(x, y, z); 92 | int lightLevel = Integer.parseInt(args[3]); 93 | this.blockLightLevelMap.put(relative, lightLevel); 94 | } 95 | } 96 | } 97 | 98 | 99 | /** 100 | * ymlファイルへ書き込み 101 | */ 102 | public void saveData(){ 103 | File file = new File("plugins/Parallel/structure_data", name + ".yml"); 104 | FileConfiguration yml = new YamlConfiguration(); 105 | 106 | List lines = new ArrayList<>(); 107 | for(Map.Entry entry : this.blockDataMap.entrySet()){ 108 | BlockPosition3i relative = entry.getKey(); 109 | 110 | try { 111 | Object iBlockData = NMSManager.getNmsHandler().getIBlockData(entry.getValue()); 112 | int id = NMSManager.getNmsHandler().getCombinedIdByIBlockData(iBlockData); 113 | 114 | String line = relative.getX() + ", " + relative.getY() + ", " + relative.getZ() + ", " + id; 115 | lines.add(line); 116 | } catch (Exception e) { 117 | e.printStackTrace(); 118 | } 119 | } 120 | yml.set("blocks", lines); 121 | 122 | List lines2 = new ArrayList<>(); 123 | for(Map.Entry entry : this.blockLightLevelMap.entrySet()){ 124 | BlockPosition3i relative = entry.getKey(); 125 | int lightLevel = entry.getValue(); 126 | 127 | String line = relative.getX() + ", " + relative.getY() + ", " + relative.getZ() + ", " + lightLevel; 128 | lines2.add(line); 129 | } 130 | yml.set("block-lights", lines2); 131 | 132 | 133 | try { 134 | yml.save(file); 135 | } catch (IOException e) { 136 | e.printStackTrace(); 137 | } 138 | } 139 | 140 | 141 | /** 142 | * ファイルが存在しなければ作成する 143 | * @param file 144 | */ 145 | public void createFile(File file){ 146 | file.getParentFile().mkdir(); 147 | if(!file.exists()){ 148 | try { 149 | file.createNewFile(); 150 | } catch (IOException e) { 151 | e.printStackTrace(); 152 | } 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /Plugin/src/main/java/be4rjp/parallel/structure/ParallelStructure.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.structure; 2 | 3 | import be4rjp.parallel.Parallel; 4 | import be4rjp.parallel.ParallelUniverse; 5 | import be4rjp.parallel.ParallelWorld; 6 | import be4rjp.parallel.enums.UpdatePacketType; 7 | import be4rjp.parallel.player.ParallelPlayer; 8 | import be4rjp.parallel.util.BlockPosition3i; 9 | import org.bukkit.Location; 10 | import org.bukkit.block.Block; 11 | import org.bukkit.block.data.BlockData; 12 | import org.bukkit.configuration.file.FileConfiguration; 13 | import org.bukkit.configuration.file.YamlConfiguration; 14 | import org.bukkit.entity.Player; 15 | 16 | import javax.annotation.Nullable; 17 | import java.io.File; 18 | import java.io.IOException; 19 | import java.util.*; 20 | 21 | public class ParallelStructure { 22 | 23 | private static Map structureMap; 24 | 25 | static { 26 | initialize(); 27 | } 28 | 29 | public static void initialize(){ 30 | structureMap = new HashMap<>(); 31 | } 32 | 33 | public static ParallelStructure getParallelStructure(String name){ 34 | return structureMap.get(name); 35 | } 36 | 37 | public static Map getStructureMap() {return structureMap;} 38 | 39 | /** 40 | * 全ての構造物を読み込む 41 | */ 42 | public static void loadAllParallelStructure() { 43 | initialize(); 44 | 45 | Parallel.getPlugin().getLogger().info("Loading structures..."); 46 | File dir = new File("plugins/Parallel/structures"); 47 | 48 | dir.getParentFile().mkdir(); 49 | dir.mkdir(); 50 | File[] files = dir.listFiles(); 51 | if (files.length == 0) { 52 | //Parallel.getPlugin().saveResource("structures/sample-structure.yml", false); 53 | files = dir.listFiles(); 54 | } 55 | 56 | if (files != null) { 57 | for (File file : files) { 58 | Parallel.getPlugin().getLogger().info(file.getName()); 59 | String name = file.getName().replace(".yml", ""); 60 | ParallelStructure parallelStructure = new ParallelStructure(name); 61 | parallelStructure.loadData(); 62 | } 63 | } 64 | } 65 | 66 | 67 | 68 | private final String name; 69 | private Location baseLocation; 70 | private Map> dataMap = new HashMap<>(); 71 | 72 | public ParallelStructure(String name){ 73 | this.name = name; 74 | structureMap.put(name, this); 75 | } 76 | 77 | public void setBaseLocation(Location baseLocation){this.baseLocation = baseLocation;} 78 | 79 | 80 | public Location getBaseLocation() {return this.baseLocation.clone();} 81 | 82 | 83 | /** 84 | * この構造物を指定された構造物データで上書きして特定のプレイヤーへ見せる 85 | * @param player 構造物を変化させて見せるプレイヤー 86 | * @param implStructureData 構造物データ 87 | */ 88 | public void setStructureData(Player player, ImplStructureData implStructureData){ 89 | ParallelPlayer parallelPlayer = ParallelPlayer.getParallelPlayer(player); 90 | if(parallelPlayer == null) return; 91 | 92 | this.setStructureData(parallelPlayer, implStructureData); 93 | } 94 | 95 | /** 96 | * この構造物を指定された構造物データを適応して特定のプレイヤーへ見せる 97 | * @param parallelPlayer 構造物を変化させて見せるプレイヤー 98 | * @param implStructureData 構造物データ 99 | */ 100 | public void setStructureData(ParallelPlayer parallelPlayer, ImplStructureData implStructureData) { 101 | this.setStructureData(parallelPlayer, implStructureData, UpdatePacketType.MULTI_BLOCK_CHANGE); 102 | } 103 | 104 | /** 105 | * この構造物を指定された構造物データを適応して特定のプレイヤーへ見せる 106 | * @param parallelPlayer 構造物を変化させて見せるプレイヤー 107 | * @param implStructureData 構造物データ 108 | */ 109 | public void setStructureData(ParallelPlayer parallelPlayer, ImplStructureData implStructureData, @Nullable UpdatePacketType type){ 110 | clearStructureData(parallelPlayer, false); 111 | 112 | ParallelUniverse universe = parallelPlayer.getUniverse(); 113 | if(universe == null) return; 114 | 115 | ParallelWorld parallelWorld = universe.getWorld(Objects.requireNonNull(baseLocation.getWorld()).getName()); 116 | 117 | Set blocks = new HashSet<>(); 118 | Set updateBlocks = new HashSet<>(); 119 | for(Map.Entry entry : implStructureData.getBlockDataMap().entrySet()){ 120 | BlockPosition3i relative = entry.getKey(); 121 | Block block = getBaseLocation().add(relative.getX(), relative.getY(), relative.getZ()).getBlock(); 122 | parallelWorld.setBlockData(block.getX(), block.getY(), block.getZ(), entry.getValue()); 123 | blocks.add(block); 124 | updateBlocks.add(new BlockPosition3i(block.getX(), block.getY(), block.getZ())); 125 | } 126 | 127 | for(Map.Entry entry : implStructureData.getBlockLightLevelMap().entrySet()){ 128 | BlockPosition3i relative = entry.getKey(); 129 | Block block = getBaseLocation().add(relative.getX(), relative.getY(), relative.getZ()).getBlock(); 130 | parallelWorld.setBlockLightLevel(block.getX(), block.getY(), block.getZ(), entry.getValue()); 131 | blocks.add(block); 132 | updateBlocks.add(new BlockPosition3i(block.getX(), block.getY(), block.getZ())); 133 | } 134 | 135 | dataMap.put(universe.getName(), blocks); 136 | 137 | parallelWorld.sendMultiBlockUpdate(updateBlocks); 138 | } 139 | 140 | 141 | /** 142 | * 適用されている構造物データを消去します 143 | * @param player 構造物を変化させて見せるプレイヤー 144 | * @param chunkUpdate チャンクアップデートのパケットを送信するかどうか 145 | */ 146 | public void clearStructureData(Player player, boolean chunkUpdate){ 147 | ParallelPlayer parallelPlayer = ParallelPlayer.getParallelPlayer(player); 148 | if(parallelPlayer == null) return; 149 | 150 | this.clearStructureData(parallelPlayer, chunkUpdate); 151 | } 152 | 153 | 154 | /** 155 | * 適用されている構造物データを消去します 156 | * @param parallelPlayer 構造物を変化させて見せるプレイヤー 157 | * @param chunkUpdate チャンクアップデートのパケットを送信するかどうか 158 | */ 159 | public void clearStructureData(ParallelPlayer parallelPlayer, boolean chunkUpdate){ 160 | 161 | ParallelUniverse universe = parallelPlayer.getUniverse(); 162 | if(universe == null) return; 163 | 164 | Set blocks = dataMap.get(universe.getName()); 165 | if(blocks == null) return; 166 | 167 | ParallelWorld parallelWorld = universe.getWorld(Objects.requireNonNull(baseLocation.getWorld()).getName()); 168 | 169 | for(Block block : blocks){ 170 | parallelWorld.removeBlockData(block.getX(), block.getY(), block.getZ()); 171 | } 172 | Set blockPosition3iSet = new HashSet<>(); 173 | blocks.forEach(block -> blockPosition3iSet.add(new BlockPosition3i(block.getX(), block.getY(), block.getZ()))); 174 | 175 | parallelWorld.sendMultiBlockUpdate(blockPosition3iSet); 176 | } 177 | 178 | 179 | /** 180 | * ymlファイルから読み込み 181 | */ 182 | public void loadData() { 183 | File file = new File("plugins/Parallel/structures", name + ".yml"); 184 | createFile(file); 185 | 186 | FileConfiguration yml = YamlConfiguration.loadConfiguration(file); 187 | this.baseLocation = yml.getLocation("base-location"); 188 | } 189 | 190 | 191 | /** 192 | * ymlファイルへ書き込み 193 | */ 194 | public void saveData() { 195 | File file = new File("plugins/Parallel/structures", name + ".yml"); 196 | FileConfiguration yml = new YamlConfiguration(); 197 | 198 | yml.set("base-location", baseLocation); 199 | 200 | try { 201 | yml.save(file); 202 | } catch (IOException e) { 203 | e.printStackTrace(); 204 | } 205 | } 206 | 207 | 208 | /** 209 | * ファイルが存在しなければ作成する 210 | * @param file 211 | */ 212 | public void createFile(File file){ 213 | file.getParentFile().mkdir(); 214 | if(!file.exists()){ 215 | try { 216 | file.createNewFile(); 217 | } catch (IOException e) { 218 | e.printStackTrace(); 219 | } 220 | } 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /Plugin/src/main/java/be4rjp/parallel/util/ChunkUtil.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.util; 2 | 3 | public class ChunkUtil { 4 | 5 | public static long getCoordinateKey(final int x, final int z) {return ((long)z << 32) | (x & 0xFFFFFFFFL);} 6 | 7 | } 8 | -------------------------------------------------------------------------------- /Plugin/src/main/java/be4rjp/parallel/util/RegionBlocks.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.util; 2 | 3 | import org.bukkit.Location; 4 | import org.bukkit.World; 5 | import org.bukkit.block.Block; 6 | import org.bukkit.util.Vector; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | public class RegionBlocks { 12 | private final World world; 13 | 14 | private final Vector maximum; 15 | private final Vector minimum; 16 | 17 | public RegionBlocks(Location firstPoint, Location secondPoint) { 18 | world = firstPoint.getWorld(); 19 | Vector firstVector = firstPoint.toVector(); 20 | Vector secondVector = secondPoint.toVector(); 21 | maximum = Vector.getMaximum(firstVector, secondVector); 22 | minimum = Vector.getMinimum(firstVector, secondVector); 23 | } 24 | 25 | public List getBlocks() { 26 | List blocks = new ArrayList<>(); 27 | for (int y = minimum.getBlockY(); y <= maximum.getBlockY(); y++) { 28 | for (int x = minimum.getBlockX(); x <= maximum.getBlockX(); x++) { 29 | for (int z = minimum.getBlockZ(); z <= maximum.getBlockZ(); z++) { 30 | Block block = world.getBlockAt(x, y, z); 31 | blocks.add(block); 32 | } 33 | } 34 | } 35 | 36 | return blocks; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Plugin/src/main/java/be4rjp/parallel/util/TaskHandler.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.util; 2 | 3 | import be4rjp.parallel.Parallel; 4 | import org.bukkit.Bukkit; 5 | import org.bukkit.World; 6 | import org.bukkit.scheduler.BukkitRunnable; 7 | import world.chiyogami.chiyogamilib.scheduler.WorldThreadRunnable; 8 | 9 | import java.util.concurrent.CompletableFuture; 10 | import java.util.function.Supplier; 11 | 12 | public class TaskHandler{ 13 | 14 | public static CompletableFuture supplySync(Supplier supplier){ 15 | CompletableFuture completableFuture = new CompletableFuture<>(); 16 | new BukkitTaskHandler<>(completableFuture, supplier, false).runTask(Parallel.getPlugin()); 17 | 18 | return completableFuture; 19 | } 20 | 21 | public static CompletableFuture supplyAsync(Supplier supplier){ 22 | CompletableFuture completableFuture = new CompletableFuture<>(); 23 | new BukkitTaskHandler<>(completableFuture, supplier, true).runTaskAsynchronously(Parallel.getPlugin()); 24 | 25 | return completableFuture; 26 | } 27 | 28 | public static CompletableFuture supplyWorldSync(World world, Supplier supplier){ 29 | CompletableFuture completableFuture = new CompletableFuture<>(); 30 | new WorldTaskHandler<>(completableFuture, supplier, world).runTask(Parallel.getPlugin()); 31 | 32 | return completableFuture; 33 | } 34 | 35 | public static void runSync(Runnable runnable){ 36 | Bukkit.getScheduler().runTask(Parallel.getPlugin(), runnable); 37 | } 38 | 39 | public static void runAsync(Runnable runnable){ 40 | Bukkit.getScheduler().runTaskAsynchronously(Parallel.getPlugin(), runnable); 41 | } 42 | 43 | public static void runAsyncImmediately(Runnable runnable){ 44 | Thread thread = new Thread(runnable); 45 | thread.setDaemon(true); 46 | thread.start(); 47 | } 48 | 49 | public static void runWorldSync(World world, Runnable runnable){ 50 | new WorldThreadRunnable(world){ 51 | @Override 52 | public void run() { 53 | runnable.run(); 54 | } 55 | }.runTask(Parallel.getPlugin()); 56 | } 57 | 58 | 59 | private static class BukkitTaskHandler extends BukkitRunnable{ 60 | private final CompletableFuture completableFuture; 61 | private final Supplier supplier; 62 | private final boolean isAsync; 63 | 64 | private BukkitTaskHandler(CompletableFuture completableFuture, Supplier supplier, boolean isAsync){ 65 | this.completableFuture = completableFuture; 66 | this.supplier = supplier; 67 | this.isAsync = isAsync; 68 | } 69 | 70 | @Override 71 | public void run() { 72 | T result = supplier.get(); 73 | 74 | Runnable runnable = () -> completableFuture.complete(result); 75 | if(isAsync){ 76 | TaskHandler.runSync(runnable); 77 | }else{ 78 | TaskHandler.runAsync(runnable); 79 | } 80 | } 81 | } 82 | 83 | 84 | private static class WorldTaskHandler extends WorldThreadRunnable{ 85 | private final CompletableFuture completableFuture; 86 | private final Supplier supplier; 87 | 88 | private WorldTaskHandler(CompletableFuture completableFuture, Supplier supplier, World world){ 89 | super(world); 90 | this.completableFuture = completableFuture; 91 | this.supplier = supplier; 92 | } 93 | 94 | @Override 95 | public void run() { 96 | T result = supplier.get(); 97 | TaskHandler.runAsync(() -> completableFuture.complete(result)); 98 | } 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /Plugin/src/main/resources/config.yml: -------------------------------------------------------------------------------- 1 | # 動作モードの設定 2 | # NORMAL or ONLY_ONE 3 | # ONLY_ONEに設定した場合は全てのプレイヤーに対して同じParallelWorldが使われるようになります 4 | work-type: NORMAL 5 | 6 | # パフォーマンスモードを使用するかどうかの設定 7 | # このプラグイン以外でブロックの設置が行われる可能性のある場合は false 推奨 8 | performance-mode: false 9 | 10 | ## ライトパケットへの介入を行うかどうかの設定 11 | rewrite-light-packet: true 12 | 13 | # 読み込まれていないチャンクのパケットを送信しようとしたときに警告を表示するかどうかの設定 14 | show-chunk-packet-warning: true -------------------------------------------------------------------------------- /Plugin/src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: Parallel 2 | version: ${project.version} 3 | main: be4rjp.parallel.Parallel 4 | api-version: 1.15 5 | softdepend: [WorldEdit, Multiverse-Core, Cinema4C] 6 | depend: [AsyncChunkLib] 7 | #-------------------------------------- 8 | commands: 9 | parallel: 10 | description: Type /parallel help 11 | usage: Type /parallel help 12 | permission: parallel.admin 13 | #-------------------------------------- 14 | permissions: 15 | parallel.admin: 16 | description: admin command. 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Parallel-v2 2 | プレイヤーごとに表示するブロックを変更するためのプラグイン 3 | 4 | このプラグインは他のプラグインからの呼び出しを前提としています 5 | 6 | ### Required 7 | https://github.com/Be4rJP/AsyncChunkLib 8 | 9 | ### Supported version 10 | ``` 11 | 1.15.2, 1.16.5 12 | ``` 13 | 14 | ### maven 15 | ```xml 16 | 17 | 18 | github 19 | https://raw.github.com/Be4rJP/Parallel/mvn-repo/ 20 | 21 | 22 | ``` 23 | 24 | ```xml 25 | 26 | be4rjp 27 | parallel_api 28 | 2.0.2 29 | provided 30 | 31 | ``` 32 | 33 | ### 使用例 34 | 35 | * 別プラグインからブロックを設置 36 | ```java 37 | Player player = ...; 38 | Block block = ...; 39 | 40 | //APIのインスタンスを取得 41 | ParallelAPI api = ParallelAPI.getInstance(); 42 | 43 | //Universeを作成 44 | ParallelUniverse universe = api.createUniverse("TestUniverse"); 45 | 46 | //ParallelPlayerを取得 47 | ParallelPlayer parallelPlayer = api.getParallelPlayer(player); 48 | if(parallelPlayer == null) return; 49 | 50 | //作成したuniverseにプレイヤーを参加させる 51 | universe.addPlayer(parallelPlayer); 52 | 53 | //作成したuniverse内のParallelWorldを取得 54 | ParallelWorld parallelWorld = universe.getWorld(player.getWorld().getName()); 55 | 56 | //指定された座標にブロックをセット 57 | parallelWorld.setType(block.getX(), block.getY(), block.getZ(), Material.REDSTONE_BLOCK); 58 | 59 | //ブロックの変更をプレイヤーに通知 60 | parallelWorld.sendBlockChange(block.getX(), block.getY(), block.getZ()); 61 | ``` 62 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | 6 | UTF-8 7 | 2.0.3 8 | 9 | 10 | be4rjp 11 | parallel_parent 12 | ${revision} 13 | pom 14 | 15 | 16 | 17 | internal.repo 18 | Temporary Staging Repository 19 | file://${project.build.directory}/mvn-repo 20 | 21 | 22 | 23 | 24 | API 25 | v1_15_R1 26 | v1_16_R3 27 | Plugin 28 | 29 | 30 | 31 | 32 | spigotmc-repo 33 | https://hub.spigotmc.org/nexus/content/repositories/snapshots/ 34 | 35 | 36 | sonatype 37 | https://oss.sonatype.org/content/groups/public/ 38 | 39 | 40 | minecraft-libraries 41 | Minecraft Libraries 42 | https://libraries.minecraft.net 43 | 44 | 45 | enginehub-maven 46 | https://maven.enginehub.org/repo/ 47 | 48 | 49 | jitpack.io 50 | https://jitpack.io 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /v1_15_R1/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | parallel_v1_15_R1 5 | jar 6 | ${revision} 7 | 8 | 9 | be4rjp 10 | parallel_parent 11 | ${revision} 12 | 13 | 14 | 15 | 1.8 16 | UTF-8 17 | 18 | 19 | 20 | 21 | 22 | org.apache.maven.plugins 23 | maven-compiler-plugin 24 | 3.8.1 25 | 26 | ${java.version} 27 | ${java.version} 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | org.spigotmc 36 | spigot-api 37 | 1.15.2-R0.1-SNAPSHOT 38 | provided 39 | 40 | 41 | org.spigotmc 42 | spigot 43 | 1.15.2-R0.1-SNAPSHOT 44 | provided 45 | 46 | 47 | be4rjp 48 | parallel_api 49 | jar 50 | ${revision} 51 | 52 | 53 | com.github.Be4rJP 54 | AsyncChunkLib 55 | v1.0.2 56 | provided 57 | 58 | 59 | fastutil 60 | fastutil 61 | 5.0.9 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /v1_15_R1/src/main/java/be4rjp/parallel/v1_15_R1/BlockChangePacketHandler.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.v1_15_R1; 2 | 3 | import be4rjp.parallel.ParallelUniverse; 4 | import be4rjp.parallel.ParallelWorld; 5 | import be4rjp.parallel.nms.IPacketHandler; 6 | import be4rjp.parallel.player.ParallelPlayer; 7 | import net.minecraft.server.v1_15_R1.BlockPosition; 8 | import net.minecraft.server.v1_15_R1.PacketPlayOutBlockChange; 9 | import org.bukkit.Material; 10 | import org.bukkit.block.data.BlockData; 11 | import org.bukkit.craftbukkit.v1_15_R1.block.data.CraftBlockData; 12 | 13 | import java.lang.reflect.Field; 14 | 15 | public class BlockChangePacketHandler implements IPacketHandler { 16 | 17 | public static Field a; 18 | 19 | static { 20 | try { 21 | a = PacketPlayOutBlockChange.class.getDeclaredField("a"); 22 | a.setAccessible(true); 23 | }catch (Exception e){e.printStackTrace();} 24 | } 25 | 26 | @Override 27 | public Object rewrite(Object packet, ParallelPlayer parallelPlayer, boolean cacheSetting) { 28 | 29 | ParallelUniverse universe = parallelPlayer.getUniverse(); 30 | if(universe == null) return packet; 31 | 32 | String worldName = parallelPlayer.getBukkitPlayer().getWorld().getName(); 33 | ParallelWorld parallelWorld = universe.getWorld(worldName); 34 | 35 | try { 36 | PacketPlayOutBlockChange blockChange = (PacketPlayOutBlockChange) packet; 37 | BlockPosition bp = (BlockPosition) a.get(blockChange); 38 | 39 | BlockData blockData = parallelWorld.getBlockData(bp.getX(), bp.getY(), bp.getZ()); 40 | if(blockData == null) return packet; 41 | //if(blockData.getMaterial() == Material.AIR) return packet; 42 | 43 | PacketPlayOutBlockChange newPacket = new PacketPlayOutBlockChange(); 44 | a.set(newPacket, bp); 45 | newPacket.block = ((CraftBlockData) blockData).getState(); 46 | 47 | return newPacket; 48 | }catch (Exception e){e.printStackTrace();} 49 | 50 | return packet; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /v1_15_R1/src/main/java/be4rjp/parallel/v1_15_R1/FlyPacketHandler.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.v1_15_R1; 2 | 3 | import be4rjp.parallel.ParallelUniverse; 4 | import be4rjp.parallel.ParallelWorld; 5 | import be4rjp.parallel.nms.IPacketHandler; 6 | import be4rjp.parallel.player.ParallelPlayer; 7 | import net.minecraft.server.v1_15_R1.EntityPlayer; 8 | import net.minecraft.server.v1_15_R1.PlayerConnection; 9 | import org.bukkit.World; 10 | import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer; 11 | import org.bukkit.util.NumberConversions; 12 | 13 | import java.lang.reflect.Field; 14 | 15 | 16 | public class FlyPacketHandler implements IPacketHandler { 17 | 18 | private static Field C; 19 | private static Field E; 20 | 21 | static { 22 | try { 23 | C = PlayerConnection.class.getDeclaredField("C"); 24 | E = PlayerConnection.class.getDeclaredField("E"); 25 | 26 | C.setAccessible(true); 27 | E.setAccessible(true); 28 | }catch (Exception e){ 29 | e.printStackTrace(); 30 | } 31 | } 32 | 33 | @Override 34 | public Object rewrite(Object packet, ParallelPlayer parallelPlayer, boolean cacheSetting) { 35 | ParallelUniverse universe = parallelPlayer.getUniverse(); 36 | if(universe == null) return packet; 37 | 38 | World world = parallelPlayer.getBukkitPlayer().getWorld(); 39 | String worldName = world.getName(); 40 | ParallelWorld parallelWorld = universe.getWorld(worldName); 41 | 42 | EntityPlayer entityPlayer = ((CraftPlayer) parallelPlayer.getBukkitPlayer()).getHandle(); 43 | 44 | int x = NumberConversions.floor(entityPlayer.locX()); 45 | int y = NumberConversions.floor(entityPlayer.locY()); 46 | int z = NumberConversions.floor(entityPlayer.locZ()); 47 | 48 | int downY = y - 1; 49 | downY = Math.max(0, downY); 50 | 51 | if(parallelWorld.hasBlockData(x, y, z) || parallelWorld.hasBlockData(x, downY, z)){ 52 | try { 53 | PlayerConnection playerConnection = entityPlayer.playerConnection; 54 | C.set(playerConnection, 0); 55 | E.set(playerConnection, 0); 56 | }catch (Exception e){e.printStackTrace();} 57 | } 58 | 59 | return packet; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /v1_15_R1/src/main/java/be4rjp/parallel/v1_15_R1/LightUpdatePacketHandler.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.v1_15_R1; 2 | 3 | import be4rjp.parallel.ParallelChunk; 4 | import be4rjp.parallel.ParallelUniverse; 5 | import be4rjp.parallel.ParallelWorld; 6 | import be4rjp.parallel.nms.IPacketHandler; 7 | import be4rjp.parallel.player.ParallelPlayer; 8 | import be4rjp.parallel.util.SectionLevelArray; 9 | import net.minecraft.server.v1_15_R1.NibbleArray; 10 | import net.minecraft.server.v1_15_R1.PacketPlayOutLightUpdate; 11 | import org.bukkit.World; 12 | 13 | import java.lang.reflect.Field; 14 | import java.util.*; 15 | 16 | public class LightUpdatePacketHandler implements IPacketHandler { 17 | 18 | private static Field a; 19 | private static Field b; 20 | private static Field c; 21 | private static Field d; 22 | private static Field e; 23 | private static Field f; 24 | private static Field g; 25 | private static Field h; 26 | 27 | static { 28 | try { 29 | a = PacketPlayOutLightUpdate.class.getDeclaredField("a"); 30 | b = PacketPlayOutLightUpdate.class.getDeclaredField("b"); 31 | c = PacketPlayOutLightUpdate.class.getDeclaredField("c"); 32 | d = PacketPlayOutLightUpdate.class.getDeclaredField("d"); 33 | e = PacketPlayOutLightUpdate.class.getDeclaredField("e"); 34 | f = PacketPlayOutLightUpdate.class.getDeclaredField("f"); 35 | g = PacketPlayOutLightUpdate.class.getDeclaredField("g"); 36 | h = PacketPlayOutLightUpdate.class.getDeclaredField("h"); 37 | 38 | a.setAccessible(true); 39 | b.setAccessible(true); 40 | c.setAccessible(true); 41 | d.setAccessible(true); 42 | e.setAccessible(true); 43 | f.setAccessible(true); 44 | g.setAccessible(true); 45 | h.setAccessible(true); 46 | }catch (Exception e){e.printStackTrace();} 47 | } 48 | 49 | @Override 50 | public Object rewrite(Object packet, ParallelPlayer parallelPlayer, boolean cacheSetting) { 51 | 52 | ParallelUniverse universe = parallelPlayer.getUniverse(); 53 | if(universe == null) return packet; 54 | 55 | World world = parallelPlayer.getBukkitPlayer().getWorld(); 56 | String worldName = world.getName(); 57 | ParallelWorld parallelWorld = universe.getWorld(worldName); 58 | 59 | try{ 60 | 61 | int chunkX = a.getInt(packet); 62 | int chunkZ = b.getInt(packet); 63 | 64 | ParallelChunk parallelChunk = parallelWorld.getChunk(chunkX, chunkZ); 65 | if(parallelChunk == null) return packet; 66 | 67 | Object cachedPacket = parallelChunk.getCachedLightUpdatePacket(); 68 | if(cachedPacket != null) return cachedPacket; 69 | 70 | int cValue = c.getInt(packet); 71 | int dValue = d.getInt(packet); 72 | int eValue = e.getInt(packet); 73 | int fValue = f.getInt(packet); 74 | Deque gValue = new ArrayDeque<>((List) g.get(packet)); 75 | Deque hValue = new ArrayDeque<>((List) h.get(packet)); 76 | 77 | int newC = 0; 78 | int newD = 0; 79 | int newE = 0; 80 | int newF = 0; 81 | List newG = new ArrayList<>(); 82 | List newH = new ArrayList<>(); 83 | 84 | boolean edited = false; 85 | 86 | for(int index = 0; index < 18; index++){ 87 | int sectionIndex = index - 1; 88 | 89 | int cSectionBit = cValue & (1 << index); 90 | newC |= cSectionBit; 91 | newE |= eValue & (1 << index); 92 | 93 | int dSectionBit = dValue & (1 << index); 94 | newD |= dSectionBit; 95 | newF |= fValue & (1 << index); 96 | 97 | if(index == 0 || index == 17){ 98 | 99 | if(cSectionBit != 0){ 100 | newG.add(gValue.removeFirst()); 101 | } 102 | 103 | if(dSectionBit != 0){ 104 | newH.add(hValue.removeFirst()); 105 | } 106 | continue; 107 | } 108 | 109 | 110 | SectionLevelArray skyLevelArray = parallelChunk.getSkyLightSectionLevelArray(sectionIndex); 111 | SectionLevelArray blockLevelArray = parallelChunk.getBlockLightSectionLevelArray(sectionIndex); 112 | 113 | if(skyLevelArray == null){ 114 | if(cSectionBit != 0){ 115 | newG.add(gValue.removeFirst()); 116 | } 117 | }else { 118 | if(cSectionBit == 0){ 119 | NibbleArray nibbleArray = new NibbleArray(); 120 | 121 | boolean notEmpty = skyLevelArray.threadsafeIteration(nibbleArray::a); 122 | if(notEmpty) edited = true; 123 | 124 | newG.add(nibbleArray.asBytes()); 125 | 126 | if(notEmpty) { 127 | newC |= 1 << index; 128 | newE &= ~(1 << index); 129 | }else{ 130 | newE |= 1 << index; 131 | } 132 | }else{ 133 | NibbleArray nibbleArray = new NibbleArray(gValue.removeFirst().clone()); 134 | 135 | boolean notEmpty = skyLevelArray.threadsafeIteration(nibbleArray::a); 136 | if(notEmpty) edited = true; 137 | 138 | newG.add(nibbleArray.asBytes()); 139 | 140 | if(notEmpty) { 141 | newE &= ~(1 << index); 142 | } 143 | } 144 | } 145 | 146 | if(blockLevelArray == null){ 147 | if(dSectionBit != 0){ 148 | newH.add(hValue.removeFirst()); 149 | } 150 | }else { 151 | if(dSectionBit == 0){ 152 | NibbleArray nibbleArray = new NibbleArray(); 153 | 154 | boolean notEmpty = blockLevelArray.threadsafeIteration(nibbleArray::a); 155 | if(notEmpty) edited = true; 156 | 157 | newH.add(nibbleArray.asBytes()); 158 | 159 | if(notEmpty) { 160 | newD |= 1 << index; 161 | newF &= ~(1 << index); 162 | }else{ 163 | newF |= 1 << index; 164 | } 165 | }else{ 166 | NibbleArray nibbleArray = new NibbleArray(hValue.removeFirst().clone()); 167 | 168 | boolean notEmpty = blockLevelArray.threadsafeIteration(nibbleArray::a); 169 | if(notEmpty) edited = true; 170 | 171 | newH.add(nibbleArray.asBytes()); 172 | 173 | if(notEmpty) { 174 | newF &= ~(1 << index); 175 | } 176 | } 177 | } 178 | } 179 | 180 | if(!edited) return packet; 181 | 182 | 183 | PacketPlayOutLightUpdate newPacket = new PacketPlayOutLightUpdate(); 184 | a.set(newPacket, chunkX); 185 | b.set(newPacket, chunkZ); 186 | c.set(newPacket, newC); 187 | d.set(newPacket, newD); 188 | e.set(newPacket, newE); 189 | f.set(newPacket, newF); 190 | g.set(newPacket, newG); 191 | h.set(newPacket, newH); 192 | 193 | if(cacheSetting) parallelChunk.setLightUpdatePacketCache(newPacket); 194 | 195 | return newPacket; 196 | 197 | }catch (Exception e){e.printStackTrace();} 198 | 199 | return packet; 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /v1_15_R1/src/main/java/be4rjp/parallel/v1_15_R1/MapChunkPacketHandler.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.v1_15_R1; 2 | 3 | import be4rjp.asyncchunklib.impl.AsyncChunkCache; 4 | import be4rjp.parallel.ParallelChunk; 5 | import be4rjp.parallel.ParallelUniverse; 6 | import be4rjp.parallel.ParallelWorld; 7 | import be4rjp.parallel.nms.IPacketHandler; 8 | import be4rjp.parallel.player.ParallelPlayer; 9 | import be4rjp.parallel.util.SectionTypeArray; 10 | import net.minecraft.server.v1_15_R1.*; 11 | import org.bukkit.ChunkSnapshot; 12 | import org.bukkit.World; 13 | import org.bukkit.craftbukkit.v1_15_R1.CraftChunkSnapshot; 14 | import org.bukkit.craftbukkit.v1_15_R1.CraftWorld; 15 | 16 | import java.lang.reflect.Field; 17 | import java.util.List; 18 | 19 | public class MapChunkPacketHandler implements IPacketHandler { 20 | 21 | private static Field a; 22 | private static Field b; 23 | private static Field c; 24 | private static Field d; 25 | private static Field e; 26 | private static Field g; 27 | private static Field h; 28 | 29 | private static Field blockids; 30 | 31 | private static Field blockIds; 32 | 33 | private static BiomeStorage EMPTY_BIOME_STORAGE = new BiomeStorage(new BiomeBase[0]) {}; 34 | 35 | static { 36 | try { 37 | a = PacketPlayOutMapChunk.class.getDeclaredField("a"); 38 | b = PacketPlayOutMapChunk.class.getDeclaredField("b"); 39 | c = PacketPlayOutMapChunk.class.getDeclaredField("c"); 40 | d = PacketPlayOutMapChunk.class.getDeclaredField("d"); 41 | e = PacketPlayOutMapChunk.class.getDeclaredField("e"); 42 | g = PacketPlayOutMapChunk.class.getDeclaredField("g"); 43 | h = PacketPlayOutMapChunk.class.getDeclaredField("h"); 44 | a.setAccessible(true); 45 | b.setAccessible(true); 46 | c.setAccessible(true); 47 | d.setAccessible(true); 48 | e.setAccessible(true); 49 | g.setAccessible(true); 50 | h.setAccessible(true); 51 | 52 | blockids = CraftChunkSnapshot.class.getDeclaredField("blockids"); 53 | blockids.setAccessible(true); 54 | 55 | blockIds = ChunkSection.class.getDeclaredField("blockIds"); 56 | blockIds.setAccessible(true); 57 | }catch (Exception e){e.printStackTrace();} 58 | } 59 | 60 | @Override 61 | public Object rewrite(Object packet, ParallelPlayer parallelPlayer, boolean cacheSetting) { 62 | 63 | ParallelUniverse universe = parallelPlayer.getUniverse(); 64 | if(universe == null) return packet; 65 | 66 | World world = parallelPlayer.getBukkitPlayer().getWorld(); 67 | String worldName = world.getName(); 68 | ParallelWorld parallelWorld = universe.getWorld(worldName); 69 | 70 | try { 71 | 72 | int chunkX = a.getInt(packet); 73 | int chunkZ = b.getInt(packet); 74 | 75 | ParallelChunk parallelChunk = parallelWorld.getChunk(chunkX, chunkZ); 76 | if(parallelChunk == null) return packet; 77 | 78 | Object cachedPacket = parallelChunk.getCachedMapChunkPacket(); 79 | if(cachedPacket != null) return cachedPacket; 80 | 81 | ChunkSnapshot chunkSnapshot = AsyncChunkCache.getChunkCache(worldName, chunkX, chunkZ); 82 | if(chunkSnapshot == null) return packet; 83 | 84 | 85 | DataPaletteBlock[] cachedDataBlocks = (DataPaletteBlock[]) blockids.get(chunkSnapshot); 86 | 87 | ChunkSection[] chunkSections = new ChunkSection[16]; 88 | int nonEmptyChunkSections = 0; 89 | boolean edited = false; 90 | 91 | for(int index = 0; index < 16; index++){ 92 | 93 | ChunkSection chunkSection = Chunk.a; 94 | 95 | SectionTypeArray sectionTypeArray = parallelChunk.getSectionTypeArray(index); 96 | if(sectionTypeArray != null) { 97 | DataPaletteBlock cachedBlockData = cachedDataBlocks[index]; 98 | 99 | if(cachedBlockData != null) { 100 | final short[] nonEmptyTemp = {0}; 101 | cachedBlockData.a((iBlockData, i) -> { 102 | Fluid fluid = iBlockData.getFluid(); 103 | if (!iBlockData.isAir()) { 104 | nonEmptyTemp[0] = (short)(nonEmptyTemp[0] + i); 105 | } 106 | 107 | if (!fluid.isEmpty()) { 108 | nonEmptyTemp[0] = (short)(nonEmptyTemp[0] + i); 109 | } 110 | }); 111 | short nonEmpty = nonEmptyTemp[0]; 112 | 113 | chunkSection = new ChunkSection(index << 4, nonEmpty, (short) 0, (short) 0); 114 | 115 | NBTTagCompound data = new NBTTagCompound(); 116 | cachedBlockData.a(data, "Palette", "BlockStates"); 117 | DataPaletteBlock blocks = chunkSection.getBlocks(); 118 | blocks.a(data.getList("Palette", 10), data.getLongArray("BlockStates")); 119 | } 120 | 121 | if(chunkSection == Chunk.a) chunkSection = new ChunkSection(index << 4); 122 | 123 | ChunkSection finalChunkSection = chunkSection; 124 | boolean notEmpty = sectionTypeArray.threadsafeIteration((x, y, z, iBlockData) -> { 125 | finalChunkSection.setType(x, y, z, (IBlockData) iBlockData); 126 | }); 127 | 128 | if(notEmpty) edited = true; 129 | 130 | }else{ 131 | if(!chunkSnapshot.isSectionEmpty(index)){ 132 | DataPaletteBlock dataPaletteBlock = cachedDataBlocks[index]; 133 | 134 | final short[] nonEmptyTemp = {0}; 135 | 136 | dataPaletteBlock.a((iBlockData, i) -> { 137 | Fluid fluid = iBlockData.getFluid(); 138 | if (!iBlockData.isAir()) { 139 | nonEmptyTemp[0] = (short)(nonEmptyTemp[0] + i); 140 | } 141 | 142 | if (!fluid.isEmpty()) { 143 | nonEmptyTemp[0] = (short)(nonEmptyTemp[0] + i); 144 | } 145 | }); 146 | 147 | short nonEmpty = nonEmptyTemp[0]; 148 | chunkSection = new ChunkSection(index << 4, nonEmpty, (short) 0, (short) 0); 149 | blockIds.set(chunkSection, dataPaletteBlock); 150 | } 151 | } 152 | 153 | if(chunkSection != Chunk.a) nonEmptyChunkSections |= (1 << index); 154 | chunkSections[index] = chunkSection; 155 | } 156 | 157 | if(!edited) return packet; 158 | 159 | Chunk chunk = new Chunk(((CraftWorld) world).getHandle(), new ChunkCoordIntPair(chunkX, chunkZ), 160 | EMPTY_BIOME_STORAGE, ChunkConverter.a, TickListEmpty.b(), TickListEmpty.b(), 0L, chunkSections, null); 161 | 162 | int cValue = c.getInt(packet); 163 | 164 | PacketPlayOutMapChunk newPacket = new PacketPlayOutMapChunk(chunk, nonEmptyChunkSections | cValue); 165 | 166 | NBTTagCompound dValue = (NBTTagCompound) d.get(packet); 167 | BiomeStorage eValue = (BiomeStorage) e.get(packet); 168 | List gValue = (List) g.get(packet); 169 | boolean hValue = h.getBoolean(packet); 170 | 171 | d.set(newPacket, dValue); 172 | e.set(newPacket, eValue); 173 | g.set(newPacket, gValue); 174 | h.set(newPacket, hValue || nonEmptyChunkSections == 65535); 175 | 176 | if(cacheSetting) parallelChunk.setMapChunkPacketCache(newPacket); 177 | 178 | return newPacket; 179 | 180 | }catch (Exception e){e.printStackTrace();} 181 | 182 | return packet; 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /v1_15_R1/src/main/java/be4rjp/parallel/v1_15_R1/MultiBlockChangePacketHandler.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.v1_15_R1; 2 | 3 | import be4rjp.parallel.ParallelChunk; 4 | import be4rjp.parallel.ParallelUniverse; 5 | import be4rjp.parallel.ParallelWorld; 6 | import be4rjp.parallel.nms.IPacketHandler; 7 | import be4rjp.parallel.player.ParallelPlayer; 8 | import net.minecraft.server.v1_15_R1.BlockPosition; 9 | import net.minecraft.server.v1_15_R1.ChunkCoordIntPair; 10 | import net.minecraft.server.v1_15_R1.PacketPlayOutMultiBlockChange; 11 | import org.bukkit.block.data.BlockData; 12 | import org.bukkit.craftbukkit.v1_15_R1.block.data.CraftBlockData; 13 | 14 | import java.lang.reflect.Field; 15 | 16 | public class MultiBlockChangePacketHandler implements IPacketHandler { 17 | 18 | public static Field a; 19 | public static Field b; 20 | 21 | static { 22 | try{ 23 | a = PacketPlayOutMultiBlockChange.class.getDeclaredField("a"); 24 | b = PacketPlayOutMultiBlockChange.class.getDeclaredField("b"); 25 | 26 | a.setAccessible(true); 27 | b.setAccessible(true); 28 | 29 | }catch (Exception e){e.printStackTrace();} 30 | } 31 | 32 | @Override 33 | public Object rewrite(Object packet, ParallelPlayer parallelPlayer, boolean cacheSetting) { 34 | 35 | ParallelUniverse universe = parallelPlayer.getUniverse(); 36 | if(universe == null) return packet; 37 | 38 | String worldName = parallelPlayer.getBukkitPlayer().getWorld().getName(); 39 | ParallelWorld parallelWorld = universe.getWorld(worldName); 40 | 41 | try { 42 | ChunkCoordIntPair aValue = (ChunkCoordIntPair) a.get(packet); 43 | PacketPlayOutMultiBlockChange.MultiBlockChangeInfo[] bValue = (PacketPlayOutMultiBlockChange.MultiBlockChangeInfo[]) b.get(packet); 44 | 45 | int chunkX = aValue.x; 46 | int chunkZ = aValue.z; 47 | 48 | ParallelChunk parallelChunk = parallelWorld.getChunk(chunkX, chunkZ); 49 | if(parallelChunk == null) return packet; 50 | 51 | PacketPlayOutMultiBlockChange newPacket = new PacketPlayOutMultiBlockChange(); 52 | a.set(newPacket, aValue); 53 | 54 | int length = bValue.length; 55 | PacketPlayOutMultiBlockChange.MultiBlockChangeInfo[] newInfo = new PacketPlayOutMultiBlockChange.MultiBlockChangeInfo[length]; 56 | 57 | for(int index = 0; index < length; index++){ 58 | PacketPlayOutMultiBlockChange.MultiBlockChangeInfo info = bValue[index]; 59 | BlockPosition bp = info.a(); 60 | BlockData blockData = parallelChunk.getBlockData(bp.getX(), bp.getY(), bp.getZ()); 61 | 62 | if(blockData == null){ 63 | newInfo[index] = info; 64 | }else{ 65 | newInfo[index] = newPacket.new MultiBlockChangeInfo(info.b(), ((CraftBlockData) blockData).getState()); 66 | } 67 | } 68 | 69 | b.set(newPacket, newInfo); 70 | 71 | return newPacket; 72 | 73 | }catch (Exception e){e.printStackTrace();} 74 | 75 | return packet; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /v1_15_R1/src/main/java/be4rjp/parallel/v1_15_R1/NMSHandler.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.v1_15_R1; 2 | 3 | import be4rjp.parallel.ParallelChunk; 4 | import be4rjp.parallel.ParallelWorld; 5 | import be4rjp.parallel.nms.INMSHandler; 6 | import be4rjp.parallel.util.BlockPosition3i; 7 | import be4rjp.parallel.util.ChunkPosition; 8 | import be4rjp.parallel.util.SectionLevelArray; 9 | import be4rjp.parallel.util.SectionTypeArray; 10 | import io.netty.channel.Channel; 11 | import net.minecraft.server.v1_15_R1.*; 12 | import org.bukkit.Bukkit; 13 | import org.bukkit.Chunk; 14 | import org.bukkit.World; 15 | import org.bukkit.block.data.BlockData; 16 | import org.bukkit.craftbukkit.v1_15_R1.CraftChunk; 17 | import org.bukkit.craftbukkit.v1_15_R1.CraftWorld; 18 | import org.bukkit.craftbukkit.v1_15_R1.block.data.CraftBlockData; 19 | import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer; 20 | import org.bukkit.entity.Player; 21 | import org.jetbrains.annotations.Nullable; 22 | 23 | import java.util.*; 24 | 25 | public class NMSHandler implements INMSHandler { 26 | 27 | @Override 28 | public Channel getChannel(Player player) { 29 | return ((CraftPlayer) player).getHandle().playerConnection.networkManager.channel; 30 | } 31 | 32 | @Override 33 | public void sendPacket(Player player, Object packet) { 34 | ((CraftPlayer) player).getHandle().playerConnection.sendPacket((Packet) packet); 35 | } 36 | 37 | @Override 38 | public Object getIBlockDataByCombinedId(int id) {return Block.getByCombinedId(id);} 39 | 40 | @Override 41 | public int getCombinedIdByIBlockData(Object iBlockData) {return Block.getCombinedId((IBlockData) iBlockData);} 42 | 43 | @Override 44 | public Object getIBlockData(BlockData blockData) {return ((CraftBlockData) blockData).getState();} 45 | 46 | @Override 47 | public BlockData getBukkitBlockData(Object iBlockData) {return CraftBlockData.fromData((IBlockData) iBlockData);} 48 | 49 | @Override 50 | public Object[] createIBlockDataArray(int length) {return new IBlockData[length];} 51 | 52 | @Override 53 | public boolean isMapChunkPacket(Object packet) {return packet instanceof PacketPlayOutMapChunk;} 54 | 55 | @Override 56 | public boolean isMultiBlockChangePacket(Object packet) {return packet instanceof PacketPlayOutMultiBlockChange;} 57 | 58 | @Override 59 | public boolean isBlockChangePacket(Object packet) {return packet instanceof PacketPlayOutBlockChange;} 60 | 61 | @Override 62 | public boolean isLightUpdatePacket(Object packet) {return packet instanceof PacketPlayOutLightUpdate;} 63 | 64 | @Override 65 | public boolean isFlyPacket(Object packet) {return packet instanceof PacketPlayInFlying;} 66 | 67 | @Override 68 | public @Nullable Object createBlockChangePacket(ParallelWorld parallelWorld, int blockX, int blockY, int blockZ) { 69 | PacketPlayOutBlockChange packet = new PacketPlayOutBlockChange(); 70 | BlockData blockData = parallelWorld.getBlockData(blockX, blockY, blockZ); 71 | if(blockData == null) return null; 72 | 73 | try { 74 | BlockChangePacketHandler.a.set(packet, new BlockPosition(blockX, blockY, blockZ)); 75 | packet.block = ((CraftBlockData) blockData).getState(); 76 | return packet; 77 | 78 | }catch (Exception e){e.printStackTrace();} 79 | 80 | return null; 81 | } 82 | 83 | @Override 84 | public Set createMultiBlockChangePacket(ParallelWorld parallelWorld, Set blocks) { 85 | Map> chunkMap = new HashMap<>(); 86 | 87 | for(BlockPosition3i bp : blocks){ 88 | chunkMap.computeIfAbsent(new ChunkPosition(bp.getX(), bp.getZ()), cp -> new HashSet<>()).add(bp); 89 | } 90 | 91 | Set packets = new HashSet<>(); 92 | 93 | for(Map.Entry> entry : chunkMap.entrySet()){ 94 | ChunkPosition chunkPosition = entry.getKey(); 95 | Set bps = entry.getValue(); 96 | 97 | ParallelChunk parallelChunk = parallelWorld.getChunk(chunkPosition.x, chunkPosition.z); 98 | if(parallelChunk == null) continue; 99 | 100 | PacketPlayOutMultiBlockChange packet = new PacketPlayOutMultiBlockChange(); 101 | List infoList = new ArrayList<>(); 102 | 103 | for(BlockPosition3i bp : bps){ 104 | BlockData blockData = parallelChunk.getBlockData(bp.getX(), bp.getY(), bp.getZ()); 105 | if(blockData == null) continue; 106 | 107 | short loc = (short) ((bp.getX() & 0xF) << 12 | (bp.getZ() & 0xF) << 8 | bp.getY()); 108 | infoList.add(packet.new MultiBlockChangeInfo(loc, ((CraftBlockData) blockData).getState())); 109 | } 110 | 111 | try { 112 | MultiBlockChangePacketHandler.a.set(packet, new ChunkCoordIntPair(chunkPosition.x, chunkPosition.z)); 113 | MultiBlockChangePacketHandler.b.set(packet, infoList.toArray()); 114 | packets.add(packet); 115 | }catch (Exception e){e.printStackTrace();} 116 | } 117 | 118 | return packets; 119 | } 120 | 121 | @Override 122 | public void sendChunkMultiBlockChangeUpdatePacket(Player player, ParallelChunk parallelChunk) { 123 | PacketPlayOutMultiBlockChange packet = new PacketPlayOutMultiBlockChange(); 124 | List infoList = new ArrayList<>(); 125 | 126 | boolean has = false; 127 | for(int sectionIndex = 0; sectionIndex < 16; sectionIndex++){ 128 | SectionTypeArray sectionTypeArray = parallelChunk.getSectionTypeArray(sectionIndex); 129 | if(sectionTypeArray == null) continue; 130 | 131 | int finalSectionIndex = sectionIndex; 132 | boolean notEmpty = sectionTypeArray.threadsafeIteration((x, y, z, iBlockData) -> { 133 | short loc = (short) (x << 12 | z << 8 | (y + (finalSectionIndex << 4))); 134 | infoList.add(packet.new MultiBlockChangeInfo(loc, (IBlockData) iBlockData)); 135 | }); 136 | 137 | if(notEmpty) has = true; 138 | } 139 | 140 | if(!has) return; 141 | 142 | if(infoList.size() == 0) return; 143 | 144 | PacketPlayOutMultiBlockChange.MultiBlockChangeInfo[] array = infoList.toArray(new PacketPlayOutMultiBlockChange.MultiBlockChangeInfo[infoList.size()]); 145 | 146 | try { 147 | MultiBlockChangePacketHandler.a.set(packet, new ChunkCoordIntPair(parallelChunk.getChunkX(), parallelChunk.getChunkZ())); 148 | MultiBlockChangePacketHandler.b.set(packet, array); 149 | sendPacket(player, packet); 150 | }catch (Exception e){e.printStackTrace();} 151 | } 152 | 153 | @Override 154 | public @Nullable Object createLightUpdatePacketAtPrimaryThread(ParallelChunk parallelChunk) { 155 | if(!Bukkit.isPrimaryThread()) throw new IllegalStateException("DO NOT CALL FROM ASYNC THREAD!"); 156 | 157 | World world = Bukkit.getWorld(parallelChunk.getWorld().getName()); 158 | if(world == null) return null; 159 | 160 | boolean has = false; 161 | for(int sectionIndex = 0; sectionIndex < 16; sectionIndex++){ 162 | SectionLevelArray blockLevelArray = parallelChunk.getBlockLightSectionLevelArray(sectionIndex); 163 | SectionLevelArray skyLevelArray = parallelChunk.getSkyLightSectionLevelArray(sectionIndex); 164 | 165 | if(blockLevelArray != null){ 166 | if(blockLevelArray.getSize() != 0) has = true; 167 | } 168 | if(skyLevelArray != null){ 169 | if(skyLevelArray.getSize() != 0) has = true; 170 | } 171 | } 172 | if(!has) return null; 173 | 174 | return new PacketPlayOutLightUpdate( 175 | new ChunkCoordIntPair(parallelChunk.getChunkX(), parallelChunk.getChunkZ()), 176 | ((CraftWorld) world).getHandle().getChunkProvider().getLightEngine()); 177 | } 178 | 179 | @Override 180 | public void sendClearChunkMultiBlockChangePacketAtPrimaryThread(Player player, ParallelChunk parallelChunk) { 181 | if(!Bukkit.isPrimaryThread()) throw new IllegalStateException("DO NOT CALL FROM ASYNC THREAD!"); 182 | 183 | World world = Bukkit.getWorld(parallelChunk.getWorld().getName()); 184 | if(world == null) return; 185 | 186 | if(player.getWorld() != world) return; 187 | 188 | List coordList = new ArrayList<>(); 189 | 190 | boolean has = false; 191 | for(int sectionIndex = 0; sectionIndex < 16; sectionIndex++){ 192 | SectionTypeArray sectionTypeArray = parallelChunk.getSectionTypeArray(sectionIndex); 193 | if(sectionTypeArray == null) continue; 194 | 195 | int finalSectionIndex = sectionIndex; 196 | boolean notEmpty = sectionTypeArray.threadsafeIteration((x, y, z, iBlockData) -> { 197 | short loc = (short) (x << 12 | z << 8 | (y + (finalSectionIndex << 4))); 198 | coordList.add(loc); 199 | }); 200 | 201 | if(notEmpty) has = true; 202 | } 203 | 204 | if(!has) return; 205 | 206 | if(coordList.size() == 0) return; 207 | 208 | Chunk chunk = world.getChunkAt(parallelChunk.getChunkX(), parallelChunk.getChunkZ()); 209 | net.minecraft.server.v1_15_R1.Chunk nmsChunk = ((CraftChunk) chunk).getHandle(); 210 | 211 | short[] array = new short[coordList.size()]; 212 | for(int i = 0; i < coordList.size(); i++){ 213 | array[i] = coordList.get(i); 214 | } 215 | 216 | PacketPlayOutMultiBlockChange packet = new PacketPlayOutMultiBlockChange(coordList.size(), array, nmsChunk); 217 | sendPacket(player, packet); 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /v1_16_R3/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | parallel_v1_16_R3 5 | jar 6 | ${revision} 7 | 8 | 9 | be4rjp 10 | parallel_parent 11 | ${revision} 12 | 13 | 14 | 15 | 1.8 16 | UTF-8 17 | 18 | 19 | 20 | 21 | 22 | org.apache.maven.plugins 23 | maven-compiler-plugin 24 | 3.8.1 25 | 26 | ${java.version} 27 | ${java.version} 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | org.spigotmc 36 | spigot-api 37 | 1.16.5-R0.1-SNAPSHOT 38 | provided 39 | 40 | 41 | org.spigotmc 42 | spigot 43 | 1.16.5-R0.1-SNAPSHOT 44 | provided 45 | 46 | 47 | be4rjp 48 | parallel_api 49 | jar 50 | ${revision} 51 | 52 | 53 | com.github.Be4rJP 54 | AsyncChunkLib 55 | v1.0.2 56 | provided 57 | 58 | 59 | fastutil 60 | fastutil 61 | 5.0.9 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /v1_16_R3/src/main/java/be4rjp/parallel/v1_16_R3/BlockChangePacketHandler.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.v1_16_R3; 2 | 3 | import be4rjp.parallel.ParallelUniverse; 4 | import be4rjp.parallel.ParallelWorld; 5 | import be4rjp.parallel.nms.IPacketHandler; 6 | import be4rjp.parallel.player.ParallelPlayer; 7 | import net.minecraft.server.v1_16_R3.BlockPosition; 8 | import net.minecraft.server.v1_16_R3.IBlockData; 9 | import net.minecraft.server.v1_16_R3.PacketPlayOutBlockBreak; 10 | import net.minecraft.server.v1_16_R3.PacketPlayOutBlockChange; 11 | import org.bukkit.Material; 12 | import org.bukkit.block.data.BlockData; 13 | import org.bukkit.craftbukkit.v1_16_R3.block.data.CraftBlockData; 14 | 15 | import java.lang.reflect.Field; 16 | 17 | public class BlockChangePacketHandler implements IPacketHandler { 18 | 19 | public static Field a; 20 | public static Field c; 21 | public static Field d; 22 | 23 | static { 24 | try { 25 | a = PacketPlayOutBlockChange.class.getDeclaredField("a"); 26 | a.setAccessible(true); 27 | 28 | c = PacketPlayOutBlockBreak.class.getDeclaredField("c"); 29 | d = PacketPlayOutBlockBreak.class.getDeclaredField("d"); 30 | c.setAccessible(true); 31 | d.setAccessible(true); 32 | }catch (Exception e){e.printStackTrace();} 33 | } 34 | 35 | @Override 36 | public Object rewrite(Object packet, ParallelPlayer parallelPlayer, boolean cacheSetting) { 37 | 38 | ParallelUniverse universe = parallelPlayer.getUniverse(); 39 | if(universe == null) return packet; 40 | 41 | String worldName = parallelPlayer.getBukkitPlayer().getWorld().getName(); 42 | ParallelWorld parallelWorld = universe.getWorld(worldName); 43 | 44 | try { 45 | if (packet instanceof PacketPlayOutBlockChange) { 46 | PacketPlayOutBlockChange blockChange = (PacketPlayOutBlockChange) packet; 47 | BlockPosition bp = (BlockPosition) a.get(blockChange); 48 | 49 | BlockData blockData = parallelWorld.getBlockData(bp.getX(), bp.getY(), bp.getZ()); 50 | if (blockData == null) return packet; 51 | //if(blockData.getMaterial() == Material.AIR) return packet; 52 | 53 | blockChange.block = ((CraftBlockData) blockData).getState(); 54 | 55 | return blockChange; 56 | } else { 57 | PacketPlayOutBlockBreak blockBreak = (PacketPlayOutBlockBreak) packet; 58 | BlockPosition bp = (BlockPosition) c.get(blockBreak); 59 | 60 | BlockData blockData = parallelWorld.getBlockData(bp.getX(), bp.getY(), bp.getZ()); 61 | if (blockData == null) return packet; 62 | 63 | IBlockData data = ((CraftBlockData) blockData).getState(); 64 | d.set(blockBreak, data); 65 | 66 | return blockBreak; 67 | } 68 | }catch (Exception e){e.printStackTrace();} 69 | 70 | return packet; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /v1_16_R3/src/main/java/be4rjp/parallel/v1_16_R3/FlyPacketHandler.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.v1_16_R3; 2 | 3 | import be4rjp.parallel.ParallelUniverse; 4 | import be4rjp.parallel.ParallelWorld; 5 | import be4rjp.parallel.nms.IPacketHandler; 6 | import be4rjp.parallel.player.ParallelPlayer; 7 | import net.minecraft.server.v1_16_R3.EntityPlayer; 8 | import net.minecraft.server.v1_16_R3.PlayerConnection; 9 | import org.bukkit.World; 10 | import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer; 11 | import org.bukkit.util.NumberConversions; 12 | 13 | import java.lang.reflect.Field; 14 | 15 | 16 | public class FlyPacketHandler implements IPacketHandler { 17 | 18 | private static Field C; 19 | private static Field E; 20 | 21 | static { 22 | try { 23 | C = PlayerConnection.class.getDeclaredField("C"); 24 | E = PlayerConnection.class.getDeclaredField("E"); 25 | 26 | C.setAccessible(true); 27 | E.setAccessible(true); 28 | }catch (Exception e){ 29 | e.printStackTrace(); 30 | } 31 | } 32 | 33 | @Override 34 | public Object rewrite(Object packet, ParallelPlayer parallelPlayer, boolean cacheSetting) { 35 | ParallelUniverse universe = parallelPlayer.getUniverse(); 36 | if(universe == null) return packet; 37 | 38 | World world = parallelPlayer.getBukkitPlayer().getWorld(); 39 | String worldName = world.getName(); 40 | ParallelWorld parallelWorld = universe.getWorld(worldName); 41 | 42 | EntityPlayer entityPlayer = ((CraftPlayer) parallelPlayer.getBukkitPlayer()).getHandle(); 43 | 44 | int x = NumberConversions.floor(entityPlayer.locX()); 45 | int y = NumberConversions.floor(entityPlayer.locY()); 46 | int z = NumberConversions.floor(entityPlayer.locZ()); 47 | 48 | int downY = y - 1; 49 | downY = Math.max(0, downY); 50 | 51 | if(parallelWorld.hasBlockData(x, y, z) || parallelWorld.hasBlockData(x, downY, z)){ 52 | try { 53 | PlayerConnection playerConnection = entityPlayer.playerConnection; 54 | C.set(playerConnection, 0); 55 | E.set(playerConnection, 0); 56 | }catch (Exception e){e.printStackTrace();} 57 | } 58 | 59 | return packet; 60 | } 61 | 62 | } 63 | 64 | -------------------------------------------------------------------------------- /v1_16_R3/src/main/java/be4rjp/parallel/v1_16_R3/LightUpdatePacketHandler.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.v1_16_R3; 2 | 3 | import be4rjp.parallel.ParallelChunk; 4 | import be4rjp.parallel.ParallelUniverse; 5 | import be4rjp.parallel.ParallelWorld; 6 | import be4rjp.parallel.nms.IPacketHandler; 7 | import be4rjp.parallel.player.ParallelPlayer; 8 | import be4rjp.parallel.util.SectionLevelArray; 9 | import net.minecraft.server.v1_16_R3.NibbleArray; 10 | import net.minecraft.server.v1_16_R3.PacketPlayOutLightUpdate; 11 | import org.bukkit.World; 12 | 13 | import java.lang.reflect.Field; 14 | import java.util.*; 15 | 16 | public class LightUpdatePacketHandler implements IPacketHandler { 17 | 18 | private static Field a; 19 | private static Field b; 20 | private static Field c; 21 | private static Field d; 22 | private static Field e; 23 | private static Field f; 24 | private static Field g; 25 | private static Field h; 26 | private static Field i; 27 | 28 | static { 29 | try { 30 | a = PacketPlayOutLightUpdate.class.getDeclaredField("a"); 31 | b = PacketPlayOutLightUpdate.class.getDeclaredField("b"); 32 | c = PacketPlayOutLightUpdate.class.getDeclaredField("c"); 33 | d = PacketPlayOutLightUpdate.class.getDeclaredField("d"); 34 | e = PacketPlayOutLightUpdate.class.getDeclaredField("e"); 35 | f = PacketPlayOutLightUpdate.class.getDeclaredField("f"); 36 | g = PacketPlayOutLightUpdate.class.getDeclaredField("g"); 37 | h = PacketPlayOutLightUpdate.class.getDeclaredField("h"); 38 | i = PacketPlayOutLightUpdate.class.getDeclaredField("i"); 39 | 40 | a.setAccessible(true); 41 | b.setAccessible(true); 42 | c.setAccessible(true); 43 | d.setAccessible(true); 44 | e.setAccessible(true); 45 | f.setAccessible(true); 46 | g.setAccessible(true); 47 | h.setAccessible(true); 48 | i.setAccessible(true); 49 | }catch (Exception e){e.printStackTrace();} 50 | } 51 | 52 | @Override 53 | public Object rewrite(Object packet, ParallelPlayer parallelPlayer, boolean cacheSetting) { 54 | 55 | ParallelUniverse universe = parallelPlayer.getUniverse(); 56 | if(universe == null) return packet; 57 | 58 | World world = parallelPlayer.getBukkitPlayer().getWorld(); 59 | String worldName = world.getName(); 60 | ParallelWorld parallelWorld = universe.getWorld(worldName); 61 | 62 | try{ 63 | 64 | int chunkX = a.getInt(packet); 65 | int chunkZ = b.getInt(packet); 66 | 67 | boolean iFlag = i.getBoolean(packet); 68 | 69 | ParallelChunk parallelChunk = parallelWorld.getChunk(chunkX, chunkZ); 70 | if(parallelChunk == null) return packet; 71 | 72 | Object cachedPacket = parallelChunk.getCachedLightUpdatePacket(); 73 | if(cachedPacket != null) return cachedPacket; 74 | 75 | int cValue = c.getInt(packet); 76 | int dValue = d.getInt(packet); 77 | int eValue = e.getInt(packet); 78 | int fValue = f.getInt(packet); 79 | Deque gValue = new ArrayDeque<>((List) g.get(packet)); 80 | Deque hValue = new ArrayDeque<>((List) h.get(packet)); 81 | 82 | int newC = 0; 83 | int newD = 0; 84 | int newE = 0; 85 | int newF = 0; 86 | List newG = new ArrayList<>(); 87 | List newH = new ArrayList<>(); 88 | 89 | boolean edited = false; 90 | 91 | for(int index = 0; index < 18; index++){ 92 | int sectionIndex = index - 1; 93 | 94 | int cSectionBit = cValue & (1 << index); 95 | newC |= cSectionBit; 96 | newE |= eValue & (1 << index); 97 | 98 | int dSectionBit = dValue & (1 << index); 99 | newD |= dSectionBit; 100 | newF |= fValue & (1 << index); 101 | 102 | if(index == 0 || index == 17){ 103 | 104 | if(cSectionBit != 0){ 105 | newG.add(gValue.removeFirst()); 106 | } 107 | 108 | if(dSectionBit != 0){ 109 | newH.add(hValue.removeFirst()); 110 | } 111 | continue; 112 | } 113 | 114 | 115 | SectionLevelArray skyLevelArray = parallelChunk.getSkyLightSectionLevelArray(sectionIndex); 116 | SectionLevelArray blockLevelArray = parallelChunk.getBlockLightSectionLevelArray(sectionIndex); 117 | 118 | if(skyLevelArray == null){ 119 | if(cSectionBit != 0){ 120 | newG.add(gValue.removeFirst()); 121 | } 122 | }else { 123 | if(cSectionBit == 0){ 124 | NibbleArray nibbleArray = new NibbleArray(); 125 | 126 | boolean notEmpty = skyLevelArray.threadsafeIteration(nibbleArray::a); 127 | if(notEmpty) edited = true; 128 | 129 | newG.add(nibbleArray.asBytes()); 130 | 131 | if(notEmpty) { 132 | newC |= 1 << index; 133 | newE &= ~(1 << index); 134 | }else{ 135 | newE |= 1 << index; 136 | } 137 | }else{ 138 | NibbleArray nibbleArray = new NibbleArray(gValue.removeFirst().clone()); 139 | 140 | boolean notEmpty = skyLevelArray.threadsafeIteration(nibbleArray::a); 141 | if(notEmpty) edited = true; 142 | 143 | newG.add(nibbleArray.asBytes()); 144 | 145 | if(notEmpty) { 146 | newE &= ~(1 << index); 147 | } 148 | } 149 | } 150 | 151 | if(blockLevelArray == null){ 152 | if(dSectionBit != 0){ 153 | newH.add(hValue.removeFirst()); 154 | } 155 | }else { 156 | if(dSectionBit == 0){ 157 | NibbleArray nibbleArray = new NibbleArray(); 158 | 159 | boolean notEmpty = blockLevelArray.threadsafeIteration(nibbleArray::a); 160 | if(notEmpty) edited = true; 161 | 162 | newH.add(nibbleArray.asBytes()); 163 | 164 | if(notEmpty) { 165 | newD |= 1 << index; 166 | newF &= ~(1 << index); 167 | }else{ 168 | newF |= 1 << index; 169 | } 170 | }else{ 171 | NibbleArray nibbleArray = new NibbleArray(hValue.removeFirst().clone()); 172 | 173 | boolean notEmpty = blockLevelArray.threadsafeIteration(nibbleArray::a); 174 | if(notEmpty) edited = true; 175 | 176 | newH.add(nibbleArray.asBytes()); 177 | 178 | if(notEmpty) { 179 | newF &= ~(1 << index); 180 | } 181 | } 182 | } 183 | } 184 | 185 | if(!edited) return packet; 186 | 187 | 188 | PacketPlayOutLightUpdate newPacket = new PacketPlayOutLightUpdate(); 189 | a.set(newPacket, chunkX); 190 | b.set(newPacket, chunkZ); 191 | c.set(newPacket, newC); 192 | d.set(newPacket, newD); 193 | e.set(newPacket, newE); 194 | f.set(newPacket, newF); 195 | g.set(newPacket, newG); 196 | h.set(newPacket, newH); 197 | i.set(newPacket, iFlag); 198 | 199 | if(cacheSetting) parallelChunk.setLightUpdatePacketCache(newPacket); 200 | 201 | return newPacket; 202 | 203 | }catch (Exception e){e.printStackTrace();} 204 | 205 | return packet; 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /v1_16_R3/src/main/java/be4rjp/parallel/v1_16_R3/MapChunkPacketHandler.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.v1_16_R3; 2 | 3 | import be4rjp.asyncchunklib.impl.AsyncChunkCache; 4 | import be4rjp.parallel.ParallelChunk; 5 | import be4rjp.parallel.ParallelUniverse; 6 | import be4rjp.parallel.ParallelWorld; 7 | import be4rjp.parallel.nms.IPacketHandler; 8 | import be4rjp.parallel.player.ParallelPlayer; 9 | import be4rjp.parallel.util.SectionTypeArray; 10 | import net.minecraft.server.v1_16_R3.*; 11 | import org.bukkit.ChunkSnapshot; 12 | import org.bukkit.World; 13 | import org.bukkit.craftbukkit.v1_16_R3.CraftChunkSnapshot; 14 | import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; 15 | 16 | import java.lang.reflect.Field; 17 | import java.util.List; 18 | 19 | public class MapChunkPacketHandler implements IPacketHandler { 20 | 21 | private static Field a; 22 | private static Field b; 23 | private static Field c; 24 | private static Field d; 25 | private static Field e; 26 | private static Field g; 27 | private static Field h; 28 | 29 | private static Field blockids; 30 | 31 | private static Field blockIds; 32 | 33 | private static BiomeStorage EMPTY_BIOME_STORAGE = new BiomeStorage(null, null) { 34 | @Override 35 | public int[] a() { 36 | return new int[0]; 37 | } 38 | }; 39 | 40 | static { 41 | try { 42 | a = PacketPlayOutMapChunk.class.getDeclaredField("a"); 43 | b = PacketPlayOutMapChunk.class.getDeclaredField("b"); 44 | c = PacketPlayOutMapChunk.class.getDeclaredField("c"); 45 | d = PacketPlayOutMapChunk.class.getDeclaredField("d"); 46 | e = PacketPlayOutMapChunk.class.getDeclaredField("e"); 47 | g = PacketPlayOutMapChunk.class.getDeclaredField("g"); 48 | h = PacketPlayOutMapChunk.class.getDeclaredField("h"); 49 | a.setAccessible(true); 50 | b.setAccessible(true); 51 | c.setAccessible(true); 52 | d.setAccessible(true); 53 | e.setAccessible(true); 54 | g.setAccessible(true); 55 | h.setAccessible(true); 56 | 57 | blockids = CraftChunkSnapshot.class.getDeclaredField("blockids"); 58 | blockids.setAccessible(true); 59 | 60 | blockIds = ChunkSection.class.getDeclaredField("blockIds"); 61 | blockIds.setAccessible(true); 62 | }catch (Exception e){e.printStackTrace();} 63 | } 64 | 65 | @Override 66 | public Object rewrite(Object packet, ParallelPlayer parallelPlayer, boolean cacheSetting) { 67 | 68 | ParallelUniverse universe = parallelPlayer.getUniverse(); 69 | if(universe == null) return packet; 70 | 71 | World world = parallelPlayer.getBukkitPlayer().getWorld(); 72 | String worldName = world.getName(); 73 | ParallelWorld parallelWorld = universe.getWorld(worldName); 74 | 75 | try { 76 | 77 | int chunkX = a.getInt(packet); 78 | int chunkZ = b.getInt(packet); 79 | 80 | ParallelChunk parallelChunk = parallelWorld.getChunk(chunkX, chunkZ); 81 | if(parallelChunk == null) return packet; 82 | 83 | Object cachedPacket = parallelChunk.getCachedMapChunkPacket(); 84 | if(cachedPacket != null) return cachedPacket; 85 | 86 | ChunkSnapshot chunkSnapshot = AsyncChunkCache.getChunkCache(worldName, chunkX, chunkZ); 87 | if(chunkSnapshot == null) return packet; 88 | 89 | 90 | DataPaletteBlock[] cachedDataBlocks = (DataPaletteBlock[]) blockids.get(chunkSnapshot); 91 | 92 | ChunkSection[] chunkSections = new ChunkSection[16]; 93 | int nonEmptyChunkSections = 0; 94 | boolean edited = false; 95 | 96 | for(int index = 0; index < 16; index++){ 97 | 98 | ChunkSection chunkSection = Chunk.a; 99 | 100 | SectionTypeArray sectionTypeArray = parallelChunk.getSectionTypeArray(index); 101 | if(sectionTypeArray != null) { 102 | DataPaletteBlock cachedBlockData = cachedDataBlocks[index]; 103 | 104 | if(cachedBlockData != null) { 105 | final short[] nonEmptyTemp = {0}; 106 | cachedBlockData.a((iBlockData, i) -> { 107 | Fluid fluid = iBlockData.getFluid(); 108 | if (!iBlockData.isAir()) { 109 | nonEmptyTemp[0] = (short)(nonEmptyTemp[0] + i); 110 | } 111 | 112 | if (!fluid.isEmpty()) { 113 | nonEmptyTemp[0] = (short)(nonEmptyTemp[0] + i); 114 | } 115 | }); 116 | short nonEmpty = nonEmptyTemp[0]; 117 | 118 | chunkSection = new ChunkSection(index << 4, nonEmpty, (short) 0, (short) 0); 119 | 120 | NBTTagCompound data = new NBTTagCompound(); 121 | cachedBlockData.a(data, "Palette", "BlockStates"); 122 | DataPaletteBlock blocks = chunkSection.getBlocks(); 123 | blocks.a(data.getList("Palette", 10), data.getLongArray("BlockStates")); 124 | } 125 | 126 | if(chunkSection == Chunk.a) chunkSection = new ChunkSection(index << 4); 127 | 128 | ChunkSection finalChunkSection = chunkSection; 129 | boolean notEmpty = sectionTypeArray.threadsafeIteration((x, y, z, iBlockData) -> { 130 | finalChunkSection.setType(x, y, z, (IBlockData) iBlockData); 131 | }); 132 | 133 | if(notEmpty) edited = true; 134 | 135 | }else{ 136 | if(!chunkSnapshot.isSectionEmpty(index)){ 137 | DataPaletteBlock dataPaletteBlock = cachedDataBlocks[index]; 138 | 139 | final short[] nonEmptyTemp = {0}; 140 | 141 | dataPaletteBlock.a((iBlockData, i) -> { 142 | Fluid fluid = iBlockData.getFluid(); 143 | if (!iBlockData.isAir()) { 144 | nonEmptyTemp[0] = (short)(nonEmptyTemp[0] + i); 145 | } 146 | 147 | if (!fluid.isEmpty()) { 148 | nonEmptyTemp[0] = (short)(nonEmptyTemp[0] + i); 149 | } 150 | }); 151 | 152 | short nonEmpty = nonEmptyTemp[0]; 153 | chunkSection = new ChunkSection(index << 4, nonEmpty, (short) 0, (short) 0); 154 | blockIds.set(chunkSection, dataPaletteBlock); 155 | } 156 | } 157 | 158 | if(chunkSection != Chunk.a) nonEmptyChunkSections |= (1 << index); 159 | chunkSections[index] = chunkSection; 160 | } 161 | 162 | if(!edited) return packet; 163 | 164 | Chunk chunk = new Chunk(((CraftWorld) world).getHandle(), new ChunkCoordIntPair(chunkX, chunkZ), 165 | EMPTY_BIOME_STORAGE, ChunkConverter.a, TickListEmpty.b(), TickListEmpty.b(), 0L, chunkSections, null); 166 | 167 | int cValue = c.getInt(packet); 168 | 169 | PacketPlayOutMapChunk newPacket = new PacketPlayOutMapChunk(chunk, nonEmptyChunkSections | cValue); 170 | 171 | NBTTagCompound dValue = (NBTTagCompound) d.get(packet); 172 | Object eValue = e.get(packet); 173 | List gValue = (List) g.get(packet); 174 | boolean hValue = h.getBoolean(packet); 175 | 176 | d.set(newPacket, dValue); 177 | e.set(newPacket, eValue); 178 | g.set(newPacket, gValue); 179 | h.set(newPacket, hValue || nonEmptyChunkSections == 65535); 180 | 181 | if(cacheSetting) parallelChunk.setMapChunkPacketCache(newPacket); 182 | 183 | return newPacket; 184 | 185 | }catch (Exception e){e.printStackTrace();} 186 | 187 | return packet; 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /v1_16_R3/src/main/java/be4rjp/parallel/v1_16_R3/MultiBlockChangePacketHandler.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.v1_16_R3; 2 | 3 | import be4rjp.parallel.ParallelChunk; 4 | import be4rjp.parallel.ParallelUniverse; 5 | import be4rjp.parallel.ParallelWorld; 6 | import be4rjp.parallel.nms.IPacketHandler; 7 | import be4rjp.parallel.player.ParallelPlayer; 8 | import be4rjp.parallel.util.SectionTypeArray; 9 | import net.minecraft.server.v1_16_R3.IBlockData; 10 | import net.minecraft.server.v1_16_R3.PacketPlayOutMultiBlockChange; 11 | import net.minecraft.server.v1_16_R3.SectionPosition; 12 | 13 | import java.lang.reflect.Field; 14 | 15 | public class MultiBlockChangePacketHandler implements IPacketHandler { 16 | 17 | public static Field a; 18 | public static Field b; 19 | public static Field c; 20 | public static Field d; 21 | 22 | static { 23 | try{ 24 | a = PacketPlayOutMultiBlockChange.class.getDeclaredField("a"); 25 | b = PacketPlayOutMultiBlockChange.class.getDeclaredField("b"); 26 | c = PacketPlayOutMultiBlockChange.class.getDeclaredField("c"); 27 | d = PacketPlayOutMultiBlockChange.class.getDeclaredField("d"); 28 | 29 | a.setAccessible(true); 30 | b.setAccessible(true); 31 | c.setAccessible(true); 32 | d.setAccessible(true); 33 | 34 | }catch (Exception e){e.printStackTrace();} 35 | } 36 | 37 | @Override 38 | public Object rewrite(Object packet, ParallelPlayer parallelPlayer, boolean cacheSetting) { 39 | 40 | ParallelUniverse universe = parallelPlayer.getUniverse(); 41 | if(universe == null) return packet; 42 | 43 | String worldName = parallelPlayer.getBukkitPlayer().getWorld().getName(); 44 | ParallelWorld parallelWorld = universe.getWorld(worldName); 45 | 46 | try { 47 | 48 | SectionPosition aValue = (SectionPosition) a.get(packet); 49 | 50 | int chunkX = aValue.getX(); 51 | int chunkZ = aValue.getZ(); 52 | 53 | ParallelChunk parallelChunk = parallelWorld.getChunk(chunkX, chunkZ); 54 | if(parallelChunk == null) return packet; 55 | 56 | SectionTypeArray sectionTypeArray = parallelChunk.getSectionTypeArray(aValue.getY()); 57 | if(sectionTypeArray == null) return packet; 58 | 59 | short[] bValue = (short[]) b.get(packet); 60 | IBlockData[] cValueClone = ((IBlockData[]) c.get(packet)).clone(); 61 | 62 | for(int i = 0; i < bValue.length; i++){ 63 | short coord = bValue[i]; 64 | 65 | int x = coord >> 8; 66 | int y = coord & 0xF; 67 | int z = (coord >> 4) & 0xF; 68 | 69 | IBlockData iBlockData = (IBlockData) sectionTypeArray.getType(x, y, z); 70 | if(iBlockData != null){ 71 | cValueClone[i] = iBlockData; 72 | } 73 | } 74 | 75 | boolean dValue = d.getBoolean(packet); 76 | 77 | 78 | PacketPlayOutMultiBlockChange newPacket = new PacketPlayOutMultiBlockChange(); 79 | a.set(newPacket, aValue); 80 | b.set(newPacket, bValue); 81 | c.set(newPacket, cValueClone); 82 | d.set(newPacket, dValue); 83 | 84 | return newPacket; 85 | 86 | }catch (Exception e){e.printStackTrace();} 87 | 88 | return packet; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /v1_16_R3/src/main/java/be4rjp/parallel/v1_16_R3/NMSHandler.java: -------------------------------------------------------------------------------- 1 | package be4rjp.parallel.v1_16_R3; 2 | 3 | import be4rjp.parallel.ParallelChunk; 4 | import be4rjp.parallel.ParallelWorld; 5 | import be4rjp.parallel.nms.INMSHandler; 6 | import be4rjp.parallel.util.BlockPosition3i; 7 | import be4rjp.parallel.util.SectionLevelArray; 8 | import be4rjp.parallel.util.SectionTypeArray; 9 | import io.netty.channel.Channel; 10 | import net.minecraft.server.v1_16_R3.*; 11 | import org.bukkit.Bukkit; 12 | import org.bukkit.Chunk; 13 | import org.bukkit.World; 14 | import org.bukkit.block.data.BlockData; 15 | import org.bukkit.craftbukkit.v1_16_R3.CraftChunk; 16 | import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; 17 | import org.bukkit.craftbukkit.v1_16_R3.block.data.CraftBlockData; 18 | import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer; 19 | import org.bukkit.entity.Player; 20 | import org.jetbrains.annotations.Nullable; 21 | 22 | import java.util.*; 23 | 24 | public class NMSHandler implements INMSHandler { 25 | 26 | @Override 27 | public Channel getChannel(Player player) { 28 | return ((CraftPlayer) player).getHandle().playerConnection.networkManager.channel; 29 | } 30 | 31 | @Override 32 | public void sendPacket(Player player, Object packet) { 33 | ((CraftPlayer) player).getHandle().playerConnection.sendPacket((Packet) packet); 34 | } 35 | 36 | @Override 37 | public Object getIBlockDataByCombinedId(int id) {return Block.getByCombinedId(id);} 38 | 39 | @Override 40 | public int getCombinedIdByIBlockData(Object iBlockData) {return Block.getCombinedId((IBlockData) iBlockData);} 41 | 42 | @Override 43 | public Object getIBlockData(BlockData blockData) {return ((CraftBlockData) blockData).getState();} 44 | 45 | @Override 46 | public BlockData getBukkitBlockData(Object iBlockData) {return CraftBlockData.fromData((IBlockData) iBlockData);} 47 | 48 | @Override 49 | public Object[] createIBlockDataArray(int length) {return new IBlockData[length];} 50 | 51 | @Override 52 | public boolean isMapChunkPacket(Object packet) {return packet instanceof PacketPlayOutMapChunk;} 53 | 54 | @Override 55 | public boolean isMultiBlockChangePacket(Object packet) {return packet instanceof PacketPlayOutMultiBlockChange;} 56 | 57 | @Override 58 | public boolean isBlockChangePacket(Object packet) {return packet instanceof PacketPlayOutBlockChange || packet instanceof PacketPlayOutBlockBreak;} 59 | 60 | @Override 61 | public boolean isLightUpdatePacket(Object packet) {return packet instanceof PacketPlayOutLightUpdate;} 62 | 63 | @Override 64 | public boolean isFlyPacket(Object packet) {return packet instanceof PacketPlayInFlying;} 65 | 66 | @Override 67 | public @Nullable Object createBlockChangePacket(ParallelWorld parallelWorld, int blockX, int blockY, int blockZ) { 68 | PacketPlayOutBlockChange packet = new PacketPlayOutBlockChange(); 69 | BlockData blockData = parallelWorld.getBlockData(blockX, blockY, blockZ); 70 | if(blockData == null) return null; 71 | 72 | try { 73 | BlockChangePacketHandler.a.set(packet, new BlockPosition(blockX, blockY, blockZ)); 74 | packet.block = ((CraftBlockData) blockData).getState(); 75 | return packet; 76 | 77 | }catch (Exception e){e.printStackTrace();} 78 | 79 | return null; 80 | } 81 | 82 | @Override 83 | public Set createMultiBlockChangePacket(ParallelWorld parallelWorld, Set blocks) { 84 | Map> chunkMap = new HashMap<>(); 85 | 86 | for(BlockPosition3i bp : blocks){ 87 | chunkMap.computeIfAbsent(new BlockPosition3i(bp.getX() >> 4, bp.getY() >> 4, bp.getZ() >> 4), cp -> new HashSet<>()).add(bp); 88 | } 89 | 90 | Set packets = new HashSet<>(); 91 | 92 | for(Map.Entry> entry : chunkMap.entrySet()){ 93 | BlockPosition3i sectionPosition = entry.getKey(); 94 | Set bps = entry.getValue(); 95 | 96 | ParallelChunk parallelChunk = parallelWorld.getChunk(sectionPosition.getX(), sectionPosition.getZ()); 97 | if(parallelChunk == null) continue; 98 | 99 | SectionTypeArray sectionTypeArray = parallelChunk.getSectionTypeArray(sectionPosition.getY()); 100 | if(sectionTypeArray == null) continue; 101 | 102 | List coordList = new ArrayList<>(); 103 | List dataList = new ArrayList<>(); 104 | 105 | for(BlockPosition3i bp : bps){ 106 | IBlockData iBlockData = (IBlockData) sectionTypeArray.getType(bp.getX() & 0xF, bp.getY() & 0xF, bp.getZ() & 0xF); 107 | if(iBlockData == null) continue; 108 | 109 | coordList.add((short) ((bp.getX() & 0xF) << 8 | (bp.getZ() & 0xF) << 4 | bp.getY() & 0xF)); 110 | dataList.add(iBlockData); 111 | } 112 | 113 | short[] coordArray = new short[coordList.size()]; 114 | IBlockData[] dataArray = new IBlockData[dataList.size()]; 115 | for(int i = 0; i < coordList.size(); i++){ 116 | coordArray[i] = coordList.get(i); 117 | dataArray[i] = dataList.get(i); 118 | } 119 | 120 | try { 121 | PacketPlayOutMultiBlockChange packet = new PacketPlayOutMultiBlockChange(); 122 | MultiBlockChangePacketHandler.a.set(packet, SectionPosition.a(sectionPosition.getX(), sectionPosition.getY(), sectionPosition.getZ())); 123 | MultiBlockChangePacketHandler.b.set(packet, coordArray); 124 | MultiBlockChangePacketHandler.c.set(packet, dataArray); 125 | MultiBlockChangePacketHandler.d.setBoolean(packet, true); 126 | 127 | packets.add(packet); 128 | }catch (Exception e){e.printStackTrace();} 129 | } 130 | 131 | return packets; 132 | } 133 | 134 | @Override 135 | public void sendChunkMultiBlockChangeUpdatePacket(Player player, ParallelChunk parallelChunk) { 136 | 137 | for(int sectionIndex = 0; sectionIndex < 16; sectionIndex++){ 138 | SectionTypeArray sectionTypeArray = parallelChunk.getSectionTypeArray(sectionIndex); 139 | if(sectionTypeArray == null) continue; 140 | 141 | List coordList = new ArrayList<>(); 142 | List dataList = new ArrayList<>(); 143 | 144 | boolean notEmpty = sectionTypeArray.threadsafeIteration((x, y, z, iBlockData) -> { 145 | coordList.add((short) (x << 8 | z << 4 | y)); 146 | dataList.add((IBlockData) iBlockData); 147 | }); 148 | 149 | if(!notEmpty) continue; 150 | 151 | short[] coordArray = new short[coordList.size()]; 152 | IBlockData[] dataArray = new IBlockData[dataList.size()]; 153 | for(int i = 0; i < coordList.size(); i++){ 154 | coordArray[i] = coordList.get(i); 155 | dataArray[i] = dataList.get(i); 156 | } 157 | 158 | try { 159 | PacketPlayOutMultiBlockChange packet = new PacketPlayOutMultiBlockChange(); 160 | MultiBlockChangePacketHandler.a.set(packet, SectionPosition.a(parallelChunk.getChunkX(), sectionIndex, parallelChunk.getChunkZ())); 161 | MultiBlockChangePacketHandler.b.set(packet, coordArray); 162 | MultiBlockChangePacketHandler.c.set(packet, dataArray); 163 | MultiBlockChangePacketHandler.d.setBoolean(packet, true); 164 | 165 | sendPacket(player, packet); 166 | }catch (Exception e){e.printStackTrace();} 167 | } 168 | } 169 | 170 | @Override 171 | public @Nullable Object createLightUpdatePacketAtPrimaryThread(ParallelChunk parallelChunk) { 172 | if(!Bukkit.isPrimaryThread()) throw new IllegalStateException("DO NOT CALL FROM ASYNC THREAD!"); 173 | 174 | World world = Bukkit.getWorld(parallelChunk.getWorld().getName()); 175 | if(world == null) return null; 176 | 177 | boolean has = false; 178 | for(int sectionIndex = 0; sectionIndex < 16; sectionIndex++){ 179 | SectionLevelArray blockLevelArray = parallelChunk.getBlockLightSectionLevelArray(sectionIndex); 180 | SectionLevelArray skyLevelArray = parallelChunk.getSkyLightSectionLevelArray(sectionIndex); 181 | 182 | if(blockLevelArray != null){ 183 | if(blockLevelArray.getSize() != 0) has = true; 184 | } 185 | if(skyLevelArray != null){ 186 | if(skyLevelArray.getSize() != 0) has = true; 187 | } 188 | } 189 | if(!has) return null; 190 | 191 | return new PacketPlayOutLightUpdate( 192 | new ChunkCoordIntPair(parallelChunk.getChunkX(), parallelChunk.getChunkZ()), 193 | ((CraftWorld) world).getHandle().getChunkProvider().getLightEngine(), true); 194 | } 195 | 196 | @Override 197 | public void sendClearChunkMultiBlockChangePacketAtPrimaryThread(Player player, ParallelChunk parallelChunk) { 198 | if (!Bukkit.isPrimaryThread()) throw new IllegalStateException("DO NOT CALL FROM ASYNC THREAD!"); 199 | 200 | World world = Bukkit.getWorld(parallelChunk.getWorld().getName()); 201 | if (world == null) return; 202 | 203 | if (player.getWorld() != world) return; 204 | 205 | Chunk chunk = world.getChunkAt(parallelChunk.getChunkX(), parallelChunk.getChunkZ()); 206 | net.minecraft.server.v1_16_R3.Chunk nmsChunk = ((CraftChunk) chunk).getHandle(); 207 | 208 | for (int sectionIndex = 0; sectionIndex < 16; sectionIndex++) { 209 | SectionTypeArray sectionTypeArray = parallelChunk.getSectionTypeArray(sectionIndex); 210 | if (sectionTypeArray == null) continue; 211 | 212 | ChunkSection chunkSection = nmsChunk.getSections()[sectionIndex]; 213 | if (chunkSection == null) continue; 214 | 215 | List coordList = new ArrayList<>(); 216 | List dataList = new ArrayList<>(); 217 | boolean notEmpty = sectionTypeArray.threadsafeIteration((x, y, z, iBlockData) -> { 218 | coordList.add((short) (x << 8 | z << 4 | y)); 219 | 220 | IBlockData chunkData = chunkSection.getType(x, y, z); 221 | if(chunkData == null) chunkData = ((CraftBlockData) org.bukkit.Material.AIR.createBlockData()).getState(); 222 | dataList.add(chunkData); 223 | }); 224 | if (!notEmpty) continue; 225 | 226 | short[] coordArray = new short[coordList.size()]; 227 | IBlockData[] dataArray = new IBlockData[dataList.size()]; 228 | for(int i = 0; i < coordList.size(); i++){ 229 | coordArray[i] = coordList.get(i); 230 | dataArray[i] = dataList.get(i); 231 | } 232 | 233 | try { 234 | PacketPlayOutMultiBlockChange packet = new PacketPlayOutMultiBlockChange(); 235 | MultiBlockChangePacketHandler.a.set(packet, SectionPosition.a(parallelChunk.getChunkX(), sectionIndex, parallelChunk.getChunkZ())); 236 | MultiBlockChangePacketHandler.b.set(packet, coordArray); 237 | MultiBlockChangePacketHandler.c.set(packet, dataArray); 238 | MultiBlockChangePacketHandler.d.setBoolean(packet, true); 239 | 240 | sendPacket(player, packet); 241 | }catch (Exception e){e.printStackTrace();} 242 | } 243 | } 244 | } 245 | --------------------------------------------------------------------------------