Interdimensional Railways
- Trackgraphs and trains now properly differentiate between the dimensions they are located in - Tracks placed next to a nether portal will attempt to connect to a second track piece in the nether
This commit is contained in:
parent
e281512787
commit
32da097c26
68 changed files with 2182 additions and 524 deletions
|
@ -486,7 +486,7 @@ f385988cb6fa9c48b5d59a6942ec50ed2b60c8bf assets/create/blockstates/stockpile_swi
|
|||
e815bfd854c2653f10828bb11950f7fb991d7efc assets/create/blockstates/stressometer.json
|
||||
8b0c2c7ac72529565b3339aa8df7565858100afa assets/create/blockstates/tiled_glass.json
|
||||
a2454400b1cf9889f70aebdc89c52a1be25f543c assets/create/blockstates/tiled_glass_pane.json
|
||||
85b57776edf426c2f8df6698b2482ea925914a5c assets/create/blockstates/track.json
|
||||
a64fcf2bee9b49f1448d1ff691bd92d7590a59b0 assets/create/blockstates/track.json
|
||||
408ae1009ee8bb2f2b83753d5909c53744f7865f assets/create/blockstates/track_signal.json
|
||||
60609cfbcc9be6f7e41fb493ef3147beb9750b60 assets/create/blockstates/track_station.json
|
||||
29af21c8d82891139d48d69f0393f612f2b6f8f1 assets/create/blockstates/tuff_pillar.json
|
||||
|
|
|
@ -30,6 +30,21 @@
|
|||
"model": "create:block/track/ascending",
|
||||
"y": 90
|
||||
},
|
||||
"shape=tn,turn=false": {
|
||||
"model": "create:block/track/teleport",
|
||||
"y": 180
|
||||
},
|
||||
"shape=ts,turn=false": {
|
||||
"model": "create:block/track/teleport"
|
||||
},
|
||||
"shape=te,turn=false": {
|
||||
"model": "create:block/track/teleport",
|
||||
"y": 270
|
||||
},
|
||||
"shape=tw,turn=false": {
|
||||
"model": "create:block/track/teleport",
|
||||
"y": 90
|
||||
},
|
||||
"shape=cr_o,turn=false": {
|
||||
"model": "create:block/track/cross_ortho"
|
||||
},
|
||||
|
@ -78,6 +93,21 @@
|
|||
"model": "create:block/track/ascending",
|
||||
"y": 90
|
||||
},
|
||||
"shape=tn,turn=true": {
|
||||
"model": "create:block/track/teleport",
|
||||
"y": 180
|
||||
},
|
||||
"shape=ts,turn=true": {
|
||||
"model": "create:block/track/teleport"
|
||||
},
|
||||
"shape=te,turn=true": {
|
||||
"model": "create:block/track/teleport",
|
||||
"y": 270
|
||||
},
|
||||
"shape=tw,turn=true": {
|
||||
"model": "create:block/track/teleport",
|
||||
"y": 90
|
||||
},
|
||||
"shape=cr_o,turn=true": {
|
||||
"model": "create:block/track/cross_ortho"
|
||||
},
|
||||
|
|
|
@ -148,6 +148,7 @@ public class AllShapes {
|
|||
TRACK_ORTHO = shape(TrackVoxelShapes.orthogonal()).forHorizontal(NORTH),
|
||||
TRACK_ASC = shape(TrackVoxelShapes.ascending()).forHorizontal(SOUTH),
|
||||
TRACK_DIAG = shape(TrackVoxelShapes.diagonal()).forHorizontal(SOUTH),
|
||||
TRACK_ORTHO_LONG = shape(TrackVoxelShapes.longOrthogonalZOffset()).forHorizontal(SOUTH),
|
||||
|
||||
WHISTLE_BASE = shape(1, 0, 1, 15, 3, 15).add(5, 0, 5, 11, 8, 11)
|
||||
.forDirectional(UP)
|
||||
|
|
|
@ -18,6 +18,7 @@ import net.minecraft.world.level.block.Blocks;
|
|||
import net.minecraft.world.level.block.BubbleColumnBlock;
|
||||
import net.minecraft.world.level.block.FarmBlock;
|
||||
import net.minecraft.world.level.block.LiquidBlock;
|
||||
import net.minecraft.world.level.block.NetherPortalBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.storage.loot.LootContext;
|
||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||
|
@ -80,6 +81,8 @@ public class PloughMovementBehaviour extends BlockBreakingMovementBehaviour {
|
|||
return false;
|
||||
if (state.getBlock() instanceof BubbleColumnBlock)
|
||||
return false;
|
||||
if (state.getBlock() instanceof NetherPortalBlock)
|
||||
return false;
|
||||
return state.getCollisionShape(world, breakingPos)
|
||||
.isEmpty();
|
||||
}
|
||||
|
|
|
@ -297,7 +297,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
|||
contraption.onEntityTick(level);
|
||||
tickContraption();
|
||||
super.tick();
|
||||
|
||||
|
||||
if (!(level instanceof ServerLevelAccessor sl))
|
||||
return;
|
||||
|
||||
|
@ -362,7 +362,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
|||
|
||||
context.rotation = v -> applyRotation(v, 1);
|
||||
context.position = actorPosition;
|
||||
if (!actor.isActive(context))
|
||||
if (!isActorActive(context, actor))
|
||||
continue;
|
||||
if (newPosVisited && !context.stall) {
|
||||
actor.visitNewPosition(context, gridPosition);
|
||||
|
@ -408,6 +408,10 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
|||
contraption.stalled = isStalled();
|
||||
}
|
||||
|
||||
protected boolean isActorActive(MovementContext context, MovementBehaviour actor) {
|
||||
return actor.isActive(context);
|
||||
}
|
||||
|
||||
protected void onContraptionStalled() {
|
||||
AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> this),
|
||||
new ContraptionStallPacket(getId(), getX(), getY(), getZ(), getStalledAngle()));
|
||||
|
@ -790,4 +794,8 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
|||
// Contraptions no longer catch fire
|
||||
}
|
||||
|
||||
public boolean isReadyForRender() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import static com.simibubi.create.content.contraptions.components.structureMovem
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
@ -1372,6 +1373,22 @@ public abstract class Contraption {
|
|||
// return pos.equals(te.getBlockPos());
|
||||
// }
|
||||
// }
|
||||
|
||||
public Collection<StructureBlockInfo> getRenderedBlocks() {
|
||||
return blocks.values();
|
||||
}
|
||||
|
||||
public Collection<BlockEntity> getSpecialRenderedTEs() {
|
||||
return specialRenderedTileEntities;
|
||||
}
|
||||
|
||||
public boolean isHiddenInPortal(BlockPos localPos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Optional<List<AABB>> getSimplifiedEntityColliders() {
|
||||
return simplifiedEntityColliders;
|
||||
}
|
||||
|
||||
public static class ContraptionInvWrapper extends CombinedInvWrapper {
|
||||
protected final boolean isExternal;
|
||||
|
@ -1392,4 +1409,5 @@ public abstract class Contraption {
|
|||
return handler instanceof ContraptionInvWrapper && ((ContraptionInvWrapper) handler).isSlotExternal(slot);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -116,7 +116,7 @@ public class ContraptionCollider {
|
|||
|
||||
// Use simplified bbs when present
|
||||
final Vec3 motionCopy = motion;
|
||||
List<AABB> collidableBBs = contraption.simplifiedEntityColliders.orElseGet(() -> {
|
||||
List<AABB> collidableBBs = contraption.getSimplifiedEntityColliders().orElseGet(() -> {
|
||||
|
||||
// Else find 'nearby' individual block shapes to collide with
|
||||
List<AABB> bbs = new ArrayList<>();
|
||||
|
@ -490,6 +490,7 @@ public class ContraptionCollider {
|
|||
|
||||
List<VoxelShape> potentialHits = BlockPos.betweenClosedStream(min, max)
|
||||
.filter(contraption.getBlocks()::containsKey)
|
||||
.filter(Predicates.not(contraption::isHiddenInPortal))
|
||||
.map(p -> {
|
||||
BlockState blockState = contraption.getBlocks()
|
||||
.get(p).state;
|
||||
|
|
|
@ -82,7 +82,7 @@ public class ContraptionHandlerClient {
|
|||
Couple<Vec3> rayInputs = getRayInputs(player);
|
||||
Vec3 origin = rayInputs.getFirst();
|
||||
Vec3 target = rayInputs.getSecond();
|
||||
AABB aabb = new AABB(origin, target).inflate(4);
|
||||
AABB aabb = new AABB(origin, target).inflate(16);
|
||||
List<AbstractContraptionEntity> intersectingContraptions =
|
||||
mc.level.getEntitiesOfClass(AbstractContraptionEntity.class, aabb);
|
||||
|
||||
|
@ -143,6 +143,8 @@ public class ContraptionHandlerClient {
|
|||
VoxelShape raytraceShape = state.getShape(Minecraft.getInstance().level, BlockPos.ZERO.below());
|
||||
if (raytraceShape.isEmpty())
|
||||
return false;
|
||||
if (contraption.isHiddenInPortal(p))
|
||||
return false;
|
||||
BlockHitResult rayTrace = raytraceShape.clip(localOrigin, localTarget, p);
|
||||
if (rayTrace != null) {
|
||||
mutableResult.setValue(rayTrace);
|
||||
|
|
|
@ -47,6 +47,7 @@ import net.minecraft.world.level.block.Mirror;
|
|||
import net.minecraft.world.level.block.Rotation;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
||||
import net.minecraft.world.level.portal.PortalInfo;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.entity.IEntityAdditionalSpawnData;
|
||||
|
@ -287,6 +288,12 @@ public class SuperGlueEntity extends Entity implements IEntityAdditionalSpawnDat
|
|||
return getBoundingBox().contains(Vec3.atCenterOf(pos));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PortalInfo findDimensionEntryPoint(ServerLevel pDestination) {
|
||||
portalEntrancePos = blockPosition();
|
||||
return super.findDimensionEntryPoint(pDestination);
|
||||
}
|
||||
|
||||
public void spawnParticles() {
|
||||
AABB bb = getBoundingBox();
|
||||
Vec3 origin = new Vec3(bb.minX, bb.minY, bb.minZ);
|
||||
|
|
|
@ -68,7 +68,7 @@ public class ControlsHandler {
|
|||
if (packetCooldown > 0)
|
||||
packetCooldown--;
|
||||
|
||||
if (InputConstants.isKeyDown(Minecraft.getInstance()
|
||||
if (entity.isRemoved() || InputConstants.isKeyDown(Minecraft.getInstance()
|
||||
.getWindow()
|
||||
.getWindow(), GLFW.GLFW_KEY_ESCAPE)) {
|
||||
BlockPos pos = controlsPos;
|
||||
|
|
|
@ -27,6 +27,12 @@ public class ControlsMovementBehaviour implements MovementBehaviour {
|
|||
LerpedFloat equipAnimation = LerpedFloat.linear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopMoving(MovementContext context) {
|
||||
context.contraption.entity.stopControlling(context.localPos);
|
||||
MovementBehaviour.super.stopMoving(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick(MovementContext context) {
|
||||
MovementBehaviour.super.tick(context);
|
||||
|
|
|
@ -13,6 +13,7 @@ import com.simibubi.create.foundation.utility.IntAttached;
|
|||
import com.simibubi.create.foundation.utility.WorldAttached;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
|
||||
public class ControlsServerHandler {
|
||||
|
@ -29,6 +30,11 @@ public class ControlsServerHandler {
|
|||
ControlsContext ctx = entry.getValue();
|
||||
Collection<ManuallyPressedKey> list = ctx.keys;
|
||||
|
||||
if (ctx.entity.isRemoved()) {
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
for (Iterator<ManuallyPressedKey> entryIterator = list.iterator(); entryIterator.hasNext();) {
|
||||
ManuallyPressedKey pressedKey = entryIterator.next();
|
||||
pressedKey.decrement();
|
||||
|
@ -36,9 +42,16 @@ public class ControlsServerHandler {
|
|||
entryIterator.remove(); // key released
|
||||
}
|
||||
|
||||
Player player = world.getPlayerByUUID(entry.getKey());
|
||||
if (player == null) {
|
||||
ctx.entity.stopControlling(ctx.controlsLocalPos);
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ctx.entity.control(ctx.controlsLocalPos, list.stream()
|
||||
.map(ManuallyPressedKey::getSecond)
|
||||
.toList(), world.getPlayerByUUID(entry.getKey()))) {
|
||||
.toList(), player)) {
|
||||
ctx.entity.stopControlling(ctx.controlsLocalPos);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ public abstract class ActorInstance {
|
|||
this.context = context;
|
||||
}
|
||||
|
||||
public void tick() { }
|
||||
public void tick() { }
|
||||
|
||||
public void beginFrame() { }
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@ public class ContraptionEntityRenderer<C extends AbstractContraptionEntity> exte
|
|||
return false;
|
||||
if (!entity.isAlive())
|
||||
return false;
|
||||
if (!entity.isReadyForRender())
|
||||
return false;
|
||||
|
||||
return super.shouldRender(entity, clippingHelper, cameraX, cameraY, cameraZ);
|
||||
}
|
||||
|
|
|
@ -12,10 +12,12 @@ import com.jozufozu.flywheel.backend.instancing.TaskEngine;
|
|||
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstanceManager;
|
||||
import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld;
|
||||
import com.simibubi.create.AllMovementBehaviours;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
|
||||
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo;
|
||||
|
||||
public class ContraptionInstanceManager extends BlockEntityInstanceManager {
|
||||
|
@ -24,14 +26,22 @@ public class ContraptionInstanceManager extends BlockEntityInstanceManager {
|
|||
|
||||
private final VirtualRenderWorld renderWorld;
|
||||
|
||||
ContraptionInstanceManager(MaterialManager materialManager, VirtualRenderWorld contraption) {
|
||||
private Contraption contraption;
|
||||
|
||||
ContraptionInstanceManager(MaterialManager materialManager, VirtualRenderWorld renderWorld, Contraption contraption) {
|
||||
super(materialManager);
|
||||
this.renderWorld = contraption;
|
||||
this.renderWorld = renderWorld;
|
||||
this.contraption = contraption;
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
actors.forEach(ActorInstance::tick);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canCreateInstance(BlockEntity blockEntity) {
|
||||
return !contraption.isHiddenInPortal(blockEntity.getBlockPos());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginFrame(TaskEngine taskEngine, Camera info) {
|
||||
|
@ -49,6 +59,9 @@ public class ContraptionInstanceManager extends BlockEntityInstanceManager {
|
|||
public ActorInstance createActor(Pair<StructureBlockInfo, MovementContext> actor) {
|
||||
StructureBlockInfo blockInfo = actor.getLeft();
|
||||
MovementContext context = actor.getRight();
|
||||
|
||||
if (contraption.isHiddenInPortal(context.localPos))
|
||||
return null;
|
||||
|
||||
MovementBehaviour movementBehaviour = AllMovementBehaviours.of(blockInfo.state);
|
||||
|
||||
|
|
|
@ -48,29 +48,36 @@ public class ContraptionRenderDispatcher {
|
|||
|
||||
/**
|
||||
* Reset a contraption's renderer.
|
||||
*
|
||||
* @param contraption The contraption to invalidate.
|
||||
* @return true if there was a renderer associated with the given contraption.
|
||||
*/
|
||||
public static boolean invalidate(Contraption contraption) {
|
||||
Level level = contraption.entity.level;
|
||||
|
||||
return WORLDS.get(level).invalidate(contraption);
|
||||
return WORLDS.get(level)
|
||||
.invalidate(contraption);
|
||||
}
|
||||
|
||||
public static void tick(Level world) {
|
||||
if (Minecraft.getInstance().isPaused()) return;
|
||||
if (Minecraft.getInstance()
|
||||
.isPaused())
|
||||
return;
|
||||
|
||||
WORLDS.get(world).tick();
|
||||
WORLDS.get(world)
|
||||
.tick();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void beginFrame(BeginFrameEvent event) {
|
||||
WORLDS.get(event.getWorld()).beginFrame(event);
|
||||
WORLDS.get(event.getWorld())
|
||||
.beginFrame(event);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void renderLayer(RenderLayerEvent event) {
|
||||
WORLDS.get(event.getWorld()).renderLayer(event);
|
||||
WORLDS.get(event.getWorld())
|
||||
.renderLayer(event);
|
||||
|
||||
GlError.pollAndThrow(() -> "contraption layer: " + event.getLayer());
|
||||
}
|
||||
|
@ -84,15 +91,17 @@ public class ContraptionRenderDispatcher {
|
|||
reset();
|
||||
}
|
||||
|
||||
public static void renderFromEntity(AbstractContraptionEntity entity, Contraption contraption, MultiBufferSource buffers) {
|
||||
public static void renderFromEntity(AbstractContraptionEntity entity, Contraption contraption,
|
||||
MultiBufferSource buffers) {
|
||||
Level world = entity.level;
|
||||
|
||||
ContraptionRenderInfo renderInfo = WORLDS.get(world)
|
||||
.getRenderInfo(contraption);
|
||||
.getRenderInfo(contraption);
|
||||
ContraptionMatrices matrices = renderInfo.getMatrices();
|
||||
|
||||
// something went wrong with the other rendering
|
||||
if (!matrices.isReady()) return;
|
||||
if (!matrices.isReady())
|
||||
return;
|
||||
|
||||
VirtualRenderWorld renderWorld = renderInfo.renderWorld;
|
||||
|
||||
|
@ -106,28 +115,30 @@ public class ContraptionRenderDispatcher {
|
|||
|
||||
public static VirtualRenderWorld setupRenderWorld(Level world, Contraption c) {
|
||||
ContraptionWorld contraptionWorld = c.getContraptionWorld();
|
||||
VirtualRenderWorld renderWorld = new VirtualRenderWorld(world, c.anchor, contraptionWorld.getHeight(), contraptionWorld.getMinBuildHeight());
|
||||
|
||||
BlockPos origin = c.anchor;
|
||||
int height = contraptionWorld.getHeight();
|
||||
int minBuildHeight = contraptionWorld.getMinBuildHeight();
|
||||
VirtualRenderWorld renderWorld = new VirtualRenderWorld(world, origin, height, minBuildHeight);
|
||||
|
||||
renderWorld.setBlockEntities(c.presentTileEntities.values());
|
||||
|
||||
for (StructureTemplate.StructureBlockInfo info : c.getBlocks()
|
||||
.values())
|
||||
.values())
|
||||
// Skip individual lighting updates to prevent lag with large contraptions
|
||||
renderWorld.setBlock(info.pos, info.state, Block.UPDATE_SUPPRESS_LIGHT);
|
||||
|
||||
renderWorld.runLightingEngine();
|
||||
|
||||
return renderWorld;
|
||||
}
|
||||
|
||||
public static void renderTileEntities(Level world, VirtualRenderWorld renderWorld, Contraption c,
|
||||
ContraptionMatrices matrices, MultiBufferSource buffer) {
|
||||
TileEntityRenderHelper.renderTileEntities(world, renderWorld, c.specialRenderedTileEntities,
|
||||
matrices.getModelViewProjection(), matrices.getLight(), buffer);
|
||||
ContraptionMatrices matrices, MultiBufferSource buffer) {
|
||||
TileEntityRenderHelper.renderTileEntities(world, renderWorld, c.getSpecialRenderedTEs(),
|
||||
matrices.getModelViewProjection(), matrices.getLight(), buffer);
|
||||
}
|
||||
|
||||
protected static void renderActors(Level world, VirtualRenderWorld renderWorld, Contraption c,
|
||||
ContraptionMatrices matrices, MultiBufferSource buffer) {
|
||||
ContraptionMatrices matrices, MultiBufferSource buffer) {
|
||||
PoseStack m = matrices.getModel();
|
||||
|
||||
for (Pair<StructureTemplate.StructureBlockInfo, MovementContext> actor : c.getActors()) {
|
||||
|
@ -140,18 +151,20 @@ public class ContraptionRenderDispatcher {
|
|||
|
||||
MovementBehaviour movementBehaviour = AllMovementBehaviours.of(blockInfo.state);
|
||||
if (movementBehaviour != null) {
|
||||
if (c.isHiddenInPortal(blockInfo.pos))
|
||||
continue;
|
||||
m.pushPose();
|
||||
TransformStack.cast(m)
|
||||
.translate(blockInfo.pos);
|
||||
.translate(blockInfo.pos);
|
||||
movementBehaviour.renderInContraption(context, renderWorld, matrices, buffer);
|
||||
m.popPose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static SuperByteBuffer buildStructureBuffer(VirtualRenderWorld renderWorld, Contraption c, RenderType layer) {
|
||||
Collection<StructureTemplate.StructureBlockInfo> values = c.getBlocks()
|
||||
.values();
|
||||
public static SuperByteBuffer buildStructureBuffer(VirtualRenderWorld renderWorld, Contraption c,
|
||||
RenderType layer) {
|
||||
Collection<StructureTemplate.StructureBlockInfo> values = c.getRenderedBlocks();
|
||||
BufferBuilder builder = ModelUtil.getBufferBuilderFromTemplate(renderWorld, layer, values);
|
||||
return new SuperByteBuffer(builder);
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ public class ContraptionRenderInfo {
|
|||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return visible && contraption.entity.isAlive();
|
||||
return visible && contraption.entity.isAlive() && contraption.entity.isReadyForRender();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -29,6 +29,7 @@ import net.minecraft.client.renderer.RenderType;
|
|||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
|
@ -137,10 +138,10 @@ public class FlwContraption extends ContraptionRenderInfo {
|
|||
renderLayers.clear();
|
||||
|
||||
List<RenderType> blockLayers = RenderType.chunkBufferLayers();
|
||||
|
||||
Collection<StructureBlockInfo> renderedBlocks = contraption.getRenderedBlocks();
|
||||
|
||||
for (RenderType layer : blockLayers) {
|
||||
Model layerModel = new WorldModel(renderWorld, layer, contraption.getBlocks().values(), layer + "_" + contraption.entity.getId());
|
||||
|
||||
Model layerModel = new WorldModel(renderWorld, layer, renderedBlocks, layer + "_" + contraption.entity.getId());
|
||||
renderLayers.put(layer, new ArrayModelRenderer(layerModel));
|
||||
}
|
||||
}
|
||||
|
@ -187,14 +188,14 @@ public class FlwContraption extends ContraptionRenderInfo {
|
|||
.setGroupFactory(ContraptionGroup.forContraption(parent))
|
||||
.setIgnoreOriginCoordinate(true)
|
||||
.build();
|
||||
tileInstanceManager = new ContraptionInstanceManager(engine, parent.renderWorld);
|
||||
tileInstanceManager = new ContraptionInstanceManager(engine, parent.renderWorld, parent.contraption);
|
||||
engine.addListener(tileInstanceManager);
|
||||
|
||||
this.engine = engine;
|
||||
}
|
||||
case BATCHING -> {
|
||||
engine = new BatchingEngine();
|
||||
tileInstanceManager = new ContraptionInstanceManager(engine, parent.renderWorld);
|
||||
tileInstanceManager = new ContraptionInstanceManager(engine, parent.renderWorld, parent.contraption);
|
||||
}
|
||||
default -> throw new IllegalArgumentException("Unknown engine type");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
package com.simibubi.create.content.logistics.trains;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
public class DimensionPalette {
|
||||
|
||||
List<ResourceKey<Level>> gatheredDims;
|
||||
|
||||
public DimensionPalette() {
|
||||
gatheredDims = new ArrayList<>();
|
||||
}
|
||||
|
||||
public int encode(ResourceKey<Level> dimension) {
|
||||
int indexOf = gatheredDims.indexOf(dimension);
|
||||
if (indexOf == -1) {
|
||||
indexOf = gatheredDims.size();
|
||||
gatheredDims.add(dimension);
|
||||
}
|
||||
return indexOf;
|
||||
}
|
||||
|
||||
public ResourceKey<Level> decode(int index) {
|
||||
if (gatheredDims.size() <= index || index < 0)
|
||||
return Level.OVERWORLD;
|
||||
return gatheredDims.get(index);
|
||||
}
|
||||
|
||||
public void send(FriendlyByteBuf buffer) {
|
||||
buffer.writeInt(gatheredDims.size());
|
||||
gatheredDims.forEach(rk -> buffer.writeResourceLocation(rk.location()));
|
||||
}
|
||||
|
||||
public static DimensionPalette receive(FriendlyByteBuf buffer) {
|
||||
DimensionPalette palette = new DimensionPalette();
|
||||
int length = buffer.readInt();
|
||||
for (int i = 0; i < length; i++)
|
||||
palette.gatheredDims.add(ResourceKey.create(Registry.DIMENSION_REGISTRY, buffer.readResourceLocation()));
|
||||
return palette;
|
||||
}
|
||||
|
||||
public void write(CompoundTag tag) {
|
||||
tag.put("DimensionPalette", NBTHelper.writeCompoundList(gatheredDims, rk -> {
|
||||
CompoundTag c = new CompoundTag();
|
||||
c.putString("Id", rk.location()
|
||||
.toString());
|
||||
return c;
|
||||
}));
|
||||
}
|
||||
|
||||
public static DimensionPalette read(CompoundTag tag) {
|
||||
DimensionPalette palette = new DimensionPalette();
|
||||
NBTHelper.iterateCompoundList(tag.getList("DimensionPalette", Tag.TAG_COMPOUND), c -> palette.gatheredDims
|
||||
.add(ResourceKey.create(Registry.DIMENSION_REGISTRY, new ResourceLocation(c.getString("Id")))));
|
||||
return palette;
|
||||
}
|
||||
|
||||
}
|
|
@ -146,8 +146,8 @@ public class GlobalRailwayManager {
|
|||
markTracksDirty();
|
||||
}
|
||||
|
||||
public void updateSplitGraph(TrackGraph graph) {
|
||||
Set<TrackGraph> disconnected = graph.findDisconnectedGraphs(null);
|
||||
public void updateSplitGraph(LevelAccessor level, TrackGraph graph) {
|
||||
Set<TrackGraph> disconnected = graph.findDisconnectedGraphs(level, null);
|
||||
disconnected.forEach(this::putGraphWithDefaultGroup);
|
||||
if (!disconnected.isEmpty()) {
|
||||
sync.graphSplit(graph, disconnected);
|
||||
|
@ -219,6 +219,13 @@ public class GlobalRailwayManager {
|
|||
|
||||
for (Iterator<Train> iterator = waitingTrains.iterator(); iterator.hasNext();) {
|
||||
Train train = iterator.next();
|
||||
|
||||
if (train.invalid) {
|
||||
iterator.remove();
|
||||
trains.remove(train.id);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (train.navigation.waitingForSignal != null)
|
||||
continue;
|
||||
movingTrains.add(train);
|
||||
|
@ -227,11 +234,20 @@ public class GlobalRailwayManager {
|
|||
|
||||
for (Iterator<Train> iterator = movingTrains.iterator(); iterator.hasNext();) {
|
||||
Train train = iterator.next();
|
||||
|
||||
if (train.invalid) {
|
||||
iterator.remove();
|
||||
trains.remove(train.id);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (train.navigation.waitingForSignal == null)
|
||||
continue;
|
||||
waitingTrains.add(train);
|
||||
iterator.remove();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void tickSignalOverlay() {
|
||||
|
|
|
@ -21,7 +21,10 @@ import com.simibubi.create.foundation.utility.Pair;
|
|||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Direction.AxisDirection;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
|
@ -47,8 +50,10 @@ public interface ITrackBlock {
|
|||
return isSlope(world, pos, state) ? .5 : 0;
|
||||
}
|
||||
|
||||
public static Collection<DiscoveredLocation> walkConnectedTracks(BlockGetter world, TrackNodeLocation location,
|
||||
public static Collection<DiscoveredLocation> walkConnectedTracks(BlockGetter worldIn, TrackNodeLocation location,
|
||||
boolean linear) {
|
||||
BlockGetter world = location != null && worldIn instanceof ServerLevel sl ? sl.getServer()
|
||||
.getLevel(location.dimension) : worldIn;
|
||||
List<DiscoveredLocation> list = new ArrayList<>();
|
||||
for (BlockPos blockPos : location.allAdjacent()) {
|
||||
BlockState blockState = world.getBlockState(blockPos);
|
||||
|
@ -58,15 +63,18 @@ public interface ITrackBlock {
|
|||
return list;
|
||||
}
|
||||
|
||||
public default Collection<DiscoveredLocation> getConnected(BlockGetter world, BlockPos pos, BlockState state,
|
||||
public default Collection<DiscoveredLocation> getConnected(BlockGetter worldIn, BlockPos pos, BlockState state,
|
||||
boolean linear, @Nullable TrackNodeLocation connectedTo) {
|
||||
BlockGetter world = connectedTo != null && worldIn instanceof ServerLevel sl ? sl.getServer()
|
||||
.getLevel(connectedTo.dimension) : worldIn;
|
||||
Vec3 center = Vec3.atBottomCenterOf(pos)
|
||||
.add(0, getElevationAtCenter(world, pos, state), 0);
|
||||
List<DiscoveredLocation> list = new ArrayList<>();
|
||||
TrackShape shape = state.getValue(TrackBlock.SHAPE);
|
||||
getTrackAxes(world, pos, state).forEach(axis -> {
|
||||
addToListIfConnected(connectedTo, list, (d, b) -> axis.scale(b ? d : -d)
|
||||
.add(center), b -> shape.getNormal(), axis, null);
|
||||
.add(center), b -> shape.getNormal(), b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD,
|
||||
axis, null);
|
||||
});
|
||||
|
||||
return list;
|
||||
|
@ -74,15 +82,22 @@ public interface ITrackBlock {
|
|||
|
||||
public static void addToListIfConnected(@Nullable TrackNodeLocation fromEnd, Collection<DiscoveredLocation> list,
|
||||
BiFunction<Double, Boolean, Vec3> offsetFactory, Function<Boolean, Vec3> normalFactory,
|
||||
Vec3 axis, BezierConnection viaTurn) {
|
||||
Function<Boolean, ResourceKey<Level>> dimensionFactory, Vec3 axis, BezierConnection viaTurn) {
|
||||
|
||||
DiscoveredLocation firstLocation = new DiscoveredLocation(offsetFactory.apply(0.5d, true)).viaTurn(viaTurn)
|
||||
.withNormal(normalFactory.apply(true))
|
||||
.withDirection(axis);
|
||||
DiscoveredLocation secondLocation = new DiscoveredLocation(offsetFactory.apply(0.5d, false)).viaTurn(viaTurn)
|
||||
.withNormal(normalFactory.apply(false))
|
||||
.withDirection(axis);
|
||||
DiscoveredLocation firstLocation =
|
||||
new DiscoveredLocation(dimensionFactory.apply(true), offsetFactory.apply(0.5d, true)).viaTurn(viaTurn)
|
||||
.withNormal(normalFactory.apply(true))
|
||||
.withDirection(axis);
|
||||
DiscoveredLocation secondLocation =
|
||||
new DiscoveredLocation(dimensionFactory.apply(false), offsetFactory.apply(0.5d, false)).viaTurn(viaTurn)
|
||||
.withNormal(normalFactory.apply(false))
|
||||
.withDirection(axis);
|
||||
|
||||
if (!firstLocation.dimension.equals(secondLocation.dimension)) {
|
||||
firstLocation.forceNode();
|
||||
secondLocation.forceNode();
|
||||
}
|
||||
|
||||
boolean skipFirst = false;
|
||||
boolean skipSecond = false;
|
||||
|
||||
|
|
|
@ -26,14 +26,15 @@ public class RailwaySavedData extends SavedData {
|
|||
public CompoundTag save(CompoundTag nbt) {
|
||||
GlobalRailwayManager railways = Create.RAILWAYS;
|
||||
Create.LOGGER.info("Saving Railway Information...");
|
||||
nbt.put("RailGraphs", NBTHelper.writeCompoundList(railways.trackNetworks.values(), TrackGraph::write));
|
||||
nbt.put("SignalBlocks",
|
||||
NBTHelper.writeCompoundList(railways.signalEdgeGroups.values(), seg -> {
|
||||
if (seg.fallbackGroup && !railways.trackNetworks.containsKey(seg.id))
|
||||
return null;
|
||||
return seg.write();
|
||||
}));
|
||||
nbt.put("Trains", NBTHelper.writeCompoundList(railways.trains.values(), Train::write));
|
||||
DimensionPalette dimensions = new DimensionPalette();
|
||||
nbt.put("RailGraphs", NBTHelper.writeCompoundList(railways.trackNetworks.values(), tg -> tg.write(dimensions)));
|
||||
nbt.put("SignalBlocks", NBTHelper.writeCompoundList(railways.signalEdgeGroups.values(), seg -> {
|
||||
if (seg.fallbackGroup && !railways.trackNetworks.containsKey(seg.id))
|
||||
return null;
|
||||
return seg.write();
|
||||
}));
|
||||
nbt.put("Trains", NBTHelper.writeCompoundList(railways.trains.values(), t -> t.write(dimensions)));
|
||||
dimensions.write(nbt);
|
||||
return nbt;
|
||||
}
|
||||
|
||||
|
@ -44,18 +45,19 @@ public class RailwaySavedData extends SavedData {
|
|||
sd.trains = new HashMap<>();
|
||||
Create.LOGGER.info("Loading Railway Information...");
|
||||
|
||||
DimensionPalette dimensions = DimensionPalette.read(nbt);
|
||||
NBTHelper.iterateCompoundList(nbt.getList("RailGraphs", Tag.TAG_COMPOUND), c -> {
|
||||
TrackGraph graph = TrackGraph.read(c);
|
||||
TrackGraph graph = TrackGraph.read(c, dimensions);
|
||||
sd.trackNetworks.put(graph.id, graph);
|
||||
});
|
||||
NBTHelper.iterateCompoundList(nbt.getList("Trains", Tag.TAG_COMPOUND), c -> {
|
||||
Train train = Train.read(c, sd.trackNetworks);
|
||||
sd.trains.put(train.id, train);
|
||||
});
|
||||
NBTHelper.iterateCompoundList(nbt.getList("SignalBlocks", Tag.TAG_COMPOUND), c -> {
|
||||
SignalEdgeGroup group = SignalEdgeGroup.read(c);
|
||||
sd.signalEdgeGroups.put(group.id, group);
|
||||
});
|
||||
NBTHelper.iterateCompoundList(nbt.getList("Trains", Tag.TAG_COMPOUND), c -> {
|
||||
Train train = Train.read(c, sd.trackNetworks, dimensions);
|
||||
sd.trains.put(train.id, train);
|
||||
});
|
||||
|
||||
for (TrackGraph graph : sd.trackNetworks.values()) {
|
||||
for (SignalBoundary signal : graph.getPoints(EdgePointType.SIGNAL)) {
|
||||
|
|
|
@ -11,7 +11,6 @@ import com.simibubi.create.foundation.utility.VecHelper;
|
|||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction.Axis;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
@ -22,8 +21,10 @@ public class TrackEdge {
|
|||
public TrackNode node2;
|
||||
BezierConnection turn;
|
||||
EdgeData edgeData;
|
||||
boolean interDimensional;
|
||||
|
||||
public TrackEdge(TrackNode node1, TrackNode node2, BezierConnection turn) {
|
||||
this.interDimensional = !node1.location.dimension.equals(node2.location.dimension);
|
||||
this.edgeData = new EdgeData(this);
|
||||
this.node1 = node1;
|
||||
this.node2 = node2;
|
||||
|
@ -34,6 +35,10 @@ public class TrackEdge {
|
|||
return turn != null;
|
||||
}
|
||||
|
||||
public boolean isInterDimensional() {
|
||||
return interDimensional;
|
||||
}
|
||||
|
||||
public EdgeData getEdgeData() {
|
||||
return edgeData;
|
||||
}
|
||||
|
@ -47,15 +52,24 @@ public class TrackEdge {
|
|||
.normalize();
|
||||
}
|
||||
|
||||
public boolean canTravelTo(TrackEdge other) {
|
||||
if (isInterDimensional() || other.isInterDimensional())
|
||||
return true;
|
||||
Vec3 newDirection = other.getDirection(true);
|
||||
return getDirection(false).dot(newDirection) > 7 / 8f;
|
||||
}
|
||||
|
||||
public double getLength() {
|
||||
return isTurn() ? turn.getLength()
|
||||
: node1.location.getLocation()
|
||||
.distanceTo(node2.location.getLocation());
|
||||
return isInterDimensional() ? 0
|
||||
: isTurn() ? turn.getLength()
|
||||
: node1.location.getLocation()
|
||||
.distanceTo(node2.location.getLocation());
|
||||
}
|
||||
|
||||
public double incrementT(double currentT, double distance) {
|
||||
boolean tooFar = Math.abs(distance) > 5;
|
||||
distance = distance / getLength();
|
||||
double length = getLength();
|
||||
distance = distance / (length == 0 ? 1 : length);
|
||||
return !tooFar && isTurn() ? turn.incrementT(currentT, distance) : currentT + distance;
|
||||
}
|
||||
|
||||
|
@ -71,6 +85,8 @@ public class TrackEdge {
|
|||
Vec3 w1 = other1.location.getLocation();
|
||||
Vec3 w2 = other2.location.getLocation();
|
||||
|
||||
if (isInterDimensional() || other.isInterDimensional())
|
||||
return Collections.emptyList();
|
||||
if (v1.y != v2.y || v1.y != w1.y || v1.y != w2.y)
|
||||
return Collections.emptyList();
|
||||
|
||||
|
@ -152,26 +168,17 @@ public class TrackEdge {
|
|||
return isTurn() ? turn.getNormal(Mth.clamp(t, 0, 1)) : node1.getNormal();
|
||||
}
|
||||
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
buffer.writeBoolean(isTurn());
|
||||
if (isTurn())
|
||||
turn.write(buffer);
|
||||
}
|
||||
|
||||
public static TrackEdge read(FriendlyByteBuf buffer) {
|
||||
return new TrackEdge(null, null, buffer.readBoolean() ? new BezierConnection(buffer) : null);
|
||||
}
|
||||
|
||||
public CompoundTag write() {
|
||||
public CompoundTag write(DimensionPalette dimensions) {
|
||||
CompoundTag baseCompound = isTurn() ? turn.write(BlockPos.ZERO) : new CompoundTag();
|
||||
baseCompound.put("Signals", edgeData.write());
|
||||
baseCompound.put("Signals", edgeData.write(dimensions));
|
||||
return baseCompound;
|
||||
}
|
||||
|
||||
public static TrackEdge read(CompoundTag tag, TrackGraph graph) {
|
||||
public static TrackEdge read(TrackNode node1, TrackNode node2, CompoundTag tag, TrackGraph graph,
|
||||
DimensionPalette dimensions) {
|
||||
TrackEdge trackEdge =
|
||||
new TrackEdge(null, null, tag.contains("Positions") ? new BezierConnection(tag, BlockPos.ZERO) : null);
|
||||
trackEdge.edgeData = EdgeData.read(tag.getCompound("Signals"), trackEdge, graph);
|
||||
new TrackEdge(node1, node2, tag.contains("Positions") ? new BezierConnection(tag, BlockPos.ZERO) : null);
|
||||
trackEdge.edgeData = EdgeData.read(tag.getCompound("Signals"), trackEdge, graph, dimensions);
|
||||
return trackEdge;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,10 +31,8 @@ import com.simibubi.create.foundation.utility.Couple;
|
|||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
@ -117,8 +115,8 @@ public class TrackGraph {
|
|||
return nodes.keySet();
|
||||
}
|
||||
|
||||
public TrackNode locateNode(Vec3 position) {
|
||||
return locateNode(new TrackNodeLocation(position));
|
||||
public TrackNode locateNode(Level level, Vec3 position) {
|
||||
return locateNode(new TrackNodeLocation(position).in(level));
|
||||
}
|
||||
|
||||
public TrackNode locateNode(TrackNodeLocation position) {
|
||||
|
@ -269,7 +267,8 @@ public class TrackGraph {
|
|||
}
|
||||
}
|
||||
|
||||
public Set<TrackGraph> findDisconnectedGraphs(@Nullable Map<Integer, UUID> preAssignedIds) {
|
||||
public Set<TrackGraph> findDisconnectedGraphs(@Nullable LevelAccessor level,
|
||||
@Nullable Map<Integer, UUID> preAssignedIds) {
|
||||
Set<TrackGraph> dicovered = new HashSet<>();
|
||||
Set<TrackNodeLocation> vertices = new HashSet<>(nodes.keySet());
|
||||
List<TrackNodeLocation> frontier = new ArrayList<>();
|
||||
|
@ -295,7 +294,7 @@ public class TrackGraph {
|
|||
frontier.add(connected.getLocation());
|
||||
|
||||
if (target != null) {
|
||||
transfer(currentNode, target);
|
||||
transfer(level, currentNode, target);
|
||||
if (preAssignedIds != null && preAssignedIds.containsKey(currentNode.getNetId()))
|
||||
target.setId(preAssignedIds.get(currentNode.getNetId()));
|
||||
}
|
||||
|
@ -313,13 +312,13 @@ public class TrackGraph {
|
|||
color = Color.rainbowColor(new Random(id.getLeastSignificantBits()).nextInt());
|
||||
}
|
||||
|
||||
public void transfer(TrackNode node, TrackGraph target) {
|
||||
public void transfer(LevelAccessor level, TrackNode node, TrackGraph target) {
|
||||
target.addNode(node);
|
||||
target.invalidateBounds();
|
||||
|
||||
TrackNodeLocation nodeLoc = node.getLocation();
|
||||
Map<TrackNode, TrackEdge> connections = getConnectionsFrom(node);
|
||||
Map<UUID, Train> trains = Create.RAILWAYS.trains;
|
||||
Map<UUID, Train> trains = Create.RAILWAYS.sided(level).trains;
|
||||
|
||||
if (!connections.isEmpty()) {
|
||||
target.connectionsByNode.put(node, connections);
|
||||
|
@ -487,7 +486,7 @@ public class TrackGraph {
|
|||
Create.RAILWAYS.markTracksDirty();
|
||||
}
|
||||
|
||||
public CompoundTag write() {
|
||||
public CompoundTag write(DimensionPalette dimensions) {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.putUUID("Id", id);
|
||||
tag.putInt("Color", color.getRGB());
|
||||
|
@ -499,7 +498,8 @@ public class TrackGraph {
|
|||
for (TrackNode railNode : nodes.values()) {
|
||||
indexTracker.put(railNode, i);
|
||||
CompoundTag nodeTag = new CompoundTag();
|
||||
nodeTag.put("Location", NbtUtils.writeBlockPos(new BlockPos(railNode.getLocation())));
|
||||
nodeTag.put("Location", railNode.getLocation()
|
||||
.write(dimensions));
|
||||
nodeTag.put("Normal", VecHelper.writeNBT(railNode.getNormal()));
|
||||
nodesList.add(nodeTag);
|
||||
i++;
|
||||
|
@ -517,21 +517,21 @@ public class TrackGraph {
|
|||
if (index2 == null)
|
||||
return;
|
||||
connectionTag.putInt("To", index2);
|
||||
connectionTag.put("EdgeData", edge.write());
|
||||
connectionTag.put("EdgeData", edge.write(dimensions));
|
||||
connectionsList.add(connectionTag);
|
||||
});
|
||||
nodeTag.put("Connections", connectionsList);
|
||||
});
|
||||
|
||||
tag.put("Nodes", nodesList);
|
||||
tag.put("Points", edgePoints.write());
|
||||
tag.put("Points", edgePoints.write(dimensions));
|
||||
return tag;
|
||||
}
|
||||
|
||||
public static TrackGraph read(CompoundTag tag) {
|
||||
public static TrackGraph read(CompoundTag tag, DimensionPalette dimensions) {
|
||||
TrackGraph graph = new TrackGraph(tag.getUUID("Id"));
|
||||
graph.color = new Color(tag.getInt("Color"));
|
||||
graph.edgePoints.read(tag.getCompound("Points"));
|
||||
graph.edgePoints.read(tag.getCompound("Points"), dimensions);
|
||||
|
||||
Map<Integer, TrackNode> indexTracker = new HashMap<>();
|
||||
ListTag nodesList = tag.getList("Nodes", Tag.TAG_COMPOUND);
|
||||
|
@ -539,8 +539,7 @@ public class TrackGraph {
|
|||
int i = 0;
|
||||
for (Tag t : nodesList) {
|
||||
CompoundTag nodeTag = (CompoundTag) t;
|
||||
TrackNodeLocation location =
|
||||
TrackNodeLocation.fromPackedPos(NbtUtils.readBlockPos(nodeTag.getCompound("Location")));
|
||||
TrackNodeLocation location = TrackNodeLocation.read(nodeTag.getCompound("Location"), dimensions);
|
||||
Vec3 normal = VecHelper.readNBT(nodeTag.getList("Normal", Tag.TAG_DOUBLE));
|
||||
graph.loadNode(location, nextNodeId(), normal);
|
||||
indexTracker.put(i, graph.locateNode(location));
|
||||
|
@ -557,9 +556,7 @@ public class TrackGraph {
|
|||
continue;
|
||||
NBTHelper.iterateCompoundList(nodeTag.getList("Connections", Tag.TAG_COMPOUND), c -> {
|
||||
TrackNode node2 = indexTracker.get(c.getInt("To"));
|
||||
TrackEdge edge = TrackEdge.read(c.getCompound("EdgeData"), graph);
|
||||
edge.node1 = node1;
|
||||
edge.node2 = node2;
|
||||
TrackEdge edge = TrackEdge.read(node1, node2, c.getCompound("EdgeData"), graph, dimensions);
|
||||
graph.putConnection(node1, node2, edge);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ public class TrackGraphHelper {
|
|||
// Case 1: Centre of block lies on a node
|
||||
|
||||
TrackNodeLocation location = new TrackNodeLocation(Vec3.atBottomCenterOf(pos)
|
||||
.add(0, track.getElevationAtCenter(level, pos, trackBlockState), 0));
|
||||
.add(0, track.getElevationAtCenter(level, pos, trackBlockState), 0)).in(level);
|
||||
graph = Create.RAILWAYS.sided(level)
|
||||
.getGraph(level, location);
|
||||
if (graph != null) {
|
||||
|
@ -142,7 +142,7 @@ public class TrackGraphHelper {
|
|||
if (bc == null || !bc.isPrimary())
|
||||
return null;
|
||||
|
||||
TrackNodeLocation targetLoc = new TrackNodeLocation(bc.starts.getSecond());
|
||||
TrackNodeLocation targetLoc = new TrackNodeLocation(bc.starts.getSecond()).in(level);
|
||||
for (DiscoveredLocation location : track.getConnected(level, pos, state, true, null)) {
|
||||
TrackGraph graph = Create.RAILWAYS.sided(level)
|
||||
.getGraph(level, location);
|
||||
|
|
|
@ -46,7 +46,8 @@ public class TrackGraphSync {
|
|||
|
||||
public void edgeAdded(TrackGraph graph, TrackNode node1, TrackNode node2, TrackEdge edge) {
|
||||
flushGraphPacket(graph.id);
|
||||
currentGraphSyncPacket.addedEdges.add(Pair.of(Couple.create(node1.getNetId(), node2.getNetId()), edge));
|
||||
currentGraphSyncPacket.addedEdges
|
||||
.add(Pair.of(Couple.create(node1.getNetId(), node2.getNetId()), edge.getTurn()));
|
||||
}
|
||||
|
||||
public void pointAdded(TrackGraph graph, TrackEdgePoint point) {
|
||||
|
@ -127,7 +128,7 @@ public class TrackGraphSync {
|
|||
graph.connectionsByNode.get(node)
|
||||
.forEach((node2, edge) -> {
|
||||
Couple<Integer> key = Couple.create(node.getNetId(), node2.getNetId());
|
||||
currentPacket.addedEdges.add(Pair.of(key, edge));
|
||||
currentPacket.addedEdges.add(Pair.of(key, edge.getTurn()));
|
||||
currentPacket.syncEdgeData(node, node2, edge);
|
||||
});
|
||||
|
||||
|
|
|
@ -15,14 +15,13 @@ import com.simibubi.create.foundation.utility.Couple;
|
|||
import com.simibubi.create.foundation.utility.Pair;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public class TrackGraphSyncPacket extends TrackGraphPacket {
|
||||
|
||||
Map<Integer, Pair<TrackNodeLocation, Vec3>> addedNodes;
|
||||
List<Pair<Couple<Integer>, TrackEdge>> addedEdges;
|
||||
List<Pair<Couple<Integer>, BezierConnection>> addedEdges;
|
||||
List<Integer> removedNodes;
|
||||
List<TrackEdgePoint> addedEdgePoints;
|
||||
List<UUID> removedEdgePoints;
|
||||
|
@ -52,6 +51,8 @@ public class TrackGraphSyncPacket extends TrackGraphPacket {
|
|||
if (packetDeletesGraph)
|
||||
return;
|
||||
|
||||
DimensionPalette dimensions = DimensionPalette.receive(buffer);
|
||||
|
||||
addedNodes = new HashMap<>();
|
||||
addedEdges = new ArrayList<>();
|
||||
addedEdgePoints = new ArrayList<>();
|
||||
|
@ -67,15 +68,16 @@ public class TrackGraphSyncPacket extends TrackGraphPacket {
|
|||
size = buffer.readVarInt();
|
||||
for (int i = 0; i < size; i++)
|
||||
addedNodes.put(buffer.readVarInt(),
|
||||
Pair.of(TrackNodeLocation.fromPackedPos(buffer.readBlockPos()), VecHelper.read(buffer)));
|
||||
Pair.of(TrackNodeLocation.receive(buffer, dimensions), VecHelper.read(buffer)));
|
||||
|
||||
size = buffer.readVarInt();
|
||||
for (int i = 0; i < size; i++)
|
||||
addedEdges.add(Pair.of(Couple.create(buffer::readVarInt), TrackEdge.read(buffer)));
|
||||
addedEdges.add(
|
||||
Pair.of(Couple.create(buffer::readVarInt), buffer.readBoolean() ? new BezierConnection(buffer) : null));
|
||||
|
||||
size = buffer.readVarInt();
|
||||
for (int i = 0; i < size; i++)
|
||||
addedEdgePoints.add(EdgePointType.read(buffer));
|
||||
addedEdgePoints.add(EdgePointType.read(buffer, dimensions));
|
||||
|
||||
size = buffer.readVarInt();
|
||||
for (int i = 0; i < size; i++)
|
||||
|
@ -99,19 +101,26 @@ public class TrackGraphSyncPacket extends TrackGraphPacket {
|
|||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
|
||||
buffer.writeUUID(graphId);
|
||||
buffer.writeBoolean(packetDeletesGraph);
|
||||
|
||||
if (packetDeletesGraph)
|
||||
return;
|
||||
|
||||
// Populate and send palette ahead of time
|
||||
DimensionPalette dimensions = new DimensionPalette();
|
||||
addedNodes.forEach((node, loc) -> dimensions.encode(loc.getFirst().dimension));
|
||||
addedEdgePoints.forEach(ep -> ep.edgeLocation.forEach(loc -> dimensions.encode(loc.dimension)));
|
||||
dimensions.send(buffer);
|
||||
|
||||
buffer.writeVarInt(removedNodes.size());
|
||||
removedNodes.forEach(buffer::writeVarInt);
|
||||
|
||||
buffer.writeVarInt(addedNodes.size());
|
||||
addedNodes.forEach((node, loc) -> {
|
||||
buffer.writeVarInt(node);
|
||||
buffer.writeBlockPos(new BlockPos(loc.getFirst()));
|
||||
loc.getFirst()
|
||||
.send(buffer, dimensions);
|
||||
VecHelper.write(loc.getSecond(), buffer);
|
||||
});
|
||||
|
||||
|
@ -119,12 +128,14 @@ public class TrackGraphSyncPacket extends TrackGraphPacket {
|
|||
addedEdges.forEach(pair -> {
|
||||
pair.getFirst()
|
||||
.forEach(buffer::writeVarInt);
|
||||
pair.getSecond()
|
||||
.write(buffer);
|
||||
BezierConnection turn = pair.getSecond();
|
||||
buffer.writeBoolean(turn != null);
|
||||
if (turn != null)
|
||||
turn.write(buffer);
|
||||
});
|
||||
|
||||
buffer.writeVarInt(addedEdgePoints.size());
|
||||
addedEdgePoints.forEach(ep -> ep.write(buffer));
|
||||
addedEdgePoints.forEach(ep -> ep.write(buffer, dimensions));
|
||||
|
||||
buffer.writeVarInt(removedEdgePoints.size());
|
||||
removedEdgePoints.forEach(buffer::writeUUID);
|
||||
|
@ -166,17 +177,13 @@ public class TrackGraphSyncPacket extends TrackGraphPacket {
|
|||
graph.loadNode(nodeLocation.getFirst(), nodeId, nodeLocation.getSecond());
|
||||
}
|
||||
|
||||
for (Pair<Couple<Integer>, TrackEdge> pair : addedEdges) {
|
||||
for (Pair<Couple<Integer>, BezierConnection> pair : addedEdges) {
|
||||
Couple<TrackNode> nodes = pair.getFirst()
|
||||
.map(graph::getNode);
|
||||
TrackNode node1 = nodes.getFirst();
|
||||
TrackNode node2 = nodes.getSecond();
|
||||
if (node1 != null && node2 != null) {
|
||||
TrackEdge edge = pair.getSecond();
|
||||
edge.node1 = node1;
|
||||
edge.node2 = node2;
|
||||
graph.putConnection(node1, node2, edge);
|
||||
}
|
||||
if (node1 != null && node2 != null)
|
||||
graph.putConnection(node1, node2, new TrackEdge(node1, node2, pair.getSecond()));
|
||||
}
|
||||
|
||||
for (TrackEdgePoint edgePoint : addedEdgePoints)
|
||||
|
@ -189,7 +196,7 @@ public class TrackGraphSyncPacket extends TrackGraphPacket {
|
|||
handleEdgeData(manager, graph);
|
||||
|
||||
if (!splitSubGraphs.isEmpty())
|
||||
graph.findDisconnectedGraphs(splitSubGraphs)
|
||||
graph.findDisconnectedGraphs(null, splitSubGraphs)
|
||||
.forEach(manager::putGraph);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ import com.simibubi.create.AllKeys;
|
|||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.CreateClient;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgeData;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackEdgeIntersection;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBoundary;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroup;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint;
|
||||
|
@ -51,6 +50,9 @@ public class TrackGraphVisualizer {
|
|||
Vec3 location = nodeLocation.getLocation();
|
||||
if (location.distanceTo(camera) > 50)
|
||||
continue;
|
||||
if (!mc.level.dimension()
|
||||
.equals(nodeLocation.dimension))
|
||||
continue;
|
||||
|
||||
Map<TrackNode, TrackEdge> map = graph.connectionsByNode.get(node);
|
||||
if (map == null)
|
||||
|
@ -62,16 +64,8 @@ public class TrackGraphVisualizer {
|
|||
TrackEdge edge = entry.getValue();
|
||||
EdgeData signalData = edge.getEdgeData();
|
||||
|
||||
// temporary
|
||||
if (other.hashCode() > hashCode == ctrl)
|
||||
for (TrackEdgeIntersection intersection : signalData.getIntersections()) {
|
||||
Vec3 v1 = edge.getPosition(intersection.location / edge.getLength());
|
||||
Vec3 v2 = v1.add(node.normal.scale(8 / 16f));
|
||||
outliner.showLine(intersection, v1, v2)
|
||||
.colored(Color.mixColors(Color.WHITE, graph.color, 1))
|
||||
.lineWidth(width);
|
||||
} //
|
||||
|
||||
if (!edge.node1.location.dimension.equals(edge.node2.location.dimension))
|
||||
continue;
|
||||
if (other.hashCode() > hashCode && !ctrl)
|
||||
continue;
|
||||
|
||||
|
@ -234,6 +228,9 @@ public class TrackGraphVisualizer {
|
|||
Vec3 location = nodeLocation.getLocation();
|
||||
if (location.distanceTo(camera) > 50)
|
||||
continue;
|
||||
if (!mc.level.dimension()
|
||||
.equals(nodeLocation.dimension))
|
||||
continue;
|
||||
|
||||
Vec3 yOffset = new Vec3(0, 3 / 16f, 0);
|
||||
Vec3 v1 = location.add(yOffset);
|
||||
|
@ -249,12 +246,20 @@ public class TrackGraphVisualizer {
|
|||
int hashCode = node.hashCode();
|
||||
for (Entry<TrackNode, TrackEdge> entry : map.entrySet()) {
|
||||
TrackNode other = entry.getKey();
|
||||
TrackEdge edge = entry.getValue();
|
||||
|
||||
if (!edge.node1.location.dimension.equals(edge.node2.location.dimension)) {
|
||||
v1 = location.add(yOffset);
|
||||
v2 = v1.add(node.normal.scale(3 / 16f));
|
||||
CreateClient.OUTLINER.showLine(Integer.valueOf(node.netId), v1, v2)
|
||||
.colored(Color.mixColors(Color.WHITE, graph.color, 1))
|
||||
.lineWidth(1 / 4f);
|
||||
continue;
|
||||
}
|
||||
if (other.hashCode() > hashCode && !AllKeys.isKeyDown(GLFW.GLFW_KEY_LEFT_CONTROL))
|
||||
continue;
|
||||
yOffset = new Vec3(0, (other.hashCode() > hashCode ? 6 : 4) / 16f, 0);
|
||||
|
||||
TrackEdge edge = entry.getValue();
|
||||
yOffset = new Vec3(0, (other.hashCode() > hashCode ? 6 : 4) / 16f, 0);
|
||||
if (!edge.isTurn()) {
|
||||
CreateClient.OUTLINER.showLine(edge, edge.getPosition(0)
|
||||
.add(yOffset),
|
||||
|
|
|
@ -2,16 +2,24 @@ package com.simibubi.create.content.logistics.trains;
|
|||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Vec3i;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public class TrackNodeLocation extends Vec3i {
|
||||
|
||||
public ResourceKey<Level> dimension;
|
||||
|
||||
public TrackNodeLocation(Vec3 vec) {
|
||||
this(vec.x, vec.y, vec.z);
|
||||
}
|
||||
|
@ -20,7 +28,16 @@ public class TrackNodeLocation extends Vec3i {
|
|||
super(Math.round(p_121865_ * 2), Math.floor(p_121866_ * 2), Math.round(p_121867_ * 2));
|
||||
}
|
||||
|
||||
public static TrackNodeLocation fromPackedPos(BlockPos bufferPos) {
|
||||
public TrackNodeLocation in(Level level) {
|
||||
return in(level.dimension());
|
||||
}
|
||||
|
||||
public TrackNodeLocation in(ResourceKey<Level> dimension) {
|
||||
this.dimension = dimension;
|
||||
return this;
|
||||
}
|
||||
|
||||
private static TrackNodeLocation fromPackedPos(BlockPos bufferPos) {
|
||||
return new TrackNodeLocation(bufferPos);
|
||||
}
|
||||
|
||||
|
@ -32,14 +49,44 @@ public class TrackNodeLocation extends Vec3i {
|
|||
return new Vec3(getX() / 2f, getY() / 2f, getZ() / 2f);
|
||||
}
|
||||
|
||||
public ResourceKey<Level> getDimension() {
|
||||
return dimension;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object pOther) {
|
||||
return super.equals(pOther);
|
||||
return super.equals(pOther) && pOther instanceof TrackNodeLocation tnl
|
||||
&& Objects.equals(tnl.dimension, dimension);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (this.getY() + this.getZ() * 31) * 31 + this.getX();
|
||||
return (this.getY() + (this.getZ() * 31 + dimension.hashCode()) * 31) * 31 + this.getX();
|
||||
}
|
||||
|
||||
public CompoundTag write(DimensionPalette dimensions) {
|
||||
CompoundTag c = NbtUtils.writeBlockPos(new BlockPos(this));
|
||||
if (dimensions != null)
|
||||
c.putInt("D", dimensions.encode(dimension));
|
||||
return c;
|
||||
}
|
||||
|
||||
public static TrackNodeLocation read(CompoundTag tag, DimensionPalette dimensions) {
|
||||
TrackNodeLocation location = fromPackedPos(NbtUtils.readBlockPos(tag));
|
||||
if (dimensions != null)
|
||||
location.dimension = dimensions.decode(tag.getInt("D"));
|
||||
return location;
|
||||
}
|
||||
|
||||
public void send(FriendlyByteBuf buffer, DimensionPalette dimensions) {
|
||||
buffer.writeBlockPos(new BlockPos(this));
|
||||
buffer.writeVarInt(dimensions.encode(dimension));
|
||||
}
|
||||
|
||||
public static TrackNodeLocation receive(FriendlyByteBuf buffer, DimensionPalette dimensions) {
|
||||
TrackNodeLocation location = fromPackedPos(buffer.readBlockPos());
|
||||
location.dimension = dimensions.decode(buffer.readVarInt());
|
||||
return location;
|
||||
}
|
||||
|
||||
public Collection<BlockPos> allAdjacent() {
|
||||
|
@ -60,12 +107,18 @@ public class TrackNodeLocation extends Vec3i {
|
|||
Vec3 direction;
|
||||
Vec3 normal;
|
||||
|
||||
public DiscoveredLocation(double p_121865_, double p_121866_, double p_121867_) {
|
||||
public DiscoveredLocation(Level level, double p_121865_, double p_121866_, double p_121867_) {
|
||||
super(p_121865_, p_121866_, p_121867_);
|
||||
in(level);
|
||||
}
|
||||
|
||||
public DiscoveredLocation(Vec3 vec) {
|
||||
public DiscoveredLocation(ResourceKey<Level> dimension, Vec3 vec) {
|
||||
super(vec);
|
||||
in(dimension);
|
||||
}
|
||||
|
||||
public DiscoveredLocation(Level level, Vec3 vec) {
|
||||
this(level.dimension(), vec);
|
||||
}
|
||||
|
||||
public DiscoveredLocation viaTurn(BezierConnection turn) {
|
||||
|
|
|
@ -73,7 +73,7 @@ public class TrackPropagator {
|
|||
// 3. Ensure any affected graph gets checked for segmentation
|
||||
|
||||
for (TrackGraph railGraph : toUpdate)
|
||||
manager.updateSplitGraph(railGraph);
|
||||
manager.updateSplitGraph(reader, railGraph);
|
||||
|
||||
manager.markTracksDirty();
|
||||
}
|
||||
|
@ -235,9 +235,9 @@ public class TrackPropagator {
|
|||
if (location.shouldForceNode())
|
||||
return true;
|
||||
if (next.stream()
|
||||
.anyMatch(DiscoveredLocation::connectedViaTurn))
|
||||
.anyMatch(DiscoveredLocation::shouldForceNode))
|
||||
return true;
|
||||
|
||||
|
||||
Vec3 direction = location.direction;
|
||||
if (direction != null && next.stream()
|
||||
.anyMatch(dl -> dl.notInLineWith(direction)))
|
||||
|
|
|
@ -29,10 +29,10 @@ public sealed class BogeyInstance {
|
|||
shafts = new ModelData[2];
|
||||
|
||||
materialManager.defaultSolid()
|
||||
.material(Materials.TRANSFORMED)
|
||||
.getModel(AllBlocks.SHAFT.getDefaultState()
|
||||
.setValue(ShaftBlock.AXIS, Direction.Axis.Z))
|
||||
.createInstances(shafts);
|
||||
.material(Materials.TRANSFORMED)
|
||||
.getModel(AllBlocks.SHAFT.getDefaultState()
|
||||
.setValue(ShaftBlock.AXIS, Direction.Axis.Z))
|
||||
.createInstances(shafts);
|
||||
|
||||
}
|
||||
|
||||
|
@ -41,14 +41,23 @@ public sealed class BogeyInstance {
|
|||
shaft.delete();
|
||||
}
|
||||
|
||||
public void hiddenFrame() {
|
||||
beginFrame(0, null);
|
||||
}
|
||||
|
||||
public void beginFrame(float wheelAngle, PoseStack ms) {
|
||||
if (ms == null) {
|
||||
for (int i : Iterate.zeroAndOne)
|
||||
shafts[i].setEmptyTransform();
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i : Iterate.zeroAndOne)
|
||||
shafts[i].setTransform(ms)
|
||||
.translate(-.5f, .25f, i * -1)
|
||||
.centre()
|
||||
.rotateZ(wheelAngle)
|
||||
.unCentre();
|
||||
.translate(-.5f, .25f, i * -1)
|
||||
.centre()
|
||||
.rotateZ(wheelAngle)
|
||||
.unCentre();
|
||||
}
|
||||
|
||||
public void updateLight(BlockAndTintGetter world, CarriageContraptionEntity entity) {
|
||||
|
@ -67,7 +76,8 @@ public sealed class BogeyInstance {
|
|||
|
||||
public void updateLight(int blockLight, int skyLight) {
|
||||
for (ModelData shaft : shafts) {
|
||||
shaft.setBlockLight(blockLight).setSkyLight(skyLight);
|
||||
shaft.setBlockLight(blockLight)
|
||||
.setSkyLight(skyLight);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,37 +90,46 @@ public sealed class BogeyInstance {
|
|||
super(bogey, materialManager);
|
||||
|
||||
frame = materialManager.defaultSolid()
|
||||
.material(Materials.TRANSFORMED)
|
||||
.getModel(AllBlockPartials.BOGEY_FRAME)
|
||||
.createInstance();
|
||||
.material(Materials.TRANSFORMED)
|
||||
.getModel(AllBlockPartials.BOGEY_FRAME)
|
||||
.createInstance();
|
||||
|
||||
wheels = new ModelData[2];
|
||||
|
||||
materialManager.defaultSolid()
|
||||
.material(Materials.TRANSFORMED)
|
||||
.getModel(AllBlockPartials.SMALL_BOGEY_WHEELS)
|
||||
.createInstances(wheels);
|
||||
.material(Materials.TRANSFORMED)
|
||||
.getModel(AllBlockPartials.SMALL_BOGEY_WHEELS)
|
||||
.createInstances(wheels);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginFrame(float wheelAngle, PoseStack ms) {
|
||||
super.beginFrame(wheelAngle, ms);
|
||||
|
||||
if (ms == null) {
|
||||
frame.setEmptyTransform();
|
||||
for (int side : Iterate.positiveAndNegative)
|
||||
wheels[(side + 1) / 2].setEmptyTransform();
|
||||
return;
|
||||
}
|
||||
|
||||
frame.setTransform(ms);
|
||||
|
||||
for (int side : Iterate.positiveAndNegative) {
|
||||
wheels[(side + 1) / 2].setTransform(ms)
|
||||
.translate(0, 12 / 16f, side)
|
||||
.rotateX(wheelAngle);
|
||||
.translate(0, 12 / 16f, side)
|
||||
.rotateX(wheelAngle);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLight(int blockLight, int skyLight) {
|
||||
super.updateLight(blockLight, skyLight);
|
||||
frame.setBlockLight(blockLight).setSkyLight(skyLight);
|
||||
frame.setBlockLight(blockLight)
|
||||
.setSkyLight(skyLight);
|
||||
for (ModelData wheel : wheels)
|
||||
wheel.setBlockLight(blockLight).setSkyLight(skyLight);
|
||||
wheel.setBlockLight(blockLight)
|
||||
.setSkyLight(skyLight);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -133,58 +152,73 @@ public sealed class BogeyInstance {
|
|||
public Drive(CarriageBogey bogey, MaterialManager materialManager) {
|
||||
super(bogey, materialManager);
|
||||
Material<ModelData> mat = materialManager.defaultSolid()
|
||||
.material(Materials.TRANSFORMED);
|
||||
.material(Materials.TRANSFORMED);
|
||||
|
||||
secondShaft = new ModelData[2];
|
||||
|
||||
mat.getModel(AllBlocks.SHAFT.getDefaultState()
|
||||
.setValue(ShaftBlock.AXIS, Direction.Axis.X))
|
||||
.createInstances(secondShaft);
|
||||
.setValue(ShaftBlock.AXIS, Direction.Axis.X))
|
||||
.createInstances(secondShaft);
|
||||
|
||||
drive = mat.getModel(AllBlockPartials.BOGEY_DRIVE)
|
||||
.createInstance();
|
||||
.createInstance();
|
||||
piston = mat.getModel(AllBlockPartials.BOGEY_PISTON)
|
||||
.createInstance();
|
||||
.createInstance();
|
||||
wheels = mat.getModel(AllBlockPartials.LARGE_BOGEY_WHEELS)
|
||||
.createInstance();
|
||||
.createInstance();
|
||||
pin = mat.getModel(AllBlockPartials.BOGEY_PIN)
|
||||
.createInstance();
|
||||
.createInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginFrame(float wheelAngle, PoseStack ms) {
|
||||
super.beginFrame(wheelAngle, ms);
|
||||
|
||||
if (ms == null) {
|
||||
for (int i : Iterate.zeroAndOne)
|
||||
secondShaft[i].setEmptyTransform();
|
||||
drive.setEmptyTransform();
|
||||
piston.setEmptyTransform();
|
||||
wheels.setEmptyTransform();
|
||||
pin.setEmptyTransform();
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i : Iterate.zeroAndOne)
|
||||
secondShaft[i].setTransform(ms)
|
||||
.translate(-.5f, .25f, .5f + i * -2)
|
||||
.centre()
|
||||
.rotateX(wheelAngle)
|
||||
.unCentre();
|
||||
.translate(-.5f, .25f, .5f + i * -2)
|
||||
.centre()
|
||||
.rotateX(wheelAngle)
|
||||
.unCentre();
|
||||
|
||||
drive.setTransform(ms);
|
||||
piston.setTransform(ms)
|
||||
.translate(0, 0, 1 / 4f * Math.sin(AngleHelper.rad(wheelAngle)));
|
||||
.translate(0, 0, 1 / 4f * Math.sin(AngleHelper.rad(wheelAngle)));
|
||||
|
||||
wheels.setTransform(ms)
|
||||
.translate(0, 1, 0)
|
||||
.rotateX(wheelAngle);
|
||||
.translate(0, 1, 0)
|
||||
.rotateX(wheelAngle);
|
||||
pin.setTransform(ms)
|
||||
.translate(0, 1, 0)
|
||||
.rotateX(wheelAngle)
|
||||
.translate(0, 1 / 4f, 0)
|
||||
.rotateX(-wheelAngle);
|
||||
.translate(0, 1, 0)
|
||||
.rotateX(wheelAngle)
|
||||
.translate(0, 1 / 4f, 0)
|
||||
.rotateX(-wheelAngle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLight(int blockLight, int skyLight) {
|
||||
super.updateLight(blockLight, skyLight);
|
||||
for (ModelData shaft : secondShaft)
|
||||
shaft.setBlockLight(blockLight).setSkyLight(skyLight);
|
||||
drive.setBlockLight(blockLight).setSkyLight(skyLight);
|
||||
piston.setBlockLight(blockLight).setSkyLight(skyLight);
|
||||
wheels.setBlockLight(blockLight).setSkyLight(skyLight);
|
||||
pin.setBlockLight(blockLight).setSkyLight(skyLight);
|
||||
shaft.setBlockLight(blockLight)
|
||||
.setSkyLight(skyLight);
|
||||
drive.setBlockLight(blockLight)
|
||||
.setSkyLight(skyLight);
|
||||
piston.setBlockLight(blockLight)
|
||||
.setSkyLight(skyLight);
|
||||
wheels.setBlockLight(blockLight)
|
||||
.setSkyLight(skyLight);
|
||||
pin.setBlockLight(blockLight)
|
||||
.setSkyLight(skyLight);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -2,25 +2,41 @@ package com.simibubi.create.content.logistics.trains.entity;
|
|||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.commons.lang3.mutable.MutableDouble;
|
||||
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher;
|
||||
import com.simibubi.create.content.logistics.trains.DimensionPalette;
|
||||
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNodeLocation;
|
||||
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.IEdgePointListener;
|
||||
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ITrackSelector;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.Entity.RemovalReason;
|
||||
|
@ -28,6 +44,9 @@ import net.minecraft.world.entity.EntityType;
|
|||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
|
||||
public class Carriage {
|
||||
|
||||
|
@ -42,29 +61,21 @@ public class Carriage {
|
|||
public int bogeySpacing;
|
||||
public Couple<CarriageBogey> bogeys;
|
||||
|
||||
public Vec3 positionAnchor;
|
||||
public Couple<Vec3> rotationAnchors;
|
||||
|
||||
CompoundTag serialisedEntity;
|
||||
WeakReference<CarriageContraptionEntity> entity;
|
||||
|
||||
// client
|
||||
public boolean pointsInitialised;
|
||||
Map<Integer, CompoundTag> serialisedPassengers;
|
||||
|
||||
private Map<ResourceKey<Level>, DimensionalCarriageEntity> entities;
|
||||
|
||||
static final int FIRST = 0, MIDDLE = 1, LAST = 2, BOTH = 3;
|
||||
|
||||
public Carriage(CarriageBogey bogey1, @Nullable CarriageBogey bogey2, int bogeySpacing) {
|
||||
this.bogeySpacing = bogeySpacing;
|
||||
this.bogeys = Couple.create(bogey1, bogey2);
|
||||
this.entity = new WeakReference<>(null);
|
||||
this.id = netIdGenerator.incrementAndGet();
|
||||
this.serialisedEntity = new CompoundTag();
|
||||
this.pointsInitialised = false;
|
||||
this.rotationAnchors = Couple.create(null, null);
|
||||
this.presentConductors = Couple.create(false, false);
|
||||
|
||||
updateContraptionAnchors();
|
||||
this.serialisedPassengers = new HashMap<>();
|
||||
this.entities = new HashMap<>();
|
||||
|
||||
bogey1.setLeading();
|
||||
bogey1.carriage = this;
|
||||
|
@ -76,13 +87,18 @@ public class Carriage {
|
|||
this.train = train;
|
||||
}
|
||||
|
||||
public boolean presentInMultipleDimensions() {
|
||||
return entities.size() > 1;
|
||||
}
|
||||
|
||||
public void setContraption(Level level, CarriageContraption contraption) {
|
||||
CarriageContraptionEntity entity = CarriageContraptionEntity.create(level, contraption);
|
||||
entity.setCarriage(this);
|
||||
contraption.startMoving(level);
|
||||
contraption.onEntityInitialize(level, entity);
|
||||
updateContraptionAnchors();
|
||||
alignEntity(entity);
|
||||
|
||||
getDimensional(level).alignEntity(entity);
|
||||
|
||||
List<Entity> players = new ArrayList<>();
|
||||
for (Entity passenger : entity.getPassengers())
|
||||
|
@ -96,11 +112,24 @@ public class Carriage {
|
|||
serialisedEntity = entity.serializeNBT();
|
||||
}
|
||||
|
||||
public DimensionalCarriageEntity getDimensional(Level level) {
|
||||
return getDimensional(level.dimension());
|
||||
}
|
||||
|
||||
public DimensionalCarriageEntity getDimensional(ResourceKey<Level> dimension) {
|
||||
return entities.computeIfAbsent(dimension, $ -> new DimensionalCarriageEntity());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public DimensionalCarriageEntity getDimensionalIfPresent(ResourceKey<Level> dimension) {
|
||||
return entities.get(dimension);
|
||||
}
|
||||
|
||||
public double travel(Level level, TrackGraph graph, double distance,
|
||||
Function<TravellingPoint, ITrackSelector> forwardControl,
|
||||
Function<TravellingPoint, ITrackSelector> backwardControl, int type) {
|
||||
boolean onTwoBogeys = isOnTwoBogeys();
|
||||
double stress = onTwoBogeys ? bogeySpacing - leadingAnchor().distanceTo(trailingAnchor()) : 0;
|
||||
double stress = onTwoBogeys ? bogeySpacing - getAnchorDiff() : 0;
|
||||
blocked = false;
|
||||
|
||||
MutableDouble distanceMoved = new MutableDouble(distance);
|
||||
|
@ -140,12 +169,23 @@ public class Carriage {
|
|||
IEdgePointListener passiveListener = point.ignoreEdgePoints();
|
||||
|
||||
toMove += correction + bogeyCorrection;
|
||||
double moved =
|
||||
point
|
||||
.travel(graph, toMove, toMove > 0 ? frontTrackSelector : backTrackSelector,
|
||||
toMove > 0 ? atFront ? frontListener : atBack ? backListener : passiveListener
|
||||
: atFront ? backListener : atBack ? frontListener : passiveListener,
|
||||
point.ignoreTurns());
|
||||
|
||||
ITrackSelector trackSelector = toMove > 0 ? frontTrackSelector : backTrackSelector;
|
||||
IEdgePointListener signalListener =
|
||||
toMove > 0 ? atFront ? frontListener : atBack ? backListener : passiveListener
|
||||
: atFront ? backListener : atBack ? frontListener : passiveListener;
|
||||
|
||||
double moved = point.travel(graph, toMove, trackSelector, signalListener, point.ignoreTurns(), c -> {
|
||||
for (DimensionalCarriageEntity dce : entities.values())
|
||||
if (c.either(tnl -> tnl.equals(dce.pivot)))
|
||||
return false;
|
||||
if (entities.size() > 1) {
|
||||
train.status.doublePortal();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
blocked |= point.blocked;
|
||||
|
||||
distanceMoved.setValue(moved);
|
||||
|
@ -153,98 +193,185 @@ public class Carriage {
|
|||
}
|
||||
|
||||
updateContraptionAnchors();
|
||||
manageEntity(level);
|
||||
manageEntities(level);
|
||||
return distanceMoved.getValue();
|
||||
}
|
||||
|
||||
public void updateConductors() {
|
||||
CarriageContraptionEntity entity = this.entity.get();
|
||||
if (entity != null && entity.isAlive())
|
||||
presentConductors = entity.checkConductors();
|
||||
private double getAnchorDiff() {
|
||||
double diff = 0;
|
||||
int entries = 0;
|
||||
|
||||
TravellingPoint leadingPoint = getLeadingPoint();
|
||||
TravellingPoint trailingPoint = getTrailingPoint();
|
||||
if (leadingPoint.node1 != null && trailingPoint.node1 != null)
|
||||
if (!leadingPoint.node1.getLocation().dimension.equals(trailingPoint.node1.getLocation().dimension))
|
||||
return bogeySpacing;
|
||||
|
||||
for (DimensionalCarriageEntity dce : entities.values())
|
||||
if (dce.leadingAnchor() != null && dce.trailingAnchor() != null) {
|
||||
entries++;
|
||||
diff += dce.leadingAnchor()
|
||||
.distanceTo(dce.trailingAnchor());
|
||||
}
|
||||
|
||||
if (entries == 0)
|
||||
return bogeySpacing;
|
||||
return diff / entries;
|
||||
}
|
||||
|
||||
public void createEntity(Level level) {
|
||||
Entity entity = EntityType.loadEntityRecursive(serialisedEntity, level, e -> {
|
||||
e.moveTo(positionAnchor);
|
||||
return e;
|
||||
public void updateConductors() {
|
||||
if (anyAvailableEntity() == null || entities.size() > 1)
|
||||
return;
|
||||
presentConductors.replace($ -> false);
|
||||
for (DimensionalCarriageEntity dimensionalCarriageEntity : entities.values()) {
|
||||
CarriageContraptionEntity entity = dimensionalCarriageEntity.entity.get();
|
||||
if (entity != null && entity.isAlive())
|
||||
presentConductors.replaceWithParams((current, checked) -> current || checked, entity.checkConductors());
|
||||
}
|
||||
}
|
||||
|
||||
private Set<ResourceKey<Level>> currentlyTraversedDimensions = new HashSet<>();
|
||||
|
||||
public void manageEntities(Level level) {
|
||||
currentlyTraversedDimensions.clear();
|
||||
|
||||
bogeys.forEach(cb -> {
|
||||
if (cb == null)
|
||||
return;
|
||||
cb.points.forEach(tp -> {
|
||||
if (tp.node1 == null)
|
||||
return;
|
||||
currentlyTraversedDimensions.add(tp.node1.getLocation().dimension);
|
||||
});
|
||||
});
|
||||
|
||||
if (!(entity instanceof CarriageContraptionEntity cce))
|
||||
return;
|
||||
for (Iterator<Entry<ResourceKey<Level>, DimensionalCarriageEntity>> iterator = entities.entrySet()
|
||||
.iterator(); iterator.hasNext();) {
|
||||
Entry<ResourceKey<Level>, DimensionalCarriageEntity> entry = iterator.next();
|
||||
|
||||
cce.setGraph(train.graph == null ? null : train.graph.id);
|
||||
cce.setCarriage(this);
|
||||
cce.syncCarriage();
|
||||
boolean discard =
|
||||
!currentlyTraversedDimensions.isEmpty() && !currentlyTraversedDimensions.contains(entry.getKey());
|
||||
ServerLevel currentLevel = level.getServer()
|
||||
.getLevel(entry.getKey());
|
||||
if (currentLevel == null)
|
||||
continue;
|
||||
|
||||
this.entity = new WeakReference<>(cce);
|
||||
DimensionalCarriageEntity dimensionalCarriageEntity = entry.getValue();
|
||||
CarriageContraptionEntity entity = dimensionalCarriageEntity.entity.get();
|
||||
|
||||
if (level instanceof ServerLevel sl)
|
||||
sl.tryAddFreshEntityWithPassengers(entity);
|
||||
}
|
||||
if (entity == null) {
|
||||
if (discard)
|
||||
iterator.remove();
|
||||
else if (dimensionalCarriageEntity.positionAnchor != null && CarriageEntityHandler
|
||||
.isActiveChunk(currentLevel, new BlockPos(dimensionalCarriageEntity.positionAnchor)))
|
||||
dimensionalCarriageEntity.createEntity(currentLevel, anyAvailableEntity() == null);
|
||||
|
||||
public void manageEntity(Level level) {
|
||||
CarriageContraptionEntity entity = this.entity.get();
|
||||
if (entity == null) {
|
||||
if (CarriageEntityHandler.isActiveChunk(level, new BlockPos(positionAnchor)))
|
||||
createEntity(level);
|
||||
} else {
|
||||
CarriageEntityHandler.validateCarriageEntity(entity);
|
||||
if (!entity.isAlive() || entity.leftTickingChunks) {
|
||||
removeAndSaveEntity(entity);
|
||||
return;
|
||||
} else {
|
||||
if (discard) {
|
||||
discard = dimensionalCarriageEntity.discardTicks > 3;
|
||||
dimensionalCarriageEntity.discardTicks++;
|
||||
} else
|
||||
dimensionalCarriageEntity.discardTicks = 0;
|
||||
|
||||
CarriageEntityHandler.validateCarriageEntity(entity);
|
||||
if (!entity.isAlive() || entity.leftTickingChunks || discard) {
|
||||
dimensionalCarriageEntity.removeAndSaveEntity(entity, discard);
|
||||
if (discard)
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
entity = dimensionalCarriageEntity.entity.get();
|
||||
if (entity != null && dimensionalCarriageEntity.positionAnchor != null) {
|
||||
dimensionalCarriageEntity.alignEntity(entity);
|
||||
entity.syncCarriage();
|
||||
}
|
||||
}
|
||||
|
||||
entity = this.entity.get();
|
||||
if (entity == null)
|
||||
return;
|
||||
|
||||
alignEntity(entity);
|
||||
entity.syncCarriage();
|
||||
}
|
||||
|
||||
private void removeAndSaveEntity(CarriageContraptionEntity entity) {
|
||||
serialisedEntity = entity.serializeNBT();
|
||||
|
||||
for (Entity passenger : entity.getPassengers())
|
||||
if (!(passenger instanceof Player))
|
||||
passenger.discard();
|
||||
entity.discard();
|
||||
|
||||
this.entity.clear();
|
||||
}
|
||||
|
||||
public void updateContraptionAnchors() {
|
||||
CarriageBogey leadingBogey = leadingBogey();
|
||||
if (leadingBogey.points.either(t -> t.edge == null))
|
||||
return;
|
||||
positionAnchor = leadingBogey.getAnchorPosition();
|
||||
rotationAnchors = bogeys.mapWithContext((b, first) -> isOnTwoBogeys() ? b.getAnchorPosition()
|
||||
: leadingBogey.points.get(first)
|
||||
.getPosition());
|
||||
CarriageBogey trailingBogey = trailingBogey();
|
||||
if (trailingBogey.points.either(t -> t.edge == null))
|
||||
return;
|
||||
|
||||
ResourceKey<Level> leadingBogeyDim = leadingBogey.getDimension();
|
||||
ResourceKey<Level> trailingBogeyDim = trailingBogey.getDimension();
|
||||
double leadingWheelSpacing = leadingBogey.type.getWheelPointSpacing();
|
||||
double trailingWheelSpacing = trailingBogey.type.getWheelPointSpacing();
|
||||
|
||||
for (boolean leading : Iterate.trueAndFalse) {
|
||||
TravellingPoint point = leading ? getLeadingPoint() : getTrailingPoint();
|
||||
TravellingPoint otherPoint = !leading ? getLeadingPoint() : getTrailingPoint();
|
||||
ResourceKey<Level> dimension = point.node1.getLocation().dimension;
|
||||
ResourceKey<Level> otherDimension = otherPoint.node1.getLocation().dimension;
|
||||
|
||||
if (dimension.equals(otherDimension) && leading) {
|
||||
getDimensional(dimension).discardPivot();
|
||||
continue;
|
||||
}
|
||||
|
||||
DimensionalCarriageEntity dce = getDimensional(dimension);
|
||||
|
||||
dce.positionAnchor = dimension.equals(leadingBogeyDim) ? leadingBogey.getAnchorPosition()
|
||||
: pivoted(dce, dimension, point,
|
||||
leading ? leadingWheelSpacing / 2 : bogeySpacing + trailingWheelSpacing / 2);
|
||||
|
||||
int prevmin = dce.minAllowedLocalCoord();
|
||||
int prevmax = dce.maxAllowedLocalCoord();
|
||||
|
||||
dce.updateCutoff(leading);
|
||||
if (prevmin != dce.minAllowedLocalCoord() || prevmax != dce.maxAllowedLocalCoord()) {
|
||||
dce.updateRenderedCutoff();
|
||||
dce.updatePassengerLoadout();
|
||||
}
|
||||
|
||||
if (isOnTwoBogeys()) {
|
||||
dce.rotationAnchors.setFirst(dimension.equals(leadingBogeyDim) ? leadingBogey.getAnchorPosition()
|
||||
: pivoted(dce, dimension, point,
|
||||
leading ? leadingWheelSpacing / 2 : bogeySpacing + trailingWheelSpacing / 2));
|
||||
dce.rotationAnchors.setSecond(dimension.equals(trailingBogeyDim) ? trailingBogey.getAnchorPosition()
|
||||
: pivoted(dce, dimension, point,
|
||||
leading ? leadingWheelSpacing / 2 + bogeySpacing : trailingWheelSpacing / 2));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dimension.equals(otherDimension)) {
|
||||
dce.rotationAnchors = leadingBogey.points.map(TravellingPoint::getPosition);
|
||||
continue;
|
||||
}
|
||||
|
||||
dce.rotationAnchors.setFirst(leadingBogey.points.getFirst() == point ? point.getPosition()
|
||||
: pivoted(dce, dimension, point, leadingWheelSpacing));
|
||||
dce.rotationAnchors.setSecond(leadingBogey.points.getSecond() == point ? point.getPosition()
|
||||
: pivoted(dce, dimension, point, leadingWheelSpacing));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void alignEntity(CarriageContraptionEntity entity) {
|
||||
Vec3 positionVec = rotationAnchors.getFirst();
|
||||
Vec3 coupledVec = rotationAnchors.getSecond();
|
||||
private Vec3 pivoted(DimensionalCarriageEntity dce, ResourceKey<Level> dimension, TravellingPoint start,
|
||||
double offset) {
|
||||
if (train.graph == null)
|
||||
return dce.pivot == null ? null : dce.pivot.getLocation();
|
||||
TrackNodeLocation pivot = dce.findPivot(dimension, start == getLeadingPoint());
|
||||
if (pivot == null)
|
||||
return null;
|
||||
Vec3 startVec = start.getPosition();
|
||||
Vec3 portalVec = pivot.getLocation()
|
||||
.add(0, 1, 0);
|
||||
return VecHelper.lerp((float) (offset / startVec.distanceTo(portalVec)), startVec, portalVec);
|
||||
}
|
||||
|
||||
double diffX = positionVec.x - coupledVec.x;
|
||||
double diffY = positionVec.y - coupledVec.y;
|
||||
double diffZ = positionVec.z - coupledVec.z;
|
||||
|
||||
entity.setPos(positionAnchor);
|
||||
entity.prevYaw = entity.yaw;
|
||||
entity.prevPitch = entity.pitch;
|
||||
|
||||
entity.yaw = (float) (Mth.atan2(diffZ, diffX) * 180 / Math.PI) + 180;
|
||||
entity.pitch = (float) (Math.atan2(diffY, Math.sqrt(diffX * diffX + diffZ * diffZ)) * 180 / Math.PI) * -1;
|
||||
|
||||
if (entity.firstPositionUpdate) {
|
||||
entity.xo = entity.getX();
|
||||
entity.yo = entity.getY();
|
||||
entity.zo = entity.getZ();
|
||||
entity.prevYaw = entity.yaw;
|
||||
entity.prevPitch = entity.pitch;
|
||||
public void alignEntity(Level level) {
|
||||
DimensionalCarriageEntity dimensionalCarriageEntity = entities.get(level.dimension());
|
||||
if (dimensionalCarriageEntity != null) {
|
||||
CarriageContraptionEntity entity = dimensionalCarriageEntity.entity.get();
|
||||
if (entity != null)
|
||||
dimensionalCarriageEntity.alignEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -268,41 +395,79 @@ public class Carriage {
|
|||
return bogeys.getSecond() != null;
|
||||
}
|
||||
|
||||
public Vec3 leadingAnchor() {
|
||||
return isOnTwoBogeys() ? rotationAnchors.getFirst() : positionAnchor;
|
||||
public CarriageContraptionEntity anyAvailableEntity() {
|
||||
for (DimensionalCarriageEntity dimensionalCarriageEntity : entities.values()) {
|
||||
CarriageContraptionEntity entity = dimensionalCarriageEntity.entity.get();
|
||||
if (entity != null)
|
||||
return entity;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Vec3 trailingAnchor() {
|
||||
return isOnTwoBogeys() ? rotationAnchors.getSecond() : positionAnchor;
|
||||
public void forEachPresentEntity(Consumer<CarriageContraptionEntity> callback) {
|
||||
for (DimensionalCarriageEntity dimensionalCarriageEntity : entities.values()) {
|
||||
CarriageContraptionEntity entity = dimensionalCarriageEntity.entity.get();
|
||||
if (entity != null)
|
||||
callback.accept(entity);
|
||||
}
|
||||
}
|
||||
|
||||
public CompoundTag write() {
|
||||
public CompoundTag write(DimensionPalette dimensions) {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.put("FirstBogey", bogeys.getFirst()
|
||||
.write());
|
||||
.write(dimensions));
|
||||
if (isOnTwoBogeys())
|
||||
tag.put("SecondBogey", bogeys.getSecond()
|
||||
.write());
|
||||
.write(dimensions));
|
||||
tag.putInt("Spacing", bogeySpacing);
|
||||
tag.putBoolean("FrontConductor", presentConductors.getFirst());
|
||||
tag.putBoolean("BackConductor", presentConductors.getSecond());
|
||||
tag.putBoolean("Stalled", stalled);
|
||||
|
||||
CarriageContraptionEntity entity = this.entity.get();
|
||||
if (entity != null)
|
||||
serialisedEntity = entity.serializeNBT();
|
||||
Map<Integer, CompoundTag> passengerMap = new HashMap<>();
|
||||
|
||||
for (DimensionalCarriageEntity dimensionalCarriageEntity : entities.values()) {
|
||||
CarriageContraptionEntity entity = dimensionalCarriageEntity.entity.get();
|
||||
if (entity == null)
|
||||
continue;
|
||||
serialize(entity);
|
||||
Contraption contraption = entity.getContraption();
|
||||
if (contraption == null)
|
||||
continue;
|
||||
Map<UUID, Integer> mapping = contraption.getSeatMapping();
|
||||
for (Entity passenger : entity.getPassengers())
|
||||
if (mapping.containsKey(passenger.getUUID()))
|
||||
passengerMap.put(mapping.get(passenger.getUUID()), passenger.serializeNBT());
|
||||
}
|
||||
|
||||
tag.put("Entity", serialisedEntity.copy());
|
||||
tag.put("PositionAnchor", VecHelper.writeNBT(positionAnchor));
|
||||
tag.put("RotationAnchors", rotationAnchors.serializeEach(VecHelper::writeNBTCompound));
|
||||
|
||||
CompoundTag passengerTag = new CompoundTag();
|
||||
passengerMap.putAll(serialisedPassengers);
|
||||
passengerMap.forEach((seat, nbt) -> passengerTag.put("Seat" + seat, nbt.copy()));
|
||||
tag.put("Passengers", passengerTag);
|
||||
|
||||
tag.put("EntityPositioning", NBTHelper.writeCompoundList(entities.entrySet(), e -> {
|
||||
CompoundTag c = e.getValue()
|
||||
.write();
|
||||
c.putInt("Dim", dimensions.encode(e.getKey()));
|
||||
return c;
|
||||
}));
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
public static Carriage read(CompoundTag tag, TrackGraph graph) {
|
||||
CarriageBogey bogey1 = CarriageBogey.read(tag.getCompound("FirstBogey"), graph);
|
||||
private void serialize(Entity entity) {
|
||||
serialisedEntity = entity.serializeNBT();
|
||||
serialisedEntity.remove("Passengers");
|
||||
serialisedEntity.getCompound("Contraption")
|
||||
.remove("Passengers");
|
||||
}
|
||||
|
||||
public static Carriage read(CompoundTag tag, TrackGraph graph, DimensionPalette dimensions) {
|
||||
CarriageBogey bogey1 = CarriageBogey.read(tag.getCompound("FirstBogey"), graph, dimensions);
|
||||
CarriageBogey bogey2 =
|
||||
tag.contains("SecondBogey") ? CarriageBogey.read(tag.getCompound("SecondBogey"), graph) : null;
|
||||
tag.contains("SecondBogey") ? CarriageBogey.read(tag.getCompound("SecondBogey"), graph, dimensions) : null;
|
||||
|
||||
Carriage carriage = new Carriage(bogey1, bogey2, tag.getInt("Spacing"));
|
||||
|
||||
|
@ -311,13 +476,373 @@ public class Carriage {
|
|||
carriage.serialisedEntity = tag.getCompound("Entity")
|
||||
.copy();
|
||||
|
||||
if (carriage.positionAnchor == null) {
|
||||
carriage.positionAnchor = VecHelper.readNBT(tag.getList("PositionAnchor", Tag.TAG_DOUBLE));
|
||||
carriage.rotationAnchors =
|
||||
Couple.deserializeEach(tag.getList("RotationAnchors", Tag.TAG_COMPOUND), VecHelper::readNBTCompound);
|
||||
}
|
||||
NBTHelper.iterateCompoundList(tag.getList("EntityPositioning", Tag.TAG_COMPOUND),
|
||||
c -> carriage.getDimensional(dimensions.decode(c.getInt("Dim")))
|
||||
.read(c));
|
||||
|
||||
CompoundTag passengersTag = tag.getCompound("Passengers");
|
||||
passengersTag.getAllKeys()
|
||||
.forEach(key -> carriage.serialisedPassengers.put(Integer.valueOf(key.substring(4)),
|
||||
passengersTag.getCompound(key)));
|
||||
|
||||
return carriage;
|
||||
}
|
||||
|
||||
private TravellingPoint portalScout = new TravellingPoint();
|
||||
|
||||
public class DimensionalCarriageEntity {
|
||||
public Vec3 positionAnchor;
|
||||
public Couple<Vec3> rotationAnchors;
|
||||
public WeakReference<CarriageContraptionEntity> entity;
|
||||
|
||||
public TrackNodeLocation pivot;
|
||||
int discardTicks;
|
||||
|
||||
// 0 == whole, 0..1 = fading out, -1..0 = fading in
|
||||
public float cutoff;
|
||||
|
||||
// client
|
||||
public boolean pointsInitialised;
|
||||
|
||||
public DimensionalCarriageEntity() {
|
||||
this.entity = new WeakReference<>(null);
|
||||
this.rotationAnchors = Couple.create(null, null);
|
||||
this.pointsInitialised = false;
|
||||
}
|
||||
|
||||
public void discardPivot() {
|
||||
float prevCutoff = cutoff;
|
||||
cutoff = 0;
|
||||
pivot = null;
|
||||
if (!serialisedPassengers.isEmpty() || !Mth.equal(prevCutoff, cutoff)) {
|
||||
updatePassengerLoadout();
|
||||
updateRenderedCutoff();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateCutoff(boolean leadingIsCurrent) {
|
||||
Vec3 leadingAnchor = rotationAnchors.getFirst();
|
||||
Vec3 trailingAnchor = rotationAnchors.getSecond();
|
||||
|
||||
if (leadingAnchor == null || trailingAnchor == null)
|
||||
return;
|
||||
if (pivot == null) {
|
||||
cutoff = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
Vec3 pivotLoc = pivot.getLocation()
|
||||
.add(0, 1, 0);
|
||||
|
||||
double leadingSpacing = leadingBogey().type.getWheelPointSpacing() / 2;
|
||||
double trailingSpacing = trailingBogey().type.getWheelPointSpacing() / 2;
|
||||
double anchorSpacing = leadingSpacing + bogeySpacing + trailingSpacing;
|
||||
|
||||
if (isOnTwoBogeys()) {
|
||||
Vec3 diff = trailingAnchor.subtract(leadingAnchor)
|
||||
.normalize();
|
||||
trailingAnchor = trailingAnchor.add(diff.scale(trailingSpacing));
|
||||
leadingAnchor = leadingAnchor.add(diff.scale(-leadingSpacing));
|
||||
}
|
||||
|
||||
double leadingDiff = leadingAnchor.distanceTo(pivotLoc);
|
||||
double trailingDiff = trailingAnchor.distanceTo(pivotLoc);
|
||||
|
||||
leadingDiff /= anchorSpacing;
|
||||
trailingDiff /= anchorSpacing;
|
||||
|
||||
if (leadingIsCurrent && leadingDiff > trailingDiff && leadingDiff > 1)
|
||||
cutoff = 0;
|
||||
else if (leadingIsCurrent && leadingDiff < trailingDiff && trailingDiff > 1)
|
||||
cutoff = 1;
|
||||
else if (!leadingIsCurrent && leadingDiff > trailingDiff && leadingDiff > 1)
|
||||
cutoff = -1;
|
||||
else if (!leadingIsCurrent && leadingDiff < trailingDiff && trailingDiff > 1)
|
||||
cutoff = 0;
|
||||
else
|
||||
cutoff = (float) Mth.clamp(1 - (leadingIsCurrent ? leadingDiff : trailingDiff), 0, 1)
|
||||
* (leadingIsCurrent ? 1 : -1);
|
||||
}
|
||||
|
||||
public TrackNodeLocation findPivot(ResourceKey<Level> dimension, boolean leading) {
|
||||
if (pivot != null)
|
||||
return pivot;
|
||||
|
||||
TravellingPoint start = leading ? getLeadingPoint() : getTrailingPoint();
|
||||
TravellingPoint end = !leading ? getLeadingPoint() : getTrailingPoint();
|
||||
|
||||
portalScout.node1 = start.node1;
|
||||
portalScout.node2 = start.node2;
|
||||
portalScout.edge = start.edge;
|
||||
portalScout.position = start.position;
|
||||
|
||||
ITrackSelector trackSelector = portalScout.follow(end);
|
||||
int distance = bogeySpacing + 10;
|
||||
int direction = leading ? -1 : 1;
|
||||
|
||||
portalScout.travel(train.graph, direction * distance, trackSelector, portalScout.ignoreEdgePoints(),
|
||||
portalScout.ignoreTurns(), nodes -> {
|
||||
for (boolean b : Iterate.trueAndFalse)
|
||||
if (nodes.get(b).dimension.equals(dimension))
|
||||
pivot = nodes.get(b);
|
||||
return true;
|
||||
});
|
||||
|
||||
return pivot;
|
||||
}
|
||||
|
||||
public CompoundTag write() {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.putFloat("Cutoff", cutoff);
|
||||
tag.putInt("DiscardTicks", discardTicks);
|
||||
if (pivot != null)
|
||||
tag.put("Pivot", pivot.write(null));
|
||||
if (positionAnchor != null)
|
||||
tag.put("PositionAnchor", VecHelper.writeNBT(positionAnchor));
|
||||
if (rotationAnchors.both(Objects::nonNull))
|
||||
tag.put("RotationAnchors", rotationAnchors.serializeEach(VecHelper::writeNBTCompound));
|
||||
return tag;
|
||||
}
|
||||
|
||||
public void read(CompoundTag tag) {
|
||||
cutoff = tag.getFloat("Cutoff");
|
||||
discardTicks = tag.getInt("DiscardTicks");
|
||||
if (tag.contains("Pivot"))
|
||||
pivot = TrackNodeLocation.read(tag.getCompound("Pivot"), null);
|
||||
if (positionAnchor != null)
|
||||
return;
|
||||
if (tag.contains("PositionAnchor"))
|
||||
positionAnchor = VecHelper.readNBT(tag.getList("PositionAnchor", Tag.TAG_DOUBLE));
|
||||
if (tag.contains("RotationAnchors"))
|
||||
rotationAnchors = Couple.deserializeEach(tag.getList("RotationAnchors", Tag.TAG_COMPOUND),
|
||||
VecHelper::readNBTCompound);
|
||||
}
|
||||
|
||||
public Vec3 leadingAnchor() {
|
||||
return isOnTwoBogeys() ? rotationAnchors.getFirst() : positionAnchor;
|
||||
}
|
||||
|
||||
public Vec3 trailingAnchor() {
|
||||
return isOnTwoBogeys() ? rotationAnchors.getSecond() : positionAnchor;
|
||||
}
|
||||
|
||||
public int minAllowedLocalCoord() {
|
||||
if (cutoff <= 0)
|
||||
return Integer.MIN_VALUE;
|
||||
if (cutoff >= 1)
|
||||
return Integer.MAX_VALUE;
|
||||
return Mth.floor(-bogeySpacing + -1 + (2 + bogeySpacing) * cutoff);
|
||||
}
|
||||
|
||||
public int maxAllowedLocalCoord() {
|
||||
if (cutoff >= 0)
|
||||
return Integer.MAX_VALUE;
|
||||
if (cutoff <= -1)
|
||||
return Integer.MIN_VALUE;
|
||||
return Mth.ceil(-bogeySpacing + -1 + (2 + bogeySpacing) * (cutoff + 1));
|
||||
}
|
||||
|
||||
public void updatePassengerLoadout() {
|
||||
Entity entity = this.entity.get();
|
||||
if (!(entity instanceof CarriageContraptionEntity cce))
|
||||
return;
|
||||
if (!(entity.level instanceof ServerLevel sLevel))
|
||||
return;
|
||||
|
||||
Set<Integer> loadedPassengers = new HashSet<>();
|
||||
int min = minAllowedLocalCoord();
|
||||
int max = maxAllowedLocalCoord();
|
||||
|
||||
for (Entry<Integer, CompoundTag> entry : serialisedPassengers.entrySet()) {
|
||||
Integer seatId = entry.getKey();
|
||||
List<BlockPos> seats = cce.getContraption()
|
||||
.getSeats();
|
||||
if (seatId >= seats.size())
|
||||
continue;
|
||||
|
||||
BlockPos localPos = seats.get(seatId);
|
||||
if (!cce.isLocalCoordWithin(localPos, min, max))
|
||||
continue;
|
||||
|
||||
CompoundTag tag = entry.getValue();
|
||||
Entity passenger = null;
|
||||
|
||||
if (tag.contains("PlayerPassenger")) {
|
||||
passenger = sLevel.getServer()
|
||||
.getPlayerList()
|
||||
.getPlayer(tag.getUUID("PlayerPassenger"));
|
||||
|
||||
} else {
|
||||
passenger = EntityType.loadEntityRecursive(tag, entity.level, e -> {
|
||||
e.moveTo(positionAnchor);
|
||||
return e;
|
||||
});
|
||||
if (passenger != null)
|
||||
sLevel.tryAddFreshEntityWithPassengers(passenger);
|
||||
}
|
||||
|
||||
if (passenger != null) {
|
||||
ResourceKey<Level> passengerDimension = passenger.level.dimension();
|
||||
if (!passengerDimension.equals(sLevel.dimension()) && passenger instanceof ServerPlayer sp)
|
||||
continue;
|
||||
cce.addSittingPassenger(passenger, seatId);
|
||||
}
|
||||
|
||||
loadedPassengers.add(seatId);
|
||||
}
|
||||
|
||||
loadedPassengers.forEach(serialisedPassengers::remove);
|
||||
|
||||
Map<UUID, Integer> mapping = cce.getContraption()
|
||||
.getSeatMapping();
|
||||
for (Entity passenger : entity.getPassengers()) {
|
||||
BlockPos localPos = cce.getContraption()
|
||||
.getSeatOf(passenger.getUUID());
|
||||
if (cce.isLocalCoordWithin(localPos, min, max))
|
||||
continue;
|
||||
if (!mapping.containsKey(passenger.getUUID()))
|
||||
continue;
|
||||
|
||||
Integer seat = mapping.get(passenger.getUUID());
|
||||
if ((passenger instanceof ServerPlayer sp)) {
|
||||
dismountPlayer(sLevel, sp, seat, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
serialisedPassengers.put(seat, passenger.serializeNBT());
|
||||
passenger.discard();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void dismountPlayer(ServerLevel sLevel, ServerPlayer sp, Integer seat, boolean portal) {
|
||||
if (!portal) {
|
||||
sp.stopRiding();
|
||||
return;
|
||||
}
|
||||
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.putUUID("PlayerPassenger", sp.getUUID());
|
||||
serialisedPassengers.put(seat, tag);
|
||||
sp.stopRiding();
|
||||
sp.getPersistentData()
|
||||
.remove("ContraptionDismountLocation");
|
||||
|
||||
for (Entry<ResourceKey<Level>, DimensionalCarriageEntity> other : entities.entrySet()) {
|
||||
DimensionalCarriageEntity otherDce = other.getValue();
|
||||
if (otherDce == this)
|
||||
continue;
|
||||
if (sp.level.dimension()
|
||||
.equals(other.getKey()))
|
||||
continue;
|
||||
if (otherDce.pivot == null)
|
||||
continue;
|
||||
Vec3 loc = otherDce.pivot.getLocation();
|
||||
ServerLevel level = sLevel.getServer()
|
||||
.getLevel(other.getKey());
|
||||
sp.teleportTo(level, loc.x, loc.y, loc.z, sp.getYRot(), sp.getXRot());
|
||||
sp.setPortalCooldown();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateRenderedCutoff() {
|
||||
Entity entity = this.entity.get();
|
||||
if (!(entity instanceof CarriageContraptionEntity cce))
|
||||
return;
|
||||
if (!entity.level.isClientSide())
|
||||
return;
|
||||
Contraption contraption = cce.getContraption();
|
||||
if (!(contraption instanceof CarriageContraption cc))
|
||||
return;
|
||||
cc.portalCutoffMin = minAllowedLocalCoord();
|
||||
cc.portalCutoffMax = maxAllowedLocalCoord();
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> invalidate(cce));
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
private void invalidate(CarriageContraptionEntity entity) {
|
||||
ContraptionRenderDispatcher.invalidate(entity.getContraption());
|
||||
entity.updateRenderedPortalCutoff();
|
||||
}
|
||||
|
||||
private void createEntity(Level level, boolean loadPassengers) {
|
||||
Entity entity = EntityType.loadEntityRecursive(serialisedEntity, level, e -> {
|
||||
e.moveTo(positionAnchor);
|
||||
return e;
|
||||
});
|
||||
|
||||
if (!(entity instanceof CarriageContraptionEntity cce)) {
|
||||
train.invalid = true;
|
||||
return;
|
||||
}
|
||||
|
||||
cce.setGraph(train.graph == null ? null : train.graph.id);
|
||||
cce.setCarriage(Carriage.this);
|
||||
cce.syncCarriage();
|
||||
|
||||
this.entity = new WeakReference<>(cce);
|
||||
|
||||
if (level instanceof ServerLevel sl)
|
||||
sl.tryAddFreshEntityWithPassengers(entity);
|
||||
|
||||
updatePassengerLoadout();
|
||||
}
|
||||
|
||||
private void removeAndSaveEntity(CarriageContraptionEntity entity, boolean portal) {
|
||||
Contraption contraption = entity.getContraption();
|
||||
if (contraption != null) {
|
||||
Map<UUID, Integer> mapping = contraption.getSeatMapping();
|
||||
for (Entity passenger : entity.getPassengers()) {
|
||||
if (!mapping.containsKey(passenger.getUUID()))
|
||||
continue;
|
||||
|
||||
Integer seat = mapping.get(passenger.getUUID());
|
||||
|
||||
if (passenger instanceof ServerPlayer sp) {
|
||||
dismountPlayer(sp.getLevel(), sp, seat, portal);
|
||||
continue;
|
||||
}
|
||||
|
||||
serialisedPassengers.put(seat, passenger.serializeNBT());
|
||||
}
|
||||
}
|
||||
|
||||
for (Entity passenger : entity.getPassengers())
|
||||
if (!(passenger instanceof Player))
|
||||
passenger.discard();
|
||||
|
||||
serialize(entity);
|
||||
entity.discard();
|
||||
this.entity.clear();
|
||||
}
|
||||
|
||||
public void alignEntity(CarriageContraptionEntity entity) {
|
||||
if (rotationAnchors.either(Objects::isNull))
|
||||
return;
|
||||
|
||||
Vec3 positionVec = rotationAnchors.getFirst();
|
||||
Vec3 coupledVec = rotationAnchors.getSecond();
|
||||
|
||||
double diffX = positionVec.x - coupledVec.x;
|
||||
double diffY = positionVec.y - coupledVec.y;
|
||||
double diffZ = positionVec.z - coupledVec.z;
|
||||
|
||||
entity.setPos(positionAnchor);
|
||||
entity.prevYaw = entity.yaw;
|
||||
entity.prevPitch = entity.pitch;
|
||||
|
||||
entity.yaw = (float) (Mth.atan2(diffZ, diffX) * 180 / Math.PI) + 180;
|
||||
entity.pitch = (float) (Math.atan2(diffY, Math.sqrt(diffX * diffX + diffZ * diffZ)) * 180 / Math.PI) * -1;
|
||||
|
||||
if (!entity.firstPositionUpdate)
|
||||
return;
|
||||
|
||||
entity.xo = entity.getX();
|
||||
entity.yo = entity.getY();
|
||||
entity.zo = entity.getZ();
|
||||
entity.prevYaw = entity.yaw;
|
||||
entity.prevPitch = entity.pitch;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import javax.annotation.Nullable;
|
|||
|
||||
import com.jozufozu.flywheel.api.MaterialManager;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.logistics.trains.DimensionPalette;
|
||||
import com.simibubi.create.content.logistics.trains.IBogeyBlock;
|
||||
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||
|
@ -15,8 +16,10 @@ import com.simibubi.create.foundation.utility.animation.LerpedFloat;
|
|||
import net.minecraft.core.Direction.Axis;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
@ -48,6 +51,20 @@ public class CarriageBogey {
|
|||
couplingAnchors = Couple.create(null, null);
|
||||
}
|
||||
|
||||
public ResourceKey<Level> getDimension() {
|
||||
TravellingPoint leading = leading();
|
||||
TravellingPoint trailing = trailing();
|
||||
if (leading.edge == null || trailing.edge == null)
|
||||
return null;
|
||||
if (leading.edge.isInterDimensional() || trailing.edge.isInterDimensional())
|
||||
return null;
|
||||
ResourceKey<Level> dimension1 = leading.node1.getLocation().dimension;
|
||||
ResourceKey<Level> dimension2 = trailing.node1.getLocation().dimension;
|
||||
if (dimension1.equals(dimension2))
|
||||
return dimension1;
|
||||
return null;
|
||||
}
|
||||
|
||||
public void updateAngles(CarriageContraptionEntity entity, double distanceMoved) {
|
||||
double angleDiff = 360 * distanceMoved / (Math.PI * 2 * type.getWheelRadius());
|
||||
|
||||
|
@ -56,6 +73,10 @@ public class CarriageBogey {
|
|||
|
||||
if (leading().edge == null || carriage.train.derailed) {
|
||||
yRot = -90 + entity.yaw - derailAngle;
|
||||
} else if (!entity.level.dimension()
|
||||
.equals(getDimension())) {
|
||||
yRot = -90 + entity.yaw;
|
||||
xRot = 0;
|
||||
} else {
|
||||
Vec3 positionVec = leading().getPosition();
|
||||
Vec3 coupledVec = trailing().getPosition();
|
||||
|
@ -86,6 +107,8 @@ public class CarriageBogey {
|
|||
}
|
||||
|
||||
public double getStress() {
|
||||
if (getDimension() == null)
|
||||
return 0;
|
||||
return type.getWheelPointSpacing() - leading().getPosition()
|
||||
.distanceTo(trailing().getPosition());
|
||||
}
|
||||
|
@ -119,19 +142,19 @@ public class CarriageBogey {
|
|||
couplingAnchors.set(leading, entityPos.add(thisOffset));
|
||||
}
|
||||
|
||||
public CompoundTag write() {
|
||||
public CompoundTag write(DimensionPalette dimensions) {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.putString("Type", ((Block) type).getRegistryName()
|
||||
.toString());
|
||||
tag.put("Points", points.serializeEach(TravellingPoint::write));
|
||||
tag.put("Points", points.serializeEach(tp -> tp.write(dimensions)));
|
||||
return tag;
|
||||
}
|
||||
|
||||
public static CarriageBogey read(CompoundTag tag, TrackGraph graph) {
|
||||
public static CarriageBogey read(CompoundTag tag, TrackGraph graph, DimensionPalette dimensions) {
|
||||
ResourceLocation location = new ResourceLocation(tag.getString("Type"));
|
||||
IBogeyBlock type = (IBogeyBlock) ForgeRegistries.BLOCKS.getValue(location);
|
||||
Couple<TravellingPoint> points =
|
||||
Couple.deserializeEach(tag.getList("Points", Tag.TAG_COMPOUND), c -> TravellingPoint.read(c, graph));
|
||||
Couple<TravellingPoint> points = Couple.deserializeEach(tag.getList("Points", Tag.TAG_COMPOUND),
|
||||
c -> TravellingPoint.read(c, graph, dimensions));
|
||||
CarriageBogey carriageBogey = new CarriageBogey(type, points.getFirst(), points.getSecond());
|
||||
return carriageBogey;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
package com.simibubi.create.content.logistics.trains.entity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
|
@ -25,14 +28,17 @@ import com.simibubi.create.foundation.utility.VecHelper;
|
|||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Direction.Axis;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
|
@ -51,11 +57,17 @@ public class CarriageContraption extends Contraption {
|
|||
private BlockPos secondBogeyPos;
|
||||
private List<BlockPos> assembledBlazeBurners;
|
||||
|
||||
// render
|
||||
public int portalCutoffMin;
|
||||
public int portalCutoffMax;
|
||||
|
||||
public CarriageContraption() {
|
||||
conductorSeats = new HashMap<>();
|
||||
assembledBlazeBurners = new ArrayList<>();
|
||||
blazeBurnerConductors = Couple.create(false, false);
|
||||
soundQueue = new ArrivalSoundQueue();
|
||||
portalCutoffMin = Integer.MIN_VALUE;
|
||||
portalCutoffMax = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
public void setSoundQueueOffset(int offset) {
|
||||
|
@ -216,4 +228,70 @@ public class CarriageContraption extends Contraption {
|
|||
return secondBogeyPos;
|
||||
}
|
||||
|
||||
private Collection<BlockEntity> specialRenderedTEsOutsidePortal = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public Collection<StructureBlockInfo> getRenderedBlocks() {
|
||||
if (notInPortal())
|
||||
return super.getRenderedBlocks();
|
||||
|
||||
specialRenderedTEsOutsidePortal = new ArrayList<>();
|
||||
specialRenderedTileEntities.stream()
|
||||
.filter(te -> !isHiddenInPortal(te.getBlockPos()))
|
||||
.forEach(specialRenderedTEsOutsidePortal::add);
|
||||
|
||||
Collection<StructureBlockInfo> values = new ArrayList<>();
|
||||
for (Entry<BlockPos, StructureBlockInfo> entry : blocks.entrySet()) {
|
||||
BlockPos pos = entry.getKey();
|
||||
if (withinVisible(pos))
|
||||
values.add(entry.getValue());
|
||||
else if (atSeam(pos))
|
||||
values.add(new StructureBlockInfo(pos, Blocks.PURPLE_STAINED_GLASS.defaultBlockState(), null));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<BlockEntity> getSpecialRenderedTEs() {
|
||||
if (notInPortal())
|
||||
return super.getSpecialRenderedTEs();
|
||||
return specialRenderedTEsOutsidePortal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<List<AABB>> getSimplifiedEntityColliders() {
|
||||
if (notInPortal())
|
||||
return super.getSimplifiedEntityColliders();
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHiddenInPortal(BlockPos localPos) {
|
||||
if (notInPortal())
|
||||
return super.isHiddenInPortal(localPos);
|
||||
return !withinVisible(localPos) || atSeam(localPos);
|
||||
}
|
||||
|
||||
private boolean notInPortal() {
|
||||
return portalCutoffMin == Integer.MIN_VALUE && portalCutoffMax == Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
public boolean atSeam(BlockPos localPos) {
|
||||
Direction facing = assemblyDirection;
|
||||
Axis axis = facing.getClockWise()
|
||||
.getAxis();
|
||||
int coord = axis.choose(localPos.getZ(), localPos.getY(), localPos.getX()) * -facing.getAxisDirection()
|
||||
.getStep();
|
||||
return coord == portalCutoffMin || coord == portalCutoffMax;
|
||||
}
|
||||
|
||||
public boolean withinVisible(BlockPos localPos) {
|
||||
Direction facing = assemblyDirection;
|
||||
Axis axis = facing.getClockWise()
|
||||
.getAxis();
|
||||
int coord = axis.choose(localPos.getZ(), localPos.getY(), localPos.getX()) * -facing.getAxisDirection()
|
||||
.getStep();
|
||||
return coord > portalCutoffMin && coord < portalCutoffMax;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,8 +2,10 @@ package com.simibubi.create.content.logistics.trains.entity;
|
|||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
@ -14,9 +16,13 @@ import com.simibubi.create.AllEntityDataSerializers;
|
|||
import com.simibubi.create.AllEntityTypes;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.CreateClient;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntity;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsBlock;
|
||||
import com.simibubi.create.content.contraptions.particle.CubeParticleData;
|
||||
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
||||
import com.simibubi.create.content.logistics.trains.entity.Carriage.DimensionalCarriageEntity;
|
||||
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.SteerDirection;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.GlobalStation;
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
|
@ -44,6 +50,8 @@ import net.minecraft.world.entity.player.Player;
|
|||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
||||
|
||||
|
@ -125,6 +133,17 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
return entityData.get(SCHEDULED);
|
||||
}
|
||||
|
||||
public boolean isLocalCoordWithin(BlockPos localPos, int min, int max) {
|
||||
if (!(getContraption()instanceof CarriageContraption cc))
|
||||
return false;
|
||||
Direction facing = cc.getAssemblyDirection();
|
||||
Axis axis = facing.getClockWise()
|
||||
.getAxis();
|
||||
int coord = axis.choose(localPos.getZ(), localPos.getY(), localPos.getX()) * -facing.getAxisDirection()
|
||||
.getStep();
|
||||
return coord >= min && coord <= max;
|
||||
}
|
||||
|
||||
public static CarriageContraptionEntity create(Level world, CarriageContraption contraption) {
|
||||
CarriageContraptionEntity entity =
|
||||
new CarriageContraptionEntity(AllEntityTypes.CARRIAGE_CONTRAPTION.get(), world);
|
||||
|
@ -162,8 +181,12 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
if (train == null || train.carriages.size() <= carriageIndex)
|
||||
return;
|
||||
carriage = train.carriages.get(carriageIndex);
|
||||
if (carriage != null)
|
||||
carriage.entity = new WeakReference<>(this);
|
||||
if (carriage != null) {
|
||||
DimensionalCarriageEntity dimensional = carriage.getDimensional(level);
|
||||
dimensional.entity = new WeakReference<>(this);
|
||||
dimensional.pivot = null;
|
||||
carriage.updateContraptionAnchors();
|
||||
}
|
||||
updateTrackGraph();
|
||||
} else
|
||||
discard();
|
||||
|
@ -201,7 +224,9 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!carriage.pointsInitialised)
|
||||
DimensionalCarriageEntity dce = carriage.getDimensional(level);
|
||||
|
||||
if (!dce.pointsInitialised)
|
||||
return;
|
||||
|
||||
carriageData.approach(this, carriage, 1f / getType().updateInterval());
|
||||
|
@ -213,7 +238,7 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
yo = getY();
|
||||
zo = getZ();
|
||||
|
||||
carriage.alignEntity(this);
|
||||
dce.alignEntity(this);
|
||||
|
||||
double distanceTo = 0;
|
||||
if (!firstPositionUpdate) {
|
||||
|
@ -232,6 +257,8 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
|
||||
if (carriage.train.derailed)
|
||||
spawnDerailParticles(carriage);
|
||||
if (dce.pivot != null)
|
||||
spawnPortalParticles(dce);
|
||||
|
||||
firstPositionUpdate = false;
|
||||
validForRender = true;
|
||||
|
@ -247,7 +274,7 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
for (int index = 0; index < carriageCount; index++) {
|
||||
int i = arrivalSoundReversed ? carriageCount - 1 - index : index;
|
||||
Carriage carriage = carriages.get(i);
|
||||
CarriageContraptionEntity entity = carriage.entity.get();
|
||||
CarriageContraptionEntity entity = carriage.getDimensional(level).entity.get();
|
||||
if (entity == null || !(entity.contraption instanceof CarriageContraption otherCC))
|
||||
break;
|
||||
tick = arrivalSoundReversed ? otherCC.soundQueue.lastTick() : otherCC.soundQueue.firstTick();
|
||||
|
@ -268,7 +295,7 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
|
||||
boolean keepTicking = false;
|
||||
for (Carriage c : carriages) {
|
||||
CarriageContraptionEntity entity = c.entity.get();
|
||||
CarriageContraptionEntity entity = c.getDimensional(level).entity.get();
|
||||
if (entity == null || !(entity.contraption instanceof CarriageContraption otherCC))
|
||||
continue;
|
||||
keepTicking |= otherCC.soundQueue.tick(entity, arrivalSoundTicks, arrivalSoundReversed);
|
||||
|
@ -287,6 +314,11 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
super.tickActors();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isActorActive(MovementContext context, MovementBehaviour actor) {
|
||||
return !getContraption().isHiddenInPortal(context.localPos) && super.isActorActive(context, actor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleStallInformation(float x, float y, float z, float angle) {}
|
||||
|
||||
|
@ -300,12 +332,49 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
}
|
||||
}
|
||||
|
||||
private Set<BlockPos> particleSlice = new HashSet<>();
|
||||
private float particleAvgY = 0;
|
||||
|
||||
private void spawnPortalParticles(DimensionalCarriageEntity dce) {
|
||||
Vec3 pivot = dce.pivot.getLocation()
|
||||
.add(0, 1.5f, 0);
|
||||
if (particleSlice.isEmpty())
|
||||
return;
|
||||
|
||||
boolean alongX = Mth.equal(pivot.x, Math.round(pivot.x));
|
||||
int extraFlip = Direction.fromYRot(yaw)
|
||||
.getAxisDirection()
|
||||
.getStep();
|
||||
|
||||
Vec3 emitter = pivot.add(0, particleAvgY, 0);
|
||||
double speed = position().distanceTo(getPrevPositionVec());
|
||||
int size = (int) (particleSlice.size() * Mth.clamp(4 - speed * 4, 0, 4));
|
||||
|
||||
for (BlockPos pos : particleSlice) {
|
||||
if (size != 0 && random.nextInt(size) != 0)
|
||||
continue;
|
||||
if (alongX)
|
||||
pos = new BlockPos(0, pos.getY(), pos.getX());
|
||||
Vec3 v = pivot.add(pos.getX() * extraFlip, pos.getY(), pos.getZ() * extraFlip);
|
||||
CubeParticleData data =
|
||||
new CubeParticleData(.25f, 0, .5f, .65f + (random.nextFloat() - .5f) * .25f, 4, false);
|
||||
Vec3 m = v.subtract(emitter)
|
||||
.normalize()
|
||||
.scale(.325f);
|
||||
m = VecHelper.rotate(m, random.nextFloat() * 360, alongX ? Axis.X : Axis.Z);
|
||||
m = m.add(VecHelper.offsetRandomly(Vec3.ZERO, random, 0.25f));
|
||||
level.addParticle(data, v.x, v.y, v.z, m.x, m.y, m.z);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClientRemoval() {
|
||||
super.onClientRemoval();
|
||||
entityData.set(CARRIAGE_DATA, new CarriageSyncData());
|
||||
if (carriage != null) {
|
||||
carriage.pointsInitialised = false;
|
||||
DimensionalCarriageEntity dce = carriage.getDimensional(level);
|
||||
dce.pointsInitialised = false;
|
||||
carriage.leadingBogey().couplingAnchors = Couple.create(null, null);
|
||||
carriage.trailingBogey().couplingAnchors = Couple.create(null, null);
|
||||
}
|
||||
|
@ -467,7 +536,9 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
|
||||
if (lookAhead != null) {
|
||||
if (spaceDown) {
|
||||
carriage.train.manualTick = true;
|
||||
nav.startNavigation(lookAhead, -1, false);
|
||||
carriage.train.manualTick = false;
|
||||
navDistanceTotal = nav.distanceToDestination;
|
||||
return true;
|
||||
}
|
||||
|
@ -541,4 +612,69 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
prevPosInvalid = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadyForRender() {
|
||||
return super.isReadyForRender() && validForRender && !firstPositionUpdate;
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
private WeakReference<CarriageContraptionInstance> instanceHolder;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void bindInstance(CarriageContraptionInstance instance) {
|
||||
this.instanceHolder = new WeakReference<>(instance);
|
||||
updateRenderedPortalCutoff();
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void updateRenderedPortalCutoff() {
|
||||
if (carriage == null)
|
||||
return;
|
||||
|
||||
// update portal slice
|
||||
particleSlice.clear();
|
||||
particleAvgY = 0;
|
||||
|
||||
if (contraption instanceof CarriageContraption cc) {
|
||||
Direction forward = cc.getAssemblyDirection()
|
||||
.getClockWise();
|
||||
Axis axis = forward.getAxis();
|
||||
boolean x = axis == Axis.X;
|
||||
boolean flip = true;
|
||||
|
||||
for (BlockPos pos : contraption.getBlocks()
|
||||
.keySet()) {
|
||||
if (!cc.atSeam(pos))
|
||||
continue;
|
||||
int pX = x ? pos.getX() : pos.getZ();
|
||||
pX *= forward.getAxisDirection()
|
||||
.getStep() * (flip ? 1 : -1);
|
||||
pos = new BlockPos(pX, pos.getY(), 0);
|
||||
particleSlice.add(pos);
|
||||
particleAvgY += pos.getY();
|
||||
}
|
||||
|
||||
}
|
||||
if (particleSlice.size() > 0)
|
||||
particleAvgY /= particleSlice.size();
|
||||
|
||||
// update hidden bogeys (if instanced)
|
||||
if (instanceHolder == null)
|
||||
return;
|
||||
CarriageContraptionInstance instance = instanceHolder.get();
|
||||
if (instance == null)
|
||||
return;
|
||||
|
||||
int bogeySpacing = carriage.bogeySpacing;
|
||||
|
||||
carriage.bogeys.forEachWithContext((bogey, first) -> {
|
||||
if (bogey == null)
|
||||
return;
|
||||
|
||||
BlockPos bogeyPos = bogey.isLeading ? BlockPos.ZERO
|
||||
: BlockPos.ZERO.relative(getInitialOrientation().getCounterClockWise(), bogeySpacing);
|
||||
instance.setBogeyVisibility(first, !contraption.isHiddenInPortal(bogeyPos));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,9 +29,7 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer
|
|||
for (CarriageBogey bogey : carriage.bogeys)
|
||||
if (bogey != null)
|
||||
bogey.couplingAnchors.replace(v -> null);
|
||||
if (!super.shouldRender(entity, clippingHelper, cameraX, cameraY, cameraZ))
|
||||
return false;
|
||||
return entity.validForRender && !entity.firstPositionUpdate;
|
||||
return super.shouldRender(entity, clippingHelper, cameraX, cameraY, cameraZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -53,12 +51,19 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer
|
|||
if (bogey == null)
|
||||
return;
|
||||
|
||||
if (!Backend.isOn()) {
|
||||
BlockPos bogeyPos = bogey.isLeading ? BlockPos.ZERO
|
||||
: BlockPos.ZERO.relative(entity.getInitialOrientation()
|
||||
.getCounterClockWise(), bogeySpacing);
|
||||
|
||||
if (!Backend.isOn() && !entity.getContraption()
|
||||
.isHiddenInPortal(bogeyPos)) {
|
||||
|
||||
ms.pushPose();
|
||||
translateBogey(ms, bogey, bogeySpacing, viewYRot, viewXRot, partialTicks);
|
||||
|
||||
int light = getBogeyLightCoords(entity, bogey, partialTicks);
|
||||
bogey.type.render(null, bogey.wheelAngle.getValue(partialTicks), ms, partialTicks, buffers, light, overlay);
|
||||
bogey.type.render(null, bogey.wheelAngle.getValue(partialTicks), ms, partialTicks, buffers, light,
|
||||
overlay);
|
||||
|
||||
ms.popPose();
|
||||
}
|
||||
|
@ -70,25 +75,28 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer
|
|||
});
|
||||
}
|
||||
|
||||
public static void translateBogey(PoseStack ms, CarriageBogey bogey, int bogeySpacing, float viewYRot, float viewXRot, float partialTicks) {
|
||||
public static void translateBogey(PoseStack ms, CarriageBogey bogey, int bogeySpacing, float viewYRot,
|
||||
float viewXRot, float partialTicks) {
|
||||
TransformStack.cast(ms)
|
||||
.rotateY(viewYRot + 90)
|
||||
.rotateX(-viewXRot)
|
||||
.rotateY(180)
|
||||
.translate(0, 0, bogey.isLeading ? 0 : -bogeySpacing)
|
||||
.rotateY(-180)
|
||||
.rotateX(viewXRot)
|
||||
.rotateY(-viewYRot - 90)
|
||||
.rotateY(bogey.yaw.getValue(partialTicks))
|
||||
.rotateX(bogey.pitch.getValue(partialTicks))
|
||||
.translate(0, .5f, 0);
|
||||
.rotateY(viewYRot + 90)
|
||||
.rotateX(-viewXRot)
|
||||
.rotateY(180)
|
||||
.translate(0, 0, bogey.isLeading ? 0 : -bogeySpacing)
|
||||
.rotateY(-180)
|
||||
.rotateX(viewXRot)
|
||||
.rotateY(-viewYRot - 90)
|
||||
.rotateY(bogey.yaw.getValue(partialTicks))
|
||||
.rotateX(bogey.pitch.getValue(partialTicks))
|
||||
.translate(0, .5f, 0);
|
||||
}
|
||||
|
||||
public static int getBogeyLightCoords(CarriageContraptionEntity entity, CarriageBogey bogey, float partialTicks) {
|
||||
|
||||
var lightPos = new BlockPos(Objects.requireNonNullElseGet(bogey.getAnchorPosition(), () -> entity.getLightProbePosition(partialTicks)));
|
||||
var lightPos = new BlockPos(
|
||||
Objects.requireNonNullElseGet(bogey.getAnchorPosition(), () -> entity.getLightProbePosition(partialTicks)));
|
||||
|
||||
return LightTexture.pack(entity.level.getBrightness(LightLayer.BLOCK, lightPos), entity.level.getBrightness(LightLayer.SKY, lightPos));
|
||||
return LightTexture.pack(entity.level.getBrightness(LightLayer.BLOCK, lightPos),
|
||||
entity.level.getBrightness(LightLayer.SKY, lightPos));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import com.jozufozu.flywheel.util.AnimationTickHolder;
|
|||
import com.jozufozu.flywheel.util.transform.TransformStack;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
|
||||
public class CarriageContraptionInstance extends EntityInstance<CarriageContraptionEntity> implements DynamicInstance {
|
||||
|
||||
|
@ -14,25 +15,34 @@ public class CarriageContraptionInstance extends EntityInstance<CarriageContrapt
|
|||
|
||||
private Carriage carriage;
|
||||
private Couple<BogeyInstance> bogeys;
|
||||
private Couple<Boolean> bogeyHidden;
|
||||
|
||||
public CarriageContraptionInstance(MaterialManager materialManager, CarriageContraptionEntity entity) {
|
||||
super(materialManager, entity);
|
||||
bogeyHidden = Couple.create(() -> false);
|
||||
entity.bindInstance(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
carriage = entity.getCarriage();
|
||||
|
||||
if (carriage == null) return;
|
||||
if (carriage == null)
|
||||
return;
|
||||
|
||||
bogeys = carriage.bogeys.mapNotNullWithParam(CarriageBogey::createInstance, materialManager);
|
||||
updateLight();
|
||||
}
|
||||
|
||||
public void setBogeyVisibility(boolean first, boolean visible) {
|
||||
bogeyHidden.set(first, !visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginFrame() {
|
||||
if (bogeys == null) {
|
||||
init();
|
||||
if (entity.isReadyForRender())
|
||||
init();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -47,18 +57,23 @@ public class CarriageContraptionInstance extends EntityInstance<CarriageContrapt
|
|||
TransformStack.cast(ms)
|
||||
.translate(getInstancePosition(partialTicks));
|
||||
|
||||
for (BogeyInstance instance : bogeys) {
|
||||
if (instance != null) {
|
||||
ms.pushPose();
|
||||
CarriageBogey bogey = instance.bogey;
|
||||
|
||||
CarriageContraptionEntityRenderer.translateBogey(ms, bogey, bogeySpacing, viewYRot, viewXRot,
|
||||
partialTicks);
|
||||
ms.translate(0, -1.5 - 1 / 128f, 0);
|
||||
|
||||
instance.beginFrame(bogey.wheelAngle.getValue(partialTicks), ms);
|
||||
ms.popPose();
|
||||
for (boolean current : Iterate.trueAndFalse) {
|
||||
BogeyInstance instance = bogeys.get(current);
|
||||
if (instance == null)
|
||||
continue;
|
||||
if (bogeyHidden.get(current)) {
|
||||
instance.hiddenFrame();
|
||||
continue;
|
||||
}
|
||||
|
||||
ms.pushPose();
|
||||
CarriageBogey bogey = instance.bogey;
|
||||
|
||||
CarriageContraptionEntityRenderer.translateBogey(ms, bogey, bogeySpacing, viewYRot, viewXRot, partialTicks);
|
||||
ms.translate(0, -1.5 - 1 / 128f, 0);
|
||||
|
||||
instance.beginFrame(bogey.wheelAngle.getValue(partialTicks), ms);
|
||||
ms.popPose();
|
||||
}
|
||||
|
||||
ms.popPose();
|
||||
|
@ -66,7 +81,8 @@ public class CarriageContraptionInstance extends EntityInstance<CarriageContrapt
|
|||
|
||||
@Override
|
||||
public void updateLight() {
|
||||
if (bogeys == null) return;
|
||||
if (bogeys == null)
|
||||
return;
|
||||
|
||||
bogeys.forEach(instance -> {
|
||||
if (instance != null)
|
||||
|
@ -76,7 +92,8 @@ public class CarriageContraptionInstance extends EntityInstance<CarriageContrapt
|
|||
|
||||
@Override
|
||||
public void remove() {
|
||||
if (bogeys == null) return;
|
||||
if (bogeys == null)
|
||||
return;
|
||||
|
||||
bogeys.forEach(instance -> {
|
||||
if (instance != null)
|
||||
|
|
|
@ -18,6 +18,7 @@ import net.minecraft.client.renderer.RenderType;
|
|||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LightLayer;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
@ -35,14 +36,15 @@ public class CarriageCouplingRenderer {
|
|||
return;
|
||||
|
||||
Vec3 camera = cameraEntity.getPosition(partialTicks);
|
||||
Level level = cameraEntity.level;
|
||||
|
||||
for (Train train : trains) {
|
||||
List<Carriage> carriages = train.carriages;
|
||||
for (int i = 0; i < carriages.size() - 1; i++) {
|
||||
Carriage carriage = carriages.get(i);
|
||||
CarriageContraptionEntity entity = carriage.entity.get();
|
||||
CarriageContraptionEntity entity = carriage.getDimensional(level).entity.get();
|
||||
Carriage carriage2 = carriages.get(i + 1);
|
||||
CarriageContraptionEntity entity2 = carriage.entity.get();
|
||||
CarriageContraptionEntity entity2 = carriage.getDimensional(level).entity.get();
|
||||
|
||||
if (entity == null || entity2 == null)
|
||||
continue;
|
||||
|
@ -51,7 +53,7 @@ public class CarriageCouplingRenderer {
|
|||
CarriageBogey bogey2 = carriage2.leadingBogey();
|
||||
Vec3 anchor = bogey1.couplingAnchors.getSecond();
|
||||
Vec3 anchor2 = bogey2.couplingAnchors.getFirst();
|
||||
|
||||
|
||||
if (anchor == null || anchor2 == null)
|
||||
continue;
|
||||
if (!anchor.closerThan(camera, 64))
|
||||
|
|
|
@ -16,6 +16,8 @@ import org.apache.commons.lang3.mutable.MutableBoolean;
|
|||
import com.simibubi.create.content.logistics.trains.TrackEdge;
|
||||
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNode;
|
||||
import com.simibubi.create.content.logistics.trains.entity.Carriage.DimensionalCarriageEntity;
|
||||
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ITrackSelector;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
|
@ -107,10 +109,12 @@ public class CarriageSyncData {
|
|||
}
|
||||
|
||||
public void update(CarriageContraptionEntity entity, Carriage carriage) {
|
||||
DimensionalCarriageEntity dce = carriage.getDimensional(entity.level);
|
||||
|
||||
TrackGraph graph = carriage.train.graph;
|
||||
if (graph == null) {
|
||||
fallbackLocations = Pair.of(carriage.positionAnchor, carriage.rotationAnchors);
|
||||
carriage.pointsInitialised = true;
|
||||
fallbackLocations = Pair.of(dce.positionAnchor, dce.rotationAnchors);
|
||||
dce.pointsInitialised = true;
|
||||
setDirty(true);
|
||||
return;
|
||||
}
|
||||
|
@ -136,10 +140,12 @@ public class CarriageSyncData {
|
|||
}
|
||||
|
||||
public void apply(CarriageContraptionEntity entity, Carriage carriage) {
|
||||
DimensionalCarriageEntity dce = carriage.getDimensional(entity.level);
|
||||
|
||||
fallbackPointSnapshot = null;
|
||||
if (fallbackLocations != null) {
|
||||
fallbackPointSnapshot = Pair.of(carriage.positionAnchor, carriage.rotationAnchors);
|
||||
carriage.pointsInitialised = true;
|
||||
fallbackPointSnapshot = Pair.of(dce.positionAnchor, dce.rotationAnchors);
|
||||
dce.pointsInitialised = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -154,7 +160,7 @@ public class CarriageSyncData {
|
|||
|
||||
CarriageBogey bogey = carriage.bogeys.get(i / 2 == 0);
|
||||
TravellingPoint bogeyPoint = bogey.points.get(i % 2 == 0);
|
||||
TravellingPoint point = carriage.pointsInitialised ? pointsToApproach[i] : bogeyPoint;
|
||||
TravellingPoint point = dce.pointsInitialised ? pointsToApproach[i] : bogeyPoint;
|
||||
|
||||
Couple<TrackNode> nodes = pair.getFirst()
|
||||
.map(graph::getNode);
|
||||
|
@ -170,7 +176,7 @@ public class CarriageSyncData {
|
|||
point.edge = edge;
|
||||
point.position = pair.getSecond();
|
||||
|
||||
if (carriage.pointsInitialised) {
|
||||
if (dce.pointsInitialised) {
|
||||
float foundDistance = -1;
|
||||
boolean direction = false;
|
||||
for (boolean forward : Iterate.trueAndFalse) {
|
||||
|
@ -194,9 +200,9 @@ public class CarriageSyncData {
|
|||
}
|
||||
}
|
||||
|
||||
if (!carriage.pointsInitialised) {
|
||||
if (!dce.pointsInitialised) {
|
||||
carriage.train.navigation.distanceToDestination = distanceToDestination;
|
||||
carriage.pointsInitialised = true;
|
||||
dce.pointsInitialised = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -207,10 +213,12 @@ public class CarriageSyncData {
|
|||
}
|
||||
|
||||
public void approach(CarriageContraptionEntity entity, Carriage carriage, float partial) {
|
||||
DimensionalCarriageEntity dce = carriage.getDimensional(entity.level);
|
||||
|
||||
if (fallbackLocations != null && fallbackPointSnapshot != null) {
|
||||
carriage.positionAnchor = approachVector(partial, carriage.positionAnchor, fallbackLocations.getFirst(),
|
||||
dce.positionAnchor = approachVector(partial, dce.positionAnchor, fallbackLocations.getFirst(),
|
||||
fallbackPointSnapshot.getFirst());
|
||||
carriage.rotationAnchors.replaceWithContext((current, first) -> approachVector(partial, current,
|
||||
dce.rotationAnchors.replaceWithContext((current, first) -> approachVector(partial, current,
|
||||
fallbackLocations.getSecond()
|
||||
.get(first),
|
||||
fallbackPointSnapshot.getSecond()
|
||||
|
@ -238,9 +246,9 @@ public class CarriageSyncData {
|
|||
MutableBoolean success = new MutableBoolean(true);
|
||||
TravellingPoint toApproach = pointsToApproach[index];
|
||||
|
||||
point.travel(graph, partial * f,
|
||||
point.follow(toApproach, b -> success.setValue(success.booleanValue() && b)),
|
||||
point.ignoreEdgePoints(), point.ignoreTurns());
|
||||
ITrackSelector trackSelector =
|
||||
point.follow(toApproach, b -> success.setValue(success.booleanValue() && b));
|
||||
point.travel(graph, partial * f, trackSelector);
|
||||
|
||||
// could not pathfind to server location
|
||||
if (!success.booleanValue()) {
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.apache.commons.lang3.mutable.MutableObject;
|
|||
|
||||
import com.jozufozu.flywheel.repack.joml.Math;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.logistics.trains.DimensionPalette;
|
||||
import com.simibubi.create.content.logistics.trains.TrackEdge;
|
||||
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNode;
|
||||
|
@ -37,9 +38,7 @@ import com.simibubi.create.foundation.utility.Iterate;
|
|||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
@ -368,7 +367,7 @@ public class Navigation {
|
|||
cancelNavigation();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (Math.abs(distanceToDestination) > 100)
|
||||
announceArrival = true;
|
||||
|
||||
|
@ -460,7 +459,7 @@ public class Navigation {
|
|||
return true;
|
||||
});
|
||||
|
||||
if (!train.doubleEnded || !train.hasBackwardConductor())
|
||||
if (!train.doubleEnded || !train.manualTick && !train.hasBackwardConductor())
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -621,14 +620,9 @@ public class Navigation {
|
|||
|
||||
List<Entry<TrackNode, TrackEdge>> validTargets = new ArrayList<>();
|
||||
Map<TrackNode, TrackEdge> connectionsFrom = graph.getConnectionsFrom(node2);
|
||||
for (Entry<TrackNode, TrackEdge> connection : connectionsFrom.entrySet()) {
|
||||
TrackEdge newEdge = connection.getValue();
|
||||
Vec3 currentDirection = edge.getDirection(false);
|
||||
Vec3 newDirection = newEdge.getDirection(true);
|
||||
if (currentDirection.dot(newDirection) < 7 / 8f)
|
||||
continue;
|
||||
validTargets.add(connection);
|
||||
}
|
||||
for (Entry<TrackNode, TrackEdge> connection : connectionsFrom.entrySet())
|
||||
if (edge.canTravelTo(connection.getValue()))
|
||||
validTargets.add(connection);
|
||||
|
||||
if (validTargets.isEmpty())
|
||||
continue;
|
||||
|
@ -673,7 +667,7 @@ public class Navigation {
|
|||
Pair<Couple<TrackNode>, TrackEdge> current, GlobalStation station);
|
||||
}
|
||||
|
||||
public CompoundTag write() {
|
||||
public CompoundTag write(DimensionPalette dimensions) {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
if (destination == null)
|
||||
return tag;
|
||||
|
@ -685,8 +679,7 @@ public class Navigation {
|
|||
tag.put("Path", NBTHelper.writeCompoundList(currentPath, c -> {
|
||||
CompoundTag nbt = new CompoundTag();
|
||||
nbt.put("Nodes", c.map(TrackNode::getLocation)
|
||||
.map(BlockPos::new)
|
||||
.serializeEach(NbtUtils::writeBlockPos));
|
||||
.serializeEach(loc -> loc.write(dimensions)));
|
||||
return nbt;
|
||||
}));
|
||||
if (waitingForSignal == null)
|
||||
|
@ -698,7 +691,7 @@ public class Navigation {
|
|||
return tag;
|
||||
}
|
||||
|
||||
public void read(CompoundTag tag, TrackGraph graph) {
|
||||
public void read(CompoundTag tag, TrackGraph graph, DimensionPalette dimensions) {
|
||||
destination = graph != null && tag.contains("Destination")
|
||||
? graph.getPoint(EdgePointType.STATION, tag.getUUID("Destination"))
|
||||
: null;
|
||||
|
@ -713,8 +706,7 @@ public class Navigation {
|
|||
currentPath.clear();
|
||||
NBTHelper.iterateCompoundList(tag.getList("Path", Tag.TAG_COMPOUND),
|
||||
c -> currentPath.add(Couple
|
||||
.deserializeEach(c.getList("Nodes", Tag.TAG_COMPOUND),
|
||||
c2 -> TrackNodeLocation.fromPackedPos(NbtUtils.readBlockPos(c2)))
|
||||
.deserializeEach(c.getList("Nodes", Tag.TAG_COMPOUND), c2 -> TrackNodeLocation.read(c2, dimensions))
|
||||
.map(graph::locateNode)));
|
||||
waitingForSignal = tag.contains("BlockingSignal")
|
||||
? Pair.of(tag.getUUID("BlockingSignal"), tag.getBoolean("BlockingSignalSide"))
|
||||
|
|
|
@ -20,10 +20,12 @@ import org.apache.commons.lang3.mutable.MutableBoolean;
|
|||
import org.apache.commons.lang3.mutable.MutableObject;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.logistics.trains.DimensionPalette;
|
||||
import com.simibubi.create.content.logistics.trains.GraphLocation;
|
||||
import com.simibubi.create.content.logistics.trains.TrackEdge;
|
||||
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNode;
|
||||
import com.simibubi.create.content.logistics.trains.entity.Carriage.DimensionalCarriageEntity;
|
||||
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.IEdgePointListener;
|
||||
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ITrackSelector;
|
||||
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.SteerDirection;
|
||||
|
@ -50,6 +52,7 @@ import net.minecraft.core.Direction.Axis;
|
|||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
|
@ -72,6 +75,8 @@ public class Train {
|
|||
public Component name;
|
||||
public TrainStatus status;
|
||||
|
||||
public boolean invalid;
|
||||
|
||||
public SteerDirection manualSteer;
|
||||
public boolean manualTick;
|
||||
|
||||
|
@ -154,7 +159,7 @@ public class Train {
|
|||
Create.RAILWAYS.markTracksDirty();
|
||||
|
||||
if (graph == null) {
|
||||
carriages.forEach(c -> c.manageEntity(level));
|
||||
carriages.forEach(c -> c.manageEntities(level));
|
||||
updateConductors();
|
||||
return;
|
||||
}
|
||||
|
@ -175,9 +180,40 @@ public class Train {
|
|||
Carriage carriage = carriages.get(i);
|
||||
if (previousCarriage != null) {
|
||||
int target = carriageSpacing.get(i - 1);
|
||||
Vec3 leadingAnchor = carriage.leadingAnchor();
|
||||
Vec3 trailingAnchor = previousCarriage.trailingAnchor();
|
||||
double actual = leadingAnchor.distanceTo(trailingAnchor);
|
||||
double actual = target;
|
||||
|
||||
TravellingPoint leadingPoint = carriage.getLeadingPoint();
|
||||
TravellingPoint trailingPoint = previousCarriage.getTrailingPoint();
|
||||
|
||||
int entries = 0;
|
||||
double total = 0;
|
||||
|
||||
if (leadingPoint.node1 != null && trailingPoint.node1 != null) {
|
||||
ResourceKey<Level> d1 = leadingPoint.node1.getLocation().dimension;
|
||||
ResourceKey<Level> d2 = trailingPoint.node1.getLocation().dimension;
|
||||
for (boolean b : Iterate.trueAndFalse) {
|
||||
ResourceKey<Level> d = b ? d1 : d2;
|
||||
if (!b && d1.equals(d2))
|
||||
continue;
|
||||
|
||||
DimensionalCarriageEntity dimensional = carriage.getDimensionalIfPresent(d);
|
||||
DimensionalCarriageEntity dimensional2 = previousCarriage.getDimensionalIfPresent(d);
|
||||
if (dimensional == null || dimensional2 == null)
|
||||
continue;
|
||||
|
||||
Vec3 leadingAnchor = dimensional.leadingAnchor();
|
||||
Vec3 trailingAnchor = dimensional2.trailingAnchor();
|
||||
if (leadingAnchor == null || trailingAnchor == null)
|
||||
continue;
|
||||
|
||||
total += leadingAnchor.distanceTo(trailingAnchor);
|
||||
entries++;
|
||||
}
|
||||
}
|
||||
|
||||
if (entries > 0)
|
||||
actual = total / entries;
|
||||
|
||||
stress[i - 1] = target - actual;
|
||||
}
|
||||
previousCarriage = carriage;
|
||||
|
@ -383,10 +419,19 @@ public class Train {
|
|||
if (derailed)
|
||||
return;
|
||||
|
||||
Vec3 start = (speed < 0 ? carriage.getTrailingPoint() : carriage.getLeadingPoint()).getPosition();
|
||||
Vec3 end = (speed < 0 ? carriage.getLeadingPoint() : carriage.getTrailingPoint()).getPosition();
|
||||
TravellingPoint trailingPoint = carriage.getTrailingPoint();
|
||||
TravellingPoint leadingPoint = carriage.getLeadingPoint();
|
||||
|
||||
Pair<Train, Vec3> collision = findCollidingTrain(level, start, end, this);
|
||||
if (leadingPoint.node1 == null || trailingPoint.node1 == null)
|
||||
return;
|
||||
ResourceKey<Level> dimension = leadingPoint.node1.getLocation().dimension;
|
||||
if (!dimension.equals(trailingPoint.node1.getLocation().dimension))
|
||||
return;
|
||||
|
||||
Vec3 start = (speed < 0 ? trailingPoint : leadingPoint).getPosition();
|
||||
Vec3 end = (speed < 0 ? leadingPoint : trailingPoint).getPosition();
|
||||
|
||||
Pair<Train, Vec3> collision = findCollidingTrain(level, start, end, this, dimension);
|
||||
if (collision == null)
|
||||
return;
|
||||
|
||||
|
@ -402,7 +447,8 @@ public class Train {
|
|||
train.crash();
|
||||
}
|
||||
|
||||
public static Pair<Train, Vec3> findCollidingTrain(Level level, Vec3 start, Vec3 end, Train ignore) {
|
||||
public static Pair<Train, Vec3> findCollidingTrain(Level level, Vec3 start, Vec3 end, Train ignore,
|
||||
ResourceKey<Level> dimension) {
|
||||
for (Train train : Create.RAILWAYS.sided(level).trains.values()) {
|
||||
if (train == ignore)
|
||||
continue;
|
||||
|
@ -419,6 +465,11 @@ public class Train {
|
|||
TravellingPoint otherTrailing = otherCarriage.getTrailingPoint();
|
||||
if (otherLeading.edge == null || otherTrailing.edge == null)
|
||||
continue;
|
||||
ResourceKey<Level> otherDimension = otherLeading.node1.getLocation().dimension;
|
||||
if (!otherDimension.equals(otherTrailing.node1.getLocation().dimension))
|
||||
continue;
|
||||
if (!otherDimension.equals(dimension))
|
||||
continue;
|
||||
|
||||
Vec3 start2 = otherLeading.getPosition();
|
||||
Vec3 end2 = otherTrailing.getPosition();
|
||||
|
@ -486,7 +537,7 @@ public class Train {
|
|||
for (int i = 0; i < carriages.size(); i++) {
|
||||
|
||||
Carriage carriage = carriages.get(backwards ? carriages.size() - i - 1 : i);
|
||||
CarriageContraptionEntity entity = carriage.entity.get();
|
||||
CarriageContraptionEntity entity = carriage.anyAvailableEntity();
|
||||
if (entity == null)
|
||||
return false;
|
||||
|
||||
|
@ -511,7 +562,9 @@ public class Train {
|
|||
|
||||
public boolean canDisassemble() {
|
||||
for (Carriage carriage : carriages) {
|
||||
CarriageContraptionEntity entity = carriage.entity.get();
|
||||
if (carriage.presentInMultipleDimensions())
|
||||
return false;
|
||||
CarriageContraptionEntity entity = carriage.anyAvailableEntity();
|
||||
if (entity == null)
|
||||
return false;
|
||||
if (!Mth.equal(entity.pitch, 0))
|
||||
|
@ -629,11 +682,8 @@ public class Train {
|
|||
}
|
||||
|
||||
public void syncTrackGraphChanges() {
|
||||
for (Carriage carriage : carriages) {
|
||||
CarriageContraptionEntity entity = carriage.entity.get();
|
||||
if (entity != null)
|
||||
entity.setGraph(graph == null ? null : graph.id);
|
||||
}
|
||||
for (Carriage carriage : carriages)
|
||||
carriage.forEachPresentEntity(e -> e.setGraph(graph == null ? null : graph.id));
|
||||
}
|
||||
|
||||
public int getTotalLength() {
|
||||
|
@ -681,7 +731,10 @@ public class Train {
|
|||
public LivingEntity getOwner(Level level) {
|
||||
try {
|
||||
UUID uuid = owner;
|
||||
return uuid == null ? null : level.getPlayerByUUID(uuid);
|
||||
return uuid == null ? null
|
||||
: level.getServer()
|
||||
.getPlayerList()
|
||||
.getPlayer(uuid);
|
||||
} catch (IllegalArgumentException illegalargumentexception) {
|
||||
return null;
|
||||
}
|
||||
|
@ -799,13 +852,13 @@ public class Train {
|
|||
return Penalties.ANY_TRAIN;
|
||||
}
|
||||
|
||||
public CompoundTag write() {
|
||||
public CompoundTag write(DimensionPalette dimensions) {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.putUUID("Id", id);
|
||||
tag.putUUID("Owner", owner);
|
||||
if (graph != null)
|
||||
tag.putUUID("Graph", graph.id);
|
||||
tag.put("Carriages", NBTHelper.writeCompoundList(carriages, Carriage::write));
|
||||
tag.put("Carriages", NBTHelper.writeCompoundList(carriages, c -> c.write(dimensions)));
|
||||
tag.putIntArray("CarriageSpacing", carriageSpacing);
|
||||
tag.putBoolean("DoubleEnded", doubleEnded);
|
||||
tag.putDouble("Speed", speed);
|
||||
|
@ -830,22 +883,22 @@ public class Train {
|
|||
compoundTag.putUUID("Id", uid);
|
||||
return compoundTag;
|
||||
}));
|
||||
tag.put("MigratingPoints", NBTHelper.writeCompoundList(migratingPoints, TrainMigration::write));
|
||||
tag.put("MigratingPoints", NBTHelper.writeCompoundList(migratingPoints, tm -> tm.write(dimensions)));
|
||||
|
||||
tag.put("Runtime", runtime.write());
|
||||
tag.put("Navigation", navigation.write());
|
||||
tag.put("Navigation", navigation.write(dimensions));
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
public static Train read(CompoundTag tag, Map<UUID, TrackGraph> trackNetworks) {
|
||||
public static Train read(CompoundTag tag, Map<UUID, TrackGraph> trackNetworks, DimensionPalette dimensions) {
|
||||
UUID id = tag.getUUID("Id");
|
||||
UUID owner = tag.getUUID("Owner");
|
||||
UUID graphId = tag.contains("Graph") ? tag.getUUID("Graph") : null;
|
||||
TrackGraph graph = graphId == null ? null : trackNetworks.get(graphId);
|
||||
List<Carriage> carriages = new ArrayList<>();
|
||||
NBTHelper.iterateCompoundList(tag.getList("Carriages", Tag.TAG_COMPOUND),
|
||||
c -> carriages.add(Carriage.read(c, graph)));
|
||||
c -> carriages.add(Carriage.read(c, graph, dimensions)));
|
||||
List<Integer> carriageSpacing = new ArrayList<>();
|
||||
for (int i : tag.getIntArray("CarriageSpacing"))
|
||||
carriageSpacing.add(i);
|
||||
|
@ -868,10 +921,10 @@ public class Train {
|
|||
NBTHelper.iterateCompoundList(tag.getList("ReservedSignalBlocks", Tag.TAG_COMPOUND),
|
||||
c -> train.reservedSignalBlocks.add(c.getUUID("Id")));
|
||||
NBTHelper.iterateCompoundList(tag.getList("MigratingPoints", Tag.TAG_COMPOUND),
|
||||
c -> train.migratingPoints.add(TrainMigration.read(c)));
|
||||
c -> train.migratingPoints.add(TrainMigration.read(c, dimensions)));
|
||||
|
||||
train.runtime.read(tag.getCompound("Runtime"));
|
||||
train.navigation.read(tag.getCompound("Navigation"), graph);
|
||||
train.navigation.read(tag.getCompound("Navigation"), graph, dimensions);
|
||||
|
||||
if (train.getCurrentStation() != null)
|
||||
train.getCurrentStation()
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.simibubi.create.content.logistics.trains.entity;
|
|||
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.simibubi.create.content.logistics.trains.DimensionPalette;
|
||||
import com.simibubi.create.content.logistics.trains.GraphLocation;
|
||||
import com.simibubi.create.content.logistics.trains.TrackEdge;
|
||||
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
||||
|
@ -10,9 +11,7 @@ import com.simibubi.create.content.logistics.trains.TrackNodeLocation;
|
|||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
@ -100,24 +99,22 @@ public class TrainMigration {
|
|||
return null;
|
||||
}
|
||||
|
||||
public CompoundTag write() {
|
||||
public CompoundTag write(DimensionPalette dimensions) {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.putBoolean("Curve", curve);
|
||||
tag.put("Fallback", VecHelper.writeNBT(fallback));
|
||||
tag.putDouble("Position", positionOnOldEdge);
|
||||
tag.put("Nodes", locations.map(BlockPos::new)
|
||||
.serializeEach(NbtUtils::writeBlockPos));
|
||||
tag.put("Nodes", locations.serializeEach(l -> l.write(dimensions)));
|
||||
return tag;
|
||||
}
|
||||
|
||||
public static TrainMigration read(CompoundTag tag) {
|
||||
public static TrainMigration read(CompoundTag tag, DimensionPalette dimensions) {
|
||||
TrainMigration trainMigration = new TrainMigration();
|
||||
trainMigration.curve = tag.getBoolean("Curve");
|
||||
trainMigration.fallback = VecHelper.readNBT(tag.getList("Fallback", Tag.TAG_DOUBLE));
|
||||
trainMigration.positionOnOldEdge = tag.getDouble("Position");
|
||||
trainMigration.locations =
|
||||
Couple.deserializeEach(tag.getList("Nodes", Tag.TAG_COMPOUND), NbtUtils::readBlockPos)
|
||||
.map(TrackNodeLocation::fromPackedPos);
|
||||
Couple.deserializeEach(tag.getList("Nodes", Tag.TAG_COMPOUND), c -> TrackNodeLocation.read(c, dimensions));
|
||||
return trainMigration;
|
||||
}
|
||||
|
||||
|
|
|
@ -189,14 +189,18 @@ public class TrainRelocator {
|
|||
};
|
||||
ITrackSelector steer = probe.steer(SteerDirection.NONE, track.getUpNormal(level, pos, blockState));
|
||||
MutableBoolean blocked = new MutableBoolean(false);
|
||||
MutableBoolean portal = new MutableBoolean(false);
|
||||
|
||||
MutableInt blockingIndex = new MutableInt(0);
|
||||
train.forEachTravellingPointBackwards((tp, d) -> {
|
||||
if (blocked.booleanValue())
|
||||
return;
|
||||
probe.travel(graph, d, steer, ignoreSignals, ignoreTurns);
|
||||
probe.travel(graph, d, steer, ignoreSignals, ignoreTurns, $ -> {
|
||||
portal.setTrue();
|
||||
return true;
|
||||
});
|
||||
recorder.accept(probe);
|
||||
if (probe.blocked) {
|
||||
if (probe.blocked || portal.booleanValue()) {
|
||||
blocked.setTrue();
|
||||
return;
|
||||
}
|
||||
|
@ -212,7 +216,8 @@ public class TrainRelocator {
|
|||
Vec3 vec1 = recordedVecs.get(i);
|
||||
Vec3 vec2 = recordedVecs.get(i + 1);
|
||||
boolean blocking = i >= blockingIndex.intValue() - 1;
|
||||
boolean collided = !blocked.booleanValue() && Train.findCollidingTrain(level, vec1, vec2, train) != null;
|
||||
boolean collided = !blocked.booleanValue()
|
||||
&& Train.findCollidingTrain(level, vec1, vec2, train, level.dimension()) != null;
|
||||
if (level.isClientSide && simulate)
|
||||
toVisualise.add(vec2);
|
||||
if (collided || blocking)
|
||||
|
|
|
@ -70,6 +70,13 @@ public class TrainStatus {
|
|||
track = true;
|
||||
}
|
||||
|
||||
public void doublePortal() {
|
||||
if (track)
|
||||
return;
|
||||
displayInformation("A Carriage cannot enter a portal whilst leaving another.", false);
|
||||
track = true;
|
||||
}
|
||||
|
||||
public void endOfTrack() {
|
||||
if (track)
|
||||
return;
|
||||
|
|
|
@ -11,10 +11,12 @@ import java.util.function.BiConsumer;
|
|||
import java.util.function.BiFunction;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.logistics.trains.DimensionPalette;
|
||||
import com.simibubi.create.content.logistics.trains.GraphLocation;
|
||||
import com.simibubi.create.content.logistics.trains.TrackEdge;
|
||||
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
||||
|
@ -25,9 +27,7 @@ import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.
|
|||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
@ -59,6 +59,9 @@ public class TravellingPoint {
|
|||
public static interface ITurnListener extends BiConsumer<Double, TrackEdge> {
|
||||
};
|
||||
|
||||
public static interface IPortalListener extends Predicate<Couple<TrackNodeLocation>> {
|
||||
};
|
||||
|
||||
public TravellingPoint() {}
|
||||
|
||||
public TravellingPoint(TrackNode node1, TrackNode node2, TrackEdge edge, double position) {
|
||||
|
@ -77,6 +80,10 @@ public class TravellingPoint {
|
|||
};
|
||||
}
|
||||
|
||||
public IPortalListener ignorePortals() {
|
||||
return $ -> false;
|
||||
}
|
||||
|
||||
public ITrackSelector random() {
|
||||
return (graph, pair) -> pair.getSecond()
|
||||
.get(Create.RANDOM.nextInt(pair.getSecond()
|
||||
|
@ -176,8 +183,22 @@ public class TravellingPoint {
|
|||
};
|
||||
}
|
||||
|
||||
public double travel(TrackGraph graph, double distance, ITrackSelector trackSelector) {
|
||||
return travel(graph, distance, trackSelector, ignoreEdgePoints());
|
||||
}
|
||||
|
||||
public double travel(TrackGraph graph, double distance, ITrackSelector trackSelector,
|
||||
IEdgePointListener signalListener) {
|
||||
return travel(graph, distance, trackSelector, signalListener, ignoreTurns());
|
||||
}
|
||||
|
||||
public double travel(TrackGraph graph, double distance, ITrackSelector trackSelector,
|
||||
IEdgePointListener signalListener, ITurnListener turnListener) {
|
||||
return travel(graph, distance, trackSelector, signalListener, turnListener, ignorePortals());
|
||||
}
|
||||
|
||||
public double travel(TrackGraph graph, double distance, ITrackSelector trackSelector,
|
||||
IEdgePointListener signalListener, ITurnListener turnListener, IPortalListener portalListener) {
|
||||
blocked = false;
|
||||
double edgeLength = edge.getLength();
|
||||
if (Mth.equal(distance, 0))
|
||||
|
@ -185,7 +206,7 @@ public class TravellingPoint {
|
|||
|
||||
double prevPos = position;
|
||||
double traveled = distance;
|
||||
double currentT = position / edgeLength;
|
||||
double currentT = edgeLength == 0 ? 0 : position / edgeLength;
|
||||
double incrementT = edge.incrementT(currentT, distance);
|
||||
position = incrementT * edgeLength;
|
||||
|
||||
|
@ -222,9 +243,7 @@ public class TravellingPoint {
|
|||
continue;
|
||||
|
||||
TrackEdge newEdge = entry.getValue();
|
||||
Vec3 currentDirection = edge.getDirection(false);
|
||||
Vec3 newDirection = newEdge.getDirection(true);
|
||||
if (currentDirection.dot(newDirection) < 7 / 8f)
|
||||
if (!edge.canTravelTo(newEdge))
|
||||
continue;
|
||||
|
||||
validTargets.add(entry);
|
||||
|
@ -240,6 +259,16 @@ public class TravellingPoint {
|
|||
Entry<TrackNode, TrackEdge> entry = validTargets.size() == 1 ? validTargets.get(0)
|
||||
: trackSelector.apply(graph, Pair.of(true, validTargets));
|
||||
|
||||
if (entry.getValue()
|
||||
.getLength() == 0 && portalListener.test(
|
||||
Couple.create(node2.getLocation(), entry.getKey()
|
||||
.getLocation()))) {
|
||||
traveled -= position - edgeLength;
|
||||
position = edgeLength;
|
||||
blocked = true;
|
||||
break;
|
||||
}
|
||||
|
||||
node1 = node2;
|
||||
node2 = entry.getKey();
|
||||
edge = entry.getValue();
|
||||
|
@ -272,12 +301,9 @@ public class TravellingPoint {
|
|||
TrackNode newNode = entry.getKey();
|
||||
if (newNode == node2)
|
||||
continue;
|
||||
|
||||
TrackEdge newEdge = graph.getConnectionsFrom(newNode)
|
||||
.get(node1);
|
||||
Vec3 currentDirection = edge.getDirection(true);
|
||||
Vec3 newDirection = newEdge.getDirection(false);
|
||||
if (currentDirection.dot(newDirection) < 7 / 8f)
|
||||
if (!graph.getConnectionsFrom(newNode)
|
||||
.get(node1)
|
||||
.canTravelTo(edge))
|
||||
continue;
|
||||
|
||||
validTargets.add(entry);
|
||||
|
@ -293,6 +319,16 @@ public class TravellingPoint {
|
|||
Entry<TrackNode, TrackEdge> entry = validTargets.size() == 1 ? validTargets.get(0)
|
||||
: trackSelector.apply(graph, Pair.of(false, validTargets));
|
||||
|
||||
if (entry.getValue()
|
||||
.getLength() == 0 && portalListener.test(
|
||||
Couple.create(entry.getKey()
|
||||
.getLocation(), node1.getLocation()))) {
|
||||
traveled -= position;
|
||||
position = 0;
|
||||
blocked = true;
|
||||
break;
|
||||
}
|
||||
|
||||
node2 = node1;
|
||||
node1 = entry.getKey();
|
||||
edge = graph.getConnectionsFrom(node1)
|
||||
|
@ -322,9 +358,10 @@ public class TravellingPoint {
|
|||
if (edge.isTurn())
|
||||
turnListener.accept(Math.max(0, totalDistance), edge);
|
||||
|
||||
EdgeData edgeData = edge.getEdgeData();
|
||||
double from = forward ? prevPos : position;
|
||||
double to = forward ? position : prevPos;
|
||||
|
||||
EdgeData edgeData = edge.getEdgeData();
|
||||
List<TrackEdgePoint> edgePoints = edgeData.getPoints();
|
||||
|
||||
double length = edge.getLength();
|
||||
|
@ -353,7 +390,11 @@ public class TravellingPoint {
|
|||
}
|
||||
|
||||
public Vec3 getPosition() {
|
||||
double t = position / edge.getLength();
|
||||
return getPositionWithOffset(0);
|
||||
}
|
||||
|
||||
public Vec3 getPositionWithOffset(double offset) {
|
||||
double t = (position + offset) / edge.getLength();
|
||||
return edge.getPosition(t)
|
||||
.add(edge.getNormal(node1, node2, t)
|
||||
.scale(1));
|
||||
|
@ -369,28 +410,25 @@ public class TravellingPoint {
|
|||
.get(node2);
|
||||
}
|
||||
|
||||
public CompoundTag write() {
|
||||
public CompoundTag write(DimensionPalette dimensions) {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
Couple<TrackNode> nodes = Couple.create(node1, node2);
|
||||
if (nodes.either(Objects::isNull))
|
||||
return tag;
|
||||
tag.put("Nodes", nodes.map(TrackNode::getLocation)
|
||||
.map(BlockPos::new)
|
||||
.serializeEach(NbtUtils::writeBlockPos));
|
||||
.serializeEach(loc -> loc.write(dimensions)));
|
||||
tag.putDouble("Position", position);
|
||||
return tag;
|
||||
}
|
||||
|
||||
public static TravellingPoint read(CompoundTag tag, TrackGraph graph) {
|
||||
public static TravellingPoint read(CompoundTag tag, TrackGraph graph, DimensionPalette dimensions) {
|
||||
if (graph == null)
|
||||
return new TravellingPoint(null, null, null, 0);
|
||||
|
||||
Couple<TrackNode> locs =
|
||||
tag.contains("Nodes")
|
||||
? Couple.deserializeEach(tag.getList("Nodes", Tag.TAG_COMPOUND), NbtUtils::readBlockPos)
|
||||
.map(TrackNodeLocation::fromPackedPos)
|
||||
.map(graph::locateNode)
|
||||
: Couple.create(null, null);
|
||||
Couple<TrackNode> locs = tag.contains("Nodes")
|
||||
? Couple.deserializeEach(tag.getList("Nodes", Tag.TAG_COMPOUND), c -> TrackNodeLocation.read(c, dimensions))
|
||||
.map(graph::locateNode)
|
||||
: Couple.create(null, null);
|
||||
|
||||
if (locs.either(Objects::isNull))
|
||||
return new TravellingPoint(null, null, null, 0);
|
||||
|
|
|
@ -10,6 +10,7 @@ import javax.annotation.Nullable;
|
|||
|
||||
import com.google.common.base.Objects;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.logistics.trains.DimensionPalette;
|
||||
import com.simibubi.create.content.logistics.trains.TrackEdge;
|
||||
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNode;
|
||||
|
@ -177,7 +178,7 @@ public class EdgeData {
|
|||
return null;
|
||||
}
|
||||
|
||||
public CompoundTag write() {
|
||||
public CompoundTag write(DimensionPalette dimensions) {
|
||||
CompoundTag nbt = new CompoundTag();
|
||||
if (singleSignalGroup == passiveGroup)
|
||||
NBTHelper.putMarker(nbt, "PassiveGroup");
|
||||
|
@ -194,11 +195,11 @@ public class EdgeData {
|
|||
return tag;
|
||||
}));
|
||||
if (hasIntersections())
|
||||
nbt.put("Intersections", NBTHelper.writeCompoundList(intersections, TrackEdgeIntersection::write));
|
||||
nbt.put("Intersections", NBTHelper.writeCompoundList(intersections, tei -> tei.write(dimensions)));
|
||||
return nbt;
|
||||
}
|
||||
|
||||
public static EdgeData read(CompoundTag nbt, TrackEdge edge, TrackGraph graph) {
|
||||
public static EdgeData read(CompoundTag nbt, TrackEdge edge, TrackGraph graph, DimensionPalette dimensions) {
|
||||
EdgeData data = new EdgeData(edge);
|
||||
if (nbt.contains("SignalGroup"))
|
||||
data.singleSignalGroup = nbt.getUUID("SignalGroup");
|
||||
|
@ -216,8 +217,8 @@ public class EdgeData {
|
|||
data.points.add(point);
|
||||
});
|
||||
if (nbt.contains("Intersections"))
|
||||
data.intersections =
|
||||
NBTHelper.readCompoundList(nbt.getList("Intersections", Tag.TAG_COMPOUND), TrackEdgeIntersection::read);
|
||||
data.intersections = NBTHelper.readCompoundList(nbt.getList("Intersections", Tag.TAG_COMPOUND),
|
||||
c -> TrackEdgeIntersection.read(c, dimensions));
|
||||
return data;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import java.util.Map.Entry;
|
|||
import java.util.UUID;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.logistics.trains.DimensionPalette;
|
||||
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint;
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
|
@ -65,14 +66,14 @@ public class EdgePointStorage {
|
|||
pointsByType.clear();
|
||||
}
|
||||
|
||||
public CompoundTag write() {
|
||||
public CompoundTag write(DimensionPalette dimensions) {
|
||||
CompoundTag nbt = new CompoundTag();
|
||||
for (Entry<EdgePointType<?>, Map<UUID, TrackEdgePoint>> entry : pointsByType.entrySet()) {
|
||||
EdgePointType<?> type = entry.getKey();
|
||||
ListTag list = NBTHelper.writeCompoundList(entry.getValue()
|
||||
.values(), edgePoint -> {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
edgePoint.write(tag);
|
||||
edgePoint.write(tag, dimensions);
|
||||
return tag;
|
||||
});
|
||||
nbt.put(type.getId()
|
||||
|
@ -81,14 +82,14 @@ public class EdgePointStorage {
|
|||
return nbt;
|
||||
}
|
||||
|
||||
public void read(CompoundTag nbt) {
|
||||
public void read(CompoundTag nbt, DimensionPalette dimensions) {
|
||||
for (EdgePointType<?> type : EdgePointType.TYPES.values()) {
|
||||
ListTag list = nbt.getList(type.getId()
|
||||
.toString(), Tag.TAG_COMPOUND);
|
||||
Map<UUID, TrackEdgePoint> map = getMap(type);
|
||||
NBTHelper.iterateCompoundList(list, tag -> {
|
||||
TrackEdgePoint edgePoint = type.create();
|
||||
edgePoint.read(tag, false);
|
||||
edgePoint.read(tag, false, dimensions);
|
||||
map.put(edgePoint.getId(), edgePoint);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import java.util.Map;
|
|||
import java.util.function.Supplier;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.logistics.trains.DimensionPalette;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBoundary;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.GlobalStation;
|
||||
|
@ -44,11 +45,11 @@ public class EdgePointType<T extends TrackEdgePoint> {
|
|||
return id;
|
||||
}
|
||||
|
||||
public static TrackEdgePoint read(FriendlyByteBuf buffer) {
|
||||
public static TrackEdgePoint read(FriendlyByteBuf buffer, DimensionPalette dimensions) {
|
||||
ResourceLocation type = buffer.readResourceLocation();
|
||||
EdgePointType<?> edgePointType = TYPES.get(type);
|
||||
TrackEdgePoint point = edgePointType.create();
|
||||
point.read(buffer);
|
||||
point.read(buffer, dimensions);
|
||||
return point;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,12 +2,11 @@ package com.simibubi.create.content.logistics.trains.management.edgePoint;
|
|||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.simibubi.create.content.logistics.trains.DimensionPalette;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNodeLocation;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.nbt.Tag;
|
||||
|
||||
public class TrackEdgeIntersection {
|
||||
|
@ -31,18 +30,18 @@ public class TrackEdgeIntersection {
|
|||
|| target1.equals(target.getSecond()) && target2.equals(target.getFirst());
|
||||
}
|
||||
|
||||
public CompoundTag write() {
|
||||
public CompoundTag write(DimensionPalette dimensions) {
|
||||
CompoundTag nbt = new CompoundTag();
|
||||
nbt.putUUID("Id", id);
|
||||
if (groupId != null)
|
||||
nbt.putUUID("GroupId", groupId);
|
||||
nbt.putDouble("Location", location);
|
||||
nbt.putDouble("TargetLocation", targetLocation);
|
||||
nbt.put("TargetEdge", target.serializeEach(loc -> NbtUtils.writeBlockPos(new BlockPos(loc))));
|
||||
nbt.put("TargetEdge", target.serializeEach(loc -> loc.write(dimensions)));
|
||||
return nbt;
|
||||
}
|
||||
|
||||
public static TrackEdgeIntersection read(CompoundTag nbt) {
|
||||
public static TrackEdgeIntersection read(CompoundTag nbt, DimensionPalette dimensions) {
|
||||
TrackEdgeIntersection intersection = new TrackEdgeIntersection();
|
||||
intersection.id = nbt.getUUID("Id");
|
||||
if (nbt.contains("GroupId"))
|
||||
|
@ -50,7 +49,7 @@ public class TrackEdgeIntersection {
|
|||
intersection.location = nbt.getDouble("Location");
|
||||
intersection.targetLocation = nbt.getDouble("TargetLocation");
|
||||
intersection.target = Couple.deserializeEach(nbt.getList("TargetEdge", Tag.TAG_COMPOUND),
|
||||
tag -> TrackNodeLocation.fromPackedPos(NbtUtils.readBlockPos(tag)));
|
||||
tag -> TrackNodeLocation.read(tag, dimensions));
|
||||
return intersection;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import javax.annotation.Nullable;
|
|||
import com.jozufozu.flywheel.core.PartialModel;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.logistics.trains.DimensionPalette;
|
||||
import com.simibubi.create.content.logistics.trains.GraphLocation;
|
||||
import com.simibubi.create.content.logistics.trains.ITrackBlock;
|
||||
import com.simibubi.create.content.logistics.trains.TrackEdge;
|
||||
|
@ -186,7 +187,7 @@ public class TrackTargetingBehaviour<T extends TrackEdgePoint> extends TileEntit
|
|||
boolean reverseEdge = front || point instanceof SingleTileEdgePoint;
|
||||
|
||||
if (data != null)
|
||||
point.read(data, true);
|
||||
point.read(data, true, DimensionPalette.read(data));
|
||||
|
||||
point.setId(id);
|
||||
point.setLocation(reverseEdge ? loc.edge : loc.edge.swap(), reverseEdge ? loc.position : length - loc.position);
|
||||
|
|
|
@ -198,6 +198,9 @@ public class TrackTargetingBlockItem extends BlockItem {
|
|||
|
||||
Couple<TrackNode> nodes = location.edge.map(location.graph::locateNode);
|
||||
TrackEdge edge = location.graph.getConnection(nodes);
|
||||
if (edge == null)
|
||||
return;
|
||||
|
||||
EdgeData edgeData = edge.getEdgeData();
|
||||
double edgePosition = location.position;
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import java.util.UUID;
|
|||
|
||||
import com.google.common.base.Objects;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.logistics.trains.DimensionPalette;
|
||||
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNode;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType;
|
||||
|
@ -237,8 +238,8 @@ public class SignalBoundary extends TrackEdgePoint {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void read(CompoundTag nbt, boolean migration) {
|
||||
super.read(nbt, migration);
|
||||
public void read(CompoundTag nbt, boolean migration, DimensionPalette dimensions) {
|
||||
super.read(nbt, migration, dimensions);
|
||||
|
||||
if (migration)
|
||||
return;
|
||||
|
@ -265,8 +266,8 @@ public class SignalBoundary extends TrackEdgePoint {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void read(FriendlyByteBuf buffer) {
|
||||
super.read(buffer);
|
||||
public void read(FriendlyByteBuf buffer, DimensionPalette dimensions) {
|
||||
super.read(buffer, dimensions);
|
||||
for (int i = 1; i <= 2; i++) {
|
||||
if (buffer.readBoolean())
|
||||
groups.set(i == 1, buffer.readUUID());
|
||||
|
@ -274,8 +275,8 @@ public class SignalBoundary extends TrackEdgePoint {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void write(CompoundTag nbt) {
|
||||
super.write(nbt);
|
||||
public void write(CompoundTag nbt, DimensionPalette dimensions) {
|
||||
super.write(nbt, dimensions);
|
||||
for (int i = 1; i <= 2; i++)
|
||||
if (!blockEntities.get(i == 1)
|
||||
.isEmpty())
|
||||
|
@ -293,8 +294,8 @@ public class SignalBoundary extends TrackEdgePoint {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
super.write(buffer);
|
||||
public void write(FriendlyByteBuf buffer, DimensionPalette dimensions) {
|
||||
super.write(buffer, dimensions);
|
||||
for (int i = 1; i <= 2; i++) {
|
||||
boolean hasGroup = groups.get(i == 1) != null;
|
||||
buffer.writeBoolean(hasGroup);
|
||||
|
|
|
@ -24,8 +24,6 @@ import com.simibubi.create.foundation.utility.Couple;
|
|||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public class SignalPropagator {
|
||||
|
||||
public static void onSignalRemoved(TrackGraph graph, SignalBoundary signal) {
|
||||
|
@ -103,7 +101,7 @@ public class SignalPropagator {
|
|||
return true;
|
||||
|
||||
}, false);
|
||||
|
||||
|
||||
group.resolveColor();
|
||||
sync.edgeGroupCreated(groupId, group.color);
|
||||
}
|
||||
|
@ -180,14 +178,10 @@ public class SignalPropagator {
|
|||
continue;
|
||||
|
||||
// chain signal: check if reachable
|
||||
if (forCollection) {
|
||||
Vec3 currentDirection = graph.getConnectionsFrom(prevNode)
|
||||
.get(currentNode)
|
||||
.getDirection(false);
|
||||
Vec3 newDirection = edge.getDirection(true);
|
||||
if (currentDirection.dot(newDirection) < 3 / 4f)
|
||||
continue;
|
||||
}
|
||||
if (forCollection && !graph.getConnectionsFrom(prevNode)
|
||||
.get(currentNode)
|
||||
.canTravelTo(edge))
|
||||
continue;
|
||||
|
||||
TrackEdge oppositeEdge = graph.getConnectionsFrom(nextNode)
|
||||
.get(currentNode);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.simibubi.create.content.logistics.trains.management.edgePoint.signal;
|
||||
|
||||
import com.simibubi.create.content.logistics.trains.DimensionPalette;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
|
@ -35,16 +37,16 @@ public abstract class SingleTileEdgePoint extends TrackEdgePoint {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void read(CompoundTag nbt, boolean migration) {
|
||||
super.read(nbt, migration);
|
||||
public void read(CompoundTag nbt, boolean migration, DimensionPalette dimensions) {
|
||||
super.read(nbt, migration, dimensions);
|
||||
if (migration)
|
||||
return;
|
||||
tilePos = NbtUtils.readBlockPos(nbt.getCompound("TilePos"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(CompoundTag nbt) {
|
||||
super.write(nbt);
|
||||
public void write(CompoundTag nbt, DimensionPalette dimensions) {
|
||||
super.write(nbt, dimensions);
|
||||
nbt.put("TilePos", NbtUtils.writeBlockPos(tilePos));
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.simibubi.create.content.logistics.trains.management.edgePoint.signal
|
|||
import java.util.UUID;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.logistics.trains.DimensionPalette;
|
||||
import com.simibubi.create.content.logistics.trains.TrackEdge;
|
||||
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNode;
|
||||
|
@ -14,7 +15,6 @@ import com.simibubi.create.foundation.utility.Couple;
|
|||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
|
@ -56,7 +56,9 @@ public abstract class TrackEdgePoint {
|
|||
if (behaviour == null)
|
||||
return;
|
||||
CompoundTag migrationData = new CompoundTag();
|
||||
write(migrationData);
|
||||
DimensionPalette dimensions = new DimensionPalette();
|
||||
write(migrationData, dimensions);
|
||||
dimensions.write(migrationData);
|
||||
behaviour.invalidateEdgePoint(migrationData);
|
||||
}
|
||||
|
||||
|
@ -84,32 +86,32 @@ public abstract class TrackEdgePoint {
|
|||
.equals(node1.getLocation());
|
||||
}
|
||||
|
||||
public void read(CompoundTag nbt, boolean migration) {
|
||||
public void read(CompoundTag nbt, boolean migration, DimensionPalette dimensions) {
|
||||
if (migration)
|
||||
return;
|
||||
|
||||
id = nbt.getUUID("Id");
|
||||
position = nbt.getDouble("Position");
|
||||
edgeLocation = Couple.deserializeEach(nbt.getList("Edge", Tag.TAG_COMPOUND),
|
||||
tag -> TrackNodeLocation.fromPackedPos(NbtUtils.readBlockPos(tag)));
|
||||
tag -> TrackNodeLocation.read(tag, dimensions));
|
||||
}
|
||||
|
||||
public void read(FriendlyByteBuf buffer) {
|
||||
public void read(FriendlyByteBuf buffer, DimensionPalette dimensions) {
|
||||
id = buffer.readUUID();
|
||||
edgeLocation = Couple.create(() -> TrackNodeLocation.fromPackedPos(buffer.readBlockPos()));
|
||||
edgeLocation = Couple.create(() -> TrackNodeLocation.receive(buffer, dimensions));
|
||||
position = buffer.readDouble();
|
||||
}
|
||||
|
||||
public void write(CompoundTag nbt) {
|
||||
public void write(CompoundTag nbt, DimensionPalette dimensions) {
|
||||
nbt.putUUID("Id", id);
|
||||
nbt.putDouble("Position", position);
|
||||
nbt.put("Edge", edgeLocation.serializeEach(loc -> NbtUtils.writeBlockPos(new BlockPos(loc))));
|
||||
nbt.put("Edge", edgeLocation.serializeEach(loc -> loc.write(dimensions)));
|
||||
}
|
||||
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
public void write(FriendlyByteBuf buffer, DimensionPalette dimensions) {
|
||||
buffer.writeResourceLocation(type.getId());
|
||||
buffer.writeUUID(id);
|
||||
edgeLocation.forEach(loc -> buffer.writeBlockPos(new BlockPos(loc)));
|
||||
edgeLocation.forEach(loc -> loc.send(buffer, dimensions));
|
||||
buffer.writeDouble(position);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import java.lang.ref.WeakReference;
|
|||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.simibubi.create.content.logistics.trains.DimensionPalette;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNode;
|
||||
import com.simibubi.create.content.logistics.trains.entity.Train;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SingleTileEdgePoint;
|
||||
|
@ -33,16 +34,16 @@ public class GlobalStation extends SingleTileEdgePoint {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void read(CompoundTag nbt, boolean migration) {
|
||||
super.read(nbt, migration);
|
||||
public void read(CompoundTag nbt, boolean migration, DimensionPalette dimensions) {
|
||||
super.read(nbt, migration, dimensions);
|
||||
name = nbt.getString("Name");
|
||||
assembling = nbt.getBoolean("Assembling");
|
||||
nearestTrain = new WeakReference<Train>(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(FriendlyByteBuf buffer) {
|
||||
super.read(buffer);
|
||||
public void read(FriendlyByteBuf buffer, DimensionPalette dimensions) {
|
||||
super.read(buffer, dimensions);
|
||||
name = buffer.readUtf();
|
||||
assembling = buffer.readBoolean();
|
||||
if (buffer.readBoolean())
|
||||
|
@ -50,15 +51,15 @@ public class GlobalStation extends SingleTileEdgePoint {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void write(CompoundTag nbt) {
|
||||
super.write(nbt);
|
||||
public void write(CompoundTag nbt, DimensionPalette dimensions) {
|
||||
super.write(nbt, dimensions);
|
||||
nbt.putString("Name", name);
|
||||
nbt.putBoolean("Assembling", assembling);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
super.write(buffer);
|
||||
public void write(FriendlyByteBuf buffer, DimensionPalette dimensions) {
|
||||
super.write(buffer, dimensions);
|
||||
buffer.writeUtf(name);
|
||||
buffer.writeBoolean(assembling);
|
||||
buffer.writeBoolean(tilePos != null);
|
||||
|
|
|
@ -22,6 +22,7 @@ import com.simibubi.create.content.logistics.trains.ITrackBlock;
|
|||
import com.simibubi.create.content.logistics.trains.TrackEdge;
|
||||
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNode;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNodeLocation;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNodeLocation.DiscoveredLocation;
|
||||
import com.simibubi.create.content.logistics.trains.entity.Carriage;
|
||||
import com.simibubi.create.content.logistics.trains.entity.CarriageBogey;
|
||||
|
@ -409,7 +410,7 @@ public class StationTileEntity extends SmartTileEntity {
|
|||
ITrackBlock track = edgePoint.getTrack();
|
||||
BlockPos bogeyOffset = new BlockPos(track.getUpNormal(level, trackPosition, trackState));
|
||||
|
||||
DiscoveredLocation location = null;
|
||||
TrackNodeLocation location = null;
|
||||
Vec3 centre = Vec3.atBottomCenterOf(trackPosition)
|
||||
.add(0, track.getElevationAtCenter(level, trackPosition, trackState), 0);
|
||||
Collection<DiscoveredLocation> ends = track.getConnected(level, trackPosition, trackState, true, null);
|
||||
|
@ -442,9 +443,9 @@ public class StationTileEntity extends SmartTileEntity {
|
|||
if (points.size() == pointOffsets.size())
|
||||
break;
|
||||
|
||||
DiscoveredLocation currentLocation = location;
|
||||
location = new DiscoveredLocation(location.getLocation()
|
||||
.add(directionVec.scale(.5)));
|
||||
TrackNodeLocation currentLocation = location;
|
||||
location = new TrackNodeLocation(location.getLocation()
|
||||
.add(directionVec.scale(.5))).in(location.dimension);
|
||||
|
||||
if (graph == null)
|
||||
graph = Create.RAILWAYS.getGraph(level, currentLocation);
|
||||
|
|
|
@ -77,7 +77,7 @@ public class StandardBogeyBlock extends Block implements IBogeyBlock, ITE<Standa
|
|||
|
||||
@Override
|
||||
public boolean allowsSingleBogeyCarriage() {
|
||||
return !large;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
package com.simibubi.create.content.logistics.trains.track;
|
||||
|
||||
import static com.simibubi.create.AllShapes.TRACK_ASC;
|
||||
import static com.simibubi.create.AllShapes.TRACK_CROSS;
|
||||
import static com.simibubi.create.AllShapes.TRACK_CROSS_DIAG;
|
||||
import static com.simibubi.create.AllShapes.TRACK_CROSS_DIAG_ORTHO;
|
||||
import static com.simibubi.create.AllShapes.TRACK_CROSS_ORTHO_DIAG;
|
||||
import static com.simibubi.create.AllShapes.TRACK_DIAG;
|
||||
import static com.simibubi.create.AllShapes.TRACK_ORTHO;
|
||||
import static com.simibubi.create.AllShapes.TRACK_ORTHO_LONG;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
@ -21,6 +24,8 @@ import com.simibubi.create.AllBlockPartials;
|
|||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllShapes;
|
||||
import com.simibubi.create.AllTileEntities;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueEntity;
|
||||
import com.simibubi.create.content.contraptions.particle.CubeParticleData;
|
||||
import com.simibubi.create.content.contraptions.wrench.IWrenchable;
|
||||
import com.simibubi.create.content.curiosities.girder.GirderBlock;
|
||||
import com.simibubi.create.content.logistics.trains.BezierConnection;
|
||||
|
@ -33,7 +38,9 @@ import com.simibubi.create.content.logistics.trains.management.edgePoint.station
|
|||
import com.simibubi.create.foundation.block.render.DestroyProgressRenderingHandler;
|
||||
import com.simibubi.create.foundation.block.render.ReducedDestroyEffects;
|
||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||
import com.simibubi.create.foundation.utility.BlockFace;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
|
@ -42,6 +49,8 @@ import net.minecraft.core.BlockPos;
|
|||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Direction.Axis;
|
||||
import net.minecraft.core.Direction.AxisDirection;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
|
@ -51,10 +60,13 @@ import net.minecraft.world.item.context.BlockPlaceContext;
|
|||
import net.minecraft.world.item.context.UseOnContext;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.EntityBlock;
|
||||
import net.minecraft.world.level.block.Mirror;
|
||||
import net.minecraft.world.level.block.NetherPortalBlock;
|
||||
import net.minecraft.world.level.block.Rotation;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
@ -64,6 +76,9 @@ import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
|||
import net.minecraft.world.level.block.state.properties.EnumProperty;
|
||||
import net.minecraft.world.level.levelgen.structure.BoundingBox;
|
||||
import net.minecraft.world.level.material.PushReaction;
|
||||
import net.minecraft.world.level.portal.PortalForcer;
|
||||
import net.minecraft.world.level.portal.PortalInfo;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
|
@ -77,17 +92,17 @@ import net.minecraftforge.client.IBlockRenderProperties;
|
|||
public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrackBlock {
|
||||
|
||||
public static final EnumProperty<TrackShape> SHAPE = EnumProperty.create("shape", TrackShape.class);
|
||||
public static final BooleanProperty HAS_TURN = BooleanProperty.create("turn");
|
||||
public static final BooleanProperty HAS_TE = BooleanProperty.create("turn");
|
||||
|
||||
public TrackBlock(Properties p_49795_) {
|
||||
super(p_49795_);
|
||||
registerDefaultState(defaultBlockState().setValue(SHAPE, TrackShape.ZO)
|
||||
.setValue(HAS_TURN, false));
|
||||
.setValue(HAS_TE, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createBlockStateDefinition(Builder<Block, BlockState> p_49915_) {
|
||||
super.createBlockStateDefinition(p_49915_.add(SHAPE, HAS_TURN));
|
||||
super.createBlockStateDefinition(p_49915_.add(SHAPE, HAS_TE));
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
|
@ -113,7 +128,7 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
|||
TrackShape best = TrackShape.ZO;
|
||||
double bestValue = Float.MAX_VALUE;
|
||||
for (TrackShape shape : TrackShape.values()) {
|
||||
if (shape.isJunction())
|
||||
if (shape.isJunction() || shape.isPortal())
|
||||
continue;
|
||||
Vec3 axis = shape.getAxes()
|
||||
.get(0);
|
||||
|
@ -153,7 +168,7 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
|||
|
||||
@Override
|
||||
public void onPlace(BlockState pState, Level pLevel, BlockPos pPos, BlockState pOldState, boolean pIsMoving) {
|
||||
if (pOldState.getBlock() == this && pState.setValue(HAS_TURN, true) == pOldState.setValue(HAS_TURN, true))
|
||||
if (pOldState.getBlock() == this && pState.setValue(HAS_TE, true) == pOldState.setValue(HAS_TE, true))
|
||||
return;
|
||||
if (pLevel.isClientSide)
|
||||
return;
|
||||
|
@ -164,14 +179,119 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
|||
}
|
||||
|
||||
@Override
|
||||
public void tick(BlockState p_60462_, ServerLevel p_60463_, BlockPos p_60464_, Random p_60465_) {
|
||||
TrackPropagator.onRailAdded(p_60463_, p_60464_, p_60462_);
|
||||
public void tick(BlockState state, ServerLevel level, BlockPos pos, Random p_60465_) {
|
||||
TrackPropagator.onRailAdded(level, pos, state);
|
||||
if (!state.getValue(SHAPE)
|
||||
.isPortal())
|
||||
connectToNether(level, pos, state);
|
||||
}
|
||||
|
||||
protected void connectToNether(ServerLevel level, BlockPos pos, BlockState state) {
|
||||
TrackShape shape = state.getValue(TrackBlock.SHAPE);
|
||||
Axis portalTest = shape == TrackShape.XO ? Axis.X : shape == TrackShape.ZO ? Axis.Z : null;
|
||||
if (portalTest == null)
|
||||
return;
|
||||
|
||||
boolean pop = false;
|
||||
|
||||
for (Direction d : Iterate.directionsInAxis(portalTest)) {
|
||||
BlockPos portalPos = pos.relative(d);
|
||||
BlockState portalState = level.getBlockState(portalPos);
|
||||
if (!(portalState.getBlock() instanceof NetherPortalBlock))
|
||||
continue;
|
||||
|
||||
pop = true;
|
||||
Pair<ServerLevel, BlockFace> otherSide = getOtherSide(level, new BlockFace(pos, d));
|
||||
if (otherSide == null)
|
||||
continue;
|
||||
|
||||
ServerLevel otherLevel = otherSide.getFirst();
|
||||
BlockFace otherTrack = otherSide.getSecond();
|
||||
BlockPos otherTrackPos = otherTrack.getPos();
|
||||
BlockState existing = otherLevel.getBlockState(otherTrackPos);
|
||||
if (!existing.getMaterial()
|
||||
.isReplaceable())
|
||||
continue;
|
||||
|
||||
level.setBlock(pos, state.setValue(SHAPE, TrackShape.asPortal(d))
|
||||
.setValue(HAS_TE, true), 3);
|
||||
BlockEntity te = level.getBlockEntity(pos);
|
||||
if (te instanceof TrackTileEntity tte)
|
||||
tte.bind(otherLevel.dimension(), otherTrackPos);
|
||||
|
||||
otherLevel.setBlock(otherTrackPos, state.setValue(SHAPE, TrackShape.asPortal(otherTrack.getFace()))
|
||||
.setValue(HAS_TE, true), 3);
|
||||
BlockEntity otherTe = otherLevel.getBlockEntity(otherTrackPos);
|
||||
if (otherTe instanceof TrackTileEntity tte)
|
||||
tte.bind(level.dimension(), pos);
|
||||
|
||||
pop = false;
|
||||
}
|
||||
|
||||
if (pop)
|
||||
level.destroyBlock(pos, true);
|
||||
}
|
||||
|
||||
protected Pair<ServerLevel, BlockFace> getOtherSide(ServerLevel level, BlockFace inboundTrack) {
|
||||
BlockPos portalPos = inboundTrack.getConnectedPos();
|
||||
BlockState portalState = level.getBlockState(portalPos);
|
||||
if (!(portalState.getBlock() instanceof NetherPortalBlock))
|
||||
return null;
|
||||
|
||||
MinecraftServer minecraftserver = level.getServer();
|
||||
ResourceKey<Level> resourcekey = level.dimension() == Level.NETHER ? Level.OVERWORLD : Level.NETHER;
|
||||
ServerLevel otherLevel = minecraftserver.getLevel(resourcekey);
|
||||
if (otherLevel == null || !minecraftserver.isNetherEnabled())
|
||||
return null;
|
||||
|
||||
PortalForcer teleporter = otherLevel.getPortalForcer();
|
||||
SuperGlueEntity probe = new SuperGlueEntity(level, new AABB(portalPos));
|
||||
probe.setYRot(inboundTrack.getFace()
|
||||
.toYRot());
|
||||
PortalInfo portalinfo = teleporter.getPortalInfo(probe, otherLevel, probe::findDimensionEntryPoint);
|
||||
if (portalinfo == null)
|
||||
return null;
|
||||
|
||||
BlockPos otherPortalPos = new BlockPos(portalinfo.pos);
|
||||
BlockState otherPortalState = otherLevel.getBlockState(otherPortalPos);
|
||||
if (!(otherPortalState.getBlock() instanceof NetherPortalBlock))
|
||||
return null;
|
||||
|
||||
Direction targetDirection = inboundTrack.getFace();
|
||||
if (targetDirection.getAxis() == otherPortalState.getValue(NetherPortalBlock.AXIS))
|
||||
targetDirection = targetDirection.getClockWise();
|
||||
BlockPos otherPos = otherPortalPos.relative(targetDirection);
|
||||
return Pair.of(otherLevel, new BlockFace(otherPos, targetDirection.getOpposite()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<DiscoveredLocation> getConnected(BlockGetter world, BlockPos pos, BlockState state,
|
||||
public BlockState updateShape(BlockState state, Direction pDirection, BlockState pNeighborState,
|
||||
LevelAccessor level, BlockPos pCurrentPos, BlockPos pNeighborPos) {
|
||||
TrackShape shape = state.getValue(SHAPE);
|
||||
if (!shape.isPortal())
|
||||
return state;
|
||||
|
||||
for (Direction d : Iterate.horizontalDirections) {
|
||||
if (TrackShape.asPortal(d) != state.getValue(SHAPE))
|
||||
continue;
|
||||
if (pDirection != d)
|
||||
continue;
|
||||
|
||||
BlockPos portalPos = pCurrentPos.relative(d);
|
||||
BlockState portalState = level.getBlockState(portalPos);
|
||||
if (!(portalState.getBlock() instanceof NetherPortalBlock))
|
||||
return Blocks.AIR.defaultBlockState();
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<DiscoveredLocation> getConnected(BlockGetter worldIn, BlockPos pos, BlockState state,
|
||||
boolean linear, TrackNodeLocation connectedTo) {
|
||||
Collection<DiscoveredLocation> list;
|
||||
BlockGetter world = connectedTo != null && worldIn instanceof ServerLevel sl ? sl.getServer()
|
||||
.getLevel(connectedTo.dimension) : worldIn;
|
||||
|
||||
if (getTrackAxes(world, pos, state).size() > 1) {
|
||||
Vec3 center = Vec3.atBottomCenterOf(pos)
|
||||
|
@ -183,11 +303,12 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
|||
ITrackBlock.addToListIfConnected(connectedTo, list,
|
||||
(d, b) -> axis.scale(b ? 0 : fromCenter ? -d : d)
|
||||
.add(center),
|
||||
b -> shape.getNormal(), axis, null);
|
||||
b -> shape.getNormal(), b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, axis,
|
||||
null);
|
||||
} else
|
||||
list = ITrackBlock.super.getConnected(world, pos, state, linear, connectedTo);
|
||||
|
||||
if (!state.getValue(HAS_TURN))
|
||||
if (!state.getValue(HAS_TE))
|
||||
return list;
|
||||
if (linear)
|
||||
return list;
|
||||
|
@ -198,22 +319,62 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
|||
|
||||
Map<BlockPos, BezierConnection> connections = trackTE.getConnections();
|
||||
connections.forEach((connectedPos, bc) -> ITrackBlock.addToListIfConnected(connectedTo, list,
|
||||
(d, b) -> d == 1 ? Vec3.atLowerCornerOf(bc.tePositions.get(b)) : bc.starts.get(b), bc.normals::get, null,
|
||||
bc));
|
||||
(d, b) -> d == 1 ? Vec3.atLowerCornerOf(bc.tePositions.get(b)) : bc.starts.get(b), bc.normals::get,
|
||||
b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, null, bc));
|
||||
|
||||
if (trackTE.boundLocation == null || !(world instanceof ServerLevel level))
|
||||
return list;
|
||||
|
||||
ResourceKey<Level> otherDim = trackTE.boundLocation.getFirst();
|
||||
ServerLevel otherLevel = level.getServer()
|
||||
.getLevel(otherDim);
|
||||
if (otherLevel == null)
|
||||
return list;
|
||||
BlockPos boundPos = trackTE.boundLocation.getSecond();
|
||||
BlockState boundState = otherLevel.getBlockState(boundPos);
|
||||
if (!AllBlocks.TRACK.has(boundState))
|
||||
return list;
|
||||
|
||||
Vec3 center = Vec3.atBottomCenterOf(pos)
|
||||
.add(0, getElevationAtCenter(world, pos, state), 0);
|
||||
Vec3 boundCenter = Vec3.atBottomCenterOf(boundPos)
|
||||
.add(0, getElevationAtCenter(otherLevel, boundPos, boundState), 0);
|
||||
TrackShape shape = state.getValue(TrackBlock.SHAPE);
|
||||
TrackShape boundShape = boundState.getValue(TrackBlock.SHAPE);
|
||||
Vec3 boundAxis = getTrackAxes(otherLevel, boundPos, boundState).get(0);
|
||||
|
||||
getTrackAxes(world, pos, state).forEach(axis -> {
|
||||
ITrackBlock.addToListIfConnected(connectedTo, list, (d, b) -> (b ? axis : boundAxis).scale(d)
|
||||
.add(b ? center : boundCenter), b -> (b ? shape : boundShape).getNormal(),
|
||||
b -> b ? level.dimension() : otherLevel.dimension(), axis, null);
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public void animateTick(BlockState pState, Level pLevel, BlockPos pPos, Random pRand) {
|
||||
if (!pState.getValue(SHAPE)
|
||||
.isPortal())
|
||||
return;
|
||||
Vec3 v = Vec3.atLowerCornerOf(pPos)
|
||||
.subtract(.125f, 0, .125f);
|
||||
CubeParticleData data =
|
||||
new CubeParticleData(1, pRand.nextFloat(), 1, .0125f + .0625f * pRand.nextFloat(), 30, false);
|
||||
pLevel.addParticle(data, v.x + pRand.nextFloat() * 1.5f, v.y + .25f, v.z + pRand.nextFloat() * 1.5f, 0.0D,
|
||||
0.04D, 0.0D);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState pNewState, boolean pIsMoving) {
|
||||
boolean removeTE = false;
|
||||
if (pState.getValue(HAS_TURN) && (!pState.is(pNewState.getBlock()) || !pNewState.getValue(HAS_TURN))) {
|
||||
if (pState.getValue(HAS_TE) && (!pState.is(pNewState.getBlock()) || !pNewState.getValue(HAS_TE))) {
|
||||
BlockEntity blockEntity = pLevel.getBlockEntity(pPos);
|
||||
if (blockEntity instanceof TrackTileEntity && !pLevel.isClientSide)
|
||||
((TrackTileEntity) blockEntity).removeInboundConnections();
|
||||
removeTE = true;
|
||||
}
|
||||
|
||||
if (pNewState.getBlock() != this || pState.setValue(HAS_TURN, true) != pNewState.setValue(HAS_TURN, true))
|
||||
if (pNewState.getBlock() != this || pState.setValue(HAS_TE, true) != pNewState.setValue(HAS_TE, true))
|
||||
TrackPropagator.onRailRemoved(pLevel, pPos, pState);
|
||||
if (removeTE)
|
||||
pLevel.removeBlockEntity(pPos);
|
||||
|
@ -282,13 +443,13 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
|||
case AS:
|
||||
return TRACK_ASC.get(Direction.SOUTH);
|
||||
case CR_D:
|
||||
return AllShapes.TRACK_CROSS_DIAG;
|
||||
return TRACK_CROSS_DIAG;
|
||||
case CR_NDX:
|
||||
return TRACK_CROSS_ORTHO_DIAG.get(Direction.SOUTH);
|
||||
case CR_NDZ:
|
||||
return TRACK_CROSS_DIAG_ORTHO.get(Direction.SOUTH);
|
||||
case CR_O:
|
||||
return AllShapes.TRACK_CROSS;
|
||||
return TRACK_CROSS;
|
||||
case CR_PDX:
|
||||
return TRACK_CROSS_DIAG_ORTHO.get(Direction.EAST);
|
||||
case CR_PDZ:
|
||||
|
@ -301,6 +462,14 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
|||
return TRACK_ORTHO.get(Direction.EAST);
|
||||
case ZO:
|
||||
return TRACK_ORTHO.get(Direction.SOUTH);
|
||||
case TE:
|
||||
return TRACK_ORTHO_LONG.get(Direction.EAST);
|
||||
case TW:
|
||||
return TRACK_ORTHO_LONG.get(Direction.WEST);
|
||||
case TS:
|
||||
return TRACK_ORTHO_LONG.get(Direction.SOUTH);
|
||||
case TN:
|
||||
return TRACK_ORTHO_LONG.get(Direction.NORTH);
|
||||
case NONE:
|
||||
default:
|
||||
}
|
||||
|
@ -320,7 +489,7 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
|||
|
||||
@Override
|
||||
public BlockEntity newBlockEntity(BlockPos p_153215_, BlockState state) {
|
||||
if (!state.getValue(HAS_TURN))
|
||||
if (!state.getValue(HAS_TE))
|
||||
return null;
|
||||
return AllTileEntities.TRACK.create(p_153215_, state);
|
||||
}
|
||||
|
@ -354,7 +523,7 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
|||
public InteractionResult onSneakWrenched(BlockState state, UseOnContext context) {
|
||||
Player player = context.getPlayer();
|
||||
Level level = context.getLevel();
|
||||
if (!level.isClientSide && !player.isCreative() && state.getValue(HAS_TURN)) {
|
||||
if (!level.isClientSide && !player.isCreative() && state.getValue(HAS_TE)) {
|
||||
BlockEntity blockEntity = level.getBlockEntity(context.getClickedPos());
|
||||
if (blockEntity instanceof TrackTileEntity trackTE) {
|
||||
trackTE.cancelDrops = true;
|
||||
|
@ -489,7 +658,7 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
|||
@Override
|
||||
public boolean trackEquals(BlockState state1, BlockState state2) {
|
||||
return state1.getBlock() == this && state2.getBlock() == this
|
||||
&& state1.setValue(HAS_TURN, false) == state2.setValue(HAS_TURN, false);
|
||||
&& state1.setValue(HAS_TE, false) == state2.setValue(HAS_TE, false);
|
||||
}
|
||||
|
||||
public static class RenderProperties extends ReducedDestroyEffects implements DestroyProgressRenderingHandler {
|
||||
|
|
|
@ -13,6 +13,7 @@ import com.simibubi.create.AllShapes;
|
|||
import com.simibubi.create.content.logistics.trains.BezierConnection;
|
||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||
import com.simibubi.create.foundation.utility.AnimationTickHolder;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.RaycastHelper;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import com.simibubi.create.foundation.utility.WorldAttached;
|
||||
|
@ -237,6 +238,7 @@ public class TrackBlockOutline {
|
|||
private static final VoxelShape LONG_CROSS =
|
||||
Shapes.or(TrackVoxelShapes.longOrthogonalZ(), TrackVoxelShapes.longOrthogonalX());
|
||||
private static final VoxelShape LONG_ORTHO = TrackVoxelShapes.longOrthogonalZ();
|
||||
private static final VoxelShape LONG_ORTHO_OFFSET = TrackVoxelShapes.longOrthogonalZOffset();
|
||||
|
||||
private static void walkShapes(TrackShape shape, TransformStack msr, Consumer<VoxelShape> renderer) {
|
||||
float angle45 = Mth.PI / 4;
|
||||
|
@ -246,6 +248,16 @@ public class TrackBlockOutline {
|
|||
else if (shape == TrackShape.ZO || shape == TrackShape.CR_NDZ || shape == TrackShape.CR_PDZ)
|
||||
renderer.accept(AllShapes.TRACK_ORTHO.get(Direction.SOUTH));
|
||||
|
||||
if (shape.isPortal()) {
|
||||
for (Direction d : Iterate.horizontalDirections) {
|
||||
if (TrackShape.asPortal(d) != shape)
|
||||
continue;
|
||||
msr.rotateCentered(Direction.UP, AngleHelper.rad(AngleHelper.horizontalAngle(d)));
|
||||
renderer.accept(LONG_ORTHO_OFFSET);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (shape == TrackShape.PD || shape == TrackShape.CR_PDX || shape == TrackShape.CR_PDZ) {
|
||||
msr.rotateCentered(Direction.UP, angle45);
|
||||
renderer.accept(LONG_ORTHO);
|
||||
|
|
|
@ -144,7 +144,7 @@ public class TrackPlacement {
|
|||
if (pos1.distSqr(pos2) > 32 * 32)
|
||||
return info.withMessage("too_far")
|
||||
.tooJumbly();
|
||||
if (!state1.hasProperty(TrackBlock.HAS_TURN))
|
||||
if (!state1.hasProperty(TrackBlock.HAS_TE))
|
||||
return info.withMessage("original_missing");
|
||||
|
||||
if (axis1.dot(end2.subtract(end1)) < 0) {
|
||||
|
@ -469,8 +469,19 @@ public class TrackPlacement {
|
|||
Vec3 axis = first ? info.axis1 : info.axis2;
|
||||
BlockPos pos = first ? info.pos1 : info.pos2;
|
||||
BlockState state = first ? state1 : state2;
|
||||
if (state.hasProperty(TrackBlock.HAS_TURN) && !simulate)
|
||||
state = state.setValue(TrackBlock.HAS_TURN, false);
|
||||
if (state.hasProperty(TrackBlock.HAS_TE) && !simulate)
|
||||
state = state.setValue(TrackBlock.HAS_TE, false);
|
||||
|
||||
switch (state.getValue(TrackBlock.SHAPE)) {
|
||||
case TE, TW:
|
||||
state = state.setValue(TrackBlock.SHAPE, TrackShape.XO);
|
||||
break;
|
||||
case TN, TS:
|
||||
state = state.setValue(TrackBlock.SHAPE, TrackShape.ZO);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < (info.curve != null ? extent + 1 : extent); i++) {
|
||||
Vec3 offset = axis.scale(i);
|
||||
|
@ -501,12 +512,12 @@ public class TrackPlacement {
|
|||
if (!simulate) {
|
||||
BlockState stateAtPos = level.getBlockState(targetPos1);
|
||||
level.setBlock(targetPos1,
|
||||
(stateAtPos.getBlock() == state1.getBlock() ? stateAtPos : state1).setValue(TrackBlock.HAS_TURN, true),
|
||||
(stateAtPos.getBlock() == state1.getBlock() ? stateAtPos : state1).setValue(TrackBlock.HAS_TE, true),
|
||||
3);
|
||||
|
||||
stateAtPos = level.getBlockState(targetPos2);
|
||||
level.setBlock(targetPos2,
|
||||
(stateAtPos.getBlock() == state2.getBlock() ? stateAtPos : state2).setValue(TrackBlock.HAS_TURN, true),
|
||||
(stateAtPos.getBlock() == state2.getBlock() ? stateAtPos : state2).setValue(TrackBlock.HAS_TE, true),
|
||||
3);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import com.google.common.collect.ImmutableList;
|
|||
import com.google.common.collect.ImmutableMap;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.util.StringRepresentable;
|
||||
import net.minecraft.world.level.block.Mirror;
|
||||
import net.minecraft.world.level.block.Rotation;
|
||||
|
@ -23,6 +24,11 @@ public enum TrackShape implements StringRepresentable {
|
|||
AE("ascending", 270, new Vec3(1, 1, 0), new Vec3(-1, 1, 0)),
|
||||
AW("ascending", 90, new Vec3(-1, 1, 0), new Vec3(1, 1, 0)),
|
||||
|
||||
TN("teleport", 180, new Vec3(0, 0, -1), new Vec3(0, 1, 0)),
|
||||
TS("teleport", 0, new Vec3(0, 0, 1), new Vec3(0, 1, 0)),
|
||||
TE("teleport", 270, new Vec3(1, 0, 0), new Vec3(0, 1, 0)),
|
||||
TW("teleport", 90, new Vec3(-1, 0, 0), new Vec3(0, 1, 0)),
|
||||
|
||||
CR_O("cross_ortho", new Vec3(0, 0, 1), new Vec3(1, 0, 0)),
|
||||
CR_D("cross_diag", new Vec3(1, 0, 1), new Vec3(-1, 0, 1)),
|
||||
CR_PDX("cross_d1_xo", new Vec3(1, 0, 0), new Vec3(1, 0, 1)),
|
||||
|
@ -60,7 +66,7 @@ public enum TrackShape implements StringRepresentable {
|
|||
.put(CR_PDZ, CR_NDZ)
|
||||
.put(CR_NDZ, CR_PDZ)
|
||||
.build());
|
||||
|
||||
|
||||
clockwise.putAll(ImmutableMap.<TrackShape, TrackShape>builder()
|
||||
.put(PD, ND)
|
||||
.put(ND, PD)
|
||||
|
@ -112,6 +118,29 @@ public enum TrackShape implements StringRepresentable {
|
|||
return axes.size() > 1;
|
||||
}
|
||||
|
||||
public boolean isPortal() {
|
||||
switch (this) {
|
||||
case TE, TN, TS, TW:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static TrackShape asPortal(Direction horizontalFacing) {
|
||||
switch (horizontalFacing) {
|
||||
case EAST:
|
||||
return TE;
|
||||
case NORTH:
|
||||
return TN;
|
||||
case SOUTH:
|
||||
return TS;
|
||||
case WEST:
|
||||
default:
|
||||
return TW;
|
||||
}
|
||||
}
|
||||
|
||||
public Vec3 getNormal() {
|
||||
return normal;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import java.util.Map.Entry;
|
|||
import java.util.Set;
|
||||
|
||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableTE;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform;
|
||||
import com.simibubi.create.content.logistics.trains.BezierConnection;
|
||||
|
@ -17,12 +18,19 @@ import com.simibubi.create.foundation.tileEntity.IMergeableTE;
|
|||
import com.simibubi.create.foundation.tileEntity.RemoveTileEntityPacket;
|
||||
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction.Axis;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
@ -38,6 +46,8 @@ public class TrackTileEntity extends SmartTileEntity implements ITransformableTE
|
|||
boolean connectionsValidated;
|
||||
boolean cancelDrops;
|
||||
|
||||
public Pair<ResourceKey<Level>, BlockPos> boundLocation;
|
||||
|
||||
public TrackTileEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
|
||||
super(type, pos, state);
|
||||
connections = new HashMap<>();
|
||||
|
@ -84,12 +94,14 @@ public class TrackTileEntity extends SmartTileEntity implements ITransformableTE
|
|||
public void removeConnection(BlockPos target) {
|
||||
connections.remove(target);
|
||||
notifyUpdate();
|
||||
if (!connections.isEmpty())
|
||||
if (!connections.isEmpty() || getBlockState().getOptionalValue(TrackBlock.SHAPE)
|
||||
.orElse(TrackShape.NONE)
|
||||
.isPortal())
|
||||
return;
|
||||
|
||||
BlockState blockState = level.getBlockState(worldPosition);
|
||||
if (blockState.hasProperty(TrackBlock.HAS_TURN))
|
||||
level.setBlockAndUpdate(worldPosition, blockState.setValue(TrackBlock.HAS_TURN, false));
|
||||
if (blockState.hasProperty(TrackBlock.HAS_TE))
|
||||
level.setBlockAndUpdate(worldPosition, blockState.setValue(TrackBlock.HAS_TE, false));
|
||||
AllPackets.channel.send(packetTarget(), new RemoveTileEntityPacket(worldPosition));
|
||||
}
|
||||
|
||||
|
@ -108,6 +120,11 @@ public class TrackTileEntity extends SmartTileEntity implements ITransformableTE
|
|||
AllPackets.channel.send(packetTarget(), new RemoveTileEntityPacket(worldPosition));
|
||||
}
|
||||
|
||||
public void bind(ResourceKey<Level> boundDimension, BlockPos boundLocation) {
|
||||
this.boundLocation = Pair.of(boundDimension, boundLocation);
|
||||
setChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void write(CompoundTag tag, boolean clientPacket) {
|
||||
super.write(tag, clientPacket);
|
||||
|
@ -115,6 +132,13 @@ public class TrackTileEntity extends SmartTileEntity implements ITransformableTE
|
|||
for (BezierConnection bezierConnection : connections.values())
|
||||
listTag.add(bezierConnection.write(worldPosition));
|
||||
tag.put("Connections", listTag);
|
||||
|
||||
if (boundLocation != null) {
|
||||
tag.put("BoundLocation", NbtUtils.writeBlockPos(boundLocation.getSecond()));
|
||||
tag.putString("BoundDimension", boundLocation.getFirst()
|
||||
.location()
|
||||
.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -134,6 +158,11 @@ public class TrackTileEntity extends SmartTileEntity implements ITransformableTE
|
|||
registerToCurveInteraction();
|
||||
else
|
||||
removeFromCurveInteraction();
|
||||
|
||||
if (tag.contains("BoundLocation"))
|
||||
boundLocation = Pair.of(
|
||||
ResourceKey.create(Registry.DIMENSION_REGISTRY, new ResourceLocation(tag.getString("BoundDimension"))),
|
||||
NbtUtils.readBlockPos(tag.getCompound("BoundLocation")));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -204,6 +233,20 @@ public class TrackTileEntity extends SmartTileEntity implements ITransformableTE
|
|||
removeFromCurveInteraction();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setRemovedNotDueToChunkUnload() {
|
||||
super.setRemovedNotDueToChunkUnload();
|
||||
|
||||
if (boundLocation != null && level instanceof ServerLevel) {
|
||||
ServerLevel otherLevel = level.getServer()
|
||||
.getLevel(boundLocation.getFirst());
|
||||
if (otherLevel == null)
|
||||
return;
|
||||
if (AllBlocks.TRACK.has(otherLevel.getBlockState(boundLocation.getSecond())))
|
||||
otherLevel.destroyBlock(boundLocation.getSecond(), false);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerToCurveInteraction() {
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::registerToCurveInteractionUnsafe);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,10 @@ public class TrackVoxelShapes {
|
|||
return Block.box(-14, 0, -3.3, 16 + 14, 4, 19.3);
|
||||
}
|
||||
|
||||
public static VoxelShape longOrthogonalZOffset() {
|
||||
return Block.box(-14, 0, 0, 16 + 14, 4, 24);
|
||||
}
|
||||
|
||||
public static VoxelShape ascending() {
|
||||
VoxelShape shape = Block.box(-14, 0, 0, 16 + 14, 4, 4);
|
||||
VoxelShape[] shapes = new VoxelShape[6];
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
{
|
||||
"credit": "Made with Blockbench",
|
||||
"ambientocclusion": false,
|
||||
"texture_size": [32, 32],
|
||||
"textures": {
|
||||
"1": "create:block/portal_track",
|
||||
"2": "create:block/portal_track_mip",
|
||||
"3": "create:block/standard_track",
|
||||
"particle": "create:block/palettes/stone_types/polished/andesite_cut_polished"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"name": "cube1",
|
||||
"from": [8, -1.95625, 10],
|
||||
"to": [29.95, 2.14375, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [11, 2, 0, 4], "texture": "#1"},
|
||||
"south": {"uv": [0, 2, 11, 4], "texture": "#1"},
|
||||
"down": {"uv": [0, 0, 11, 2], "texture": "#1"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "cube2",
|
||||
"from": [8, -1.95625, 2],
|
||||
"to": [29.95, 2.14375, 6],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [11, 2, 0, 4], "texture": "#3"},
|
||||
"south": {"uv": [0, 2, 11, 4], "texture": "#3"},
|
||||
"down": {"uv": [0, 4, 11, 6], "texture": "#3"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "cube3",
|
||||
"from": [-13.95, -1.95625, 10],
|
||||
"to": [8, 2.14375, 14],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [0, 2, 11, 4], "texture": "#1"},
|
||||
"south": {"uv": [11, 2, 0, 4], "texture": "#1"},
|
||||
"down": {"uv": [0, 0, 11, 2], "rotation": 180, "texture": "#1"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "cube2",
|
||||
"from": [8, -1.95625, 18],
|
||||
"to": [29.95, 2.14375, 22],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [11, 14, 0, 16], "texture": "#1"},
|
||||
"south": {"uv": [0, 14, 11, 16], "texture": "#1"},
|
||||
"down": {"uv": [0, 4, 11, 6], "texture": "#1"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "cube4",
|
||||
"from": [-13.95, -1.95625, 18],
|
||||
"to": [8, 2.14375, 22],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [0, 14, 11, 16], "texture": "#1"},
|
||||
"south": {"uv": [11, 14, 0, 16], "texture": "#1"},
|
||||
"down": {"uv": [0, 4, 11, 6], "rotation": 180, "texture": "#1"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "cube4",
|
||||
"from": [-13.95, -1.95625, 2],
|
||||
"to": [8, 2.14375, 6],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [0, 2, 11, 4], "texture": "#3"},
|
||||
"south": {"uv": [11, 2, 0, 4], "texture": "#3"},
|
||||
"down": {"uv": [0, 4, 11, 6], "rotation": 180, "texture": "#3"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "cube5",
|
||||
"from": [-13.95, -1.95625, 0],
|
||||
"to": [8, 2.14375, 24],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
|
||||
"faces": {
|
||||
"west": {"uv": [11, 12.5, 13.05, 0.5], "rotation": 90, "texture": "#2"},
|
||||
"up": {"uv": [0, 12.5, 10.975, 0.5], "rotation": 180, "texture": "#2"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "cube6",
|
||||
"from": [8, -1.95625, 0],
|
||||
"to": [29.95, 2.14375, 24],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
|
||||
"faces": {
|
||||
"east": {"uv": [11, 0.5, 13.05, 12.5], "rotation": 90, "texture": "#2"},
|
||||
"up": {"uv": [0, 0.5, 10.975, 12.5], "texture": "#2"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "tie1",
|
||||
"from": [21.35, 1.09375, 0],
|
||||
"to": [25.55, 1.14375, 24],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
|
||||
"faces": {
|
||||
"up": {"uv": [12, 8.5, 0, 10.5], "rotation": 270, "texture": "#1"},
|
||||
"down": {"uv": [0, 8.5, 12, 10.5], "rotation": 270, "texture": "#1"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "tie2",
|
||||
"from": [21.45, 5.49375, 0],
|
||||
"to": [25.45, 5.54375, 24],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
|
||||
"faces": {
|
||||
"up": {"uv": [12, 11.5, 0, 13.5], "rotation": 270, "texture": "#1"},
|
||||
"down": {"uv": [0, 8.5, 12, 10.5], "rotation": 270, "texture": "#1"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "tie3",
|
||||
"from": [21.9, 1.14375, 0],
|
||||
"to": [25, 5.54375, 24],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [11, 2, 12.5, 4], "texture": "#3"},
|
||||
"east": {"uv": [12, 6, 0, 8], "texture": "#1"},
|
||||
"south": {"uv": [12.5, 2, 11, 4], "texture": "#1"},
|
||||
"west": {"uv": [0, 6, 12, 8], "texture": "#1"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "tie4",
|
||||
"from": [-9.45, 5.49375, 0],
|
||||
"to": [-5.45, 5.54375, 24],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
|
||||
"faces": {
|
||||
"up": {"uv": [12, 13.5, 0, 11.5], "rotation": 270, "texture": "#1"},
|
||||
"down": {"uv": [0, 10.5, 12, 8.5], "rotation": 270, "texture": "#1"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "tie5",
|
||||
"from": [-9, 1.14375, 0],
|
||||
"to": [-5.9, 5.54375, 24],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [12.5, 2, 11, 4], "texture": "#3"},
|
||||
"east": {"uv": [12, 6, 0, 8], "texture": "#1"},
|
||||
"south": {"uv": [12.5, 2, 11, 4], "texture": "#1"},
|
||||
"west": {"uv": [0, 6, 12, 8], "texture": "#1"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "tie6",
|
||||
"from": [-9.55, 1.09375, 0],
|
||||
"to": [-5.35, 1.14375, 24],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
|
||||
"faces": {
|
||||
"up": {"uv": [12, 10.5, 0, 8.5], "rotation": 270, "texture": "#1"},
|
||||
"down": {"uv": [0, 10.5, 12, 8.5], "rotation": 270, "texture": "#1"}
|
||||
}
|
||||
}
|
||||
],
|
||||
"groups": [
|
||||
{
|
||||
"name": "group",
|
||||
"origin": [0, 0, 0],
|
||||
"color": 0,
|
||||
"children": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
|
||||
}
|
||||
]
|
||||
}
|
BIN
src/main/resources/assets/create/textures/block/portal_track.png
Normal file
BIN
src/main/resources/assets/create/textures/block/portal_track.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
Binary file not shown.
After Width: | Height: | Size: 944 B |
Binary file not shown.
Before Width: | Height: | Size: 1,004 B After Width: | Height: | Size: 1,004 B |
Loading…
Reference in a new issue