mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-11-18 07:53:07 +01:00
Improve handling of contraption data for syncing and minecart pickup
- filter out null contraptions in ContraptionRenderingWorld - fix and unify contraption data size estimates - add config for max contraption size for syncing - Minecart pickup max is increased if XL Packets is loaded
This commit is contained in:
parent
8d89080bc0
commit
41697aca7f
7 changed files with 102 additions and 44 deletions
|
@ -1,6 +1,5 @@
|
|||
package com.simibubi.create.content.contraptions.components.structureMovement;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
|
@ -11,11 +10,11 @@ import java.util.UUID;
|
|||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.simibubi.create.foundation.utility.ContraptionData;
|
||||
|
||||
import org.apache.commons.lang3.mutable.MutableInt;
|
||||
import org.apache.commons.lang3.tuple.MutablePair;
|
||||
|
||||
import com.google.common.io.ByteArrayDataOutput;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.AllMovementBehaviours;
|
||||
|
@ -44,7 +43,6 @@ import net.minecraft.client.Minecraft;
|
|||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtIo;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.chat.Component;
|
||||
|
@ -96,7 +94,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
|||
/*
|
||||
* staleTicks are a band-aid to prevent a frame or two of missing blocks between
|
||||
* contraption discard and off-thread block placement on disassembly
|
||||
*
|
||||
*
|
||||
* FIXME this timeout should be longer but then also cancelled early based on a
|
||||
* chunk rebuild listener
|
||||
*/
|
||||
|
@ -116,7 +114,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
|||
return;
|
||||
contraption.onEntityCreated(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void move(MoverType pType, Vec3 pPos) {
|
||||
if (pType == MoverType.SHULKER)
|
||||
|
@ -140,7 +138,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
|||
public boolean collisionEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public void registerColliding(Entity collidingEntity) {
|
||||
collidingEntities.put(collidingEntity, new MutableInt());
|
||||
}
|
||||
|
@ -319,7 +317,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
|||
public Vec3 toGlobalVector(Vec3 localVec, float partialTicks) {
|
||||
return toGlobalVector(localVec, partialTicks, false);
|
||||
}
|
||||
|
||||
|
||||
public Vec3 toGlobalVector(Vec3 localVec, float partialTicks, boolean prevAnchor) {
|
||||
Vec3 anchor = prevAnchor ? getPrevAnchorVec() : getAnchorVec();
|
||||
Vec3 rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO);
|
||||
|
@ -329,7 +327,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
|||
.add(anchor);
|
||||
return localVec;
|
||||
}
|
||||
|
||||
|
||||
public Vec3 toLocalVector(Vec3 localVec, float partialTicks) {
|
||||
return toLocalVector(localVec, partialTicks, false);
|
||||
}
|
||||
|
@ -546,7 +544,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
|||
public Vec3 getAnchorVec() {
|
||||
return position();
|
||||
}
|
||||
|
||||
|
||||
public Vec3 getPrevAnchorVec() {
|
||||
return getPrevPositionVec();
|
||||
}
|
||||
|
@ -598,22 +596,10 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
|||
CompoundTag compound = new CompoundTag();
|
||||
writeAdditional(compound, true);
|
||||
|
||||
try {
|
||||
ByteArrayDataOutput dataOutput = ByteStreams.newDataOutput();
|
||||
NbtIo.write(compound, dataOutput);
|
||||
byte[] byteArray = dataOutput.toByteArray();
|
||||
int estimatedPacketSize = byteArray.length;
|
||||
if (estimatedPacketSize > 2_000_000) {
|
||||
Create.LOGGER.warn("Could not send Contraption Spawn Data (Packet too big): "
|
||||
+ getContraption().getType().id + " @" + position() + " (" + getUUID().toString() + ")");
|
||||
buffer.writeNbt(new CompoundTag());
|
||||
return;
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
buffer.writeNbt(new CompoundTag());
|
||||
return;
|
||||
if (ContraptionData.isTooLargeForSync(compound)) {
|
||||
String info = getContraption().getType().id + " @" + position() + " (" + getStringUUID() + ")";
|
||||
Create.LOGGER.warn("Could not send Contraption Spawn Data (Packet too big): " + info);
|
||||
compound = null;
|
||||
}
|
||||
|
||||
buffer.writeNbt(compound);
|
||||
|
@ -633,7 +619,10 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
|||
|
||||
@Override
|
||||
public void readSpawnData(FriendlyByteBuf additionalData) {
|
||||
readAdditional(additionalData.readNbt(), true);
|
||||
CompoundTag nbt = additionalData.readAnySizeNbt();
|
||||
if (nbt != null) {
|
||||
readAdditional(nbt, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -823,7 +812,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
|||
public Vec3 getContactPointMotion(Vec3 globalContactPoint) {
|
||||
if (prevPosInvalid)
|
||||
return Vec3.ZERO;
|
||||
|
||||
|
||||
Vec3 contactPoint = toGlobalVector(toLocalVector(globalContactPoint, 0, true), 1, true);
|
||||
Vec3 contraptionLocalMovement = contactPoint.subtract(globalContactPoint);
|
||||
Vec3 contraptionAnchorMovement = position().subtract(getPrevPositionVec());
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
package com.simibubi.create.content.contraptions.components.structureMovement.mounted;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.simibubi.create.foundation.utility.ContraptionData;
|
||||
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
|
||||
import org.apache.commons.lang3.tuple.MutablePair;
|
||||
|
||||
import com.google.common.io.ByteArrayDataOutput;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.AllMovementBehaviours;
|
||||
import com.simibubi.create.content.contraptions.components.actors.PortableStorageInterfaceMovement;
|
||||
|
@ -31,7 +32,6 @@ import net.minecraft.core.NonNullList;
|
|||
import net.minecraft.core.dispenser.DefaultDispenseItemBehavior;
|
||||
import net.minecraft.core.dispenser.DispenseItemBehavior;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtIo;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
|
@ -251,18 +251,10 @@ public class MinecartContraptionItem extends Item {
|
|||
|
||||
ItemStack generatedStack = create(type, oce).setHoverName(entity.getCustomName());
|
||||
|
||||
try {
|
||||
ByteArrayDataOutput dataOutput = ByteStreams.newDataOutput();
|
||||
NbtIo.write(generatedStack.serializeNBT(), dataOutput);
|
||||
int estimatedPacketSize = dataOutput.toByteArray().length;
|
||||
if (estimatedPacketSize > 2_000_000) {
|
||||
player.displayClientMessage(Lang.translateDirect("contraption.minecart_contraption_too_big")
|
||||
.withStyle(ChatFormatting.RED), true);
|
||||
return;
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
if (ContraptionData.isTooLargeForPickup(generatedStack.serializeNBT())) {
|
||||
MutableComponent message = Lang.translateDirect("contraption.minecart_contraption_too_big")
|
||||
.withStyle(ChatFormatting.RED);
|
||||
player.displayClientMessage(message, true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ public abstract class ContraptionRenderingWorld<C extends ContraptionRenderInfo>
|
|||
.map(Reference::get)
|
||||
.filter(Objects::nonNull)
|
||||
.map(AbstractContraptionEntity::getContraption)
|
||||
.filter(Objects::nonNull) // contraptions that are too large will not be synced, and un-synced contraptions will be null
|
||||
.forEach(this::getRenderInfo);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.simibubi.create.foundation.config;
|
||||
|
||||
import com.simibubi.create.foundation.config.ui.ConfigAnnotations;
|
||||
import com.simibubi.create.foundation.utility.ContraptionData;
|
||||
|
||||
public class CKinetics extends ConfigBase {
|
||||
|
||||
|
@ -30,6 +31,8 @@ public class CKinetics extends ConfigBase {
|
|||
|
||||
public final ConfigGroup contraptions = group(1, "contraptions", "Moving Contraptions");
|
||||
public final ConfigInt maxBlocksMoved = i(2048, 1, "maxBlocksMoved", Comments.maxBlocksMoved);
|
||||
public final ConfigInt maxDataSize =
|
||||
i(ContraptionData.DEFAULT_MAX, 0, "maxDataSize", Comments.bytes, Comments.maxDataDisable, Comments.maxDataSize, Comments.maxDataSize2);
|
||||
public final ConfigInt maxChassisRange = i(16, 1, "maxChassisRange", Comments.maxChassisRange);
|
||||
public final ConfigInt maxPistonPoles = i(64, 1, "maxPistonPoles", Comments.maxPistonPoles);
|
||||
public final ConfigInt maxRopeLength = i(256, 1, "maxRopeLength", Comments.maxRopeLength);
|
||||
|
@ -75,6 +78,9 @@ public class CKinetics extends ConfigBase {
|
|||
"multiplier used for calculating exhaustion from speed when a crank is turned.";
|
||||
static String maxBlocksMoved =
|
||||
"Maximum amount of blocks in a structure movable by Pistons, Bearings or other means.";
|
||||
static String maxDataSize = "Maximum amount of data a contraption can have before it can't be synced with players.";
|
||||
static String maxDataSize2 = "Un-synced contraptions will not be visible and will not have collision.";
|
||||
static String maxDataDisable = "[0 to disable this limit]";
|
||||
static String maxChassisRange = "Maximum value of a chassis attachment range.";
|
||||
static String maxPistonPoles = "Maximum amount of extension poles behind a Mechanical Piston.";
|
||||
static String maxRopeLength = "Max length of rope available off a Rope Pulley.";
|
||||
|
@ -86,6 +92,7 @@ public class CKinetics extends ConfigBase {
|
|||
static String stats = "Configure speed/capacity levels for requirements and indicators.";
|
||||
static String rpm = "[in Revolutions per Minute]";
|
||||
static String su = "[in Stress Units]";
|
||||
static String bytes = "[in Bytes]";
|
||||
static String mediumSpeed = "Minimum speed of rotation to be considered 'medium'";
|
||||
static String fastSpeed = "Minimum speed of rotation to be considered 'fast'";
|
||||
static String mediumStressImpact = "Minimum stress impact to be considered 'medium'";
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package com.simibubi.create.foundation.mixin.accessor;
|
||||
|
||||
import net.minecraft.nbt.NbtAccounter;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(NbtAccounter.class)
|
||||
public interface NbtAccounterAccessor {
|
||||
@Accessor("usage")
|
||||
long create$getUsage();
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.simibubi.create.foundation.utility;
|
||||
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.mixin.accessor.NbtAccounterAccessor;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtAccounter;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket;
|
||||
import net.minecraftforge.fml.ModList;
|
||||
|
||||
public class ContraptionData {
|
||||
/**
|
||||
* A sane, default maximum for contraption data size.
|
||||
*/
|
||||
public static final int DEFAULT_MAX = 2_000_000;
|
||||
/**
|
||||
* XL Packets expands the NBT packet limit to 2 GB.
|
||||
*/
|
||||
public static final int EXPANDED_MAX = 2_000_000_000;
|
||||
/**
|
||||
* Minecart item sizes are limited by the vanilla slot change packet ({@link ClientboundContainerSetSlotPacket}).
|
||||
* {@link ContraptionData#DEFAULT_MAX} is used as the default.
|
||||
* XL Packets expands the size limit to ~2 GB. If the mod is loaded, we take advantage of it and use the higher limit.
|
||||
*/
|
||||
public static final int PICKUP_MAX = ModList.get().isLoaded("xlpackets") ? EXPANDED_MAX : DEFAULT_MAX;
|
||||
|
||||
/**
|
||||
* @return true if the given NBT is too large for a contraption to be synced to clients.
|
||||
*/
|
||||
public static boolean isTooLargeForSync(CompoundTag data) {
|
||||
int max = AllConfigs.SERVER.kinetics.maxDataSize.get();
|
||||
return max != 0 && packetSize(data) > max;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the given NBT is too large for a contraption to be picked up with a wrench.
|
||||
*/
|
||||
public static boolean isTooLargeForPickup(CompoundTag data) {
|
||||
return packetSize(data) > PICKUP_MAX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the size of the given NBT when put through a packet, in bytes.
|
||||
*/
|
||||
public static long packetSize(CompoundTag data) {
|
||||
FriendlyByteBuf test = new FriendlyByteBuf(Unpooled.buffer());
|
||||
test.writeNbt(data);
|
||||
NbtAccounter sizeTracker = new NbtAccounter(Long.MAX_VALUE);
|
||||
test.readNbt(sizeTracker);
|
||||
long size = ((NbtAccounterAccessor) sizeTracker).create$getUsage();
|
||||
test.release();
|
||||
return size;
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@
|
|||
"accessor.DispenserBlockAccessor",
|
||||
"accessor.FallingBlockEntityAccessor",
|
||||
"accessor.LivingEntityAccessor",
|
||||
"accessor.NbtAccounterAccessor",
|
||||
"accessor.ServerLevelAccessor"
|
||||
],
|
||||
"client": [
|
||||
|
|
Loading…
Reference in a new issue