package com.hypixel.hytale.builtin.portals.integrations; import com.hypixel.hytale.builtin.instances.removal.InstanceDataResource; import com.hypixel.hytale.builtin.instances.removal.RemovalCondition; import com.hypixel.hytale.builtin.instances.removal.TimeoutCondition; import com.hypixel.hytale.builtin.instances.removal.WorldEmptyCondition; import com.hypixel.hytale.codec.Codec; import com.hypixel.hytale.codec.KeyedCodec; import com.hypixel.hytale.codec.builder.BuilderCodec; import com.hypixel.hytale.component.Store; import com.hypixel.hytale.server.core.modules.time.TimeResource; import com.hypixel.hytale.server.core.universe.world.World; import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; import java.time.Duration; import java.time.Instant; import javax.annotation.Nonnull; public class PortalRemovalCondition implements RemovalCondition { public static final BuilderCodec CODEC = BuilderCodec.builder(PortalRemovalCondition.class, PortalRemovalCondition::new) .documentation("A condition for temporary portal worlds.") .append(new KeyedCodec<>("TimeoutSeconds", Codec.DOUBLE), (o, i) -> o.setTimeLimitSeconds(i), o -> o.getTimeLimitSeconds()) .documentation("How long the portal world will stay open (in seconds) after being joined.") .add() .build(); private final WorldEmptyCondition worldEmptyCondition = new WorldEmptyCondition(90.0); private TimeoutCondition timeLimitCondition; public PortalRemovalCondition() { this(60.0); } public PortalRemovalCondition(double timeLimitSeconds) { this.timeLimitCondition = new TimeoutCondition(timeLimitSeconds); } private double getTimeLimitSeconds() { return this.timeLimitCondition.getTimeoutSeconds(); } private void setTimeLimitSeconds(double timeLimitSeconds) { this.timeLimitCondition = new TimeoutCondition(timeLimitSeconds); } public double getElapsedSeconds(World world) { double timeLimitSeconds = this.timeLimitCondition.getTimeoutSeconds(); double remainingSeconds = this.getRemainingSeconds(world); return Math.max(0.0, timeLimitSeconds - remainingSeconds); } public double getRemainingSeconds(World world) { Store chunkStore = world.getChunkStore().getStore(); Store entityStore = world.getEntityStore().getStore(); InstanceDataResource instanceData = chunkStore.getResource(InstanceDataResource.getResourceType()); TimeResource timeResource = entityStore.getResource(TimeResource.getResourceType()); Instant timeoutInstant = instanceData.getTimeoutTimer(); if (timeoutInstant == null) { return this.timeLimitCondition.getTimeoutSeconds(); } else { double remainingSeconds = Duration.between(timeResource.getNow(), timeoutInstant).toNanos() / 1.0E9; return Math.max(0.0, remainingSeconds); } } public void setRemainingSeconds(World world, double seconds) { seconds = Math.max(0.0, seconds); Store chunkStore = world.getChunkStore().getStore(); Store entityStore = world.getEntityStore().getStore(); InstanceDataResource instanceData = chunkStore.getResource(InstanceDataResource.getResourceType()); TimeResource timeResource = entityStore.getResource(TimeResource.getResourceType()); instanceData.setTimeoutTimer(timeResource.getNow().plusMillis((long)(seconds * 1000.0))); } @Override public boolean shouldRemoveWorld(@Nonnull Store store) { InstanceDataResource instanceData = store.getResource(InstanceDataResource.getResourceType()); return instanceData.hadPlayer() && this.timeLimitCondition.shouldRemoveWorld(store) ? true : this.worldEmptyCondition.shouldRemoveWorld(store); } }