From 2f102a77857df961ddbb5978c615114dae0ce475 Mon Sep 17 00:00:00 2001 From: gnembon Date: Mon, 8 Jun 2020 21:24:56 -0300 Subject: [PATCH] Switched to 64FNV-1a as shapes keying algorithm as collision resistant Allow shapes to be sent in bulk as one / few packets Optimized rendering of shapes that not render all faces Moving shapes render now smoothly with higher framerates --- .../DebugRenderer_scarpetRenderMixin.java | 23 +- .../WorldRenderer_scarpetRenderMixin.java | 32 +++ .../carpet/network/ClientNetworkHandler.java | 7 +- .../java/carpet/script/CarpetExpression.java | 45 +--- .../carpet/script/utils/ShapeDispatcher.java | 249 ++++++++++++++---- .../carpet/script/utils/ShapesRenderer.java | 232 ++++++++++------ .../assets/carpet/scripts/chunk_display.sc | 181 +++++++++++++ .../assets/carpet/scripts/overlay.sc | 16 +- src/main/resources/carpet.mixins.json | 3 +- 9 files changed, 595 insertions(+), 193 deletions(-) create mode 100644 src/main/java/carpet/mixins/WorldRenderer_scarpetRenderMixin.java create mode 100644 src/main/resources/assets/carpet/scripts/chunk_display.sc diff --git a/src/main/java/carpet/mixins/DebugRenderer_scarpetRenderMixin.java b/src/main/java/carpet/mixins/DebugRenderer_scarpetRenderMixin.java index a57a3b26..0ed9e836 100644 --- a/src/main/java/carpet/mixins/DebugRenderer_scarpetRenderMixin.java +++ b/src/main/java/carpet/mixins/DebugRenderer_scarpetRenderMixin.java @@ -1,11 +1,7 @@ package carpet.mixins; import carpet.network.CarpetClient; -import carpet.script.utils.ShapesRenderer; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.debug.DebugRenderer; -import net.minecraft.client.util.math.MatrixStack; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -14,25 +10,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(DebugRenderer.class) public class DebugRenderer_scarpetRenderMixin { - private ShapesRenderer shapes; - - @Inject(method = "", at = @At("RETURN")) - private void addRenderers(MinecraftClient client, CallbackInfo ci) - { - shapes = new ShapesRenderer(client); - CarpetClient.shapes = shapes; - } - @Inject(method = "reset", at = @At("HEAD")) private void resetScarpetRenderes(CallbackInfo ci) { - shapes.reset(); + if (CarpetClient.shapes != null) + CarpetClient.shapes.reset(); } - - @Inject(method = "render", at = @At("HEAD")) - private void renderScarpetThings(MatrixStack matrices, VertexConsumerProvider.Immediate vertexConsumers, double cameraX, double cameraY, double cameraZ, CallbackInfo ci) - { - shapes.render(matrices, vertexConsumers, cameraX, cameraY, cameraZ); - } - } diff --git a/src/main/java/carpet/mixins/WorldRenderer_scarpetRenderMixin.java b/src/main/java/carpet/mixins/WorldRenderer_scarpetRenderMixin.java new file mode 100644 index 00000000..df777e69 --- /dev/null +++ b/src/main/java/carpet/mixins/WorldRenderer_scarpetRenderMixin.java @@ -0,0 +1,32 @@ +package carpet.mixins; + +import carpet.network.CarpetClient; +import carpet.script.utils.ShapesRenderer; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.BufferBuilderStorage; +import net.minecraft.client.render.Camera; +import net.minecraft.client.render.GameRenderer; +import net.minecraft.client.render.LightmapTextureManager; +import net.minecraft.client.render.WorldRenderer; +import net.minecraft.client.util.math.Matrix4f; +import net.minecraft.client.util.math.MatrixStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(WorldRenderer.class) +public class WorldRenderer_scarpetRenderMixin +{ + @Inject(method = "", at = @At("RETURN")) + private void addRenderers(MinecraftClient client, BufferBuilderStorage bufferBuilders, CallbackInfo ci) + { + CarpetClient.shapes = new ShapesRenderer(client); + } + + @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/debug/DebugRenderer;render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider$Immediate;DDD)V")) + private void renderScarpetThings(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo ci) + { + if (CarpetClient.shapes != null) CarpetClient.shapes.render(camera, tickDelta); + } +} diff --git a/src/main/java/carpet/network/ClientNetworkHandler.java b/src/main/java/carpet/network/ClientNetworkHandler.java index 07ec99df..c65e2ac6 100644 --- a/src/main/java/carpet/network/ClientNetworkHandler.java +++ b/src/main/java/carpet/network/ClientNetworkHandler.java @@ -8,6 +8,7 @@ import io.netty.buffer.Unpooled; import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.nbt.AbstractNumberTag; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; import net.minecraft.nbt.Tag; import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; import net.minecraft.util.PacketByteBuf; @@ -35,10 +36,14 @@ public class ClientNetworkHandler } }); put("TickRate", (p, t) -> TickSpeed.tickrate(((AbstractNumberTag)t).getFloat(), false)); - put("scShape", (p, t) -> { + put("scShape", (p, t) -> { // deprecated if (CarpetClient.shapes != null) CarpetClient.shapes.addShape((CompoundTag)t); }); + put("scShapes", (p, t) -> { + if (CarpetClient.shapes != null) + CarpetClient.shapes.addShapes((ListTag) t); + }); }}; diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index 06d324b3..711d07d6 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -2662,47 +2662,28 @@ public class CarpetExpression this.expr.addLazyFunction("draw_shape", -1, (c, t, lv) -> { CarpetContext cc = (CarpetContext)c; - if (lv.size() < 3) throw new InternalExpressionException("'draw_shape' takes at least three parameters, shape name, duration, and its params"); - String shapeType = lv.get(0).evalValue(c).getString(); - Value duration = NumericValue.asNumber(lv.get(1).evalValue(c)); - Map params; - if (lv.size() == 3) + ServerPlayerEntity player[] = {null}; + List>> shapes = new ArrayList<>(); + if (lv.size() == 1) // bulk { - Value paramValue = lv.get(2).evalValue(c); - if (paramValue instanceof MapValue) + Value specLoad = lv.get(0).evalValue(c); + if (!(specLoad instanceof ListValue)) throw new InternalExpressionException("In bulk mode - shapes need to be provided as a list of shape specs"); + for (Value list : ((ListValue) specLoad).getItems()) { - params = new HashMap<>(); - ((MapValue) paramValue).getMap().entrySet().forEach(e -> params.put(e.getKey().getString(),e.getValue())); + if (!(list instanceof ListValue)) throw new InternalExpressionException("In bulk mode - shapes need to be provided as a list of shape specs"); + shapes.add( ShapeDispatcher.fromFunctionArgs(cc, ((ListValue) list).getItems(), player)); } - else if (paramValue instanceof ListValue) - { - params = ShapeDispatcher.parseParams(((ListValue) paramValue).getItems()); - } - else throw new InternalExpressionException("Parameters for 'draw_shape' need to be defined either in a list or a map"); } else { - List paramList = new ArrayList<>(); - for (int i=2; i < lv.size(); i++) paramList.add(lv.get(i).evalValue(c)); - params = ShapeDispatcher.parseParams(paramList); + List params = new ArrayList<>(); + for (LazyValue v : lv) params.add(v.evalValue(c)); + shapes.add(ShapeDispatcher.fromFunctionArgs(cc, params, player)); } - params.putIfAbsent("dim", new StringValue(cc.s.getWorld().getDimension().getType().toString())); - params.putIfAbsent("duration", duration); - ServerPlayerEntity player = null; - if (params.containsKey("player")) - { - player = EntityValue.getPlayerByValue(cc.s.getMinecraftServer(), params.get("player")); - if (player == null) - throw new InternalExpressionException("'player' parameter needs to represent an existing player"); - params.remove("player"); - } - - ShapeDispatcher.ExpiringShape shape = ShapeDispatcher.create(cc, shapeType, params); ShapeDispatcher.sendShape( - (player==null)?cc.s.getWorld().getPlayers():Collections.singletonList(player), - shape, - params + (player[0]==null)?cc.s.getWorld().getPlayers():Collections.singletonList(player[0]), + shapes ); return LazyValue.TRUE; }); diff --git a/src/main/java/carpet/script/utils/ShapeDispatcher.java b/src/main/java/carpet/script/utils/ShapeDispatcher.java index 5a66f723..770d7639 100644 --- a/src/main/java/carpet/script/utils/ShapeDispatcher.java +++ b/src/main/java/carpet/script/utils/ShapeDispatcher.java @@ -8,6 +8,7 @@ import carpet.script.exception.InternalExpressionException; import carpet.script.value.BlockValue; import carpet.script.value.EntityValue; import carpet.script.value.ListValue; +import carpet.script.value.MapValue; import carpet.script.value.NumericValue; import carpet.script.value.StringValue; import carpet.script.value.Value; @@ -19,8 +20,10 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.command.arguments.ParticleArgumentType; import net.minecraft.entity.Entity; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.DoubleTag; import net.minecraft.nbt.FloatTag; import net.minecraft.nbt.IntTag; +import net.minecraft.nbt.ListTag; import net.minecraft.nbt.StringTag; import net.minecraft.nbt.Tag; import net.minecraft.particle.ParticleEffect; @@ -32,7 +35,9 @@ import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.util.registry.Registry; import net.minecraft.world.dimension.DimensionType; +import org.apache.commons.lang3.tuple.Pair; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -49,23 +54,90 @@ public class ShapeDispatcher { private static final Map particleCache = new HashMap<>(); - public static void sendShape(List players, ExpiringShape shape, Map params) + public static Pair> fromFunctionArgs( + CarpetContext cc, + List lv, + ServerPlayerEntity[] playerRef + ) { - Consumer alternative = null; - CompoundTag tag = null; + if (lv.size() < 3) throw new InternalExpressionException("'draw_shape' takes at least three parameters, shape name, duration, and its params"); + String shapeType = lv.get(0).getString(); + Value duration = NumericValue.asNumber(lv.get(1)); + Map params; + if (lv.size() == 3) + { + Value paramValue = lv.get(2); + if (paramValue instanceof MapValue) + { + params = new HashMap<>(); + ((MapValue) paramValue).getMap().entrySet().forEach(e -> params.put(e.getKey().getString(),e.getValue())); + } + else if (paramValue instanceof ListValue) + { + params = parseParams(((ListValue) paramValue).getItems()); + } + else throw new InternalExpressionException("Parameters for 'draw_shape' need to be defined either in a list or a map"); + } + else + { + List paramList = new ArrayList<>(); + for (int i=2; i < lv.size(); i++) paramList.add(lv.get(i)); + params = ShapeDispatcher.parseParams(paramList); + } + params.putIfAbsent("dim", new StringValue(cc.s.getWorld().getDimension().getType().toString())); + params.putIfAbsent("duration", duration); + + if (params.containsKey("player")) + { + ServerPlayerEntity player = EntityValue.getPlayerByValue(cc.s.getMinecraftServer(), params.get("player")); + if (player == null) + throw new InternalExpressionException("'player' parameter needs to represent an existing player"); + params.remove("player"); + playerRef[0] = player; + } + return Pair.of(ShapeDispatcher.create(cc, shapeType, params), params); + } + + public static void sendShape(List players, List>> shapes) + { + List clientPlayers = new ArrayList<>(); + List alternativePlayers = new ArrayList<>(); for (ServerPlayerEntity player : players) { if (ServerNetworkHandler.validCarpetPlayers.contains(player)) { - if (tag == null) tag = ExpiringShape.toTag(params); - ServerNetworkHandler.sendCustomCommand(player,"scShape", tag); + clientPlayers.add(player); } else { - if (alternative == null) alternative = shape.alternative(); - alternative.accept(player); + alternativePlayers.add(player); } } + if (!clientPlayers.isEmpty()) + { + + ListTag tag = new ListTag(); + int tagcount = 0; + for (Pair> s : shapes) + { + tag.add(ExpiringShape.toTag(s.getRight())); // 4000 shapes limit boxes + if (tagcount++>1000) + { + tagcount = 0; + Tag finalTag = tag; + clientPlayers.forEach( p -> ServerNetworkHandler.sendCustomCommand(p, "scShapes", finalTag)); + tag = new ListTag(); + } + } + Tag finalTag = tag; + if (tag.size() > 0) clientPlayers.forEach( p -> ServerNetworkHandler.sendCustomCommand(p, "scShapes", finalTag)); + } + if (!alternativePlayers.isEmpty()) + { + List> alternatives = new ArrayList<>(); + shapes.forEach(s -> alternatives.add(s.getLeft().alternative())); + alternativePlayers.forEach(p -> alternatives.forEach( a -> a.accept(p))); + } } public static ParticleEffect getParticleData(String name) @@ -174,7 +246,7 @@ public class ShapeDispatcher protected float fr, fg, fb, fa; protected int fillColor; protected int duration = 0; - private int key; + private long key; protected int followEntity; protected DimensionType entityDimension; @@ -214,7 +286,7 @@ public class ShapeDispatcher duration = NumericValue.asNumber(options.get("duration")).getInt(); - lineWidth = NumericValue.asNumber(options.getOrDefault("width", optional.get("width"))).getFloat(); + lineWidth = NumericValue.asNumber(options.getOrDefault("line", optional.get("line"))).getFloat(); fillColor = NumericValue.asNumber(options.getOrDefault("fill", optional.get("fill"))).getInt(); this.fr = (float)(fillColor >> 24 & 0xFF) / 255.0F; @@ -254,19 +326,19 @@ public class ShapeDispatcher } public abstract Consumer alternative(); - public int key() + public long key() { if (key!=0) return key; key = calcKey(); return key; } - protected int calcKey() - { - int hash = 17; - hash = 31*hash + color; - hash = 31*hash + followEntity; - hash = 31*hash + Float.hashCode(lineWidth); - if (fa != 0.0) hash = 31*hash + fillColor; + protected long calcKey() + { // using FNV-1a algorithm + long hash = -3750763034362895579L; + hash ^= color; hash *= 1099511628211L; + hash ^= followEntity; hash *= 1099511628211L; + hash ^= Float.hashCode(lineWidth); hash *= 1099511628211L; + if (fa != 0.0) { hash = 31*hash + fillColor; hash *= 1099511628211L; } return hash; } // list of params that need to be there @@ -274,7 +346,7 @@ public class ShapeDispatcher private final Map optional = ImmutableMap.of( "color", new NumericValue(-1), "follow", new NumericValue(-1), - "width", new NumericValue(2.0), + "line", new NumericValue(2.0), "fill", new NumericValue(0xffffff00) ); protected Set requiredParams() {return required;} @@ -306,6 +378,7 @@ public class ShapeDispatcher super.init(options); from = vecFromValue(options.get("from")); to = vecFromValue(options.get("to")); + if (from.equals(to)) throw new InternalExpressionException("Box dimensions are invalid - cannot draw a zero-size boxes"); } @Override @@ -330,12 +403,12 @@ public class ShapeDispatcher } @Override - public int calcKey() + public long calcKey() { - int hash = super.calcKey(); - hash = 31*hash + 1; - hash = 31*hash + from.hashCode(); - hash = 31*hash + to.hashCode(); + long hash = super.calcKey(); + hash ^= 1; hash *= 1099511628211L; + hash ^= from.hashCode(); hash *= 1099511628211L; + hash ^= to.hashCode(); hash *= 1099511628211L; return hash; } @@ -389,6 +462,7 @@ public class ShapeDispatcher super.init(options); from = vecFromValue(options.get("from")); to = vecFromValue(options.get("to")); + if (from.equals(to)) throw new InternalExpressionException("Line dimensions are invalid - cannot draw a zero-length lines"); } @Override @@ -414,12 +488,12 @@ public class ShapeDispatcher } @Override - public int calcKey() + public long calcKey() { - int hash = super.calcKey(); - hash = 31*hash + 2; - hash = 31*hash + from.hashCode(); - hash = 31*hash + to.hashCode(); + long hash = super.calcKey(); + hash ^= 2; hash *= 1099511628211L; + hash ^= from.hashCode(); hash *= 1099511628211L; + hash ^= to.hashCode(); hash *= 1099511628211L; return hash; } } @@ -494,13 +568,13 @@ public class ShapeDispatcher };} @Override - public int calcKey() + public long calcKey() { - int hash = super.calcKey(); - hash = 31*hash + 3; - hash = 31*hash + center.hashCode(); - hash = 31*hash + Double.hashCode(radius); - hash = 31*hash + level; + long hash = super.calcKey(); + hash ^= 3; hash *= 1099511628211L; + hash ^= center.hashCode(); hash *= 1099511628211L; + hash ^= Double.hashCode(radius); hash *= 1099511628211L; + hash ^= level; hash *= 1099511628211L; return hash; } } @@ -514,7 +588,7 @@ public class ShapeDispatcher put("duration", new PositiveIntParam("duration")); put("color", new ColorParam("color")); put("follow", new EntityParam("follow")); - put("width", new PositiveFloatParam("width")); + put("line", new PositiveFloatParam("line")); put("fill", new ColorParam("fill")); put("from", new Vec3Param("from", false)); @@ -522,6 +596,9 @@ public class ShapeDispatcher put("center", new Vec3Param("center", false)); put("radius", new PositiveFloatParam("radius")); put("level", new PositiveIntParam("level")); + put("height", new PositiveFloatParam("height")); + put("axis", new StringChoiceParam("axis", "x", "y", "z")); + put("points", new PointsParam("points")); }}; protected String id; protected Param(String id) @@ -543,6 +620,24 @@ public class ShapeDispatcher public Value decode(Tag tag) { return new StringValue(tag.asString()); } } + public static class StringChoiceParam extends StringParam + { + private Set options; + public StringChoiceParam(String id, String ... options) + { + super(id); + this.options = Sets.newHashSet(options); + } + + + @Override + public Value validate(Map options, CarpetContext cc, Value value) + { + if (this.options.contains(value.getString())) return value; + return null; + } + } + public static class DimensionParam extends StringParam { protected DimensionParam() { super("dim"); } @@ -620,13 +715,17 @@ public class ShapeDispatcher } @Override public Value validate(Map options, CarpetContext cc, Value value) + { + return validate(this, options, cc, value, roundsUpForBlocks); + } + public static Value validate(Param p, Map options, CarpetContext cc, Value value, boolean roundsUp) { if (value instanceof BlockValue) { if (options.containsKey("follow")) - throw new InternalExpressionException(id+" parameter cannot use blocks as positions for relative positioning due to 'follow' attribute being present"); + throw new InternalExpressionException(p.id+" parameter cannot use blocks as positions for relative positioning due to 'follow' attribute being present"); BlockPos pos = ((BlockValue) value).getPos(); - int offset = roundsUpForBlocks?1:0; + int offset = roundsUp?1:0; return ListValue.of( new NumericValue(pos.getX()+offset), new NumericValue(pos.getY()+offset), @@ -636,18 +735,18 @@ public class ShapeDispatcher if (value instanceof ListValue) { List values = ((ListValue) value).getItems(); - if (values.size()!=3) throw new InternalExpressionException("'"+id+"' requires 3 numerical values"); + if (values.size()!=3) throw new InternalExpressionException("'"+p.id+"' requires 3 numerical values"); for (Value component : values) { if (!(component instanceof NumericValue)) - throw new InternalExpressionException("'"+id+"' requires 3 numerical values"); + throw new InternalExpressionException("'"+p.id+"' requires 3 numerical values"); } return value; } if (value instanceof EntityValue) { if (options.containsKey("follow")) - throw new InternalExpressionException(id+" parameter cannot use entity as positions for relative positioning due to 'follow' attribute being present"); + throw new InternalExpressionException(p.id+" parameter cannot use entity as positions for relative positioning due to 'follow' attribute being present"); Entity e = ((EntityValue) value).getEntity(); return ListValue.of( new NumericValue(e.getX()), @@ -656,29 +755,81 @@ public class ShapeDispatcher ); } CarpetSettings.LOG.error("Value: "+value.getString()); - throw new InternalExpressionException("'"+id+"' requires a triple, block or entity to indicate position"); + throw new InternalExpressionException("'"+p.id+"' requires a triple, block or entity to indicate position"); } public Value decode(Tag tag) { - CompoundTag ctag = (CompoundTag)tag; + ListTag ctag = (ListTag)tag; return ListValue.of( - new NumericValue(ctag.getDouble("x")), - new NumericValue(ctag.getDouble("y")), - new NumericValue(ctag.getDouble("z")) + new NumericValue(ctag.getDouble(0)), + new NumericValue(ctag.getDouble(1)), + new NumericValue(ctag.getDouble(2)) ); } @Override public Tag toTag(Value value) { List lv = ((ListValue)value).getItems(); - CompoundTag tag = new CompoundTag(); - tag.putDouble("x", NumericValue.asNumber(lv.get(0)).getDouble()); - tag.putDouble("y", NumericValue.asNumber(lv.get(1)).getDouble()); - tag.putDouble("z", NumericValue.asNumber(lv.get(2)).getDouble()); + ListTag tag = new ListTag(); + tag.add(DoubleTag.of(NumericValue.asNumber(lv.get(0)).getDouble())); + tag.add(DoubleTag.of(NumericValue.asNumber(lv.get(1)).getDouble())); + tag.add(DoubleTag.of(NumericValue.asNumber(lv.get(2)).getDouble())); return tag; } } + + public static class PointsParam extends Param + { + public PointsParam(String id) + { + super(id); + } + @Override + public Value validate(Map options, CarpetContext cc, Value value) + { + if (!(value instanceof ListValue)) + throw new InternalExpressionException(id+ " parameter should be a list"); + List points = new ArrayList<>(); + for (Value point: ((ListValue) value).getItems()) + points.add(Vec3Param.validate(this, options, cc, point, false)); + return ListValue.wrap(points); + } + + public Value decode(Tag tag) + { + ListTag ltag = (ListTag)tag; + List points = new ArrayList<>(); + for (int i=0, ll = ltag.size(); i lv = ((ListValue)pointsValue).getItems(); + ListTag ltag = new ListTag(); + for (Value value : lv) + { + List coords = ((ListValue)value).getItems(); + ListTag tag = new ListTag(); + tag.add(DoubleTag.of(NumericValue.asNumber(lv.get(0)).getDouble())); + tag.add(DoubleTag.of(NumericValue.asNumber(lv.get(1)).getDouble())); + tag.add(DoubleTag.of(NumericValue.asNumber(lv.get(2)).getDouble())); + ltag.add(tag); + } + return ltag; + } + } + + public static class ColorParam extends NumericParam { protected ColorParam(String id) diff --git a/src/main/java/carpet/script/utils/ShapesRenderer.java b/src/main/java/carpet/script/utils/ShapesRenderer.java index e259a219..1819885b 100644 --- a/src/main/java/carpet/script/utils/ShapesRenderer.java +++ b/src/main/java/carpet/script/utils/ShapesRenderer.java @@ -2,15 +2,15 @@ package carpet.script.utils; import carpet.CarpetSettings; import com.mojang.blaze3d.systems.RenderSystem; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.BufferBuilder; +import net.minecraft.client.render.Camera; import net.minecraft.client.render.Tessellator; -import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.VertexFormats; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.Entity; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; import net.minecraft.util.Identifier; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; @@ -25,7 +25,7 @@ import java.util.function.BiFunction; public class ShapesRenderer { - private final Map>> shapes; + private final Map>> shapes; private MinecraftClient client; private Map>> renderedShapes @@ -40,12 +40,12 @@ public class ShapesRenderer { this.client = minecraftClient; shapes = new HashMap<>(); - shapes.put(DimensionType.OVERWORLD, new Int2ObjectOpenHashMap<>()); - shapes.put(DimensionType.THE_NETHER, new Int2ObjectOpenHashMap<>()); - shapes.put(DimensionType.THE_END, new Int2ObjectOpenHashMap<>()); + shapes.put(DimensionType.OVERWORLD, new Long2ObjectOpenHashMap<>()); + shapes.put(DimensionType.THE_NETHER, new Long2ObjectOpenHashMap<>()); + shapes.put(DimensionType.THE_END, new Long2ObjectOpenHashMap<>()); } - public void render(MatrixStack matrices, VertexConsumerProvider vertexConsumers, double cameraX, double cameraY, double cameraZ) + public void render(Camera camera, float partialTick) { IWorld iWorld = this.client.world; DimensionType dimensionType = iWorld.getDimension().getType(); @@ -68,20 +68,25 @@ public class ShapesRenderer //RenderSystem.polygonOffset(-3f, -3f); //RenderSystem.enablePolygonOffset(); //Entity entity = this.client.gameRenderer.getCamera().getFocusedEntity(); + Tessellator tessellator = Tessellator.getInstance(); BufferBuilder bufferBuilder = tessellator.getBuffer(); // render + double cameraX = camera.getPos().x; + double cameraY = camera.getPos().y; + double cameraZ = camera.getPos().z; + synchronized (shapes) { - shapes.get(dimensionType).int2ObjectEntrySet().removeIf( + shapes.get(dimensionType).long2ObjectEntrySet().removeIf( entry -> entry.getValue().isExpired(currentTime) ); shapes.get(dimensionType).values().forEach( s -> { if ( s.shouldRender(dimensionType)) - s.renderFaces(tessellator, bufferBuilder, cameraX, cameraY, cameraZ); + s.renderFaces(tessellator, bufferBuilder, cameraX, cameraY, cameraZ, partialTick); } ); //lines @@ -89,7 +94,7 @@ public class ShapesRenderer s -> { if ( s.shouldRender(dimensionType)) - s.renderLines(tessellator, bufferBuilder, cameraX, cameraY, cameraZ); + s.renderLines(tessellator, bufferBuilder, cameraX, cameraY, cameraZ, partialTick); } ); } @@ -102,6 +107,14 @@ public class ShapesRenderer RenderSystem.shadeModel(7424); } + public void addShapes(ListTag tag) + { + for (int i=0, count = tag.size(); i < count; i++) + { + addShape(tag.getCompound(i)); + } + } + public void addShape(CompoundTag tag) { ShapeDispatcher.ExpiringShape shape = ShapeDispatcher.fromTag(tag); @@ -116,7 +129,7 @@ public class ShapesRenderer { RenderedShape rshape = shapeFactory.apply(client, shape); DimensionType dim = Registry.DIMENSION_TYPE.get(new Identifier(tag.getString("dim"))); - int key = rshape.key(); + long key = rshape.key(); synchronized (shapes) { RenderedShape existing = shapes.get(dim).get(key); @@ -135,7 +148,7 @@ public class ShapesRenderer { synchronized (shapes) { - shapes.values().forEach(Int2ObjectOpenHashMap::clear); + shapes.values().forEach(Long2ObjectOpenHashMap::clear); } } @@ -146,13 +159,13 @@ public class ShapesRenderer protected MinecraftClient client; long expiryTick; double renderEpsilon = 0; - public abstract void renderLines(Tessellator tessellator, BufferBuilder builder, double cx, double cy, double cz ); - public void renderFaces(Tessellator tessellator, BufferBuilder builder, double cx, double cy, double cz ) {} + public abstract void renderLines(Tessellator tessellator, BufferBuilder builder, double cx, double cy, double cz, float partialTick ); + public void renderFaces(Tessellator tessellator, BufferBuilder builder, double cx, double cy, double cz, float partialTick ) {} protected RenderedShape(MinecraftClient client, T shape) { this.shape = shape; expiryTick = client.world.getTime()+shape.getExpiry(); - renderEpsilon = (2+((double)shape.key())/Integer.MAX_VALUE)/1000; + renderEpsilon = (3+((double)shape.key())/Long.MAX_VALUE)/1000; this.client = client; } @@ -160,7 +173,7 @@ public class ShapesRenderer { return expiryTick < currentTick; } - public int key() + public long key() { return shape.key(); }; @@ -172,11 +185,15 @@ public class ShapesRenderer if (client.world.getEntityById(shape.followEntity) == null) return false; return true; } - protected Vec3d relativiseRender(Vec3d vec) + protected Vec3d relativiseRender(Vec3d vec, float partialTick) { if (shape.followEntity <= 0) return vec; Entity e = client.world.getEntityById(shape.followEntity); - return shape.toAbsolute(e, vec); + return vec.add( + MathHelper.lerp(partialTick, e.prevX, e.getX()), + MathHelper.lerp(partialTick, e.prevY, e.getY()), + MathHelper.lerp(partialTick, e.prevZ, e.getZ()) + ); } } @@ -189,28 +206,30 @@ public class ShapesRenderer } @Override - public void renderLines(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, double cz) + public void renderLines(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, double cz, float partialTick) { if (shape.a == 0.0) return; - Vec3d v1 = relativiseRender(shape.from); - Vec3d v2 = relativiseRender(shape.to); + Vec3d v1 = relativiseRender(shape.from, partialTick); + Vec3d v2 = relativiseRender(shape.to, partialTick); RenderSystem.lineWidth(shape.lineWidth); drawBoxWireGLLines(tessellator, bufferBuilder, (float)(v1.x-cx-renderEpsilon), (float)(v1.y-cy-renderEpsilon), (float)(v1.z-cz-renderEpsilon), (float)(v2.x-cx+renderEpsilon), (float)(v2.y-cy+renderEpsilon), (float)(v2.z-cz+renderEpsilon), + v1.x!=v2.x, v1.y!=v2.y, v1.z!=v2.z, shape.r, shape.g, shape.b, shape.a, shape.r, shape.g, shape.b ); } @Override - public void renderFaces(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, double cz) + public void renderFaces(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, double cz, float partialTick) { if (shape.fa == 0.0) return; - Vec3d v1 = relativiseRender(shape.from); - Vec3d v2 = relativiseRender(shape.to); + Vec3d v1 = relativiseRender(shape.from, partialTick); + Vec3d v2 = relativiseRender(shape.to, partialTick); RenderSystem.lineWidth(1.0F); drawBoxFaces(tessellator, bufferBuilder, (float)(v1.x-cx-renderEpsilon), (float)(v1.y-cy-renderEpsilon), (float)(v1.z-cz-renderEpsilon), (float)(v2.x-cx+renderEpsilon), (float)(v2.y-cy+renderEpsilon), (float)(v2.z-cz+renderEpsilon), + v1.x!=v2.x, v1.y!=v2.y, v1.z!=v2.z, shape.fr, shape.fg, shape.fb, shape.fa ); } @@ -224,10 +243,10 @@ public class ShapesRenderer super(client, (ShapeDispatcher.Line)shape); } @Override - public void renderLines(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, double cz) + public void renderLines(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, double cz, float partialTick) { - Vec3d v1 = relativiseRender(shape.from); - Vec3d v2 = relativiseRender(shape.to); + Vec3d v1 = relativiseRender(shape.from, partialTick); + Vec3d v2 = relativiseRender(shape.to, partialTick); RenderSystem.lineWidth(shape.lineWidth); drawLine(tessellator, bufferBuilder, (float)(v1.x-cx-renderEpsilon), (float)(v1.y-cy-renderEpsilon), (float)(v1.z-cz-renderEpsilon), @@ -244,10 +263,10 @@ public class ShapesRenderer super(client, (ShapeDispatcher.Sphere)shape); } @Override - public void renderLines(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, double cz) + public void renderLines(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, double cz, float partialTick) { if (shape.a == 0.0) return; - Vec3d vc = relativiseRender(shape.center); + Vec3d vc = relativiseRender(shape.center, partialTick); RenderSystem.lineWidth(shape.lineWidth); drawSphereWireframe(tessellator, bufferBuilder, (float)(vc.x-cx-renderEpsilon), (float)(vc.y-cy-renderEpsilon), (float)(vc.z-cz-renderEpsilon), @@ -255,10 +274,10 @@ public class ShapesRenderer shape.r, shape.g, shape.b, shape.a); } @Override - public void renderFaces(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, double cz) + public void renderFaces(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, double cz, float partialTick) { if (shape.fa == 0.0) return; - Vec3d vc = relativiseRender(shape.center); + Vec3d vc = relativiseRender(shape.center, partialTick); RenderSystem.lineWidth(1.0f); drawSphereFaces(tessellator, bufferBuilder, (float)(vc.x-cx-renderEpsilon), (float)(vc.y-cy-renderEpsilon), (float)(vc.z-cz-renderEpsilon), @@ -276,68 +295,117 @@ public class ShapesRenderer tessellator.draw(); } - public static void drawBoxWireGLLines(Tessellator tessellator, BufferBuilder builder, float x1, float y1, float z1, float x2, float y2, float z2, float red1, float grn1, float blu1, float alpha, float red2, float grn2, float blu2) + public static void drawBoxWireGLLines( + Tessellator tessellator, BufferBuilder builder, + float x1, float y1, float z1, + float x2, float y2, float z2, + boolean xthick, boolean ythick, boolean zthick, + float red1, float grn1, float blu1, float alpha, float red2, float grn2, float blu2) { builder.begin(GL11.GL_LINES, VertexFormats.POSITION_COLOR); // 3 - builder.vertex(x1, y1, z1).color(red1, grn2, blu2, alpha).next(); - builder.vertex(x2, y1, z1).color(red1, grn2, blu2, alpha).next(); - builder.vertex(x1, y1, z1).color(red2, grn1, blu2, alpha).next(); - builder.vertex(x1, y2, z1).color(red2, grn1, blu2, alpha).next(); - builder.vertex(x1, y1, z1).color(red2, grn2, blu1, alpha).next(); - builder.vertex(x1, y1, z2).color(red2, grn2, blu1, alpha).next(); - builder.vertex(x2, y1, z1).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x2, y2, z1).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x2, y2, z1).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x1, y2, z1).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x1, y2, z1).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x1, y2, z2).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x1, y2, z2).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x1, y1, z2).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x1, y1, z2).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x2, y1, z2).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x2, y1, z2).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x2, y1, z1).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x1, y2, z2).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x2, y2, z2).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x2, y1, z2).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x2, y2, z2).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x2, y2, z1).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x2, y2, z2).color(red1, grn1, blu1, alpha).next(); + if (xthick) + { + builder.vertex(x1, y1, z1).color(red1, grn2, blu2, alpha).next(); + builder.vertex(x2, y1, z1).color(red1, grn2, blu2, alpha).next(); + + builder.vertex(x2, y2, z1).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x1, y2, z1).color(red1, grn1, blu1, alpha).next(); + + builder.vertex(x1, y1, z2).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x2, y1, z2).color(red1, grn1, blu1, alpha).next(); + + builder.vertex(x1, y2, z2).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x2, y2, z2).color(red1, grn1, blu1, alpha).next(); + } + if (ythick) + { + builder.vertex(x1, y1, z1).color(red2, grn1, blu2, alpha).next(); + builder.vertex(x1, y2, z1).color(red2, grn1, blu2, alpha).next(); + + builder.vertex(x2, y1, z1).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x2, y2, z1).color(red1, grn1, blu1, alpha).next(); + + builder.vertex(x1, y2, z2).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x1, y1, z2).color(red1, grn1, blu1, alpha).next(); + + builder.vertex(x2, y1, z2).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x2, y2, z2).color(red1, grn1, blu1, alpha).next(); + } + if (zthick) + { + builder.vertex(x1, y1, z1).color(red2, grn2, blu1, alpha).next(); + builder.vertex(x1, y1, z2).color(red2, grn2, blu1, alpha).next(); + + builder.vertex(x1, y2, z1).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x1, y2, z2).color(red1, grn1, blu1, alpha).next(); + + builder.vertex(x2, y1, z2).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x2, y1, z1).color(red1, grn1, blu1, alpha).next(); + + builder.vertex(x2, y2, z1).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x2, y2, z2).color(red1, grn1, blu1, alpha).next(); + } tessellator.draw(); } - public static void drawBoxFaces(Tessellator tessellator, BufferBuilder builder, float x1, float y1, float z1, float x2, float y2, float z2, float red1, float grn1, float blu1, float alpha) + public static void drawBoxFaces( + Tessellator tessellator, BufferBuilder builder, + float x1, float y1, float z1, + float x2, float y2, float z2, + boolean xthick, boolean ythick, boolean zthick, + float red1, float grn1, float blu1, float alpha) { builder.begin(GL11.GL_QUADS, VertexFormats.POSITION_COLOR); - builder.vertex(x1, y1, z1).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x2, y1, z1).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x2, y2, z1).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x1, y2, z1).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x1, y1, z2).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x1, y2, z2).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x2, y2, z2).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x2, y1, z2).color(red1, grn1, blu1, alpha).next(); + if (xthick && ythick) + { + builder.vertex(x1, y1, z1).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x2, y1, z1).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x2, y2, z1).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x1, y2, z1).color(red1, grn1, blu1, alpha).next(); + if (zthick) + { + builder.vertex(x1, y1, z2).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x1, y2, z2).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x2, y2, z2).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x2, y1, z2).color(red1, grn1, blu1, alpha).next(); + } + } - builder.vertex(x1, y1, z1).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x1, y2, z1).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x1, y2, z2).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x1, y1, z2).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x2, y1, z1).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x2, y1, z2).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x2, y2, z2).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x2, y2, z1).color(red1, grn1, blu1, alpha).next(); + if (zthick && ythick) + { + builder.vertex(x1, y1, z1).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x1, y2, z1).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x1, y2, z2).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x1, y1, z2).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x1, y1, z1).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x1, y1, z2).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x2, y1, z2).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x2, y1, z1).color(red1, grn1, blu1, alpha).next(); + if (xthick) + { + builder.vertex(x2, y1, z1).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x2, y1, z2).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x2, y2, z2).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x2, y2, z1).color(red1, grn1, blu1, alpha).next(); + } + } - builder.vertex(x1, y2, z1).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x2, y2, z1).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x2, y2, z2).color(red1, grn1, blu1, alpha).next(); - builder.vertex(x1, y2, z2).color(red1, grn1, blu1, alpha).next(); + // now at least drawing one + if (zthick && xthick) + { + builder.vertex(x1, y1, z1).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x2, y1, z1).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x2, y1, z2).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x1, y1, z2).color(red1, grn1, blu1, alpha).next(); + + + if (ythick) + { + builder.vertex(x1, y2, z1).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x2, y2, z1).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x2, y2, z2).color(red1, grn1, blu1, alpha).next(); + builder.vertex(x1, y2, z2).color(red1, grn1, blu1, alpha).next(); + } + } tessellator.draw(); } diff --git a/src/main/resources/assets/carpet/scripts/chunk_display.sc b/src/main/resources/assets/carpet/scripts/chunk_display.sc new file mode 100644 index 00000000..1a9edf21 --- /dev/null +++ b/src/main/resources/assets/carpet/scripts/chunk_display.sc @@ -0,0 +1,181 @@ +global_chunk_colors = m( + // loaded ticking + l(3, l(0xBBFF0000, 0x88bb0000)), // lime, green + l(2, l(0xFF000000, 0x88000000)), // red + l(1, l(0xFFFF0000, 0xbbbb0000)), // yellow + // 'unloaded' (in memory, so rather 'inaccessible') + l(0, l(0xcccccc00, 0x11111100)), // gray / hi constast + // stable full generation (for '0's, all 1,2,3 are always 'full') + l('full', l(0xbbbbbb00, 0x88888800)), // gray + // unstable final bits + l('heightmaps', l(0xFFFFFF00, 0x00000000)), // check + l('spawn', l(0xFFFFFF00, 0x00000000)), // check + l('light_gen', l(0xFFFFFF00, 0x00000000)), // check + // stable features + l('features', l(0x88bb2200, 0x66882200)), // green muddled + //stable terrain + l('liquid_carvers', l(0x65432100, 0x54321000)), // browns + //unstable terrain - not generated yet + l('carvers', l(0xFFFFFF00, 0x00000000)), // check + l('surface', l(0xFFFFFF00, 0x00000000)), // check + l('noise', l(0xFFFFFF00, 0x00000000)), // check + l('biomes', l(0xFFFFFF00, 0x00000000)), // check + l('structure_references', l(0xFFFFFF00, 0x00000000)), // check + // stable + l('structure_starts', l(0x66666600, 0x22222200)), // darkgrey + // not stated yet + l('empty', l(0xFF88888800, 0xDD444400)), // pink + // proper not in memory + l(null , l(0xFFFFFF00, 0xFFFFFF00)), // hwite + + // ticket types + l('player', l(0x0000DD00, 0x00008800)), // blue + l('portal', l(0xAA00AA00, 0xAA00AA00)), // purple + l('dragon', l(0xAA008800, 0xAA008800)), // purple + l('forced', l(0xAABBFF00, 0x8899AA00)), // blue + l('light', l(0xFFFF0000, 0xBBBB0000)), // yellow + l('post_teleport', l(0xAA00AA00, 0xAA00AA00)), // purple + l('start', l(0xDDFF0000, 0xDDFF0000)), // lime, green + // recent chunk requests + l('unknown', l(0xFFFFFF00, 0x00000000)) // check +); + +// map representing current displayed chunkloading setup +global_current_setup = null; + +// which blocks in the inventory represent which dimension +global_block_markers = m( + l('netherrack', 'the_nether'), + l('grass_block', 'overworld'), + l('end_stone', 'the_end') +); + +__on_player_uses_item(player, item_tuple, hand) -> +( + if (hand != 'mainhand', return()); + if (!has(global_block_markers, item_tuple:0), return()); + if (item_tuple:1%16 != 0, return()); + new_setup = true; + if (global_current_setup, + new_setup = __remove_previous_setup(player) + ); + if (!new_setup, return()); + tag = nbt('{}'); + put(tag:'Enchantments','[]'); + put(tag:'Enchantments', '{lvl:1s,id:"minecraft:protection"}', 0); + inventory_set(player, player~'selected_slot', item_tuple:1, item_tuple:0, tag); + __setup_tracker(player, item_tuple); +); + +//__on_tick() -> null; + +__remove_previous_setup(new_player) -> +( + if (!global_current_setup, return()); + global_running = false; + p = player(); + if (p && + global_block_markers:((item = inventory_get(p, global_current_setup:'inventory_slot')):0)==global_current_setup:'source_dimension' && + item:1 == global_current_setup:'radius' && + item:2, + inventory_set(p, global_current_setup:'inventory_slot', item:1, item:0, null); // disenchant + if( new_player == p && new_player~'selected_slot' == global_current_setup:'inventory_slot', + disabled = true + ); + ); + global_current_setup = null; + !disabled +); + +__setup_tracker(player, item) -> +( + setup = m(); + setup:'player_name' = str(player); + setup:'inventory_slot' = player ~ 'selected_slot'; + setup:'plot_dimension' = player ~ 'dimension'; + setup:'plot_center' = map(pos(player), floor(_))-l(0,1,0); + setup:'radius' = item:1; + setup:'source_dimension' = global_block_markers:(item:0); + multiplier = 1; + if (setup:'source_dimension' != setup:'plot_dimension', + multiplier = if ( + setup:'source_dimension' == 'the_nether', 1/8, + setup:'source_dimension' == 'the_end', 0, + 8); + ); + setup:'source_center' = setup:'plot_center' * multiplier; + print(setup:'source_dimension'+' around '+setup:'source_center'+' with '+setup:'radius'+' radius ('+ (2*setup:'radius'+1)^2 +' chunks)'); + + l(sx, sy, sz) = setup:'source_center'; + global_status_cache = m(); + loop( 2*setup:'radius'+1, dx = _ - setup:'radius'; + loop( 2*setup:'radius'+1, dz = _ - setup:'radius'; + source_pos = l(sx+16*dx,sy,sz+16*dz); + global_status_cache:source_pos = null + ) + ); + global_current_setup = setup; + global_running = true; + schedule(0, '__chunk_visualizer_tick', player); +); + +global_status_cache = m(); + +__chunk_visualizer_tick(p) -> +( + setup = global_current_setup; + if(!setup, return()); + if (!global_running, return()); + show_activity = (p~'holds':0 == 'redstone_torch'); + in_dimension( setup:'plot_dimension', + l(sx, sy, sz) = setup:'source_center'; + l(px, py, pz) = setup:'plot_center'; + source_center = setup:'source_center'; + radius = setup:'radius'; + source_dimension = setup:'source_dimension'; + + shapes = l(); + + loop( 2*radius+1, dx = _ - radius; + loop( 2*radius+1, dz = _ - radius; + changed = false; + source_pos = l(sx+16*dx,sy,sz+16*dz); + status = in_dimension( source_dimension, + loaded_status = loaded_status(source_pos); + if (loaded_status > 0, loaded_status, generation_status(source_pos)) + ); + // will mix with light ticket + if (status=='light', status = 'light_gen'); + + if ( status != global_status_cache:source_pos, + global_status_cache:source_pos = status; + changed = true; + ); + if (loaded_status > 0, + tickets = in_dimension( source_dimension, chunk_tickets(source_pos)); + for(tickets, + l(type, level) = _; + if (show_activity || type != 'unknown', + global_status_cache:source_pos = type; + changed = true; + ); + ); + ); + //if (changed, + //to = global_status_cache:source_pos; + //if(!has(global_chunk_colors:to), print('problem with '+to)); + //set(px+dx,py,pz+dz, global_chunk_colors:to:((dx+dz)%2)); + //set(px+dx,py,pz+dz, global_chunk_colors:(global_status_cache:source_pos):((dx+dz)%2)); + //bpos = l(px+dx/2, py, pz+dz/2); + bpos = l(dx/2, -10, dz/2); + bcol = global_chunk_colors:(global_status_cache:source_pos):((dx+dz)%2); + shapes += l('box', 10, 'from', bpos, 'to', bpos + l(0.5,0,0.5), 'color', bcol, 'fill', bcol+128, + 'follow', p) + ; + //); + ); + ); + draw_shape(shapes); + ); + schedule(5, '__chunk_visualizer_tick', p) +) \ No newline at end of file diff --git a/src/main/resources/assets/carpet/scripts/overlay.sc b/src/main/resources/assets/carpet/scripts/overlay.sc index 81b42749..8038b9d3 100644 --- a/src/main/resources/assets/carpet/scripts/overlay.sc +++ b/src/main/resources/assets/carpet/scripts/overlay.sc @@ -94,7 +94,7 @@ __structure_renderer(player_name) -> l(from, to) = structure_data; total_size = _euclidean(from, to); density = max(10, total_size/10); - draw_shape('box', 15, 'from', from, 'to', to+1, 'color', 0x00FFFFFF, 'width', 3, 'fill', 0x00FFFF22); + draw_shape('box', 15, 'from', from, 'to', to+1, 'color', 0x00FFFFFF, 'line', 3, 'fill', 0x00FFFF22); structure_pieces = slice(sort_key(structure_pieces, _euclidean_sq((_:2+_:3)/2,ppos)), 0, config:'max_pieces'); for (structure_pieces, l(piece, direction, from, to) = _; r = 255 - floor(128 * _i/config:'max_pieces'); @@ -133,12 +133,14 @@ __chunk_renderer(player_name) -> b = 30; a = max(0, 255-player_distance); color = a+256*(b+256*(g+256*r)); - draw_shape('line', 15, 'from', top_00, 'to', top_10, 'color', color, 'width', 3); - draw_shape('line', 15, 'from', top_10, 'to', top_11, 'color', color, 'width', 3); - draw_shape('line', 15, 'from', top_11, 'to', top_01, 'color', color, 'width', 3); - draw_shape('line', 15, 'from', top_01, 'to', top_00, 'color', color, 'width', 3); - draw_shape('line', 15, 'from', top_00, 'to', top_11, 'color', color, 'width', 3); - draw_shape('line', 15, 'from', top_01, 'to', top_10, 'color', color, 'width', 3); + draw_shape(l( + l('line', 15, 'from', top_00, 'to', top_10, 'color', color, 'line', 3), + l('line', 15, 'from', top_10, 'to', top_11, 'color', color, 'line', 3), + l('line', 15, 'from', top_11, 'to', top_01, 'color', color, 'line', 3), + l('line', 15, 'from', top_01, 'to', top_00, 'color', color, 'line', 3), + l('line', 15, 'from', top_00, 'to', top_11, 'color', color, 'line', 3), + l('line', 15, 'from', top_01, 'to', top_10, 'color', color, 'line', 3) + )); ) ) ) diff --git a/src/main/resources/carpet.mixins.json b/src/main/resources/carpet.mixins.json index 65ec4c40..db91b5fe 100644 --- a/src/main/resources/carpet.mixins.json +++ b/src/main/resources/carpet.mixins.json @@ -182,7 +182,8 @@ "WorldRenderer_fogOffMixin", "WorldRenderer_creativeNoClipMixin", "ClientPlayNetworkHandlerMixin", - "DebugRenderer_scarpetRenderMixin" + "DebugRenderer_scarpetRenderMixin", + "WorldRenderer_scarpetRenderMixin" ], "server": [ "MinecraftDedicatedServerMixin"