Multiblock Madness

- Fixed moving single-tile tanks and vaults leading to corrupt nbt #6915 #6925 #6943 #6979
- Display links now check for click events in transferred components #6942
- Fixed negative values displayed on kinetic generator goggle overlay
This commit is contained in:
simibubi 2024-10-09 01:17:27 +02:00
parent f51c99e715
commit 2828c88d80
11 changed files with 97 additions and 35 deletions

View file

@ -1139,6 +1139,7 @@ public abstract class Contraption {
if (blockEntity instanceof IMultiBlockEntityContainer) {
if (tag.contains("LastKnownPos") || capturedMultiblocks.isEmpty()) {
tag.put("LastKnownPos", NbtUtils.writeBlockPos(BlockPos.ZERO.below(Integer.MAX_VALUE - 1)));
tag.remove("Controller");
}
}
@ -1195,6 +1196,9 @@ public abstract class Contraption {
// swap nbt data to the new controller position
StructureBlockInfo prevControllerInfo = blocks.get(controllerPos);
StructureBlockInfo newControllerInfo = blocks.get(otherPos);
if (prevControllerInfo == null || newControllerInfo == null)
return;
blocks.put(otherPos, new StructureBlockInfo(newControllerInfo.pos, newControllerInfo.state, prevControllerInfo.nbt));
blocks.put(controllerPos, new StructureBlockInfo(prevControllerInfo.pos, prevControllerInfo.state, newControllerInfo.nbt));
});

View file

@ -73,9 +73,8 @@ public abstract class GeneratingKineticBlockEntity extends KineticBlockEntity {
float speed = getTheoreticalSpeed();
if (speed != getGeneratedSpeed() && speed != 0)
stressBase *= getGeneratedSpeed() / speed;
speed = Math.abs(speed);
float stressTotal = stressBase * speed;
float stressTotal = Math.abs(stressBase * speed);
Lang.number(stressTotal)
.translate("generic.unit.stress")

View file

@ -13,6 +13,7 @@ import com.simibubi.create.content.trains.display.FlapDisplayBlockEntity;
import com.simibubi.create.content.trains.display.FlapDisplayLayout;
import com.simibubi.create.foundation.gui.ModularGuiLineBuilder;
import com.simibubi.create.foundation.utility.Components;
import com.simibubi.create.foundation.utility.NBTProcessors;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
@ -38,6 +39,12 @@ public abstract class DisplaySource extends DisplayBehaviour {
List<MutableComponent> text = provideText(context, stats);
if (text.isEmpty())
text = EMPTY;
if (activeTarget.requiresComponentSanitization())
for (MutableComponent component : text)
if (NBTProcessors.textComponentHasClickEvent(component))
return; // Naughty
activeTarget.acceptText(line, text, context);
}

View file

@ -68,4 +68,8 @@ public abstract class DisplayTarget extends DisplayBehaviour {
return false;
}
public boolean requiresComponentSanitization() {
return false;
}
}

View file

@ -81,4 +81,9 @@ public class LecternDisplayTarget extends DisplayTarget {
return written;
}
@Override
public boolean requiresComponentSanitization() {
return true;
}
}

View file

@ -36,4 +36,9 @@ public class SignDisplayTarget extends DisplayTarget {
return new DisplayTargetStats(4, 15, this);
}
@Override
public boolean requiresComponentSanitization() {
return true;
}
}

View file

@ -10,6 +10,8 @@ import java.util.function.Predicate;
import java.util.stream.Stream;
import com.simibubi.create.Create;
import com.simibubi.create.foundation.blockEntity.IMultiBlockEntityContainer;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.utility.BBHelper;
import com.simibubi.create.foundation.utility.NBTProcessors;
import com.simibubi.create.foundation.utility.worldWrappers.WrappedWorld;
@ -251,4 +253,24 @@ public class SchematicWorld extends WrappedWorld implements ServerLevelAccessor
throw new IllegalStateException("Cannot use IServerWorld#getWorld in a client environment");
}
public void fixControllerBlockEntities() {
for (BlockEntity blockEntity : blockEntities.values()) {
if (!(blockEntity instanceof IMultiBlockEntityContainer multiBlockEntity))
continue;
BlockPos lastKnown = multiBlockEntity.getLastKnownPos();
BlockPos current = blockEntity.getBlockPos();
if (lastKnown == null || current == null)
continue;
if (multiBlockEntity.isController())
continue;
if (!lastKnown.equals(current)) {
BlockPos newControllerPos = multiBlockEntity.getController()
.offset(current.subtract(lastKnown));
if (multiBlockEntity instanceof SmartBlockEntity sbe)
sbe.markVirtual();
multiBlockEntity.setController(newControllerPos);
}
}
}
}

View file

@ -168,6 +168,7 @@ public class SchematicHandler {
schematic.placeInWorld(w, pos, pos, placementSettings, w.getRandom(), Block.UPDATE_CLIENTS);
for (BlockEntity blockEntity : w.getBlockEntities())
blockEntity.setLevel(w);
w.fixControllerBlockEntities();
} catch (Exception e) {
Minecraft.getInstance().player.displayClientMessage(Lang.translate("schematic.error")
.component(), false);
@ -182,6 +183,7 @@ public class SchematicHandler {
placementSettings.getMirror());
for (BlockEntity be : wMirroredFB.getRenderedBlockEntities())
transform.apply(be);
wMirroredFB.fixControllerBlockEntities();
placementSettings.setMirror(Mirror.LEFT_RIGHT);
pos = BlockPos.ZERO.south(size.getZ() - 1);
@ -190,6 +192,7 @@ public class SchematicHandler {
placementSettings.getMirror());
for (BlockEntity be : wMirroredLR.getRenderedBlockEntities())
transform.apply(be);
wMirroredLR.fixControllerBlockEntities();
renderers.get(0)
.display(w);

View file

@ -14,7 +14,6 @@ import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.content.kinetics.belt.BeltBlock;
import com.simibubi.create.content.kinetics.belt.BeltBlockEntity;
import com.simibubi.create.content.schematics.SchematicWorld;
import com.simibubi.create.foundation.blockEntity.IMultiBlockEntityContainer;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.mixin.accessor.ParticleEngineAccessor;
import com.simibubi.create.foundation.ponder.element.WorldSectionElement;
@ -252,38 +251,22 @@ public class PonderWorld extends SchematicWorld {
smartBlockEntity.markVirtual();
}
@Override
public void fixControllerBlockEntities() {
super.fixControllerBlockEntities();
for (BlockEntity blockEntity : blockEntities.values()) {
if (blockEntity instanceof BeltBlockEntity) {
BeltBlockEntity beltBlockEntity = (BeltBlockEntity) blockEntity;
if (!beltBlockEntity.isController())
if (!(blockEntity instanceof BeltBlockEntity beltBlockEntity))
continue;
if (!beltBlockEntity.isController())
continue;
BlockPos controllerPos = blockEntity.getBlockPos();
for (BlockPos blockPos : BeltBlock.getBeltChain(this, controllerPos)) {
BlockEntity blockEntity2 = getBlockEntity(blockPos);
if (!(blockEntity2 instanceof BeltBlockEntity))
continue;
BlockPos controllerPos = blockEntity.getBlockPos();
for (BlockPos blockPos : BeltBlock.getBeltChain(this, controllerPos)) {
BlockEntity blockEntity2 = getBlockEntity(blockPos);
if (!(blockEntity2 instanceof BeltBlockEntity))
continue;
BeltBlockEntity belt2 = (BeltBlockEntity) blockEntity2;
belt2.setController(controllerPos);
}
BeltBlockEntity belt2 = (BeltBlockEntity) blockEntity2;
belt2.setController(controllerPos);
}
if (blockEntity instanceof IMultiBlockEntityContainer) {
IMultiBlockEntityContainer multiBlockEntity = (IMultiBlockEntityContainer) blockEntity;
BlockPos lastKnown = multiBlockEntity.getLastKnownPos();
BlockPos current = blockEntity.getBlockPos();
if (lastKnown == null || current == null)
continue;
if (multiBlockEntity.isController())
continue;
if (!lastKnown.equals(current)) {
BlockPos newControllerPos = multiBlockEntity.getController()
.offset(current.subtract(lastKnown));
multiBlockEntity.setController(newControllerPos);
}
}
}
}

View file

@ -12,6 +12,7 @@ import com.simibubi.create.content.kinetics.base.KineticBlockEntity;
import com.simibubi.create.content.processing.burner.BlazeBurnerBlock;
import com.simibubi.create.content.processing.burner.BlazeBurnerBlock.HeatLevel;
import com.simibubi.create.foundation.blockEntity.IMergeableBE;
import com.simibubi.create.foundation.blockEntity.IMultiBlockEntityContainer;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
@ -19,6 +20,7 @@ import net.minecraft.core.Registry;
import net.minecraft.core.SectionPos;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
@ -316,8 +318,11 @@ public class BlockHelper {
data.putInt("x", target.getX());
data.putInt("y", target.getY());
data.putInt("z", target.getZ());
if (blockEntity instanceof KineticBlockEntity)
((KineticBlockEntity) blockEntity).warnOfMovement();
if (blockEntity instanceof KineticBlockEntity kbe)
kbe.warnOfMovement();
if (blockEntity instanceof IMultiBlockEntityContainer imbe)
if (!imbe.isController())
data.put("Controller", NbtUtils.writeBlockPos(imbe.getController()));
blockEntity.load(data);
}
}

View file

@ -2,6 +2,7 @@ package com.simibubi.create.foundation.utility;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.function.UnaryOperator;
@ -57,6 +58,24 @@ public final class NBTProcessors {
});
addProcessor(AllBlockEntityTypes.CREATIVE_CRATE.get(), itemProcessor("Filter"));
addProcessor(AllBlockEntityTypes.PLACARD.get(), itemProcessor("Item"));
addProcessor(AllBlockEntityTypes.CLIPBOARD.get(), data -> {
if (!data.contains("Item", Tag.TAG_COMPOUND))
return data;
CompoundTag book = data.getCompound("Item");
if (!book.contains("tag", Tag.TAG_COMPOUND))
return data;
CompoundTag itemData = book.getCompound("tag");
for (List<String> entries : NBTHelper.readCompoundList(itemData.getList("Pages", Tag.TAG_COMPOUND),
pageTag -> NBTHelper.readCompoundList(pageTag.getList("Entries", Tag.TAG_COMPOUND),
tag -> tag.getString("Text")))) {
for (String entry : entries)
if (textComponentHasClickEvent(entry))
return null;
}
return data;
});
}
// Triggered by block tag, not BE type
@ -120,7 +139,13 @@ public final class NBTProcessors {
}
public static boolean textComponentHasClickEvent(String json) {
Component component = Component.Serializer.fromJson(json.isEmpty() ? "\"\"" : json);
return textComponentHasClickEvent(Component.Serializer.fromJson(json.isEmpty() ? "\"\"" : json));
}
public static boolean textComponentHasClickEvent(Component component) {
for (Component sibling : component.getSiblings())
if (textComponentHasClickEvent(sibling))
return true;
return component != null && component.getStyle() != null && component.getStyle()
.getClickEvent() != null;
}
@ -144,7 +169,7 @@ public final class NBTProcessors {
return signProcessor.apply(compound);
if (blockEntity.onlyOpCanSetNbt())
return null;
return withUnsafeNBTDiscarded(compound);
return compound;
}
}