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;
|
package com.simibubi.create.content.contraptions.components.structureMovement;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.IdentityHashMap;
|
import java.util.IdentityHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -11,11 +10,11 @@ import java.util.UUID;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.simibubi.create.foundation.utility.ContraptionData;
|
||||||
|
|
||||||
import org.apache.commons.lang3.mutable.MutableInt;
|
import org.apache.commons.lang3.mutable.MutableInt;
|
||||||
import org.apache.commons.lang3.tuple.MutablePair;
|
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.mojang.blaze3d.vertex.PoseStack;
|
||||||
import com.simibubi.create.AllItems;
|
import com.simibubi.create.AllItems;
|
||||||
import com.simibubi.create.AllMovementBehaviours;
|
import com.simibubi.create.AllMovementBehaviours;
|
||||||
|
@ -44,7 +43,6 @@ import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.NbtIo;
|
|
||||||
import net.minecraft.nbt.Tag;
|
import net.minecraft.nbt.Tag;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import net.minecraft.network.chat.Component;
|
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
|
* staleTicks are a band-aid to prevent a frame or two of missing blocks between
|
||||||
* contraption discard and off-thread block placement on disassembly
|
* contraption discard and off-thread block placement on disassembly
|
||||||
*
|
*
|
||||||
* FIXME this timeout should be longer but then also cancelled early based on a
|
* FIXME this timeout should be longer but then also cancelled early based on a
|
||||||
* chunk rebuild listener
|
* chunk rebuild listener
|
||||||
*/
|
*/
|
||||||
|
@ -116,7 +114,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
||||||
return;
|
return;
|
||||||
contraption.onEntityCreated(this);
|
contraption.onEntityCreated(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void move(MoverType pType, Vec3 pPos) {
|
public void move(MoverType pType, Vec3 pPos) {
|
||||||
if (pType == MoverType.SHULKER)
|
if (pType == MoverType.SHULKER)
|
||||||
|
@ -140,7 +138,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
||||||
public boolean collisionEnabled() {
|
public boolean collisionEnabled() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerColliding(Entity collidingEntity) {
|
public void registerColliding(Entity collidingEntity) {
|
||||||
collidingEntities.put(collidingEntity, new MutableInt());
|
collidingEntities.put(collidingEntity, new MutableInt());
|
||||||
}
|
}
|
||||||
|
@ -319,7 +317,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
||||||
public Vec3 toGlobalVector(Vec3 localVec, float partialTicks) {
|
public Vec3 toGlobalVector(Vec3 localVec, float partialTicks) {
|
||||||
return toGlobalVector(localVec, partialTicks, false);
|
return toGlobalVector(localVec, partialTicks, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vec3 toGlobalVector(Vec3 localVec, float partialTicks, boolean prevAnchor) {
|
public Vec3 toGlobalVector(Vec3 localVec, float partialTicks, boolean prevAnchor) {
|
||||||
Vec3 anchor = prevAnchor ? getPrevAnchorVec() : getAnchorVec();
|
Vec3 anchor = prevAnchor ? getPrevAnchorVec() : getAnchorVec();
|
||||||
Vec3 rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO);
|
Vec3 rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO);
|
||||||
|
@ -329,7 +327,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
||||||
.add(anchor);
|
.add(anchor);
|
||||||
return localVec;
|
return localVec;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vec3 toLocalVector(Vec3 localVec, float partialTicks) {
|
public Vec3 toLocalVector(Vec3 localVec, float partialTicks) {
|
||||||
return toLocalVector(localVec, partialTicks, false);
|
return toLocalVector(localVec, partialTicks, false);
|
||||||
}
|
}
|
||||||
|
@ -546,7 +544,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
||||||
public Vec3 getAnchorVec() {
|
public Vec3 getAnchorVec() {
|
||||||
return position();
|
return position();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vec3 getPrevAnchorVec() {
|
public Vec3 getPrevAnchorVec() {
|
||||||
return getPrevPositionVec();
|
return getPrevPositionVec();
|
||||||
}
|
}
|
||||||
|
@ -598,22 +596,10 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
||||||
CompoundTag compound = new CompoundTag();
|
CompoundTag compound = new CompoundTag();
|
||||||
writeAdditional(compound, true);
|
writeAdditional(compound, true);
|
||||||
|
|
||||||
try {
|
if (ContraptionData.isTooLargeForSync(compound)) {
|
||||||
ByteArrayDataOutput dataOutput = ByteStreams.newDataOutput();
|
String info = getContraption().getType().id + " @" + position() + " (" + getStringUUID() + ")";
|
||||||
NbtIo.write(compound, dataOutput);
|
Create.LOGGER.warn("Could not send Contraption Spawn Data (Packet too big): " + info);
|
||||||
byte[] byteArray = dataOutput.toByteArray();
|
compound = null;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.writeNbt(compound);
|
buffer.writeNbt(compound);
|
||||||
|
@ -633,7 +619,10 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readSpawnData(FriendlyByteBuf additionalData) {
|
public void readSpawnData(FriendlyByteBuf additionalData) {
|
||||||
readAdditional(additionalData.readNbt(), true);
|
CompoundTag nbt = additionalData.readAnySizeNbt();
|
||||||
|
if (nbt != null) {
|
||||||
|
readAdditional(nbt, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -823,7 +812,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
||||||
public Vec3 getContactPointMotion(Vec3 globalContactPoint) {
|
public Vec3 getContactPointMotion(Vec3 globalContactPoint) {
|
||||||
if (prevPosInvalid)
|
if (prevPosInvalid)
|
||||||
return Vec3.ZERO;
|
return Vec3.ZERO;
|
||||||
|
|
||||||
Vec3 contactPoint = toGlobalVector(toLocalVector(globalContactPoint, 0, true), 1, true);
|
Vec3 contactPoint = toGlobalVector(toLocalVector(globalContactPoint, 0, true), 1, true);
|
||||||
Vec3 contraptionLocalMovement = contactPoint.subtract(globalContactPoint);
|
Vec3 contraptionLocalMovement = contactPoint.subtract(globalContactPoint);
|
||||||
Vec3 contraptionAnchorMovement = position().subtract(getPrevPositionVec());
|
Vec3 contraptionAnchorMovement = position().subtract(getPrevPositionVec());
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
package com.simibubi.create.content.contraptions.components.structureMovement.mounted;
|
package com.simibubi.create.content.contraptions.components.structureMovement.mounted;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
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 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.AllItems;
|
||||||
import com.simibubi.create.AllMovementBehaviours;
|
import com.simibubi.create.AllMovementBehaviours;
|
||||||
import com.simibubi.create.content.contraptions.components.actors.PortableStorageInterfaceMovement;
|
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.DefaultDispenseItemBehavior;
|
||||||
import net.minecraft.core.dispenser.DispenseItemBehavior;
|
import net.minecraft.core.dispenser.DispenseItemBehavior;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.NbtIo;
|
|
||||||
import net.minecraft.tags.BlockTags;
|
import net.minecraft.tags.BlockTags;
|
||||||
import net.minecraft.world.InteractionResult;
|
import net.minecraft.world.InteractionResult;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
|
@ -251,18 +251,10 @@ public class MinecartContraptionItem extends Item {
|
||||||
|
|
||||||
ItemStack generatedStack = create(type, oce).setHoverName(entity.getCustomName());
|
ItemStack generatedStack = create(type, oce).setHoverName(entity.getCustomName());
|
||||||
|
|
||||||
try {
|
if (ContraptionData.isTooLargeForPickup(generatedStack.serializeNBT())) {
|
||||||
ByteArrayDataOutput dataOutput = ByteStreams.newDataOutput();
|
MutableComponent message = Lang.translateDirect("contraption.minecart_contraption_too_big")
|
||||||
NbtIo.write(generatedStack.serializeNBT(), dataOutput);
|
.withStyle(ChatFormatting.RED);
|
||||||
int estimatedPacketSize = dataOutput.toByteArray().length;
|
player.displayClientMessage(message, true);
|
||||||
if (estimatedPacketSize > 2_000_000) {
|
|
||||||
player.displayClientMessage(Lang.translateDirect("contraption.minecart_contraption_too_big")
|
|
||||||
.withStyle(ChatFormatting.RED), true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,7 @@ public abstract class ContraptionRenderingWorld<C extends ContraptionRenderInfo>
|
||||||
.map(Reference::get)
|
.map(Reference::get)
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.map(AbstractContraptionEntity::getContraption)
|
.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);
|
.forEach(this::getRenderInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.simibubi.create.foundation.config;
|
package com.simibubi.create.foundation.config;
|
||||||
|
|
||||||
import com.simibubi.create.foundation.config.ui.ConfigAnnotations;
|
import com.simibubi.create.foundation.config.ui.ConfigAnnotations;
|
||||||
|
import com.simibubi.create.foundation.utility.ContraptionData;
|
||||||
|
|
||||||
public class CKinetics extends ConfigBase {
|
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 ConfigGroup contraptions = group(1, "contraptions", "Moving Contraptions");
|
||||||
public final ConfigInt maxBlocksMoved = i(2048, 1, "maxBlocksMoved", Comments.maxBlocksMoved);
|
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 maxChassisRange = i(16, 1, "maxChassisRange", Comments.maxChassisRange);
|
||||||
public final ConfigInt maxPistonPoles = i(64, 1, "maxPistonPoles", Comments.maxPistonPoles);
|
public final ConfigInt maxPistonPoles = i(64, 1, "maxPistonPoles", Comments.maxPistonPoles);
|
||||||
public final ConfigInt maxRopeLength = i(256, 1, "maxRopeLength", Comments.maxRopeLength);
|
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.";
|
"multiplier used for calculating exhaustion from speed when a crank is turned.";
|
||||||
static String maxBlocksMoved =
|
static String maxBlocksMoved =
|
||||||
"Maximum amount of blocks in a structure movable by Pistons, Bearings or other means.";
|
"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 maxChassisRange = "Maximum value of a chassis attachment range.";
|
||||||
static String maxPistonPoles = "Maximum amount of extension poles behind a Mechanical Piston.";
|
static String maxPistonPoles = "Maximum amount of extension poles behind a Mechanical Piston.";
|
||||||
static String maxRopeLength = "Max length of rope available off a Rope Pulley.";
|
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 stats = "Configure speed/capacity levels for requirements and indicators.";
|
||||||
static String rpm = "[in Revolutions per Minute]";
|
static String rpm = "[in Revolutions per Minute]";
|
||||||
static String su = "[in Stress Units]";
|
static String su = "[in Stress Units]";
|
||||||
|
static String bytes = "[in Bytes]";
|
||||||
static String mediumSpeed = "Minimum speed of rotation to be considered 'medium'";
|
static String mediumSpeed = "Minimum speed of rotation to be considered 'medium'";
|
||||||
static String fastSpeed = "Minimum speed of rotation to be considered 'fast'";
|
static String fastSpeed = "Minimum speed of rotation to be considered 'fast'";
|
||||||
static String mediumStressImpact = "Minimum stress impact to be considered 'medium'";
|
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.DispenserBlockAccessor",
|
||||||
"accessor.FallingBlockEntityAccessor",
|
"accessor.FallingBlockEntityAccessor",
|
||||||
"accessor.LivingEntityAccessor",
|
"accessor.LivingEntityAccessor",
|
||||||
|
"accessor.NbtAccounterAccessor",
|
||||||
"accessor.ServerLevelAccessor"
|
"accessor.ServerLevelAccessor"
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
|
|
Loading…
Reference in a new issue