diff --git a/SpongeAPI b/SpongeAPI index 8602c5ef56b..36df8bdd895 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 8602c5ef56b32be40ab9e04bbb69bda77800bc91 +Subproject commit 36df8bdd89542b2d0211fc1e43b3c2ea7c3a30c7 diff --git a/generator/src/main/java/org/spongepowered/vanilla/generator/world/WorldRegistries.java b/generator/src/main/java/org/spongepowered/vanilla/generator/world/WorldRegistries.java index fa6cf6c7e47..b5d211e4ea1 100644 --- a/generator/src/main/java/org/spongepowered/vanilla/generator/world/WorldRegistries.java +++ b/generator/src/main/java/org/spongepowered/vanilla/generator/world/WorldRegistries.java @@ -53,6 +53,13 @@ public static List worldRegistries(final Context context) { "getSerializedName", "sponge" ), + new RegistryEntriesGenerator<>( + "world.server", + "TicketTypes", + "TICKET_TYPE", + context.relativeClass("world.server", "TicketType"), + Registries.TICKET_TYPE + ), new RegistryEntriesGenerator<>( "effect.particle", "ParticleTypes", diff --git a/src/main/java/org/spongepowered/common/bridge/world/DistanceManagerBridge.java b/src/main/java/org/spongepowered/common/bridge/world/DistanceManagerBridge.java index fe01575105d..9a25743bc0f 100644 --- a/src/main/java/org/spongepowered/common/bridge/world/DistanceManagerBridge.java +++ b/src/main/java/org/spongepowered/common/bridge/world/DistanceManagerBridge.java @@ -25,26 +25,28 @@ package org.spongepowered.common.bridge.world; import org.spongepowered.api.util.Ticks; -import org.spongepowered.api.world.server.ServerWorld; import org.spongepowered.api.world.server.Ticket; import org.spongepowered.api.world.server.TicketType; import org.spongepowered.math.vector.Vector3i; import java.util.Collection; -import java.util.Optional; public interface DistanceManagerBridge { - boolean bridge$checkTicketValid(Ticket ticket); + boolean bridge$checkTicketValid(Ticket ticket); - Ticks bridge$timeLeft(Ticket ticket); + Ticks bridge$timeLeft(Ticket ticket); - Optional> bridge$registerTicket(ServerWorld world, TicketType ticketType, Vector3i pos, T value, int distanceLimit); + Ticket bridge$registerTicket(TicketType ticketType, Vector3i pos, int radius); - boolean bridge$renewTicket(Ticket ticket); + boolean bridge$renewTicket(Ticket ticket); - boolean bridge$releaseTicket(Ticket ticket); + boolean bridge$releaseTicket(Ticket ticket); - Collection> bridge$tickets(TicketType ticketType); + Collection bridge$tickets(Vector3i pos); + + Collection bridge$tickets(org.spongepowered.api.world.server.TicketType type); + + Collection bridge$tickets(); } diff --git a/src/main/java/org/spongepowered/common/bridge/world/server/TicketBridge.java b/src/main/java/org/spongepowered/common/bridge/world/server/TicketBridge.java index 5feb31c4a64..a139ae7f64f 100644 --- a/src/main/java/org/spongepowered/common/bridge/world/server/TicketBridge.java +++ b/src/main/java/org/spongepowered/common/bridge/world/server/TicketBridge.java @@ -32,7 +32,7 @@ public interface TicketBridge { void bridge$setChunkPosition(long chunkPos); - org.spongepowered.api.world.server.Ticket bridge$retrieveAppropriateTicket(); + Ticket bridge$retrieveAppropriateTicket(); void bridge$setParentTicket(Ticket parentTicket); diff --git a/src/main/java/org/spongepowered/common/util/Constants.java b/src/main/java/org/spongepowered/common/util/Constants.java index af492696036..8f7256954c3 100644 --- a/src/main/java/org/spongepowered/common/util/Constants.java +++ b/src/main/java/org/spongepowered/common/util/Constants.java @@ -467,12 +467,9 @@ public static final class Chunk { public static final class ChunkTicket { - public static final int MAX_FULL_CHUNK_TICKET_LEVEL = ChunkLevel.byStatus(FullChunkStatus.ENTITY_TICKING); + public static final int FULL_CHUNK_MAX_TICKET_LEVEL = ChunkLevel.byStatus(FullChunkStatus.FULL); - // Highest ticket level that will cause loading a full chunk, plus one. - public static final int MAX_FULL_CHUNK_DISTANCE = ChunkTicket.MAX_FULL_CHUNK_TICKET_LEVEL + 1; - - public static final int INFINITE_TIMEOUT = 0; + public static final long INFINITE_TIMEOUT = 0; } public static final class Networking { diff --git a/src/main/java/org/spongepowered/common/world/server/SpongeTicketTypeBuilder.java b/src/main/java/org/spongepowered/common/world/server/SpongeTicketTypeBuilder.java index 9a522550451..a2a6905f40d 100644 --- a/src/main/java/org/spongepowered/common/world/server/SpongeTicketTypeBuilder.java +++ b/src/main/java/org/spongepowered/common/world/server/SpongeTicketTypeBuilder.java @@ -25,43 +25,64 @@ package org.spongepowered.common.world.server; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.util.Ticks; import org.spongepowered.api.world.server.TicketType; import org.spongepowered.common.util.Constants; -import java.util.Comparator; import java.util.Objects; -@SuppressWarnings("unchecked") -public final class SpongeTicketTypeBuilder implements TicketType.Builder { +public final class SpongeTicketTypeBuilder implements TicketType.Builder { - private @MonotonicNonNull String name; - private @Nullable Comparator comparator; private @MonotonicNonNull Ticks lifetime; + private int flags; @Override - public TicketType.Builder reset() { - this.name = null; - this.comparator = null; + public TicketType.Builder reset() { this.lifetime = null; + this.flags = 0; + return this; + } + + private void setFlag(int flag, boolean value) { + if (value) { + this.flags |= flag; + } else { + this.flags &= ~flag; + } + } + + @Override + public TicketType.Builder persists(boolean persists) { + this.setFlag(net.minecraft.server.level.TicketType.FLAG_PERSIST, persists); + return this; + } + + @Override + public TicketType.Builder loadsChunks(boolean loadsChunks) { + this.setFlag(net.minecraft.server.level.TicketType.FLAG_LOADING, loadsChunks); + return this; + } + + @Override + public TicketType.Builder simulatesChunks(boolean simulatesChunks) { + this.setFlag(net.minecraft.server.level.TicketType.FLAG_SIMULATION, simulatesChunks); return this; } @Override - public TicketType.Builder name(final String name) { - this.name = Objects.requireNonNull(name, "Name cannot null"); + public TicketType.Builder keepsWorldActive(boolean keepsWorldActive) { + this.setFlag(net.minecraft.server.level.TicketType.FLAG_KEEP_DIMENSION_ACTIVE, keepsWorldActive); return this; } @Override - public TicketType.Builder comparator(final @Nullable Comparator comparator) { - this.comparator = comparator; + public TicketType.Builder canExpireIfUnloaded(boolean canExpireIfUnloaded) { + this.setFlag(net.minecraft.server.level.TicketType.FLAG_CAN_EXPIRE_IF_UNLOADED, canExpireIfUnloaded); return this; } @Override - public TicketType.Builder lifetime(final Ticks lifetime) { + public TicketType.Builder lifetime(final Ticks lifetime) { Objects.requireNonNull(lifetime, "Lifetime cannot be null"); if (!lifetime.isInfinite() && lifetime.ticks() <= 0) { throw new IllegalArgumentException("The lifetime is required to be a positive integer"); @@ -71,16 +92,9 @@ public TicketType.Builder lifetime(final Ticks lifetime) { } @Override - public TicketType build() { - Objects.requireNonNull(this.name, "Name cannot null"); + public TicketType build() { Objects.requireNonNull(this.lifetime, "Lifetime cannot be null"); - if (this.comparator == null) { - this.comparator = (v1, v2) -> 0; - } - final var flag = net.minecraft.server.level.TicketType.FLAG_LOADING - | net.minecraft.server.level.TicketType.FLAG_SIMULATION - | net.minecraft.server.level.TicketType.FLAG_KEEP_DIMENSION_ACTIVE; final var timeout = this.lifetime.isInfinite() ? Constants.ChunkTicket.INFINITE_TIMEOUT : this.lifetime.ticks(); - return (TicketType) (Object) new net.minecraft.server.level.TicketType(timeout,flag); + return (TicketType) (Object) new net.minecraft.server.level.TicketType(timeout, this.flags); } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ChunkMapMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ChunkMapMixin_API.java index 951292ef152..207a96fccc9 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ChunkMapMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/ChunkMapMixin_API.java @@ -39,7 +39,7 @@ import org.spongepowered.math.vector.Vector3i; import java.util.Collection; -import java.util.Optional; +import java.util.Objects; import java.util.concurrent.CompletableFuture; @Mixin(ChunkMap.class) @@ -55,43 +55,56 @@ public abstract class ChunkMapMixin_API implements org.spongepowered.api.world.s } @Override - public boolean valid(final @NonNull Ticket ticket) { + public boolean valid(final @NonNull Ticket ticket) { + Objects.requireNonNull(ticket, "ticket"); return ((ChunkMapBridge) this).bridge$distanceManager().bridge$checkTicketValid(ticket); } @Override - public @NonNull Ticks timeLeft(final @NonNull Ticket ticket) { + public @NonNull Ticks timeLeft(final @NonNull Ticket ticket) { + Objects.requireNonNull(ticket, "ticket"); return ((ChunkMapBridge) this).bridge$distanceManager().bridge$timeLeft(ticket); } @Override - public @NonNull Optional> requestTicket(final @NonNull TicketType type, final @NonNull Vector3i chunkPosition, - final @NonNull T value, final int radius) { - if (!((Object) type instanceof net.minecraft.server.level.TicketType)) { - throw new IllegalArgumentException("TicketType must be a Minecraft TicketType"); + public @NonNull Ticket requestTicket(final @NonNull TicketType type, final @NonNull Vector3i chunkPosition, final int radius) { + Objects.requireNonNull(type, "type"); + Objects.requireNonNull(chunkPosition, "chunkPosition"); + if (radius < 0) { + throw new IllegalArgumentException("The radius must be not be negative."); } - if (radius < 1) { - throw new IllegalArgumentException("The radius must be positive."); - } - return ((ChunkMapBridge) this).bridge$distanceManager() - .bridge$registerTicket(this.world(), type, chunkPosition, value, radius); + return ((ChunkMapBridge) this).bridge$distanceManager().bridge$registerTicket(type, chunkPosition, radius); } @Override - public boolean renewTicket(final @NonNull Ticket ticket) { + public boolean renewTicket(final @NonNull Ticket ticket) { + Objects.requireNonNull(ticket, "ticket"); return ((ChunkMapBridge) this).bridge$distanceManager().bridge$renewTicket(ticket); } @Override - public boolean releaseTicket(final @NonNull Ticket ticket) { + public boolean releaseTicket(final @NonNull Ticket ticket) { + Objects.requireNonNull(ticket, "ticket"); return ((ChunkMapBridge) this).bridge$distanceManager().bridge$releaseTicket(ticket); } @Override - public @NonNull Collection> findTickets(final @NonNull TicketType type) { + public @NonNull Collection findTickets(final @NonNull Vector3i chunkOrigin) { + Objects.requireNonNull(chunkOrigin, "chunkOrigin"); + return ((ChunkMapBridge) this).bridge$distanceManager().bridge$tickets(chunkOrigin); + } + + @Override + public @NonNull Collection findTickets(final @NonNull TicketType type) { + Objects.requireNonNull(type, "type"); return ((ChunkMapBridge) this).bridge$distanceManager().bridge$tickets(type); } + @Override + public @NonNull Collection findTickets() { + return ((ChunkMapBridge) this).bridge$distanceManager().bridge$tickets(); + } + @Override public @NonNull CompletableFuture regenerateChunk(final int cx, final int cy, final int cz, final @NonNull ChunkRegenerateFlag flag) { final CompletableFuture cf = new CompletableFuture<>(); diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/TicketMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/TicketMixin_API.java index 41e00267aa5..c3e79a0db2e 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/TicketMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/TicketMixin_API.java @@ -25,8 +25,36 @@ package org.spongepowered.common.mixin.api.minecraft.server.level; import net.minecraft.server.level.Ticket; +import net.minecraft.world.level.ChunkPos; +import org.spongepowered.api.world.server.TicketType; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.common.bridge.world.server.TicketBridge; +import org.spongepowered.common.util.Constants; +import org.spongepowered.common.util.VecHelper; +import org.spongepowered.math.vector.Vector3i; @Mixin(Ticket.class) -public abstract class TicketMixin_API implements org.spongepowered.api.world.server.Ticket { +public abstract class TicketMixin_API implements org.spongepowered.api.world.server.Ticket { + + // @formatter:off + @Shadow @Final private net.minecraft.server.level.TicketType type; + @Shadow @Final private int ticketLevel; + // @formatter:on + + @Override + public TicketType type() { + return (TicketType) (Object) this.type; + } + + @Override + public Vector3i chunkOrigin() { + return VecHelper.toVector3i(new ChunkPos(((TicketBridge) this).bridge$chunkPosition())); + } + + @Override + public int radius() { + return Math.max(0, Constants.ChunkTicket.FULL_CHUNK_MAX_TICKET_LEVEL - this.ticketLevel); + } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/TicketTypeMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/TicketTypeMixin_API.java index f4b55f7ad58..ed9847518f1 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/TicketTypeMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/server/level/TicketTypeMixin_API.java @@ -24,33 +24,50 @@ */ package org.spongepowered.common.mixin.api.minecraft.server.level; +import net.minecraft.server.level.TicketType; import org.checkerframework.checker.nullness.qual.NonNull; import org.spongepowered.api.util.Ticks; -import org.spongepowered.api.world.server.TicketType; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.common.util.Constants; -@Mixin(net.minecraft.server.level.TicketType.class) -public abstract class TicketTypeMixin_API implements TicketType { +@Mixin(TicketType.class) +public abstract class TicketTypeMixin_API implements org.spongepowered.api.world.server.TicketType { // @formatter:off @Shadow @Final private long timeout; - + @Shadow @Final private int flags; // @formatter:on @Override - public String name() { - // TODO - change this out - return ""; + public boolean persists() { + return (this.flags & TicketType.FLAG_PERSIST) != 0; + } + + @Override + public boolean loadsChunks() { + return (this.flags & TicketType.FLAG_LOADING) != 0; + } + + @Override + public boolean simulatesChunks() { + return (this.flags & TicketType.FLAG_SIMULATION) != 0; + } + + @Override + public boolean keepsWorldActive() { + return (this.flags & TicketType.FLAG_KEEP_DIMENSION_ACTIVE) != 0; + } + + @Override + public boolean canExpireIfUnloaded() { + return (this.flags & TicketType.FLAG_CAN_EXPIRE_IF_UNLOADED) != 0; } @Override @NonNull public Ticks lifetime() { - return this.timeout == Constants.ChunkTicket.INFINITE_TIMEOUT - ? Ticks.infinite() - : Ticks.of(this.timeout); + return this.timeout == Constants.ChunkTicket.INFINITE_TIMEOUT ? Ticks.infinite() : Ticks.of(this.timeout); } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/DistanceManagerMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/DistanceManagerMixin.java index f3ea9e10d29..663955211f5 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/DistanceManagerMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/DistanceManagerMixin.java @@ -26,10 +26,8 @@ import net.minecraft.server.level.DistanceManager; import net.minecraft.server.level.TicketType; -import net.minecraft.util.Mth; import net.minecraft.world.level.TicketStorage; import org.spongepowered.api.util.Ticks; -import org.spongepowered.api.world.server.ServerWorld; import org.spongepowered.api.world.server.Ticket; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -44,7 +42,7 @@ import org.spongepowered.math.vector.Vector3i; import java.util.Collection; -import java.util.Optional; +import java.util.List; import java.util.stream.Collectors; @Mixin(DistanceManager.class) @@ -55,25 +53,19 @@ public abstract class DistanceManagerMixin implements DistanceManagerBridge { // @formatter:on @Override - @SuppressWarnings({"unchecked", "ConstantConditions"}) - public boolean bridge$checkTicketValid(final Ticket ticket) { + public boolean bridge$checkTicketValid(final Ticket ticket) { // Only report the ticket is valid if it's associated with this manager. - final var nativeTicket = ((net.minecraft.server.level.Ticket) (Object) ticket); - final var bridgeTicket = (TicketBridge) ticket; - final var tickets = this.ticketStorage.getTickets(bridgeTicket.bridge$chunkPosition()); - if (tickets != null && tickets.contains(nativeTicket)) { - return !nativeTicket.isTimedOut(); - } - return false; + final var nativeTicket = (net.minecraft.server.level.Ticket) ticket; + final long chunkPos = ((TicketBridge) ticket).bridge$chunkPosition(); + return !nativeTicket.isTimedOut() && this.ticketStorage.getTickets(chunkPos).contains(nativeTicket); } @Override - @SuppressWarnings("ConstantConditions") - public Ticks bridge$timeLeft(final Ticket ticket) { + public Ticks bridge$timeLeft(final Ticket ticket) { if (this.bridge$checkTicketValid(ticket)) { final var mcTicket = (net.minecraft.server.level.Ticket) ticket; - if (mcTicket.getType().timeout() == 0) { - return Ticks.zero(); + if (mcTicket.getType().timeout() == Constants.ChunkTicket.INFINITE_TIMEOUT) { + return Ticks.infinite(); } final long left = ((TicketAccessor) ticket).accessor$ticksLeft(); return new SpongeTicks(Math.max(0, left)); @@ -82,10 +74,9 @@ public abstract class DistanceManagerMixin implements DistanceManagerBridge { } @Override - @SuppressWarnings({"unchecked", "ConstantConditions"}) - public boolean bridge$renewTicket(final Ticket ticket) { + public boolean bridge$renewTicket(final Ticket ticket) { if (this.bridge$checkTicketValid(ticket)) { - final var nativeTicket = (net.minecraft.server.level.Ticket) (Object) ticket; + final var nativeTicket = (net.minecraft.server.level.Ticket) ticket; nativeTicket.resetTicksLeft(); this.ticketStorage.setDirty(); return true; @@ -94,34 +85,43 @@ public abstract class DistanceManagerMixin implements DistanceManagerBridge { } @Override - @SuppressWarnings("unchecked") - public Optional> bridge$registerTicket( - final ServerWorld world, final org.spongepowered.api.world.server.TicketType ticketType, - final Vector3i pos, final T value, final int distanceLimit) { - final int distance = Mth.clamp(Constants.ChunkTicket.MAX_FULL_CHUNK_DISTANCE - distanceLimit, 0, Constants.ChunkTicket.MAX_FULL_CHUNK_TICKET_LEVEL); + public Ticket bridge$registerTicket(final org.spongepowered.api.world.server.TicketType ticketType, final Vector3i pos, final int radius) { final TicketType type = (TicketType) (Object) ticketType; - final net.minecraft.server.level.Ticket ticketToRequest = new net.minecraft.server.level.Ticket(type, distance); + final int level = Math.max(0, Constants.ChunkTicket.FULL_CHUNK_MAX_TICKET_LEVEL - Math.max(0, radius)); + final net.minecraft.server.level.Ticket ticketToRequest = new net.minecraft.server.level.Ticket(type, level); this.ticketStorage.addTicket(VecHelper.toChunkPos(pos).toLong(), ticketToRequest); - return Optional.of(((TicketBridge) (Object) ticketToRequest).bridge$retrieveAppropriateTicket()); + return (Ticket) ((TicketBridge) ticketToRequest).bridge$retrieveAppropriateTicket(); } @Override - @SuppressWarnings({"ConstantConditions"}) - public boolean bridge$releaseTicket(final Ticket ticket) { - if (this.bridge$checkTicketValid(ticket)) { - final var chunkPos = ((TicketBridge) ticket).bridge$chunkPosition(); - return this.ticketStorage.removeTicket(chunkPos, (net.minecraft.server.level.Ticket) ticket); + public boolean bridge$releaseTicket(final Ticket ticket) { + final var nativeTicket = (net.minecraft.server.level.Ticket) ticket; + if (!nativeTicket.isTimedOut()) { + final long chunkPos = ((TicketBridge) ticket).bridge$chunkPosition(); + return this.ticketStorage.removeTicket(chunkPos, nativeTicket); } return false; } - @SuppressWarnings({"ConstantConditions", "unchecked"}) @Override - public Collection> bridge$tickets(final org.spongepowered.api.world.server.TicketType ticketType) { - return ((TicketStorageAccessor) this.ticketStorage).accessor$tickets().values().stream() - .flatMap(x -> x.stream().filter(ticket -> ticket.getType() == (TicketType) (Object) ticketType)) - .map(x -> (Ticket) (Object) x) - .collect(Collectors.toList()); + @SuppressWarnings({"rawtypes", "unchecked"}) + public Collection bridge$tickets(final Vector3i pos) { + return (Collection) List.copyOf(this.ticketStorage.getTickets(VecHelper.toChunkPos(pos).toLong())); + } + + @Override + public Collection bridge$tickets(final org.spongepowered.api.world.server.TicketType type) { + return ((TicketStorageAccessor) this.ticketStorage).accessor$tickets().values() + .stream().flatMap(Collection::stream) + .map(Ticket.class::cast).filter(ticket -> ticket.type().equals(type)) + .collect(Collectors.toList()); } + @Override + public Collection bridge$tickets() { + return ((TicketStorageAccessor) this.ticketStorage).accessor$tickets().values() + .stream().flatMap(Collection::stream) + .map(Ticket.class::cast) + .collect(Collectors.toList()); + } } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/TicketMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/TicketMixin.java index 81055fd79bc..c3bffd84d73 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/TicketMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/TicketMixin.java @@ -47,13 +47,9 @@ public abstract class TicketMixin implements TicketBridge { this.impl$chunkPosition = chunkPos; } - @SuppressWarnings({"unchecked", "ConstantConditions"}) @Override - public org.spongepowered.api.world.server.Ticket bridge$retrieveAppropriateTicket() { - if (this.impl$parent != null) { - return (org.spongepowered.api.world.server.Ticket) (Object) this.impl$parent; - } - return (org.spongepowered.api.world.server.Ticket) this; + public Ticket bridge$retrieveAppropriateTicket() { + return this.impl$parent == null ? (Ticket) (Object) this : this.impl$parent; } @Override diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/TicketStorageMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/TicketStorageMixin.java index eea5de41298..2306926bd79 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/TicketStorageMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/TicketStorageMixin.java @@ -37,13 +37,11 @@ @Mixin(TicketStorage.class) public class TicketStorageMixin { - @SuppressWarnings("ConstantConditions") @Inject(method = "addTicket(JLnet/minecraft/server/level/Ticket;)Z", at = @At("HEAD")) private void impl$addChunkPosToTicket(final long chunkPos, final net.minecraft.server.level.Ticket ticket, final CallbackInfoReturnable ci) { - ((TicketBridge) (Object) ticket).bridge$setChunkPosition(chunkPos); + ((TicketBridge) ticket).bridge$setChunkPosition(chunkPos); } - @SuppressWarnings("ConstantConditions") @ModifyVariable(method = "addTicket(JLnet/minecraft/server/level/Ticket;)Z", at = @At(value = "LOAD"), slice = @Slice( @@ -58,7 +56,7 @@ public class TicketStorageMixin { // potentially costly search on an array - because addTicket doesn't return the ticket that is actually // in the manager. if (storedTicket != originalTicket) { - ((TicketBridge) (Object) originalTicket).bridge$setParentTicket(storedTicket); + ((TicketBridge) originalTicket).bridge$setParentTicket(storedTicket); } return storedTicket; } diff --git a/testplugins/src/main/java/org/spongepowered/test/chunkmanager/ChunkManagerTest.java b/testplugins/src/main/java/org/spongepowered/test/chunkmanager/ChunkManagerTest.java index 1afab787237..5098d1fff3c 100644 --- a/testplugins/src/main/java/org/spongepowered/test/chunkmanager/ChunkManagerTest.java +++ b/testplugins/src/main/java/org/spongepowered/test/chunkmanager/ChunkManagerTest.java @@ -25,7 +25,7 @@ package org.spongepowered.test.chunkmanager; import com.google.inject.Inject; -import net.kyori.adventure.identity.Identity; +import io.leangen.geantyref.TypeToken; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.LinearComponents; import net.kyori.adventure.text.format.NamedTextColor; @@ -39,12 +39,14 @@ import org.spongepowered.api.event.Listener; import org.spongepowered.api.event.lifecycle.RegisterCommandEvent; import org.spongepowered.api.event.world.chunk.ChunkEvent; +import org.spongepowered.api.registry.RegistryTypes; import org.spongepowered.api.scheduler.Task; import org.spongepowered.api.util.Ticks; import org.spongepowered.api.world.server.ChunkManager; import org.spongepowered.api.world.server.ServerLocation; import org.spongepowered.api.world.server.Ticket; import org.spongepowered.api.world.server.TicketType; +import org.spongepowered.api.world.server.TicketTypes; import org.spongepowered.math.vector.Vector3i; import org.spongepowered.plugin.PluginContainer; import org.spongepowered.plugin.builtin.jvm.Plugin; @@ -53,7 +55,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; -import java.util.Optional; import java.util.Set; @Plugin("chunkmanagertest") @@ -62,7 +63,7 @@ public final class ChunkManagerTest implements LoadableModule { private final PluginContainer pluginContainer; private final ChunkListener listener; - private Map>> ticketsMap = new HashMap<>(); + private final Map> ticketsMap = new HashMap<>(); @Inject public ChunkManagerTest(final PluginContainer pluginContainer, final Logger logger) { @@ -82,81 +83,71 @@ private void registerCommands(final RegisterCommandEvent private Command.Parameterized registerTicketCommand() { final Parameter.Value serverLocationParameter = Parameter.location().key("position").build(); - final Parameter.Value timeParameter = Parameter.integerNumber().key("time").optional().build(); + final Parameter.Value typeParameter = Parameter.registryElement(TypeToken.get(TicketType.class), RegistryTypes.TICKET_TYPE, "minecraft").key("time").optional().build(); return Command.builder() .addParameter(serverLocationParameter) - .addParameter(timeParameter) + .addParameter(typeParameter) .executor(context -> { final ServerLocation location = context.requireOne(serverLocationParameter); - final Optional time = context.one(timeParameter); - - final TicketType ticketType = TicketType.builder() - .name("chunkManagerTest") - .comparator(Vector3i::compareTo) - .lifetime(time.map(Ticks::of).orElse(Ticks.infinite())) - .build(); + final TicketType ticketType = context.one(typeParameter).orElseGet(TicketTypes.FORCED); final ChunkManager manager = location.world().chunkManager(); - final Optional> optionalTicket = manager - .requestTicket(ticketType, location.chunkPosition(), location.chunkPosition(), 5); - if (optionalTicket.isPresent()) { - final Ticket ticket = optionalTicket.get(); - final Set> tickets = this.ticketsMap.computeIfAbsent(location.chunkPosition(), k -> new HashSet<>()); - tickets.add(ticket); - context.sendMessage(Identity.nil(), LinearComponents.linear( - Component.text("Ticket registered. Lifetime - "), - Component.text(manager.timeLeft(ticket).ticks()))); - - context.sendMessage(Identity.nil(), LinearComponents.linear( - Component.text("Ticket validity check: "), - Component.text(manager.valid(ticket)) - )); - - // now find the ticket - if (manager.findTickets(ticketType).contains(ticket)) { - context.sendMessage(Identity.nil(), - Component.text().content("Ticket was found in the chunk manager").color(NamedTextColor.GREEN).build()); - } else { - context.sendMessage(Identity.nil(), - Component.text().content("Ticket was not found in the chunk manager").color(NamedTextColor.RED).build()); - } - - time.ifPresentOrElse(t -> { - Sponge.server().scheduler().submit(Task.builder() - .plugin(this.pluginContainer) - .delay(Ticks.of(t + 1)) - .execute(() -> context.sendMessage(Identity.nil(), LinearComponents.linear( - Component.text("Ticket validity check (1 tick before expiration): "), - Component.text(manager.valid(ticket)) - ))).build()); - - Sponge.server().scheduler().submit(Task.builder() - .plugin(this.pluginContainer) - .delay(Ticks.of(t + 2)) - .execute(() -> { - tickets.remove(ticket); - if (tickets.isEmpty()) { - this.ticketsMap.remove(location.chunkPosition(), tickets); - } - context.sendMessage(Identity.nil(), LinearComponents.linear( - Component.text("Ticket validity check (After expiration): "), - Component.text(manager.valid(ticket)))); - }).build()); - }, () -> Sponge.server().scheduler().submit(Task.builder() - .plugin(this.pluginContainer) - .interval(Ticks.of(20)) - .execute(t -> { - context.sendMessage(Identity.nil(), LinearComponents.linear( - Component.text("Ticket validity check (Repeating 20 ticks): "), - Component.text(manager.valid(ticket)))); - if (!manager.valid(ticket)) { - t.cancel(); - } - }).build())); + final Ticket ticket = manager.requestTicket(ticketType, location.chunkPosition(), 5); + + final Set tickets = this.ticketsMap.computeIfAbsent(location.chunkPosition(), k -> new HashSet<>()); + tickets.add(ticket); + + context.sendMessage(Component.text("Ticket registered.")); + final Ticks timeLeft = manager.timeLeft(ticket); + context.sendMessage(Component.text("Ticks left: " + (timeLeft.isInfinite() ? "Infinite" : timeLeft.ticks()))); + context.sendMessage(Component.text("Chunk origin: " + ticket.chunkOrigin())); + context.sendMessage(Component.text("Radius: " + ticket.radius())); + context.sendMessage(Component.text("Ticket validity check: " + manager.valid(ticket))); + + // now find the ticket + if (manager.findTickets(ticketType).contains(ticket)) { + context.sendMessage(Component.text().content("Ticket was found in the chunk manager").color(NamedTextColor.GREEN).build()); } else { - context.sendMessage(Identity.nil(), Component.text("Ticket was not registered.")); + context.sendMessage(Component.text().content("Ticket was not found in the chunk manager").color(NamedTextColor.RED).build()); } + + final Ticks lifetime = ticketType.lifetime(); + if (lifetime.isInfinite()) { + Sponge.server().scheduler().submit(Task.builder() + .plugin(this.pluginContainer) + .interval(Ticks.of(20)) + .execute(t -> { + context.sendMessage(LinearComponents.linear( + Component.text("Ticket validity check (Repeating 20 ticks): "), + Component.text(manager.valid(ticket)))); + if (!manager.valid(ticket)) { + t.cancel(); + } + }).build()); + } else { + Sponge.server().scheduler().submit(Task.builder() + .plugin(this.pluginContainer) + .delay(Ticks.of(lifetime.ticks() + 1)) + .execute(() -> context.sendMessage(LinearComponents.linear( + Component.text("Ticket validity check (1 tick before expiration): "), + Component.text(manager.valid(ticket)) + ))).build()); + + Sponge.server().scheduler().submit(Task.builder() + .plugin(this.pluginContainer) + .delay(Ticks.of(lifetime.ticks() + 2)) + .execute(() -> { + tickets.remove(ticket); + if (tickets.isEmpty()) { + this.ticketsMap.remove(location.chunkPosition(), tickets); + } + context.sendMessage(LinearComponents.linear( + Component.text("Ticket validity check (After expiration): "), + Component.text(manager.valid(ticket)))); + }).build()); + } + return CommandResult.success(); }) .build(); @@ -169,13 +160,13 @@ private Command.Parameterized unregisterTicketCommand() { .addParameter(serverLocationParameter) .executor(context -> { final ServerLocation location = context.requireOne(serverLocationParameter); - final @Nullable Set> tickets = this.ticketsMap.remove(location.chunkPosition()); + final @Nullable Set tickets = this.ticketsMap.remove(location.chunkPosition()); if (tickets != null) { final ChunkManager manager = location.world().chunkManager(); tickets.forEach(manager::releaseTicket); - context.sendMessage(Identity.nil(), Component.text("Removed tickets.", NamedTextColor.GREEN)); + context.sendMessage(Component.text("Removed tickets.", NamedTextColor.GREEN)); } else { - context.sendMessage(Identity.nil(), Component.text("No valid tickets.", NamedTextColor.RED)); + context.sendMessage(Component.text("No valid tickets.", NamedTextColor.RED)); } return CommandResult.success(); }) @@ -185,13 +176,13 @@ private Command.Parameterized unregisterTicketCommand() { @Override public void disable(final CommandContext ctx) { Sponge.eventManager().unregisterListeners(this.listener); - ctx.sendMessage(Identity.nil(), Component.text("Disabled ChunkManagerTest listener")); + ctx.sendMessage(Component.text("Disabled ChunkManagerTest listener")); } @Override public void enable(final CommandContext ctx) { Sponge.eventManager().registerListeners(this.pluginContainer, this.listener); - ctx.sendMessage(Identity.nil(), Component.text("Enabled ChunkManagerTest listener")); + ctx.sendMessage(Component.text("Enabled ChunkManagerTest listener")); } static class ChunkListener {