Skip to content

Commit 5ef0574

Browse files
committed
Fix crash when attempting to delete a construct (resolves #12)
1 parent 73e55fd commit 5ef0574

6 files changed

Lines changed: 84 additions & 10 deletions

File tree

src/client/java/dev/manifold/ConstructRenderCache.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public class ConstructRenderCache {
3636
private final ManifoldSectionCompiler compiler = new ManifoldSectionCompiler(MC.getBlockRenderer(), MC.getBlockEntityRenderDispatcher());
3737
private final RenderBuffers buffers = MC.renderBuffers();
3838
private final HashMap<UUID, CachedConstruct> renderSections = new HashMap<>();
39+
private final ArrayList<UUID> markedForRemoval = new ArrayList<>();
3940

4041
private static void renderShape(
4142
PoseStack poseStack, VertexConsumer vertexConsumer, VoxelShape voxelShape, double d, double e, double f, float r, float g, float b, float a
@@ -152,6 +153,11 @@ public void uploadMesh(UUID id, BlockPos origin, ManifoldRenderChunkRegion regio
152153
public void renderSections(PoseStack stack, Vec3 camPos, float deltaTicks) {
153154
Quaternionf cameraRot = Minecraft.getInstance().gameRenderer.getMainCamera().rotation();
154155
Quaternionf cameraInverseRot = cameraRot.invert();
156+
157+
if (!markedForRemoval.isEmpty()) {
158+
renderSections.keySet().removeAll(markedForRemoval);
159+
markedForRemoval.clear();
160+
}
155161
Collection<CachedConstruct> constructs = renderSections.values();
156162

157163
for (CachedConstruct cached : constructs) {
@@ -212,7 +218,7 @@ public void renderOutline(PoseStack stack, Vec3 camPos, float deltaTicks) {
212218
stack.mulPose(interpolatedRotation);
213219
stack.translate(blockOffset.x - com.x, blockOffset.y - com.y, blockOffset.z - com.z);
214220

215-
VertexConsumer consumer = Minecraft.getInstance().renderBuffers().bufferSource().getBuffer(RenderType.lines());
221+
VertexConsumer consumer = MC.renderBuffers().bufferSource().getBuffer(RenderType.lines());
216222
renderShape(
217223
stack,
218224
consumer,
@@ -221,7 +227,7 @@ public void renderOutline(PoseStack stack, Vec3 camPos, float deltaTicks) {
221227
1.0F, 0.0F, 0.0F, 1.0F
222228
);
223229

224-
Minecraft.getInstance().renderBuffers().outlineBufferSource().endOutlineBatch();
230+
MC.renderBuffers().outlineBufferSource().endOutlineBatch();
225231
}
226232

227233
stack.popPose();
@@ -231,6 +237,10 @@ public HashMap<UUID, CachedConstruct> getRenderedConstructs() {
231237
return this.renderSections;
232238
}
233239

240+
public void markForRemoval(UUID uuid) {
241+
this.markedForRemoval.add(uuid);
242+
}
243+
234244
public record CachedConstruct(
235245
UUID id,
236246
BlockPos origin,

src/client/java/dev/manifold/ManifoldClient.java

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import dev.manifold.network.packets.ConstructSectionDataS2CPacket;
44
import dev.manifold.network.packets.PickConstructBlockWithDataS2CPacket;
5+
import dev.manifold.network.packets.RemoveConstructS2CPacket;
56
import dev.manifold.render.ManifoldRenderChunk;
67
import dev.manifold.render.ManifoldRenderChunkRegion;
78
import io.netty.buffer.Unpooled;
@@ -80,31 +81,36 @@ public static Optional<ConstructBlockHitResult> pickConstructHit(Vec3 cameraPos,
8081
double closestDistSq = maxDistance * maxDistance;
8182

8283
for (ConstructRenderCache.CachedConstruct construct : renderer.getRenderedConstructs().values()) {
83-
//Compute inverse rotation and position
84+
UUID uuid = construct.id();
85+
86+
// Skip constructs that have been removed to prevent a crash
87+
if (!ConstructManager.INSTANCE.hasConstruct(uuid)) continue;
88+
89+
// Compute inverse rotation and position
8490
Vec3 interpolatedConstructPosition = construct.prevPosition().lerp(construct.currentPosition(), alpha);
8591
Quaternionf interpolatedRotation = new Quaternionf(construct.prevRotation()).slerp(construct.currentRotation(), alpha);
8692
Quaternionf inverseInterpolatedRotation = new Quaternionf(interpolatedRotation).invert();
8793
BlockPos simOrigin = construct.origin();
8894
Vec3 com = construct.centerOfMass();
8995

90-
//Transform ray into construct-local space (un-rotated frame)
96+
// Transform ray into construct-local space (un-rotated frame)
9197
Vec3 localStart = rotateVec(cameraPos.subtract(interpolatedConstructPosition), inverseInterpolatedRotation);
9298
Vec3 localEnd = rotateVec(rayEnd.subtract(interpolatedConstructPosition), inverseInterpolatedRotation);
9399

94100
localStart = localStart.add(interpolatedConstructPosition).add(com);
95101
localEnd = localEnd.add(interpolatedConstructPosition).add(com);
96102

97-
//Shift AABB to construct-local space
98-
AABB localAABB = ConstructManager.INSTANCE.getRenderAABB(construct.id());
103+
// Shift AABB to construct-local space
104+
AABB localAABB = ConstructManager.INSTANCE.getRenderAABB(uuid);
99105

100-
//Perform early rejection (stay in local space!)
106+
// Perform early rejection (stay in local space!)
101107
if (!localAABB.contains(localStart) && localAABB.clip(localStart, localEnd).isEmpty()) continue;
102108

103-
//Transform ray back into sim-dimension world space
109+
// Transform ray back into sim-dimension world space
104110
Vec3 simStart = localStart.add(Vec3.atLowerCornerOf(simOrigin)).subtract(interpolatedConstructPosition);
105111
Vec3 simEnd = localEnd.add(Vec3.atLowerCornerOf(simOrigin)).subtract(interpolatedConstructPosition);
106112

107-
//Perform real sim-dimension raycast
113+
// Perform real sim-dimension raycast
108114
BlockHitResult localHitResult = raycastIntoConstructDimension(simStart, simEnd, player, simLevel);
109115

110116
if (localHitResult.getType() == HitResult.Type.BLOCK) {
@@ -117,7 +123,7 @@ public static Optional<ConstructBlockHitResult> pickConstructHit(Vec3 cameraPos,
117123
closestDistSq = distSq;
118124
BlockState state = simLevel.getBlockState(localHitResult.getBlockPos());
119125
VoxelShape shape = state.getShape(simLevel, localHitResult.getBlockPos());
120-
ManifoldRenderChunkRegion region = regions.get(construct.id());
126+
ManifoldRenderChunkRegion region = regions.get(uuid);
121127
closestHit = new ConstructBlockHitResult(construct, shape, localHitResult, region);
122128
}
123129
}
@@ -181,6 +187,10 @@ public void onInitializeClient() {
181187
ClientPlayNetworking.registerGlobalReceiver(PickConstructBlockWithDataS2CPacket.TYPE, (packet, context) ->
182188
context.client().execute(() -> handlePickConstructData(packet))
183189
);
190+
191+
ClientPlayNetworking.registerGlobalReceiver(RemoveConstructS2CPacket.TYPE, (packet, context) ->
192+
context.client().execute(() -> handleRemoveConstruct(packet))
193+
);
184194
}
185195

186196
private void handlePickConstructData(PickConstructBlockWithDataS2CPacket packet) {
@@ -244,4 +254,8 @@ private void handleConstructSectionData(ConstructSectionDataS2CPacket packet) {
244254

245255
renderer.uploadMesh(packet.constructId(), packet.origin(), region);
246256
}
257+
258+
private void handleRemoveConstruct(RemoveConstructS2CPacket packet) {
259+
renderer.markForRemoval(packet.constructId());
260+
}
247261
}

src/main/java/dev/manifold/ConstructManager.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import dev.manifold.network.packets.BreakInConstructC2SPacket;
44
import dev.manifold.network.packets.ConstructSectionDataS2CPacket;
5+
import dev.manifold.network.packets.RemoveConstructS2CPacket;
56
import dev.manifold.phyics.collision.ConstructCollisionManager;
67
import io.netty.buffer.Unpooled;
78
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
@@ -75,6 +76,10 @@ public void removeConstruct(UUID id) {
7576
clearConstructArea(construct);
7677
regionOwners.remove(getRegionIndex(construct.getSimOrigin()));
7778
collisionManager.remove(id);
79+
80+
for (ServerPlayer player : simDimension.getServer().getPlayerList().getPlayers()) {
81+
ServerPlayNetworking.send(player, new RemoveConstructS2CPacket(id));
82+
}
7883
}
7984
}
8085

@@ -133,6 +138,10 @@ public Map<UUID, DynamicConstruct> getConstructs() {
133138
return constructs;
134139
}
135140

141+
public boolean hasConstruct(UUID uuid) {
142+
return constructs.containsKey(uuid);
143+
}
144+
136145
public void placeBlockInConstruct(UUID uuid, BlockPos rel, BlockState state) {
137146
DynamicConstruct construct = constructs.get(uuid);
138147
if (construct == null) return;

src/main/java/dev/manifold/init/ServerPacketRegistry.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ public static void register() {
1616
PickConstructBlockWithDataS2CPacket.CODEC
1717
);
1818

19+
PayloadTypeRegistry.playS2C().register(
20+
PacketTypes.REMOVE_CONSTRUCT,
21+
RemoveConstructS2CPacket.CODEC
22+
);
23+
1924
PayloadTypeRegistry.playC2S().register(
2025
PacketTypes.BREAK_IN_CONSTRUCT,
2126
BreakInConstructC2SPacket.CODEC

src/main/java/dev/manifold/network/PacketTypes.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,7 @@ public class PacketTypes {
1919

2020
public static final CustomPacketPayload.Type<PickConstructBlockWithDataS2CPacket> PICK_CONSTRUCT_BLOCK_S2C =
2121
new CustomPacketPayload.Type<>(Constant.id("pick_construct_block_response"));
22+
23+
public static final CustomPacketPayload.Type<RemoveConstructS2CPacket> REMOVE_CONSTRUCT =
24+
new CustomPacketPayload.Type<>(Constant.id("remove_construct"));
2225
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package dev.manifold.network.packets;
2+
3+
import dev.manifold.Constant;
4+
import net.minecraft.network.FriendlyByteBuf;
5+
import net.minecraft.network.codec.StreamCodec;
6+
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
7+
import org.jetbrains.annotations.NotNull;
8+
9+
import java.util.UUID;
10+
11+
public record RemoveConstructS2CPacket(UUID constructId) implements CustomPacketPayload {
12+
public static final CustomPacketPayload.Type<RemoveConstructS2CPacket> TYPE =
13+
new CustomPacketPayload.Type<>(Constant.id("remove_construct"));
14+
15+
public static final StreamCodec<FriendlyByteBuf, RemoveConstructS2CPacket> CODEC =
16+
StreamCodec.of(
17+
RemoveConstructS2CPacket::writeToBuf,
18+
RemoveConstructS2CPacket::readFromBuf
19+
);
20+
21+
public static RemoveConstructS2CPacket readFromBuf(FriendlyByteBuf buf) {
22+
return new RemoveConstructS2CPacket(buf.readUUID());
23+
}
24+
25+
public static void writeToBuf(FriendlyByteBuf buf, RemoveConstructS2CPacket packet) {
26+
buf.writeUUID(packet.constructId());
27+
}
28+
29+
@Override
30+
public @NotNull Type<? extends CustomPacketPayload> type() {
31+
return TYPE;
32+
}
33+
}

0 commit comments

Comments
 (0)