diff --git a/SpongeAPI b/SpongeAPI
index fcfb9213f66..0ba43afee9f 160000
--- a/SpongeAPI
+++ b/SpongeAPI
@@ -1 +1 @@
-Subproject commit fcfb9213f66959667ae63523d593e2e5cf567af9
+Subproject commit 0ba43afee9fc35e5478ee09cbd7ce8bf1ca50167
diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
index 7a0e8d0074b..4af7b96a5e2 100644
--- a/gradle/verification-metadata.xml
+++ b/gradle/verification-metadata.xml
@@ -485,6 +485,14 @@
+
+
+
+
+
+
+
+
@@ -508,6 +516,11 @@
+
+
+
+
+
@@ -587,6 +600,14 @@
+
+
+
+
+
+
+
+
@@ -665,6 +686,11 @@
+
+
+
+
+
@@ -2255,6 +2281,14 @@
+
+
+
+
+
+
+
+
diff --git a/src/main/java/org/spongepowered/common/event/inventory/InventoryEventFactory.java b/src/main/java/org/spongepowered/common/event/inventory/InventoryEventFactory.java
index 07c6de04c64..dfa469a4a84 100644
--- a/src/main/java/org/spongepowered/common/event/inventory/InventoryEventFactory.java
+++ b/src/main/java/org/spongepowered/common/event/inventory/InventoryEventFactory.java
@@ -38,6 +38,7 @@
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.AnvilMenu;
import net.minecraft.world.inventory.EnchantmentMenu;
+import net.minecraft.world.inventory.MenuType;
import net.minecraft.world.inventory.MerchantMenu;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.enchantment.EnchantmentInstance;
@@ -239,9 +240,8 @@ public static boolean callInteractContainerOpenEvent(final ServerPlayer player)
return true;
}
- public static @org.checkerframework.checker.nullness.qual.Nullable AbstractContainerMenu displayContainer(final ServerPlayer player, final Inventory inventory, final Component displayName) {
- final net.minecraft.world.inventory.AbstractContainerMenu previousContainer = player.containerMenu;
- final net.minecraft.world.inventory.AbstractContainerMenu container;
+ public static @Nullable AbstractContainerMenu displayContainer(final ServerPlayer player, final Inventory inventory, final Component displayName) {
+ final AbstractContainerMenu previousContainer = player.containerMenu;
Optional viewable = inventory.asViewable();
if (viewable.isPresent()) {
@@ -276,8 +276,7 @@ public static boolean callInteractContainerOpenEvent(final ServerPlayer player)
horse.openCustomInventoryScreen(player);
}
- container = player.containerMenu;
-
+ final AbstractContainerMenu container = player.containerMenu;
if (previousContainer == container) {
return null;
}
@@ -300,6 +299,27 @@ public static boolean callInteractContainerOpenEvent(final ServerPlayer player)
return container;
}
+ public static @Nullable AbstractContainerMenu displayContainer(final ServerPlayer player, final MenuType> type, Component displayName) {
+ final AbstractContainerMenu previousContainer = player.containerMenu;
+
+ if (displayName == null) {
+ displayName = Component.text("CustomContainer");
+ }
+
+ final MenuProvider menuProvider = new SimpleMenuProvider((menuId, playerInv, p) -> type.create(menuId, playerInv), SpongeAdventure.asVanilla(displayName));
+ player.openMenu(menuProvider);
+ final AbstractContainerMenu container = player.containerMenu;
+ if (previousContainer == container) {
+ return null;
+ }
+
+ if (!InventoryEventFactory.callInteractContainerOpenEvent(player)) {
+ return null;
+ }
+
+ return player.containerMenu;
+ }
+
public static TransferInventoryEvent.Pre callTransferPre(final Inventory source, final Inventory destination) {
PhaseTracker.getCauseStackManager().pushCause(source);
final TransferInventoryEvent.Pre event = SpongeEventFactory.createTransferInventoryEventPre(
diff --git a/src/main/java/org/spongepowered/common/inventory/custom/SpongeViewableInventoryBuilder.java b/src/main/java/org/spongepowered/common/inventory/custom/SpongeViewableInventoryBuilder.java
index 23b0461ecdd..3c70687523f 100644
--- a/src/main/java/org/spongepowered/common/inventory/custom/SpongeViewableInventoryBuilder.java
+++ b/src/main/java/org/spongepowered/common/inventory/custom/SpongeViewableInventoryBuilder.java
@@ -136,6 +136,7 @@ private Slot newDummySlot() {
}
// Slot definition Impl:
+ @Override
public BuildingStep slotsAtIndizes(List source, List at) {
Validate.isTrue(source.size() == at.size(), "Source and index list sizes differ");
for (int i = 0; i < at.size(); i++) {
@@ -148,10 +149,12 @@ public BuildingStep slotsAtIndizes(List source, List at) {
}
// complex redirects - (source/index list generation)
+ @Override
public BuildingStep slotsAtPositions(List source, List at) {
return this.slotsAtIndizes(source, at.stream().map(this::posToIndex).collect(Collectors.toList()));
}
+ @Override
public DummyStep fillDummy() {
Slot slot = this.newDummySlot();
List indizes = IntStream.range(0, this.info.size).boxed().filter(idx -> !this.slotDefinitions.containsKey(idx)).collect(Collectors.toList());
@@ -160,6 +163,7 @@ public DummyStep fillDummy() {
return this;
}
+ @Override
public DummyStep dummySlots(int count, int offset) {
Slot slot = this.newDummySlot();
List source = Stream.generate(() -> slot).limit(count).collect(Collectors.toList());
@@ -167,11 +171,13 @@ public DummyStep dummySlots(int count, int offset) {
return this;
}
+ @Override
public BuildingStep slots(List source, int offset) {
List indizes = IntStream.range(offset, offset + source.size()).boxed().collect(Collectors.toList());
return this.slotsAtIndizes(source, indizes);
}
+ @Override
public DummyStep dummyGrid(Vector2i size, Vector2i offset) {
Slot slot = this.newDummySlot();
List source = Stream.generate(() -> slot).limit(size.x() * size.y()).collect(Collectors.toList());
@@ -179,6 +185,7 @@ public DummyStep dummyGrid(Vector2i size, Vector2i offset) {
return this;
}
+ @Override
public BuildingStep grid(List source, Vector2i size, Vector2i offset) {
int xMin = offset.x();
int yMin = offset.y();
@@ -196,14 +203,17 @@ public BuildingStep grid(List source, Vector2i size, Vector2i offset) {
// simple redirects
+ @Override
public DummyStep dummySlots(int count, Vector2i offset) {
return this.dummySlots(count, this.posToIndex(offset));
}
+ @Override
public BuildingStep slots(List source, Vector2i offset) {
return this.slots(source, this.posToIndex(offset));
}
+ @Override
public DummyStep dummyGrid(Vector2i size, int offset) {
return this.dummyGrid(size, this.indexToPos(offset));
}
@@ -225,6 +235,7 @@ public EndStep plugin(final PluginContainer plugin) {
return this;
}
+ @Override
public EndStep identity(UUID uuid) {
this.identity = uuid;
return this;
diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/data/BlockEntity_DataHolderMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/data/BlockEntity_DataHolderMixin_API.java
new file mode 100644
index 00000000000..823b337eeee
--- /dev/null
+++ b/src/mixins/java/org/spongepowered/common/mixin/api/data/BlockEntity_DataHolderMixin_API.java
@@ -0,0 +1,44 @@
+/*
+ * This file is part of Sponge, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) SpongePowered
+ * Copyright (c) contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package org.spongepowered.common.mixin.api.data;
+
+import org.spongepowered.api.block.BlockState;
+import org.spongepowered.api.block.entity.BlockEntity;
+import org.spongepowered.api.data.DataHolder;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.common.data.holder.SpongeMutableDataHolder;
+
+import java.util.Arrays;
+import java.util.List;
+
+@Mixin(net.minecraft.world.level.block.entity.BlockEntity.class)
+public abstract class BlockEntity_DataHolderMixin_API implements DataHolder, SpongeMutableDataHolder {
+
+ @Override
+ public List impl$delegateDataHolder() {
+ final BlockState state = ((BlockEntity) this).block();
+ return Arrays.asList(this, state, state.type());
+ }
+}
diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/data/DataHolderMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/data/DataHolderMixin_API.java
index 846e1d75c4a..4d2a31a5efc 100644
--- a/src/mixins/java/org/spongepowered/common/mixin/api/data/DataHolderMixin_API.java
+++ b/src/mixins/java/org/spongepowered/common/mixin/api/data/DataHolderMixin_API.java
@@ -26,12 +26,11 @@
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.ItemStack;
-import net.minecraft.world.level.block.entity.BlockEntity;
import org.spongepowered.api.data.DataHolder;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.common.data.holder.SpongeMutableDataHolder;
-@Mixin(value = {BlockEntity.class, Entity.class, ItemStack.class}, priority = 899)
+@Mixin(value = {Entity.class, ItemStack.class}, priority = 899)
public abstract class DataHolderMixin_API implements DataHolder, SpongeMutableDataHolder {
}
diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/BlockEntityMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/BlockEntityMixin_API.java
index e17fe5ef9a8..67914d7391d 100644
--- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/BlockEntityMixin_API.java
+++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/entity/BlockEntityMixin_API.java
@@ -183,5 +183,4 @@ public Set> getValues() {
protected Set> api$getVanillaValues() {
return new HashSet<>();
}
-
}
diff --git a/src/mixins/java/org/spongepowered/common/mixin/inventory/api/server/level/ServerPlayerMixin_Inventory_API.java b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/server/level/ServerPlayerMixin_Inventory_API.java
index 3c4711ab9f7..c0913065f32 100644
--- a/src/mixins/java/org/spongepowered/common/mixin/inventory/api/server/level/ServerPlayerMixin_Inventory_API.java
+++ b/src/mixins/java/org/spongepowered/common/mixin/inventory/api/server/level/ServerPlayerMixin_Inventory_API.java
@@ -25,9 +25,11 @@
package org.spongepowered.common.mixin.inventory.api.server.level;
import net.kyori.adventure.text.Component;
+import net.minecraft.world.inventory.MenuType;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
import org.spongepowered.api.item.inventory.Container;
+import org.spongepowered.api.item.inventory.ContainerType;
import org.spongepowered.api.item.inventory.Inventory;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.common.bridge.world.inventory.container.ContainerBridge;
@@ -64,6 +66,20 @@ public Optional openInventory(final Inventory inventory, final Compon
return Optional.ofNullable((Container) InventoryEventFactory.displayContainer((net.minecraft.server.level.ServerPlayer) (Object) this, inventory, displayName));
}
+ @Override
+ public Optional openInventory(final ContainerType type) {
+ return this.openInventory(type, null);
+ }
+
+ @Override
+ public Optional openInventory(final ContainerType type, final Component displayName) {
+ final ContainerBridge openContainer = (ContainerBridge) this.containerMenu;
+ if (openContainer.bridge$isInUse()) {
+ throw new UnsupportedOperationException("This player is currently modifying an open container. Opening a new one must be delayed!");
+ }
+ return Optional.ofNullable((Container) InventoryEventFactory.displayContainer((net.minecraft.server.level.ServerPlayer) (Object) this, (MenuType>) type, displayName));
+ }
+
@Override
public boolean closeInventory() throws IllegalArgumentException {
final net.minecraft.world.inventory.AbstractContainerMenu openContainer = this.containerMenu;
diff --git a/src/mixins/resources/mixins.sponge.api.json b/src/mixins/resources/mixins.sponge.api.json
index 621a2304140..ff00fce102a 100644
--- a/src/mixins/resources/mixins.sponge.api.json
+++ b/src/mixins/resources/mixins.sponge.api.json
@@ -5,6 +5,7 @@
"mixinPriority": 1100,
"mixins": [
"common.entity.living.HumanEntityMixin_API",
+ "data.BlockEntity_DataHolderMixin_API",
"data.DataHolderMixin_API",
"data.persistence.DataContainerMixin_API",
"entity.ai.goal.AbstractGoalMixin_API",