Skip to content

Commit b88f2ea

Browse files
committed
Merge remote-tracking branch 'origin/api-13' into api-14
2 parents 4123018 + 1262216 commit b88f2ea

14 files changed

Lines changed: 190 additions & 110 deletions

File tree

generator/src/main/java/org/spongepowered/vanilla/generator/RegistryEntriesGenerator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ public void generate(final Context ctx) throws IOException {
128128
if (registry == null) {
129129
throw new IllegalArgumentException("Unknown registry " + this.registry);
130130
}
131-
scopeType = this.scopeOverride != null ? this.scopeOverride : RegistryScope.WORLD;
131+
scopeType = this.scopeOverride != null ? this.scopeOverride : RegistryScope.SERVER;
132132
} else {
133133
scopeType = this.scopeOverride != null ? this.scopeOverride : RegistryScope.GAME;
134134
}

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ guava = "32.1.2-jre"
1818
mockito = "5.11.0"
1919
jline = "3.25.1"
2020
tinylog = "2.7.0"
21-
vineflower = "1.10.1"
21+
vineflower = "1.11.1"
2222

2323
[libraries]
2424
# common

src/main/java/org/spongepowered/common/data/provider/entity/EndermanData.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
package org.spongepowered.common.data.provider.entity;
2626

2727
import net.minecraft.world.entity.monster.EnderMan;
28+
import org.spongepowered.api.block.BlockState;
2829
import org.spongepowered.api.data.Keys;
2930
import org.spongepowered.common.accessor.world.entity.monster.EnderManAccessor;
3031
import org.spongepowered.common.data.provider.DataProviderRegistrator;
@@ -40,7 +41,12 @@ public static void register(final DataProviderRegistrator registrator) {
4041
.asMutable(EnderMan.class)
4142
.create(Keys.IS_SCREAMING)
4243
.get(EnderMan::isCreepy)
43-
.set((h, v) -> h.getEntityData().set(EnderManAccessor.accessor$DATA_CREEPY(), v));
44+
.set((h, v) -> h.getEntityData().set(EnderManAccessor.accessor$DATA_CREEPY(), v))
45+
.create(Keys.BLOCK_STATE)
46+
.get(h -> (BlockState) h.getCarriedBlock())
47+
.set((h, v) -> h.setCarriedBlock((net.minecraft.world.level.block.state.BlockState) v))
48+
.delete(h -> h.setCarriedBlock(null));
49+
;
4450
}
4551
// @formatter:on
4652
}

src/main/java/org/spongepowered/common/data/provider/item/stack/CompassItemData.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import net.minecraft.world.item.ItemStack;
3232
import net.minecraft.world.item.component.LodestoneTracker;
3333
import net.minecraft.world.level.Level;
34+
import org.checkerframework.checker.nullness.qual.Nullable;
3435
import org.spongepowered.api.data.Keys;
3536
import org.spongepowered.api.world.server.ServerLocation;
3637
import org.spongepowered.api.world.server.ServerWorld;
@@ -51,8 +52,8 @@ static void register(final DataProviderRegistrator registrator) {
5152
.asMutable(ItemStack.class)
5253
.create(Keys.LODESTONE)
5354
.get(stack -> {
54-
final LodestoneTracker component = stack.get(DataComponents.LODESTONE_TRACKER);
55-
if (component == null) {
55+
final @Nullable LodestoneTracker component = stack.get(DataComponents.LODESTONE_TRACKER);
56+
if (component == null || component.target().isEmpty()) {
5657
return null;
5758
}
5859
final GlobalPos globalPos = component.target().get();

src/main/java/org/spongepowered/common/event/tracking/phase/general/CommandState.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ final class CommandState extends GeneralState<CommandPhaseContext> {
5151
private final BiConsumer<CauseStackManager.StackFrame, CommandPhaseContext> COMMAND_MODIFIER = super.getFrameModifier()
5252
.andThen((frame, ctx) -> {
5353
if (ctx.commandMapping != null) {
54+
ctx.commandMapping.plugin().ifPresent(frame::pushCause);
5455
frame.pushCause(ctx.commandMapping);
5556
}
5657
});

src/main/java/org/spongepowered/common/event/tracking/phase/tick/FluidTickContext.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
package org.spongepowered.common.event.tracking.phase.tick;
2626

2727
import net.minecraft.world.level.block.Block;
28-
import net.minecraft.world.level.block.LiquidBlock;
2928
import net.minecraft.world.level.block.state.BlockState;
3029
import net.minecraft.world.level.material.FluidState;
3130
import org.spongepowered.api.world.LocatableBlock;

src/main/java/org/spongepowered/common/world/level/chunk/storage/SpongeEntityChunk.java

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
*/
2525
package org.spongepowered.common.world.level.chunk.storage;
2626

27-
import com.google.common.collect.ImmutableList;
2827
import net.minecraft.server.level.ServerLevel;
2928
import net.minecraft.util.Tuple;
3029
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@@ -48,25 +47,24 @@
4847
import java.util.AbstractMap;
4948
import java.util.ArrayList;
5049
import java.util.Collection;
50+
import java.util.Collections;
5151
import java.util.List;
5252
import java.util.Objects;
5353
import java.util.Optional;
5454
import java.util.UUID;
5555
import java.util.function.Predicate;
56-
import java.util.stream.Stream;
5756

5857
public final class SpongeEntityChunk implements EntityChunk {
5958

6059
private final ServerLevel level;
6160
private final Vector3i chunkPosition;
62-
private final Stream<net.minecraft.world.entity.Entity> entities;
61+
private final List<net.minecraft.world.entity.Entity> entities;
6362

6463
private @MonotonicNonNull SpongeChunkLayout chunkLayout;
6564
private @MonotonicNonNull Vector3i blockMin;
6665
private @MonotonicNonNull Vector3i blockMax;
67-
private @MonotonicNonNull List<net.minecraft.world.entity.Entity> newEntities;
6866

69-
public SpongeEntityChunk(final ServerLevel level, final Vector3i chunkPosition, final Stream<net.minecraft.world.entity.Entity> entities) {
67+
public SpongeEntityChunk(final ServerLevel level, final Vector3i chunkPosition, final List<net.minecraft.world.entity.Entity> entities) {
7068
this.level = level;
7169
this.chunkPosition = chunkPosition;
7270
this.entities = entities;
@@ -106,23 +104,23 @@ public boolean isAreaAvailable(final int x, final int y, final int z) {
106104

107105
@Override
108106
public Collection<? extends Player> players() {
109-
return this.entities.filter(Player.class::isInstance).map(Player.class::cast).toList();
107+
return this.entities.stream().filter(Player.class::isInstance).map(Player.class::cast).toList();
110108
}
111109

112110
@Override
113111
public Optional<Entity> entity(final UUID uuid) {
114-
return this.entities.filter(e -> e.getUUID().equals(uuid)).map(Entity.class::cast).findFirst();
112+
return this.entities.stream().filter(e -> e.getUUID().equals(uuid)).map(Entity.class::cast).findFirst();
115113
}
116114

117115
@Override
118116
public Collection<? extends Entity> entities() {
119-
return this.entities.map(Entity.class::cast).toList();
117+
return this.entities.stream().map(Entity.class::cast).toList();
120118
}
121119

122120
@Override
123121
public <T extends Entity> Collection<? extends T> entities(final Class<? extends T> entityClass, final AABB box, final @Nullable Predicate<? super T> predicate) {
124122
final net.minecraft.world.phys.AABB mcAabb = VecHelper.toMinecraftAABB(box);
125-
return this.entities
123+
return this.entities.stream()
126124
.filter(e -> entityClass.isInstance(e) && e.getBoundingBox().intersects(mcAabb))
127125
.map(entityClass::cast)
128126
.filter(e -> predicate.test(e))
@@ -132,7 +130,7 @@ public <T extends Entity> Collection<? extends T> entities(final Class<? extends
132130
@Override
133131
public Collection<? extends Entity> entities(final AABB box, final Predicate<? super Entity> filter) {
134132
final net.minecraft.world.phys.AABB mcAabb = VecHelper.toMinecraftAABB(box);
135-
return this.entities.map(Entity.class::cast)
133+
return this.entities.stream().map(Entity.class::cast)
136134
.filter(e -> ((net.minecraft.world.entity.Entity) e).getBoundingBox().intersects(mcAabb) && filter.test(e))
137135
.toList();
138136
}
@@ -156,7 +154,7 @@ public VolumeStream<EntityChunk, Entity> entityStream(final Vector3i min, final
156154
this,
157155
this,
158156
// Entity Accessor
159-
(chunk) -> chunk.entities.filter(entity -> VecHelper.inBounds(entity.blockPosition(), min, max))
157+
(chunk) -> chunk.entities.stream().filter(entity -> VecHelper.inBounds(entity.blockPosition(), min, max))
160158
.map(entity -> new AbstractMap.SimpleEntry<>(entity.blockPosition(), entity)),
161159
// Entity Identity Function
162160
VolumeStreamUtils.getOrCloneEntityWithVolume(shouldCarbonCopy, backingVolume, this.level),
@@ -200,10 +198,7 @@ public Optional<Entity> createEntity(final DataContainer container, final Vector
200198

201199
@Override
202200
public boolean spawnEntity(final Entity entity) {
203-
if (this.newEntities == null) {
204-
this.newEntities = new ArrayList<>();
205-
}
206-
this.newEntities.add((net.minecraft.world.entity.Entity) entity);
201+
this.entities.add((net.minecraft.world.entity.Entity) entity);
207202
return true;
208203
}
209204

@@ -217,17 +212,31 @@ public Collection<Entity> spawnEntities(final Iterable<? extends Entity> entitie
217212
return list;
218213
}
219214

215+
@Override
216+
public void filterEntities(final Predicate<? super Entity> predicate) {
217+
this.entities.removeIf(e -> !predicate.test((Entity) e));
218+
}
219+
220+
@Override
221+
public void filterEntities(final AABB box, final Predicate<? super Entity> predicate) {
222+
final net.minecraft.world.phys.AABB mcAabb = VecHelper.toMinecraftAABB(box);
223+
this.entities.removeIf(e -> e.getBoundingBox().intersects(mcAabb) && !predicate.test((Entity) e));
224+
}
225+
226+
@Override
227+
public <T extends Entity> void filterEntities(final Class<? extends T> entityClass, final AABB box, final @Nullable Predicate<? super T> predicate) {
228+
final net.minecraft.world.phys.AABB mcAabb = VecHelper.toMinecraftAABB(box);
229+
this.entities.removeIf(e -> entityClass.isInstance(e) && e.getBoundingBox().intersects(mcAabb)
230+
&& (predicate == null || !predicate.test(entityClass.cast(e))));
231+
}
232+
220233
private void checkPositionInChunk(final Vector3d position) {
221234
if (!VecHelper.inBounds(position, this.min(), this.max())) {
222235
throw new IllegalArgumentException("Supplied bounds are not within this chunk.");
223236
}
224237
}
225238

226-
public @Nullable List<net.minecraft.world.entity.Entity> buildIfChanged() {
227-
if (this.newEntities == null) {
228-
return null;
229-
}
230-
231-
return Stream.concat(this.entities, this.newEntities.stream()).collect(ImmutableList.toImmutableList());
239+
public List<net.minecraft.world.entity.Entity> build() {
240+
return Collections.unmodifiableList(this.entities);
232241
}
233242
}

src/main/java/org/spongepowered/common/world/server/SpongeWorldManager.java

Lines changed: 56 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import net.minecraft.world.level.LevelSettings;
5656
import net.minecraft.world.level.biome.BiomeManager;
5757
import net.minecraft.world.level.chunk.ChunkGenerator;
58+
import net.minecraft.world.level.chunk.storage.IOWorker;
5859
import net.minecraft.world.level.dimension.BuiltinDimensionTypes;
5960
import net.minecraft.world.level.dimension.DimensionType;
6061
import net.minecraft.world.level.dimension.LevelStem;
@@ -351,12 +352,7 @@ public CompletableFuture<Boolean> unloadWorld(final ServerWorld world) {
351352
return CompletableFuture.completedFuture(false);
352353
}
353354

354-
try {
355-
this.unloadWorld0((ServerLevel) world);
356-
return CompletableFuture.completedFuture(true);
357-
} catch (final IOException e) {
358-
return FutureUtil.completedWithException(e);
359-
}
355+
return this.unloadWorld0((ServerLevel) world);
360356
}
361357

362358
@Override
@@ -537,7 +533,6 @@ public FileVisitResult visitFile(final Path file, final BasicFileAttributes attr
537533
@Override
538534
public CompletableFuture<Boolean> moveWorld(final ResourceKey key, final ResourceKey movedKey) {
539535
final net.minecraft.resources.ResourceKey<Level> registryKey = SpongeWorldManager.createRegistryKey(Objects.requireNonNull(key, "key"));
540-
final net.minecraft.resources.ResourceKey<Level> movedKeyKey = SpongeWorldManager.createRegistryKey(Objects.requireNonNull(movedKey, "movedKey"));
541536

542537
if (Level.OVERWORLD.equals(registryKey)) {
543538
return CompletableFuture.completedFuture(false);
@@ -553,13 +548,15 @@ public CompletableFuture<Boolean> moveWorld(final ResourceKey key, final Resourc
553548

554549
final ServerLevel loadedWorld = this.worlds.get(registryKey);
555550
if (loadedWorld != null) {
556-
try {
557-
this.unloadWorld0(loadedWorld);
558-
} catch (final IOException e) {
559-
return FutureUtil.completedWithException(e);
560-
}
551+
return this.unloadWorld0(loadedWorld).thenCompose($ -> this.moveWorld0(key, movedKey));
561552
}
562553

554+
return this.moveWorld0(key, movedKey);
555+
}
556+
557+
private CompletableFuture<Boolean> moveWorld0(final ResourceKey key, final ResourceKey movedKey) {
558+
final net.minecraft.resources.ResourceKey<Level> movedKeyKey = SpongeWorldManager.createRegistryKey(Objects.requireNonNull(movedKey, "movedKey"));
559+
563560
return CompletableFuture.runAsync(() -> {
564561
final Path originalDirectory = this.getDirectory(key);
565562
final Path movedDirectory = this.getDirectory(movedKey);
@@ -611,14 +608,21 @@ public CompletableFuture<Boolean> deleteWorld(final ResourceKey key) {
611608
final boolean disableLevelSaving = loadedWorld.noSave;
612609
loadedWorld.noSave = true;
613610
((IOWorkerBridge) loadedWorld.getChunkSource().chunkMap.chunkScanner()).bridge$forciblyClear();
614-
try {
615-
this.unloadWorld0(loadedWorld);
616-
} catch (final IOException e) {
617-
loadedWorld.noSave = disableLevelSaving;
618-
return FutureUtil.completedWithException(e);
619-
}
611+
return this.unloadWorld0(loadedWorld)
612+
.thenCompose($ -> this.deleteWorld0(key))
613+
.whenComplete(($, e) -> {
614+
if (e != null) {
615+
loadedWorld.noSave = disableLevelSaving;
616+
}
617+
});
620618
}
621619

620+
return this.deleteWorld0(key);
621+
}
622+
623+
private CompletableFuture<Boolean> deleteWorld0(final ResourceKey key) {
624+
final net.minecraft.resources.ResourceKey<Level> registryKey = SpongeWorldManager.createRegistryKey(key);
625+
622626
return CompletableFuture.runAsync(() -> {
623627
final Path directory = this.getDirectory(key);
624628
if (Files.exists(directory)) {
@@ -653,38 +657,50 @@ public CompletableFuture<Boolean> deleteWorld(final ResourceKey key) {
653657
}, SpongeCommon.server());
654658
}
655659

656-
private void unloadWorld0(final ServerLevel level) throws IOException {
660+
private CompletableFuture<Boolean> unloadWorld0(final ServerLevel level) {
657661
final net.minecraft.resources.ResourceKey<Level> registryKey = level.dimension();
658662

659663
if (!level.getPlayers(p -> true).isEmpty()) {
660-
throw new IOException(String.format("World '%s' was told to unload but players remain.", registryKey.location()));
664+
return CompletableFuture.failedFuture(new IOException(String.format("World '%s' was told to unload but players remain.", registryKey.location())));
661665
}
662666

663-
SpongeCommon.logger().info("Unloading world '{}'", registryKey.location());
667+
// We first tell the world to save without flushing
668+
// and wait for the callback when I/O queue is empty.
669+
level.save(null, false, level.noSave);
664670

665-
final UnloadWorldEvent unloadWorldEvent = SpongeEventFactory.createUnloadWorldEvent(PhaseTracker.getInstance().currentCause(), (ServerWorld) level);
666-
SpongeCommon.post(unloadWorldEvent);
671+
return ((IOWorker) level.getChunkSource().chunkMap.chunkScanner()).synchronize(true).thenComposeAsync($ -> {
672+
if (!level.getPlayers(p -> true).isEmpty()) {
673+
return CompletableFuture.failedFuture(new IOException(String.format("World '%s' was told to unload but players remain.", registryKey.location())));
674+
}
667675

668-
final int lastSpawnChunkRadius = ((ServerLevelAccessor) level).accessor$lastSpawnChunkRadius();
669-
if (lastSpawnChunkRadius > 1) {
670-
level.getChunkSource().removeRegionTicket(TicketType.START, new ChunkPos(level.getSharedSpawnPos()), lastSpawnChunkRadius, Unit.INSTANCE);
671-
((ServerLevelAccessor) level).accessor$setLastSpawnChunkRadius(1);
672-
}
676+
SpongeCommon.logger().info("Unloading world '{}'", registryKey.location());
673677

674-
final var configAdapter = ((ServerLevelDataBridge) level.getLevelData()).bridge$spongeData().configAdapter();
675-
if (configAdapter != null) {
676-
configAdapter.save();
677-
}
678+
final UnloadWorldEvent unloadWorldEvent = SpongeEventFactory.createUnloadWorldEvent(PhaseTracker.getInstance().currentCause(), (ServerWorld) level);
679+
SpongeCommon.post(unloadWorldEvent);
678680

679-
try {
680-
level.save(null, true, level.noSave);
681-
level.close();
682-
((ServerLevelBridge) level).bridge$getLevelSave().close();
683-
} catch (final Exception ex) {
684-
throw new IOException(ex);
685-
}
681+
final int lastSpawnChunkRadius = ((ServerLevelAccessor) level).accessor$lastSpawnChunkRadius();
682+
if (lastSpawnChunkRadius > 1) {
683+
level.getChunkSource().removeRegionTicket(TicketType.START, new ChunkPos(level.getSharedSpawnPos()), lastSpawnChunkRadius, Unit.INSTANCE);
684+
((ServerLevelAccessor) level).accessor$setLastSpawnChunkRadius(1);
685+
}
686+
687+
final var configAdapter = ((ServerLevelDataBridge) level.getLevelData()).bridge$spongeData().configAdapter();
688+
if (configAdapter != null) {
689+
configAdapter.save();
690+
}
686691

687-
this.worlds.remove(registryKey);
692+
try {
693+
level.save(null, true, level.noSave);
694+
level.close();
695+
((ServerLevelBridge) level).bridge$getLevelSave().close();
696+
} catch (final Exception ex) {
697+
return CompletableFuture.failedFuture(new IOException(ex));
698+
}
699+
700+
this.worlds.remove(registryKey);
701+
702+
return CompletableFuture.completedFuture(true);
703+
}, SpongeCommon.server());
688704
}
689705

690706
public void createNonDefaultLevels() {

src/mixins/java/org/spongepowered/common/mixin/core/commands/arguments/selector/EntitySelectorParserMixin.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import net.minecraft.commands.arguments.selector.EntitySelectorParser;
3030
import org.checkerframework.checker.nullness.qual.Nullable;
3131
import org.objectweb.asm.Opcodes;
32+
import org.spongepowered.api.command.CommandCause;
3233
import org.spongepowered.api.command.selector.SelectorType;
3334
import org.spongepowered.api.util.Tristate;
3435
import org.spongepowered.asm.mixin.Final;
@@ -41,6 +42,7 @@
4142
import org.spongepowered.common.accessor.commands.arguments.selector.options.EntitySelectorOptionsAccessor;
4243
import org.spongepowered.common.accessor.commands.arguments.selector.options.EntitySelectorOptions_OptionAccessor;
4344
import org.spongepowered.common.bridge.commands.arguments.selector.EntitySelectorParserBridge;
45+
import org.spongepowered.common.util.Constants;
4446

4547
@Mixin(EntitySelectorParser.class)
4648
public abstract class EntitySelectorParserMixin implements EntitySelectorParserBridge {
@@ -103,4 +105,10 @@ public abstract class EntitySelectorParserMixin implements EntitySelectorParserB
103105
return this.reader;
104106
}
105107

108+
@Inject(method = "allowSelectors", at = @At("HEAD"), cancellable = true)
109+
private static <S> void impl$onAllowSelectors(final S $$0, final CallbackInfoReturnable<Boolean> cir) {
110+
if ($$0 instanceof final CommandCause cause && cause.hasPermission(Constants.Permissions.SELECTOR_PERMISSION)) {
111+
cir.setReturnValue(true);
112+
}
113+
}
106114
}

0 commit comments

Comments
 (0)