Contraption bugs and balance
- Added a config option to disable the stress/torque mechanic entirely - Water wheel speed is halved and now configurable - Water wheels now validate their current speed from time to time - Fixed windmill bearings counting their sail blocks incorrectly - Fixed windmill bearings not assembling when placed in a powered block position - Fixed Contraption controllers not removing their entity reference on the client when disassembled - Bearings no longer start rotating when no block was found - Contraptions no longer move unbreakable blocks - Pistons no longer assemble the whole line of blocks when retracting - Non-sticky pistons no longer pull blocks back when assembled - Pulley no longer assembles when the structure by itself is immovable - Fixed pistons applying reversed motion in some orientations - Fixed piston contraptions not including the poles into its render bounds - Fixed Contraptions not culling backfaces when rendered - Translucent blocks now get moved to the back of the render order in contraptions, fixes hidden block faces between translucent and non-translucent blocks - Fixed Contraptions being movable through water, fans and other means of applying motion to entities. - Belt segments can no longer be rotated by a wrench - Hand cranks are now gated behind brass and sheet production
This commit is contained in:
parent
9308d3ca2b
commit
81a2e314bc
29 changed files with 191 additions and 130 deletions
|
@ -2,9 +2,11 @@ package com.simibubi.create.config;
|
|||
|
||||
public class CKinetics extends ConfigBase {
|
||||
|
||||
public ConfigBool disableStress = b(false, "disableStress", Comments.disableStress);
|
||||
public ConfigInt maxBeltLength = i(20, 5, "maxBeltLength", Comments.maxBeltLength);
|
||||
public ConfigInt crushingDamage = i(4, 0, "crushingDamage", Comments.crushingDamage);
|
||||
public ConfigInt maxMotorSpeed = i(256, 64, "maxMotorSpeed", Comments.rpm, Comments.maxMotorSpeed);
|
||||
public ConfigInt waterWheelSpeed = i(5, 1, "waterWheelSpeed", Comments.rpm, Comments.waterWheelSpeed);
|
||||
public ConfigInt maxRotationSpeed = i(256, 64, "maxRotationSpeed", Comments.rpm, Comments.maxRotationSpeed);
|
||||
public ConfigEnum<DeployerAggroSetting> ignoreDeployerAttacks =
|
||||
e(DeployerAggroSetting.CREEPERS, "ignoreDeployerAttacks", Comments.ignoreDeployerAttacks);
|
||||
|
@ -67,6 +69,8 @@ public class CKinetics extends ConfigBase {
|
|||
static String highCapacity = "Minimum added Capacity by sources to be considered 'high'";
|
||||
static String stress = "Fine tune the kinetic stats of individual components";
|
||||
static String ignoreDeployerAttacks = "Select what mobs should ignore Deployers when attacked by them.";
|
||||
static String waterWheelSpeed = "Rotation speed gained by a water wheel for each side with running water. (halved if not against blades)";
|
||||
static String disableStress = "Disable the Stress mechanic altogether.";
|
||||
}
|
||||
|
||||
public static enum DeployerAggroSetting {
|
||||
|
|
|
@ -84,16 +84,17 @@ public class ItemDescription {
|
|||
}
|
||||
|
||||
public ItemDescription withKineticStats(Block block) {
|
||||
|
||||
|
||||
boolean isEngine = block instanceof EngineBlock;
|
||||
CKinetics config = AllConfigs.SERVER.kinetics;
|
||||
SpeedLevel minimumRequiredSpeedLevel = isEngine ? SpeedLevel.NONE : ((IRotate) block).getMinimumRequiredSpeedLevel();
|
||||
SpeedLevel minimumRequiredSpeedLevel =
|
||||
isEngine ? SpeedLevel.NONE : ((IRotate) block).getMinimumRequiredSpeedLevel();
|
||||
boolean hasSpeedRequirement = minimumRequiredSpeedLevel != SpeedLevel.NONE;
|
||||
ResourceLocation id = ((Block) block).getRegistryName();
|
||||
Map<ResourceLocation, ConfigValue<Double>> impacts = config.stressValues.impacts;
|
||||
Map<ResourceLocation, ConfigValue<Double>> capacities = config.stressValues.capacities;
|
||||
boolean hasStressImpact = impacts.containsKey(id) && impacts.get(id).get() > 0;
|
||||
boolean hasStressCapacity = capacities.containsKey(id);
|
||||
boolean hasStressImpact = impacts.containsKey(id) && impacts.get(id).get() > 0 && StressImpact.isEnabled();
|
||||
boolean hasStressCapacity = capacities.containsKey(id) && StressImpact.isEnabled();
|
||||
boolean hasGlasses =
|
||||
AllItems.GOGGLES.typeOf(Minecraft.getInstance().player.getItemStackFromSlot(EquipmentSlotType.HEAD));
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ public class SuperByteBufferCache {
|
|||
|
||||
public static final Compartment<BlockState> GENERIC_TILE = new Compartment<>();
|
||||
public static final Compartment<AllBlockPartials> PARTIAL = new Compartment<>();
|
||||
|
||||
|
||||
Map<Compartment<?>, Cache<Object, SuperByteBuffer>> cache;
|
||||
|
||||
public SuperByteBufferCache() {
|
||||
|
@ -42,7 +42,7 @@ public class SuperByteBufferCache {
|
|||
public SuperByteBuffer renderBlock(BlockState toRender) {
|
||||
return getGeneric(toRender, () -> standardBlockRender(toRender));
|
||||
}
|
||||
|
||||
|
||||
public SuperByteBuffer renderPartial(AllBlockPartials partial, BlockState referenceState) {
|
||||
return get(PARTIAL, partial, () -> standardModelRender(partial.get(), referenceState));
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ public class SuperByteBufferCache {
|
|||
return get(compartment, toRender, () -> standardBlockRender(toRender));
|
||||
}
|
||||
|
||||
SuperByteBuffer getGeneric(BlockState key, Supplier<SuperByteBuffer> supplier) {
|
||||
SuperByteBuffer getGeneric(BlockState key, Supplier<SuperByteBuffer> supplier) {
|
||||
return get(GENERIC_TILE, key, supplier);
|
||||
}
|
||||
|
||||
|
@ -78,19 +78,19 @@ public class SuperByteBufferCache {
|
|||
BlockRendererDispatcher dispatcher = Minecraft.getInstance().getBlockRendererDispatcher();
|
||||
return standardModelRender(dispatcher.getModelForState(renderedState), renderedState);
|
||||
}
|
||||
|
||||
|
||||
private SuperByteBuffer standardModelRender(IBakedModel model, BlockState referenceState) {
|
||||
BlockRendererDispatcher dispatcher = Minecraft.getInstance().getBlockRendererDispatcher();
|
||||
BlockModelRenderer blockRenderer = dispatcher.getBlockModelRenderer();
|
||||
BufferBuilder builder = new BufferBuilder(0);
|
||||
Random random = new Random();
|
||||
|
||||
|
||||
builder.setTranslation(0, 1, 0);
|
||||
builder.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK);
|
||||
blockRenderer.renderModelFlat(Minecraft.getInstance().world, model, referenceState, BlockPos.ZERO.down(),
|
||||
builder, true, random, 42, EmptyModelData.INSTANCE);
|
||||
builder.finishDrawing();
|
||||
|
||||
|
||||
return new SuperByteBuffer(builder.getByteBuffer());
|
||||
}
|
||||
|
||||
|
|
|
@ -74,8 +74,11 @@ public abstract class DirectionalKineticBlock extends KineticBlock {
|
|||
@Override
|
||||
public BlockState getStateForPlacement(BlockItemUseContext context) {
|
||||
Direction preferred = getPreferredFacing(context);
|
||||
if (preferred == null || context.isPlacerSneaking())
|
||||
return getDefaultState().with(FACING, context.getNearestLookingDirection().getOpposite());
|
||||
if (preferred == null) {
|
||||
Direction nearestLookingDirection = context.getNearestLookingDirection();
|
||||
return getDefaultState().with(FACING,
|
||||
context.isPlacerSneaking() ? nearestLookingDirection : nearestLookingDirection.getOpposite());
|
||||
}
|
||||
return getDefaultState().with(FACING, preferred.getOpposite());
|
||||
}
|
||||
|
||||
|
|
|
@ -63,6 +63,10 @@ public interface IRotate extends IWrenchable {
|
|||
public TextFormatting getColor() {
|
||||
return this == LOW ? TextFormatting.YELLOW : this == MEDIUM ? TextFormatting.GOLD : TextFormatting.RED;
|
||||
}
|
||||
|
||||
public static boolean isEnabled() {
|
||||
return !AllConfigs.SERVER.kinetics.disableStress.get();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasShaftTowards(IWorldReader world, BlockPos pos, BlockState state, Direction face);
|
||||
|
|
|
@ -17,6 +17,7 @@ import com.simibubi.create.foundation.utility.VecHelper;
|
|||
import com.simibubi.create.modules.contraptions.KineticNetwork;
|
||||
import com.simibubi.create.modules.contraptions.RotationPropagator;
|
||||
import com.simibubi.create.modules.contraptions.base.IRotate.SpeedLevel;
|
||||
import com.simibubi.create.modules.contraptions.base.IRotate.StressImpact;
|
||||
import com.simibubi.create.modules.contraptions.particle.RotationIndicatorParticleData;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
|
@ -71,7 +72,7 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
|
|||
public void sync(float maxStress, float currentStress) {
|
||||
this.maxStress = maxStress;
|
||||
this.currentStress = currentStress;
|
||||
boolean overStressed = maxStress < currentStress;
|
||||
boolean overStressed = maxStress < currentStress && StressImpact.isEnabled();
|
||||
if (overStressed != this.overStressed) {
|
||||
float prevSpeed = getSpeed();
|
||||
this.overStressed = overStressed;
|
||||
|
@ -153,7 +154,7 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
|
|||
if (compound.contains("Id")) {
|
||||
maxStress = compound.getFloat("MaxStress");
|
||||
currentStress = compound.getFloat("Stress");
|
||||
overStressed = maxStress < currentStress;
|
||||
overStressed = maxStress < currentStress && StressImpact.isEnabled();
|
||||
setNetworkID(NBTUtil.readUniqueId(compound.getCompound("Id")));
|
||||
newNetworkID = networkID;
|
||||
initNetwork = true;
|
||||
|
|
|
@ -40,6 +40,7 @@ import net.minecraft.nbt.ListNBT;
|
|||
import net.minecraft.nbt.NBTUtil;
|
||||
import net.minecraft.state.properties.BlockStateProperties;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.BlockRenderLayer;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
import net.minecraft.util.Direction.AxisDirection;
|
||||
|
@ -66,10 +67,13 @@ public abstract class Contraption {
|
|||
protected Direction cachedColliderDirection;
|
||||
protected BlockPos anchor;
|
||||
|
||||
List<BlockPos> renderOrder;
|
||||
|
||||
public Contraption() {
|
||||
blocks = new HashMap<>();
|
||||
storage = new HashMap<>();
|
||||
actors = new ArrayList<>();
|
||||
renderOrder = new ArrayList<>();
|
||||
}
|
||||
|
||||
private static List<BlockInfo> getChassisClusterAt(World world, BlockPos pos) {
|
||||
|
@ -432,6 +436,10 @@ public abstract class Contraption {
|
|||
return true;
|
||||
if (blockState.getBlock() instanceof ShulkerBoxBlock)
|
||||
return false;
|
||||
if (blockState.getBlockHardness(world, pos) == -1)
|
||||
return false;
|
||||
if (blockState.getBlock() == Blocks.OBSIDIAN)
|
||||
return false;
|
||||
return blockState.getPushReaction() != PushReaction.BLOCK;
|
||||
}
|
||||
|
||||
|
@ -481,12 +489,21 @@ public abstract class Contraption {
|
|||
|
||||
public void readNBT(World world, CompoundNBT nbt) {
|
||||
blocks.clear();
|
||||
renderOrder.clear();
|
||||
|
||||
nbt.getList("Blocks", 10).forEach(c -> {
|
||||
CompoundNBT comp = (CompoundNBT) c;
|
||||
BlockInfo info = new BlockInfo(NBTUtil.readBlockPos(comp.getCompound("Pos")),
|
||||
NBTUtil.readBlockState(comp.getCompound("Block")),
|
||||
comp.contains("Data") ? comp.getCompound("Data") : null);
|
||||
blocks.put(info.pos, info);
|
||||
if (world.isRemote) {
|
||||
BlockRenderLayer renderLayer = info.state.getBlock().getRenderLayer();
|
||||
if (renderLayer == BlockRenderLayer.TRANSLUCENT)
|
||||
renderOrder.add(info.pos);
|
||||
else
|
||||
renderOrder.add(0, info.pos);
|
||||
}
|
||||
});
|
||||
|
||||
actors.clear();
|
||||
|
@ -626,7 +643,7 @@ public abstract class Contraption {
|
|||
}
|
||||
}
|
||||
|
||||
public AxisAlignedBB getCollisionBoxFront() {
|
||||
public AxisAlignedBB getCollisionBox() {
|
||||
return constructCollisionBox;
|
||||
}
|
||||
|
||||
|
|
|
@ -260,7 +260,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
|||
if (this.isAddedToWorld() && !this.world.isRemote && world instanceof ServerWorld)
|
||||
((ServerWorld) this.world).chunkCheck(this); // Forge - Process chunk registration after moving.
|
||||
if (contraption != null) {
|
||||
AxisAlignedBB cbox = contraption.getCollisionBoxFront();
|
||||
AxisAlignedBB cbox = contraption.getCollisionBox();
|
||||
if (cbox != null)
|
||||
this.setBoundingBox(cbox.offset(x, y, z));
|
||||
}
|
||||
|
@ -401,4 +401,13 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
|||
ce.roll = packet.roll;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMotion(Vec3d motionIn) {
|
||||
// Make sure nothing can move contraptions out of the way
|
||||
}
|
||||
|
||||
public void setContraptionMotion(Vec3d vec) {
|
||||
super.setMotion(vec);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ public class ContraptionEntityRenderer extends EntityRenderer<ContraptionEntity>
|
|||
|
||||
Vec3d rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO);
|
||||
TessellatorHelper.prepareFastRender();
|
||||
GlStateManager.enableCull();
|
||||
TessellatorHelper.begin(DefaultVertexFormats.BLOCK);
|
||||
ContraptionRenderer.render(entity.world, entity.getContraption(), superByteBuffer -> {
|
||||
superByteBuffer.translate(-rotationOffset.x, -rotationOffset.y, -rotationOffset.z);
|
||||
|
@ -87,6 +88,7 @@ public class ContraptionEntityRenderer extends EntityRenderer<ContraptionEntity>
|
|||
}, Tessellator.getInstance().getBuffer());
|
||||
TessellatorHelper.draw();
|
||||
|
||||
GlStateManager.disableCull();
|
||||
GlStateManager.popMatrix();
|
||||
GlStateManager.shadeModel(7424);
|
||||
GlStateManager.alphaFunc(516, 0.1F);
|
||||
|
|
|
@ -17,6 +17,7 @@ import net.minecraft.client.renderer.BlockRendererDispatcher;
|
|||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.BlockPos.MutableBlockPos;
|
||||
import net.minecraft.world.LightType;
|
||||
import net.minecraft.world.World;
|
||||
|
@ -48,7 +49,8 @@ public class ContraptionRenderer {
|
|||
|
||||
for (BlockInfo info : c.blocks.values())
|
||||
renderWorld.setBlockState(info.pos, info.state);
|
||||
for (BlockInfo info : c.blocks.values()) {
|
||||
for (BlockPos pos : c.renderOrder) {
|
||||
BlockInfo info = c.blocks.get(pos);
|
||||
IBakedModel originalModel = dispatcher.getModelForState(info.state);
|
||||
blockRenderer.renderModel(renderWorld, originalModel, info.state, info.pos, builder, true, random, 42,
|
||||
EmptyModelData.INSTANCE);
|
||||
|
|
|
@ -19,7 +19,7 @@ public abstract class BearingBlock extends DirectionalKineticBlock {
|
|||
public boolean hasShaftTowards(IWorldReader world, BlockPos pos, BlockState state, Direction face) {
|
||||
return face == state.get(FACING).getOpposite();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean hasStaticPart() {
|
||||
return true;
|
||||
|
|
|
@ -14,10 +14,10 @@ import net.minecraft.world.World;
|
|||
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
|
||||
|
||||
public class BearingContraption extends Contraption {
|
||||
|
||||
|
||||
protected int sailBlocks;
|
||||
protected Direction facing;
|
||||
|
||||
|
||||
@Override
|
||||
protected AllContraptionTypes getType() {
|
||||
return AllContraptionTypes.BEARING;
|
||||
|
@ -36,7 +36,8 @@ public class BearingContraption extends Contraption {
|
|||
|
||||
@Override
|
||||
public void add(BlockPos pos, Pair<BlockInfo, TileEntity> capture) {
|
||||
if (AllBlockTags.WINDMILL_SAILS.matches(capture.getKey().state))
|
||||
BlockPos localPos = pos.subtract(anchor);
|
||||
if (!blocks.containsKey(localPos) && AllBlockTags.WINDMILL_SAILS.matches(capture.getKey().state))
|
||||
sailBlocks++;
|
||||
super.add(pos, capture);
|
||||
}
|
||||
|
|
|
@ -146,6 +146,8 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe
|
|||
return;
|
||||
if (contraption.getLeft() == null)
|
||||
return;
|
||||
if (contraption.getLeft().blocks.isEmpty())
|
||||
return;
|
||||
BlockPos anchor = pos.offset(direction);
|
||||
|
||||
contraption.getLeft().removeBlocksFromWorld(world, BlockPos.ZERO);
|
||||
|
@ -229,6 +231,9 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe
|
|||
clientMinuteAngleDiff = AngleHelper.getShortestAngleDiff(minuteAngleBefore, minuteAngle);
|
||||
hourAngle = hourAngleBefore;
|
||||
minuteAngle = minuteAngleBefore;
|
||||
} else {
|
||||
hourHand = null;
|
||||
minuteHand = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -245,7 +250,7 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe
|
|||
|
||||
@Override
|
||||
public float getInterpolatedAngle(float partialTicks) {
|
||||
if (hourHand != null && hourHand.isStalled())
|
||||
if (hourHand == null || hourHand.isStalled())
|
||||
partialTicks = 0;
|
||||
return MathHelper.lerp(partialTicks, hourAngle, hourAngle + getHourArmSpeed());
|
||||
}
|
||||
|
|
|
@ -15,6 +15,11 @@ public class MechanicalBearingBlock extends BearingBlock implements IWithTileEnt
|
|||
public TileEntity createTileEntity(BlockState state, IBlockReader world) {
|
||||
return new MechanicalBearingTileEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockAdded(BlockState state, World worldIn, BlockPos pos, BlockState oldState, boolean isMoving) {
|
||||
withTileEntityDo(worldIn, pos, MechanicalBearingTileEntity::neighbourChanged);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void neighborChanged(BlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos,
|
||||
|
|
|
@ -98,13 +98,16 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
|
|||
public void readClientUpdate(CompoundNBT tag) {
|
||||
float angleBefore = angle;
|
||||
super.readClientUpdate(tag);
|
||||
clientAngleDiff = AngleHelper.getShortestAngleDiff(angleBefore, angle);
|
||||
angle = angleBefore;
|
||||
if (running) {
|
||||
clientAngleDiff = AngleHelper.getShortestAngleDiff(angleBefore, angle);
|
||||
angle = angleBefore;
|
||||
} else
|
||||
movedContraption = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getInterpolatedAngle(float partialTicks) {
|
||||
if (movedContraption != null && movedContraption.isStalled())
|
||||
if (movedContraption == null || movedContraption.isStalled())
|
||||
partialTicks = 0;
|
||||
return MathHelper.lerp(partialTicks, angle, angle + getAngularSpeed());
|
||||
}
|
||||
|
@ -133,6 +136,8 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
|
|||
return;
|
||||
if (isWindmill && contraption.getSailBlocks() == 0)
|
||||
return;
|
||||
if (contraption.blocks.isEmpty())
|
||||
return;
|
||||
contraption.removeBlocksFromWorld(world, BlockPos.ZERO);
|
||||
movedContraption = ContraptionEntity.createStationary(world, contraption).controlledBy(this);
|
||||
BlockPos anchor = pos.offset(direction);
|
||||
|
@ -152,7 +157,7 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
|
|||
return;
|
||||
if (movedContraption != null)
|
||||
movedContraption.disassemble();
|
||||
|
||||
|
||||
movedContraption = null;
|
||||
running = false;
|
||||
angle = 0;
|
||||
|
|
|
@ -136,7 +136,8 @@ public abstract class LinearActuatorTileEntity extends KineticTileEntity impleme
|
|||
if (running) {
|
||||
clientOffsetDiff = offset - offsetBefore;
|
||||
offset = offsetBefore;
|
||||
}
|
||||
} else
|
||||
movedContraption = null;
|
||||
|
||||
if (tag.contains("ForceMovement"))
|
||||
if (movedContraption != null)
|
||||
|
@ -157,9 +158,9 @@ public abstract class LinearActuatorTileEntity extends KineticTileEntity impleme
|
|||
|
||||
protected void applyContraptionMotion() {
|
||||
if (movedContraption.isStalled())
|
||||
movedContraption.setMotion(Vec3d.ZERO);
|
||||
movedContraption.setContraptionMotion(Vec3d.ZERO);
|
||||
else
|
||||
movedContraption.setMotion(getMotionVector());
|
||||
movedContraption.setContraptionMotion(getMotionVector());
|
||||
}
|
||||
|
||||
protected void applyContraptionPosition() {
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.simibubi.create.modules.contraptions.components.contraptions.piston;
|
|||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllTileEntities;
|
||||
import com.simibubi.create.foundation.utility.ServerSpeedProvider;
|
||||
import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionEntity;
|
||||
import com.simibubi.create.modules.contraptions.components.contraptions.piston.MechanicalPistonBlock.PistonState;
|
||||
|
||||
|
@ -82,10 +83,13 @@ public class MechanicalPistonTileEntity extends LinearActuatorTileEntity {
|
|||
|
||||
@Override
|
||||
public float getMovementSpeed() {
|
||||
float movementSpeed = getSpeed() / 512f;
|
||||
if (world.isRemote)
|
||||
movementSpeed *= ServerSpeedProvider.get();
|
||||
Direction pistonDirection = getBlockState().get(BlockStateProperties.FACING);
|
||||
int movementModifier =
|
||||
pistonDirection.getAxisDirection().getOffset() * (pistonDirection.getAxis() == Axis.Z ? -1 : 1);
|
||||
return super.getMovementSpeed() * -movementModifier;
|
||||
return movementSpeed * -movementModifier + clientOffsetDiff / 2f;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -99,7 +103,8 @@ public class MechanicalPistonTileEntity extends LinearActuatorTileEntity {
|
|||
|
||||
@Override
|
||||
protected Vec3d toMotionVector(float speed) {
|
||||
return new Vec3d(getBlockState().get(BlockStateProperties.FACING).getDirectionVec()).scale(speed);
|
||||
Direction pistonDirection = getBlockState().get(BlockStateProperties.FACING);
|
||||
return new Vec3d(pistonDirection.getDirectionVec()).scale(speed);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -32,7 +32,7 @@ import net.minecraft.world.gen.feature.template.Template.BlockInfo;
|
|||
|
||||
public class PistonContraption extends Contraption {
|
||||
|
||||
protected AxisAlignedBB pistonCollisionBox;
|
||||
protected AxisAlignedBB pistonExtensionCollisionBox;
|
||||
|
||||
protected int extensionLength;
|
||||
protected int initialExtensionProgress;
|
||||
|
@ -42,7 +42,7 @@ public class PistonContraption extends Contraption {
|
|||
protected AllContraptionTypes getType() {
|
||||
return AllContraptionTypes.PISTON;
|
||||
}
|
||||
|
||||
|
||||
public static PistonContraption movePistonAt(World world, BlockPos pos, Direction direction, boolean retract) {
|
||||
if (isFrozen())
|
||||
return null;
|
||||
|
@ -100,33 +100,39 @@ public class PistonContraption extends Contraption {
|
|||
return false;
|
||||
}
|
||||
|
||||
anchor = pos.offset(direction, initialExtensionProgress + 1);
|
||||
extensionLength = extensionsInBack + extensionsInFront;
|
||||
initialExtensionProgress = extensionsInFront;
|
||||
pistonCollisionBox = new AxisAlignedBB(end.offset(direction, -extensionsInFront));
|
||||
|
||||
anchor = pos.offset(direction, initialExtensionProgress + 1);
|
||||
pistonExtensionCollisionBox = new AxisAlignedBB(end.offset(direction, -extensionsInFront).subtract(anchor));
|
||||
|
||||
if (extensionLength == 0)
|
||||
return false;
|
||||
|
||||
constructCollisionBox = new AxisAlignedBB(0, 0, 0, 0, 0, 0);
|
||||
|
||||
for (BlockInfo pole : poles) {
|
||||
BlockPos polePos = pole.pos.offset(direction, -extensionsInFront).subtract(anchor);
|
||||
blocks.put(polePos, new BlockInfo(polePos, pole.state, null));
|
||||
pistonCollisionBox = pistonCollisionBox.union(new AxisAlignedBB(polePos));
|
||||
BlockPos relPos = pole.pos.offset(direction, -extensionsInFront);
|
||||
BlockPos localPos = relPos.subtract(anchor);
|
||||
blocks.put(localPos, new BlockInfo(localPos, pole.state, null));
|
||||
pistonExtensionCollisionBox = pistonExtensionCollisionBox.union(new AxisAlignedBB(localPos));
|
||||
}
|
||||
|
||||
constructCollisionBox = new AxisAlignedBB(BlockPos.ZERO.offset(direction, -initialExtensionProgress));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean addToInitialFrontier(World world, BlockPos pos, Direction direction, List<BlockPos> frontier) {
|
||||
for (int offset = 1; offset <= AllConfigs.SERVER.kinetics.maxChassisRange.get(); offset++) {
|
||||
BlockPos currentPos = pos.offset(direction, offset);
|
||||
if (!world.isAreaLoaded(currentPos, 1))
|
||||
return false;
|
||||
if (!world.isBlockPresent(currentPos))
|
||||
frontier.clear();
|
||||
boolean sticky = STICKY_MECHANICAL_PISTON.typeOf(world.getBlockState(pos.offset(orientation, -1)));
|
||||
boolean retracting = direction != orientation;
|
||||
if (retracting && !sticky)
|
||||
return true;
|
||||
for (int offset = 0; offset <= AllConfigs.SERVER.kinetics.maxChassisRange.get(); offset++) {
|
||||
if (offset == 1 && retracting)
|
||||
break;
|
||||
BlockPos currentPos = pos.offset(orientation, offset + initialExtensionProgress);
|
||||
if (!world.isBlockPresent(currentPos))
|
||||
return false;
|
||||
BlockState state = world.getBlockState(currentPos);
|
||||
if (state.getMaterial().isReplaceable())
|
||||
break;
|
||||
|
@ -135,7 +141,7 @@ public class PistonContraption extends Contraption {
|
|||
if (AllBlocks.MECHANICAL_PISTON_HEAD.typeOf(state) && state.get(FACING) == direction.getOpposite())
|
||||
break;
|
||||
if (!canPush(world, currentPos, direction))
|
||||
return false;
|
||||
return retracting;
|
||||
frontier.add(currentPos);
|
||||
}
|
||||
return true;
|
||||
|
@ -149,7 +155,7 @@ public class PistonContraption extends Contraption {
|
|||
@Override
|
||||
public void disassemble(World world, BlockPos offset, float yaw, float pitch) {
|
||||
super.disassemble(world, offset, yaw, pitch, (pos, state) -> {
|
||||
BlockPos pistonPos = anchor.offset(orientation, -initialExtensionProgress - 1);
|
||||
BlockPos pistonPos = anchor.offset(orientation, -1);
|
||||
BlockState pistonState = world.getBlockState(pistonPos);
|
||||
TileEntity te = world.getTileEntity(pistonPos);
|
||||
if (pos.equals(pistonPos)) {
|
||||
|
@ -167,7 +173,7 @@ public class PistonContraption extends Contraption {
|
|||
@Override
|
||||
public void removeBlocksFromWorld(IWorld world, BlockPos offset) {
|
||||
super.removeBlocksFromWorld(world, offset, (pos, state) -> {
|
||||
BlockPos pistonPos = anchor.offset(orientation, -initialExtensionProgress - 1);
|
||||
BlockPos pistonPos = anchor.offset(orientation, -1);
|
||||
BlockState blockState = world.getBlockState(pos);
|
||||
if (pos.equals(pistonPos) && blockState.getBlock() instanceof MechanicalPistonBlock) {
|
||||
world.setBlockState(pos, blockState.with(MechanicalPistonBlock.STATE, PistonState.MOVING), 66);
|
||||
|
@ -184,15 +190,15 @@ public class PistonContraption extends Contraption {
|
|||
initialExtensionProgress = nbt.getInt("InitialLength");
|
||||
orientation = Direction.byIndex(nbt.getInt("Orientation"));
|
||||
if (nbt.contains("BoundsBack"))
|
||||
pistonCollisionBox = NBTHelper.readAABB(nbt.getList("BoundsBack", 5));
|
||||
pistonExtensionCollisionBox = NBTHelper.readAABB(nbt.getList("BoundsBack", 5));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundNBT writeNBT() {
|
||||
CompoundNBT nbt = super.writeNBT();
|
||||
|
||||
if (pistonCollisionBox != null) {
|
||||
ListNBT bb = NBTHelper.writeAABB(pistonCollisionBox);
|
||||
if (pistonExtensionCollisionBox != null) {
|
||||
ListNBT bb = NBTHelper.writeAABB(pistonExtensionCollisionBox);
|
||||
nbt.put("BoundsBack", bb);
|
||||
}
|
||||
nbt.putInt("InitialLength", initialExtensionProgress);
|
||||
|
@ -202,7 +208,8 @@ public class PistonContraption extends Contraption {
|
|||
return nbt;
|
||||
}
|
||||
|
||||
public AxisAlignedBB getCollisionBoxBack() {
|
||||
return pistonCollisionBox;
|
||||
@Override
|
||||
public AxisAlignedBB getCollisionBox() {
|
||||
return super.getCollisionBox().union(pistonExtensionCollisionBox);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,15 +32,18 @@ public class PulleyTileEntity extends LinearActuatorTileEntity {
|
|||
if (offset <= 0 && getSpeed() < 0)
|
||||
return;
|
||||
|
||||
// Collect Construct
|
||||
if (!world.isRemote) {
|
||||
BlockPos anchor = pos.down((int) (offset + 1));
|
||||
PulleyContraption contraption = PulleyContraption.assemblePulleyAt(world, anchor, (int) offset);
|
||||
if (contraption == null && getSpeed() > 0)
|
||||
return;
|
||||
|
||||
for (int i = ((int) offset); i > 0; i--) {
|
||||
BlockPos offset = pos.down(i);
|
||||
world.setBlockState(offset, Blocks.AIR.getDefaultState(), 66);
|
||||
}
|
||||
|
||||
// Collect Construct
|
||||
BlockPos anchor = pos.down((int) (offset + 1));
|
||||
PulleyContraption contraption = PulleyContraption.assemblePulleyAt(world, anchor, (int) offset);
|
||||
|
||||
if (contraption != null && !contraption.blocks.isEmpty()) {
|
||||
contraption.removeBlocksFromWorld(world, BlockPos.ZERO);
|
||||
movedContraption = ContraptionEntity.createStationary(world, contraption).controlledBy(this);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.simibubi.create.modules.contraptions.components.waterwheel;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.config.AllConfigs;
|
||||
import com.simibubi.create.modules.contraptions.base.HorizontalKineticBlock;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
|
@ -65,6 +66,10 @@ public class WaterWheelBlock extends HorizontalKineticBlock {
|
|||
|
||||
@Override
|
||||
public void onBlockAdded(BlockState state, World worldIn, BlockPos pos, BlockState oldState, boolean isMoving) {
|
||||
updateAllSides(state, worldIn, pos);
|
||||
}
|
||||
|
||||
public void updateAllSides(BlockState state, World worldIn, BlockPos pos) {
|
||||
for (Direction d : Direction.values())
|
||||
updateFlowAt(state, worldIn, pos, d);
|
||||
updateWheelSpeed(worldIn, pos);
|
||||
|
@ -99,15 +104,16 @@ public class WaterWheelBlock extends HorizontalKineticBlock {
|
|||
flow = flowVec.y > 0 ^ !clockwise ? -flowVec.y * clockwiseMultiplier : -flowVec.y;
|
||||
}
|
||||
|
||||
te.setFlow(f, (int) (flow * 5));
|
||||
te.setFlow(f, (float) (flow * AllConfigs.SERVER.kinetics.waterWheelSpeed.get() / 2f));
|
||||
}
|
||||
|
||||
private void updateWheelSpeed(IWorld world, BlockPos pos) {
|
||||
if (world.isRemote())
|
||||
return;
|
||||
WaterWheelTileEntity te = (WaterWheelTileEntity) world.getTileEntity(pos);
|
||||
if (te == null)
|
||||
TileEntity tileEntity = world.getTileEntity(pos);
|
||||
if (!(tileEntity instanceof WaterWheelTileEntity))
|
||||
return;
|
||||
WaterWheelTileEntity te = (WaterWheelTileEntity) tileEntity;
|
||||
te.updateGeneratedRotation();
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.simibubi.create.modules.contraptions.components.waterwheel;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllTileEntities;
|
||||
import com.simibubi.create.modules.contraptions.base.GeneratingKineticTileEntity;
|
||||
|
||||
|
@ -12,14 +13,14 @@ import net.minecraft.util.math.AxisAlignedBB;
|
|||
|
||||
public class WaterWheelTileEntity extends GeneratingKineticTileEntity {
|
||||
|
||||
private Map<Direction, Integer> flows;
|
||||
private Map<Direction, Float> flows;
|
||||
|
||||
public WaterWheelTileEntity() {
|
||||
super(AllTileEntities.WATER_WHEEL.type);
|
||||
flows = new HashMap<Direction, Integer>();
|
||||
flows = new HashMap<>();
|
||||
for (Direction d : Direction.values())
|
||||
setFlow(d, 0);
|
||||
|
||||
setLazyTickRate(20);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -27,7 +28,7 @@ public class WaterWheelTileEntity extends GeneratingKineticTileEntity {
|
|||
super.read(compound);
|
||||
if (compound.contains("Flows")) {
|
||||
for (Direction d : Direction.values())
|
||||
setFlow(d, compound.getCompound("Flows").getInt(d.getName()));
|
||||
setFlow(d, compound.getCompound("Flows").getFloat(d.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,22 +42,29 @@ public class WaterWheelTileEntity extends GeneratingKineticTileEntity {
|
|||
|
||||
CompoundNBT flows = new CompoundNBT();
|
||||
for (Direction d : Direction.values())
|
||||
flows.putInt(d.getName(), this.flows.get(d));
|
||||
flows.putFloat(d.getName(), this.flows.get(d));
|
||||
compound.put("Flows", flows);
|
||||
|
||||
return super.write(compound);
|
||||
}
|
||||
|
||||
public void setFlow(Direction direction, int speed) {
|
||||
public void setFlow(Direction direction, float speed) {
|
||||
flows.put(direction, speed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getGeneratedSpeed() {
|
||||
float speed = 0;
|
||||
for (Integer i : flows.values())
|
||||
speed += i;
|
||||
for (Float f : flows.values())
|
||||
speed += f;
|
||||
return speed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lazyTick() {
|
||||
super.lazyTick();
|
||||
WaterWheelBlock block = (WaterWheelBlock) AllBlocks.WATER_WHEEL.get();
|
||||
block.updateAllSides(getBlockState(), world, pos);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -279,7 +279,7 @@ public class BeltBlock extends HorizontalKineticBlock implements IHaveNoBlockIte
|
|||
return ActionResultType.SUCCESS;
|
||||
}
|
||||
|
||||
return super.onWrenched(state, context);
|
||||
return ActionResultType.FAIL;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -102,7 +102,7 @@ public class GaugeInformationRenderer {
|
|||
private static void addStressTooltip(BlockState state, List<String> tooltip, KineticTileEntity te) {
|
||||
String spacing = " ";
|
||||
float stressApplied = te.getStressApplied();
|
||||
if (stressApplied == 0)
|
||||
if (stressApplied == 0 || !StressImpact.isEnabled())
|
||||
return;
|
||||
|
||||
String _kineticStatsTitle = Lang.translate("gui.goggles.kinetic_stats");
|
||||
|
@ -115,8 +115,8 @@ public class GaugeInformationRenderer {
|
|||
tooltip.add(spacing + GRAY + _stressImpact);
|
||||
|
||||
String addedStress = AQUA + "" + format(stressApplied) + _stressUnit + " " + DARK_GRAY + _atCurrentSpeed;
|
||||
String addedStressAtBase = GRAY + "" + format(stressApplied * Math.abs(te.getSpeed())) + _stressUnit + " "
|
||||
+ DARK_GRAY + _baseValue;
|
||||
String addedStressAtBase =
|
||||
GRAY + "" + format(stressApplied * Math.abs(te.getSpeed())) + _stressUnit + " " + DARK_GRAY + _baseValue;
|
||||
tooltip.add(spacing + " " + addedStress);
|
||||
tooltip.add(spacing + " " + addedStressAtBase);
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ public class GaugeInformationRenderer {
|
|||
private static void addGeneratorTooltip(BlockState state, List<String> tooltip, GeneratingKineticTileEntity te) {
|
||||
String spacing = " ";
|
||||
float addedStressCapacity = te.getAddedStressCapacity();
|
||||
if (addedStressCapacity == 0)
|
||||
if (addedStressCapacity == 0 || !StressImpact.isEnabled())
|
||||
return;
|
||||
|
||||
String _stressUnit = Lang.translate("generic.unit.stress");
|
||||
|
@ -144,8 +144,8 @@ public class GaugeInformationRenderer {
|
|||
if (actualSpeed != 0)
|
||||
relativeCap = addedStressCapacity * actualSpeed;
|
||||
|
||||
String addedCapacity = AQUA + "" + format(addedStressCapacity) + _stressUnit + " " + DARK_GRAY
|
||||
+ _atCurrentSpeed;
|
||||
String addedCapacity =
|
||||
AQUA + "" + format(addedStressCapacity) + _stressUnit + " " + DARK_GRAY + _atCurrentSpeed;
|
||||
String addedCapacityAtBase = GRAY + "" + format(relativeCap) + _stressUnit + " " + DARK_GRAY + _baseValue;
|
||||
tooltip.add(spacing + " " + addedCapacity);
|
||||
tooltip.add(spacing + " " + addedCapacityAtBase);
|
||||
|
@ -170,6 +170,10 @@ public class GaugeInformationRenderer {
|
|||
if (AllBlocks.STRESS_GAUGE.typeOf(state)) {
|
||||
if (!(te instanceof StressGaugeTileEntity))
|
||||
return;
|
||||
if (!StressImpact.isEnabled()) {
|
||||
tooltip.clear();
|
||||
return;
|
||||
}
|
||||
StressGaugeTileEntity stressGauge = (StressGaugeTileEntity) te;
|
||||
List<String> stressLevels = Lang.translatedOptions("tooltip.stressImpact", "low", "medium", "high");
|
||||
double stress = stressGauge.currentStress;
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.simibubi.create.modules.contraptions.relays.gauge;
|
|||
|
||||
import com.simibubi.create.AllTileEntities;
|
||||
import com.simibubi.create.foundation.utility.ColorHelper;
|
||||
import com.simibubi.create.modules.contraptions.base.IRotate.StressImpact;
|
||||
|
||||
public class StressGaugeTileEntity extends GaugeTileEntity {
|
||||
|
||||
|
@ -13,7 +14,9 @@ public class StressGaugeTileEntity extends GaugeTileEntity {
|
|||
public void sync(float maxStress, float currentStress) {
|
||||
super.sync(maxStress, currentStress);
|
||||
|
||||
if (overStressed)
|
||||
if (!StressImpact.isEnabled())
|
||||
dialTarget = 0;
|
||||
else if (overStressed)
|
||||
dialTarget = 1.125f;
|
||||
else if (maxStress == 0)
|
||||
dialTarget = 0;
|
||||
|
|
|
@ -3,9 +3,8 @@
|
|||
"parent": "block/block",
|
||||
"textures": {
|
||||
"0": "create:block/axis",
|
||||
"1": "create:block/axis_top",
|
||||
"2": "create:block/andesite_casing_short",
|
||||
"3": "block/spruce_log",
|
||||
"3": "create:block/brass_block",
|
||||
"particle": "create:block/axis"
|
||||
},
|
||||
"elements": [
|
||||
|
@ -14,12 +13,12 @@
|
|||
"from": [5, 5, 11],
|
||||
"to": [11, 11, 14],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 6, 6], "texture": "#3"},
|
||||
"east": {"uv": [0, 0, 3, 6], "texture": "#3"},
|
||||
"south": {"uv": [0, 0, 6, 6], "texture": "#3"},
|
||||
"west": {"uv": [0, 0, 3, 6], "texture": "#3"},
|
||||
"up": {"uv": [0, 0, 6, 3], "texture": "#3"},
|
||||
"down": {"uv": [0, 0, 6, 3], "texture": "#3"}
|
||||
"north": {"uv": [5, 0, 11, 6], "texture": "#3"},
|
||||
"east": {"uv": [13, 6, 16, 12], "texture": "#3"},
|
||||
"south": {"uv": [3, 4, 9, 10], "texture": "#3"},
|
||||
"west": {"uv": [0, 3, 3, 9], "texture": "#3"},
|
||||
"up": {"uv": [6, 0, 12, 3], "texture": "#3"},
|
||||
"down": {"uv": [6, 13, 12, 16], "texture": "#3"}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -69,5 +68,5 @@
|
|||
"name": "shaft_half",
|
||||
"origin": [8, 8, 8],
|
||||
"children": [0]
|
||||
}, 1, 2, 3, 4]
|
||||
}, 1, 2, 3]
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
"0": "create:block/axis",
|
||||
"1": "create:block/axis_top",
|
||||
"2": "create:block/andesite_casing_short",
|
||||
"3": "block/spruce_log",
|
||||
"4": "create:block/brass_block",
|
||||
"particle": "create:block/axis"
|
||||
},
|
||||
"elements": [
|
||||
|
@ -27,12 +27,12 @@
|
|||
"from": [5, 5, 11],
|
||||
"to": [11, 11, 14],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 6, 6], "texture": "#3"},
|
||||
"east": {"uv": [0, 0, 3, 6], "texture": "#3"},
|
||||
"south": {"uv": [0, 0, 6, 6], "texture": "#3"},
|
||||
"west": {"uv": [0, 0, 3, 6], "texture": "#3"},
|
||||
"up": {"uv": [0, 0, 6, 3], "texture": "#3"},
|
||||
"down": {"uv": [0, 0, 6, 3], "texture": "#3"}
|
||||
"north": {"uv": [0, 0, 6, 6], "texture": "#4"},
|
||||
"east": {"uv": [13, 5, 16, 11], "texture": "#4"},
|
||||
"south": {"uv": [5, 5, 11, 11], "texture": "#4"},
|
||||
"west": {"uv": [0, 5, 3, 11], "texture": "#4"},
|
||||
"up": {"uv": [5, 0, 11, 3], "texture": "#4"},
|
||||
"down": {"uv": [4, 13, 10, 16], "texture": "#4"}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 220 B After Width: | Height: | Size: 261 B |
|
@ -1,19 +1,19 @@
|
|||
{
|
||||
"type": "crafting_shaped",
|
||||
"pattern": [
|
||||
" L ",
|
||||
" A ",
|
||||
"PPP",
|
||||
" A"
|
||||
" L"
|
||||
],
|
||||
"key": {
|
||||
"L": {
|
||||
"tag": "minecraft:logs"
|
||||
"item": "create:andesite_alloy"
|
||||
},
|
||||
"P": {
|
||||
"tag": "minecraft:planks"
|
||||
},
|
||||
"A": {
|
||||
"item": "create:andesite_alloy"
|
||||
"tag": "forge:plates/brass"
|
||||
}
|
||||
},
|
||||
"result": {
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
{
|
||||
"type": "create:mechanical_crafting",
|
||||
"pattern": [
|
||||
" PPP ",
|
||||
"PSBSP",
|
||||
"PBCBP",
|
||||
"PSBSP",
|
||||
" PPP "
|
||||
],
|
||||
"key": {
|
||||
"P": {
|
||||
"item": "minecraft:polished_andesite"
|
||||
},
|
||||
"S": {
|
||||
"tag": "forge:rods/wooden"
|
||||
},
|
||||
"C": {
|
||||
"item": "create:large_cogwheel"
|
||||
},
|
||||
"B": {
|
||||
"item": "create:andesite_alloy"
|
||||
}
|
||||
},
|
||||
"result": {
|
||||
"item": "create:crushing_wheel",
|
||||
"count": 1
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"type": "create:module",
|
||||
"module": "contraptions"
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in a new issue