Merge branch '1.18/api' into mc1.18/dev

This commit is contained in:
Rabbitminers 2023-05-07 10:13:40 +01:00 committed by GitHub
commit a7a25896c1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
61 changed files with 1074 additions and 1189 deletions

3
.gitignore vendored
View file

@ -42,4 +42,5 @@ local.properties
# PDT-specific # PDT-specific
.buildpath .buildpath
.DS_Store .DS_Store
/libs/

View file

@ -135,6 +135,9 @@ repositories {
includeGroup "maven.modrinth" includeGroup "maven.modrinth"
} }
} }
flatDir {
dirs 'libs'
}
} }
dependencies { dependencies {
@ -169,6 +172,7 @@ dependencies {
// runtimeOnly fg.deobf("slimeknights.mantle:Mantle:1.16.5-1.6.115") // runtimeOnly fg.deobf("slimeknights.mantle:Mantle:1.16.5-1.6.115")
// runtimeOnly fg.deobf("slimeknights.tconstruct:TConstruct:1.16.5-3.1.1.252") // runtimeOnly fg.deobf("slimeknights.tconstruct:TConstruct:1.16.5-3.1.1.252")
// runtimeOnly fg.deobf("maven.modrinth:rubidium:0.5.3") // runtimeOnly fg.deobf("maven.modrinth:rubidium:0.5.3")
implementation fg.deobf("com.railwayteam.railways:railways-1.18.2-1.1.1:all") { transitive = false }
// https://discord.com/channels/313125603924639766/725850371834118214/910619168821354497 // https://discord.com/channels/313125603924639766/725850371834118214/910619168821354497
// Prevent Mixin annotation processor from getting into IntelliJ's annotation processor settings // Prevent Mixin annotation processor from getting into IntelliJ's annotation processor settings

View file

@ -559,7 +559,7 @@ bf2b0310500213ff853c748c236eb5d01f61658e assets/create/blockstates/yellow_toolbo
7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json 7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json
b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json
f85edc574ee6de0de7693ffb031266643db6724a assets/create/lang/en_ud.json f85edc574ee6de0de7693ffb031266643db6724a assets/create/lang/en_ud.json
eb624aafc91b284143c3a0cc7d9bbb8de66e8950 assets/create/lang/en_us.json c0b485449804a49390ef01491350a2878b2b57bd assets/create/lang/en_us.json
487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json 487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json
b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json
3066db1bf03cffa1a9c7fbacf47ae586632f4eb3 assets/create/models/block/acacia_window_pane_noside_alt.json 3066db1bf03cffa1a9c7fbacf47ae586632f4eb3 assets/create/models/block/acacia_window_pane_noside_alt.json
@ -5611,6 +5611,7 @@ ac265a674626e0e832330086fd18fe0be37fc327 data/create/recipes/weathered_copper_ti
2a2700b43614f86d3294726595cb28ed7dca4387 data/create/tags/blocks/brittle.json 2a2700b43614f86d3294726595cb28ed7dca4387 data/create/tags/blocks/brittle.json
d99d5c67bdffff60789a19bd51a5c5267c75e0a4 data/create/tags/blocks/casing.json d99d5c67bdffff60789a19bd51a5c5267c75e0a4 data/create/tags/blocks/casing.json
2b4c93e5a752ebf54217594766f30d8d60cb4343 data/create/tags/blocks/fan_transparent.json 2b4c93e5a752ebf54217594766f30d8d60cb4343 data/create/tags/blocks/fan_transparent.json
ad8fa04f7bbbafd70d0ce158af78a35e899301e2 data/create/tags/blocks/girdable_tracks.json
ee6d2b53d81f2bed492662b6c06f46c4f2b9ef9b data/create/tags/blocks/movable_empty_collider.json ee6d2b53d81f2bed492662b6c06f46c4f2b9ef9b data/create/tags/blocks/movable_empty_collider.json
6e5d3b2123fbb00e7f439c091623619502551bca data/create/tags/blocks/non_movable.json 6e5d3b2123fbb00e7f439c091623619502551bca data/create/tags/blocks/non_movable.json
10781e8cfcbb3486327aace3aa00e437fb44b331 data/create/tags/blocks/ore_override_stone.json 10781e8cfcbb3486327aace3aa00e437fb44b331 data/create/tags/blocks/ore_override_stone.json
@ -5618,6 +5619,7 @@ ee6d2b53d81f2bed492662b6c06f46c4f2b9ef9b data/create/tags/blocks/movable_empty_c
23eb7cf8abff36f85320c35c69b98fdb775c8ec9 data/create/tags/blocks/safe_nbt.json 23eb7cf8abff36f85320c35c69b98fdb775c8ec9 data/create/tags/blocks/safe_nbt.json
6cdeeac1689f7b5bfd9bc40b462143d8eaf3ad0b data/create/tags/blocks/seats.json 6cdeeac1689f7b5bfd9bc40b462143d8eaf3ad0b data/create/tags/blocks/seats.json
d063e12c9ef75f39518c6d129ea35d833464d547 data/create/tags/blocks/toolboxes.json d063e12c9ef75f39518c6d129ea35d833464d547 data/create/tags/blocks/toolboxes.json
ad8fa04f7bbbafd70d0ce158af78a35e899301e2 data/create/tags/blocks/tracks.json
9460e92c8e483446318b849abe7e6f52dcd4a269 data/create/tags/blocks/tree_attachments.json 9460e92c8e483446318b849abe7e6f52dcd4a269 data/create/tags/blocks/tree_attachments.json
50936b211d94167a35ec78c89954082a336b6269 data/create/tags/blocks/valve_handles.json 50936b211d94167a35ec78c89954082a336b6269 data/create/tags/blocks/valve_handles.json
eac71740fb12bdb38b5dfaa2268613d7ba82b809 data/create/tags/blocks/windmill_sails.json eac71740fb12bdb38b5dfaa2268613d7ba82b809 data/create/tags/blocks/windmill_sails.json

View file

@ -1754,6 +1754,12 @@
"enchantment.create.capacity.desc": "Increases Backtank air capacity.", "enchantment.create.capacity.desc": "Increases Backtank air capacity.",
"enchantment.create.potato_recovery.desc": "Potato Cannon projectiles have a chance to be reused.", "enchantment.create.potato_recovery.desc": "Potato Cannon projectiles have a chance to be reused.",
"create.bogey.style.updated_style": "Updated style",
"create.bogey.style.updated_style_and_size": "Updated style and size",
"create.bogey.style.no_other_sizes": "No other sizes",
"create.bogey.style.invalid": "Unnamed style",
"create.bogey.style.standard": "Standard",
"_": "->------------------------] Subtitles [------------------------<-", "_": "->------------------------] Subtitles [------------------------<-",

View file

@ -1,5 +1,6 @@
package com.simibubi.create; package com.simibubi.create;
import com.google.common.collect.ImmutableMap;
import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock; import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock;
import com.simibubi.create.content.logistics.trains.BogeyRenderer; import com.simibubi.create.content.logistics.trains.BogeyRenderer;
import com.simibubi.create.content.logistics.trains.BogeyRenderer.CommonRenderer; import com.simibubi.create.content.logistics.trains.BogeyRenderer.CommonRenderer;
@ -7,6 +8,7 @@ import com.simibubi.create.content.logistics.trains.BogeySizes;
import com.simibubi.create.content.logistics.trains.StandardBogeyRenderer.*; import com.simibubi.create.content.logistics.trains.StandardBogeyRenderer.*;
import com.simibubi.create.content.logistics.trains.entity.BogeyStyle; import com.simibubi.create.content.logistics.trains.entity.BogeyStyle;
import com.simibubi.create.foundation.utility.Components;
import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.Lang;
import com.tterrag.registrate.util.entry.BlockEntry; import com.tterrag.registrate.util.entry.BlockEntry;
@ -26,20 +28,26 @@ import static com.simibubi.create.Create.LOGGER;
public class AllBogeyStyles { public class AllBogeyStyles {
public static final Map<ResourceLocation, BogeyStyle> BOGEY_STYLES = new HashMap<>(); public static final Map<ResourceLocation, BogeyStyle> BOGEY_STYLES = new HashMap<>();
public static final Map<ResourceLocation, Map<ResourceLocation, BogeyStyle>> STYLE_GROUPS = new HashMap<>(); // each set of styles that should be cycled through
private static final Map<ResourceLocation, BogeyStyle> EMPTY_GROUP = ImmutableMap.of();
public static BogeyStyle STANDARD = create("standard") public static Map<ResourceLocation, BogeyStyle> getCycleGroup(ResourceLocation cycleGroup) {
return STYLE_GROUPS.getOrDefault(cycleGroup, EMPTY_GROUP);
}
public static BogeyStyle STANDARD = create("standard", "standard")
.commonRenderer(CommonStandardBogeyRenderer::new) .commonRenderer(CommonStandardBogeyRenderer::new)
.displayName(Lang.translateDirect("create.bogeys.styles.standard")) .displayName(Components.translatable("create.bogey.style.standard"))
.size(BogeySizes.SMALL, SmallStandardBogeyRenderer::new, AllBlocks.SMALL_BOGEY) .size(BogeySizes.SMALL, SmallStandardBogeyRenderer::new, AllBlocks.SMALL_BOGEY)
.size(BogeySizes.LARGE, LargeStandardBogeyRenderer::new, AllBlocks.LARGE_BOGEY) .size(BogeySizes.LARGE, LargeStandardBogeyRenderer::new, AllBlocks.LARGE_BOGEY)
.build(); .build();
public static BogeyStyleBuilder create(String name) { public static BogeyStyleBuilder create(String name, String cycleGroup) {
return create(Create.asResource(name)); return create(Create.asResource(name), Create.asResource(cycleGroup));
} }
public static BogeyStyleBuilder create(ResourceLocation name) { public static BogeyStyleBuilder create(ResourceLocation name, ResourceLocation cycleGroup) {
return new BogeyStyleBuilder(name); return new BogeyStyleBuilder(name, cycleGroup);
} }
public static void register() { public static void register() {
@ -49,16 +57,18 @@ public class AllBogeyStyles {
public static class BogeyStyleBuilder { public static class BogeyStyleBuilder {
protected final Map<BogeySizes.BogeySize, BogeyStyle.SizeData> sizes = new HashMap<>(); protected final Map<BogeySizes.BogeySize, BogeyStyle.SizeData> sizes = new HashMap<>();
protected final ResourceLocation name; protected final ResourceLocation name;
protected final ResourceLocation cycleGroup;
protected Component displayName = Lang.translateDirect("create.bogeys.invalid"); protected Component displayName = Lang.translateDirect("bogey.style.invalid");
protected ResourceLocation soundType = AllSoundEvents.TRAIN2.getId(); protected ResourceLocation soundType = AllSoundEvents.TRAIN2.getId();
protected CompoundTag defaultData = new CompoundTag(); protected CompoundTag defaultData = new CompoundTag();
protected ParticleOptions contactParticle = ParticleTypes.CRIT; protected ParticleOptions contactParticle = ParticleTypes.CRIT;
protected ParticleOptions smokeParticle = ParticleTypes.POOF; protected ParticleOptions smokeParticle = ParticleTypes.POOF;
protected Optional<Supplier<? extends CommonRenderer>> commonRenderer = Optional.empty(); protected Optional<Supplier<? extends CommonRenderer>> commonRenderer = Optional.empty();
public BogeyStyleBuilder(ResourceLocation name) { public BogeyStyleBuilder(ResourceLocation name, ResourceLocation cycleGroup) {
this.name = name; this.name = name;
this.cycleGroup = cycleGroup;
} }
public BogeyStyleBuilder displayName(Component displayName) { public BogeyStyleBuilder displayName(Component displayName) {
@ -105,8 +115,9 @@ public class AllBogeyStyles {
public BogeyStyle build() { public BogeyStyle build() {
BogeyStyle entry = BogeyStyle entry =
new BogeyStyle(name, displayName, soundType, contactParticle, smokeParticle, defaultData, sizes, commonRenderer); new BogeyStyle(name, cycleGroup, displayName, soundType, contactParticle, smokeParticle, defaultData, sizes, commonRenderer);
BOGEY_STYLES.put(name, entry); BOGEY_STYLES.put(name, entry);
STYLE_GROUPS.computeIfAbsent(cycleGroup, l -> new HashMap<>()).put(name, entry);
return entry; return entry;
} }
} }

View file

@ -192,6 +192,7 @@ import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationRenderer; import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationRenderer;
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationTileEntity; import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationTileEntity;
import com.simibubi.create.content.logistics.trains.track.FakeTrackTileEntity; import com.simibubi.create.content.logistics.trains.track.FakeTrackTileEntity;
import com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity;
import com.simibubi.create.content.logistics.trains.track.StandardBogeyTileEntity; import com.simibubi.create.content.logistics.trains.track.StandardBogeyTileEntity;
import com.simibubi.create.content.logistics.trains.track.TrackBlock; import com.simibubi.create.content.logistics.trains.track.TrackBlock;
import com.simibubi.create.content.logistics.trains.track.TrackInstance; import com.simibubi.create.content.logistics.trains.track.TrackInstance;
@ -203,12 +204,9 @@ import com.simibubi.create.content.schematics.block.SchematicannonRenderer;
import com.simibubi.create.content.schematics.block.SchematicannonTileEntity; import com.simibubi.create.content.schematics.block.SchematicannonTileEntity;
import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer; import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer;
import com.tterrag.registrate.util.entry.BlockEntityEntry; import com.tterrag.registrate.util.entry.BlockEntityEntry;
import com.tterrag.registrate.util.entry.BlockEntry;
import com.tterrag.registrate.util.nullness.NonNullSupplier; import com.tterrag.registrate.util.nullness.NonNullSupplier;
import net.minecraft.world.level.block.Block;
public class AllTileEntities { public class AllTileEntities {
// Schematics // Schematics

View file

@ -342,7 +342,7 @@ public abstract class Contraption {
} }
// Bogeys tend to have sticky sides // Bogeys tend to have sticky sides
if (state.getBlock()instanceof AbstractBogeyBlock bogey) if (state.getBlock()instanceof AbstractBogeyBlock<?> bogey)
for (Direction d : bogey.getStickySurfaces(world, pos, state)) for (Direction d : bogey.getStickySurfaces(world, pos, state))
if (!visited.contains(pos.relative(d))) if (!visited.contains(pos.relative(d)))
frontier.add(pos.relative(d)); frontier.add(pos.relative(d));

View file

@ -37,7 +37,7 @@ public class ChassisRangeDisplay {
timer = DISPLAY_TIME; timer = DISPLAY_TIME;
CreateClient.OUTLINER.showCluster(getOutlineKey(), createSelection(te)) CreateClient.OUTLINER.showCluster(getOutlineKey(), createSelection(te))
.colored(0xFFFFFF) .colored(0xFFFFFF)
.disableLineNormals() .disableNormals()
.lineWidth(1 / 16f) .lineWidth(1 / 16f)
.withFaceTexture(AllSpecialTextures.HIGHLIGHT_CHECKERED); .withFaceTexture(AllSpecialTextures.HIGHLIGHT_CHECKERED);
} }

View file

@ -100,7 +100,7 @@ public class SuperGlueSelectionHandler {
CreateClient.OUTLINER.showAABB(glueEntity, glueEntity.getBoundingBox()) CreateClient.OUTLINER.showAABB(glueEntity, glueEntity.getBoundingBox())
.colored(h ? HIGHLIGHT : PASSIVE) .colored(h ? HIGHLIGHT : PASSIVE)
.withFaceTextures(faceTex, faceTex) .withFaceTextures(faceTex, faceTex)
.disableLineNormals() .disableNormals()
.lineWidth(h ? 1 / 16f : 1 / 64f); .lineWidth(h ? 1 / 16f : 1 / 64f);
} }
} }
@ -155,12 +155,12 @@ public class SuperGlueSelectionHandler {
CreateClient.OUTLINER.showAABB(bbOutlineSlot, currentSelectionBox) CreateClient.OUTLINER.showAABB(bbOutlineSlot, currentSelectionBox)
.colored(canReach && canAfford && !cancel ? HIGHLIGHT : FAIL) .colored(canReach && canAfford && !cancel ? HIGHLIGHT : FAIL)
.withFaceTextures(AllSpecialTextures.GLUE, AllSpecialTextures.GLUE) .withFaceTextures(AllSpecialTextures.GLUE, AllSpecialTextures.GLUE)
.disableLineNormals() .disableNormals()
.lineWidth(1 / 16f); .lineWidth(1 / 16f);
CreateClient.OUTLINER.showCluster(clusterOutlineSlot, currentCluster) CreateClient.OUTLINER.showCluster(clusterOutlineSlot, currentCluster)
.colored(0x4D9162) .colored(0x4D9162)
.disableLineNormals() .disableNormals()
.lineWidth(1 / 64f); .lineWidth(1 / 64f);
} }
@ -259,7 +259,7 @@ public class SuperGlueSelectionHandler {
CreateClient.OUTLINER.showCluster(clusterOutlineSlot, currentCluster) CreateClient.OUTLINER.showCluster(clusterOutlineSlot, currentCluster)
.colored(0xB5F2C6) .colored(0xB5F2C6)
.withFaceTextures(AllSpecialTextures.GLUE, AllSpecialTextures.HIGHLIGHT_CHECKERED) .withFaceTextures(AllSpecialTextures.GLUE, AllSpecialTextures.HIGHLIGHT_CHECKERED)
.disableLineNormals() .disableNormals()
.lineWidth(1 / 24f); .lineWidth(1 / 24f);
discard(); discard();

View file

@ -39,7 +39,7 @@ public class ZapperRenderHandler extends ShootableGadgetRenderHandler {
cachedBeams.forEach(beam -> { cachedBeams.forEach(beam -> {
CreateClient.OUTLINER.endChasingLine(beam, beam.start, beam.end, 1 - beam.itensity, false) CreateClient.OUTLINER.endChasingLine(beam, beam.start, beam.end, 1 - beam.itensity, false)
.disableLineNormals() .disableNormals()
.colored(0xffffff) .colored(0xffffff)
.lineWidth(beam.itensity * 1 / 8f); .lineWidth(beam.itensity * 1 / 8f);
}); });

View file

@ -33,7 +33,7 @@ public class WorldshaperRenderHandler {
CreateClient.OUTLINER.showCluster("terrainZapper", renderedPositions.get()) CreateClient.OUTLINER.showCluster("terrainZapper", renderedPositions.get())
.colored(0xbfbfbf) .colored(0xbfbfbf)
.disableLineNormals() .disableNormals()
.lineWidth(1 / 32f) .lineWidth(1 / 32f)
.withFaceTexture(AllSpecialTextures.CHECKERED); .withFaceTexture(AllSpecialTextures.CHECKERED);
} }

View file

@ -9,6 +9,8 @@ import java.util.Set;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Vector3f; import com.mojang.math.Vector3f;
@ -17,7 +19,10 @@ import com.simibubi.create.AllBogeyStyles;
import com.simibubi.create.AllItems; import com.simibubi.create.AllItems;
import com.simibubi.create.content.contraptions.wrench.IWrenchable; import com.simibubi.create.content.contraptions.wrench.IWrenchable;
import com.simibubi.create.content.logistics.trains.entity.BogeyStyle; import com.simibubi.create.content.logistics.trains.entity.BogeyStyle;
import com.simibubi.create.content.logistics.trains.track.StandardBogeyTileEntity; import com.simibubi.create.content.logistics.trains.entity.Carriage;
import com.simibubi.create.content.logistics.trains.entity.CarriageBogey;
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint;
import com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity;
import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement; import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement;
import com.simibubi.create.content.schematics.ItemRequirement; import com.simibubi.create.content.schematics.ItemRequirement;
import com.simibubi.create.foundation.block.ITE; import com.simibubi.create.foundation.block.ITE;
@ -46,6 +51,7 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.EnumProperty; import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
@ -55,7 +61,7 @@ import net.minecraftforge.registries.ForgeRegistries;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public abstract class AbstractBogeyBlock extends Block implements ITE<StandardBogeyTileEntity>, ProperWaterloggedBlock, ISpecialBlockItemRequirement, IWrenchable { public abstract class AbstractBogeyBlock<T extends AbstractBogeyTileEntity> extends Block implements ITE<T>, ProperWaterloggedBlock, ISpecialBlockItemRequirement, IWrenchable {
public static final EnumProperty<Direction.Axis> AXIS = BlockStateProperties.HORIZONTAL_AXIS; public static final EnumProperty<Direction.Axis> AXIS = BlockStateProperties.HORIZONTAL_AXIS;
static final List<ResourceLocation> BOGEYS = new ArrayList<>(); static final List<ResourceLocation> BOGEYS = new ArrayList<>();
public BogeySizes.BogeySize size; public BogeySizes.BogeySize size;
@ -67,7 +73,23 @@ public abstract class AbstractBogeyBlock extends Block implements ITE<StandardBo
this.size = size; this.size = size;
} }
public static void register(ResourceLocation block) { public boolean isOnIncompatibleTrack(Carriage carriage, boolean leading) {
TravellingPoint point = leading ? carriage.getLeadingPoint() : carriage.getTrailingPoint();
CarriageBogey bogey = leading ? carriage.leadingBogey() : carriage.trailingBogey();
return point.edge.getTrackMaterial().trackType != getTrackType(bogey.getStyle());
}
public Set<TrackMaterial.TrackType> getValidPathfindingTypes(BogeyStyle style) {
return ImmutableSet.of(getTrackType(style));
}
public abstract TrackMaterial.TrackType getTrackType(BogeyStyle style);
/**
* Only for internal Create use. If you have your own style set, do not call this method
*/
@Deprecated
public static void registerStandardBogey(ResourceLocation block) {
BOGEYS.add(block); BOGEYS.add(block);
} }
@ -100,16 +122,34 @@ public abstract class AbstractBogeyBlock extends Block implements ITE<StandardBo
public abstract double getWheelRadius(); public abstract double getWheelRadius();
public abstract Vec3 getConnectorAnchorOffset(); public Vec3 getConnectorAnchorOffset(boolean upsideDown) {
return getConnectorAnchorOffset();
}
/**
* This should be implemented, but not called directly
*/
protected abstract Vec3 getConnectorAnchorOffset();
public boolean allowsSingleBogeyCarriage() { public boolean allowsSingleBogeyCarriage() {
return true; return true;
} }
public abstract BogeyStyle getDefaultStyle();
/**
* Legacy system doesn't capture bogey tile entities when constructing a train
*/
public boolean captureTileEntityForTrain() {
return false;
}
@OnlyIn(Dist.CLIENT) @OnlyIn(Dist.CLIENT)
public void render(@Nullable BlockState state, float wheelAngle, PoseStack ms, float partialTicks, public void render(@Nullable BlockState state, boolean upsideDown, float wheelAngle, PoseStack ms, float partialTicks,
MultiBufferSource buffers, int light, int overlay, StandardBogeyTileEntity sbte) { MultiBufferSource buffers, int light, int overlay, BogeyStyle style, CompoundTag bogeyData) {
BogeyStyle style = sbte.getStyle(); if (style == null)
style = getDefaultStyle();
final Optional<BogeyRenderer.CommonRenderer> commonRenderer final Optional<BogeyRenderer.CommonRenderer> commonRenderer
= style.getInWorldCommonRenderInstance(); = style.getInWorldCommonRenderInstance();
final BogeyRenderer renderer = style.getInWorldRenderInstance(this.getSize()); final BogeyRenderer renderer = style.getInWorldRenderInstance(this.getSize());
@ -120,14 +160,17 @@ public abstract class AbstractBogeyBlock extends Block implements ITE<StandardBo
} }
ms.translate(0, -1.5 - 1 / 128f, 0); ms.translate(0, -1.5 - 1 / 128f, 0);
VertexConsumer vb = buffers.getBuffer(RenderType.cutoutMipped()); VertexConsumer vb = buffers.getBuffer(RenderType.cutoutMipped());
renderer.render(sbte.getBogeyData(), wheelAngle, ms, light, vb); if (bogeyData == null)
bogeyData = new CompoundTag();
renderer.render(upsideDown, bogeyData, wheelAngle, ms, light, vb, state == null);
CompoundTag finalBogeyData = bogeyData;
commonRenderer.ifPresent(common -> commonRenderer.ifPresent(common ->
common.render(sbte.getBogeyData(), wheelAngle, ms, light, vb)); common.render(upsideDown, finalBogeyData, wheelAngle, ms, light, vb, state == null));
} }
public BogeySizes.BogeySize getSize() { public BogeySizes.BogeySize getSize() {
return this.size; return this.size;
}; }
public Direction getBogeyUpDirection() { public Direction getBogeyUpDirection() {
return Direction.UP; return Direction.UP;
@ -153,21 +196,21 @@ public abstract class AbstractBogeyBlock extends Block implements ITE<StandardBo
if (!player.isShiftKeyDown() && stack.is(AllItems.WRENCH.get()) && !player.getCooldowns().isOnCooldown(stack.getItem()) if (!player.isShiftKeyDown() && stack.is(AllItems.WRENCH.get()) && !player.getCooldowns().isOnCooldown(stack.getItem())
&& AllBogeyStyles.BOGEY_STYLES.size() > 1) { && AllBogeyStyles.BOGEY_STYLES.size() > 1) {
Collection<BogeyStyle> styles = AllBogeyStyles.BOGEY_STYLES.values();
if (styles.size() <= 1)
return InteractionResult.PASS;
BlockEntity be = level.getBlockEntity(pos); BlockEntity be = level.getBlockEntity(pos);
if (!(be instanceof StandardBogeyTileEntity sbte)) if (!(be instanceof AbstractBogeyTileEntity sbte))
return InteractionResult.FAIL; return InteractionResult.FAIL;
player.getCooldowns().addCooldown(stack.getItem(), 20); player.getCooldowns().addCooldown(stack.getItem(), 20);
BogeyStyle currentStyle = sbte.getStyle(); BogeyStyle currentStyle = sbte.getStyle();
BogeySizes.BogeySize size = getSize(); BogeySizes.BogeySize size = getSize();
BogeyStyle style = this.getNextStyle(currentStyle); BogeyStyle style = this.getNextStyle(currentStyle);
if (style == currentStyle)
return InteractionResult.PASS;
Set<BogeySizes.BogeySize> validSizes = style.validSizes(); Set<BogeySizes.BogeySize> validSizes = style.validSizes();
for (int i = 0; i < BogeySizes.count(); i++) { for (int i = 0; i < BogeySizes.count(); i++) {
@ -181,17 +224,17 @@ public abstract class AbstractBogeyBlock extends Block implements ITE<StandardBo
sbte.setBogeyData(sbte.getBogeyData().merge(defaultData)); sbte.setBogeyData(sbte.getBogeyData().merge(defaultData));
if (size == getSize()) { if (size == getSize()) {
player.displayClientMessage(Lang.translateDirect("create.bogey.style.updated_style") player.displayClientMessage(Lang.translateDirect("bogey.style.updated_style")
.append(": " + style.displayName), true); .append(": ").append(style.displayName), true);
} else { } else {
CompoundTag oldData = sbte.getBogeyData(); CompoundTag oldData = sbte.getBogeyData();
level.setBlock(pos, this.getStateOfSize(sbte, size), 3); level.setBlock(pos, this.getStateOfSize(sbte, size), 3);
BlockEntity newBlockEntity = level.getBlockEntity(pos); BlockEntity newBlockEntity = level.getBlockEntity(pos);
if (!(newBlockEntity instanceof StandardBogeyTileEntity newTileEntity)) if (!(newBlockEntity instanceof AbstractBogeyTileEntity newTileEntity))
return InteractionResult.FAIL; return InteractionResult.FAIL;
newTileEntity.setBogeyData(oldData); newTileEntity.setBogeyData(oldData);
player.displayClientMessage(Lang.translateDirect("create.bogey.style.updated_style_and_size") player.displayClientMessage(Lang.translateDirect("bogey.style.updated_style_and_size")
.append(": " + style.displayName), true); .append(": ").append(style.displayName), true);
} }
return InteractionResult.CONSUME; return InteractionResult.CONSUME;
@ -200,28 +243,34 @@ public abstract class AbstractBogeyBlock extends Block implements ITE<StandardBo
return InteractionResult.PASS; return InteractionResult.PASS;
} }
/**
* If, instead of using the style-based cycling system you prefer to use separate blocks, return them from this method
*/
protected List<ResourceLocation> getBogeyBlockCycle() {
return BOGEYS;
}
@Override @Override
public BlockState getRotatedBlockState(BlockState state, Direction targetedFace) { public BlockState getRotatedBlockState(BlockState state, Direction targetedFace) {
Block block = state.getBlock(); Block block = state.getBlock();
int indexOf = BOGEYS.indexOf(RegisteredObjects.getKeyOrThrow(block)); List<ResourceLocation> bogeyCycle = getBogeyBlockCycle();
int indexOf = bogeyCycle.indexOf(RegisteredObjects.getKeyOrThrow(block));
if (indexOf == -1) if (indexOf == -1)
return state; return state;
int index = (indexOf + 1) % BOGEYS.size(); int index = (indexOf + 1) % bogeyCycle.size();
Direction bogeyUpDirection = getBogeyUpDirection(); Direction bogeyUpDirection = getBogeyUpDirection();
boolean trackAxisAlongFirstCoordinate = isTrackAxisAlongFirstCoordinate(state); boolean trackAxisAlongFirstCoordinate = isTrackAxisAlongFirstCoordinate(state);
while (index != indexOf) { while (index != indexOf) {
ResourceLocation id = BOGEYS.get(index); ResourceLocation id = bogeyCycle.get(index);
Block newBlock = ForgeRegistries.BLOCKS.getValue(id); Block newBlock = ForgeRegistries.BLOCKS.getValue(id);
if (newBlock instanceof AbstractBogeyBlock bogey) { if (newBlock instanceof AbstractBogeyBlock<?> bogey) {
BlockState matchingBogey = bogey.getMatchingBogey(bogeyUpDirection, trackAxisAlongFirstCoordinate); BlockState matchingBogey = bogey.getMatchingBogey(bogeyUpDirection, trackAxisAlongFirstCoordinate);
if (matchingBogey != null) if (matchingBogey != null)
return matchingBogey.hasProperty(WATERLOGGED) return copyProperties(state, matchingBogey);
? matchingBogey.setValue(WATERLOGGED, state.getValue(WATERLOGGED))
: matchingBogey;
} }
index = (index + 1) % BOGEYS.size(); index = (index + 1) % bogeyCycle.size();
} }
return state; return state;
@ -229,37 +278,55 @@ public abstract class AbstractBogeyBlock extends Block implements ITE<StandardBo
public BlockState getNextSize(Level level, BlockPos pos) { public BlockState getNextSize(Level level, BlockPos pos) {
BlockEntity te = level.getBlockEntity(pos); BlockEntity te = level.getBlockEntity(pos);
if (te instanceof StandardBogeyTileEntity sbte) if (te instanceof AbstractBogeyTileEntity sbte)
return this.getNextSize(sbte); return this.getNextSize(sbte);
return level.getBlockState(pos); return level.getBlockState(pos);
} }
public BlockState getNextSize(StandardBogeyTileEntity sbte) { /**
* List of BlockState Properties to copy between sizes
*/
public List<Property<?>> propertiesToCopy() {
return ImmutableList.of(WATERLOGGED, AXIS);
}
// generic method needed to satisfy Property and BlockState's generic requirements
private <V extends Comparable<V>> BlockState copyProperty(BlockState source, BlockState target, Property<V> property) {
if (source.hasProperty(property) && target.hasProperty(property)) {
return target.setValue(property, source.getValue(property));
}
return target;
}
private BlockState copyProperties(BlockState source, BlockState target) {
for (Property<?> property : propertiesToCopy())
target = copyProperty(source, target, property);
return target;
}
public BlockState getNextSize(AbstractBogeyTileEntity sbte) {
BogeySizes.BogeySize size = this.getSize(); BogeySizes.BogeySize size = this.getSize();
BogeyStyle style = sbte.getStyle(); BogeyStyle style = sbte.getStyle();
BlockState nextBlock = style.getNextBlock(size).defaultBlockState(); BlockState nextBlock = style.getNextBlock(size).defaultBlockState();
return nextBlock.hasProperty(WATERLOGGED) nextBlock = copyProperties(sbte.getBlockState(), nextBlock);
? nextBlock.setValue(WATERLOGGED, sbte.getBlockState().getValue(WATERLOGGED)) return nextBlock;
: nextBlock;
} }
public BlockState getStateOfSize(StandardBogeyTileEntity sbte, BogeySizes.BogeySize size) { public BlockState getStateOfSize(AbstractBogeyTileEntity sbte, BogeySizes.BogeySize size) {
BogeyStyle style = sbte.getStyle(); BogeyStyle style = sbte.getStyle();
BlockState state = style.getBlockOfSize(size).defaultBlockState(); BlockState state = style.getBlockOfSize(size).defaultBlockState();
return state.hasProperty(WATERLOGGED) return copyProperties(sbte.getBlockState(), state);
? state.setValue(WATERLOGGED, sbte.getBlockState().getValue(WATERLOGGED))
: state;
} }
public BogeyStyle getNextStyle(Level level, BlockPos pos) { public BogeyStyle getNextStyle(Level level, BlockPos pos) {
BlockEntity te = level.getBlockEntity(pos); BlockEntity te = level.getBlockEntity(pos);
if (te instanceof StandardBogeyTileEntity sbte) if (te instanceof AbstractBogeyTileEntity sbte)
return this.getNextStyle(sbte.getStyle()); return this.getNextStyle(sbte.getStyle());
return AllBogeyStyles.STANDARD; return getDefaultStyle();
} }
public BogeyStyle getNextStyle(BogeyStyle style) { public BogeyStyle getNextStyle(BogeyStyle style) {
Collection<BogeyStyle> allStyles = AllBogeyStyles.BOGEY_STYLES.values(); Collection<BogeyStyle> allStyles = style.getCycleGroup().values();
if (allStyles.size() <= 1) if (allStyles.size() <= 1)
return style; return style;
List<BogeyStyle> list = new ArrayList<>(allStyles); List<BogeyStyle> list = new ArrayList<>(allStyles);
@ -279,4 +346,16 @@ public abstract class AbstractBogeyBlock extends Block implements ITE<StandardBo
public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) { public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) {
return new ItemRequirement(ItemRequirement.ItemUseType.CONSUME, AllBlocks.RAILWAY_CASING.asStack()); return new ItemRequirement(ItemRequirement.ItemUseType.CONSUME, AllBlocks.RAILWAY_CASING.asStack());
} }
public boolean canBeUpsideDown() {
return false;
}
public boolean isUpsideDown(BlockState state) {
return false;
}
public BlockState getVersion(BlockState base, boolean upsideDown) {
return base;
}
} }

View file

@ -37,12 +37,12 @@ public abstract class BogeyRenderer {
* *
* @param model The key for the model data to instantiate or retrieve * @param model The key for the model data to instantiate or retrieve
* @param ms The posestack used for contraption model data * @param ms The posestack used for contraption model data
* @param inContraption The type of model needed * @param inInstancedContraption The type of model needed
* @param size The amount of models needed * @param size The amount of models needed
* @return A generic transform which can be used for both in-world and in-contraption models * @return A generic transform which can be used for both in-world and in-contraption models
*/ */
public Transform<?>[] getTransformsFromPartial(PartialModel model, PoseStack ms, boolean inContraption, int size) { public Transform<?>[] getTransformsFromPartial(PartialModel model, PoseStack ms, boolean inInstancedContraption, int size) {
return (inContraption) ? transformContraptionModelData(keyFromModel(model), ms) : createModelData(model, size); return (inInstancedContraption) ? transformContraptionModelData(keyFromModel(model), ms) : createModelData(model, size);
} }
/** /**
@ -69,7 +69,7 @@ public abstract class BogeyRenderer {
* @param vb (Optional) Vertex Consumer used for in-world rendering * @param vb (Optional) Vertex Consumer used for in-world rendering
*/ */
@OnlyIn(Dist.CLIENT) @OnlyIn(Dist.CLIENT)
public abstract void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb); public abstract void render(boolean upsideDown, CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb, boolean inContraption);
/** /**
* Used for calling in-contraption rendering ensuring that falsey data is handled correctly * Used for calling in-contraption rendering ensuring that falsey data is handled correctly
@ -79,8 +79,8 @@ public abstract class BogeyRenderer {
* @param ms The posestack to render to * @param ms The posestack to render to
*/ */
@OnlyIn(Dist.CLIENT) @OnlyIn(Dist.CLIENT)
public void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms) { public void render(boolean upsideDown, CompoundTag bogeyData, float wheelAngle, PoseStack ms) {
this.render(bogeyData, wheelAngle, ms, 0, null); this.render(upsideDown, bogeyData, wheelAngle, ms, 0, null, true);
} }
public abstract BogeySizes.BogeySize getSize(); public abstract BogeySizes.BogeySize getSize();
@ -147,12 +147,12 @@ public abstract class BogeyRenderer {
* *
* @param model The key of the model to be collected or instantiated * @param model The key of the model to be collected or instantiated
* @param ms Posestack to bind the model to if it is within a contraption * @param ms Posestack to bind the model to if it is within a contraption
* @param inContraption Type of rendering required * @param inInstancedContraption Type of rendering required
* @return A generic transform which can be used for both in-world and in-contraption models * @return A generic transform which can be used for both in-world and in-contraption models
*/ */
public Transform<?> getTransformFromPartial(PartialModel model, PoseStack ms, boolean inContraption) { public Transform<?> getTransformFromPartial(PartialModel model, PoseStack ms, boolean inInstancedContraption) {
BlockState air = Blocks.AIR.defaultBlockState(); BlockState air = Blocks.AIR.defaultBlockState();
return inContraption ? contraptionModelData.get(keyFromModel(model))[0].setTransform(ms) return inInstancedContraption ? contraptionModelData.get(keyFromModel(model))[0].setTransform(ms)
: CachedBufferer.partial(model, air); : CachedBufferer.partial(model, air);
} }

View file

@ -1,7 +1,7 @@
package com.simibubi.create.content.logistics.trains; package com.simibubi.create.content.logistics.trains;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.content.logistics.trains.track.StandardBogeyTileEntity; import com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity;
import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
@ -17,10 +17,10 @@ public class BogeyTileEntityRenderer<T extends BlockEntity> extends SafeTileEnti
protected void renderSafe(T te, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, protected void renderSafe(T te, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light,
int overlay) { int overlay) {
BlockState blockState = te.getBlockState(); BlockState blockState = te.getBlockState();
if (te instanceof StandardBogeyTileEntity sbte) { if (te instanceof AbstractBogeyTileEntity sbte) {
float angle = sbte.getVirtualAngle(partialTicks); float angle = sbte.getVirtualAngle(partialTicks);
if (blockState.getBlock() instanceof AbstractBogeyBlock bogey) if (blockState.getBlock() instanceof AbstractBogeyBlock<?> bogey)
bogey.render(blockState, angle, ms, partialTicks, buffer, light, overlay, sbte); bogey.render(blockState, bogey.isUpsideDown(blockState), angle, ms, partialTicks, buffer, light, overlay, sbte.getStyle(), sbte.getBogeyData());
} }
} }

View file

@ -265,13 +265,17 @@ public class GlobalRailwayManager {
public void clientTick() { public void clientTick() {
if (isTrackGraphDebugActive()) if (isTrackGraphDebugActive())
for (TrackGraph trackGraph : trackNetworks.values()) for (TrackGraph trackGraph : trackNetworks.values())
TrackGraphVisualizer.debugViewGraph(trackGraph); TrackGraphVisualizer.debugViewGraph(trackGraph, isTrackGraphDebugExtended());
} }
private static boolean isTrackGraphDebugActive() { private static boolean isTrackGraphDebugActive() {
return KineticDebugger.isF3DebugModeActive() && AllConfigs.CLIENT.showTrackGraphOnF3.get(); return KineticDebugger.isF3DebugModeActive() && AllConfigs.CLIENT.showTrackGraphOnF3.get();
} }
private static boolean isTrackGraphDebugExtended() {
return AllConfigs.CLIENT.showExtendedTrackGraphOnF3.get();
}
public GlobalRailwayManager sided(LevelAccessor level) { public GlobalRailwayManager sided(LevelAccessor level) {
if (level != null && !level.isClientSide()) if (level != null && !level.isClientSide())
return this; return this;

View file

@ -25,6 +25,7 @@ import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
@ -74,22 +75,42 @@ public interface ITrackBlock {
getTrackAxes(world, pos, state).forEach(axis -> { getTrackAxes(world, pos, state).forEach(axis -> {
addToListIfConnected(connectedTo, list, (d, b) -> axis.scale(b ? d : -d) addToListIfConnected(connectedTo, list, (d, b) -> axis.scale(b ? d : -d)
.add(center), b -> shape.getNormal(), b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, .add(center), b -> shape.getNormal(), b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD,
axis, null); axis, null, (b, v) -> getMaterialSimple(world, v));
}); });
return list; return list;
} }
public static TrackMaterial getMaterialSimple(BlockGetter world, Vec3 pos) {
return getMaterialSimple(world, pos, TrackMaterial.ANDESITE);
}
public static TrackMaterial getMaterialSimple(BlockGetter world, Vec3 pos, TrackMaterial defaultMaterial) {
if (defaultMaterial == null)
defaultMaterial = TrackMaterial.ANDESITE;
if (world != null) {
Block block = world.getBlockState(new BlockPos(pos)).getBlock();
if (block instanceof ITrackBlock track) {
return track.getMaterial();
}
}
return defaultMaterial;
}
public static void addToListIfConnected(@Nullable TrackNodeLocation fromEnd, Collection<DiscoveredLocation> list, public static void addToListIfConnected(@Nullable TrackNodeLocation fromEnd, Collection<DiscoveredLocation> list,
BiFunction<Double, Boolean, Vec3> offsetFactory, Function<Boolean, Vec3> normalFactory, BiFunction<Double, Boolean, Vec3> offsetFactory, Function<Boolean, Vec3> normalFactory,
Function<Boolean, ResourceKey<Level>> dimensionFactory, Vec3 axis, BezierConnection viaTurn) { Function<Boolean, ResourceKey<Level>> dimensionFactory, Vec3 axis, BezierConnection viaTurn, BiFunction<Boolean, Vec3, TrackMaterial> materialFactory) {
DiscoveredLocation firstLocation = DiscoveredLocation firstLocation =
new DiscoveredLocation(dimensionFactory.apply(true), offsetFactory.apply(0.5d, true)).viaTurn(viaTurn) new DiscoveredLocation(dimensionFactory.apply(true), offsetFactory.apply(0.5d, true)).viaTurn(viaTurn)
.materialA(materialFactory.apply(true, offsetFactory.apply(0.0d, true)))
.materialB(materialFactory.apply(true, offsetFactory.apply(1.0d, true)))
.withNormal(normalFactory.apply(true)) .withNormal(normalFactory.apply(true))
.withDirection(axis); .withDirection(axis);
DiscoveredLocation secondLocation = DiscoveredLocation secondLocation =
new DiscoveredLocation(dimensionFactory.apply(false), offsetFactory.apply(0.5d, false)).viaTurn(viaTurn) new DiscoveredLocation(dimensionFactory.apply(false), offsetFactory.apply(0.5d, false)).viaTurn(viaTurn)
.materialA(materialFactory.apply(false, offsetFactory.apply(0.0d, false)))
.materialB(materialFactory.apply(false, offsetFactory.apply(1.0d, false)))
.withNormal(normalFactory.apply(false)) .withNormal(normalFactory.apply(false))
.withDirection(axis); .withDirection(axis);

View file

@ -31,10 +31,10 @@ public class StandardBogeyRenderer {
} }
@Override @Override
public void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb) { public void render(boolean upsideDown, CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb, boolean inContraption) {
boolean inContraption = vb == null; boolean inInstancedContraption = vb == null;
Transform<?>[] shafts = getTransformsFromBlockState(AllBlocks.SHAFT.getDefaultState() Transform<?>[] shafts = getTransformsFromBlockState(AllBlocks.SHAFT.getDefaultState()
.setValue(ShaftBlock.AXIS, Direction.Axis.Z), ms, inContraption, 2); .setValue(ShaftBlock.AXIS, Direction.Axis.Z), ms, inInstancedContraption, 2);
for (int i : Iterate.zeroAndOne) { for (int i : Iterate.zeroAndOne) {
shafts[i].translate(-.5f, .25f, i * -1) shafts[i].translate(-.5f, .25f, i * -1)
.centre() .centre()
@ -60,20 +60,20 @@ public class StandardBogeyRenderer {
} }
@Override @Override
public void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb) { public void render(boolean upsideDown, CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb, boolean inContraption) {
boolean inContraption = vb == null; boolean inInstancedContraption = vb == null;
Transform<?> transform = getTransformFromPartial(BOGEY_FRAME, ms, inContraption); Transform<?> transform = getTransformFromPartial(BOGEY_FRAME, ms, inInstancedContraption);
finalize(transform, ms, light, vb); finalize(transform, ms, light, vb);
Transform<?>[] wheels = getTransformsFromPartial(SMALL_BOGEY_WHEELS, ms, inContraption, 2); Transform<?>[] wheels = getTransformsFromPartial(SMALL_BOGEY_WHEELS, ms, inInstancedContraption, 2);
for (int side : Iterate.positiveAndNegative) { for (int side : Iterate.positiveAndNegative) {
if (!inContraption) if (!inInstancedContraption)
ms.pushPose(); ms.pushPose();
Transform<?> wheel = wheels[(side + 1)/2]; Transform<?> wheel = wheels[(side + 1)/2];
wheel.translate(0, 12 / 16f, side) wheel.translate(0, 12 / 16f, side)
.rotateX(wheelAngle); .rotateX(wheelAngle);
finalize(wheel, ms, light, vb); finalize(wheel, ms, light, vb);
if (!inContraption) if (!inInstancedContraption)
ms.popPose(); ms.popPose();
} }
} }
@ -93,11 +93,11 @@ public class StandardBogeyRenderer {
} }
@Override @Override
public void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb) { public void render(boolean upsideDown, CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb, boolean inContraption) {
boolean inContraption = vb == null; boolean inInstancedContraption = vb == null;
Transform<?>[] secondaryShafts = getTransformsFromBlockState(AllBlocks.SHAFT.getDefaultState() Transform<?>[] secondaryShafts = getTransformsFromBlockState(AllBlocks.SHAFT.getDefaultState()
.setValue(ShaftBlock.AXIS, Direction.Axis.X), ms, inContraption, 2); .setValue(ShaftBlock.AXIS, Direction.Axis.X), ms, inInstancedContraption, 2);
for (int i : Iterate.zeroAndOne) { for (int i : Iterate.zeroAndOne) {
Transform<?> secondShaft = secondaryShafts[i]; Transform<?> secondShaft = secondaryShafts[i];
@ -108,29 +108,29 @@ public class StandardBogeyRenderer {
finalize(secondShaft, ms, light, vb); finalize(secondShaft, ms, light, vb);
} }
Transform<?> bogeyDrive = getTransformFromPartial(BOGEY_DRIVE, ms, inContraption); Transform<?> bogeyDrive = getTransformFromPartial(BOGEY_DRIVE, ms, inInstancedContraption);
finalize(bogeyDrive, ms, light, vb); finalize(bogeyDrive, ms, light, vb);
Transform<?> bogeyPiston = getTransformFromPartial(BOGEY_PISTON, ms, inContraption) Transform<?> bogeyPiston = getTransformFromPartial(BOGEY_PISTON, ms, inInstancedContraption)
.translate(0, 0, 1 / 4f * Math.sin(AngleHelper.rad(wheelAngle))); .translate(0, 0, 1 / 4f * Math.sin(AngleHelper.rad(wheelAngle)));
finalize(bogeyPiston, ms, light, vb); finalize(bogeyPiston, ms, light, vb);
if (!inContraption) if (!inInstancedContraption)
ms.pushPose(); ms.pushPose();
Transform<?> bogeyWheels = getTransformFromPartial(LARGE_BOGEY_WHEELS, ms, inContraption) Transform<?> bogeyWheels = getTransformFromPartial(LARGE_BOGEY_WHEELS, ms, inInstancedContraption)
.translate(0, 1, 0) .translate(0, 1, 0)
.rotateX(wheelAngle); .rotateX(wheelAngle);
finalize(bogeyWheels, ms, light, vb); finalize(bogeyWheels, ms, light, vb);
Transform<?> bogeyPin = getTransformFromPartial(BOGEY_PIN, ms, inContraption) Transform<?> bogeyPin = getTransformFromPartial(BOGEY_PIN, ms, inInstancedContraption)
.translate(0, 1, 0) .translate(0, 1, 0)
.rotateX(wheelAngle) .rotateX(wheelAngle)
.translate(0, 1 / 4f, 0) .translate(0, 1 / 4f, 0)
.rotateX(-wheelAngle); .rotateX(-wheelAngle);
finalize(bogeyPin, ms, light, vb); finalize(bogeyPin, ms, light, vb);
if (!inContraption) if (!inInstancedContraption)
ms.popPose(); ms.popPose();
} }
} }

View file

@ -22,13 +22,19 @@ public class TrackEdge {
BezierConnection turn; BezierConnection turn;
EdgeData edgeData; EdgeData edgeData;
boolean interDimensional; boolean interDimensional;
TrackMaterial trackMaterial;
public TrackEdge(TrackNode node1, TrackNode node2, BezierConnection turn) { public TrackEdge(TrackNode node1, TrackNode node2, BezierConnection turn, TrackMaterial trackMaterial) {
this.interDimensional = !node1.location.dimension.equals(node2.location.dimension); this.interDimensional = !node1.location.dimension.equals(node2.location.dimension);
this.edgeData = new EdgeData(this); this.edgeData = new EdgeData(this);
this.node1 = node1; this.node1 = node1;
this.node2 = node2; this.node2 = node2;
this.turn = turn; this.turn = turn;
this.trackMaterial = trackMaterial;
}
public TrackMaterial getTrackMaterial() {
return trackMaterial;
} }
public boolean isTurn() { public boolean isTurn() {
@ -181,13 +187,15 @@ public class TrackEdge {
public CompoundTag write(DimensionPalette dimensions) { public CompoundTag write(DimensionPalette dimensions) {
CompoundTag baseCompound = isTurn() ? turn.write(BlockPos.ZERO) : new CompoundTag(); CompoundTag baseCompound = isTurn() ? turn.write(BlockPos.ZERO) : new CompoundTag();
baseCompound.put("Signals", edgeData.write(dimensions)); baseCompound.put("Signals", edgeData.write(dimensions));
baseCompound.putString("Material", getTrackMaterial().id.toString());
return baseCompound; return baseCompound;
} }
public static TrackEdge read(TrackNode node1, TrackNode node2, CompoundTag tag, TrackGraph graph, public static TrackEdge read(TrackNode node1, TrackNode node2, CompoundTag tag, TrackGraph graph,
DimensionPalette dimensions) { DimensionPalette dimensions) {
TrackEdge trackEdge = TrackEdge trackEdge =
new TrackEdge(node1, node2, tag.contains("Positions") ? new BezierConnection(tag, BlockPos.ZERO) : null); new TrackEdge(node1, node2, tag.contains("Positions") ? new BezierConnection(tag, BlockPos.ZERO) : null,
TrackMaterial.deserialize(tag.getString("Material")));
trackEdge.edgeData = EdgeData.read(tag.getCompound("Signals"), trackEdge, graph, dimensions); trackEdge.edgeData = EdgeData.read(tag.getCompound("Signals"), trackEdge, graph, dimensions);
return trackEdge; return trackEdge;
} }

View file

@ -393,14 +393,15 @@ public class TrackGraph {
return connectionsFrom.get(nodes.getSecond()); return connectionsFrom.get(nodes.getSecond());
} }
public void connectNodes(LevelAccessor reader, TrackNodeLocation location, TrackNodeLocation location2, public void connectNodes(LevelAccessor reader, DiscoveredLocation location, DiscoveredLocation location2,
@Nullable BezierConnection turn) { @Nullable BezierConnection turn) {
TrackNode node1 = nodes.get(location); TrackNode node1 = nodes.get(location);
TrackNode node2 = nodes.get(location2); TrackNode node2 = nodes.get(location2);
boolean bezier = turn != null; boolean bezier = turn != null;
TrackEdge edge = new TrackEdge(node1, node2, turn); TrackMaterial material = bezier ? turn.getMaterial() : location2.materialA;
TrackEdge edge2 = new TrackEdge(node2, node1, bezier ? turn.secondary() : null); TrackEdge edge = new TrackEdge(node1, node2, turn, material);
TrackEdge edge2 = new TrackEdge(node2, node1, bezier ? turn.secondary() : null, material);
for (TrackGraph graph : Create.RAILWAYS.trackNetworks.values()) { for (TrackGraph graph : Create.RAILWAYS.trackNetworks.values()) {
for (TrackNode otherNode1 : graph.nodes.values()) { for (TrackNode otherNode1 : graph.nodes.values()) {

View file

@ -60,7 +60,7 @@ public class TrackGraphSync {
public void edgeAdded(TrackGraph graph, TrackNode node1, TrackNode node2, TrackEdge edge) { public void edgeAdded(TrackGraph graph, TrackNode node1, TrackNode node2, TrackEdge edge) {
flushGraphPacket(graph); flushGraphPacket(graph);
currentGraphSyncPacket.addedEdges currentGraphSyncPacket.addedEdges
.add(Pair.of(Couple.create(node1.getNetId(), node2.getNetId()), edge.getTurn())); .add(Pair.of(Pair.of(Couple.create(node1.getNetId(), node2.getNetId()), edge.getTrackMaterial()), edge.getTurn()));
currentPayload++; currentPayload++;
} }
@ -82,7 +82,7 @@ public class TrackGraphSync {
if (currentGraphSyncPacket.addedNodes.remove(nodeId) == null) if (currentGraphSyncPacket.addedNodes.remove(nodeId) == null)
currentGraphSyncPacket.removedNodes.add(nodeId); currentGraphSyncPacket.removedNodes.add(nodeId);
currentGraphSyncPacket.addedEdges.removeIf(pair -> { currentGraphSyncPacket.addedEdges.removeIf(pair -> {
Couple<Integer> ids = pair.getFirst(); Couple<Integer> ids = pair.getFirst().getFirst();
return ids.getFirst() return ids.getFirst()
.intValue() == nodeId .intValue() == nodeId
|| ids.getSecond() || ids.getSecond()
@ -156,7 +156,7 @@ public class TrackGraphSync {
graph.connectionsByNode.get(node) graph.connectionsByNode.get(node)
.forEach((node2, edge) -> { .forEach((node2, edge) -> {
Couple<Integer> key = Couple.create(node.getNetId(), node2.getNetId()); Couple<Integer> key = Couple.create(node.getNetId(), node2.getNetId());
currentPacket.addedEdges.add(Pair.of(key, edge.getTurn())); currentPacket.addedEdges.add(Pair.of(Pair.of(key, edge.getTrackMaterial()), edge.getTurn()));
currentPacket.syncEdgeData(node, node2, edge); currentPacket.syncEdgeData(node, node2, edge);
}); });

View file

@ -22,7 +22,7 @@ import net.minecraft.world.phys.Vec3;
public class TrackGraphSyncPacket extends TrackGraphPacket { public class TrackGraphSyncPacket extends TrackGraphPacket {
Map<Integer, Pair<TrackNodeLocation, Vec3>> addedNodes; Map<Integer, Pair<TrackNodeLocation, Vec3>> addedNodes;
List<Pair<Couple<Integer>, BezierConnection>> addedEdges; List<Pair<Pair<Couple<Integer>, TrackMaterial>, BezierConnection>> addedEdges;
List<Integer> removedNodes; List<Integer> removedNodes;
List<TrackEdgePoint> addedEdgePoints; List<TrackEdgePoint> addedEdgePoints;
List<UUID> removedEdgePoints; List<UUID> removedEdgePoints;
@ -79,7 +79,7 @@ public class TrackGraphSyncPacket extends TrackGraphPacket {
size = buffer.readVarInt(); size = buffer.readVarInt();
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
addedEdges.add( addedEdges.add(
Pair.of(Couple.create(buffer::readVarInt), buffer.readBoolean() ? new BezierConnection(buffer) : null)); Pair.of(Pair.of(Couple.create(buffer::readVarInt), TrackMaterial.deserialize(buffer.readUtf())), buffer.readBoolean() ? new BezierConnection(buffer) : null));
size = buffer.readVarInt(); size = buffer.readVarInt();
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
@ -134,8 +134,9 @@ public class TrackGraphSyncPacket extends TrackGraphPacket {
buffer.writeVarInt(addedEdges.size()); buffer.writeVarInt(addedEdges.size());
addedEdges.forEach(pair -> { addedEdges.forEach(pair -> {
pair.getFirst() pair.getFirst().getFirst()
.forEach(buffer::writeVarInt); .forEach(buffer::writeVarInt);
buffer.writeUtf(pair.getFirst().getSecond().id.toString());
BezierConnection turn = pair.getSecond(); BezierConnection turn = pair.getSecond();
buffer.writeBoolean(turn != null); buffer.writeBoolean(turn != null);
if (turn != null) if (turn != null)
@ -192,13 +193,13 @@ public class TrackGraphSyncPacket extends TrackGraphPacket {
graph.loadNode(nodeLocation.getFirst(), nodeId, nodeLocation.getSecond()); graph.loadNode(nodeLocation.getFirst(), nodeId, nodeLocation.getSecond());
} }
for (Pair<Couple<Integer>, BezierConnection> pair : addedEdges) { for (Pair<Pair<Couple<Integer>, TrackMaterial>, BezierConnection> pair : addedEdges) {
Couple<TrackNode> nodes = pair.getFirst() Couple<TrackNode> nodes = pair.getFirst().getFirst()
.map(graph::getNode); .map(graph::getNode);
TrackNode node1 = nodes.getFirst(); TrackNode node1 = nodes.getFirst();
TrackNode node2 = nodes.getSecond(); TrackNode node2 = nodes.getSecond();
if (node1 != null && node2 != null) if (node1 != null && node2 != null)
graph.putConnection(node1, node2, new TrackEdge(node1, node2, pair.getSecond())); graph.putConnection(node1, node2, new TrackEdge(node1, node2, pair.getSecond(), pair.getFirst().getSecond()));
} }
for (TrackEdgePoint edgePoint : addedEdgePoints) for (TrackEdgePoint edgePoint : addedEdgePoints)
@ -268,4 +269,4 @@ public class TrackGraphSyncPacket extends TrackGraphPacket {
updatedEdgeData.put(key, Pair.of(groupType, list)); updatedEdgeData.put(key, Pair.of(groupType, list));
} }
} }

View file

@ -5,6 +5,15 @@ import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.UUID; import java.util.UUID;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.renderer.block.model.ItemTransforms;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.block.Blocks;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
import com.simibubi.create.AllKeys; import com.simibubi.create.AllKeys;
@ -209,7 +218,7 @@ public class TrackGraphVisualizer {
} }
} }
public static void debugViewGraph(TrackGraph graph) { public static void debugViewGraph(TrackGraph graph, boolean extended) {
Minecraft mc = Minecraft.getInstance(); Minecraft mc = Minecraft.getInstance();
Entity cameraEntity = mc.cameraEntity; Entity cameraEntity = mc.cameraEntity;
if (cameraEntity == null) if (cameraEntity == null)
@ -262,6 +271,13 @@ public class TrackGraphVisualizer {
yOffset = new Vec3(0, (other.hashCode() > hashCode ? 6 : 4) / 16f, 0); yOffset = new Vec3(0, (other.hashCode() > hashCode ? 6 : 4) / 16f, 0);
if (!edge.isTurn()) { if (!edge.isTurn()) {
if (extended) {
Vec3 materialPos = edge.getPosition(0.5).add(0, 1, 0);
CreateClient.OUTLINER.showItem(Pair.of(edge, edge.edgeData), materialPos,
new ItemStack(edge.getTrackMaterial().trackBlock.get().get()));
CreateClient.OUTLINER.showAABB(edge.edgeData, AABB.ofSize(materialPos, 1, 1, 1))
.colored(graph.color);
}
CreateClient.OUTLINER.showLine(edge, edge.getPosition(0) CreateClient.OUTLINER.showLine(edge, edge.getPosition(0)
.add(yOffset), .add(yOffset),
edge.getPosition(1) edge.getPosition(1)
@ -273,6 +289,13 @@ public class TrackGraphVisualizer {
Vec3 previous = null; Vec3 previous = null;
BezierConnection turn = edge.getTurn(); BezierConnection turn = edge.getTurn();
if (extended) {
Vec3 materialPos = edge.getPosition(0.5).add(0, 1, 0);
CreateClient.OUTLINER.showItem(Pair.of(edge, edge.edgeData), materialPos,
new ItemStack(edge.getTrackMaterial().trackBlock.get().get()));
CreateClient.OUTLINER.showAABB(edge.edgeData, AABB.ofSize(materialPos, 1, 1, 1))
.colored(graph.color);
}
for (int i = 0; i <= turn.getSegmentCount(); i++) { for (int i = 0; i <= turn.getSegmentCount(); i++) {
Vec3 current = edge.getPosition(i * 1f / turn.getSegmentCount()); Vec3 current = edge.getPosition(i * 1f / turn.getSegmentCount());
if (previous != null) if (previous != null)

View file

@ -24,8 +24,8 @@ public class TrackNodeLocation extends Vec3i {
this(vec.x, vec.y, vec.z); this(vec.x, vec.y, vec.z);
} }
public TrackNodeLocation(double p_121865_, double p_121866_, double p_121867_) { public TrackNodeLocation(double x, double y, double z) {
super(Math.round(p_121865_ * 2), Math.floor(p_121866_ * 2), Math.round(p_121867_ * 2)); super(Math.round(x * 2), Math.floor(y * 2), Math.round(z * 2));
} }
public TrackNodeLocation in(Level level) { public TrackNodeLocation in(Level level) {
@ -116,9 +116,11 @@ public class TrackNodeLocation extends Vec3i {
boolean forceNode = false; boolean forceNode = false;
Vec3 direction; Vec3 direction;
Vec3 normal; Vec3 normal;
TrackMaterial materialA;
TrackMaterial materialB;
public DiscoveredLocation(Level level, double p_121865_, double p_121866_, double p_121867_) { public DiscoveredLocation(Level level, double x, double y, double z) {
super(p_121865_, p_121866_, p_121867_); super(x, y, z);
in(level); in(level);
} }
@ -131,6 +133,22 @@ public class TrackNodeLocation extends Vec3i {
this(level.dimension(), vec); this(level.dimension(), vec);
} }
public DiscoveredLocation materialA(TrackMaterial material) {
this.materialA = material;
return this;
}
public DiscoveredLocation materialB(TrackMaterial material) {
this.materialB = material;
return this;
}
public DiscoveredLocation materials(TrackMaterial materialA, TrackMaterial materialB) {
this.materialA = materialA;
this.materialB = materialB;
return this;
}
public DiscoveredLocation viaTurn(BezierConnection turn) { public DiscoveredLocation viaTurn(BezierConnection turn) {
this.turn = turn; this.turn = turn;
if (turn != null) if (turn != null)
@ -165,6 +183,10 @@ public class TrackNodeLocation extends Vec3i {
return forceNode; return forceNode;
} }
public boolean differentMaterials() {
return materialA != materialB;
}
public boolean notInLineWith(Vec3 direction) { public boolean notInLineWith(Vec3 direction) {
return this.direction != null return this.direction != null
&& Math.max(direction.dot(this.direction), direction.dot(this.direction.scale(-1))) < 7 / 8f; && Math.max(direction.dot(this.direction), direction.dot(this.direction.scale(-1))) < 7 / 8f;

View file

@ -234,10 +234,12 @@ public class TrackPropagator {
return true; return true;
if (location.shouldForceNode()) if (location.shouldForceNode())
return true; return true;
if (location.differentMaterials())
return true;
if (next.stream() if (next.stream()
.anyMatch(DiscoveredLocation::shouldForceNode)) .anyMatch(DiscoveredLocation::shouldForceNode))
return true; return true;
Vec3 direction = location.direction; Vec3 direction = location.direction;
if (direction != null && next.stream() if (direction != null && next.stream()
.anyMatch(dl -> dl.notInLineWith(direction))) .anyMatch(dl -> dl.notInLineWith(direction)))

View file

@ -11,7 +11,7 @@ public class BackupBogeyRenderer extends BogeyRenderer.CommonRenderer {
public static BackupBogeyRenderer INSTANCE = new BackupBogeyRenderer(); public static BackupBogeyRenderer INSTANCE = new BackupBogeyRenderer();
@Override @Override
public void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb) { public void render(boolean upsideDown, CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb, boolean inContraption) {
} }

View file

@ -46,8 +46,8 @@ public final class BogeyInstance {
} }
commonRenderer.ifPresent(bogeyRenderer -> commonRenderer.ifPresent(bogeyRenderer ->
bogeyRenderer.render(bogey.bogeyData, wheelAngle, ms)); bogeyRenderer.render(bogey.isUpsideDown(), bogey.bogeyData, wheelAngle, ms));
renderer.render(bogey.bogeyData, wheelAngle, ms); renderer.render(bogey.isUpsideDown(), bogey.bogeyData, wheelAngle, ms);
} }
public void updateLight(BlockAndTintGetter world, CarriageContraptionEntity entity) { public void updateLight(BlockAndTintGetter world, CarriageContraptionEntity entity) {

View file

@ -1,6 +1,7 @@
package com.simibubi.create.content.logistics.trains.entity; package com.simibubi.create.content.logistics.trains.entity;
import com.jozufozu.flywheel.api.MaterialManager; import com.jozufozu.flywheel.api.MaterialManager;
import com.simibubi.create.AllBogeyStyles;
import com.simibubi.create.AllSoundEvents; import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.content.logistics.trains.BogeyRenderer; import com.simibubi.create.content.logistics.trains.BogeyRenderer;
@ -28,6 +29,7 @@ public class BogeyStyle {
private final Optional<Supplier<? extends CommonRenderer>> commonRendererFactory; private final Optional<Supplier<? extends CommonRenderer>> commonRendererFactory;
public final ResourceLocation name; public final ResourceLocation name;
public final ResourceLocation cycleGroup;
private final Optional<CommonRenderer> commonRenderer; private final Optional<CommonRenderer> commonRenderer;
private final Map<BogeySizes.BogeySize, SizeData> sizes; private final Map<BogeySizes.BogeySize, SizeData> sizes;
public final Component displayName; public final Component displayName;
@ -36,9 +38,10 @@ public class BogeyStyle {
public final ParticleOptions smokeParticle; public final ParticleOptions smokeParticle;
public final CompoundTag defaultData; public final CompoundTag defaultData;
public BogeyStyle(ResourceLocation name, Component displayName, ResourceLocation soundType, ParticleOptions contactParticle, ParticleOptions smokeParticle, public BogeyStyle(ResourceLocation name, ResourceLocation cycleGroup, Component displayName, ResourceLocation soundType, ParticleOptions contactParticle, ParticleOptions smokeParticle,
CompoundTag defaultData, Map<BogeySizes.BogeySize, SizeData> sizes, Optional<Supplier<? extends CommonRenderer>> commonRenderer) { CompoundTag defaultData, Map<BogeySizes.BogeySize, SizeData> sizes, Optional<CommonRenderer> commonRenderer) {
this.name = name; this.name = name;
this.cycleGroup = cycleGroup;
this.displayName = displayName; this.displayName = displayName;
this.soundType = soundType; this.soundType = soundType;
this.contactParticle = contactParticle; this.contactParticle = contactParticle;
@ -51,6 +54,9 @@ public class BogeyStyle {
this.commonRenderer = commonRenderer.map(Supplier::get); this.commonRenderer = commonRenderer.map(Supplier::get);
} }
public Map<ResourceLocation, BogeyStyle> getCycleGroup() {
return AllBogeyStyles.getCycleGroup(cycleGroup);
}
public Block getNextBlock(BogeySizes.BogeySize currentSize) { public Block getNextBlock(BogeySizes.BogeySize currentSize) {
return Stream.iterate(currentSize.increment(), BogeySizes.BogeySize::increment) return Stream.iterate(currentSize.increment(), BogeySizes.BogeySize::increment)

View file

@ -85,6 +85,11 @@ public class Carriage {
bogey2.carriage = this; bogey2.carriage = this;
} }
public boolean isOnIncompatibleTrack() {
return leadingBogey().type.isOnIncompatibleTrack(this, true)
|| trailingBogey().type.isOnIncompatibleTrack(this, false);
}
public void setTrain(Train train) { public void setTrain(Train train) {
this.train = train; this.train = train;
} }
@ -306,6 +311,9 @@ public class Carriage {
double leadingWheelSpacing = leadingBogey.type.getWheelPointSpacing(); double leadingWheelSpacing = leadingBogey.type.getWheelPointSpacing();
double trailingWheelSpacing = trailingBogey.type.getWheelPointSpacing(); double trailingWheelSpacing = trailingBogey.type.getWheelPointSpacing();
boolean leadingUpsideDown = leadingBogey.isUpsideDown();
boolean trailingUpsideDown = trailingBogey.isUpsideDown();
for (boolean leading : Iterate.trueAndFalse) { for (boolean leading : Iterate.trueAndFalse) {
TravellingPoint point = leading ? getLeadingPoint() : getTrailingPoint(); TravellingPoint point = leading ? getLeadingPoint() : getTrailingPoint();
TravellingPoint otherPoint = !leading ? getLeadingPoint() : getTrailingPoint(); TravellingPoint otherPoint = !leading ? getLeadingPoint() : getTrailingPoint();
@ -321,24 +329,31 @@ public class Carriage {
dce.positionAnchor = dimension.equals(leadingBogeyDim) ? leadingBogey.getAnchorPosition() dce.positionAnchor = dimension.equals(leadingBogeyDim) ? leadingBogey.getAnchorPosition()
: pivoted(dce, dimension, point, : pivoted(dce, dimension, point,
leading ? leadingWheelSpacing / 2 : bogeySpacing + trailingWheelSpacing / 2); leading ? leadingWheelSpacing / 2 : bogeySpacing + trailingWheelSpacing / 2,
leadingUpsideDown, trailingUpsideDown);
boolean backAnchorFlip = trailingBogey.isUpsideDown() ^ leadingBogey.isUpsideDown();
if (isOnTwoBogeys()) { if (isOnTwoBogeys()) {
dce.rotationAnchors.setFirst(dimension.equals(leadingBogeyDim) ? leadingBogey.getAnchorPosition() dce.rotationAnchors.setFirst(dimension.equals(leadingBogeyDim) ? leadingBogey.getAnchorPosition()
: pivoted(dce, dimension, point, : pivoted(dce, dimension, point,
leading ? leadingWheelSpacing / 2 : bogeySpacing + trailingWheelSpacing / 2)); leading ? leadingWheelSpacing / 2 : bogeySpacing + trailingWheelSpacing / 2,
dce.rotationAnchors.setSecond(dimension.equals(trailingBogeyDim) ? trailingBogey.getAnchorPosition() leadingUpsideDown, trailingUpsideDown));
dce.rotationAnchors.setSecond(dimension.equals(trailingBogeyDim) ? trailingBogey.getAnchorPosition(backAnchorFlip)
: pivoted(dce, dimension, point, : pivoted(dce, dimension, point,
leading ? leadingWheelSpacing / 2 + bogeySpacing : trailingWheelSpacing / 2)); leading ? leadingWheelSpacing / 2 + bogeySpacing : trailingWheelSpacing / 2,
leadingUpsideDown, trailingUpsideDown));
} else { } else {
if (dimension.equals(otherDimension)) { if (dimension.equals(otherDimension)) {
dce.rotationAnchors = leadingBogey.points.map(TravellingPoint::getPosition); dce.rotationAnchors = leadingBogey.points.map(TravellingPoint::getPosition);
} else { } else {
dce.rotationAnchors.setFirst(leadingBogey.points.getFirst() == point ? point.getPosition() dce.rotationAnchors.setFirst(leadingBogey.points.getFirst() == point ? point.getPosition()
: pivoted(dce, dimension, point, leadingWheelSpacing)); : pivoted(dce, dimension, point, leadingWheelSpacing,
leadingUpsideDown, trailingUpsideDown));
dce.rotationAnchors.setSecond(leadingBogey.points.getSecond() == point ? point.getPosition() dce.rotationAnchors.setSecond(leadingBogey.points.getSecond() == point ? point.getPosition()
: pivoted(dce, dimension, point, leadingWheelSpacing)); : pivoted(dce, dimension, point, leadingWheelSpacing,
leadingUpsideDown, trailingUpsideDown));
} }
} }
@ -356,15 +371,16 @@ public class Carriage {
} }
private Vec3 pivoted(DimensionalCarriageEntity dce, ResourceKey<Level> dimension, TravellingPoint start, private Vec3 pivoted(DimensionalCarriageEntity dce, ResourceKey<Level> dimension, TravellingPoint start,
double offset) { double offset, boolean leadingUpsideDown, boolean trailingUpsideDown) {
if (train.graph == null) if (train.graph == null)
return dce.pivot == null ? null : dce.pivot.getLocation(); return dce.pivot == null ? null : dce.pivot.getLocation();
TrackNodeLocation pivot = dce.findPivot(dimension, start == getLeadingPoint()); TrackNodeLocation pivot = dce.findPivot(dimension, start == getLeadingPoint());
if (pivot == null) if (pivot == null)
return null; return null;
Vec3 startVec = start.getPosition(); boolean flipped = start != getLeadingPoint() && (leadingUpsideDown != trailingUpsideDown);
Vec3 startVec = start.getPosition(flipped);
Vec3 portalVec = pivot.getLocation() Vec3 portalVec = pivot.getLocation()
.add(0, 1, 0); .add(0, leadingUpsideDown ? -1.0 : 1.0, 0);
return VecHelper.lerp((float) (offset / startVec.distanceTo(portalVec)), startVec, portalVec); return VecHelper.lerp((float) (offset / startVec.distanceTo(portalVec)), startVec, portalVec);
} }

View file

@ -8,7 +8,7 @@ import com.simibubi.create.Create;
import com.simibubi.create.content.logistics.trains.DimensionPalette; import com.simibubi.create.content.logistics.trains.DimensionPalette;
import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock; import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock;
import com.simibubi.create.content.logistics.trains.TrackGraph; import com.simibubi.create.content.logistics.trains.TrackGraph;
import com.simibubi.create.content.logistics.trains.track.StandardBogeyTileEntity; import com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity;
import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
@ -28,7 +28,7 @@ import net.minecraft.world.level.block.Block;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.ForgeRegistries;
import static com.simibubi.create.content.logistics.trains.track.StandardBogeyTileEntity.BOGEY_STYLE_KEY; import static com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity.BOGEY_STYLE_KEY;
public class CarriageBogey { public class CarriageBogey {
@ -37,7 +37,8 @@ public class CarriageBogey {
public CompoundTag bogeyData; public CompoundTag bogeyData;
AbstractBogeyBlock type; AbstractBogeyBlock<?> type;
boolean upsideDown;
Couple<TravellingPoint> points; Couple<TravellingPoint> points;
LerpedFloat wheelAngle; LerpedFloat wheelAngle;
@ -48,11 +49,14 @@ public class CarriageBogey {
int derailAngle; int derailAngle;
public CarriageBogey(AbstractBogeyBlock type, CompoundTag bogeyData, TravellingPoint point, TravellingPoint point2) { public CarriageBogey(AbstractBogeyBlock<?> type, boolean upsideDown, CompoundTag bogeyData, TravellingPoint point, TravellingPoint point2) {
this.type = type;
if (bogeyData == null || bogeyData.isEmpty()) if (bogeyData == null || bogeyData.isEmpty())
bogeyData = this.createBogeyData(); // Prevent Crash When Updating bogeyData = this.createBogeyData(); // Prevent Crash When Updating
this.bogeyData = bogeyData; this.bogeyData = bogeyData;
this.type = type; this.upsideDown = type.canBeUpsideDown() && upsideDown;
point.upsideDown = this.upsideDown;
point2.upsideDown = this.upsideDown;
points = Couple.create(point, point2); points = Couple.create(point, point2);
wheelAngle = LerpedFloat.angular(); wheelAngle = LerpedFloat.angular();
yaw = LerpedFloat.angular(); yaw = LerpedFloat.angular();
@ -109,11 +113,15 @@ public class CarriageBogey {
} }
public TravellingPoint leading() { public TravellingPoint leading() {
return points.getFirst(); TravellingPoint point = points.getFirst();
point.upsideDown = isUpsideDown();
return point;
} }
public TravellingPoint trailing() { public TravellingPoint trailing() {
return points.getSecond(); TravellingPoint point = points.getSecond();
point.upsideDown = isUpsideDown();
return point;
} }
public double getStress() { public double getStress() {
@ -127,18 +135,25 @@ public class CarriageBogey {
@Nullable @Nullable
public Vec3 getAnchorPosition() { public Vec3 getAnchorPosition() {
return getAnchorPosition(false);
}
@Nullable
public Vec3 getAnchorPosition(boolean flipUpsideDown) {
if (leading().edge == null) if (leading().edge == null)
return null; return null;
return points.getFirst() return points.getFirst()
.getPosition() .getPosition(flipUpsideDown)
.add(points.getSecond() .add(points.getSecond()
.getPosition()) .getPosition(flipUpsideDown))
.scale(.5); .scale(.5);
} }
public void updateCouplingAnchor(Vec3 entityPos, float entityXRot, float entityYRot, int bogeySpacing, public void updateCouplingAnchor(Vec3 entityPos, float entityXRot, float entityYRot, int bogeySpacing,
float partialTicks, boolean leading) { float partialTicks, boolean leading) {
Vec3 thisOffset = type.getConnectorAnchorOffset(); boolean selfUpsideDown = isUpsideDown();
boolean leadingUpsideDown = carriage.leadingBogey().isUpsideDown();
Vec3 thisOffset = type.getConnectorAnchorOffset(selfUpsideDown);
thisOffset = thisOffset.multiply(1, 1, leading ? -1 : 1); thisOffset = thisOffset.multiply(1, 1, leading ? -1 : 1);
thisOffset = VecHelper.rotate(thisOffset, pitch.getValue(partialTicks), Axis.X); thisOffset = VecHelper.rotate(thisOffset, pitch.getValue(partialTicks), Axis.X);
@ -150,6 +165,8 @@ public class CarriageBogey {
thisOffset = VecHelper.rotate(thisOffset, 180, Axis.Y); thisOffset = VecHelper.rotate(thisOffset, 180, Axis.Y);
thisOffset = VecHelper.rotate(thisOffset, -entityXRot, Axis.X); thisOffset = VecHelper.rotate(thisOffset, -entityXRot, Axis.X);
thisOffset = VecHelper.rotate(thisOffset, entityYRot + 90, Axis.Y); thisOffset = VecHelper.rotate(thisOffset, entityYRot + 90, Axis.Y);
if (selfUpsideDown != leadingUpsideDown)
thisOffset = thisOffset.add(0, selfUpsideDown ? -2 : 2, 0);
couplingAnchors.set(leading, entityPos.add(thisOffset)); couplingAnchors.set(leading, entityPos.add(thisOffset));
} }
@ -159,6 +176,7 @@ public class CarriageBogey {
tag.putString("Type", RegisteredObjects.getKeyOrThrow((Block) type) tag.putString("Type", RegisteredObjects.getKeyOrThrow((Block) type)
.toString()); .toString());
tag.put("Points", points.serializeEach(tp -> tp.write(dimensions))); tag.put("Points", points.serializeEach(tp -> tp.write(dimensions)));
tag.putBoolean("UpsideDown", upsideDown);
tag.put(BOGEY_STYLE_KEY, bogeyData); tag.put(BOGEY_STYLE_KEY, bogeyData);
return tag; return tag;
} }
@ -166,10 +184,11 @@ public class CarriageBogey {
public static CarriageBogey read(CompoundTag tag, TrackGraph graph, DimensionPalette dimensions) { public static CarriageBogey read(CompoundTag tag, TrackGraph graph, DimensionPalette dimensions) {
ResourceLocation location = new ResourceLocation(tag.getString("Type")); ResourceLocation location = new ResourceLocation(tag.getString("Type"));
AbstractBogeyBlock type = (AbstractBogeyBlock) ForgeRegistries.BLOCKS.getValue(location); AbstractBogeyBlock type = (AbstractBogeyBlock) ForgeRegistries.BLOCKS.getValue(location);
boolean upsideDown = tag.getBoolean("UpsideDown");
Couple<TravellingPoint> points = Couple.deserializeEach(tag.getList("Points", Tag.TAG_COMPOUND), Couple<TravellingPoint> points = Couple.deserializeEach(tag.getList("Points", Tag.TAG_COMPOUND),
c -> TravellingPoint.read(c, graph, dimensions)); c -> TravellingPoint.read(c, graph, dimensions));
CompoundTag data = tag.getCompound(StandardBogeyTileEntity.BOGEY_DATA_KEY); CompoundTag data = tag.getCompound(AbstractBogeyTileEntity.BOGEY_DATA_KEY);
return new CarriageBogey(type, data, points.getFirst(), points.getSecond()); return new CarriageBogey(type, upsideDown, data, points.getFirst(), points.getSecond());
} }
public BogeyInstance createInstance(MaterialManager materialManager) { public BogeyInstance createInstance(MaterialManager materialManager) {
@ -183,11 +202,15 @@ public class CarriageBogey {
private CompoundTag createBogeyData() { private CompoundTag createBogeyData() {
CompoundTag nbt = new CompoundTag(); CompoundTag nbt = new CompoundTag();
NBTHelper.writeResourceLocation(nbt, BOGEY_STYLE_KEY, AllBogeyStyles.STANDARD.name); NBTHelper.writeResourceLocation(nbt, BOGEY_STYLE_KEY, (type != null ? type.getDefaultStyle() : AllBogeyStyles.STANDARD).name);
return nbt; return nbt;
} }
void setLeading() { void setLeading() {
isLeading = true; isLeading = true;
} }
public boolean isUpsideDown() {
return type.canBeUpsideDown() && upsideDown;
}
} }

View file

@ -162,11 +162,12 @@ public class CarriageContraption extends Contraption {
.getStep(), toLocalPos(pos)); .getStep(), toLocalPos(pos));
} }
if (blockState.getBlock() instanceof AbstractBogeyBlock) { if (blockState.getBlock() instanceof AbstractBogeyBlock bogey) {
boolean captureTE = bogey.captureTileEntityForTrain();
bogeys++; bogeys++;
if (bogeys == 2) if (bogeys == 2)
secondBogeyPos = pos; secondBogeyPos = pos;
return Pair.of(new StructureBlockInfo(pos, blockState, null), null); return Pair.of(new StructureBlockInfo(pos, blockState, captureTE ? getTileEntityNBT(world, pos) : null), captureTE ? world.getBlockEntity(pos) : null);
} }
if (AllBlocks.BLAZE_BURNER.has(blockState) if (AllBlocks.BLAZE_BURNER.has(blockState)

View file

@ -7,8 +7,6 @@ import com.jozufozu.flywheel.util.transform.TransformStack;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionEntityRenderer; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionEntityRenderer;
import com.simibubi.create.content.logistics.trains.track.StandardBogeyTileEntity;
import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.culling.Frustum; import net.minecraft.client.renderer.culling.Frustum;
@ -68,10 +66,9 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer
translateBogey(ms, bogey, bogeySpacing, viewYRot, viewXRot, partialTicks); translateBogey(ms, bogey, bogeySpacing, viewYRot, viewXRot, partialTicks);
int light = getBogeyLightCoords(entity, bogey, partialTicks); int light = getBogeyLightCoords(entity, bogey, partialTicks);
BlockEntity be = entity.getContraption().presentTileEntities.get(bogeyPos);
bogey.type.render(null, bogey.wheelAngle.getValue(partialTicks), ms, partialTicks, buffers, light, bogey.type.render(null, bogey.isUpsideDown(), bogey.wheelAngle.getValue(partialTicks), ms, partialTicks, buffers, light,
overlay, (StandardBogeyTileEntity) be); overlay, bogey.getStyle(), bogey.bogeyData);
ms.popPose(); ms.popPose();
} }
@ -85,6 +82,8 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer
public static void translateBogey(PoseStack ms, CarriageBogey bogey, int bogeySpacing, float viewYRot, public static void translateBogey(PoseStack ms, CarriageBogey bogey, int bogeySpacing, float viewYRot,
float viewXRot, float partialTicks) { float viewXRot, float partialTicks) {
boolean selfUpsideDown = bogey.isUpsideDown();
boolean leadingUpsideDown = bogey.carriage.leadingBogey().isUpsideDown();
TransformStack.cast(ms) TransformStack.cast(ms)
.rotateY(viewYRot + 90) .rotateY(viewYRot + 90)
.rotateX(-viewXRot) .rotateX(-viewXRot)
@ -95,7 +94,9 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer
.rotateY(-viewYRot - 90) .rotateY(-viewYRot - 90)
.rotateY(bogey.yaw.getValue(partialTicks)) .rotateY(bogey.yaw.getValue(partialTicks))
.rotateX(bogey.pitch.getValue(partialTicks)) .rotateX(bogey.pitch.getValue(partialTicks))
.translate(0, .5f, 0); .translate(0, .5f, 0)
.rotateZ(selfUpsideDown ? 180 : 0)
.translateY(selfUpsideDown != leadingUpsideDown ? 2 : 0);
} }
public static int getBogeyLightCoords(CarriageContraptionEntity entity, CarriageBogey bogey, float partialTicks) { public static int getBogeyLightCoords(CarriageContraptionEntity entity, CarriageBogey bogey, float partialTicks) {

View file

@ -82,7 +82,7 @@ public class CarriageCouplingRenderer {
float margin = 3 / 16f; float margin = 3 / 16f;
double couplingDistance = train.carriageSpacing.get(i) - 2 * margin double couplingDistance = train.carriageSpacing.get(i) - 2 * margin
- bogey1.type.getConnectorAnchorOffset().z - bogey2.type.getConnectorAnchorOffset().z; - bogey1.type.getConnectorAnchorOffset(bogey1.isUpsideDown()).z - bogey2.type.getConnectorAnchorOffset(bogey2.isUpsideDown()).z;
int couplingSegments = (int) Math.round(couplingDistance * 4); int couplingSegments = (int) Math.round(couplingDistance * 4);
double stretch = ((anchor2.distanceTo(anchor) - 2 * margin) * 4) / couplingSegments; double stretch = ((anchor2.distanceTo(anchor) - 2 * margin) * 4) / couplingSegments;
for (int j = 0; j < couplingSegments; j++) { for (int j = 0; j < couplingSegments; j++) {

View file

@ -88,7 +88,13 @@ public class CarriageSounds {
double distance2 = toBogey2.length(); double distance2 = toBogey2.length();
Couple<CarriageBogey> bogeys = entity.getCarriage().bogeys; Couple<CarriageBogey> bogeys = entity.getCarriage().bogeys;
closestBogeySound = bogeys.get(distance1 > distance2).getStyle().getSoundType(); CarriageBogey relevantBogey = bogeys.get(distance1 > distance2);
if (relevantBogey == null) {
relevantBogey = bogeys.getFirst();
}
if (relevantBogey != null) {
closestBogeySound = relevantBogey.getStyle().getSoundType();
}
Vec3 toCarriage = distance1 > distance2 ? toBogey2 : toBogey1; Vec3 toCarriage = distance1 > distance2 ? toBogey2 : toBogey1;
double distance = Math.min(distance1, distance2); double distance = Math.min(distance1, distance2);

View file

@ -14,6 +14,9 @@ import java.util.UUID;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.railwayteam.railways.Railways;
import com.simibubi.create.content.logistics.trains.TrackMaterial;
import org.apache.commons.lang3.mutable.MutableDouble; import org.apache.commons.lang3.mutable.MutableDouble;
import org.apache.commons.lang3.mutable.MutableObject; import org.apache.commons.lang3.mutable.MutableObject;
@ -251,7 +254,7 @@ public class Navigation {
return; return;
} }
} }
topSpeed *= train.throttle; topSpeed *= train.throttle;
double turnTopSpeed = Math.min(topSpeed, train.maxTurnSpeed()); double turnTopSpeed = Math.min(topSpeed, train.maxTurnSpeed());
@ -540,6 +543,23 @@ public class Navigation {
if (graph == null) if (graph == null)
return; return;
// Cache the list of track types that the train can travel on
Set<TrackMaterial.TrackType> validTypes = new HashSet<>();
for (int i = 0; i < train.carriages.size(); i++) {
Carriage carriage = train.carriages.get(i);
if (i == 0) {
validTypes.addAll(carriage.leadingBogey().type.getValidPathfindingTypes(carriage.leadingBogey().getStyle()));
} else {
validTypes.retainAll(carriage.leadingBogey().type.getValidPathfindingTypes(carriage.leadingBogey().getStyle()));
}
if (carriage.isOnTwoBogeys())
validTypes.retainAll(carriage.trailingBogey().type.getValidPathfindingTypes(carriage.trailingBogey().getStyle()));
}
if (validTypes.isEmpty()) // if there are no valid track types, a route can't be found
return;
Create.LOGGER.info("Valid types: "+validTypes);
Map<TrackEdge, Integer> penalties = new IdentityHashMap<>(); Map<TrackEdge, Integer> penalties = new IdentityHashMap<>();
boolean costRelevant = maxCost >= 0; boolean costRelevant = maxCost >= 0;
if (costRelevant) { if (costRelevant) {
@ -579,7 +599,7 @@ public class Navigation {
.get(initialNode2); .get(initialNode2);
if (initialEdge == null) if (initialEdge == null)
return; return;
double distanceToNode2 = forward ? initialEdge.getLength() - startingPoint.position : startingPoint.position; double distanceToNode2 = forward ? initialEdge.getLength() - startingPoint.position : startingPoint.position;
frontier.add(new FrontierEntry(distanceToNode2, 0, initialNode1, initialNode2, initialEdge)); frontier.add(new FrontierEntry(distanceToNode2, 0, initialNode1, initialNode2, initialEdge));
@ -659,6 +679,8 @@ public class Navigation {
continue; continue;
for (Entry<TrackNode, TrackEdge> target : validTargets) { for (Entry<TrackNode, TrackEdge> target : validTargets) {
if (!validTypes.contains(target.getValue().getTrackMaterial().trackType))
continue;
TrackNode newNode = target.getKey(); TrackNode newNode = target.getKey();
TrackEdge newEdge = target.getValue(); TrackEdge newEdge = target.getValue();
double newDistance = newEdge.getLength() + distance; double newDistance = newEdge.getLength() + distance;

View file

@ -17,7 +17,7 @@ import java.util.function.Consumer;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.simibubi.create.content.logistics.trains.track.StandardBogeyTileEntity; import com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
@ -317,7 +317,13 @@ public class Train {
if (leadingAnchor == null || trailingAnchor == null) if (leadingAnchor == null || trailingAnchor == null)
continue; continue;
total += leadingAnchor.distanceTo(trailingAnchor); double distanceTo = leadingAnchor.distanceToSqr(trailingAnchor);
if (carriage.leadingBogey().isUpsideDown() != previousCarriage.trailingBogey().isUpsideDown()) {
distanceTo = Math.sqrt(distanceTo - 4);
} else {
distanceTo = Math.sqrt(distanceTo);
}
total += distanceTo;
entries++; entries++;
} }
} }
@ -379,7 +385,7 @@ public class Train {
int carriageType = first ? last ? Carriage.BOTH : Carriage.FIRST : last ? Carriage.LAST : Carriage.MIDDLE; int carriageType = first ? last ? Carriage.BOTH : Carriage.FIRST : last ? Carriage.LAST : Carriage.MIDDLE;
double actualDistance = double actualDistance =
carriage.travel(level, graph, distance + totalStress, toFollowForward, toFollowBackward, carriageType); carriage.travel(level, graph, distance + totalStress, toFollowForward, toFollowBackward, carriageType);
blocked |= carriage.blocked; blocked |= carriage.blocked || carriage.isOnIncompatibleTrack();
boolean onTwoBogeys = carriage.isOnTwoBogeys(); boolean onTwoBogeys = carriage.isOnTwoBogeys();
maxStress = Math.max(maxStress, onTwoBogeys ? carriage.bogeySpacing - carriage.getAnchorDiff() : 0); maxStress = Math.max(maxStress, onTwoBogeys ? carriage.bogeySpacing - carriage.getAnchorDiff() : 0);
@ -726,14 +732,16 @@ public class Train {
if (entity.getContraption()instanceof CarriageContraption cc) if (entity.getContraption()instanceof CarriageContraption cc)
cc.returnStorageForDisassembly(carriage.storage); cc.returnStorageForDisassembly(carriage.storage);
entity.setPos(Vec3 entity.setPos(Vec3
.atLowerCornerOf(pos.relative(assemblyDirection, backwards ? offset + carriage.bogeySpacing : offset))); .atLowerCornerOf(pos.relative(assemblyDirection, backwards ? offset + carriage.bogeySpacing : offset).below(carriage.leadingBogey().isUpsideDown() ? 2 : 0)));
entity.disassemble(); entity.disassemble();
for (CarriageBogey bogey : carriage.bogeys) { for (CarriageBogey bogey : carriage.bogeys) {
if (bogey == null)
continue;
Vec3 bogeyPosition = bogey.getAnchorPosition(); Vec3 bogeyPosition = bogey.getAnchorPosition();
if (bogeyPosition == null) continue; if (bogeyPosition == null) continue;
BlockEntity be = level.getBlockEntity(new BlockPos(bogeyPosition)); BlockEntity be = level.getBlockEntity(new BlockPos(bogeyPosition));
if (!(be instanceof StandardBogeyTileEntity sbte)) if (!(be instanceof AbstractBogeyTileEntity sbte))
continue; continue;
sbte.setBogeyData(bogey.bogeyData); sbte.setBogeyData(bogey.bogeyData);
} }
@ -957,7 +965,7 @@ public class Train {
occupiedObservers.clear(); occupiedObservers.clear();
cachedObserverFiltering.clear(); cachedObserverFiltering.clear();
TravellingPoint signalScout = new TravellingPoint(node1, node2, edge, position); TravellingPoint signalScout = new TravellingPoint(node1, node2, edge, position, false);
Map<UUID, SignalEdgeGroup> allGroups = Create.RAILWAYS.signalEdgeGroups; Map<UUID, SignalEdgeGroup> allGroups = Create.RAILWAYS.signalEdgeGroups;
MutableObject<UUID> prevGroup = new MutableObject<>(null); MutableObject<UUID> prevGroup = new MutableObject<>(null);

View file

@ -49,8 +49,9 @@ public class TrainPacket extends SimplePacketBase {
if (!isFirst && !buffer.readBoolean()) if (!isFirst && !buffer.readBoolean())
continue; continue;
AbstractBogeyBlock type = (AbstractBogeyBlock) ForgeRegistries.BLOCKS.getValue(buffer.readResourceLocation()); AbstractBogeyBlock type = (AbstractBogeyBlock) ForgeRegistries.BLOCKS.getValue(buffer.readResourceLocation());
boolean upsideDown = buffer.readBoolean();
CompoundTag data = buffer.readNbt(); CompoundTag data = buffer.readNbt();
bogies.set(isFirst, new CarriageBogey(type, data, new TravellingPoint(), new TravellingPoint())); bogies.set(isFirst, new CarriageBogey(type, upsideDown, data, new TravellingPoint(), new TravellingPoint()));
} }
int spacing = buffer.readVarInt(); int spacing = buffer.readVarInt();
carriages.add(new Carriage(bogies.getFirst(), bogies.getSecond(), spacing)); carriages.add(new Carriage(bogies.getFirst(), bogies.getSecond(), spacing));
@ -88,6 +89,7 @@ public class TrainPacket extends SimplePacketBase {
} }
CarriageBogey bogey = carriage.bogeys.get(first); CarriageBogey bogey = carriage.bogeys.get(first);
buffer.writeResourceLocation(RegisteredObjects.getKeyOrThrow((Block) bogey.type)); buffer.writeResourceLocation(RegisteredObjects.getKeyOrThrow((Block) bogey.type));
buffer.writeBoolean(bogey.upsideDown);
buffer.writeNbt(bogey.bogeyData); buffer.writeNbt(bogey.bogeyData);
} }
buffer.writeVarInt(carriage.bogeySpacing); buffer.writeVarInt(carriage.bogeySpacing);

View file

@ -115,13 +115,16 @@ public class TrainRelocator {
BlockPos blockPos = blockhit.getBlockPos(); BlockPos blockPos = blockhit.getBlockPos();
BezierTrackPointLocation hoveredBezier = null; BezierTrackPointLocation hoveredBezier = null;
boolean upsideDown = relocating.carriages.get(0).leadingBogey().isUpsideDown();
Vec3 offset = upsideDown ? new Vec3(0, -0.5, 0) : Vec3.ZERO;
if (simulate && toVisualise != null && lastHoveredResult != null) { if (simulate && toVisualise != null && lastHoveredResult != null) {
for (int i = 0; i < toVisualise.size() - 1; i++) { for (int i = 0; i < toVisualise.size() - 1; i++) {
Vec3 vec1 = toVisualise.get(i); Vec3 vec1 = toVisualise.get(i).add(offset);
Vec3 vec2 = toVisualise.get(i + 1); Vec3 vec2 = toVisualise.get(i + 1).add(offset);
CreateClient.OUTLINER.showLine(Pair.of(relocating, i), vec1.add(0, -.925f, 0), vec2.add(0, -.925f, 0)) CreateClient.OUTLINER.showLine(Pair.of(relocating, i), vec1.add(0, -.925f, 0), vec2.add(0, -.925f, 0))
.colored(lastHoveredResult || i != toVisualise.size() - 2 ? 0x95CD41 : 0xEA5C2B) .colored(lastHoveredResult || i != toVisualise.size() - 2 ? 0x95CD41 : 0xEA5C2B)
.disableLineNormals() .disableNormals()
.lineWidth(i % 2 == 1 ? 1 / 6f : 1 / 4f); .lineWidth(i % 2 == 1 ? 1 / 6f : 1 / 4f);
} }
} }
@ -150,7 +153,7 @@ public class TrainRelocator {
boolean direction = bezierSelection != null && lookAngle.dot(bezierSelection.direction()) < 0; boolean direction = bezierSelection != null && lookAngle.dot(bezierSelection.direction()) < 0;
boolean result = relocate(relocating, mc.level, blockPos, hoveredBezier, direction, lookAngle, true); boolean result = relocate(relocating, mc.level, blockPos, hoveredBezier, direction, lookAngle, true);
if (!simulate && result) { if (!simulate && result) {
relocating.carriages.forEach(c -> c.forEachPresentEntity(e -> e.nonDamageTicks = 10)); relocating.carriages.forEach(c -> c.forEachPresentEntity(e -> e.nonDamageTicks = 10));
AllPackets.channel.sendToServer(new TrainRelocationPacket(relocatingTrain, blockPos, hoveredBezier, AllPackets.channel.sendToServer(new TrainRelocationPacket(relocatingTrain, blockPos, hoveredBezier,
direction, lookAngle, relocatingEntityId)); direction, lookAngle, relocatingEntityId));
} }
@ -182,7 +185,7 @@ public class TrainRelocator {
if (edge == null) if (edge == null)
return false; return false;
TravellingPoint probe = new TravellingPoint(node1, node2, edge, graphLocation.position); TravellingPoint probe = new TravellingPoint(node1, node2, edge, graphLocation.position, false);
IEdgePointListener ignoreSignals = probe.ignoreEdgePoints(); IEdgePointListener ignoreSignals = probe.ignoreEdgePoints();
ITurnListener ignoreTurns = probe.ignoreTurns(); ITurnListener ignoreTurns = probe.ignoreTurns();
List<Pair<Couple<TrackNode>, Double>> recordedLocations = new ArrayList<>(); List<Pair<Couple<TrackNode>, Double>> recordedLocations = new ArrayList<>();
@ -269,7 +272,7 @@ public class TrainRelocator {
public static void visualise(Train train, int i, Vec3 v1, Vec3 v2, boolean valid) { public static void visualise(Train train, int i, Vec3 v1, Vec3 v2, boolean valid) {
CreateClient.OUTLINER.showLine(Pair.of(train, i), v1.add(0, -.825f, 0), v2.add(0, -.825f, 0)) CreateClient.OUTLINER.showLine(Pair.of(train, i), v1.add(0, -.825f, 0), v2.add(0, -.825f, 0))
.colored(valid ? 0x95CD41 : 0xEA5C2B) .colored(valid ? 0x95CD41 : 0xEA5C2B)
.disableLineNormals() .disableNormals()
.lineWidth(i % 2 == 1 ? 1 / 6f : 1 / 4f); .lineWidth(i % 2 == 1 ? 1 / 6f : 1 / 4f);
} }

View file

@ -38,6 +38,7 @@ public class TravellingPoint {
public TrackEdge edge; public TrackEdge edge;
public double position; public double position;
public boolean blocked; public boolean blocked;
public boolean upsideDown;
public static enum SteerDirection { public static enum SteerDirection {
NONE(0), LEFT(-1), RIGHT(1); NONE(0), LEFT(-1), RIGHT(1);
@ -64,11 +65,12 @@ public class TravellingPoint {
public TravellingPoint() {} public TravellingPoint() {}
public TravellingPoint(TrackNode node1, TrackNode node2, TrackEdge edge, double position) { public TravellingPoint(TrackNode node1, TrackNode node2, TrackEdge edge, double position, boolean upsideDown) {
this.node1 = node1; this.node1 = node1;
this.node2 = node2; this.node2 = node2;
this.edge = edge; this.edge = edge;
this.position = position; this.position = position;
this.upsideDown = upsideDown;
} }
public IEdgePointListener ignoreEdgePoints() { public IEdgePointListener ignoreEdgePoints() {
@ -395,14 +397,22 @@ public class TravellingPoint {
} }
public Vec3 getPosition() { public Vec3 getPosition() {
return getPositionWithOffset(0); return getPosition(false);
}
public Vec3 getPosition(boolean flipped) {
return getPositionWithOffset(0, flipped);
} }
public Vec3 getPositionWithOffset(double offset) { public Vec3 getPositionWithOffset(double offset) {
return getPositionWithOffset(offset, false);
}
public Vec3 getPositionWithOffset(double offset, boolean flipUpsideDown) {
double t = (position + offset) / edge.getLength(); double t = (position + offset) / edge.getLength();
return edge.getPosition(t) return edge.getPosition(t)
.add(edge.getNormal(node1, node2, t) .add(edge.getNormal(node1, node2, t)
.scale(1)); .scale(upsideDown^flipUpsideDown ? -1 : 1));
} }
public void migrateTo(List<GraphLocation> locations) { public void migrateTo(List<GraphLocation> locations) {
@ -423,12 +433,13 @@ public class TravellingPoint {
tag.put("Nodes", nodes.map(TrackNode::getLocation) tag.put("Nodes", nodes.map(TrackNode::getLocation)
.serializeEach(loc -> loc.write(dimensions))); .serializeEach(loc -> loc.write(dimensions)));
tag.putDouble("Position", position); tag.putDouble("Position", position);
tag.putBoolean("UpsideDown", upsideDown);
return tag; return tag;
} }
public static TravellingPoint read(CompoundTag tag, TrackGraph graph, DimensionPalette dimensions) { public static TravellingPoint read(CompoundTag tag, TrackGraph graph, DimensionPalette dimensions) {
if (graph == null) if (graph == null)
return new TravellingPoint(null, null, null, 0); return new TravellingPoint(null, null, null, 0, false);
Couple<TrackNode> locs = tag.contains("Nodes") Couple<TrackNode> locs = tag.contains("Nodes")
? Couple.deserializeEach(tag.getList("Nodes", Tag.TAG_COMPOUND), c -> TrackNodeLocation.read(c, dimensions)) ? Couple.deserializeEach(tag.getList("Nodes", Tag.TAG_COMPOUND), c -> TrackNodeLocation.read(c, dimensions))
@ -436,11 +447,11 @@ public class TravellingPoint {
: Couple.create(null, null); : Couple.create(null, null);
if (locs.either(Objects::isNull)) if (locs.either(Objects::isNull))
return new TravellingPoint(null, null, null, 0); return new TravellingPoint(null, null, null, 0, false);
double position = tag.getDouble("Position"); double position = tag.getDouble("Position");
return new TravellingPoint(locs.getFirst(), locs.getSecond(), graph.getConnectionsFrom(locs.getFirst()) return new TravellingPoint(locs.getFirst(), locs.getSecond(), graph.getConnectionsFrom(locs.getFirst())
.get(locs.getSecond()), position); .get(locs.getSecond()), position, tag.getBoolean("UpsideDown"));
} }
} }

View file

@ -38,7 +38,7 @@ import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePoi
import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour; import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour;
import com.simibubi.create.content.logistics.trains.management.schedule.Schedule; import com.simibubi.create.content.logistics.trains.management.schedule.Schedule;
import com.simibubi.create.content.logistics.trains.management.schedule.ScheduleItem; import com.simibubi.create.content.logistics.trains.management.schedule.ScheduleItem;
import com.simibubi.create.content.logistics.trains.track.StandardBogeyTileEntity; import com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity;
import com.simibubi.create.foundation.advancement.AllAdvancements; import com.simibubi.create.foundation.advancement.AllAdvancements;
import com.simibubi.create.foundation.block.ProperWaterloggedBlock; import com.simibubi.create.foundation.block.ProperWaterloggedBlock;
import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.config.AllConfigs;
@ -67,7 +67,6 @@ import net.minecraft.util.Mth;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
@ -193,7 +192,8 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
Direction assemblyDirection; Direction assemblyDirection;
int assemblyLength; int assemblyLength;
int[] bogeyLocations; int[] bogeyLocations;
AbstractBogeyBlock[] bogeyTypes; AbstractBogeyBlock<?>[] bogeyTypes;
boolean[] upsideDownBogeys;
int bogeyCount; int bogeyCount;
@Override @Override
@ -270,28 +270,31 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
return false; return false;
BlockPos up = new BlockPos(track.getUpNormal(level, pos, state)); BlockPos up = new BlockPos(track.getUpNormal(level, pos, state));
BlockPos down = new BlockPos(track.getUpNormal(level, pos, state).multiply(-1, -1, -1));
int bogeyOffset = pos.distManhattan(edgePoint.getGlobalPosition()) - 1; int bogeyOffset = pos.distManhattan(edgePoint.getGlobalPosition()) - 1;
if (!isValidBogeyOffset(bogeyOffset)) { if (!isValidBogeyOffset(bogeyOffset)) {
for (int i = -1; i <= 1; i++) { for (boolean upsideDown : Iterate.falseAndTrue) {
BlockPos bogeyPos = pos.relative(assemblyDirection, i) for (int i = -1; i <= 1; i++) {
.offset(up); BlockPos bogeyPos = pos.relative(assemblyDirection, i)
BlockState blockState = level.getBlockState(bogeyPos); .offset(upsideDown ? down : up);
if (blockState.getBlock() instanceof AbstractBogeyBlock bogey) { BlockState blockState = level.getBlockState(bogeyPos);
BlockEntity be = level.getBlockEntity(bogeyPos); if (blockState.getBlock() instanceof AbstractBogeyBlock<?> bogey) {
if (!(be instanceof StandardBogeyTileEntity oldTE)) BlockEntity be = level.getBlockEntity(bogeyPos);
continue; if (!(be instanceof AbstractBogeyTileEntity oldTE))
CompoundTag oldData = oldTE.getBogeyData(); continue;
BlockState newBlock = bogey.getNextSize(oldTE); CompoundTag oldData = oldTE.getBogeyData();
if (newBlock.getBlock() == bogey) BlockState newBlock = bogey.getNextSize(oldTE);
player.displayClientMessage(Lang.translateDirect("create.bogey.style.no_other_sizes") if (newBlock.getBlock() == bogey)
.withStyle(ChatFormatting.RED), true); player.displayClientMessage(Lang.translateDirect("bogey.style.no_other_sizes")
level.setBlock(bogeyPos, newBlock, 3); .withStyle(ChatFormatting.RED), true);
BlockEntity newEntity = level.getBlockEntity(bogeyPos); level.setBlock(bogeyPos, newBlock, 3);
if (!(newEntity instanceof StandardBogeyTileEntity newTE)) BlockEntity newEntity = level.getBlockEntity(bogeyPos);
continue; if (!(newEntity instanceof AbstractBogeyTileEntity newTE))
newTE.setBogeyData(oldData); continue;
bogey.playRotateSound(level, bogeyPos); newTE.setBogeyData(oldData);
return true; bogey.playRotateSound(level, bogeyPos);
return true;
}
} }
} }
@ -304,7 +307,9 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
return false; return false;
} }
BlockPos targetPos = pos.offset(up); boolean upsideDown = (player.getViewXRot(1.0F) < 0 && (track.getBogeyAnchor(level, pos, state)).getBlock() instanceof AbstractBogeyBlock<?> bogey && bogey.canBeUpsideDown());
BlockPos targetPos = upsideDown ? pos.offset(down) : pos.offset(up);
if (level.getBlockState(targetPos) if (level.getBlockState(targetPos)
.getDestroySpeed(level, targetPos) == -1) { .getDestroySpeed(level, targetPos) == -1) {
return false; return false;
@ -312,7 +317,11 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
level.destroyBlock(targetPos, true); level.destroyBlock(targetPos, true);
BlockState bogeyAnchor = ProperWaterloggedBlock.withWater(level, track.getBogeyAnchor(level, pos, state), pos); BlockState bogeyAnchor = track.getBogeyAnchor(level, pos, state);
if (bogeyAnchor.getBlock() instanceof AbstractBogeyBlock<?> bogey) {
bogeyAnchor = bogey.getVersion(bogeyAnchor, upsideDown);
}
bogeyAnchor = ProperWaterloggedBlock.withWater(level, bogeyAnchor, pos);
level.setBlock(targetPos, bogeyAnchor, 3); level.setBlock(targetPos, bogeyAnchor, 3);
player.displayClientMessage(Lang.translateDirect("train_assembly.bogey_created"), true); player.displayClientMessage(Lang.translateDirect("train_assembly.bogey_created"), true);
SoundType soundtype = bogeyAnchor.getBlock() SoundType soundtype = bogeyAnchor.getBlock()
@ -387,8 +396,11 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
bogeyLocations = new int[maxBogeyCount]; bogeyLocations = new int[maxBogeyCount];
if (bogeyTypes == null) if (bogeyTypes == null)
bogeyTypes = new AbstractBogeyBlock[maxBogeyCount]; bogeyTypes = new AbstractBogeyBlock[maxBogeyCount];
if (upsideDownBogeys == null)
upsideDownBogeys = new boolean[maxBogeyCount];
Arrays.fill(bogeyLocations, -1); Arrays.fill(bogeyLocations, -1);
Arrays.fill(bogeyTypes, null); Arrays.fill(bogeyTypes, null);
Arrays.fill(upsideDownBogeys, false);
for (int i = 0; i < MAX_LENGTH; i++) { for (int i = 0; i < MAX_LENGTH; i++) {
if (i == MAX_LENGTH - 1) { if (i == MAX_LENGTH - 1) {
@ -401,10 +413,19 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
} }
BlockState potentialBogeyState = level.getBlockState(bogeyOffset.offset(currentPos)); BlockState potentialBogeyState = level.getBlockState(bogeyOffset.offset(currentPos));
if (potentialBogeyState.getBlock() instanceof AbstractBogeyBlock bogey && bogeyIndex < bogeyLocations.length) { BlockPos upsideDownBogeyOffset = new BlockPos(bogeyOffset.getX(), bogeyOffset.getY()*-1, bogeyOffset.getZ());
bogeyTypes[bogeyIndex] = bogey; if (bogeyIndex < bogeyLocations.length) {
bogeyLocations[bogeyIndex] = i; if (potentialBogeyState.getBlock() instanceof AbstractBogeyBlock<?> bogey && !bogey.isUpsideDown(potentialBogeyState)) {
bogeyIndex++; bogeyTypes[bogeyIndex] = bogey;
bogeyLocations[bogeyIndex] = i;
upsideDownBogeys[bogeyIndex] = false;
bogeyIndex++;
} else if ((potentialBogeyState = level.getBlockState(upsideDownBogeyOffset.offset(currentPos))).getBlock() instanceof AbstractBogeyBlock<?> bogey && bogey.isUpsideDown(potentialBogeyState)) {
bogeyTypes[bogeyIndex] = bogey;
bogeyLocations[bogeyIndex] = i;
upsideDownBogeys[bogeyIndex] = true;
bogeyIndex++;
}
} }
currentPos.move(assemblyDirection); currentPos.move(assemblyDirection);
@ -564,7 +585,7 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
return; return;
} }
points.add(new TravellingPoint(node, secondNode, edge, positionOnEdge)); points.add(new TravellingPoint(node, secondNode, edge, positionOnEdge, false));
} }
secondNode = node; secondNode = node;
@ -591,10 +612,11 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
spacing.add(bogeyLocations[bogeyIndex] - bogeyLocations[bogeyIndex - 1]); spacing.add(bogeyLocations[bogeyIndex] - bogeyLocations[bogeyIndex - 1]);
CarriageContraption contraption = new CarriageContraption(assemblyDirection); CarriageContraption contraption = new CarriageContraption(assemblyDirection);
BlockPos bogeyPosOffset = trackPosition.offset(bogeyOffset); BlockPos bogeyPosOffset = trackPosition.offset(bogeyOffset);
BlockPos upsideDownBogeyPosOffset = trackPosition.offset(new BlockPos(bogeyOffset.getX(), bogeyOffset.getY() * -1, bogeyOffset.getZ()));
try { try {
int offset = bogeyLocations[bogeyIndex] + 1; int offset = bogeyLocations[bogeyIndex] + 1;
boolean success = contraption.assemble(level, bogeyPosOffset.relative(assemblyDirection, offset)); boolean success = contraption.assemble(level, upsideDownBogeys[bogeyIndex] ? upsideDownBogeyPosOffset.relative(assemblyDirection, offset) : bogeyPosOffset.relative(assemblyDirection, offset));
atLeastOneForwardControls |= contraption.hasForwardControls(); atLeastOneForwardControls |= contraption.hasForwardControls();
contraption.setSoundQueueOffset(offset); contraption.setSoundQueueOffset(offset);
if (!success) { if (!success) {
@ -607,26 +629,27 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
return; return;
} }
AbstractBogeyBlock typeOfFirstBogey = bogeyTypes[bogeyIndex]; AbstractBogeyBlock<?> typeOfFirstBogey = bogeyTypes[bogeyIndex];
boolean firstBogeyIsUpsideDown = upsideDownBogeys[bogeyIndex];
BlockPos firstBogeyPos = contraption.anchor; BlockPos firstBogeyPos = contraption.anchor;
StandardBogeyTileEntity firstBogeyTileEntity = (StandardBogeyTileEntity) level.getBlockEntity(firstBogeyPos); AbstractBogeyTileEntity firstBogeyTileEntity = (AbstractBogeyTileEntity) level.getBlockEntity(firstBogeyPos);
CarriageBogey firstBogey = CarriageBogey firstBogey =
new CarriageBogey(typeOfFirstBogey, firstBogeyTileEntity.getBogeyData(), points.get(pointIndex), points.get(pointIndex + 1)); new CarriageBogey(typeOfFirstBogey, firstBogeyIsUpsideDown, firstBogeyTileEntity.getBogeyData(), points.get(pointIndex), points.get(pointIndex + 1));
CarriageBogey secondBogey = null; CarriageBogey secondBogey = null;
BlockPos secondBogeyPos = contraption.getSecondBogeyPos(); BlockPos secondBogeyPos = contraption.getSecondBogeyPos();
int bogeySpacing = 0; int bogeySpacing = 0;
if (secondBogeyPos != null) { if (secondBogeyPos != null) {
if (bogeyIndex == bogeyCount - 1 || !secondBogeyPos if (bogeyIndex == bogeyCount - 1 || !secondBogeyPos
.equals(bogeyPosOffset.relative(assemblyDirection, bogeyLocations[bogeyIndex + 1] + 1))) { .equals((upsideDownBogeys[bogeyIndex + 1] ? upsideDownBogeyPosOffset : bogeyPosOffset).relative(assemblyDirection, bogeyLocations[bogeyIndex + 1] + 1))) {
exception(new AssemblyException(Lang.translateDirect("train_assembly.not_connected_in_order")), exception(new AssemblyException(Lang.translateDirect("train_assembly.not_connected_in_order")),
contraptions.size() + 1); contraptions.size() + 1);
return; return;
} }
StandardBogeyTileEntity secondBogeyTileEntity = AbstractBogeyTileEntity secondBogeyTileEntity =
(StandardBogeyTileEntity) level.getBlockEntity(secondBogeyPos); (AbstractBogeyTileEntity) level.getBlockEntity(secondBogeyPos);
bogeySpacing = bogeyLocations[bogeyIndex + 1] - bogeyLocations[bogeyIndex]; bogeySpacing = bogeyLocations[bogeyIndex + 1] - bogeyLocations[bogeyIndex];
secondBogey = new CarriageBogey(bogeyTypes[bogeyIndex + 1], secondBogeyTileEntity.getBogeyData(), secondBogey = new CarriageBogey(bogeyTypes[bogeyIndex + 1], upsideDownBogeys[bogeyIndex + 1], secondBogeyTileEntity.getBogeyData(),
points.get(pointIndex + 2), points.get(pointIndex + 3)); points.get(pointIndex + 2), points.get(pointIndex + 3));
bogeyIndex++; bogeyIndex++;

View file

@ -0,0 +1,114 @@
package com.simibubi.create.content.logistics.trains.track;
import com.simibubi.create.AllBogeyStyles;
import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock;
import com.simibubi.create.content.logistics.trains.entity.BogeyStyle;
import com.simibubi.create.foundation.tileEntity.CachedRenderBBTileEntity;
import com.simibubi.create.foundation.utility.NBTHelper;
import com.simibubi.create.foundation.utility.animation.LerpedFloat;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
;
import org.jetbrains.annotations.NotNull;
public abstract class AbstractBogeyTileEntity extends CachedRenderBBTileEntity {
public static String BOGEY_STYLE_KEY = "BogeyStyle";
public static String BOGEY_DATA_KEY = "BogeyData";
private CompoundTag bogeyData;
public AbstractBogeyTileEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
}
public abstract BogeyStyle getDefaultStyle();
public CompoundTag getBogeyData() {
if (this.bogeyData == null || !this.bogeyData.contains(BOGEY_STYLE_KEY))
this.bogeyData = this.createBogeyData();
return this.bogeyData;
}
public void setBogeyData(@NotNull CompoundTag newData) {
if (!newData.contains(BOGEY_STYLE_KEY)) {
ResourceLocation style = getDefaultStyle().name;
NBTHelper.writeResourceLocation(newData, BOGEY_STYLE_KEY, style);
}
this.bogeyData = newData;
}
public void setBogeyStyle(@NotNull BogeyStyle style) {
ResourceLocation location = style.name;
CompoundTag data = this.getBogeyData();
NBTHelper.writeResourceLocation(data, BOGEY_STYLE_KEY, location);
markUpdated();
}
@NotNull
public BogeyStyle getStyle() {
CompoundTag data = this.getBogeyData();
ResourceLocation currentStyle = NBTHelper.readResourceLocation(data, BOGEY_STYLE_KEY);
BogeyStyle style = AllBogeyStyles.BOGEY_STYLES.get(currentStyle);
if (style == null) {
setBogeyStyle(getDefaultStyle());
return getStyle();
}
return style;
}
@Override
protected void saveAdditional(@NotNull CompoundTag pTag) {
CompoundTag data = this.getBogeyData();
if (data != null) pTag.put(BOGEY_DATA_KEY, data); // Now contains style
super.saveAdditional(pTag);
}
@Override
public void load(CompoundTag pTag) {
if (pTag.contains(BOGEY_DATA_KEY))
this.bogeyData = pTag.getCompound(BOGEY_DATA_KEY);
else
this.bogeyData = this.createBogeyData();
super.load(pTag);
}
private CompoundTag createBogeyData() {
CompoundTag nbt = new CompoundTag();
NBTHelper.writeResourceLocation(nbt, BOGEY_STYLE_KEY, getDefaultStyle().name);
return nbt;
}
@Override
protected AABB createRenderBoundingBox() {
return super.createRenderBoundingBox().inflate(2);
}
// Ponder
LerpedFloat virtualAnimation = LerpedFloat.angular();
public float getVirtualAngle(float partialTicks) {
return virtualAnimation.getValue(partialTicks);
}
public void animate(float distanceMoved) {
BlockState blockState = getBlockState();
if (!(blockState.getBlock() instanceof AbstractBogeyBlock type))
return;
double angleDiff = 360 * distanceMoved / (Math.PI * 2 * type.getWheelRadius());
double newWheelAngle = (virtualAnimation.getValue() - angleDiff) % 360;
virtualAnimation.setValue(newWheelAngle);
}
private void markUpdated() {
setChanged();
Level level = getLevel();
if (level != null)
getLevel().sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 3);
}
}

View file

@ -1,10 +1,12 @@
package com.simibubi.create.content.logistics.trains.track; package com.simibubi.create.content.logistics.trains.track;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllBogeyStyles;
import com.simibubi.create.AllTileEntities; import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.logistics.trains.BogeyRenderer;
import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock; import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock;
import com.simibubi.create.content.logistics.trains.BogeySizes; import com.simibubi.create.content.logistics.trains.BogeySizes;
import com.simibubi.create.content.logistics.trains.TrackMaterial;
import com.simibubi.create.content.logistics.trains.entity.BogeyStyle;
import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement; import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement;
import com.simibubi.create.foundation.block.ITE; import com.simibubi.create.foundation.block.ITE;
import com.simibubi.create.foundation.block.ProperWaterloggedBlock; import com.simibubi.create.foundation.block.ProperWaterloggedBlock;
@ -18,13 +20,18 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
public class StandardBogeyBlock extends AbstractBogeyBlock implements ITE<StandardBogeyTileEntity>, ProperWaterloggedBlock, ISpecialBlockItemRequirement { public class StandardBogeyBlock extends AbstractBogeyBlock<StandardBogeyTileEntity> implements ITE<StandardBogeyTileEntity>, ProperWaterloggedBlock, ISpecialBlockItemRequirement {
public StandardBogeyBlock(Properties props, BogeySizes.BogeySize size) { public StandardBogeyBlock(Properties props, BogeySizes.BogeySize size) {
super(props, size); super(props, size);
registerDefaultState(defaultBlockState().setValue(WATERLOGGED, false)); registerDefaultState(defaultBlockState().setValue(WATERLOGGED, false));
} }
@Override
public TrackMaterial.TrackType getTrackType(BogeyStyle style) {
return TrackMaterial.TrackType.STANDARD;
}
@Override @Override
public double getWheelPointSpacing() { public double getWheelPointSpacing() {
return 2; return 2;
@ -40,6 +47,11 @@ public class StandardBogeyBlock extends AbstractBogeyBlock implements ITE<Standa
return new Vec3(0, 7 / 32f, 1); return new Vec3(0, 7 / 32f, 1);
} }
@Override
public BogeyStyle getDefaultStyle() {
return AllBogeyStyles.STANDARD;
}
@Override @Override
public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter level, BlockPos pos, public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter level, BlockPos pos,
Player player) { Player player) {

View file

@ -1,112 +1,19 @@
package com.simibubi.create.content.logistics.trains.track; package com.simibubi.create.content.logistics.trains.track;
import com.simibubi.create.AllBogeyStyles; import com.simibubi.create.AllBogeyStyles;
import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock;
import com.simibubi.create.content.logistics.trains.entity.BogeyStyle; import com.simibubi.create.content.logistics.trains.entity.BogeyStyle;
import com.simibubi.create.foundation.tileEntity.CachedRenderBBTileEntity;
import com.simibubi.create.foundation.utility.NBTHelper;
import com.simibubi.create.foundation.utility.animation.LerpedFloat;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
;
import org.jetbrains.annotations.NotNull;
public class StandardBogeyTileEntity extends CachedRenderBBTileEntity {
public static String BOGEY_STYLE_KEY = "BogeyStyle";
public static String BOGEY_DATA_KEY = "BogeyData";
private CompoundTag bogeyData;
public class StandardBogeyTileEntity extends AbstractBogeyTileEntity {
public StandardBogeyTileEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) { public StandardBogeyTileEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state); super(type, pos, state);
} }
public CompoundTag getBogeyData() {
if (this.bogeyData == null || !this.bogeyData.contains(BOGEY_STYLE_KEY))
this.bogeyData = this.createBogeyData();
return this.bogeyData;
}
public void setBogeyData(@NotNull CompoundTag newData) {
if (!newData.contains(BOGEY_STYLE_KEY)) {
ResourceLocation style = AllBogeyStyles.STANDARD.name;
NBTHelper.writeResourceLocation(newData, BOGEY_STYLE_KEY, style);
}
this.bogeyData = newData;
}
public void setBogeyStyle(@NotNull BogeyStyle style) {
ResourceLocation location = style.name;
CompoundTag data = this.getBogeyData();
NBTHelper.writeResourceLocation(data, BOGEY_STYLE_KEY, location);
markUpdated();
}
@NotNull
public BogeyStyle getStyle() {
CompoundTag data = this.getBogeyData();
ResourceLocation currentStyle = NBTHelper.readResourceLocation(data, BOGEY_STYLE_KEY);
BogeyStyle style = AllBogeyStyles.BOGEY_STYLES.get(currentStyle);
if (style == null) {
setBogeyStyle(AllBogeyStyles.STANDARD);
return getStyle();
}
return style;
}
@Override @Override
protected void saveAdditional(@NotNull CompoundTag pTag) { public BogeyStyle getDefaultStyle() {
CompoundTag data = this.getBogeyData(); return AllBogeyStyles.STANDARD;
if (data != null) pTag.put(BOGEY_DATA_KEY, data); // Now contains style
super.saveAdditional(pTag);
}
@Override
public void load(CompoundTag pTag) {
if (pTag.contains(BOGEY_DATA_KEY))
this.bogeyData = pTag.getCompound(BOGEY_DATA_KEY);
else
this.bogeyData = this.createBogeyData();
super.load(pTag);
}
private CompoundTag createBogeyData() {
CompoundTag nbt = new CompoundTag();
NBTHelper.writeResourceLocation(nbt, BOGEY_STYLE_KEY, AllBogeyStyles.STANDARD.name);
return nbt;
}
@Override
protected AABB createRenderBoundingBox() {
return super.createRenderBoundingBox().inflate(2);
}
// Ponder
LerpedFloat virtualAnimation = LerpedFloat.angular();
public float getVirtualAngle(float partialTicks) {
return virtualAnimation.getValue(partialTicks);
}
public void animate(float distanceMoved) {
BlockState blockState = getBlockState();
if (!(blockState.getBlock() instanceof AbstractBogeyBlock type))
return;
double angleDiff = 360 * distanceMoved / (Math.PI * 2 * type.getWheelRadius());
double newWheelAngle = (virtualAnimation.getValue() - angleDiff) % 360;
virtualAnimation.setValue(newWheelAngle);
}
private void markUpdated() {
setChanged();
Level level = getLevel();
if (level != null)
getLevel().sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 3);
} }
} }

View file

@ -391,7 +391,7 @@ public class TrackBlock extends Block
(d, b) -> axis.scale(b ? 0 : fromCenter ? -d : d) (d, b) -> axis.scale(b ? 0 : fromCenter ? -d : d)
.add(center), .add(center),
b -> shape.getNormal(), b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, axis, b -> shape.getNormal(), b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, axis,
null); null, (b, v) -> ITrackBlock.getMaterialSimple(world, v));
} else } else
list = ITrackBlock.super.getConnected(world, pos, state, linear, connectedTo); list = ITrackBlock.super.getConnected(world, pos, state, linear, connectedTo);
@ -407,7 +407,7 @@ public class TrackBlock extends Block
Map<BlockPos, BezierConnection> connections = trackTE.getConnections(); Map<BlockPos, BezierConnection> connections = trackTE.getConnections();
connections.forEach((connectedPos, bc) -> ITrackBlock.addToListIfConnected(connectedTo, list, 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, (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)); b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, null, bc, (b, v) -> ITrackBlock.getMaterialSimple(world, v, bc.getMaterial())));
if (trackTE.boundLocation == null || !(world instanceof ServerLevel level)) if (trackTE.boundLocation == null || !(world instanceof ServerLevel level))
return list; return list;
@ -433,7 +433,7 @@ public class TrackBlock extends Block
getTrackAxes(world, pos, state).forEach(axis -> { getTrackAxes(world, pos, state).forEach(axis -> {
ITrackBlock.addToListIfConnected(connectedTo, list, (d, b) -> (b ? axis : boundAxis).scale(d) ITrackBlock.addToListIfConnected(connectedTo, list, (d, b) -> (b ? axis : boundAxis).scale(d)
.add(b ? center : boundCenter), b -> (b ? shape : boundShape).getNormal(), .add(b ? center : boundCenter), b -> (b ? shape : boundShape).getNormal(),
b -> b ? level.dimension() : otherLevel.dimension(), axis, null); b -> b ? level.dimension() : otherLevel.dimension(), axis, null, (b, v) -> ITrackBlock.getMaterialSimple(b ? level : otherLevel, v));
}); });
return list; return list;

View file

@ -748,13 +748,13 @@ public class TrackPlacement {
.showLine(Pair.of(key, i * 2), VecHelper.lerp(s, middle1, previous1), .showLine(Pair.of(key, i * 2), VecHelper.lerp(s, middle1, previous1),
VecHelper.lerp(s, middle1, rail1)) VecHelper.lerp(s, middle1, rail1))
.colored(railcolor) .colored(railcolor)
.disableLineNormals() .disableNormals()
.lineWidth(lw); .lineWidth(lw);
CreateClient.OUTLINER CreateClient.OUTLINER
.showLine(Pair.of(key, i * 2 + 1), VecHelper.lerp(s, middle2, previous2), .showLine(Pair.of(key, i * 2 + 1), VecHelper.lerp(s, middle2, previous2),
VecHelper.lerp(s, middle2, rail2)) VecHelper.lerp(s, middle2, rail2))
.colored(railcolor) .colored(railcolor)
.disableLineNormals() .disableNormals()
.lineWidth(lw); .lineWidth(lw);
} }
@ -775,7 +775,7 @@ public class TrackPlacement {
int color = Color.mixColors(0xEA5C2B, 0x95CD41, animation.getValue()); int color = Color.mixColors(0xEA5C2B, 0x95CD41, animation.getValue());
CreateClient.OUTLINER.showLine(Pair.of("start", id), v1.subtract(o1), v1.add(ex)) CreateClient.OUTLINER.showLine(Pair.of("start", id), v1.subtract(o1), v1.add(ex))
.lineWidth(1 / 8f) .lineWidth(1 / 8f)
.disableLineNormals() .disableNormals()
.colored(color); .colored(color);
} }

View file

@ -72,7 +72,7 @@ public class FlipTool extends PlacementToolBase {
AllSpecialTextures tex = AllSpecialTextures.CHECKERED; AllSpecialTextures tex = AllSpecialTextures.CHECKERED;
outline.getParams() outline.getParams()
.lineWidth(1 / 16f) .lineWidth(1 / 16f)
.disableLineNormals() .disableNormals()
.colored(0xdddddd) .colored(0xdddddd)
.withFaceTextures(tex, tex); .withFaceTextures(tex, tex);
outline.render(ms, buffer, AnimationTickHolder.getPartialTicks()); outline.render(ms, buffer, AnimationTickHolder.getPartialTicks());

View file

@ -32,7 +32,7 @@ public class RotateTool extends PlacementToolBase {
line.getParams() line.getParams()
.disableCull() .disableCull()
.disableLineNormals() .disableNormals()
.colored(0xdddddd) .colored(0xdddddd)
.lineWidth(1 / 16f); .lineWidth(1 / 16f);
line.set(start, end) line.set(start, end)

View file

@ -60,6 +60,7 @@ public class AllCommands {
.then(CameraDistanceCommand.register()) .then(CameraDistanceCommand.register())
.then(CameraAngleCommand.register()) .then(CameraAngleCommand.register())
.then(FlySpeedCommand.register()) .then(FlySpeedCommand.register())
//.then(DebugValueCommand.register())
//.then(KillTPSCommand.register()) //.then(KillTPSCommand.register())
.build(); .build();

View file

@ -0,0 +1,41 @@
package com.simibubi.create.foundation.command;
import com.mojang.brigadier.arguments.FloatArgumentType;
import com.simibubi.create.Create;
import net.minecraft.SharedConstants;
import org.apache.commons.lang3.mutable.MutableInt;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.simibubi.create.foundation.utility.Components;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.commands.arguments.coordinates.BlockPosArgument;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.BaseCommandBlock;
import net.minecraft.world.level.block.CommandBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.CommandBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
public class DebugValueCommand {
public static float value = 0;
public static ArgumentBuilder<CommandSourceStack, ?> register() {
return Commands.literal("debugValue")
.requires(cs -> cs.hasPermission(4))
.then(Commands.argument("value", FloatArgumentType.floatArg())
.executes((ctx) -> {
value = FloatArgumentType.getFloat(ctx, "value");
ctx.getSource().sendSuccess(Components.literal("Set value to: "+value), true);
return 1;
}));
}
}

View file

@ -77,6 +77,7 @@ public class CClient extends ConfigBase {
public final ConfigGroup trains = group(1, "trains", Comments.trains); public final ConfigGroup trains = group(1, "trains", Comments.trains);
public final ConfigFloat mountedZoomMultiplier = f(3, 0, "mountedZoomMultiplier", Comments.mountedZoomMultiplier); public final ConfigFloat mountedZoomMultiplier = f(3, 0, "mountedZoomMultiplier", Comments.mountedZoomMultiplier);
public final ConfigBool showTrackGraphOnF3 = b(false, "showTrackGraphOnF3", Comments.showTrackGraphOnF3); public final ConfigBool showTrackGraphOnF3 = b(false, "showTrackGraphOnF3", Comments.showTrackGraphOnF3);
public final ConfigBool showExtendedTrackGraphOnF3 = b(false, "showExtendedTrackGraphOnF3", Comments.showExtendedTrackGraphOnF3);
@Override @Override
public String getName() { public String getName() {
@ -147,6 +148,7 @@ public class CClient extends ConfigBase {
static String trains = "Railway related settings"; static String trains = "Railway related settings";
static String mountedZoomMultiplier = "How far away the Camera should zoom when seated on a train"; static String mountedZoomMultiplier = "How far away the Camera should zoom when seated on a train";
static String showTrackGraphOnF3 = "Display nodes and edges of a Railway Network while f3 debug mode is active"; static String showTrackGraphOnF3 = "Display nodes and edges of a Railway Network while f3 debug mode is active";
static String showExtendedTrackGraphOnF3 = "Additionally display materials of a Rail Network while f3 debug mode is active";
} }
} }

View file

@ -80,6 +80,7 @@ public class BuilderTransformers {
.build(); .build();
} }
@SuppressWarnings("deprecation")
public static <B extends StandardBogeyBlock, P> NonNullUnaryOperator<BlockBuilder<B, P>> bogey() { public static <B extends StandardBogeyBlock, P> NonNullUnaryOperator<BlockBuilder<B, P>> bogey() {
return b -> b.initialProperties(SharedProperties::softMetal) return b -> b.initialProperties(SharedProperties::softMetal)
.properties(p -> p.sound(SoundType.NETHERITE_BLOCK)) .properties(p -> p.sound(SoundType.NETHERITE_BLOCK))
@ -88,7 +89,7 @@ public class BuilderTransformers {
.blockstate((c, p) -> BlockStateGen.horizontalAxisBlock(c, p, s -> p.models() .blockstate((c, p) -> BlockStateGen.horizontalAxisBlock(c, p, s -> p.models()
.getExistingFile(p.modLoc("block/track/bogey/top")))) .getExistingFile(p.modLoc("block/track/bogey/top"))))
.loot((p, l) -> p.dropOther(l, AllBlocks.RAILWAY_CASING.get())) .loot((p, l) -> p.dropOther(l, AllBlocks.RAILWAY_CASING.get()))
.onRegister(block -> AbstractBogeyBlock.register(RegisteredObjects.getKeyOrThrow(block))); .onRegister(block -> AbstractBogeyBlock.registerStandardBogey(RegisteredObjects.getKeyOrThrow(block)));
} }
public static <B extends TrapDoorBlock, P> NonNullUnaryOperator<BlockBuilder<B, P>> trapdoor(boolean orientable) { public static <B extends TrapDoorBlock, P> NonNullUnaryOperator<BlockBuilder<B, P>> trapdoor(boolean orientable) {

View file

@ -398,7 +398,7 @@ public class WorldSectionElement extends AnimatedSceneElement {
aabbOutline.getParams() aabbOutline.getParams()
.lineWidth(1 / 64f) .lineWidth(1 / 64f)
.colored(0xefefef) .colored(0xefefef)
.disableLineNormals(); .disableNormals();
aabbOutline.render(ms, (SuperRenderTypeBuffer) buffer, pt); aabbOutline.render(ms, (SuperRenderTypeBuffer) buffer, pt);
ms.popPose(); ms.popPose();

View file

@ -7,7 +7,7 @@ import java.util.function.Function;
import com.simibubi.create.content.contraptions.components.deployer.DeployerTileEntity; import com.simibubi.create.content.contraptions.components.deployer.DeployerTileEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.bearing.IBearingTileEntity; import com.simibubi.create.content.contraptions.components.structureMovement.bearing.IBearingTileEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyTileEntity; import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyTileEntity;
import com.simibubi.create.content.logistics.trains.track.StandardBogeyTileEntity; import com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity;
import com.simibubi.create.foundation.ponder.PonderScene; import com.simibubi.create.foundation.ponder.PonderScene;
import com.simibubi.create.foundation.ponder.PonderWorld; import com.simibubi.create.foundation.ponder.PonderWorld;
@ -34,7 +34,7 @@ public class AnimateTileEntityInstruction extends TickingInstruction {
public static AnimateTileEntityInstruction bogey(BlockPos location, float totalDelta, int ticks) { public static AnimateTileEntityInstruction bogey(BlockPos location, float totalDelta, int ticks) {
float movedPerTick = totalDelta / ticks; float movedPerTick = totalDelta / ticks;
return new AnimateTileEntityInstruction(location, totalDelta, ticks, return new AnimateTileEntityInstruction(location, totalDelta, ticks,
(w, f) -> castIfPresent(w, location, StandardBogeyTileEntity.class) (w, f) -> castIfPresent(w, location, AbstractBogeyTileEntity.class)
.ifPresent(bte -> bte.animate(f.equals(totalDelta) ? 0 : movedPerTick)), .ifPresent(bte -> bte.animate(f.equals(totalDelta) ? 0 : movedPerTick)),
(w) -> 0f); (w) -> 0f);
} }

View file

@ -87,6 +87,9 @@ public class ValueBox extends ChasingAABBOutline {
ms.translate(pos.getX(), pos.getY(), pos.getZ()); ms.translate(pos.getX(), pos.getY(), pos.getZ());
if (hasTransform) if (hasTransform)
transform.transform(blockState, ms); transform.transform(blockState, ms);
transformNormals = ms.last()
.normal()
.copy();
params.colored(isPassive ? passiveColor : highlightColor); params.colored(isPassive ? passiveColor : highlightColor);
super.render(ms, buffer, pt); super.render(ms, buffer, pt);

View file

@ -1,18 +1,15 @@
package com.simibubi.create.foundation.utility.outliner; package com.simibubi.create.foundation.utility.outliner;
import java.util.Optional;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Vector3f;
import com.mojang.math.Vector4f;
import com.simibubi.create.AllSpecialTextures;
import com.simibubi.create.foundation.render.RenderTypes; import com.simibubi.create.foundation.render.RenderTypes;
import com.simibubi.create.foundation.render.SuperRenderTypeBuffer; import com.simibubi.create.foundation.render.SuperRenderTypeBuffer;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
@ -20,212 +17,85 @@ public class AABBOutline extends Outline {
protected AABB bb; protected AABB bb;
protected final Vector3f minPosTemp1 = new Vector3f();
protected final Vector3f maxPosTemp1 = new Vector3f();
protected final Vector4f colorTemp1 = new Vector4f();
protected final Vector3f pos0Temp = new Vector3f();
protected final Vector3f pos1Temp = new Vector3f();
protected final Vector3f pos2Temp = new Vector3f();
protected final Vector3f pos3Temp = new Vector3f();
protected final Vector3f normalTemp = new Vector3f();
protected final Vector3f originTemp = new Vector3f();
public AABBOutline(AABB bb) { public AABBOutline(AABB bb) {
setBounds(bb); this.setBounds(bb);
} }
public AABB getBounds() { @Override
return bb; public void render(PoseStack ms, SuperRenderTypeBuffer buffer, float pt) {
renderBB(ms, buffer, bb);
}
public void renderBB(PoseStack ms, SuperRenderTypeBuffer buffer, AABB bb) {
Vec3 projectedView = Minecraft.getInstance().gameRenderer.getMainCamera()
.getPosition();
boolean noCull = bb.contains(projectedView);
bb = bb.inflate(noCull ? -1 / 128d : 1 / 128d);
noCull |= params.disableCull;
Vec3 xyz = new Vec3(bb.minX, bb.minY, bb.minZ);
Vec3 Xyz = new Vec3(bb.maxX, bb.minY, bb.minZ);
Vec3 xYz = new Vec3(bb.minX, bb.maxY, bb.minZ);
Vec3 XYz = new Vec3(bb.maxX, bb.maxY, bb.minZ);
Vec3 xyZ = new Vec3(bb.minX, bb.minY, bb.maxZ);
Vec3 XyZ = new Vec3(bb.maxX, bb.minY, bb.maxZ);
Vec3 xYZ = new Vec3(bb.minX, bb.maxY, bb.maxZ);
Vec3 XYZ = new Vec3(bb.maxX, bb.maxY, bb.maxZ);
Vec3 start = xyz;
renderAACuboidLine(ms, buffer, start, Xyz);
renderAACuboidLine(ms, buffer, start, xYz);
renderAACuboidLine(ms, buffer, start, xyZ);
start = XyZ;
renderAACuboidLine(ms, buffer, start, xyZ);
renderAACuboidLine(ms, buffer, start, XYZ);
renderAACuboidLine(ms, buffer, start, Xyz);
start = XYz;
renderAACuboidLine(ms, buffer, start, xYz);
renderAACuboidLine(ms, buffer, start, Xyz);
renderAACuboidLine(ms, buffer, start, XYZ);
start = xYZ;
renderAACuboidLine(ms, buffer, start, XYZ);
renderAACuboidLine(ms, buffer, start, xyZ);
renderAACuboidLine(ms, buffer, start, xYz);
renderFace(ms, buffer, Direction.NORTH, xYz, XYz, Xyz, xyz, noCull);
renderFace(ms, buffer, Direction.SOUTH, XYZ, xYZ, xyZ, XyZ, noCull);
renderFace(ms, buffer, Direction.EAST, XYz, XYZ, XyZ, Xyz, noCull);
renderFace(ms, buffer, Direction.WEST, xYZ, xYz, xyz, xyZ, noCull);
renderFace(ms, buffer, Direction.UP, xYZ, XYZ, XYz, xYz, noCull);
renderFace(ms, buffer, Direction.DOWN, xyz, Xyz, XyZ, xyZ, noCull);
}
protected void renderFace(PoseStack ms, SuperRenderTypeBuffer buffer, Direction direction, Vec3 p1, Vec3 p2,
Vec3 p3, Vec3 p4, boolean noCull) {
if (!params.faceTexture.isPresent())
return;
ResourceLocation faceTexture = params.faceTexture.get()
.getLocation();
float alphaBefore = params.alpha;
params.alpha =
(direction == params.getHighlightedFace() && params.hightlightedFaceTexture.isPresent()) ? 1 : 0.5f;
RenderType translucentType = RenderTypes.getOutlineTranslucent(faceTexture, !noCull);
VertexConsumer builder = buffer.getLateBuffer(translucentType);
Axis axis = direction.getAxis();
Vec3 uDiff = p2.subtract(p1);
Vec3 vDiff = p4.subtract(p1);
float maxU = (float) Math.abs(axis == Axis.X ? uDiff.z : uDiff.x);
float maxV = (float) Math.abs(axis == Axis.Y ? vDiff.z : vDiff.y);
putQuadUV(ms, builder, p1, p2, p3, p4, 0, 0, maxU, maxV, Direction.UP);
params.alpha = alphaBefore;
} }
public void setBounds(AABB bb) { public void setBounds(AABB bb) {
this.bb = bb; this.bb = bb;
} }
@Override
public void render(PoseStack ms, SuperRenderTypeBuffer buffer, float pt) {
params.loadColor(colorTemp);
Vector4f color = colorTemp;
int lightmap = params.lightmap;
boolean disableLineNormals = params.disableLineNormals;
renderBox(ms, buffer, bb, color, lightmap, disableLineNormals);
}
protected void renderBox(PoseStack ms, SuperRenderTypeBuffer buffer, AABB box, Vector4f color, int lightmap, boolean disableLineNormals) {
Vector3f minPos = minPosTemp1;
Vector3f maxPos = maxPosTemp1;
Vec3 cameraPos = Minecraft.getInstance().gameRenderer.getMainCamera()
.getPosition();
boolean cameraInside = box.contains(cameraPos);
boolean cull = !cameraInside && !params.disableCull;
float inflate = cameraInside ? -1 / 128f : 1 / 128f;
minPos.set((float) box.minX - inflate, (float) box.minY - inflate, (float) box.minZ - inflate);
maxPos.set((float) box.maxX + inflate, (float) box.maxY + inflate, (float) box.maxZ + inflate);
renderBoxFaces(ms, buffer, cull, params.getHighlightedFace(), minPos, maxPos, color, lightmap);
float lineWidth = params.getLineWidth();
if (lineWidth == 0)
return;
VertexConsumer consumer = buffer.getBuffer(RenderTypes.getOutlineSolid());
renderBoxEdges(ms, consumer, minPos, maxPos, lineWidth, color, lightmap, disableLineNormals);
}
protected void renderBoxFaces(PoseStack ms, SuperRenderTypeBuffer buffer, boolean cull, Direction highlightedFace, Vector3f minPos, Vector3f maxPos, Vector4f color, int lightmap) {
PoseStack.Pose pose = ms.last();
renderBoxFace(pose, buffer, cull, highlightedFace, minPos, maxPos, Direction.DOWN, color, lightmap);
renderBoxFace(pose, buffer, cull, highlightedFace, minPos, maxPos, Direction.UP, color, lightmap);
renderBoxFace(pose, buffer, cull, highlightedFace, minPos, maxPos, Direction.NORTH, color, lightmap);
renderBoxFace(pose, buffer, cull, highlightedFace, minPos, maxPos, Direction.SOUTH, color, lightmap);
renderBoxFace(pose, buffer, cull, highlightedFace, minPos, maxPos, Direction.WEST, color, lightmap);
renderBoxFace(pose, buffer, cull, highlightedFace, minPos, maxPos, Direction.EAST, color, lightmap);
}
protected void renderBoxFace(PoseStack.Pose pose, SuperRenderTypeBuffer buffer, boolean cull, Direction highlightedFace, Vector3f minPos, Vector3f maxPos, Direction face, Vector4f color, int lightmap) {
boolean highlighted = face == highlightedFace;
// TODO: Presumably, the other texture should be used, but this was not noticed before so fixing it may lead to suboptimal visuals.
// Optional<AllSpecialTextures> optionalFaceTexture = highlighted ? params.hightlightedFaceTexture : params.faceTexture;
Optional<AllSpecialTextures> optionalFaceTexture = params.faceTexture;
if (!optionalFaceTexture.isPresent())
return;
AllSpecialTextures faceTexture = optionalFaceTexture.get();
RenderType renderType = RenderTypes.getOutlineTranslucent(faceTexture.getLocation(), cull);
VertexConsumer consumer = buffer.getLateBuffer(renderType);
float alphaMult = highlighted ? 1 : 0.5f;
colorTemp1.set(color.x(), color.y(), color.z(), color.w() * alphaMult);
color = colorTemp1;
renderBoxFace(pose, consumer, minPos, maxPos, face, color, lightmap);
}
protected void renderBoxFace(PoseStack.Pose pose, VertexConsumer consumer, Vector3f minPos, Vector3f maxPos, Direction face, Vector4f color, int lightmap) {
Vector3f pos0 = pos0Temp;
Vector3f pos1 = pos1Temp;
Vector3f pos2 = pos2Temp;
Vector3f pos3 = pos3Temp;
Vector3f normal = normalTemp;
float minX = minPos.x();
float minY = minPos.y();
float minZ = minPos.z();
float maxX = maxPos.x();
float maxY = maxPos.y();
float maxZ = maxPos.z();
float maxU;
float maxV;
switch (face) {
case DOWN -> {
// 0 1 2 3
pos0.set(minX, minY, maxZ);
pos1.set(minX, minY, minZ);
pos2.set(maxX, minY, minZ);
pos3.set(maxX, minY, maxZ);
maxU = maxX - minX;
maxV = maxZ - minZ;
normal.set(0, -1, 0);
}
case UP -> {
// 4 5 6 7
pos0.set(minX, maxY, minZ);
pos1.set(minX, maxY, maxZ);
pos2.set(maxX, maxY, maxZ);
pos3.set(maxX, maxY, minZ);
maxU = maxX - minX;
maxV = maxZ - minZ;
normal.set(0, 1, 0);
}
case NORTH -> {
// 7 2 1 4
pos0.set(maxX, maxY, minZ);
pos1.set(maxX, minY, minZ);
pos2.set(minX, minY, minZ);
pos3.set(minX, maxY, minZ);
maxU = maxX - minX;
maxV = maxY - minY;
normal.set(0, 0, -1);
}
case SOUTH -> {
// 5 0 3 6
pos0.set(minX, maxY, maxZ);
pos1.set(minX, minY, maxZ);
pos2.set(maxX, minY, maxZ);
pos3.set(maxX, maxY, maxZ);
maxU = maxX - minX;
maxV = maxY - minY;
normal.set(0, 0, 1);
}
case WEST -> {
// 4 1 0 5
pos0.set(minX, maxY, minZ);
pos1.set(minX, minY, minZ);
pos2.set(minX, minY, maxZ);
pos3.set(minX, maxY, maxZ);
maxU = maxZ - minZ;
maxV = maxY - minY;
normal.set(-1, 0, 0);
}
case EAST -> {
// 6 3 2 7
pos0.set(maxX, maxY, maxZ);
pos1.set(maxX, minY, maxZ);
pos2.set(maxX, minY, minZ);
pos3.set(maxX, maxY, minZ);
maxU = maxZ - minZ;
maxV = maxY - minY;
normal.set(1, 0, 0);
}
default -> {
maxU = 1;
maxV = 1;
}
}
bufferQuad(pose, consumer, pos0, pos1, pos2, pos3, color, 0, 0, maxU, maxV, lightmap, normal);
}
protected void renderBoxEdges(PoseStack ms, VertexConsumer consumer, Vector3f minPos, Vector3f maxPos, float lineWidth, Vector4f color, int lightmap, boolean disableNormals) {
Vector3f origin = originTemp;
PoseStack.Pose pose = ms.last();
float lineLengthX = maxPos.x() - minPos.x();
float lineLengthY = maxPos.y() - minPos.y();
float lineLengthZ = maxPos.z() - minPos.z();
origin.load(minPos);
bufferCuboidLine(pose, consumer, origin, Direction.EAST, lineLengthX, lineWidth, color, lightmap, disableNormals);
bufferCuboidLine(pose, consumer, origin, Direction.UP, lineLengthY, lineWidth, color, lightmap, disableNormals);
bufferCuboidLine(pose, consumer, origin, Direction.SOUTH, lineLengthZ, lineWidth, color, lightmap, disableNormals);
origin.set(maxPos.x(), minPos.y(), minPos.z());
bufferCuboidLine(pose, consumer, origin, Direction.UP, lineLengthY, lineWidth, color, lightmap, disableNormals);
bufferCuboidLine(pose, consumer, origin, Direction.SOUTH, lineLengthZ, lineWidth, color, lightmap, disableNormals);
origin.set(minPos.x(), maxPos.y(), minPos.z());
bufferCuboidLine(pose, consumer, origin, Direction.EAST, lineLengthX, lineWidth, color, lightmap, disableNormals);
bufferCuboidLine(pose, consumer, origin, Direction.SOUTH, lineLengthZ, lineWidth, color, lightmap, disableNormals);
origin.set(minPos.x(), minPos.y(), maxPos.z());
bufferCuboidLine(pose, consumer, origin, Direction.EAST, lineLengthX, lineWidth, color, lightmap, disableNormals);
bufferCuboidLine(pose, consumer, origin, Direction.UP, lineLengthY, lineWidth, color, lightmap, disableNormals);
origin.set(minPos.x(), maxPos.y(), maxPos.z());
bufferCuboidLine(pose, consumer, origin, Direction.EAST, lineLengthX, lineWidth, color, lightmap, disableNormals);
origin.set(maxPos.x(), minPos.y(), maxPos.z());
bufferCuboidLine(pose, consumer, origin, Direction.UP, lineLengthY, lineWidth, color, lightmap, disableNormals);
origin.set(maxPos.x(), maxPos.y(), minPos.z());
bufferCuboidLine(pose, consumer, origin, Direction.SOUTH, lineLengthZ, lineWidth, color, lightmap, disableNormals);
}
} }

View file

@ -8,156 +8,94 @@ import java.util.Set;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Vector3f;
import com.mojang.math.Vector4f;
import com.simibubi.create.AllSpecialTextures; import com.simibubi.create.AllSpecialTextures;
import com.simibubi.create.foundation.render.RenderTypes; import com.simibubi.create.foundation.render.RenderTypes;
import com.simibubi.create.foundation.render.SuperRenderTypeBuffer; import com.simibubi.create.foundation.render.SuperRenderTypeBuffer;
import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis; import net.minecraft.core.Direction.Axis;
import net.minecraft.core.Direction.AxisDirection; import net.minecraft.core.Direction.AxisDirection;
import net.minecraft.world.phys.Vec3;
public class BlockClusterOutline extends Outline { public class BlockClusterOutline extends Outline {
private final Cluster cluster; private Cluster cluster;
protected final Vector3f pos0Temp = new Vector3f(); public BlockClusterOutline(Iterable<BlockPos> selection) {
protected final Vector3f pos1Temp = new Vector3f();
protected final Vector3f pos2Temp = new Vector3f();
protected final Vector3f pos3Temp = new Vector3f();
protected final Vector3f normalTemp = new Vector3f();
protected final Vector3f originTemp = new Vector3f();
public BlockClusterOutline(Iterable<BlockPos> positions) {
cluster = new Cluster(); cluster = new Cluster();
positions.forEach(cluster::include); selection.forEach(cluster::include);
} }
@Override @Override
public void render(PoseStack ms, SuperRenderTypeBuffer buffer, float pt) { public void render(PoseStack ms, SuperRenderTypeBuffer buffer, float pt) {
params.loadColor(colorTemp); cluster.visibleEdges.forEach(edge -> {
Vector4f color = colorTemp; Vec3 start = Vec3.atLowerCornerOf(edge.pos);
int lightmap = params.lightmap; Direction direction = Direction.get(AxisDirection.POSITIVE, edge.axis);
boolean disableLineNormals = params.disableLineNormals; renderAACuboidLine(ms, buffer, start, Vec3.atLowerCornerOf(edge.pos.relative(direction)));
});
renderFaces(ms, buffer, pt, color, lightmap); Optional<AllSpecialTextures> faceTexture = params.faceTexture;
renderEdges(ms, buffer, pt, color, lightmap, disableLineNormals); if (!faceTexture.isPresent())
}
protected void renderFaces(PoseStack ms, SuperRenderTypeBuffer buffer, float pt, Vector4f color, int lightmap) {
Optional<AllSpecialTextures> optionalFaceTexture = params.faceTexture;
if (!optionalFaceTexture.isPresent())
return; return;
AllSpecialTextures faceTexture = optionalFaceTexture.get();
PoseStack.Pose pose = ms.last(); RenderType translucentType = RenderTypes.getOutlineTranslucent(faceTexture.get()
RenderType renderType = RenderTypes.getOutlineTranslucent(faceTexture.getLocation(), true); .getLocation(), true);
VertexConsumer consumer = buffer.getLateBuffer(renderType); VertexConsumer builder = buffer.getLateBuffer(translucentType);
cluster.visibleFaces.forEach((face, axisDirection) -> { cluster.visibleFaces.forEach((face, axisDirection) -> {
Direction direction = Direction.get(axisDirection, face.axis); Direction direction = Direction.get(axisDirection, face.axis);
BlockPos pos = face.pos; BlockPos pos = face.pos;
if (axisDirection == AxisDirection.POSITIVE) if (axisDirection == AxisDirection.POSITIVE)
pos = pos.relative(direction.getOpposite()); pos = pos.relative(direction.getOpposite());
bufferBlockFace(pose, consumer, pos, direction, color, lightmap); renderBlockFace(ms, builder, pos, direction);
}); });
} }
protected void renderEdges(PoseStack ms, SuperRenderTypeBuffer buffer, float pt, Vector4f color, int lightmap, boolean disableNormals) { static Vec3 xyz = new Vec3(-.5, -.5, -.5);
float lineWidth = params.getLineWidth(); static Vec3 Xyz = new Vec3(.5, -.5, -.5);
if (lineWidth == 0) static Vec3 xYz = new Vec3(-.5, .5, -.5);
return; static Vec3 XYz = new Vec3(.5, .5, -.5);
static Vec3 xyZ = new Vec3(-.5, -.5, .5);
static Vec3 XyZ = new Vec3(.5, -.5, .5);
static Vec3 xYZ = new Vec3(-.5, .5, .5);
static Vec3 XYZ = new Vec3(.5, .5, .5);
protected void renderBlockFace(PoseStack ms, VertexConsumer builder, BlockPos pos, Direction face) {
Vec3 center = VecHelper.getCenterOf(pos);
Vec3 offset = Vec3.atLowerCornerOf(face.getNormal());
offset = offset.scale(1 / 128d);
center = center.add(offset);
PoseStack.Pose pose = ms.last(); ms.pushPose();
VertexConsumer consumer = buffer.getBuffer(RenderTypes.getOutlineSolid()); ms.translate(center.x, center.y, center.z);
cluster.visibleEdges.forEach(edge -> {
BlockPos pos = edge.pos;
Vector3f origin = originTemp;
origin.set(pos.getX(), pos.getY(), pos.getZ());
Direction direction = Direction.get(AxisDirection.POSITIVE, edge.axis);
bufferCuboidLine(pose, consumer, origin, direction, 1, lineWidth, color, lightmap, disableNormals);
});
}
public static void loadFaceData(Direction face, Vector3f pos0, Vector3f pos1, Vector3f pos2, Vector3f pos3, Vector3f normal) {
switch (face) { switch (face) {
case DOWN -> { case DOWN:
// 0 1 2 3 putQuad(ms, builder, xyz, Xyz, XyZ, xyZ, face);
pos0.set(0, 0, 1); break;
pos1.set(0, 0, 0); case EAST:
pos2.set(1, 0, 0); putQuad(ms, builder, XYz, XYZ, XyZ, Xyz, face);
pos3.set(1, 0, 1); break;
normal.set(0, -1, 0); case NORTH:
putQuad(ms, builder, xYz, XYz, Xyz, xyz, face);
break;
case SOUTH:
putQuad(ms, builder, XYZ, xYZ, xyZ, XyZ, face);
break;
case UP:
putQuad(ms, builder, xYZ, XYZ, XYz, xYz, face);
break;
case WEST:
putQuad(ms, builder, xYZ, xYz, xyz, xyZ, face);
default:
break;
} }
case UP -> {
// 4 5 6 7
pos0.set(0, 1, 0);
pos1.set(0, 1, 1);
pos2.set(1, 1, 1);
pos3.set(1, 1, 0);
normal.set(0, 1, 0);
}
case NORTH -> {
// 7 2 1 4
pos0.set(1, 1, 0);
pos1.set(1, 0, 0);
pos2.set(0, 0, 0);
pos3.set(0, 1, 0);
normal.set(0, 0, -1);
}
case SOUTH -> {
// 5 0 3 6
pos0.set(0, 1, 1);
pos1.set(0, 0, 1);
pos2.set(1, 0, 1);
pos3.set(1, 1, 1);
normal.set(0, 0, 1);
}
case WEST -> {
// 4 1 0 5
pos0.set(0, 1, 0);
pos1.set(0, 0, 0);
pos2.set(0, 0, 1);
pos3.set(0, 1, 1);
normal.set(-1, 0, 0);
}
case EAST -> {
// 6 3 2 7
pos0.set(1, 1, 1);
pos1.set(1, 0, 1);
pos2.set(1, 0, 0);
pos3.set(1, 1, 0);
normal.set(1, 0, 0);
}
}
}
public static void addPos(float x, float y, float z, Vector3f pos0, Vector3f pos1, Vector3f pos2, Vector3f pos3) { ms.popPose();
pos0.add(x, y, z);
pos1.add(x, y, z);
pos2.add(x, y, z);
pos3.add(x, y, z);
}
protected void bufferBlockFace(PoseStack.Pose pose, VertexConsumer consumer, BlockPos pos, Direction face, Vector4f color, int lightmap) {
Vector3f pos0 = pos0Temp;
Vector3f pos1 = pos1Temp;
Vector3f pos2 = pos2Temp;
Vector3f pos3 = pos3Temp;
Vector3f normal = normalTemp;
loadFaceData(face, pos0, pos1, pos2, pos3, normal);
addPos(pos.getX() + face.getStepX() * 1 / 128f,
pos.getY() + face.getStepY() * 1 / 128f,
pos.getZ() + face.getStepZ() * 1 / 128f,
pos0, pos1, pos2, pos3);
bufferQuad(pose, consumer, pos0, pos1, pos2, pos3, color, lightmap, normal);
} }
private static class Cluster { private static class Cluster {

View file

@ -1,7 +1,6 @@
package com.simibubi.create.foundation.utility.outliner; package com.simibubi.create.foundation.utility.outliner;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Vector4f;
import com.simibubi.create.foundation.render.SuperRenderTypeBuffer; import com.simibubi.create.foundation.render.SuperRenderTypeBuffer;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
@ -30,12 +29,7 @@ public class ChasingAABBOutline extends AABBOutline {
@Override @Override
public void render(PoseStack ms, SuperRenderTypeBuffer buffer, float pt) { public void render(PoseStack ms, SuperRenderTypeBuffer buffer, float pt) {
params.loadColor(colorTemp); renderBB(ms, buffer, interpolateBBs(prevBB, bb, pt));
Vector4f color = colorTemp;
int lightmap = params.lightmap;
boolean disableLineNormals = params.disableLineNormals;
renderBox(ms, buffer, interpolateBBs(prevBB, bb, pt), color, lightmap, disableLineNormals);
} }
private static AABB interpolateBBs(AABB current, AABB target, float pt) { private static AABB interpolateBBs(AABB current, AABB target, float pt) {

View file

@ -0,0 +1,51 @@
package com.simibubi.create.foundation.utility.outliner;
import com.jozufozu.flywheel.util.transform.TransformStack;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.simibubi.create.AllSpecialTextures;
import com.simibubi.create.foundation.render.RenderTypes;
import com.simibubi.create.foundation.render.SuperRenderTypeBuffer;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.block.model.ItemTransforms;
import net.minecraft.client.renderer.texture.OverlayTexture;
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.world.item.ItemStack;
import net.minecraft.world.phys.Vec3;
import java.util.*;
public class ItemOutline extends Outline {
protected Vec3 pos;
protected ItemStack stack;
public ItemOutline(Vec3 pos, ItemStack stack) {
this.pos = pos;
this.stack = stack;
}
@Override
public void render(PoseStack ms, SuperRenderTypeBuffer buffer, float pt) {
Minecraft mc = Minecraft.getInstance();
ms.pushPose();
TransformStack.cast(ms)
.translate(pos)
.scale(params.alpha);
mc.getItemRenderer().render(stack, ItemTransforms.TransformType.FIXED, false, ms,
buffer, LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY,
mc.getItemRenderer().getModel(stack, null, null, 0));
ms.popPose();
}
}

View file

@ -1,10 +1,6 @@
package com.simibubi.create.foundation.utility.outliner; package com.simibubi.create.foundation.utility.outliner;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Vector3f;
import com.mojang.math.Vector4f;
import com.simibubi.create.foundation.render.RenderTypes;
import com.simibubi.create.foundation.render.SuperRenderTypeBuffer; import com.simibubi.create.foundation.render.SuperRenderTypeBuffer;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
@ -12,50 +8,33 @@ import net.minecraft.world.phys.Vec3;
public class LineOutline extends Outline { public class LineOutline extends Outline {
protected final Vector3f start = new Vector3f(); protected Vec3 start = Vec3.ZERO;
protected final Vector3f end = new Vector3f(); protected Vec3 end = Vec3.ZERO;
public LineOutline set(Vector3f start, Vector3f end) {
this.start.load(start);
this.start.load(end);
return this;
}
public LineOutline set(Vec3 start, Vec3 end) { public LineOutline set(Vec3 start, Vec3 end) {
this.start.set((float) start.x, (float) start.y, (float) start.z); this.start = start;
this.end.set((float) end.x, (float) end.y, (float) end.z); this.end = end;
return this; return this;
} }
@Override @Override
public void render(PoseStack ms, SuperRenderTypeBuffer buffer, float pt) { public void render(PoseStack ms, SuperRenderTypeBuffer buffer, float pt) {
float width = params.getLineWidth(); renderCuboidLine(ms, buffer, start, end);
if (width == 0)
return;
VertexConsumer consumer = buffer.getBuffer(RenderTypes.getOutlineSolid());
params.loadColor(colorTemp);
Vector4f color = colorTemp;
int lightmap = params.lightmap;
boolean disableLineNormals = params.disableLineNormals;
renderInner(ms, consumer, pt, width, color, lightmap, disableLineNormals);
}
protected void renderInner(PoseStack ms, VertexConsumer consumer, float pt, float width, Vector4f color, int lightmap, boolean disableNormals) {
bufferCuboidLine(ms, consumer, start, end, width, color, lightmap, disableNormals);
} }
public static class EndChasingLineOutline extends LineOutline { public static class EndChasingLineOutline extends LineOutline {
private float progress = 0;
private float prevProgress = 0;
private boolean lockStart;
private final Vector3f startTemp = new Vector3f(); float prevProgress = 0;
float progress = 0;
private boolean lockStart;
public EndChasingLineOutline(boolean lockStart) { public EndChasingLineOutline(boolean lockStart) {
this.lockStart = lockStart; this.lockStart = lockStart;
} }
@Override
public void tick() {}
public EndChasingLineOutline setProgress(float progress) { public EndChasingLineOutline setProgress(float progress) {
prevProgress = this.progress; prevProgress = this.progress;
this.progress = progress; this.progress = progress;
@ -63,24 +42,25 @@ public class LineOutline extends Outline {
} }
@Override @Override
protected void renderInner(PoseStack ms, VertexConsumer consumer, float pt, float width, Vector4f color, int lightmap, boolean disableNormals) { public LineOutline set(Vec3 start, Vec3 end) {
float distanceToTarget = Mth.lerp(pt, prevProgress, progress); if (!end.equals(this.end))
Vector3f end; super.set(start, end);
if (lockStart) { return this;
end = this.start;
} else {
end = this.end;
distanceToTarget = 1 - distanceToTarget;
}
Vector3f start = this.startTemp;
start.load(this.start);
start.sub(end);
start.mul(distanceToTarget);
start.add(end);
bufferCuboidLine(ms, consumer, start, end, width, color, lightmap, disableNormals);
} }
@Override
public void render(PoseStack ms, SuperRenderTypeBuffer buffer, float pt) {
float distanceToTarget = Mth.lerp(pt, prevProgress, progress);
if (!lockStart)
distanceToTarget = 1 - distanceToTarget;
Vec3 start = lockStart ? this.end : this.start;
Vec3 end = lockStart ? this.start : this.end;
start = end.add(this.start.subtract(end)
.scale(distanceToTarget));
renderCuboidLine(ms, buffer, start, end);
}
} }
} }

View file

@ -8,497 +8,156 @@ import com.jozufozu.flywheel.util.transform.TransformStack;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Matrix3f; import com.mojang.math.Matrix3f;
import com.mojang.math.Matrix4f;
import com.mojang.math.Vector3f;
import com.mojang.math.Vector4f;
import com.simibubi.create.AllSpecialTextures; import com.simibubi.create.AllSpecialTextures;
import com.simibubi.create.foundation.render.RenderTypes;
import com.simibubi.create.foundation.render.SuperRenderTypeBuffer; import com.simibubi.create.foundation.render.SuperRenderTypeBuffer;
import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.Color; import com.simibubi.create.foundation.utility.Color;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
import net.minecraft.world.phys.Vec3;
public abstract class Outline { public abstract class Outline {
protected final OutlineParams params; protected OutlineParams params;
protected Matrix3f transformNormals; // TODO: not used?
protected final Vector4f colorTemp = new Vector4f();
protected final Vector3f diffPosTemp = new Vector3f();
protected final Vector3f minPosTemp = new Vector3f();
protected final Vector3f maxPosTemp = new Vector3f();
protected final Vector4f posTransformTemp = new Vector4f();
protected final Vector3f normalTransformTemp = new Vector3f();
public Outline() { public Outline() {
params = new OutlineParams(); params = new OutlineParams();
} }
public OutlineParams getParams() {
return params;
}
public abstract void render(PoseStack ms, SuperRenderTypeBuffer buffer, float pt); public abstract void render(PoseStack ms, SuperRenderTypeBuffer buffer, float pt);
public void tick() {} public void tick() {}
public void bufferCuboidLine(PoseStack poseStack, VertexConsumer consumer, Vector3f start, Vector3f end, float width, Vector4f color, int lightmap, boolean disableNormals) { public OutlineParams getParams() {
Vector3f diff = this.diffPosTemp; return params;
diff.load(end);
diff.sub(start);
float length = Mth.sqrt(diff.x() * diff.x() + diff.y() * diff.y() + diff.z() * diff.z());
float hAngle = AngleHelper.deg(Mth.atan2(diff.x(), diff.z()));
float hDistance = Mth.sqrt(diff.x() * diff.x() + diff.z() * diff.z());
float vAngle = AngleHelper.deg(Mth.atan2(hDistance, diff.y())) - 90;
poseStack.pushPose();
TransformStack.cast(poseStack)
.rotateY(hAngle)
.rotateX(vAngle);
bufferCuboidLine(poseStack.last(), consumer, start, Direction.NORTH, length, width, color, lightmap, disableNormals);
poseStack.popPose();
} }
public void bufferCuboidLine(PoseStack.Pose pose, VertexConsumer consumer, Vector3f origin, Direction direction, float length, float width, Vector4f color, int lightmap, boolean disableNormals) { public void renderCuboidLine(PoseStack ms, SuperRenderTypeBuffer buffer, Vec3 start, Vec3 end) {
Vector3f minPos = minPosTemp; Vec3 diff = end.subtract(start);
Vector3f maxPos = maxPosTemp; float hAngle = AngleHelper.deg(Mth.atan2(diff.x, diff.z));
float hDistance = (float) diff.multiply(1, 0, 1)
float halfWidth = width / 2; .length();
minPos.set(origin.x() - halfWidth, origin.y() - halfWidth, origin.z() - halfWidth); float vAngle = AngleHelper.deg(Mth.atan2(hDistance, diff.y)) - 90;
maxPos.set(origin.x() + halfWidth, origin.y() + halfWidth, origin.z() + halfWidth); ms.pushPose();
TransformStack.cast(ms)
switch (direction) { .translate(start)
case DOWN -> { .rotateY(hAngle).rotateX(vAngle);
minPos.add(0, -length, 0); renderAACuboidLine(ms, buffer, Vec3.ZERO, new Vec3(0, 0, diff.length()));
} ms.popPose();
case UP -> {
maxPos.add(0, length, 0);
}
case NORTH -> {
minPos.add(0, 0, -length);
}
case SOUTH -> {
maxPos.add(0, 0, length);
}
case WEST -> {
minPos.add(-length, 0, 0);
}
case EAST -> {
maxPos.add(length, 0, 0);
}
}
bufferCuboid(pose, consumer, minPos, maxPos, color, lightmap, disableNormals);
} }
public void bufferCuboid(PoseStack.Pose pose, VertexConsumer consumer, Vector3f minPos, Vector3f maxPos, Vector4f color, int lightmap, boolean disableNormals) { public void renderAACuboidLine(PoseStack ms, SuperRenderTypeBuffer buffer, Vec3 start, Vec3 end) {
Vector4f posTransformTemp = this.posTransformTemp; float lineWidth = params.getLineWidth();
Vector3f normalTransformTemp = this.normalTransformTemp; if (lineWidth == 0)
return;
float minX = minPos.x(); VertexConsumer builder = buffer.getBuffer(RenderTypes.getOutlineSolid());
float minY = minPos.y();
float minZ = minPos.z();
float maxX = maxPos.x();
float maxY = maxPos.y();
float maxZ = maxPos.z();
Matrix4f posMatrix = pose.pose(); Vec3 diff = end.subtract(start);
if (diff.x + diff.y + diff.z < 0) {
posTransformTemp.set(minX, minY, maxZ, 1); Vec3 temp = start;
posTransformTemp.transform(posMatrix); start = end;
double x0 = posTransformTemp.x(); end = temp;
double y0 = posTransformTemp.y(); diff = diff.scale(-1);
double z0 = posTransformTemp.z();
posTransformTemp.set(minX, minY, minZ, 1);
posTransformTemp.transform(posMatrix);
double x1 = posTransformTemp.x();
double y1 = posTransformTemp.y();
double z1 = posTransformTemp.z();
posTransformTemp.set(maxX, minY, minZ, 1);
posTransformTemp.transform(posMatrix);
double x2 = posTransformTemp.x();
double y2 = posTransformTemp.y();
double z2 = posTransformTemp.z();
posTransformTemp.set(maxX, minY, maxZ, 1);
posTransformTemp.transform(posMatrix);
double x3 = posTransformTemp.x();
double y3 = posTransformTemp.y();
double z3 = posTransformTemp.z();
posTransformTemp.set(minX, maxY, minZ, 1);
posTransformTemp.transform(posMatrix);
double x4 = posTransformTemp.x();
double y4 = posTransformTemp.y();
double z4 = posTransformTemp.z();
posTransformTemp.set(minX, maxY, maxZ, 1);
posTransformTemp.transform(posMatrix);
double x5 = posTransformTemp.x();
double y5 = posTransformTemp.y();
double z5 = posTransformTemp.z();
posTransformTemp.set(maxX, maxY, maxZ, 1);
posTransformTemp.transform(posMatrix);
double x6 = posTransformTemp.x();
double y6 = posTransformTemp.y();
double z6 = posTransformTemp.z();
posTransformTemp.set(maxX, maxY, minZ, 1);
posTransformTemp.transform(posMatrix);
double x7 = posTransformTemp.x();
double y7 = posTransformTemp.y();
double z7 = posTransformTemp.z();
float r = color.x();
float g = color.y();
float b = color.z();
float a = color.w();
Matrix3f normalMatrix = pose.normal();
// down
if (disableNormals) {
normalTransformTemp.set(0, 1, 0);
} else {
normalTransformTemp.set(0, -1, 0);
} }
normalTransformTemp.transform(normalMatrix);
float nx0 = normalTransformTemp.x();
float ny0 = normalTransformTemp.y();
float nz0 = normalTransformTemp.z();
consumer.vertex(x0, y0, z0) Vec3 extension = diff.normalize()
.color(r, g, b, a) .scale(lineWidth / 2);
.uv(0, 0) Vec3 plane = VecHelper.axisAlingedPlaneOf(diff);
.overlayCoords(OverlayTexture.NO_OVERLAY) Direction face = Direction.getNearest(diff.x, diff.y, diff.z);
.uv2(lightmap) Axis axis = face.getAxis();
.normal(nx0, ny0, nz0)
.endVertex();
consumer.vertex(x1, y1, z1) start = start.subtract(extension);
.color(r, g, b, a) end = end.add(extension);
.uv(0, 1) plane = plane.scale(lineWidth / 2);
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx0, ny0, nz0)
.endVertex();
consumer.vertex(x2, y2, z2) Vec3 a1 = plane.add(start);
.color(r, g, b, a) Vec3 b1 = plane.add(end);
.uv(1, 1) plane = VecHelper.rotate(plane, -90, axis);
.overlayCoords(OverlayTexture.NO_OVERLAY) Vec3 a2 = plane.add(start);
.uv2(lightmap) Vec3 b2 = plane.add(end);
.normal(nx0, ny0, nz0) plane = VecHelper.rotate(plane, -90, axis);
.endVertex(); Vec3 a3 = plane.add(start);
Vec3 b3 = plane.add(end);
plane = VecHelper.rotate(plane, -90, axis);
Vec3 a4 = plane.add(start);
Vec3 b4 = plane.add(end);
consumer.vertex(x3, y3, z3) if (params.disableNormals) {
.color(r, g, b, a) face = Direction.UP;
.uv(1, 0) putQuad(ms, builder, b4, b3, b2, b1, face);
.overlayCoords(OverlayTexture.NO_OVERLAY) putQuad(ms, builder, a1, a2, a3, a4, face);
.uv2(lightmap) putQuad(ms, builder, a1, b1, b2, a2, face);
.normal(nx0, ny0, nz0) putQuad(ms, builder, a2, b2, b3, a3, face);
.endVertex(); putQuad(ms, builder, a3, b3, b4, a4, face);
putQuad(ms, builder, a4, b4, b1, a1, face);
// up return;
normalTransformTemp.set(0, 1, 0);
normalTransformTemp.transform(normalMatrix);
float nx1 = normalTransformTemp.x();
float ny1 = normalTransformTemp.y();
float nz1 = normalTransformTemp.z();
consumer.vertex(x4, y4, z4)
.color(r, g, b, a)
.uv(0, 0)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx1, ny1, nz1)
.endVertex();
consumer.vertex(x5, y5, z5)
.color(r, g, b, a)
.uv(0, 1)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx1, ny1, nz1)
.endVertex();
consumer.vertex(x6, y6, z6)
.color(r, g, b, a)
.uv(1, 1)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx1, ny1, nz1)
.endVertex();
consumer.vertex(x7, y7, z7)
.color(r, g, b, a)
.uv(1, 0)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx1, ny1, nz1)
.endVertex();
// north
if (disableNormals) {
normalTransformTemp.set(0, 1, 0);
} else {
normalTransformTemp.set(0, 0, -1);
} }
normalTransformTemp.transform(normalMatrix);
float nx2 = normalTransformTemp.x();
float ny2 = normalTransformTemp.y();
float nz2 = normalTransformTemp.z();
consumer.vertex(x7, y7, z7) putQuad(ms, builder, b4, b3, b2, b1, face);
.color(r, g, b, a) putQuad(ms, builder, a1, a2, a3, a4, face.getOpposite());
.uv(0, 0) Vec3 vec = a1.subtract(a4);
.overlayCoords(OverlayTexture.NO_OVERLAY) face = Direction.getNearest(vec.x, vec.y, vec.z);
.uv2(lightmap) putQuad(ms, builder, a1, b1, b2, a2, face);
.normal(nx2, ny2, nz2) vec = VecHelper.rotate(vec, -90, axis);
.endVertex(); face = Direction.getNearest(vec.x, vec.y, vec.z);
putQuad(ms, builder, a2, b2, b3, a3, face);
consumer.vertex(x2, y2, z2) vec = VecHelper.rotate(vec, -90, axis);
.color(r, g, b, a) face = Direction.getNearest(vec.x, vec.y, vec.z);
.uv(0, 1) putQuad(ms, builder, a3, b3, b4, a4, face);
.overlayCoords(OverlayTexture.NO_OVERLAY) vec = VecHelper.rotate(vec, -90, axis);
.uv2(lightmap) face = Direction.getNearest(vec.x, vec.y, vec.z);
.normal(nx2, ny2, nz2) putQuad(ms, builder, a4, b4, b1, a1, face);
.endVertex();
consumer.vertex(x1, y1, z1)
.color(r, g, b, a)
.uv(1, 1)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx2, ny2, nz2)
.endVertex();
consumer.vertex(x4, y4, z4)
.color(r, g, b, a)
.uv(1, 0)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx2, ny2, nz2)
.endVertex();
// south
if (disableNormals) {
normalTransformTemp.set(0, 1, 0);
} else {
normalTransformTemp.set(0, 0, 1);
}
normalTransformTemp.transform(normalMatrix);
float nx3 = normalTransformTemp.x();
float ny3 = normalTransformTemp.y();
float nz3 = normalTransformTemp.z();
consumer.vertex(x5, y5, z5)
.color(r, g, b, a)
.uv(0, 0)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx3, ny3, nz3)
.endVertex();
consumer.vertex(x0, y0, z0)
.color(r, g, b, a)
.uv(0, 1)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx3, ny3, nz3)
.endVertex();
consumer.vertex(x3, y3, z3)
.color(r, g, b, a)
.uv(1, 1)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx3, ny3, nz3)
.endVertex();
consumer.vertex(x6, y6, z6)
.color(r, g, b, a)
.uv(1, 0)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx3, ny3, nz3)
.endVertex();
// west
if (disableNormals) {
normalTransformTemp.set(0, 1, 0);
} else {
normalTransformTemp.set(-1, 0, 0);
}
normalTransformTemp.transform(normalMatrix);
float nx4 = normalTransformTemp.x();
float ny4 = normalTransformTemp.y();
float nz4 = normalTransformTemp.z();
consumer.vertex(x4, y4, z4)
.color(r, g, b, a)
.uv(0, 0)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx4, ny4, nz4)
.endVertex();
consumer.vertex(x1, y1, z1)
.color(r, g, b, a)
.uv(0, 1)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx4, ny4, nz4)
.endVertex();
consumer.vertex(x0, y0, z0)
.color(r, g, b, a)
.uv(1, 1)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx4, ny4, nz4)
.endVertex();
consumer.vertex(x5, y5, z5)
.color(r, g, b, a)
.uv(1, 0)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx4, ny4, nz4)
.endVertex();
// east
if (disableNormals) {
normalTransformTemp.set(0, 1, 0);
} else {
normalTransformTemp.set(1, 0, 0);
}
normalTransformTemp.transform(normalMatrix);
float nx5 = normalTransformTemp.x();
float ny5 = normalTransformTemp.y();
float nz5 = normalTransformTemp.z();
consumer.vertex(x6, y6, z6)
.color(r, g, b, a)
.uv(0, 0)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx5, ny5, nz5)
.endVertex();
consumer.vertex(x3, y3, z3)
.color(r, g, b, a)
.uv(0, 1)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx5, ny5, nz5)
.endVertex();
consumer.vertex(x2, y2, z2)
.color(r, g, b, a)
.uv(1, 1)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx5, ny5, nz5)
.endVertex();
consumer.vertex(x7, y7, z7)
.color(r, g, b, a)
.uv(1, 0)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx5, ny5, nz5)
.endVertex();
} }
public void bufferQuad(PoseStack.Pose pose, VertexConsumer consumer, Vector3f pos0, Vector3f pos1, Vector3f pos2, Vector3f pos3, Vector4f color, int lightmap, Vector3f normal) { public void putQuad(PoseStack ms, VertexConsumer builder, Vec3 v1, Vec3 v2, Vec3 v3, Vec3 v4,
bufferQuad(pose, consumer, pos0, pos1, pos2, pos3, color, 0, 0, 1, 1, lightmap, normal); Direction normal) {
putQuadUV(ms, builder, v1, v2, v3, v4, 0, 0, 1, 1, normal);
} }
public void bufferQuad(PoseStack.Pose pose, VertexConsumer consumer, Vector3f pos0, Vector3f pos1, Vector3f pos2, Vector3f pos3, Vector4f color, float minU, float minV, float maxU, float maxV, int lightmap, Vector3f normal) { public void putQuadUV(PoseStack ms, VertexConsumer builder, Vec3 v1, Vec3 v2, Vec3 v3, Vec3 v4, float minU,
Vector4f posTransformTemp = this.posTransformTemp; float minV, float maxU, float maxV, Direction normal) {
Vector3f normalTransformTemp = this.normalTransformTemp; putVertex(ms, builder, v1, minU, minV, normal);
putVertex(ms, builder, v2, maxU, minV, normal);
putVertex(ms, builder, v3, maxU, maxV, normal);
putVertex(ms, builder, v4, minU, maxV, normal);
}
Matrix4f posMatrix = pose.pose(); protected void putVertex(PoseStack ms, VertexConsumer builder, Vec3 pos, float u, float v, Direction normal) {
putVertex(ms.last(), builder, (float) pos.x, (float) pos.y, (float) pos.z, u, v, normal);
}
posTransformTemp.set(pos0.x(), pos0.y(), pos0.z(), 1); protected void putVertex(PoseStack.Pose pose, VertexConsumer builder, float x, float y, float z, float u, float v, Direction normal) {
posTransformTemp.transform(posMatrix); Color rgb = params.rgb;
double x0 = posTransformTemp.x(); if (transformNormals == null)
double y0 = posTransformTemp.y(); transformNormals = pose.normal();
double z0 = posTransformTemp.z();
posTransformTemp.set(pos1.x(), pos1.y(), pos1.z(), 1); int xOffset = 0;
posTransformTemp.transform(posMatrix); int yOffset = 0;
double x1 = posTransformTemp.x(); int zOffset = 0;
double y1 = posTransformTemp.y();
double z1 = posTransformTemp.z();
posTransformTemp.set(pos2.x(), pos2.y(), pos2.z(), 1); if (normal != null) {
posTransformTemp.transform(posMatrix); xOffset = normal.getStepX();
double x2 = posTransformTemp.x(); yOffset = normal.getStepY();
double y2 = posTransformTemp.y(); zOffset = normal.getStepZ();
double z2 = posTransformTemp.z(); }
posTransformTemp.set(pos3.x(), pos3.y(), pos3.z(), 1); builder.vertex(pose.pose(), x, y, z)
posTransformTemp.transform(posMatrix); .color(rgb.getRedAsFloat(), rgb.getGreenAsFloat(), rgb.getBlueAsFloat(), rgb.getAlphaAsFloat() * params.alpha)
double x3 = posTransformTemp.x(); .uv(u, v)
double y3 = posTransformTemp.y();
double z3 = posTransformTemp.z();
float r = color.x();
float g = color.y();
float b = color.z();
float a = color.w();
normalTransformTemp.load(normal);
normalTransformTemp.transform(pose.normal());
float nx = normalTransformTemp.x();
float ny = normalTransformTemp.y();
float nz = normalTransformTemp.z();
consumer.vertex(x0, y0, z0)
.color(r, g, b, a)
.uv(minU, minV)
.overlayCoords(OverlayTexture.NO_OVERLAY) .overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap) .uv2(params.lightMap)
.normal(nx, ny, nz) .normal(pose.normal(), xOffset, yOffset, zOffset)
.endVertex(); .endVertex();
consumer.vertex(x1, y1, z1) transformNormals = null;
.color(r, g, b, a)
.uv(minU, maxV)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx, ny, nz)
.endVertex();
consumer.vertex(x2, y2, z2)
.color(r, g, b, a)
.uv(maxU, maxV)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx, ny, nz)
.endVertex();
consumer.vertex(x3, y3, z3)
.color(r, g, b, a)
.uv(maxU, minV)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx, ny, nz)
.endVertex();
} }
public static class OutlineParams { public static class OutlineParams {
@ -507,9 +166,9 @@ public abstract class Outline {
protected Direction highlightedFace; protected Direction highlightedFace;
protected boolean fadeLineWidth; protected boolean fadeLineWidth;
protected boolean disableCull; protected boolean disableCull;
protected boolean disableLineNormals; protected boolean disableNormals;
protected float alpha; protected float alpha;
protected int lightmap; protected int lightMap;
protected Color rgb; protected Color rgb;
private float lineWidth; private float lineWidth;
@ -519,7 +178,7 @@ public abstract class Outline {
lineWidth = 1 / 32f; lineWidth = 1 / 32f;
fadeLineWidth = true; fadeLineWidth = true;
rgb = Color.WHITE; rgb = Color.WHITE;
lightmap = LightTexture.FULL_BRIGHT; lightMap = LightTexture.FULL_BRIGHT;
} }
// builder // builder
@ -534,8 +193,8 @@ public abstract class Outline {
return this; return this;
} }
public OutlineParams lightmap(int light) { public OutlineParams lightMap(int light) {
lightmap = light; lightMap = light;
return this; return this;
} }
@ -564,8 +223,8 @@ public abstract class Outline {
return this; return this;
} }
public OutlineParams disableLineNormals() { public OutlineParams disableNormals() {
disableLineNormals = true; disableNormals = true;
return this; return this;
} }
@ -584,9 +243,6 @@ public abstract class Outline {
return highlightedFace; return highlightedFace;
} }
public void loadColor(Vector4f vec) {
vec.set(rgb.getRedAsFloat(), rgb.getGreenAsFloat(), rgb.getBlueAsFloat(), rgb.getAlphaAsFloat() * alpha);
}
} }
} }

View file

@ -14,6 +14,7 @@ import com.simibubi.create.foundation.utility.outliner.Outline.OutlineParams;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
@ -32,7 +33,7 @@ public class Outliner {
public OutlineParams showLine(Object slot, Vec3 start, Vec3 end) { public OutlineParams showLine(Object slot, Vec3 start, Vec3 end) {
if (!outlines.containsKey(slot)) { if (!outlines.containsKey(slot)) {
LineOutline outline = new LineOutline(); LineOutline outline = new LineOutline();
addOutline(slot, outline); outlines.put(slot, new OutlineEntry(outline));
} }
OutlineEntry entry = outlines.get(slot); OutlineEntry entry = outlines.get(slot);
entry.ticksTillRemoval = 1; entry.ticksTillRemoval = 1;
@ -43,7 +44,7 @@ public class Outliner {
public OutlineParams endChasingLine(Object slot, Vec3 start, Vec3 end, float chasingProgress, boolean lockStart) { public OutlineParams endChasingLine(Object slot, Vec3 start, Vec3 end, float chasingProgress, boolean lockStart) {
if (!outlines.containsKey(slot)) { if (!outlines.containsKey(slot)) {
EndChasingLineOutline outline = new EndChasingLineOutline(lockStart); EndChasingLineOutline outline = new EndChasingLineOutline(lockStart);
addOutline(slot, outline); outlines.put(slot, new OutlineEntry(outline));
} }
OutlineEntry entry = outlines.get(slot); OutlineEntry entry = outlines.get(slot);
entry.ticksTillRemoval = 1; entry.ticksTillRemoval = 1;
@ -75,11 +76,18 @@ public class Outliner {
public OutlineParams showCluster(Object slot, Iterable<BlockPos> selection) { public OutlineParams showCluster(Object slot, Iterable<BlockPos> selection) {
BlockClusterOutline outline = new BlockClusterOutline(selection); BlockClusterOutline outline = new BlockClusterOutline(selection);
addOutline(slot, outline); OutlineEntry entry = new OutlineEntry(outline);
return outline.getParams(); outlines.put(slot, entry);
return entry.getOutline()
.getParams();
} }
// public OutlineParams showItem(Object slot, Vec3 pos, ItemStack stack) {
ItemOutline outline = new ItemOutline(pos, stack);
OutlineEntry entry = new OutlineEntry(outline);
outlines.put(slot, entry);
return entry.getOutline().getParams();
}
public void keep(Object slot) { public void keep(Object slot) {
if (outlines.containsKey(slot)) if (outlines.containsKey(slot))
@ -105,19 +113,17 @@ public class Outliner {
// Utility // Utility
private void addOutline(Object slot, Outline outline) {
outlines.put(slot, new OutlineEntry(outline));
}
private void createAABBOutlineIfMissing(Object slot, AABB bb) { private void createAABBOutlineIfMissing(Object slot, AABB bb) {
if (!outlines.containsKey(slot) || !(outlines.get(slot).outline instanceof AABBOutline)) { if (!outlines.containsKey(slot) || !(outlines.get(slot).outline instanceof AABBOutline)) {
ChasingAABBOutline outline = new ChasingAABBOutline(bb); ChasingAABBOutline outline = new ChasingAABBOutline(bb);
addOutline(slot, outline); outlines.put(slot, new OutlineEntry(outline));
} }
} }
private ChasingAABBOutline getAndRefreshAABB(Object slot) { private ChasingAABBOutline getAndRefreshAABB(Object slot) {
return getAndRefreshAABB(slot, 1); OutlineEntry entry = outlines.get(slot);
entry.ticksTillRemoval = 1;
return (ChasingAABBOutline) entry.getOutline();
} }
private ChasingAABBOutline getAndRefreshAABB(Object slot, int ttl) { private ChasingAABBOutline getAndRefreshAABB(Object slot, int ttl) {
@ -146,7 +152,7 @@ public class Outliner {
params.alpha = 1; params.alpha = 1;
if (entry.isFading()) { if (entry.isFading()) {
int prevTicks = entry.ticksTillRemoval + 1; int prevTicks = entry.ticksTillRemoval + 1;
float fadeticks = OutlineEntry.FADE_TICKS; float fadeticks = OutlineEntry.fadeTicks;
float lastAlpha = prevTicks >= 0 ? 1 : 1 + (prevTicks / fadeticks); float lastAlpha = prevTicks >= 0 ? 1 : 1 + (prevTicks / fadeticks);
float currentAlpha = 1 + (entry.ticksTillRemoval / fadeticks); float currentAlpha = 1 + (entry.ticksTillRemoval / fadeticks);
float alpha = Mth.lerp(pt, lastAlpha, currentAlpha); float alpha = Mth.lerp(pt, lastAlpha, currentAlpha);
@ -160,35 +166,33 @@ public class Outliner {
} }
public static class OutlineEntry { public static class OutlineEntry {
public static final int FADE_TICKS = 8;
private final Outline outline; static final int fadeTicks = 8;
private int ticksTillRemoval = 1; private Outline outline;
private int ticksTillRemoval;
public OutlineEntry(Outline outline) { public OutlineEntry(Outline outline) {
this.outline = outline; this.outline = outline;
} ticksTillRemoval = 1;
public Outline getOutline() {
return outline;
}
public int getTicksTillRemoval() {
return ticksTillRemoval;
}
public boolean isAlive() {
return ticksTillRemoval >= -FADE_TICKS;
}
public boolean isFading() {
return ticksTillRemoval < 0;
} }
public void tick() { public void tick() {
ticksTillRemoval--; ticksTillRemoval--;
outline.tick(); outline.tick();
} }
public boolean isAlive() {
return ticksTillRemoval >= -fadeTicks;
}
public boolean isFading() {
return ticksTillRemoval < 0;
}
public Outline getOutline() {
return outline;
}
} }
} }

View file

@ -920,8 +920,14 @@
"create.contraption.minecart_contraption_too_big": "This Cart Contraption seems too big to pick up", "create.contraption.minecart_contraption_too_big": "This Cart Contraption seems too big to pick up",
"create.contraption.minecart_contraption_illegal_pickup": "A mystical force is binding this Cart Contraption to the world", "create.contraption.minecart_contraption_illegal_pickup": "A mystical force is binding this Cart Contraption to the world",
"enchantment.create.capacity.desc": "Increases Backtank air capacity.", "enchantment.create.capacity.desc": "Increases Backtank air capacity.",
"enchantment.create.potato_recovery.desc": "Potato Cannon projectiles have a chance to be reused." "enchantment.create.potato_recovery.desc": "Potato Cannon projectiles have a chance to be reused.",
"create.bogey.style.updated_style": "Updated style",
"create.bogey.style.updated_style_and_size": "Updated style and size",
"create.bogey.style.no_other_sizes": "No other sizes",
"create.bogey.style.invalid": "Unnamed style",
"create.bogey.style.standard": "Standard"
} }