Skip to content

Commit abd908d

Browse files
authoredJun 17, 2025
1.21.90 & updates (#2235)
- Added support for Minecraft 1.21.90 - Implemented bamboo and cherry blocks - Fixed some slabs placing at incorrect position - Fixed inventory closing issues - Fixed riptide getting blocked by speed limit - Fixed empty buckets disappearing when dispenser is used - Mud can now be created with dispenser and water bottle - Locator bar shows random color for nearby players, can be disabled via gamerule - Small performance improvements - Added a method to change FormWindowCustom default submit button text - Sending duplicate command enums as one, fixes Protocol/WaterdogPE compatibility
1 parent b893031 commit abd908d

File tree

121 files changed

+2560
-256
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

121 files changed

+2560
-256
lines changed
 

‎src/main/java/cn/nukkit/Player.java

Lines changed: 78 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1878,6 +1878,11 @@ protected void checkBlockCollision() {
18781878

18791879
if (this.inPortalTicks == (this.gamemode == CREATIVE ? 1 : 80)) {
18801880
EntityPortalEnterEvent ev = new EntityPortalEnterEvent(this, EntityPortalEnterEvent.PortalType.NETHER);
1881+
1882+
if (this.portalPos == null) {
1883+
ev.setCancelled();
1884+
}
1885+
18811886
this.getServer().getPluginManager().callEvent(ev);
18821887

18831888
if (ev.isCancelled()) {
@@ -2379,7 +2384,7 @@ public boolean onUpdate(int currentTick) {
23792384
Item elytra = inv.getChestplate();
23802385
if (elytra == null || elytra.getId() != ItemID.ELYTRA) {
23812386
this.setGliding(false);
2382-
} else if ((this.gamemode & 0x01) == 0 && this.age % (20 * (elytra.getEnchantmentLevel(Enchantment.ID_DURABILITY) + 1)) == 0) {
2387+
} else if ((this.gamemode & 0x01) == 0 && this.age % (20 * (elytra.getEnchantmentLevel(Enchantment.ID_DURABILITY) + 1)) == 0 && !elytra.isUnbreakable()) {
23832388
elytra.setDamage(elytra.getDamage() + 1);
23842389
if (elytra.getDamage() >= elytra.getMaxDurability()) {
23852390
this.setGliding(false);
@@ -3338,6 +3343,48 @@ public void onCompletion(Server server) {
33383343
}
33393344
}
33403345

3346+
if (authPacket.getInputData().contains(AuthInputAction.START_SPIN_ATTACK)) {
3347+
Enchantment riptide = this.getInventory().getItemInHandFast().getEnchantment(Enchantment.ID_TRIDENT_RIPTIDE);
3348+
if (riptide != null) {
3349+
PlayerToggleSpinAttackEvent playerToggleSpinAttackEvent = new PlayerToggleSpinAttackEvent(this, true);
3350+
3351+
if (riptide.getLevel() < 1) {
3352+
playerToggleSpinAttackEvent.setCancelled(true);
3353+
} else {
3354+
boolean inWater = false;
3355+
for (Block block : this.getCollisionBlocks()) {
3356+
if (block instanceof BlockWater || block.level.isBlockWaterloggedAt(this.chunk, (int) block.x, (int) block.y, (int) block.z)) {
3357+
inWater = true;
3358+
break;
3359+
}
3360+
}
3361+
if (!(inWater || (this.getLevel().isRaining() && this.canSeeSky()))) {
3362+
playerToggleSpinAttackEvent.setCancelled(true);
3363+
}
3364+
}
3365+
3366+
server.getPluginManager().callEvent(playerToggleSpinAttackEvent);
3367+
3368+
if (playerToggleSpinAttackEvent.isCancelled()) {
3369+
this.setNeedSendData(true);
3370+
} else {
3371+
this.onSpinAttack(riptide.getLevel());
3372+
this.setSpinAttack(true);
3373+
this.setUsingItem(false);
3374+
this.resetFallDistance();
3375+
int riptideSound;
3376+
if (riptide.getLevel() >= 3) {
3377+
riptideSound = LevelSoundEventPacket.SOUND_ITEM_TRIDENT_RIPTIDE_3;
3378+
} else if (riptide.getLevel() == 2) {
3379+
riptideSound = LevelSoundEventPacket.SOUND_ITEM_TRIDENT_RIPTIDE_2;
3380+
} else {
3381+
riptideSound = LevelSoundEventPacket.SOUND_ITEM_TRIDENT_RIPTIDE_1;
3382+
}
3383+
this.getLevel().addLevelSoundEvent(this, riptideSound);
3384+
}
3385+
}
3386+
}
3387+
33413388
if (authPacket.getInputData().contains(AuthInputAction.STOP_SPIN_ATTACK)) {
33423389
PlayerToggleSpinAttackEvent playerToggleSpinAttackEvent = new PlayerToggleSpinAttackEvent(this, false);
33433390
this.server.getPluginManager().callEvent(playerToggleSpinAttackEvent);
@@ -3554,6 +3601,8 @@ public void onCompletion(Server server) {
35543601
this.inventoryOpen = true;
35553602
this.awardAchievement("openInventory");
35563603
}
3604+
} else if (Nukkit.DEBUG > 1) {
3605+
server.getLogger().debug(this.username + " tried to open inventory but one is already open");
35573606
}
35583607
return;
35593608
case InteractPacket.ACTION_MOUSEOVER:
@@ -3764,36 +3813,47 @@ public void onCompletion(Server server) {
37643813
return;
37653814
case ProtocolInfo.CONTAINER_CLOSE_PACKET:
37663815
ContainerClosePacket containerClosePacket = (ContainerClosePacket) packet;
3767-
if (!this.spawned || (containerClosePacket.windowId == ContainerIds.INVENTORY && !inventoryOpen)) {
3768-
return;
3769-
}
37703816

3771-
if (this.windowIndex.containsKey(containerClosePacket.windowId)) {
3772-
this.server.getPluginManager().callEvent(new InventoryCloseEvent(this.windowIndex.get(containerClosePacket.windowId), this));
3773-
if (containerClosePacket.windowId == ContainerIds.INVENTORY) this.inventoryOpen = false;
3774-
this.closingWindowId = containerClosePacket.windowId;
3775-
this.removeWindow(this.windowIndex.get(containerClosePacket.windowId), true);
3776-
this.closingWindowId = Integer.MIN_VALUE;
3817+
if (!this.spawned) {
3818+
return;
37773819
}
37783820

37793821
if (containerClosePacket.windowId == -1) {
3822+
// At least 1.21 does sometimes send windowId -1 when opening and closing containers quickly
3823+
if (this.inventoryOpen) {
3824+
this.inventoryOpen = false;
3825+
3826+
if (this.craftingType == CRAFTING_SMALL) {
3827+
for (Entry<Inventory, Integer> open : new ArrayList<>(this.windows.entrySet())) {
3828+
if (open.getKey() instanceof ContainerInventory || open.getKey() instanceof PlayerEnderChestInventory) {
3829+
this.server.getPluginManager().callEvent(new InventoryCloseEvent(open.getKey(), this));
3830+
this.closingWindowId = Integer.MAX_VALUE;
3831+
this.removeWindow(open.getKey(), true);
3832+
this.closingWindowId = Integer.MIN_VALUE;
3833+
}
3834+
}
3835+
return;
3836+
}
3837+
}
3838+
37803839
this.resetCraftingGridType();
37813840
this.addWindow(this.craftingGrid, ContainerIds.NONE);
37823841
ContainerClosePacket pk = new ContainerClosePacket();
37833842
pk.windowId = -1;
37843843
pk.wasServerInitiated = false;
37853844
this.dataPacket(pk);
3786-
} else { // TODO: check this
3845+
} else if (this.windowIndex.containsKey(containerClosePacket.windowId)) {
3846+
this.inventoryOpen = false;
3847+
Inventory inn = this.windowIndex.get(containerClosePacket.windowId);
3848+
this.server.getPluginManager().callEvent(new InventoryCloseEvent(inn, this));
3849+
this.closingWindowId = containerClosePacket.windowId;
3850+
this.removeWindow(inn, true);
3851+
this.closingWindowId = Integer.MIN_VALUE;
3852+
} else { // Close the bugged inventory client refused with id -1 above
37873853
ContainerClosePacket pk = new ContainerClosePacket();
37883854
pk.windowId = containerClosePacket.windowId;
37893855
pk.wasServerInitiated = false;
37903856
this.dataPacket(pk);
3791-
3792-
for (Inventory open : new ArrayList<>(this.windows.keySet())) {
3793-
if (open instanceof ContainerInventory) {
3794-
this.removeWindow(open);
3795-
}
3796-
}
37973857
}
37983858
return;
37993859
case ProtocolInfo.BLOCK_ENTITY_DATA_PACKET:
@@ -6494,7 +6554,7 @@ public void resetCraftingGridType() {
64946554
*/
64956555
private void moveBlockUIContents(int window) {
64966556
Inventory inventory = this.getWindowById(window);
6497-
if (inventory != null && !(inventory instanceof ContainerInventory)) {
6557+
if (inventory instanceof FakeBlockUIComponent) {
64986558
Item[] drops = this.inventory.addItem(inventory.getContents().values().toArray(new Item[0]));
64996559
inventory.clearAll();
65006560
for (Item drop : drops) {
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package cn.nukkit.block;
2+
3+
import cn.nukkit.Player;
4+
import cn.nukkit.item.Item;
5+
import cn.nukkit.item.ItemBlock;
6+
import cn.nukkit.math.BlockFace;
7+
8+
public class BlockBambooBlock extends BlockWood {
9+
10+
public BlockBambooBlock() {
11+
this(0);
12+
}
13+
14+
public BlockBambooBlock(int meta) {
15+
super(meta);
16+
}
17+
18+
@Override
19+
public String getName() {
20+
return "Bamboo Block";
21+
}
22+
23+
@Override
24+
public int getId() {
25+
return BAMBOO_BLOCK;
26+
}
27+
28+
@Override
29+
protected int getStrippedId() {
30+
return STRIPPED_BAMBOO_BLOCK;
31+
}
32+
33+
@Override
34+
protected int getStrippedDamage() {
35+
return getDamage();
36+
}
37+
38+
@Override
39+
public Item toItem() {
40+
return new ItemBlock(Block.get(this.getId(), 0), 0);
41+
}
42+
43+
@Override
44+
public boolean place(Item item, Block block, Block target, BlockFace face, double fx, double fy, double fz, Player player) {
45+
this.setPillarAxis(face.getAxis());
46+
return this.getLevel().setBlock(block, this, true, true);
47+
}
48+
49+
public void setPillarAxis(BlockFace.Axis axis) {
50+
switch (axis) {
51+
case Y:
52+
this.setDamage(0);
53+
break;
54+
case X:
55+
this.setDamage(1);
56+
break;
57+
case Z:
58+
this.setDamage(2);
59+
break;
60+
}
61+
}
62+
63+
public BlockFace.Axis getPillarAxis() {
64+
switch (this.getDamage() % 3) {
65+
case 2:
66+
return BlockFace.Axis.Z;
67+
case 1:
68+
return BlockFace.Axis.X;
69+
case 0:
70+
default:
71+
return BlockFace.Axis.Y;
72+
}
73+
}
74+
}

0 commit comments

Comments
 (0)