Skip to content

Commit 1542ff8

Browse files
authored
Merge pull request #1 from LuminiaDev/feat/new-offsets
feat: new offsets, fake blocks and non-reflection event handler
2 parents 8d5d7e1 + 65957fc commit 1542ff8

9 files changed

Lines changed: 161 additions & 59 deletions

File tree

build.gradle.kts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,22 @@ plugins {
33
id("maven-publish")
44
}
55

6-
group = "me.iwareq.fakeinventories"
7-
version = "1.1.9-MOT"
6+
group = "com.luminiadev.fakeinventories"
7+
version = "1.2.0"
88

99
java {
1010
toolchain {
11-
languageVersion = JavaLanguageVersion.of(17)
11+
languageVersion = JavaLanguageVersion.of(21)
1212
}
1313
}
1414

1515
repositories {
1616
mavenCentral()
17-
maven("https://repo.lanink.cn/repository/maven-public/")
17+
maven("https://repo.luminiadev.com/snapshots")
1818
}
1919

2020
dependencies {
21-
compileOnly("cn.nukkit:Nukkit:MOT-SNAPSHOT")
21+
compileOnly("com.koshakmine:Lumi:1.2.0-SNAPSHOT")
2222
compileOnly("org.projectlombok:lombok:1.18.38")
2323
annotationProcessor("org.projectlombok:lombok:1.18.38")
2424
}

src/main/java/me/iwareq/fakeinventories/FakeInventories.java

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@
22

33
import cn.nukkit.block.BlockID;
44
import cn.nukkit.blockentity.BlockEntity;
5-
import cn.nukkit.event.EventHandler;
65
import cn.nukkit.event.EventPriority;
76
import cn.nukkit.event.Listener;
87
import cn.nukkit.event.inventory.InventoryTransactionEvent;
98
import cn.nukkit.inventory.InventoryType;
109
import cn.nukkit.inventory.transaction.action.SlotChangeAction;
1110
import cn.nukkit.item.Item;
1211
import cn.nukkit.plugin.PluginBase;
12+
import lombok.Getter;
1313
import me.iwareq.fakeinventories.block.DoubleFakeBlock;
1414
import me.iwareq.fakeinventories.block.FakeBlock;
15+
import me.iwareq.fakeinventories.block.FakeBlockOffset;
1516
import me.iwareq.fakeinventories.block.SingleFakeBlock;
16-
import lombok.Getter;
1717

1818
import java.util.EnumMap;
1919
import java.util.Map;
@@ -24,10 +24,12 @@ public class FakeInventories extends PluginBase implements Listener {
2424
private static FakeInventories instance;
2525

2626
private static final Map<InventoryType, FakeBlock> FAKE_BLOCKS = new EnumMap<>(InventoryType.class);
27+
private static FakeBlockOffset FAKE_BLOCK_OFFSET;
2728

2829
@Override
2930
public void onLoad() {
30-
instance = this;
31+
FakeInventories.instance = this;
32+
this.saveDefaultConfig();
3133
FAKE_BLOCKS.put(InventoryType.CHEST, new SingleFakeBlock(BlockID.CHEST, BlockEntity.CHEST));
3234
FAKE_BLOCKS.put(InventoryType.ENDER_CHEST, new SingleFakeBlock(BlockID.ENDER_CHEST, BlockEntity.ENDER_CHEST));
3335
FAKE_BLOCKS.put(InventoryType.DOUBLE_CHEST, new DoubleFakeBlock(BlockID.CHEST, BlockEntity.CHEST));
@@ -38,30 +40,33 @@ public void onLoad() {
3840
FAKE_BLOCKS.put(InventoryType.DROPPER, new SingleFakeBlock(BlockID.DROPPER, InventoryType.DROPPER.getDefaultTitle()));
3941
FAKE_BLOCKS.put(InventoryType.HOPPER, new SingleFakeBlock(BlockID.HOPPER_BLOCK, BlockEntity.HOPPER));
4042
FAKE_BLOCKS.put(InventoryType.SHULKER_BOX, new SingleFakeBlock(BlockID.SHULKER_BOX, BlockEntity.SHULKER_BOX));
43+
FAKE_BLOCK_OFFSET = FakeBlockOffset.valueOf(this.getConfig().getString("fake-block-offset-mode").toUpperCase());
4144
}
4245

4346
@Override
4447
public void onEnable() {
45-
this.getServer().getPluginManager().registerEvents(this, this);
46-
}
47-
48-
@EventHandler(priority = EventPriority.MONITOR)
49-
public void onInventoryTransaction(InventoryTransactionEvent event) {
50-
event.getTransaction().getActions().forEach(action -> {
51-
if (action instanceof SlotChangeAction slotChange) {
52-
if (slotChange.getInventory() instanceof FakeInventory inventory) {
53-
int slot = slotChange.getSlot();
54-
Item sourceItem = action.getSourceItem();
55-
inventory.handle(slot, sourceItem, event);
48+
this.getServer().getPluginManager().subscribeEvent(InventoryTransactionEvent.class, event -> {
49+
event.getTransaction().getActions().forEach(action -> {
50+
if (action instanceof SlotChangeAction slotChange) {
51+
if (slotChange.getInventory() instanceof FakeInventory inventory) {
52+
int slot = slotChange.getSlot();
53+
Item sourceItem = action.getSourceItem();
54+
inventory.handle(slot, sourceItem, event);
55+
}
5656
}
57-
}
58-
});
57+
});
58+
}, EventPriority.MONITOR, this);
5959
}
60+
6061
public static FakeBlock getFakeBlock(InventoryType inventoryType) {
6162
FakeBlock fakeBlock = FAKE_BLOCKS.get(inventoryType);
6263
if (fakeBlock == null) {
6364
throw new NullPointerException("FakeBlock for " + inventoryType.name() + " inventory not found!");
6465
}
6566
return fakeBlock;
6667
}
68+
69+
public static FakeBlockOffset getFakeBlockOffset() {
70+
return FAKE_BLOCK_OFFSET;
71+
}
6772
}

src/main/java/me/iwareq/fakeinventories/FakeInventory.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import me.iwareq.fakeinventories.util.ItemHandler;
1616

1717
import java.util.HashMap;
18+
import java.util.List;
1819
import java.util.Map;
1920

2021
public class FakeInventory extends BaseInventory {
@@ -48,7 +49,12 @@ public void onOpen(Player player) {
4849
packet.windowId = player.getWindowId(this);
4950
packet.type = this.getType().getNetworkType();
5051

51-
Vector3 position = this.fakeBlock.getPositions(player).get(0);
52+
List<Vector3> positions = this.fakeBlock.getPlacePositions(player);
53+
if (positions.isEmpty()) {
54+
return;
55+
}
56+
57+
Vector3 position = positions.get(0);
5258
packet.x = position.getFloorX();
5359
packet.y = position.getFloorY();
5460
packet.z = position.getFloorZ();

src/main/java/me/iwareq/fakeinventories/block/DoubleFakeBlock.java

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,20 @@ public DoubleFakeBlock(int blockId, String tileId) {
1616
}
1717

1818
@Override
19-
public List<Vector3> getPositions(Player player) {
20-
Vector3 blockPosition = player.getPosition().add(this.getOffset(player)).floor();
21-
DimensionData dimensionData = player.getLevel().getDimensionData();
22-
if (blockPosition.getFloorY() >= dimensionData.getMinHeight() && blockPosition.getFloorY() < dimensionData.getMaxHeight()) {
23-
if ((blockPosition.getFloorX() & 1) == 1) {
24-
return Arrays.asList(blockPosition, blockPosition.east());
19+
public List<Vector3> getPlacePositions(Player player) {
20+
Vector3 position = player.getPosition().add(this.getOffset(player)).floor();
21+
DimensionData dimension = player.getLevel().getDimensionData();
22+
if (position.getFloorY() >= dimension.getMinHeight() && position.getFloorY() < dimension.getMaxHeight()) {
23+
if ((position.getFloorX() & 1) == 1) {
24+
return Arrays.asList(position, position.east());
2525
}
26-
return Arrays.asList(blockPosition, blockPosition.west());
26+
return Arrays.asList(position, position.west());
2727
}
28-
2928
return Collections.emptyList();
3029
}
3130

3231
@Override
33-
protected Vector3 getOffset(Player player) {
32+
public Vector3 getOffset(Player player) {
3433
Vector3 offset = super.getOffset(player);
3534
offset.x *= 1.5;
3635
offset.z *= 1.5;
@@ -39,9 +38,8 @@ protected Vector3 getOffset(Player player) {
3938

4039
@Override
4140
protected CompoundTag getBlockEntityDataAt(Vector3 position, String title) {
42-
int pairX = (position.getFloorX() & 1) == 1 ? 1 : -1;
4341
return super.getBlockEntityDataAt(position, title)
44-
.putInt("pairx", position.getFloorX() + pairX)
42+
.putInt("pairx", position.getFloorX() + ((position.getFloorX() & 1) == 1 ? 1 : -1))
4543
.putInt("pairz", position.getFloorZ());
4644
}
4745
}

src/main/java/me/iwareq/fakeinventories/block/FakeBlock.java

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,30 @@
33
import cn.nukkit.Player;
44
import cn.nukkit.level.DimensionData;
55
import cn.nukkit.math.Vector3;
6+
import me.iwareq.fakeinventories.FakeInventories;
67

78
import java.util.Collections;
89
import java.util.List;
10+
import java.util.Set;
911

10-
public abstract class FakeBlock {
12+
public interface FakeBlock {
1113

12-
public abstract void create(Player player, String title);
14+
void create(Player player, String title);
1315

14-
public abstract void remove(Player player);
16+
void remove(Player player);
1517

16-
public List<Vector3> getPositions(Player player) {
17-
Vector3 blockPosition = player.getPosition().add(this.getOffset(player)).floor();
18-
DimensionData dimensionData = player.getLevel().getDimensionData();
19-
if (blockPosition.getFloorY() >= dimensionData.getMinHeight() && blockPosition.getFloorY() < dimensionData.getMaxHeight())
20-
return Collections.singletonList(blockPosition);
18+
Set<Vector3> getLastPositions(Player player);
2119

20+
default List<Vector3> getPlacePositions(Player player) {
21+
Vector3 position = player.getPosition().add(this.getOffset(player)).floor();
22+
DimensionData dimension = player.getLevel().getDimensionData();
23+
if (position.getFloorY() >= dimension.getMinHeight() && position.getFloorY() < dimension.getMaxHeight()) {
24+
return Collections.singletonList(position);
25+
}
2226
return Collections.emptyList();
2327
}
2428

25-
protected Vector3 getOffset(Player player) {
26-
Vector3 offset = player.getDirectionVector();
27-
offset.x *= -(1 + player.getWidth());
28-
offset.y *= -(1 + player.getHeight());
29-
offset.z *= -(1 + player.getWidth());
30-
return offset;
29+
default Vector3 getOffset(Player player) {
30+
return FakeInventories.getFakeBlockOffset().getOffset(player);
3131
}
3232
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package me.iwareq.fakeinventories.block;
2+
3+
import cn.nukkit.Player;
4+
import cn.nukkit.math.Vector3;
5+
import me.iwareq.fakeinventories.util.InventoryUtils;
6+
7+
public enum FakeBlockOffset {
8+
STANDARD {
9+
@Override
10+
public Vector3 getOffset(Player player) {
11+
Vector3 offset = player.getDirectionVector();
12+
offset.x *= -(1 + player.getWidth());
13+
offset.y *= -(1 + player.getHeight());
14+
offset.z *= -(1 + player.getWidth());
15+
return offset;
16+
}
17+
},
18+
GEYSER {
19+
@Override
20+
public Vector3 getOffset(Player player) {
21+
return InventoryUtils.findAvailableOffset(player);
22+
}
23+
};
24+
25+
public abstract Vector3 getOffset(Player player);
26+
}

src/main/java/me/iwareq/fakeinventories/block/SingleFakeBlock.java

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,38 @@
11
package me.iwareq.fakeinventories.block;
22

33
import cn.nukkit.Player;
4+
import cn.nukkit.blockentity.BlockEntity;
45
import cn.nukkit.level.GlobalBlockPalette;
56
import cn.nukkit.math.Vector3;
67
import cn.nukkit.nbt.NBTIO;
78
import cn.nukkit.nbt.tag.CompoundTag;
89
import cn.nukkit.network.protocol.BlockEntityDataPacket;
910
import cn.nukkit.network.protocol.UpdateBlockPacket;
11+
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
1012
import lombok.RequiredArgsConstructor;
1113
import lombok.extern.slf4j.Slf4j;
1214

1315
import java.io.IOException;
1416
import java.nio.ByteOrder;
15-
import java.util.List;
17+
import java.util.HashSet;
18+
import java.util.Map;
19+
import java.util.Set;
1620

1721
@Slf4j
1822
@RequiredArgsConstructor
19-
public class SingleFakeBlock extends FakeBlock {
23+
public class SingleFakeBlock implements FakeBlock {
2024

2125
protected final int blockId;
2226
protected final String tileId;
23-
protected List<Vector3> lastPositions;
27+
protected final Map<Player, Set<Vector3>> lastPositions = new Object2ObjectArrayMap<>();
2428

2529
@Override
2630
public void create(Player player, String title) {
27-
List<Vector3> positions = this.getPositions(player);
28-
29-
this.lastPositions = positions;
30-
31-
positions.forEach(position -> {
31+
this.createAndGetLastPositions(player).addAll(this.getPlacePositions(player));
32+
this.getPlacePositions(player).forEach(position -> {
3233
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
3334
updateBlockPacket.blockRuntimeId = GlobalBlockPalette.getOrCreateRuntimeId(player.protocol, this.blockId, 0);
34-
updateBlockPacket.flags = UpdateBlockPacket.FLAG_ALL_PRIORITY;
35+
updateBlockPacket.flags = UpdateBlockPacket.FLAG_NETWORK;
3536
updateBlockPacket.x = position.getFloorX();
3637
updateBlockPacket.y = position.getFloorY();
3738
updateBlockPacket.z = position.getFloorZ();
@@ -53,20 +54,33 @@ public void create(Player player, String title) {
5354

5455
@Override
5556
public void remove(Player player) {
56-
this.lastPositions.forEach(position -> {
57+
this.getLastPositions(player).forEach(position -> {
5758
UpdateBlockPacket packet = new UpdateBlockPacket();
5859
packet.blockRuntimeId = GlobalBlockPalette.getOrCreateRuntimeId(player.protocol, player.getLevel().getBlock(position).getFullId());
59-
packet.flags = UpdateBlockPacket.FLAG_ALL_PRIORITY;
60+
packet.flags = UpdateBlockPacket.FLAG_NETWORK;
6061
packet.x = position.getFloorX();
6162
packet.y = position.getFloorY();
6263
packet.z = position.getFloorZ();
6364
player.dataPacket(packet);
6465
});
66+
this.lastPositions.remove(player);
6567
}
6668

6769
protected CompoundTag getBlockEntityDataAt(Vector3 position, String title) {
68-
return new CompoundTag()
70+
return BlockEntity.getDefaultCompound(position, title)
6971
.putString("id", tileId)
72+
.putBoolean("isMovable", true)
7073
.putString("CustomName", title);
7174
}
75+
76+
public Set<Vector3> createAndGetLastPositions(Player player) {
77+
if (!lastPositions.containsKey(player)) {
78+
lastPositions.put(player, new HashSet<>());
79+
}
80+
return lastPositions.get(player);
81+
}
82+
83+
public Set<Vector3> getLastPositions(Player player) {
84+
return lastPositions.getOrDefault(player, new HashSet<>());
85+
}
7286
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package me.iwareq.fakeinventories.util;
2+
3+
import cn.nukkit.Player;
4+
import cn.nukkit.block.BlockEntityHolder;
5+
import cn.nukkit.level.Level;
6+
import cn.nukkit.math.Vector3;
7+
import cn.nukkit.block.Block;
8+
9+
public class InventoryUtils {
10+
11+
/**
12+
* Finds a usable offset relative to the player's position for placing a fake inventory block.
13+
* Returns null if no valid offset is found.
14+
*/
15+
public static Vector3 findAvailableOffset(Player player) {
16+
Level level = player.getLevel();
17+
18+
int minY = level.getDimensionData().getMinHeight();
19+
int maxY = level.getDimensionData().getMaxHeight();
20+
21+
Vector3 playerPos = player.getPosition();
22+
23+
// Offset above the player
24+
Vector3 offsetAbove = new Vector3(0, 2, 0);
25+
Vector3 posAbove = playerPos.add(offsetAbove);
26+
if (posAbove.getY() >= minY && posAbove.getY() < maxY && canUseWorldSpace(level, posAbove)) {
27+
return offsetAbove;
28+
}
29+
30+
// Offset 4 blocks below the player
31+
Vector3 offsetBelow = new Vector3(0, -4, 0);
32+
Vector3 posBelow = playerPos.add(offsetBelow);
33+
if (posBelow.getY() >= minY && posBelow.getY() < maxY && canUseWorldSpace(level, posBelow)) {
34+
return offsetBelow;
35+
}
36+
37+
return null;
38+
}
39+
40+
/**
41+
* Checks if the block space can be used as a "fake" block location.
42+
*/
43+
private static boolean canUseWorldSpace(Level level, Vector3 pos) {
44+
Block block = level.getBlock(pos);
45+
// Valid if the block is air or a simple block without a BlockEntity
46+
return block.isAir() || !(block instanceof BlockEntityHolder<?>);
47+
}
48+
}

src/main/resources/config.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Fake block offset working mode
2+
# Available:
3+
# STANDARD - Standard working mode
4+
# GEYSER - Geyser like offset mode
5+
fake-block-offset-mode: "GEYSER"

0 commit comments

Comments
 (0)