From a7e6bc5112456c7315dbeb589e2d8c930aec0fd8 Mon Sep 17 00:00:00 2001 From: Chris Sanders Date: Sat, 4 Feb 2023 21:08:09 -0600 Subject: [PATCH 1/4] Implement creation of custom TicketTypes. --- SpongeAPI | 2 +- .../server/level/TicketTypeAccessor.java | 14 ++-- .../bridge/world/server/TicketTypeBridge.java | 35 --------- .../registry/SpongeBuilderProvider.java | 3 + .../common/registry/SpongeRegistries.java | 1 - .../registry/loader/SpongeRegistryLoader.java | 12 --- .../common/world/server/SpongeTicketType.java | 50 ------------- .../world/server/SpongeTicketTypeBuilder.java | 60 +++++++++++++++ .../server/level/TicketTypeMixin_API.java | 8 +- .../core/server/level/TicketTypeMixin.java | 73 ------------------- src/mixins/resources/mixins.sponge.core.json | 1 - 11 files changed, 80 insertions(+), 179 deletions(-) delete mode 100644 src/main/java/org/spongepowered/common/bridge/world/server/TicketTypeBridge.java delete mode 100644 src/main/java/org/spongepowered/common/world/server/SpongeTicketType.java create mode 100644 src/main/java/org/spongepowered/common/world/server/SpongeTicketTypeBuilder.java delete mode 100644 src/mixins/java/org/spongepowered/common/mixin/core/server/level/TicketTypeMixin.java diff --git a/SpongeAPI b/SpongeAPI index e21e6cc94a4..eac6332d1d7 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit e21e6cc94a4179f2c99cf3cf01a1d7e134c088e2 +Subproject commit eac6332d1d7d2c2e6ead8b84bf39226d1310d6a7 diff --git a/src/accessors/java/org/spongepowered/common/accessor/server/level/TicketTypeAccessor.java b/src/accessors/java/org/spongepowered/common/accessor/server/level/TicketTypeAccessor.java index 247e4193682..bcbe0aa9f11 100644 --- a/src/accessors/java/org/spongepowered/common/accessor/server/level/TicketTypeAccessor.java +++ b/src/accessors/java/org/spongepowered/common/accessor/server/level/TicketTypeAccessor.java @@ -26,12 +26,16 @@ import net.minecraft.server.level.TicketType; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; +import org.spongepowered.common.UntransformedInvokerError; -@Mixin(TicketType.class) -public interface TicketTypeAccessor { +import java.util.Comparator; - @Accessor("name") - String accessor$name(); +@Mixin(TicketType.class) +public interface TicketTypeAccessor { + @Invoker("") + static TicketType accessor$createInstance(final String name, final Comparator comparator, final long lifetime) { + throw new UntransformedInvokerError(); + } } diff --git a/src/main/java/org/spongepowered/common/bridge/world/server/TicketTypeBridge.java b/src/main/java/org/spongepowered/common/bridge/world/server/TicketTypeBridge.java deleted file mode 100644 index ffda434254b..00000000000 --- a/src/main/java/org/spongepowered/common/bridge/world/server/TicketTypeBridge.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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.bridge.world.server; - -import java.util.function.Function; - -public interface TicketTypeBridge { - - void bridge$setTypeConverter(Function converter); - - N bridge$convertToNativeType(T spongeType); - -} diff --git a/src/main/java/org/spongepowered/common/registry/SpongeBuilderProvider.java b/src/main/java/org/spongepowered/common/registry/SpongeBuilderProvider.java index b18f5c814e2..8e8abd95466 100644 --- a/src/main/java/org/spongepowered/common/registry/SpongeBuilderProvider.java +++ b/src/main/java/org/spongepowered/common/registry/SpongeBuilderProvider.java @@ -131,6 +131,7 @@ import org.spongepowered.api.world.generation.structure.jigsaw.ProcessorListTemplate; import org.spongepowered.api.world.schematic.PaletteType; import org.spongepowered.api.world.schematic.Schematic; +import org.spongepowered.api.world.server.TicketType; import org.spongepowered.api.world.server.WorldTemplate; import org.spongepowered.api.world.volume.stream.StreamOptions; import org.spongepowered.common.advancement.SpongeAdvancementBuilder; @@ -235,6 +236,7 @@ import org.spongepowered.common.world.schematic.SpongePaletteTypeBuilder; import org.spongepowered.common.world.schematic.SpongeSchematicBuilder; import org.spongepowered.common.world.server.SpongeLocatableBlockBuilder; +import org.spongepowered.common.world.server.SpongeTicketTypeBuilder; import org.spongepowered.common.world.server.SpongeWorldTemplate; import org.spongepowered.common.world.server.SpongeWorldTypeTemplate; import org.spongepowered.common.world.volume.stream.SpongeStreamOptionsBuilder; @@ -386,6 +388,7 @@ public void registerDefaultBuilders() { .register(JigsawPoolTemplate.Builder.class, SpongeJigsawPoolTemplate.BuilderImpl::new) .register(ChatTypeTemplate.Builder.class, SpongeChatTypeTemplate.BuilderImpl::new) .register(DamageTypeTemplate.Builder.class, SpongeDamageTypeTemplate.BuilderImpl::new) + .register(TicketType.Builder.class, SpongeTicketTypeBuilder::new) ; } } diff --git a/src/main/java/org/spongepowered/common/registry/SpongeRegistries.java b/src/main/java/org/spongepowered/common/registry/SpongeRegistries.java index 630717153b9..3e14c3cac24 100644 --- a/src/main/java/org/spongepowered/common/registry/SpongeRegistries.java +++ b/src/main/java/org/spongepowered/common/registry/SpongeRegistries.java @@ -78,7 +78,6 @@ public static void registerEarlyGlobalRegistries(final SpongeRegistryHolder hold holder.createFrozenRegistry(RegistryTypes.RESOLVE_OPERATION, SpongeRegistryLoader.resolveOperation()); holder.createFrozenRegistry(RegistryTypes.SKIN_PART, SpongeRegistryLoader.skinPart()); holder.createFrozenRegistry(RegistryTypes.SPAWN_TYPE, SpongeRegistryLoader.spawnType()); - holder.createFrozenRegistry(RegistryTypes.TICKET_TYPE, SpongeRegistryLoader.ticketType()); holder.createFrozenRegistry(RegistryTypes.TRANSACTION_TYPE, SpongeRegistryLoader.transactionType()); holder.createFrozenRegistry(RegistryTypes.WEATHER_TYPE, SpongeRegistryLoader.weather()); holder.createFrozenRegistry(RegistryTypes.DATA_FORMAT, SpongeRegistryLoader.dataFormat()); diff --git a/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java b/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java index 4e4e42550bd..23c6db5d323 100644 --- a/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java +++ b/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java @@ -108,8 +108,6 @@ import org.spongepowered.api.world.portal.PortalTypes; import org.spongepowered.api.world.schematic.PaletteType; import org.spongepowered.api.world.schematic.PaletteTypes; -import org.spongepowered.api.world.server.TicketType; -import org.spongepowered.api.world.server.TicketTypes; import org.spongepowered.api.world.weather.WeatherType; import org.spongepowered.api.world.weather.WeatherTypes; import org.spongepowered.common.accessor.world.level.levelgen.NoiseSettingsAccessor; @@ -158,13 +156,11 @@ import org.spongepowered.common.map.decoration.orientation.SpongeMapDecorationOrientation; import org.spongepowered.common.registry.RegistryLoader; import org.spongepowered.common.util.SpongeOrientation; -import org.spongepowered.common.util.VecHelper; import org.spongepowered.common.world.SpongeChunkRegenerateFlag; import org.spongepowered.common.world.portal.EndPortalType; import org.spongepowered.common.world.portal.NetherPortalType; import org.spongepowered.common.world.portal.UnknownPortalType; import org.spongepowered.common.world.schematic.SpongePaletteType; -import org.spongepowered.common.world.server.SpongeTicketType; import org.spongepowered.common.world.weather.SpongeWeatherType; import org.spongepowered.math.vector.Vector3d; import org.spongepowered.math.vector.Vector3i; @@ -489,14 +485,6 @@ public static RegistryLoader spawnType() { )); } - public static RegistryLoader> ticketType() { - return RegistryLoader.of(l -> { - l.add(TicketTypes.STANDARD, k -> new SpongeTicketType("standard", Comparator.comparingLong(x -> VecHelper.toChunkPos(x).toLong()), 1)); - l.add(TicketTypes.PORTAL, k -> (TicketType) net.minecraft.server.level.TicketType.PORTAL); - l.add(TicketTypes.POST_TELEPORT, k -> (TicketType) net.minecraft.server.level.TicketType.POST_TELEPORT); - }); - } - public static RegistryLoader transactionType() { return RegistryLoader.of(l -> l.mapping(SpongeTransactionType::new, m -> { m.add(TransactionTypes.DEPOSIT); diff --git a/src/main/java/org/spongepowered/common/world/server/SpongeTicketType.java b/src/main/java/org/spongepowered/common/world/server/SpongeTicketType.java deleted file mode 100644 index 930d6c856bd..00000000000 --- a/src/main/java/org/spongepowered/common/world/server/SpongeTicketType.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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.world.server; - -import net.minecraft.server.level.TicketType; -import org.spongepowered.api.util.Ticks; -import org.spongepowered.common.bridge.world.server.TicketTypeBridge; -import org.spongepowered.common.util.SpongeTicks; - -import java.util.Comparator; -import java.util.function.Function; - -// For use with our own ticket types. -public final class SpongeTicketType extends TicketType implements org.spongepowered.api.world.server.TicketType { - - @SuppressWarnings({"ConstantConditions", "unchecked"}) - public SpongeTicketType(final String param0, final Comparator param1, final long param2) { - super(param0, param1, param2); - // base class was mixed in to, so we know we can do this. - ((TicketTypeBridge) (Object) this).bridge$setTypeConverter(Function.identity()); - } - - @Override - public Ticks lifetime() { - return new SpongeTicks(this.timeout()); - } - -} diff --git a/src/main/java/org/spongepowered/common/world/server/SpongeTicketTypeBuilder.java b/src/main/java/org/spongepowered/common/world/server/SpongeTicketTypeBuilder.java new file mode 100644 index 00000000000..b2edf1590e4 --- /dev/null +++ b/src/main/java/org/spongepowered/common/world/server/SpongeTicketTypeBuilder.java @@ -0,0 +1,60 @@ +package org.spongepowered.common.world.server; + +import org.spongepowered.api.util.Ticks; +import org.spongepowered.api.world.server.TicketType; +import org.spongepowered.common.accessor.server.level.TicketTypeAccessor; + +import java.util.Comparator; +import java.util.Objects; + +public final class SpongeTicketTypeBuilder implements TicketType.Builder { + + private String name; + private Comparator comparator; + private long lifetime = -1; + + @Override + public TicketType.Builder reset() { + this.name = null; + this.comparator = null; + this.lifetime = -1; + return this; + } + + @Override + public TicketType.Builder name(final String name) { + this.name = Objects.requireNonNull(name, "Name cannot null"); + return this; + } + + @Override + public TicketType.Builder comparator(final Comparator comparator) { + this.comparator = comparator; + return this; + } + + @Override + public TicketType.Builder lifetime(final Ticks lifetime) { + this.lifetime = Objects.requireNonNull(lifetime, "Lifetime cannot be null").ticks(); + return this; + } + + @Override + public TicketType.Builder neverExpires() { + this.lifetime = 0; + return this; + } + + @Override + public TicketType build() { + Objects.requireNonNull(this.name, "Name cannot nulll"); + if (this.lifetime < 0) { + throw new IllegalStateException("The lifetime is required to be a positive integer"); + } + if (this.comparator == null) { + this.comparator = (v1, v2) -> 0; + } + + return (TicketType) TicketTypeAccessor.accessor$createInstance(this.name, this.comparator, this.lifetime); + } +} 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 0da1a6739ec..3bd815562ec 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 @@ -35,13 +35,19 @@ public abstract class TicketTypeMixin_API implements TicketType { // @formatter:off + @Shadow @Final private String name; @Shadow @Final private long timeout; + // @formatter:on + @Override + public String name() { + return this.name; + } + @Override @NonNull public Ticks lifetime() { return Ticks.of(this.timeout); } - } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/TicketTypeMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/TicketTypeMixin.java deleted file mode 100644 index 0c064dca3e5..00000000000 --- a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/TicketTypeMixin.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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.core.server.level; - -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.TicketType; -import net.minecraft.util.Unit; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.ChunkPos; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.common.bridge.world.server.TicketTypeBridge; -import org.spongepowered.common.util.VecHelper; -import org.spongepowered.math.vector.Vector3i; - -import java.util.function.Function; - -@Mixin(TicketType.class) -public abstract class TicketTypeMixin implements TicketTypeBridge { - - private Function impl$spongeToNativeType; - - public void bridge$setTypeConverter(final Function converter) { - this.impl$spongeToNativeType = converter; - } - - @SuppressWarnings({"unchecked", "ConstantConditions", "rawtypes"}) - @Override - public N bridge$convertToNativeType(final T spongeType) { - // I hate myself for even doing this, but hey ho. - // The intention is that people will only use Sponge registered tickets. - // If a mod provides a ticket and a plugin wants to use them, it'll have - // to use the correct type. - if (this.impl$spongeToNativeType == null) { - final TicketType thisType = (TicketType) (Object) this; - if (thisType == TicketType.POST_TELEPORT) { - this.impl$spongeToNativeType = (Function) entity -> ((Entity) entity).getId(); - } else if (thisType == TicketType.START || thisType == TicketType.DRAGON) { - this.impl$spongeToNativeType = (Function) notUsed -> Unit.INSTANCE; - } else if (thisType == TicketType.FORCED || thisType == TicketType.LIGHT || thisType == TicketType.PLAYER || - thisType == TicketType.UNKNOWN) { - this.impl$spongeToNativeType = (Function) (Function) (VecHelper::toChunkPos); - } else if (thisType == TicketType.PORTAL) { - this.impl$spongeToNativeType = (Function) (Function) (VecHelper::toBlockPos); - } else { - this.impl$spongeToNativeType = t -> (N) t; - } - } - return this.impl$spongeToNativeType.apply(spongeType); - } - -} diff --git a/src/mixins/resources/mixins.sponge.core.json b/src/mixins/resources/mixins.sponge.core.json index 29b97db7ccf..ab7938c6b72 100644 --- a/src/mixins/resources/mixins.sponge.core.json +++ b/src/mixins/resources/mixins.sponge.core.json @@ -78,7 +78,6 @@ "server.level.ServerPlayerMixin", "server.level.ServerPlayerMixin_HealthScale", "server.level.TicketMixin", - "server.level.TicketTypeMixin", "server.network.LegacyQueryHandlerMixin", "server.network.ServerCommonPacketListenerImplMixin", "server.network.ServerConfigurationPacketListenerImplMixin", From cc7b42dcdb7ec6b7fae84c99e145d44f8a728fd5 Mon Sep 17 00:00:00 2001 From: Chris Sanders Date: Sat, 4 Feb 2023 21:15:01 -0600 Subject: [PATCH 2/4] Missed this in last commit --- .../mixin/core/server/level/DistanceManagerMixin.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) 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 4d3d7845dad..99184b1c0e5 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 @@ -43,7 +43,6 @@ import org.spongepowered.common.accessor.server.level.TicketAccessor; import org.spongepowered.common.bridge.world.DistanceManagerBridge; import org.spongepowered.common.bridge.world.server.TicketBridge; -import org.spongepowered.common.bridge.world.server.TicketTypeBridge; import org.spongepowered.common.util.Constants; import org.spongepowered.common.util.SpongeTicks; import org.spongepowered.common.util.VecHelper; @@ -102,12 +101,8 @@ public abstract class DistanceManagerMixin implements DistanceManagerBridge { 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); - final TicketType type = (net.minecraft.server.level.TicketType) ticketType; - final net.minecraft.server.level.Ticket ticketToRequest = - TicketAccessor.accessor$createInstance( - type, - distance, - ((TicketTypeBridge) ticketType).bridge$convertToNativeType(value)); + final TicketType type = (net.minecraft.server.level.TicketType) ticketType; + final net.minecraft.server.level.Ticket ticketToRequest = TicketAccessor.accessor$createInstance(type, distance, value); this.shadow$addTicket(VecHelper.toChunkPos(pos).toLong(), ticketToRequest); return Optional.of(((TicketBridge) (Object) ticketToRequest).bridge$retrieveAppropriateTicket()); } @@ -127,7 +122,7 @@ public abstract class DistanceManagerMixin implements DistanceManagerBridge { @Override public Collection> bridge$tickets(final org.spongepowered.api.world.server.TicketType ticketType) { return this.tickets.values().stream() - .flatMap(x -> x.stream().filter(ticket -> ticket.getType().equals(ticketType))) + .flatMap(x -> x.stream().filter(ticket -> ticket.getType() == ticketType)) .map(x -> (Ticket) (Object) x) .collect(Collectors.toList()); } From e90c1824d78a27384aa0637c4431072056662b9e Mon Sep 17 00:00:00 2001 From: aromaa Date: Sun, 5 May 2024 00:57:34 +0300 Subject: [PATCH 3/4] Update on top of Tickets#infinite --- .../registry/loader/SpongeRegistryLoader.java | 2 - .../spongepowered/common/util/Constants.java | 2 + .../world/server/SpongeTicketTypeBuilder.java | 60 +++++++++---- .../server/level/TicketTypeMixin_API.java | 5 +- .../test/chunkmanager/ChunkManagerTest.java | 88 ++++++++++++++++--- 5 files changed, 126 insertions(+), 31 deletions(-) diff --git a/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java b/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java index 23c6db5d323..07bb8d929ef 100644 --- a/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java +++ b/src/main/java/org/spongepowered/common/registry/loader/SpongeRegistryLoader.java @@ -163,9 +163,7 @@ import org.spongepowered.common.world.schematic.SpongePaletteType; import org.spongepowered.common.world.weather.SpongeWeatherType; import org.spongepowered.math.vector.Vector3d; -import org.spongepowered.math.vector.Vector3i; -import java.util.Comparator; import java.util.function.Function; @SuppressWarnings("unchecked") diff --git a/src/main/java/org/spongepowered/common/util/Constants.java b/src/main/java/org/spongepowered/common/util/Constants.java index e45100da453..6875981f837 100644 --- a/src/main/java/org/spongepowered/common/util/Constants.java +++ b/src/main/java/org/spongepowered/common/util/Constants.java @@ -444,6 +444,8 @@ public static final class ChunkTicket { // 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 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 b2edf1590e4..0fbce2768fd 100644 --- a/src/main/java/org/spongepowered/common/world/server/SpongeTicketTypeBuilder.java +++ b/src/main/java/org/spongepowered/common/world/server/SpongeTicketTypeBuilder.java @@ -1,23 +1,51 @@ +/* + * 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.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.accessor.server.level.TicketTypeAccessor; +import org.spongepowered.common.util.Constants; import java.util.Comparator; import java.util.Objects; +@SuppressWarnings("unchecked") public final class SpongeTicketTypeBuilder implements TicketType.Builder { - private String name; - private Comparator comparator; - private long lifetime = -1; + private @MonotonicNonNull String name; + private @Nullable Comparator comparator; + private @MonotonicNonNull Ticks lifetime; @Override public TicketType.Builder reset() { this.name = null; this.comparator = null; - this.lifetime = -1; + this.lifetime = null; return this; } @@ -28,33 +56,31 @@ public TicketType.Builder name(final String name) { } @Override - public TicketType.Builder comparator(final Comparator comparator) { + public TicketType.Builder comparator(final @Nullable Comparator comparator) { this.comparator = comparator; return this; } @Override public TicketType.Builder lifetime(final Ticks lifetime) { - this.lifetime = Objects.requireNonNull(lifetime, "Lifetime cannot be null").ticks(); - return this; - } - - @Override - public TicketType.Builder neverExpires() { - this.lifetime = 0; + 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"); + } + this.lifetime = lifetime; return this; } @Override public TicketType build() { - Objects.requireNonNull(this.name, "Name cannot nulll"); - if (this.lifetime < 0) { - throw new IllegalStateException("The lifetime is required to be a positive integer"); - } + Objects.requireNonNull(this.name, "Name cannot null"); + Objects.requireNonNull(this.lifetime, "Lifetime cannot be null"); if (this.comparator == null) { this.comparator = (v1, v2) -> 0; } - return (TicketType) TicketTypeAccessor.accessor$createInstance(this.name, this.comparator, this.lifetime); + return (TicketType) TicketTypeAccessor.accessor$createInstance(this.name, this.comparator, this.lifetime.isInfinite() + ? Constants.ChunkTicket.INFINITE_TIMEOUT + : this.lifetime.ticks()); } } 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 3bd815562ec..19ce2393353 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 @@ -30,6 +30,7 @@ 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 { @@ -48,6 +49,8 @@ public String name() { @Override @NonNull public Ticks lifetime() { - return Ticks.of(this.timeout); + return this.timeout == Constants.ChunkTicket.INFINITE_TIMEOUT + ? Ticks.infinite() + : Ticks.of(this.timeout); } } 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 392267bdc5f..1afab787237 100644 --- a/testplugins/src/main/java/org/spongepowered/test/chunkmanager/ChunkManagerTest.java +++ b/testplugins/src/main/java/org/spongepowered/test/chunkmanager/ChunkManagerTest.java @@ -30,6 +30,7 @@ import net.kyori.adventure.text.LinearComponents; import net.kyori.adventure.text.format.NamedTextColor; import org.apache.logging.log4j.Logger; +import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.api.Sponge; import org.spongepowered.api.command.Command; import org.spongepowered.api.command.CommandResult; @@ -43,13 +44,17 @@ 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.TicketTypes; +import org.spongepowered.api.world.server.TicketType; import org.spongepowered.math.vector.Vector3i; import org.spongepowered.plugin.PluginContainer; import org.spongepowered.plugin.builtin.jvm.Plugin; import org.spongepowered.test.LoadableModule; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; import java.util.Optional; +import java.util.Set; @Plugin("chunkmanagertest") public final class ChunkManagerTest implements LoadableModule { @@ -57,6 +62,8 @@ public final class ChunkManagerTest implements LoadableModule { private final PluginContainer pluginContainer; private final ChunkListener listener; + private Map>> ticketsMap = new HashMap<>(); + @Inject public ChunkManagerTest(final PluginContainer pluginContainer, final Logger logger) { this.pluginContainer = pluginContainer; @@ -67,22 +74,36 @@ public ChunkManagerTest(final PluginContainer pluginContainer, final Logger logg private void registerCommands(final RegisterCommandEvent event) { event.register(this.pluginContainer, Command.builder() - .addChild(this.registerTicketCommand(), "register") - .build(), + .addChild(this.registerTicketCommand(), "register") + .addChild(this.unregisterTicketCommand(), "unregister") + .build(), "chunkticket"); } private Command.Parameterized registerTicketCommand() { final Parameter.Value serverLocationParameter = Parameter.location().key("position").build(); + final Parameter.Value timeParameter = Parameter.integerNumber().key("time").optional().build(); + return Command.builder() .addParameter(serverLocationParameter) + .addParameter(timeParameter) .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 ChunkManager manager = location.world().chunkManager(); final Optional> optionalTicket = manager - .requestTicket(TicketTypes.STANDARD, location.chunkPosition(), location.chunkPosition(), 5); + .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()))); @@ -93,7 +114,7 @@ private Command.Parameterized registerTicketCommand() { )); // now find the ticket - if (manager.findTickets(TicketTypes.STANDARD).contains(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 { @@ -101,13 +122,38 @@ private Command.Parameterized registerTicketCommand() { Component.text().content("Ticket was not found in the chunk manager").color(NamedTextColor.RED).build()); } - Sponge.server().scheduler().submit(Task.builder() + 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) - .delay(Ticks.of(2)) - .execute(() -> context.sendMessage(Identity.nil(), LinearComponents.linear( - Component.text("Ticket validity check (after 2 ticks): "), - Component.text(manager.valid(ticket)) - ))).build()); + .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())); } else { context.sendMessage(Identity.nil(), Component.text("Ticket was not registered.")); } @@ -116,6 +162,26 @@ private Command.Parameterized registerTicketCommand() { .build(); } + private Command.Parameterized unregisterTicketCommand() { + final Parameter.Value serverLocationParameter = Parameter.location().key("position").build(); + + return Command.builder() + .addParameter(serverLocationParameter) + .executor(context -> { + final ServerLocation location = context.requireOne(serverLocationParameter); + 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)); + } else { + context.sendMessage(Identity.nil(), Component.text("No valid tickets.", NamedTextColor.RED)); + } + return CommandResult.success(); + }) + .build(); + } + @Override public void disable(final CommandContext ctx) { Sponge.eventManager().unregisterListeners(this.listener); From 51b785ddbb981969bd8a0f7d9773d98d0f490652 Mon Sep 17 00:00:00 2001 From: aromaa Date: Sat, 18 May 2024 13:48:40 +0300 Subject: [PATCH 4/4] Bump SpongeAPI --- SpongeAPI | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SpongeAPI b/SpongeAPI index eac6332d1d7..aca1deab771 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit eac6332d1d7d2c2e6ead8b84bf39226d1310d6a7 +Subproject commit aca1deab7718573d0585f1ca833056d8a0d9b94f