Add rule to make the World Border update with ticks instead of real time (#1550)
This commit is contained in:
1 parent
0e2f6df4d3
commit
009d971584
5 files changed
+242
No files matched your search
@@ -27,6 +27,8 @@ import net.minecraft.world.level.block.Block;
|
|||||||
import net.minecraft.world.level.block.Blocks;
|
import net.minecraft.world.level.block.Blocks;
|
||||||
import net.minecraft.world.level.block.entity.StructureBlockEntity;
|
import net.minecraft.world.level.block.entity.StructureBlockEntity;
|
||||||
import net.minecraft.world.level.block.piston.PistonStructureResolver;
|
import net.minecraft.world.level.block.piston.PistonStructureResolver;
|
||||||
|
import net.minecraft.world.level.border.BorderStatus;
|
||||||
|
import net.minecraft.world.level.border.WorldBorder;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -1068,6 +1070,48 @@ public class CarpetSettings
|
|||||||
)
|
)
|
||||||
public static int sculkSensorRange = 8;
|
public static int sculkSensorRange = 8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener, we need to update world borders to change whether
|
||||||
|
* they are currently moving in real time or in game time.
|
||||||
|
*/
|
||||||
|
private static class WorldBorderValidator extends Validator<Boolean>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public Boolean validate(CommandSourceStack source, CarpetRule<Boolean> changingRule, Boolean newValue, String userInput)
|
||||||
|
{
|
||||||
|
if (changingRule.value() ^ newValue)
|
||||||
|
{
|
||||||
|
// Needed for the update
|
||||||
|
tickSyncedWorldBorders = newValue;
|
||||||
|
MinecraftServer server = CarpetServer.minecraft_server;
|
||||||
|
if (server == null)
|
||||||
|
{
|
||||||
|
return newValue;
|
||||||
|
}
|
||||||
|
for (ServerLevel level : server.getAllLevels())
|
||||||
|
{
|
||||||
|
WorldBorder worldBorder = level.getWorldBorder();
|
||||||
|
if (worldBorder.getStatus() != BorderStatus.STATIONARY)
|
||||||
|
{
|
||||||
|
double from = worldBorder.getSize();
|
||||||
|
double to = worldBorder.getLerpTarget();
|
||||||
|
long time = worldBorder.getLerpRemainingTime();
|
||||||
|
worldBorder.lerpSizeBetween(from, to, time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Rule(
|
||||||
|
desc = "Makes world borders move based on in game time instead of real time",
|
||||||
|
extra = "This has the effect that when the tick rate changes the world border speed also changes proportional to it",
|
||||||
|
category = FEATURE,
|
||||||
|
validate = WorldBorderValidator.class
|
||||||
|
)
|
||||||
|
public static boolean tickSyncedWorldBorders = false;
|
||||||
|
|
||||||
public enum FungusFixMode {
|
public enum FungusFixMode {
|
||||||
FALSE, RANDOM, ALL;
|
FALSE, RANDOM, ALL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package carpet.mixins;
|
||||||
|
|
||||||
|
import carpet.CarpetSettings;
|
||||||
|
import carpet.patches.TickSyncedBorderExtent;
|
||||||
|
import net.minecraft.world.level.border.WorldBorder;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(WorldBorder.class)
|
||||||
|
public class WorldBorder_tickMixin
|
||||||
|
{
|
||||||
|
@Shadow private WorldBorder.BorderExtent extent;
|
||||||
|
|
||||||
|
@Inject(method = "lerpSizeBetween", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/border/WorldBorder;getListeners()Ljava/util/List;"))
|
||||||
|
private void getExtent(double d, double e, long l, CallbackInfo ci)
|
||||||
|
{
|
||||||
|
if (d != e && CarpetSettings.tickSyncedWorldBorders)
|
||||||
|
{
|
||||||
|
this.extent = new TickSyncedBorderExtent((WorldBorder) (Object) this, l, d, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
package carpet.patches;
|
||||||
|
|
||||||
|
import carpet.CarpetServer;
|
||||||
|
import carpet.helpers.TickSpeed;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.level.border.BorderChangeListener;
|
||||||
|
import net.minecraft.world.level.border.BorderStatus;
|
||||||
|
import net.minecraft.world.level.border.WorldBorder;
|
||||||
|
import net.minecraft.world.phys.shapes.BooleanOp;
|
||||||
|
import net.minecraft.world.phys.shapes.Shapes;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is essentially a copy of {@link net.minecraft.world.level.border.WorldBorder.MovingBorderExtent}
|
||||||
|
* but instead of using real time to lerp the border
|
||||||
|
* this class uses the in game ticks.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("JavadocReference")
|
||||||
|
public class TickSyncedBorderExtent implements WorldBorder.BorderExtent
|
||||||
|
{
|
||||||
|
private final WorldBorder border;
|
||||||
|
private final long realDuration;
|
||||||
|
private final double tickDuration;
|
||||||
|
private final double from;
|
||||||
|
private final double to;
|
||||||
|
|
||||||
|
private int ticks;
|
||||||
|
|
||||||
|
public TickSyncedBorderExtent(WorldBorder border, long realDuration, double from, double to)
|
||||||
|
{
|
||||||
|
this.border = border;
|
||||||
|
this.realDuration = realDuration;
|
||||||
|
this.tickDuration = realDuration / 50.0;
|
||||||
|
this.from = from;
|
||||||
|
this.to = to;
|
||||||
|
this.ticks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getMinX()
|
||||||
|
{
|
||||||
|
int maxSize = this.border.getAbsoluteMaxSize();
|
||||||
|
return Mth.clamp(this.border.getCenterX() - this.getSize() / 2.0, -maxSize, maxSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getMaxX()
|
||||||
|
{
|
||||||
|
int maxSize = this.border.getAbsoluteMaxSize();
|
||||||
|
return Mth.clamp(this.border.getCenterX() + this.getSize() / 2.0, -maxSize, maxSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getMinZ()
|
||||||
|
{
|
||||||
|
int maxSize = this.border.getAbsoluteMaxSize();
|
||||||
|
return Mth.clamp(this.border.getCenterZ() - this.getSize() / 2.0, -maxSize, maxSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getMaxZ()
|
||||||
|
{
|
||||||
|
int maxSize = this.border.getAbsoluteMaxSize();
|
||||||
|
return Mth.clamp(this.border.getCenterZ() + this.getSize() / 2.0, -maxSize, maxSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getSize()
|
||||||
|
{
|
||||||
|
double progress = this.ticks / this.tickDuration;
|
||||||
|
return progress < 1.0 ? Mth.lerp(progress, this.from, this.to) : this.to;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getLerpSpeed()
|
||||||
|
{
|
||||||
|
return Math.abs(this.from - this.to) / this.realDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getLerpRemainingTime()
|
||||||
|
{
|
||||||
|
// Rough estimation
|
||||||
|
MinecraftServer server = CarpetServer.minecraft_server;
|
||||||
|
double ms;
|
||||||
|
if (server == null)
|
||||||
|
{
|
||||||
|
ms = TickSpeed.mspt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ms = Arrays.stream(server.tickTimes).average().orElseThrow(IllegalStateException::new) * 1.0E-6D;
|
||||||
|
}
|
||||||
|
double tps = 1_000.0D / Math.max((TickSpeed.time_warp_start_time != 0) ? 0.0 : TickSpeed.mspt, ms);
|
||||||
|
return (long) ((this.tickDuration - this.ticks) / tps * 1_000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getLerpTarget()
|
||||||
|
{
|
||||||
|
return this.to;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public BorderStatus getStatus()
|
||||||
|
{
|
||||||
|
return this.to < this.from ? BorderStatus.SHRINKING : BorderStatus.GROWING;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAbsoluteMaxSizeChange()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCenterChange()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public WorldBorder.BorderExtent update()
|
||||||
|
{
|
||||||
|
if (this.ticks++ % 20 == 0)
|
||||||
|
{
|
||||||
|
// We need to update any listeners
|
||||||
|
// Most importantly those that send updates to the client
|
||||||
|
// This is because the client logic uses real time
|
||||||
|
// So if the tick speed has changed we need to tell the client
|
||||||
|
for (BorderChangeListener listener : this.border.getListeners())
|
||||||
|
{
|
||||||
|
// We do not want to update DelegateBorderChangeListener
|
||||||
|
// This updates borders in other dimensions
|
||||||
|
if (!(listener instanceof BorderChangeListener.DelegateBorderChangeListener))
|
||||||
|
{
|
||||||
|
listener.onBorderSizeLerping(this.border, this.from, this.to, this.realDuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.ticks >= this.tickDuration ? this.border.new StaticBorderExtent(this.to) : this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public VoxelShape getCollisionShape()
|
||||||
|
{
|
||||||
|
return Shapes.join(
|
||||||
|
Shapes.INFINITY,
|
||||||
|
Shapes.box(
|
||||||
|
Math.floor(this.getMinX()),
|
||||||
|
Double.NEGATIVE_INFINITY,
|
||||||
|
Math.floor(this.getMinZ()),
|
||||||
|
Math.ceil(this.getMaxX()),
|
||||||
|
Double.POSITIVE_INFINITY,
|
||||||
|
Math.ceil(this.getMaxZ())
|
||||||
|
),
|
||||||
|
BooleanOp.ONLY_FIRST
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,11 @@ accessible class net/minecraft/server/level/ChunkMap$DistanceManager
|
|||||||
accessible class net/minecraft/server/level/ThreadedLevelLightEngine$TaskType
|
accessible class net/minecraft/server/level/ThreadedLevelLightEngine$TaskType
|
||||||
accessible class net/minecraft/world/item/crafting/Ingredient$Value
|
accessible class net/minecraft/world/item/crafting/Ingredient$Value
|
||||||
accessible class net/minecraft/world/level/lighting/BlockLightSectionStorage$BlockDataLayerStorageMap
|
accessible class net/minecraft/world/level/lighting/BlockLightSectionStorage$BlockDataLayerStorageMap
|
||||||
|
accessible class net/minecraft/world/level/border/WorldBorder$BorderExtent
|
||||||
|
accessible class net/minecraft/world/level/border/WorldBorder$StaticBorderExtent
|
||||||
accessible class net/minecraft/server/MinecraftServer$ReloadableResources
|
accessible class net/minecraft/server/MinecraftServer$ReloadableResources
|
||||||
accessible class net/minecraft/world/level/biome/Biome$ClimateSettings
|
accessible class net/minecraft/world/level/biome/Biome$ClimateSettings
|
||||||
|
|
||||||
|
accessible method net/minecraft/world/level/border/WorldBorder getListeners ()Ljava/util/List;
|
||||||
|
|
||||||
accessible field net/minecraft/world/level/block/state/BlockBehaviour UPDATE_SHAPE_ORDER [Lnet/minecraft/core/Direction;
|
accessible field net/minecraft/world/level/block/state/BlockBehaviour UPDATE_SHAPE_ORDER [Lnet/minecraft/core/Direction;
|
||||||
@@ -38,6 +38,7 @@
|
|||||||
"ChunkMap_tickMixin",
|
"ChunkMap_tickMixin",
|
||||||
"DistanceManager_tickMixin",
|
"DistanceManager_tickMixin",
|
||||||
"ServerFunctionManager_tickMixin",
|
"ServerFunctionManager_tickMixin",
|
||||||
|
"WorldBorder_tickMixin",
|
||||||
"ChunkMap_scarpetChunkCreationMixin",
|
"ChunkMap_scarpetChunkCreationMixin",
|
||||||
"LevelEntityGetterAdapter_scarpetMixin",
|
"LevelEntityGetterAdapter_scarpetMixin",
|
||||||
"ChunkHolder_scarpetChunkCreationMixin",
|
"ChunkHolder_scarpetChunkCreationMixin",
|
||||||
|
|||||||
Reference in new issue
Block a user