diff --git a/SpongeAPI b/SpongeAPI index 667d80ea551..8a9430065c6 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 667d80ea551ecec7b9aabd41b0586f4955bc7caf +Subproject commit 8a9430065c66c04e7a1f1f3f8e4f96bfb2e62947 diff --git a/forge/src/main/java/org/spongepowered/forge/hook/ForgeItemHooks.java b/forge/src/main/java/org/spongepowered/forge/hook/ForgeItemHooks.java index 7698314caa6..296d642e82a 100644 --- a/forge/src/main/java/org/spongepowered/forge/hook/ForgeItemHooks.java +++ b/forge/src/main/java/org/spongepowered/forge/hook/ForgeItemHooks.java @@ -24,8 +24,14 @@ */ package org.spongepowered.forge.hook; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantment; import org.spongepowered.common.hooks.ItemHooks; public class ForgeItemHooks implements ItemHooks { + @Override + public boolean canEnchantmentBeAppliedToItem(Enchantment enchantment, ItemStack stack) { + return stack.canApplyAtEnchantingTable(enchantment); + } } diff --git a/src/accessors/java/org/spongepowered/common/accessor/world/level/chunk/LevelChunk$BoundTickingBlockEntityAccessor.java b/src/accessors/java/org/spongepowered/common/accessor/world/level/chunk/LevelChunk$BoundTickingBlockEntityAccessor.java index e60eecb48bb..fbb9996ba79 100644 --- a/src/accessors/java/org/spongepowered/common/accessor/world/level/chunk/LevelChunk$BoundTickingBlockEntityAccessor.java +++ b/src/accessors/java/org/spongepowered/common/accessor/world/level/chunk/LevelChunk$BoundTickingBlockEntityAccessor.java @@ -25,7 +25,6 @@ package org.spongepowered.common.accessor.world.level.chunk; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityTicker; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; @@ -34,5 +33,4 @@ public interface LevelChunk$BoundTickingBlockEntityAccessor { @Accessor("blockEntity") BlockEntity accessor$blockEntity(); - @Accessor("ticker") BlockEntityTicker accessor$ticker(); } diff --git a/src/main/java/org/spongepowered/common/data/provider/item/stack/BookPagesItemStackData.java b/src/main/java/org/spongepowered/common/data/provider/item/stack/BookPagesItemStackData.java index 8ab96875da9..e064bad1c6f 100644 --- a/src/main/java/org/spongepowered/common/data/provider/item/stack/BookPagesItemStackData.java +++ b/src/main/java/org/spongepowered/common/data/provider/item/stack/BookPagesItemStackData.java @@ -28,7 +28,6 @@ import net.minecraft.core.component.DataComponents; import net.minecraft.core.registries.Registries; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; import net.minecraft.world.item.enchantment.ItemEnchantments; import org.spongepowered.api.data.Keys; import org.spongepowered.api.item.enchantment.Enchantment; @@ -58,8 +57,7 @@ public static void register(final DataProviderRegistrator registrator) { .create(Keys.STORED_ENCHANTMENTS) .get(h -> BookPagesItemStackData.get(h, DataComponents.STORED_ENCHANTMENTS)) .set((h, v) -> BookPagesItemStackData.set(h, v, Collection::stream, DataComponents.STORED_ENCHANTMENTS)) - .delete(h -> BookPagesItemStackData.delete(h, DataComponents.STORED_ENCHANTMENTS)) - .supports(h -> h.getItem() == Items.ENCHANTED_BOOK); + .delete(h -> BookPagesItemStackData.delete(h, DataComponents.STORED_ENCHANTMENTS)); } // @formatter:on diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/block/BlockEventBasedTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/block/BlockEventBasedTransaction.java index 345a2d2d461..cfcf5df8381 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/block/BlockEventBasedTransaction.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/block/BlockEventBasedTransaction.java @@ -25,8 +25,6 @@ package org.spongepowered.common.event.tracking.context.transaction.block; import com.google.common.collect.ImmutableList; -import com.google.common.collect.LinkedListMultimap; -import com.google.common.collect.ListMultimap; import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.state.BlockState; import org.checkerframework.checker.nullness.qual.NonNull; @@ -49,8 +47,8 @@ import org.spongepowered.common.event.tracking.context.transaction.world.WorldBasedTransaction; import org.spongepowered.math.vector.Vector3i; -import java.util.ArrayList; -import java.util.List; +import java.util.HashMap; +import java.util.Map; import java.util.Optional; abstract class BlockEventBasedTransaction extends WorldBasedTransaction { @@ -75,57 +73,41 @@ public final Optional generateEvent( if (!o.isPresent()) { return Optional.empty(); } - final ListMultimap positions = LinkedListMultimap.create(); + + final Map eventTransactions = new HashMap<>(); for (final GameTransaction<@NonNull ?> transaction : transactions) { final BlockEventBasedTransaction blockTransaction = (BlockEventBasedTransaction) transaction; - if (!positions.containsKey(blockTransaction.affectedPosition)) { - positions.put( - blockTransaction.affectedPosition, - blockTransaction.getOriginalSnapshot() - ); - } - if (blockTransaction.getResultingSnapshot() != null) { - positions.put( - blockTransaction.affectedPosition, - blockTransaction.getResultingSnapshot() - ); + if (!blockTransaction.actualBlockTransaction()) { + continue; } + final SpongeBlockSnapshot original = blockTransaction.getOriginalSnapshot(); + final SpongeBlockSnapshot result = blockTransaction.getResultingSnapshot(); + final Operation operation = context.getBlockOperation(original, result); + final BlockTransaction eventTransaction = new BlockTransaction(original, result, operation); + eventTransactions.merge(blockTransaction.affectedPosition, eventTransaction, (oldValue, newValue) -> { + final ImmutableList.Builder intermediary = ImmutableList.builderWithExpectedSize(oldValue.intermediary().size() + 1); + intermediary.addAll(oldValue.intermediary()); + intermediary.add(oldValue.finalReplacement()); + final Operation mergedOperation = context.getBlockOperation((SpongeBlockSnapshot) oldValue.original(), (SpongeBlockSnapshot) newValue.finalReplacement()); + return new BlockTransaction(oldValue.original(), newValue.finalReplacement(), intermediary.build(), mergedOperation); + }); } - final ImmutableList eventTransactions = positions.asMap().values() - .stream() - .map(spongeBlockSnapshots -> { - final List snapshots = new ArrayList<>(spongeBlockSnapshots); - if (snapshots.isEmpty() || snapshots.size() < 2) { - // Error case - return Optional.empty(); - } - final SpongeBlockSnapshot original = snapshots.get(0); - final SpongeBlockSnapshot result = snapshots.get(snapshots.size() - 1); - final ImmutableList intermediary; - if (snapshots.size() > 2) { - intermediary = ImmutableList.copyOf(snapshots.subList(1, snapshots.size() - 2)); - } else { - intermediary = ImmutableList.of(); - } - final Operation operation = context.getBlockOperation(original, result); - final BlockTransaction eventTransaction = new BlockTransaction(original, result, intermediary, operation); - return Optional.of(eventTransaction); - }) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(ImmutableList.toImmutableList()); - if (eventTransactions.isEmpty()) { return Optional.empty(); } + return Optional.of(SpongeEventFactory.createChangeBlockEventAll( currentCause, - eventTransactions, + ImmutableList.copyOf(eventTransactions.values()), o.get() )); } + protected boolean actualBlockTransaction() { + return true; + } + protected abstract SpongeBlockSnapshot getResultingSnapshot(); protected abstract SpongeBlockSnapshot getOriginalSnapshot(); diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/block/PrepareBlockDropsTransaction.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/block/PrepareBlockDropsTransaction.java index acfa63ed442..aafa56eb86d 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/block/PrepareBlockDropsTransaction.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/block/PrepareBlockDropsTransaction.java @@ -52,9 +52,14 @@ public PrepareBlockDropsTransaction( this.originalState = original; } + @Override + protected boolean actualBlockTransaction() { + return false; + } + @Override protected SpongeBlockSnapshot getResultingSnapshot() { - return null; + throw new UnsupportedOperationException(); } @Override diff --git a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/BlockTransactionType.java b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/BlockTransactionType.java index ca6fb81628b..b8605f062fe 100644 --- a/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/BlockTransactionType.java +++ b/src/main/java/org/spongepowered/common/event/tracking/context/transaction/type/BlockTransactionType.java @@ -24,11 +24,8 @@ */ package org.spongepowered.common.event.tracking.context.transaction.type; -import com.google.common.collect.ImmutableList; import com.google.common.collect.LinkedListMultimap; -import com.google.common.collect.ListMultimap; import com.google.common.collect.Multimap; -import net.minecraft.core.BlockPos; import org.checkerframework.checker.nullness.qual.NonNull; import org.spongepowered.api.ResourceKey; import org.spongepowered.api.block.transaction.BlockTransaction; @@ -46,7 +43,7 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.List; +import java.util.Collections; import java.util.Optional; public final class BlockTransactionType extends TransactionType { @@ -69,49 +66,36 @@ protected void consumeEventsAndMarker( if (!serverWorld.isPresent()) { return; } - final ListMultimap positions = LinkedListMultimap.create(); + // Gather transactions that were valid - events.stream() - .filter(event -> !event.isCancelled()) - .flatMap(event -> event.transactions().stream()) - .filter(BlockTransaction::isValid) - .forEach(transactions -> { - // Then "put" the most recent transactions such that we have a complete rebuild of - // each position according to what originally existed and then - // the ultimate final block on that position - final SpongeBlockSnapshot original = (SpongeBlockSnapshot) transactions.original(); - positions.put(original.getBlockPos(), original); - positions.put(original.getBlockPos(), (SpongeBlockSnapshot) transactions.finalReplacement()); - }); + final ArrayList transactions = new ArrayList<>(); + for (final ChangeBlockEvent.All event : events) { + if (event.isCancelled()) { + continue; + } - // Do not bother turning the positions into receipts if it's empty - // just return. - if (positions.isEmpty()) { - return; - } - final ImmutableList transactions = positions.asMap() - .values() - .stream() - .map(spongeBlockSnapshots -> { - final List snapshots = new ArrayList<>(spongeBlockSnapshots); - if (snapshots.isEmpty() || snapshots.size() < 2) { - // Error case - return Optional.empty(); + transactions.ensureCapacity(event.transactions().size()); + for (final BlockTransaction transaction : event.transactions()) { + if (!transaction.isValid()) { + continue; } - final SpongeBlockSnapshot original = snapshots.get(0); - final SpongeBlockSnapshot result = snapshots.get(snapshots.size() - 1); + + final SpongeBlockSnapshot original = (SpongeBlockSnapshot) transaction.original(); + final SpongeBlockSnapshot result = (SpongeBlockSnapshot) transaction.finalReplacement(); final Operation operation = context.getBlockOperation(original, result); final BlockTransactionReceipt eventTransaction = new BlockTransactionReceipt(original, result, operation); + transactions.add(eventTransaction); context.postBlockTransactionApplication(original.blockChange, eventTransaction); - return Optional.of(eventTransaction); - }) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(ImmutableList.toImmutableList()); + } + } + + if (transactions.isEmpty()) { + return; + } final Cause cause = PhaseTracker.getInstance().currentCause(); - SpongeCommon.post(SpongeEventFactory.createChangeBlockEventPost(cause, transactions, serverWorld.get())); + SpongeCommon.post(SpongeEventFactory.createChangeBlockEventPost(cause, Collections.unmodifiableList(transactions), serverWorld.get())); }); } } diff --git a/src/main/java/org/spongepowered/common/world/volume/SpongeVolumeStream.java b/src/main/java/org/spongepowered/common/world/volume/SpongeVolumeStream.java index 701133d2a1b..2d3f8779f6e 100644 --- a/src/main/java/org/spongepowered/common/world/volume/SpongeVolumeStream.java +++ b/src/main/java/org/spongepowered/common/world/volume/SpongeVolumeStream.java @@ -206,17 +206,7 @@ public Stream> toStream() { @Override public void apply(final VolumeCollector collector) { - final PhaseTracker instance = PhaseTracker.getInstance(); - try (final @Nullable PhaseContext<@NonNull ?> context = instance.getPhaseContext().isApplyingStreams() - ? null - : PluginPhase.State.VOLUME_STREAM_APPLICATION - .createPhaseContext(instance) - .setVolumeStream(this) - .spawnType(() -> PhaseTracker.getCauseStackManager().context(EventContextKeys.SPAWN_TYPE).orElse(null)) - ) { - if (context != null) { - context.buildAndSwitch(); - } + this.startPhase(() -> { this.stream.forEach(element -> { final W targetVolume = collector.target().get(); final VolumeElement transformed = collector.positionTransform().apply(VolumeElement.of( @@ -227,35 +217,39 @@ public void apply(final VolumeCollector colle collector.applicator() .apply(targetVolume, transformed); }); - } + }); } @Override public void applyUntil(final VolumeCollector collector, final Predicate predicate) { - boolean doWork = true; - for (final Iterator> iterator = this.stream.iterator(); doWork && iterator.hasNext(); ) { - final W targetVolume = collector.target().get(); - final VolumeElement element = iterator.next(); - final VolumeElement transformed = collector.positionTransform().apply(VolumeElement.of( - collector.target(), - element::type, - element.position() - )); - final R apply = collector.applicator() - .apply(targetVolume, transformed); - doWork = predicate.test(apply); - } + this.startPhase(() -> { + boolean doWork = true; + for (final Iterator> iterator = this.stream.iterator(); doWork && iterator.hasNext(); ) { + final W targetVolume = collector.target().get(); + final VolumeElement element = iterator.next(); + final VolumeElement transformed = collector.positionTransform().apply(VolumeElement.of( + collector.target(), + element::type, + element.position() + )); + final R apply = collector.applicator() + .apply(targetVolume, transformed); + doWork = predicate.test(apply); + } + }); } @Override public void forEach(final VolumeConsumer visitor) { - this.stream.forEach(element -> visitor.consume( - element.volume(), - element.type(), - element.position().x(), - element.position().y(), - element.position().z() - )); + this.startPhase(() -> { + this.stream.forEach(element -> visitor.consume( + element.volume(), + element.type(), + element.position().x(), + element.position().y(), + element.position().z() + )); + }); } @Override @@ -263,4 +257,20 @@ public void forEach(final Consumer> consumer) { this.stream.forEach(consumer); } + private void startPhase(final Runnable runnable) { + final PhaseTracker instance = PhaseTracker.getInstance(); + try (final @Nullable PhaseContext<@NonNull ?> context = instance.getPhaseContext().isApplyingStreams() + ? null + : PluginPhase.State.VOLUME_STREAM_APPLICATION + .createPhaseContext(instance) + .setVolumeStream(this) + .spawnType(() -> PhaseTracker.getCauseStackManager().context(EventContextKeys.SPAWN_TYPE).orElse(null)) + ) { + if (context != null) { + context.buildAndSwitch(); + } + + runnable.run(); + } + } } diff --git a/src/test/java/org/spongepowered/common/util/transformation/VolumeTransformationTest.java b/src/test/java/org/spongepowered/common/util/transformation/VolumeTransformationTest.java index ae2d2435294..d0fec3da68f 100644 --- a/src/test/java/org/spongepowered/common/util/transformation/VolumeTransformationTest.java +++ b/src/test/java/org/spongepowered/common/util/transformation/VolumeTransformationTest.java @@ -29,6 +29,7 @@ import com.google.inject.Injector; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -42,6 +43,7 @@ import org.spongepowered.api.Sponge; import org.spongepowered.api.block.BlockState; import org.spongepowered.api.block.BlockType; +import org.spongepowered.api.event.EventContextKey; import org.spongepowered.api.registry.RegistryHolder; import org.spongepowered.api.registry.RegistryKey; import org.spongepowered.api.registry.RegistryType; @@ -56,10 +58,12 @@ import org.spongepowered.api.world.volume.archetype.ArchetypeVolume; import org.spongepowered.api.world.volume.stream.StreamOptions; import org.spongepowered.api.world.volume.stream.VolumePositionTranslators; +import org.spongepowered.common.event.SpongeEventContextKeyBuilder; import org.spongepowered.common.registry.SpongeBuilderProvider; import org.spongepowered.common.registry.SpongeFactoryProvider; import org.spongepowered.common.registry.SpongeRegistryKey; import org.spongepowered.common.registry.SpongeRegistryType; +import org.spongepowered.common.test.UnitTestExtension; import org.spongepowered.common.test.stub.StubGame; import org.spongepowered.common.test.stub.StubKey; import org.spongepowered.common.test.stub.StubModule; @@ -81,8 +85,9 @@ import java.util.stream.IntStream; import java.util.stream.Stream; +@Disabled @SuppressWarnings("rawtypes") -@ExtendWith(MockitoExtension.class) +@ExtendWith({ MockitoExtension.class, UnitTestExtension.class }) @MockitoSettings(strictness = Strictness.LENIENT) public final class VolumeTransformationTest { @@ -138,6 +143,7 @@ static void setup() { StubMirror.registerDefaults(mirror); game.register(mirror); + builderProvider.register(EventContextKey.Builder.class, SpongeEventContextKeyBuilder::new); builderProvider.register(Transformation.Builder.class, SpongeTransformationBuilder::new); builderProvider.register(StreamOptions.Builder.class, SpongeStreamOptionsBuilder::new); StubRotations.registerDefaults(rotation); diff --git a/vanilla/src/installer/java/org/spongepowered/vanilla/installer/InstallerMain.java b/vanilla/src/installer/java/org/spongepowered/vanilla/installer/InstallerMain.java index 992785c98d9..b7220520f38 100644 --- a/vanilla/src/installer/java/org/spongepowered/vanilla/installer/InstallerMain.java +++ b/vanilla/src/installer/java/org/spongepowered/vanilla/installer/InstallerMain.java @@ -159,7 +159,7 @@ public void downloadAndRun() throws Exception { .toArray(Path[]::new); final URL rootJar = InstallerMain.class.getProtectionDomain().getCodeSource().getLocation(); - final URI fsURI = new URI("jar", rootJar.toString(), null); + final URI fsURI = new URI("jar:" + rootJar); System.setProperty("sponge.rootJarFS", fsURI.toString()); final FileSystem fs = FileSystems.newFileSystem(fsURI, Map.of());