Skip to content

Commit b1e77b3

Browse files
authored
Merge pull request #10 from Kooperlol/1.0.0
1.0.0
2 parents 60f102a + 8e35aca commit b1e77b3

10 files changed

Lines changed: 89 additions & 85 deletions

File tree

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ plugins {
44
}
55

66
group = 'codes.kooper'
7-
version = '1.0.0-alpha'
7+
version = '1.0.0-alpha-2'
88

99
repositories {
1010
mavenCentral()

src/main/java/codes/kooper/blockify/events/BlockifyBreakEvent.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import codes.kooper.blockify.models.Stage;
44
import codes.kooper.blockify.models.View;
5-
import io.papermc.paper.math.Position;
5+
import codes.kooper.blockify.types.BlockifyPosition;
66
import lombok.Getter;
77
import org.bukkit.block.data.BlockData;
88
import org.bukkit.entity.Player;
@@ -16,7 +16,7 @@ public class BlockifyBreakEvent extends Event implements Cancellable {
1616
private static final HandlerList HANDLERS = new HandlerList();
1717
private boolean cancelled = false;
1818
private final Player player;
19-
private final Position position;
19+
private final BlockifyPosition position;
2020
private final BlockData blockData;
2121
private final View view;
2222
private final Stage stage;
@@ -30,7 +30,7 @@ public class BlockifyBreakEvent extends Event implements Cancellable {
3030
* @param view The view that the player is in.
3131
* @param stage The stage that the player is in.
3232
*/
33-
public BlockifyBreakEvent(Player player, Position position, BlockData blockData, View view, Stage stage) {
33+
public BlockifyBreakEvent(Player player, BlockifyPosition position, BlockData blockData, View view, Stage stage) {
3434
this.player = player;
3535
this.position = position;
3636
this.blockData = blockData;

src/main/java/codes/kooper/blockify/events/BlockifyInteractEvent.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import codes.kooper.blockify.models.Stage;
44
import codes.kooper.blockify.models.View;
5-
import io.papermc.paper.math.Position;
5+
import codes.kooper.blockify.types.BlockifyPosition;
66
import lombok.Getter;
77
import org.bukkit.block.data.BlockData;
88
import org.bukkit.entity.Player;
@@ -16,7 +16,7 @@ public class BlockifyInteractEvent extends Event implements Cancellable {
1616
private static final HandlerList HANDLERS = new HandlerList();
1717
private boolean cancelled = false;
1818
private final Player player;
19-
private final Position position;
19+
private final BlockifyPosition position;
2020
private final BlockData blockData;
2121
private final View view;
2222
private final Stage stage;
@@ -30,7 +30,7 @@ public class BlockifyInteractEvent extends Event implements Cancellable {
3030
* @param view The view that the player is currently in.
3131
* @param stage The stage that the player is currently in.
3232
*/
33-
public BlockifyInteractEvent(Player player, Position position, BlockData blockData, View view, Stage stage) {
33+
public BlockifyInteractEvent(Player player, BlockifyPosition position, BlockData blockData, View view, Stage stage) {
3434
this.player = player;
3535
this.position = position;
3636
this.blockData = blockData;

src/main/java/codes/kooper/blockify/events/BlockifyPlaceEvent.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import codes.kooper.blockify.models.Stage;
44
import codes.kooper.blockify.models.View;
5-
import io.papermc.paper.math.Position;
5+
import codes.kooper.blockify.types.BlockifyPosition;
66
import lombok.Getter;
77
import org.bukkit.entity.Player;
88
import org.bukkit.event.Event;
@@ -13,7 +13,7 @@
1313
public class BlockifyPlaceEvent extends Event {
1414
private static final HandlerList HANDLERS = new HandlerList();
1515
private final Player player;
16-
private final Position position;
16+
private final BlockifyPosition position;
1717
private final View view;
1818
private final Stage stage;
1919

@@ -25,7 +25,7 @@ public class BlockifyPlaceEvent extends Event {
2525
* @param view The view that the player is currently in.
2626
* @param stage The stage that the player is currently in.
2727
*/
28-
public BlockifyPlaceEvent(Player player, Position position, View view, Stage stage) {
28+
public BlockifyPlaceEvent(Player player, BlockifyPosition position, View view, Stage stage) {
2929
this.player = player;
3030
this.position = position;
3131
this.view = view;

src/main/java/codes/kooper/blockify/managers/BlockChangeManager.java

Lines changed: 68 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
1717
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerChunkData;
1818
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
19+
import io.papermc.paper.math.Position;
1920
import lombok.Getter;
2021
import org.bukkit.Bukkit;
2122
import org.bukkit.Chunk;
@@ -61,14 +62,7 @@ public void sendViews(Stage stage, Player player) {
6162
*/
6263
public void sendView(Player player, View view) {
6364
Audience audience = Audience.fromPlayers(new HashSet<>(Collections.singletonList(player)));
64-
ConcurrentHashMap<BlockifyChunk, ConcurrentHashMap<BlockifyPosition, BlockData>> blocks = new ConcurrentHashMap<>();
65-
for (Map.Entry<BlockifyChunk, ConcurrentHashMap<BlockifyPosition, BlockData>> entry : view.getBlocks().entrySet()) {
66-
if (!blocks.containsKey(entry.getKey())) {
67-
blocks.put(entry.getKey(), new ConcurrentHashMap<>());
68-
}
69-
blocks.get(entry.getKey()).putAll(entry.getValue());
70-
}
71-
sendBlockChanges(view.getStage(), audience, blocks);
65+
sendBlockChanges(view.getStage(), audience, view.getBlocks().keySet());
7266
}
7367

7468
/**
@@ -80,16 +74,7 @@ public void sendView(Player player, View view) {
8074
*/
8175
public void hideView(Player player, View view) {
8276
Audience audience = Audience.fromPlayers(new HashSet<>(Collections.singletonList(player)));
83-
ConcurrentHashMap<BlockifyChunk, ConcurrentHashMap<BlockifyPosition, BlockData>> blocks = new ConcurrentHashMap<>();
84-
for (Map.Entry<BlockifyChunk, ConcurrentHashMap<BlockifyPosition, BlockData>> entry : view.getBlocks().entrySet()) {
85-
if (!blocks.containsKey(entry.getKey())) {
86-
blocks.put(entry.getKey(), new ConcurrentHashMap<>());
87-
}
88-
for (Map.Entry<BlockifyPosition, BlockData> blockEntry : entry.getValue().entrySet()) {
89-
blocks.get(entry.getKey()).put(blockEntry.getKey(), view.getStage().getWorld().getBlockData(blockEntry.getKey().getX(), blockEntry.getKey().getY(), blockEntry.getKey().getZ()));
90-
}
91-
}
92-
sendBlockChanges(view.getStage(), audience, blocks);
77+
sendBlockChanges(view.getStage(), audience, view.getBlocks().keySet(), true);
9378
}
9479

9580
/**
@@ -111,14 +96,10 @@ public void hideViews(Stage stage, Player player) {
11196
* @param stage the stage
11297
* @param audience the audience
11398
* @param position the position
114-
* @param blockData the block data
11599
*/
116-
public void sendBlockChange(Stage stage, Audience audience, BlockifyPosition position, BlockData blockData) {
117-
ConcurrentHashMap<BlockifyChunk, ConcurrentHashMap<BlockifyPosition, BlockData>> blockChanges = new ConcurrentHashMap<>();
100+
public void sendBlockChange(Stage stage, Audience audience, BlockifyPosition position) {
118101
BlockifyChunk chunk = new BlockifyChunk(position.getX() >> 4, position.getZ() >> 4);
119-
blockChanges.put(chunk, new ConcurrentHashMap<>());
120-
blockChanges.get(chunk).put(position, blockData);
121-
sendBlockChanges(stage, audience, blockChanges);
102+
sendBlockChanges(stage, audience, Collections.singleton(chunk));
122103
}
123104

124105
/**
@@ -127,12 +108,23 @@ public void sendBlockChange(Stage stage, Audience audience, BlockifyPosition pos
127108
*
128109
* @param stage the stage
129110
* @param audience the audience
130-
* @param blockChanges the block changes
111+
* @param chunks the chunks to send
131112
*/
132-
public void sendBlockChanges(Stage stage, Audience audience, ConcurrentHashMap<BlockifyChunk, ConcurrentHashMap<BlockifyPosition, BlockData>> blockChanges) {
133-
if (blockChanges.isEmpty()) {
134-
return;
135-
}
113+
public void sendBlockChanges(Stage stage, Audience audience, Collection<BlockifyChunk> chunks) {
114+
sendBlockChanges(stage, audience, chunks, false);
115+
}
116+
117+
/**
118+
* Sends block changes to the audience.
119+
* Call Asynchronously
120+
*
121+
* @param stage the stage
122+
* @param audience the audience
123+
* @param chunks the chunks to send
124+
* @param unload whether to unload the chunks
125+
*/
126+
public void sendBlockChanges(Stage stage, Audience audience, Collection<BlockifyChunk> chunks, boolean unload) {
127+
ConcurrentHashMap<BlockifyChunk, ConcurrentHashMap<BlockifyPosition, BlockData>> blockChanges = getBlockChanges(stage, chunks);
136128
Bukkit.getScheduler().runTask(Blockify.getInstance(), () -> new OnBlockChangeSendEvent(stage, blockChanges).callEvent());
137129

138130
// If there is only one block change, send it to the player directly
@@ -152,6 +144,21 @@ public void sendBlockChanges(Stage stage, Audience audience, ConcurrentHashMap<B
152144
return;
153145
}
154146

147+
// Less than 3,000 blocks then use the player.sendBlockChanges method
148+
if (blockCount < 3000) {
149+
Map<Position, BlockData> multiBlockChange = new HashMap<>();
150+
for (BlockifyChunk chunk : chunks) {
151+
if (!stage.getWorld().isChunkLoaded(chunk.x(), chunk.z())) continue;
152+
for (Map.Entry<BlockifyPosition, BlockData> entry : blockChanges.get(chunk).entrySet()) {
153+
multiBlockChange.put(entry.getKey().toPosition(), entry.getValue());
154+
}
155+
}
156+
for (Player player : audience.getOnlinePlayers()) {
157+
player.sendMultiBlockChange(multiBlockChange);
158+
}
159+
return;
160+
}
161+
155162
// Send multiple block changes to the players
156163
for (Player onlinePlayer : audience.getOnlinePlayers()) {
157164
Location playerLocation = onlinePlayer.getLocation();
@@ -160,7 +167,7 @@ public void sendBlockChanges(Stage stage, Audience audience, ConcurrentHashMap<B
160167
// The chunk index is used to keep track of the current chunk being sent
161168
AtomicInteger chunkIndex = new AtomicInteger(0);
162169
// Create an array of chunks to send from the block changes map
163-
List<BlockifyChunk> chunksToSend = new ArrayList<>(List.of(blockChanges.keySet().toArray(new BlockifyChunk[0])));
170+
List<BlockifyChunk> chunksToSend = new ArrayList<>(chunks.stream().toList());
164171
chunksToSend.sort((chunk1, chunk2) -> {
165172
// Get distance from chunks to player
166173
int x = playerLocation.getBlockX() / 16;
@@ -206,10 +213,10 @@ public void sendBlockChanges(Stage stage, Audience audience, ConcurrentHashMap<B
206213
chunkIndex.getAndIncrement();
207214

208215
// Check if the chunk is loaded; if not, return
209-
if (!stage.getWorld().isChunkLoaded(chunk.x(), chunk.z())) return;
216+
if (!stage.getWorld().isChunkLoaded(chunk.x(), chunk.z())) continue;
210217

211218
// Send the chunk packet to the player
212-
Bukkit.getScheduler().runTaskAsynchronously(Blockify.getInstance(), () -> sendChunkPacket(onlinePlayer, chunk, blockChanges));
219+
Bukkit.getScheduler().runTaskAsynchronously(Blockify.getInstance(), () -> sendChunkPacket(stage, onlinePlayer, chunk, unload));
213220
}
214221
}, 0L, 1L));
215222
}
@@ -219,14 +226,18 @@ public void sendBlockChanges(Stage stage, Audience audience, ConcurrentHashMap<B
219226
* Sends a chunk packet to the player.
220227
* Call Asynchronously
221228
*
229+
* @param stage the stage
222230
* @param player the player
223231
* @param chunk the chunk
224-
* @param blockChanges the block changes
225232
*/
226-
public void sendChunkPacket(Player player, BlockifyChunk chunk, ConcurrentHashMap<BlockifyChunk, ConcurrentHashMap<BlockifyPosition, BlockData>> blockChanges) {
233+
public void sendChunkPacket(Stage stage, Player player, BlockifyChunk chunk, boolean unload) {
227234
User packetUser = PacketEvents.getAPI().getPlayerManager().getUser(player);
228-
ConcurrentHashMap<BlockifyPosition, BlockData> blockData = blockChanges.get(chunk);
229235
int ySections = packetUser.getTotalWorldHeight() >> 4;
236+
ConcurrentHashMap<BlockifyPosition, BlockData> blockData = null;
237+
if (!unload) {
238+
ConcurrentHashMap<BlockifyChunk, ConcurrentHashMap<BlockifyPosition, BlockData>> blockChanges = getBlockChanges(stage, Collections.singleton(chunk));
239+
blockData = blockChanges.get(chunk);
240+
}
230241
Map<BlockData, WrappedBlockState> blockDataToState = new HashMap<>();
231242
List<BaseChunk> chunks = new ArrayList<>();
232243
Chunk bukkitChunk = player.getWorld().getChunkAt(chunk.x(), chunk.z());
@@ -244,7 +255,7 @@ public void sendChunkPacket(Player player, BlockifyChunk chunk, ConcurrentHashMa
244255
int worldY = (i << 4) + y + minHeight;
245256
BlockifyPosition position = new BlockifyPosition(x + (chunk.x() << 4), worldY, z + (chunk.z() << 4));
246257

247-
if (blockData.containsKey(position)) {
258+
if (!unload && blockData != null && blockData.containsKey(position)) {
248259
BlockData data = blockData.get(position);
249260
WrappedBlockState state = blockDataToState.computeIfAbsent(data, SpigotConversionUtil::fromBukkitBlockData);
250261
baseChunk.set(x, y, z, state);
@@ -272,21 +283,35 @@ public void sendChunkPacket(Player player, BlockifyChunk chunk, ConcurrentHashMa
272283
// TODO: Implement Tile Entities
273284
Column column = new Column(chunk.x(), chunk.z(), true, chunks.toArray(new BaseChunk[0]), null);
274285
LightData lightData = new LightData();
275-
byte[][] emptyLightArray = new byte[ySections][0];
286+
byte[][] fullLightArray = new byte[ySections][2048];
287+
for (int i = 0; i < ySections; i++) {
288+
Arrays.fill(fullLightArray[i], (byte) 0xFF);
289+
}
290+
BitSet fullBitSet = new BitSet();
276291
BitSet emptyBitSet = new BitSet();
277-
BitSet lightBitSet = new BitSet();
278292
for (int i = 0; i < ySections; i++) {
279-
emptyBitSet.set(i, true);
293+
fullBitSet.set(i, true);
280294
}
281-
lightData.setBlockLightArray(emptyLightArray);
282-
lightData.setSkyLightArray(emptyLightArray);
295+
lightData.setBlockLightArray(fullLightArray);
296+
lightData.setSkyLightArray(fullLightArray);
283297
lightData.setBlockLightCount(ySections);
284298
lightData.setSkyLightCount(ySections);
285-
lightData.setBlockLightMask(lightBitSet);
286-
lightData.setSkyLightMask(lightBitSet);
299+
lightData.setBlockLightMask(fullBitSet);
300+
lightData.setSkyLightMask(fullBitSet);
287301
lightData.setEmptyBlockLightMask(emptyBitSet);
288302
lightData.setEmptySkyLightMask(emptyBitSet);
289303
WrapperPlayServerChunkData chunkData = new WrapperPlayServerChunkData(column, lightData);
290304
packetUser.sendPacketSilently(chunkData);
291305
}
306+
307+
private ConcurrentHashMap<BlockifyChunk, ConcurrentHashMap<BlockifyPosition, BlockData>> getBlockChanges(Stage stage, Collection<BlockifyChunk> chunks) {
308+
ConcurrentHashMap<BlockifyChunk, ConcurrentHashMap<BlockifyPosition, BlockData>> blockChanges = new ConcurrentHashMap<>();
309+
for (View view : stage.getViews()) {
310+
for (Map.Entry<BlockifyChunk, ConcurrentHashMap<BlockifyPosition, BlockData>> entry : view.getBlocks().entrySet()) {
311+
if (!chunks.contains(entry.getKey())) continue;
312+
blockChanges.put(entry.getKey(), entry.getValue());
313+
}
314+
}
315+
return blockChanges;
316+
}
292317
}

src/main/java/codes/kooper/blockify/models/Stage.java

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,10 @@
77
import lombok.Setter;
88
import org.bukkit.Location;
99
import org.bukkit.World;
10-
import org.bukkit.block.data.BlockData;
1110

1211
import java.util.HashSet;
1312
import java.util.Set;
14-
import java.util.concurrent.ConcurrentHashMap;
13+
import java.util.stream.Collectors;
1514

1615
@Getter
1716
@Setter
@@ -57,11 +56,7 @@ public boolean isLocationWithin(Location location) {
5756
* Send blocks to the audience. Should be called asynchronously.
5857
*/
5958
public void sendBlocksToAudience() {
60-
ConcurrentHashMap<BlockifyChunk, ConcurrentHashMap<BlockifyPosition, BlockData>> blocks = new ConcurrentHashMap<>();
61-
for (View view : views) {
62-
blocks.putAll(view.getBlocks());
63-
}
64-
Blockify.getInstance().getBlockChangeManager().sendBlockChanges(this, audience, blocks);
59+
Blockify.getInstance().getBlockChangeManager().sendBlockChanges(this, audience, getChunks());
6560
}
6661

6762
/**
@@ -71,20 +66,8 @@ public void sendBlocksToAudience() {
7166
* @param blocks Blocks to refresh to the audience.
7267
*/
7368
public void refreshBlocksToAudience(Set<BlockifyPosition> blocks) {
74-
ConcurrentHashMap<BlockifyChunk, ConcurrentHashMap<BlockifyPosition, BlockData>> blockChanges = new ConcurrentHashMap<>();
75-
for (View view : views) {
76-
for (BlockifyPosition position : blocks) {
77-
if (!view.hasBlock(position)) continue;
78-
if (blockChanges.containsKey(position.toBlockifyChunk())) {
79-
blockChanges.get(position.toBlockifyChunk()).put(position, view.getBlock(position));
80-
} else {
81-
ConcurrentHashMap<BlockifyPosition, BlockData> blockData = new ConcurrentHashMap<>();
82-
blockData.put(position, view.getBlock(position));
83-
blockChanges.put(position.toBlockifyChunk(), blockData);
84-
}
85-
}
86-
}
87-
Blockify.getInstance().getBlockChangeManager().sendBlockChanges(this, audience, blockChanges);
69+
Set<BlockifyChunk> chunks = blocks.stream().map(BlockifyPosition::toBlockifyChunk).collect(Collectors.toSet());
70+
Blockify.getInstance().getBlockChangeManager().sendBlockChanges(this, audience, chunks);
8871
}
8972

9073
/**

src/main/java/codes/kooper/blockify/protocol/BlockDigAdapter.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public void onPacketPlayReceive(PacketPlayReceiveEvent event) {
4747
BlockData blockData = view.getBlock(position);
4848

4949
// Call BlockifyInteractEvent to handle custom interaction
50-
Bukkit.getScheduler().runTask(Blockify.getInstance(), () -> new BlockifyInteractEvent(player, position.toPosition(), blockData, view, view.getStage()).callEvent());
50+
Bukkit.getScheduler().runTask(Blockify.getInstance(), () -> new BlockifyInteractEvent(player, position, blockData, view, view.getStage()).callEvent());
5151

5252
// Check if block is breakable, if not, send block change packet to cancel the break
5353
if (!view.isBreakable()) {
@@ -59,12 +59,12 @@ public void onPacketPlayReceive(PacketPlayReceiveEvent event) {
5959
if (actionType == DiggingAction.FINISHED_DIGGING || canInstantBreak(player, blockData)) {
6060
Bukkit.getScheduler().runTask(Blockify.getInstance(), () -> {
6161
// Call BlockifyBreakEvent
62-
BlockifyBreakEvent blockifyBreakEvent = new BlockifyBreakEvent(player, position.toPosition(), blockData, view, view.getStage());
62+
BlockifyBreakEvent blockifyBreakEvent = new BlockifyBreakEvent(player, position, blockData, view, view.getStage());
6363
blockifyBreakEvent.callEvent();
6464
// If block is not cancelled, break the block, otherwise, revert the block
6565
if (!blockifyBreakEvent.isCancelled()) {
66-
Blockify.getInstance().getBlockChangeManager().sendBlockChange(view.getStage(), view.getStage().getAudience(), position, Material.AIR.createBlockData());
6766
view.setBlock(position, Material.AIR.createBlockData());
67+
Blockify.getInstance().getBlockChangeManager().sendBlockChange(view.getStage(), view.getStage().getAudience(), position);
6868
} else {
6969
player.sendBlockChange(position.toLocation(player.getWorld()), blockData);
7070
}

0 commit comments

Comments
 (0)