99import com .github .retrooper .packetevents .protocol .player .DiggingAction ;
1010import com .github .retrooper .packetevents .util .Vector3i ;
1111import com .github .retrooper .packetevents .wrapper .play .server .WrapperPlayServerBlockBreakAnimation ;
12+ import lombok .Getter ;
1213import org .bukkit .Bukkit ;
1314import org .bukkit .GameMode ;
1415import org .bukkit .Material ;
1920import org .bukkit .potion .PotionEffect ;
2021import org .bukkit .potion .PotionEffectType ;
2122
22- import java .util .Random ;
23+ import java .util .Set ;
2324import java .util .concurrent .ConcurrentHashMap ;
25+ import java .util .concurrent .ThreadLocalRandom ;
2426
27+ @ Getter
2528public class MiningUtils {
26- private final ConcurrentHashMap <BlockifyPosition , BlockifyBlockStage > blockStages ;
29+ private final ConcurrentHashMap <View , ConcurrentHashMap < BlockifyPosition , BlockifyBlockStage > > blockStages ;
2730
2831 public MiningUtils () {
2932 this .blockStages = new ConcurrentHashMap <>();
@@ -43,37 +46,40 @@ public void handleCustomDigging(Player player, View view, DiggingAction actionTy
4346 Bukkit .getScheduler ().runTask (Blockify .getInstance (), () -> player .addPotionEffect (new PotionEffect (PotionEffectType .SLOW_DIGGING , Integer .MAX_VALUE , -1 , true , false , false )));
4447
4548 // Update block stage periodically
46- if (!blockStages .containsKey (position )) {
47- blockStages .put (position , new BlockifyBlockStage ((byte ) 0 , System .currentTimeMillis ()));
49+ if (!blockStages .containsKey (view ) || blockStages .get (view ) == null || blockStages .get (view ).get (position ) == null ) {
50+ blockStages .putIfAbsent (view , new ConcurrentHashMap <>());
51+ blockStages .get (view ).put (position , new BlockifyBlockStage (ThreadLocalRandom .current ().nextInt (999999999 ) + 1000 , (byte ) 0 , System .currentTimeMillis ()));
4852 }
49- if (blockStages .get (position ).getTask () == 0 ) {
50- blockStages .get (position ).setTask (Bukkit .getScheduler ().runTaskTimerAsynchronously (Blockify .getInstance (), () -> {
51- if (player .isOnline () && blockStages .containsKey (position )) {
53+ if (blockStages .get (view ). get ( position ).getTask () == 0 ) {
54+ blockStages .get (view ). get ( position ).setTask (Bukkit .getScheduler ().runTaskTimerAsynchronously (Blockify .getInstance (), () -> {
55+ if (player .isOnline () && blockStages .get ( view ). containsKey (position )) {
5256 updateBlockStage (player , position , blockData , view );
5357 }
5458 }, 0 , 1 ).getTaskId ());
5559 }
5660
5761 // Check if cancelled digging
58- if (actionType == DiggingAction .CANCELLED_DIGGING && blockStages .containsKey (position )) {
59- Bukkit .getScheduler ().cancelTask (blockStages .get (position ).getTask ());
60- blockStages .get (position ).setTask (0 );
62+ if (actionType == DiggingAction .CANCELLED_DIGGING && blockStages .get ( view ). containsKey (position )) {
63+ Bukkit .getScheduler ().cancelTask (blockStages .get (view ). get ( position ).getTask ());
64+ blockStages .get (view ). get ( position ).setTask (0 );
6165 Bukkit .getScheduler ().runTask (Blockify .getInstance (), () -> player .removePotionEffect (PotionEffectType .SLOW_DIGGING ));
6266 return ;
6367 }
6468
6569 // Check if player can instantly break block (CREATIVE) or if mining speed is 0
6670 if (actionType == DiggingAction .START_DIGGING && (player .getGameMode () == GameMode .CREATIVE || view .getStage ().getAudience ().getMiningSpeed (player ) == 0 )) {
6771 actionType = DiggingAction .FINISHED_DIGGING ;
68- blockStages .get (position ).setStage ((byte ) 9 );
72+ blockStages .get (view ). get ( position ).setStage ((byte ) 9 );
6973 if (view .getStage ().getAudience ().getMiningSpeed (player ) == 0 ) {
70- WrapperPlayServerBlockBreakAnimation wrapperPlayServerBlockBreakAnimation = new WrapperPlayServerBlockBreakAnimation (new Random ().nextInt (999999999 ) + 1000 , new Vector3i (position .getX (), position .getY (), position .getZ ()), (byte ) 9 );
71- PacketEvents .getAPI ().getPlayerManager ().sendPacket (player , wrapperPlayServerBlockBreakAnimation );
74+ for (Player member : view .getStage ().getAudience ().getPlayers ()) {
75+ WrapperPlayServerBlockBreakAnimation wrapperPlayServerBlockBreakAnimation = new WrapperPlayServerBlockBreakAnimation (blockStages .get (view ).get (position ).getEntityId (), new Vector3i (position .getX (), position .getY (), position .getZ ()), (byte ) 9 );
76+ PacketEvents .getAPI ().getPlayerManager ().getUser (member ).writePacket (wrapperPlayServerBlockBreakAnimation );
77+ }
7278 }
7379 }
7480
7581 // Block break functionality
76- if (actionType == DiggingAction .FINISHED_DIGGING && blockStages .get (position ).getStage () >= 9 ) {
82+ if (actionType == DiggingAction .FINISHED_DIGGING && blockStages .get (view ). get ( position ).getStage () >= 9 ) {
7783 breakCustomBlock (player , position , blockData , view );
7884 }
7985 }
@@ -126,11 +132,14 @@ public boolean canInstantBreak(Player player, BlockData blockData) {
126132 */
127133 public void updateBlockStage (Player player , BlockifyPosition position , BlockData blockData , View view ) {
128134 // Check if block stage exists, if not, return
129- if (!blockStages .containsKey (position ) || blockStages .get (position ) == null ) return ;
135+ if (!blockStages .containsKey (view ) || blockStages .get (view ) == null || ! blockStages . get ( view ). containsKey ( position ) ) return ;
130136 // Get block stage and check if it is null, if so, remove it from the map and return
131- BlockifyBlockStage blockStage = blockStages .get (position );
137+ BlockifyBlockStage blockStage = blockStages .get (view ). get ( position );
132138 if (blockStage == null ) {
133- blockStages .remove (position );
139+ blockStages .get (view ).remove (position );
140+ if (blockStages .get (view ).isEmpty ()) {
141+ blockStages .remove (view );
142+ }
134143 return ;
135144 }
136145 // If the time difference between the last updated time and the current time is greater than a 1/9th of the mining time, update the block stage
@@ -147,9 +156,11 @@ public void updateBlockStage(Player player, BlockifyPosition position, BlockData
147156 }
148157 }
149158 // Send block break animation packet
150- if (blockStages .get (position ) == null || blockStages .get (position ).getStage () >= 9 ) return ;
151- WrapperPlayServerBlockBreakAnimation wrapperPlayServerBlockBreakAnimation = new WrapperPlayServerBlockBreakAnimation (new Random ().nextInt (999999999 ) + 1000 , new Vector3i (position .getX (), position .getY (), position .getZ ()), blockStages .get (position ).getStage ());
152- PacketEvents .getAPI ().getPlayerManager ().sendPacket (player , wrapperPlayServerBlockBreakAnimation );
159+ if (!blockStages .containsKey (view ) || blockStages .get (view ) == null || !blockStages .get (view ).containsKey (position ) || blockStages .get (view ).get (position ).getStage () >= 9 ) return ;
160+ for (Player member : view .getStage ().getAudience ().getPlayers ()) {
161+ WrapperPlayServerBlockBreakAnimation wrapperPlayServerBlockBreakAnimation = new WrapperPlayServerBlockBreakAnimation (blockStages .get (view ).get (position ).getEntityId (), new Vector3i (position .getX (), position .getY (), position .getZ ()), blockStages .get (view ).get (position ).getStage ());
162+ PacketEvents .getAPI ().getPlayerManager ().sendPacket (member , wrapperPlayServerBlockBreakAnimation );
163+ }
153164 }
154165
155166 /**
@@ -167,10 +178,7 @@ public void breakCustomBlock(Player player, BlockifyPosition position, BlockData
167178 BlockifyBreakEvent ghostBreakEvent = new BlockifyBreakEvent (player , position .toPosition (), blockData , view , view .getStage ());
168179 ghostBreakEvent .callEvent ();
169180 // If block stage exists, cancel the task and remove it from the map
170- if (blockStages .containsKey (position )) {
171- Bukkit .getScheduler ().cancelTask (blockStages .get (position ).getTask ());
172- blockStages .remove (position );
173- }
181+ resetViewBlockAnimation (view , Set .of (position ));
174182 // Remove mining fatigue effect
175183 player .removePotionEffect (PotionEffectType .SLOW_DIGGING );
176184 // If block is not cancelled, break the block, otherwise, revert the block
@@ -183,6 +191,30 @@ public void breakCustomBlock(Player player, BlockifyPosition position, BlockData
183191 });
184192 }
185193
194+ /**
195+ * Reset view's block animation at the specified positions
196+ *
197+ * @param view View of the player
198+ * @param positions Set of BlockifyPosition
199+ */
200+ public void resetViewBlockAnimation (View view , Set <BlockifyPosition > positions ) {
201+ if (!blockStages .containsKey (view ) || blockStages .get (view ) == null ) return ;
202+ for (BlockifyPosition position : positions ) {
203+ if (blockStages .get (view ).containsKey (position )) {
204+ Bukkit .getScheduler ().cancelTask (blockStages .get (view ).get (position ).getTask ());
205+ int id = blockStages .get (view ).remove (position ).getEntityId ();
206+ for (Player member : view .getStage ().getAudience ().getPlayers ()) {
207+ WrapperPlayServerBlockBreakAnimation wrapperPlayServerBlockBreakAnimation = new WrapperPlayServerBlockBreakAnimation (id , new Vector3i (position .getX (), position .getY (), position .getZ ()), (byte ) -1 );
208+ PacketEvents .getAPI ().getPlayerManager ().getUser (member ).writePacket (wrapperPlayServerBlockBreakAnimation );
209+ }
210+ if (blockStages .get (view ).isEmpty ()) {
211+ blockStages .remove (view );
212+ return ;
213+ }
214+ }
215+ }
216+ }
217+
186218 /**
187219 * Calculates the total mining time in milliseconds.
188220 * Referenced from <a href="https://minecraft.fandom.com/wiki/Breaking#Calculation">Minecraft Fandom</a>.
0 commit comments