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
.buildpath
.DS_Store
.DS_Store
/libs/

View file

@ -135,6 +135,9 @@ repositories {
includeGroup "maven.modrinth"
}
}
flatDir {
dirs 'libs'
}
}
dependencies {
@ -169,6 +172,7 @@ dependencies {
// 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("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
// 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
b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.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
b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.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
d99d5c67bdffff60789a19bd51a5c5267c75e0a4 data/create/tags/blocks/casing.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
6e5d3b2123fbb00e7f439c091623619502551bca data/create/tags/blocks/non_movable.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
6cdeeac1689f7b5bfd9bc40b462143d8eaf3ad0b data/create/tags/blocks/seats.json
d063e12c9ef75f39518c6d129ea35d833464d547 data/create/tags/blocks/toolboxes.json
ad8fa04f7bbbafd70d0ce158af78a35e899301e2 data/create/tags/blocks/tracks.json
9460e92c8e483446318b849abe7e6f52dcd4a269 data/create/tags/blocks/tree_attachments.json
50936b211d94167a35ec78c89954082a336b6269 data/create/tags/blocks/valve_handles.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.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 [------------------------<-",

View file

@ -1,5 +1,6 @@
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.BogeyRenderer;
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.entity.BogeyStyle;
import com.simibubi.create.foundation.utility.Components;
import com.simibubi.create.foundation.utility.Lang;
import com.tterrag.registrate.util.entry.BlockEntry;
@ -26,20 +28,26 @@ import static com.simibubi.create.Create.LOGGER;
public class AllBogeyStyles {
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)
.displayName(Lang.translateDirect("create.bogeys.styles.standard"))
.displayName(Components.translatable("create.bogey.style.standard"))
.size(BogeySizes.SMALL, SmallStandardBogeyRenderer::new, AllBlocks.SMALL_BOGEY)
.size(BogeySizes.LARGE, LargeStandardBogeyRenderer::new, AllBlocks.LARGE_BOGEY)
.build();
public static BogeyStyleBuilder create(String name) {
return create(Create.asResource(name));
public static BogeyStyleBuilder create(String name, String cycleGroup) {
return create(Create.asResource(name), Create.asResource(cycleGroup));
}
public static BogeyStyleBuilder create(ResourceLocation name) {
return new BogeyStyleBuilder(name);
public static BogeyStyleBuilder create(ResourceLocation name, ResourceLocation cycleGroup) {
return new BogeyStyleBuilder(name, cycleGroup);
}
public static void register() {
@ -49,16 +57,18 @@ public class AllBogeyStyles {
public static class BogeyStyleBuilder {
protected final Map<BogeySizes.BogeySize, BogeyStyle.SizeData> sizes = new HashMap<>();
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 CompoundTag defaultData = new CompoundTag();
protected ParticleOptions contactParticle = ParticleTypes.CRIT;
protected ParticleOptions smokeParticle = ParticleTypes.POOF;
protected Optional<Supplier<? extends CommonRenderer>> commonRenderer = Optional.empty();
public BogeyStyleBuilder(ResourceLocation name) {
public BogeyStyleBuilder(ResourceLocation name, ResourceLocation cycleGroup) {
this.name = name;
this.cycleGroup = cycleGroup;
}
public BogeyStyleBuilder displayName(Component displayName) {
@ -105,8 +115,9 @@ public class AllBogeyStyles {
public BogeyStyle build() {
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);
STYLE_GROUPS.computeIfAbsent(cycleGroup, l -> new HashMap<>()).put(name, 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.StationTileEntity;
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.TrackBlock;
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.foundation.tileEntity.renderer.SmartTileEntityRenderer;
import com.tterrag.registrate.util.entry.BlockEntityEntry;
import com.tterrag.registrate.util.entry.BlockEntry;
import com.tterrag.registrate.util.nullness.NonNullSupplier;
import net.minecraft.world.level.block.Block;
public class AllTileEntities {
// Schematics

View file

@ -342,7 +342,7 @@ public abstract class Contraption {
}
// 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))
if (!visited.contains(pos.relative(d)))
frontier.add(pos.relative(d));

View file

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

View file

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

View file

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

View file

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

View file

@ -9,6 +9,8 @@ import java.util.Set;
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.VertexConsumer;
import com.mojang.math.Vector3f;
@ -17,7 +19,10 @@ import com.simibubi.create.AllBogeyStyles;
import com.simibubi.create.AllItems;
import com.simibubi.create.content.contraptions.wrench.IWrenchable;
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.ItemRequirement;
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.properties.BlockStateProperties;
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.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
@ -55,7 +61,7 @@ import net.minecraftforge.registries.ForgeRegistries;
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;
static final List<ResourceLocation> BOGEYS = new ArrayList<>();
public BogeySizes.BogeySize size;
@ -67,7 +73,23 @@ public abstract class AbstractBogeyBlock extends Block implements ITE<StandardBo
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);
}
@ -100,16 +122,34 @@ public abstract class AbstractBogeyBlock extends Block implements ITE<StandardBo
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() {
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)
public void render(@Nullable BlockState state, float wheelAngle, PoseStack ms, float partialTicks,
MultiBufferSource buffers, int light, int overlay, StandardBogeyTileEntity sbte) {
BogeyStyle style = sbte.getStyle();
public void render(@Nullable BlockState state, boolean upsideDown, float wheelAngle, PoseStack ms, float partialTicks,
MultiBufferSource buffers, int light, int overlay, BogeyStyle style, CompoundTag bogeyData) {
if (style == null)
style = getDefaultStyle();
final Optional<BogeyRenderer.CommonRenderer> commonRenderer
= style.getInWorldCommonRenderInstance();
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);
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 ->
common.render(sbte.getBogeyData(), wheelAngle, ms, light, vb));
common.render(upsideDown, finalBogeyData, wheelAngle, ms, light, vb, state == null));
}
public BogeySizes.BogeySize getSize() {
return this.size;
};
}
public Direction getBogeyUpDirection() {
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())
&& AllBogeyStyles.BOGEY_STYLES.size() > 1) {
Collection<BogeyStyle> styles = AllBogeyStyles.BOGEY_STYLES.values();
if (styles.size() <= 1)
return InteractionResult.PASS;
BlockEntity be = level.getBlockEntity(pos);
if (!(be instanceof StandardBogeyTileEntity sbte))
if (!(be instanceof AbstractBogeyTileEntity sbte))
return InteractionResult.FAIL;
player.getCooldowns().addCooldown(stack.getItem(), 20);
BogeyStyle currentStyle = sbte.getStyle();
BogeySizes.BogeySize size = getSize();
BogeyStyle style = this.getNextStyle(currentStyle);
if (style == currentStyle)
return InteractionResult.PASS;
Set<BogeySizes.BogeySize> validSizes = style.validSizes();
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));
if (size == getSize()) {
player.displayClientMessage(Lang.translateDirect("create.bogey.style.updated_style")
.append(": " + style.displayName), true);
player.displayClientMessage(Lang.translateDirect("bogey.style.updated_style")
.append(": ").append(style.displayName), true);
} else {
CompoundTag oldData = sbte.getBogeyData();
level.setBlock(pos, this.getStateOfSize(sbte, size), 3);
BlockEntity newBlockEntity = level.getBlockEntity(pos);
if (!(newBlockEntity instanceof StandardBogeyTileEntity newTileEntity))
if (!(newBlockEntity instanceof AbstractBogeyTileEntity newTileEntity))
return InteractionResult.FAIL;
newTileEntity.setBogeyData(oldData);
player.displayClientMessage(Lang.translateDirect("create.bogey.style.updated_style_and_size")
.append(": " + style.displayName), true);
player.displayClientMessage(Lang.translateDirect("bogey.style.updated_style_and_size")
.append(": ").append(style.displayName), true);
}
return InteractionResult.CONSUME;
@ -200,28 +243,34 @@ public abstract class AbstractBogeyBlock extends Block implements ITE<StandardBo
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
public BlockState getRotatedBlockState(BlockState state, Direction targetedFace) {
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)
return state;
int index = (indexOf + 1) % BOGEYS.size();
int index = (indexOf + 1) % bogeyCycle.size();
Direction bogeyUpDirection = getBogeyUpDirection();
boolean trackAxisAlongFirstCoordinate = isTrackAxisAlongFirstCoordinate(state);
while (index != indexOf) {
ResourceLocation id = BOGEYS.get(index);
ResourceLocation id = bogeyCycle.get(index);
Block newBlock = ForgeRegistries.BLOCKS.getValue(id);
if (newBlock instanceof AbstractBogeyBlock bogey) {
if (newBlock instanceof AbstractBogeyBlock<?> bogey) {
BlockState matchingBogey = bogey.getMatchingBogey(bogeyUpDirection, trackAxisAlongFirstCoordinate);
if (matchingBogey != null)
return matchingBogey.hasProperty(WATERLOGGED)
? matchingBogey.setValue(WATERLOGGED, state.getValue(WATERLOGGED))
: matchingBogey;
return copyProperties(state, matchingBogey);
}
index = (index + 1) % BOGEYS.size();
index = (index + 1) % bogeyCycle.size();
}
return state;
@ -229,37 +278,55 @@ public abstract class AbstractBogeyBlock extends Block implements ITE<StandardBo
public BlockState getNextSize(Level level, BlockPos pos) {
BlockEntity te = level.getBlockEntity(pos);
if (te instanceof StandardBogeyTileEntity sbte)
if (te instanceof AbstractBogeyTileEntity sbte)
return this.getNextSize(sbte);
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();
BogeyStyle style = sbte.getStyle();
BlockState nextBlock = style.getNextBlock(size).defaultBlockState();
return nextBlock.hasProperty(WATERLOGGED)
? nextBlock.setValue(WATERLOGGED, sbte.getBlockState().getValue(WATERLOGGED))
: nextBlock;
nextBlock = copyProperties(sbte.getBlockState(), nextBlock);
return nextBlock;
}
public BlockState getStateOfSize(StandardBogeyTileEntity sbte, BogeySizes.BogeySize size) {
public BlockState getStateOfSize(AbstractBogeyTileEntity sbte, BogeySizes.BogeySize size) {
BogeyStyle style = sbte.getStyle();
BlockState state = style.getBlockOfSize(size).defaultBlockState();
return state.hasProperty(WATERLOGGED)
? state.setValue(WATERLOGGED, sbte.getBlockState().getValue(WATERLOGGED))
: state;
return copyProperties(sbte.getBlockState(), state);
}
public BogeyStyle getNextStyle(Level level, BlockPos pos) {
BlockEntity te = level.getBlockEntity(pos);
if (te instanceof StandardBogeyTileEntity sbte)
if (te instanceof AbstractBogeyTileEntity sbte)
return this.getNextStyle(sbte.getStyle());
return AllBogeyStyles.STANDARD;
return getDefaultStyle();
}
public BogeyStyle getNextStyle(BogeyStyle style) {
Collection<BogeyStyle> allStyles = AllBogeyStyles.BOGEY_STYLES.values();
Collection<BogeyStyle> allStyles = style.getCycleGroup().values();
if (allStyles.size() <= 1)
return style;
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) {
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 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
* @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) {
return (inContraption) ? transformContraptionModelData(keyFromModel(model), ms) : createModelData(model, size);
public Transform<?>[] getTransformsFromPartial(PartialModel model, PoseStack ms, boolean inInstancedContraption, int 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
*/
@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
@ -79,8 +79,8 @@ public abstract class BogeyRenderer {
* @param ms The posestack to render to
*/
@OnlyIn(Dist.CLIENT)
public void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms) {
this.render(bogeyData, wheelAngle, ms, 0, null);
public void render(boolean upsideDown, CompoundTag bogeyData, float wheelAngle, PoseStack ms) {
this.render(upsideDown, bogeyData, wheelAngle, ms, 0, null, true);
}
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 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
*/
public Transform<?> getTransformFromPartial(PartialModel model, PoseStack ms, boolean inContraption) {
public Transform<?> getTransformFromPartial(PartialModel model, PoseStack ms, boolean inInstancedContraption) {
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);
}

View file

@ -1,7 +1,7 @@
package com.simibubi.create.content.logistics.trains;
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 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,
int overlay) {
BlockState blockState = te.getBlockState();
if (te instanceof StandardBogeyTileEntity sbte) {
if (te instanceof AbstractBogeyTileEntity sbte) {
float angle = sbte.getVirtualAngle(partialTicks);
if (blockState.getBlock() instanceof AbstractBogeyBlock bogey)
bogey.render(blockState, angle, ms, partialTicks, buffer, light, overlay, sbte);
if (blockState.getBlock() instanceof AbstractBogeyBlock<?> bogey)
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() {
if (isTrackGraphDebugActive())
for (TrackGraph trackGraph : trackNetworks.values())
TrackGraphVisualizer.debugViewGraph(trackGraph);
TrackGraphVisualizer.debugViewGraph(trackGraph, isTrackGraphDebugExtended());
}
private static boolean isTrackGraphDebugActive() {
return KineticDebugger.isF3DebugModeActive() && AllConfigs.CLIENT.showTrackGraphOnF3.get();
}
private static boolean isTrackGraphDebugExtended() {
return AllConfigs.CLIENT.showExtendedTrackGraphOnF3.get();
}
public GlobalRailwayManager sided(LevelAccessor level) {
if (level != null && !level.isClientSide())
return this;

View file

@ -25,6 +25,7 @@ import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
@ -74,22 +75,42 @@ public interface ITrackBlock {
getTrackAxes(world, pos, state).forEach(axis -> {
addToListIfConnected(connectedTo, list, (d, b) -> axis.scale(b ? d : -d)
.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;
}
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,
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 =
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))
.withDirection(axis);
DiscoveredLocation secondLocation =
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))
.withDirection(axis);

View file

@ -31,10 +31,10 @@ public class StandardBogeyRenderer {
}
@Override
public void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb) {
boolean inContraption = vb == null;
public void render(boolean upsideDown, CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb, boolean inContraption) {
boolean inInstancedContraption = vb == null;
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) {
shafts[i].translate(-.5f, .25f, i * -1)
.centre()
@ -60,20 +60,20 @@ public class StandardBogeyRenderer {
}
@Override
public void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb) {
boolean inContraption = vb == null;
Transform<?> transform = getTransformFromPartial(BOGEY_FRAME, ms, inContraption);
public void render(boolean upsideDown, CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb, boolean inContraption) {
boolean inInstancedContraption = vb == null;
Transform<?> transform = getTransformFromPartial(BOGEY_FRAME, ms, inInstancedContraption);
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) {
if (!inContraption)
if (!inInstancedContraption)
ms.pushPose();
Transform<?> wheel = wheels[(side + 1)/2];
wheel.translate(0, 12 / 16f, side)
.rotateX(wheelAngle);
finalize(wheel, ms, light, vb);
if (!inContraption)
if (!inInstancedContraption)
ms.popPose();
}
}
@ -93,11 +93,11 @@ public class StandardBogeyRenderer {
}
@Override
public void render(CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb) {
boolean inContraption = vb == null;
public void render(boolean upsideDown, CompoundTag bogeyData, float wheelAngle, PoseStack ms, int light, VertexConsumer vb, boolean inContraption) {
boolean inInstancedContraption = vb == null;
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) {
Transform<?> secondShaft = secondaryShafts[i];
@ -108,29 +108,29 @@ public class StandardBogeyRenderer {
finalize(secondShaft, ms, light, vb);
}
Transform<?> bogeyDrive = getTransformFromPartial(BOGEY_DRIVE, ms, inContraption);
Transform<?> bogeyDrive = getTransformFromPartial(BOGEY_DRIVE, ms, inInstancedContraption);
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)));
finalize(bogeyPiston, ms, light, vb);
if (!inContraption)
if (!inInstancedContraption)
ms.pushPose();
Transform<?> bogeyWheels = getTransformFromPartial(LARGE_BOGEY_WHEELS, ms, inContraption)
Transform<?> bogeyWheels = getTransformFromPartial(LARGE_BOGEY_WHEELS, ms, inInstancedContraption)
.translate(0, 1, 0)
.rotateX(wheelAngle);
finalize(bogeyWheels, ms, light, vb);
Transform<?> bogeyPin = getTransformFromPartial(BOGEY_PIN, ms, inContraption)
Transform<?> bogeyPin = getTransformFromPartial(BOGEY_PIN, ms, inInstancedContraption)
.translate(0, 1, 0)
.rotateX(wheelAngle)
.translate(0, 1 / 4f, 0)
.rotateX(-wheelAngle);
finalize(bogeyPin, ms, light, vb);
if (!inContraption)
if (!inInstancedContraption)
ms.popPose();
}
}

View file

@ -22,13 +22,19 @@ public class TrackEdge {
BezierConnection turn;
EdgeData edgeData;
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.edgeData = new EdgeData(this);
this.node1 = node1;
this.node2 = node2;
this.turn = turn;
this.trackMaterial = trackMaterial;
}
public TrackMaterial getTrackMaterial() {
return trackMaterial;
}
public boolean isTurn() {
@ -181,13 +187,15 @@ public class TrackEdge {
public CompoundTag write(DimensionPalette dimensions) {
CompoundTag baseCompound = isTurn() ? turn.write(BlockPos.ZERO) : new CompoundTag();
baseCompound.put("Signals", edgeData.write(dimensions));
baseCompound.putString("Material", getTrackMaterial().id.toString());
return baseCompound;
}
public static TrackEdge read(TrackNode node1, TrackNode node2, CompoundTag tag, TrackGraph graph,
DimensionPalette dimensions) {
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);
return trackEdge;
}

View file

@ -393,14 +393,15 @@ public class TrackGraph {
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) {
TrackNode node1 = nodes.get(location);
TrackNode node2 = nodes.get(location2);
boolean bezier = turn != null;
TrackEdge edge = new TrackEdge(node1, node2, turn);
TrackEdge edge2 = new TrackEdge(node2, node1, bezier ? turn.secondary() : null);
TrackMaterial material = bezier ? turn.getMaterial() : location2.materialA;
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 (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) {
flushGraphPacket(graph);
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++;
}
@ -82,7 +82,7 @@ public class TrackGraphSync {
if (currentGraphSyncPacket.addedNodes.remove(nodeId) == null)
currentGraphSyncPacket.removedNodes.add(nodeId);
currentGraphSyncPacket.addedEdges.removeIf(pair -> {
Couple<Integer> ids = pair.getFirst();
Couple<Integer> ids = pair.getFirst().getFirst();
return ids.getFirst()
.intValue() == nodeId
|| ids.getSecond()
@ -156,7 +156,7 @@ public class TrackGraphSync {
graph.connectionsByNode.get(node)
.forEach((node2, edge) -> {
Couple<Integer> key = Couple.create(node.getNetId(), node2.getNetId());
currentPacket.addedEdges.add(Pair.of(key, edge.getTurn()));
currentPacket.addedEdges.add(Pair.of(Pair.of(key, edge.getTrackMaterial()), edge.getTurn()));
currentPacket.syncEdgeData(node, node2, edge);
});

View file

@ -22,7 +22,7 @@ import net.minecraft.world.phys.Vec3;
public class TrackGraphSyncPacket extends TrackGraphPacket {
Map<Integer, Pair<TrackNodeLocation, Vec3>> addedNodes;
List<Pair<Couple<Integer>, BezierConnection>> addedEdges;
List<Pair<Pair<Couple<Integer>, TrackMaterial>, BezierConnection>> addedEdges;
List<Integer> removedNodes;
List<TrackEdgePoint> addedEdgePoints;
List<UUID> removedEdgePoints;
@ -79,7 +79,7 @@ public class TrackGraphSyncPacket extends TrackGraphPacket {
size = buffer.readVarInt();
for (int i = 0; i < size; i++)
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();
for (int i = 0; i < size; i++)
@ -134,8 +134,9 @@ public class TrackGraphSyncPacket extends TrackGraphPacket {
buffer.writeVarInt(addedEdges.size());
addedEdges.forEach(pair -> {
pair.getFirst()
pair.getFirst().getFirst()
.forEach(buffer::writeVarInt);
buffer.writeUtf(pair.getFirst().getSecond().id.toString());
BezierConnection turn = pair.getSecond();
buffer.writeBoolean(turn != null);
if (turn != null)
@ -192,13 +193,13 @@ public class TrackGraphSyncPacket extends TrackGraphPacket {
graph.loadNode(nodeLocation.getFirst(), nodeId, nodeLocation.getSecond());
}
for (Pair<Couple<Integer>, BezierConnection> pair : addedEdges) {
Couple<TrackNode> nodes = pair.getFirst()
for (Pair<Pair<Couple<Integer>, TrackMaterial>, BezierConnection> pair : addedEdges) {
Couple<TrackNode> nodes = pair.getFirst().getFirst()
.map(graph::getNode);
TrackNode node1 = nodes.getFirst();
TrackNode node2 = nodes.getSecond();
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)
@ -268,4 +269,4 @@ public class TrackGraphSyncPacket extends TrackGraphPacket {
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.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 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();
Entity cameraEntity = mc.cameraEntity;
if (cameraEntity == null)
@ -262,6 +271,13 @@ public class TrackGraphVisualizer {
yOffset = new Vec3(0, (other.hashCode() > hashCode ? 6 : 4) / 16f, 0);
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)
.add(yOffset),
edge.getPosition(1)
@ -273,6 +289,13 @@ public class TrackGraphVisualizer {
Vec3 previous = null;
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++) {
Vec3 current = edge.getPosition(i * 1f / turn.getSegmentCount());
if (previous != null)

View file

@ -24,8 +24,8 @@ public class TrackNodeLocation extends Vec3i {
this(vec.x, vec.y, vec.z);
}
public TrackNodeLocation(double p_121865_, double p_121866_, double p_121867_) {
super(Math.round(p_121865_ * 2), Math.floor(p_121866_ * 2), Math.round(p_121867_ * 2));
public TrackNodeLocation(double x, double y, double z) {
super(Math.round(x * 2), Math.floor(y * 2), Math.round(z * 2));
}
public TrackNodeLocation in(Level level) {
@ -116,9 +116,11 @@ public class TrackNodeLocation extends Vec3i {
boolean forceNode = false;
Vec3 direction;
Vec3 normal;
TrackMaterial materialA;
TrackMaterial materialB;
public DiscoveredLocation(Level level, double p_121865_, double p_121866_, double p_121867_) {
super(p_121865_, p_121866_, p_121867_);
public DiscoveredLocation(Level level, double x, double y, double z) {
super(x, y, z);
in(level);
}
@ -131,6 +133,22 @@ public class TrackNodeLocation extends Vec3i {
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) {
this.turn = turn;
if (turn != null)
@ -165,6 +183,10 @@ public class TrackNodeLocation extends Vec3i {
return forceNode;
}
public boolean differentMaterials() {
return materialA != materialB;
}
public boolean notInLineWith(Vec3 direction) {
return this.direction != null
&& 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;
if (location.shouldForceNode())
return true;
if (location.differentMaterials())
return true;
if (next.stream()
.anyMatch(DiscoveredLocation::shouldForceNode))
return true;
Vec3 direction = location.direction;
if (direction != null && next.stream()
.anyMatch(dl -> dl.notInLineWith(direction)))

View file

@ -11,7 +11,7 @@ public class BackupBogeyRenderer extends BogeyRenderer.CommonRenderer {
public static BackupBogeyRenderer INSTANCE = new BackupBogeyRenderer();
@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 ->
bogeyRenderer.render(bogey.bogeyData, wheelAngle, ms));
renderer.render(bogey.bogeyData, wheelAngle, ms);
bogeyRenderer.render(bogey.isUpsideDown(), bogey.bogeyData, wheelAngle, ms));
renderer.render(bogey.isUpsideDown(), bogey.bogeyData, wheelAngle, ms);
}
public void updateLight(BlockAndTintGetter world, CarriageContraptionEntity entity) {

View file

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

View file

@ -85,6 +85,11 @@ public class Carriage {
bogey2.carriage = this;
}
public boolean isOnIncompatibleTrack() {
return leadingBogey().type.isOnIncompatibleTrack(this, true)
|| trailingBogey().type.isOnIncompatibleTrack(this, false);
}
public void setTrain(Train train) {
this.train = train;
}
@ -306,6 +311,9 @@ public class Carriage {
double leadingWheelSpacing = leadingBogey.type.getWheelPointSpacing();
double trailingWheelSpacing = trailingBogey.type.getWheelPointSpacing();
boolean leadingUpsideDown = leadingBogey.isUpsideDown();
boolean trailingUpsideDown = trailingBogey.isUpsideDown();
for (boolean leading : Iterate.trueAndFalse) {
TravellingPoint point = leading ? getLeadingPoint() : getTrailingPoint();
TravellingPoint otherPoint = !leading ? getLeadingPoint() : getTrailingPoint();
@ -321,24 +329,31 @@ public class Carriage {
dce.positionAnchor = dimension.equals(leadingBogeyDim) ? leadingBogey.getAnchorPosition()
: 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()) {
dce.rotationAnchors.setFirst(dimension.equals(leadingBogeyDim) ? leadingBogey.getAnchorPosition()
: pivoted(dce, dimension, point,
leading ? leadingWheelSpacing / 2 : bogeySpacing + trailingWheelSpacing / 2));
dce.rotationAnchors.setSecond(dimension.equals(trailingBogeyDim) ? trailingBogey.getAnchorPosition()
leading ? leadingWheelSpacing / 2 : bogeySpacing + trailingWheelSpacing / 2,
leadingUpsideDown, trailingUpsideDown));
dce.rotationAnchors.setSecond(dimension.equals(trailingBogeyDim) ? trailingBogey.getAnchorPosition(backAnchorFlip)
: pivoted(dce, dimension, point,
leading ? leadingWheelSpacing / 2 + bogeySpacing : trailingWheelSpacing / 2));
leading ? leadingWheelSpacing / 2 + bogeySpacing : trailingWheelSpacing / 2,
leadingUpsideDown, trailingUpsideDown));
} else {
if (dimension.equals(otherDimension)) {
dce.rotationAnchors = leadingBogey.points.map(TravellingPoint::getPosition);
} else {
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()
: 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,
double offset) {
double offset, boolean leadingUpsideDown, boolean trailingUpsideDown) {
if (train.graph == null)
return dce.pivot == null ? null : dce.pivot.getLocation();
TrackNodeLocation pivot = dce.findPivot(dimension, start == getLeadingPoint());
if (pivot == null)
return null;
Vec3 startVec = start.getPosition();
boolean flipped = start != getLeadingPoint() && (leadingUpsideDown != trailingUpsideDown);
Vec3 startVec = start.getPosition(flipped);
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);
}

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.AbstractBogeyBlock;
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.Couple;
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.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 {
@ -37,7 +37,8 @@ public class CarriageBogey {
public CompoundTag bogeyData;
AbstractBogeyBlock type;
AbstractBogeyBlock<?> type;
boolean upsideDown;
Couple<TravellingPoint> points;
LerpedFloat wheelAngle;
@ -48,11 +49,14 @@ public class CarriageBogey {
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())
bogeyData = this.createBogeyData(); // Prevent Crash When Updating
this.bogeyData = bogeyData;
this.type = type;
this.upsideDown = type.canBeUpsideDown() && upsideDown;
point.upsideDown = this.upsideDown;
point2.upsideDown = this.upsideDown;
points = Couple.create(point, point2);
wheelAngle = LerpedFloat.angular();
yaw = LerpedFloat.angular();
@ -109,11 +113,15 @@ public class CarriageBogey {
}
public TravellingPoint leading() {
return points.getFirst();
TravellingPoint point = points.getFirst();
point.upsideDown = isUpsideDown();
return point;
}
public TravellingPoint trailing() {
return points.getSecond();
TravellingPoint point = points.getSecond();
point.upsideDown = isUpsideDown();
return point;
}
public double getStress() {
@ -127,18 +135,25 @@ public class CarriageBogey {
@Nullable
public Vec3 getAnchorPosition() {
return getAnchorPosition(false);
}
@Nullable
public Vec3 getAnchorPosition(boolean flipUpsideDown) {
if (leading().edge == null)
return null;
return points.getFirst()
.getPosition()
.add(points.getSecond()
.getPosition())
.scale(.5);
.getPosition(flipUpsideDown)
.add(points.getSecond()
.getPosition(flipUpsideDown))
.scale(.5);
}
public void updateCouplingAnchor(Vec3 entityPos, float entityXRot, float entityYRot, int bogeySpacing,
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 = 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, -entityXRot, Axis.X);
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));
}
@ -159,6 +176,7 @@ public class CarriageBogey {
tag.putString("Type", RegisteredObjects.getKeyOrThrow((Block) type)
.toString());
tag.put("Points", points.serializeEach(tp -> tp.write(dimensions)));
tag.putBoolean("UpsideDown", upsideDown);
tag.put(BOGEY_STYLE_KEY, bogeyData);
return tag;
}
@ -166,10 +184,11 @@ public class CarriageBogey {
public static CarriageBogey read(CompoundTag tag, TrackGraph graph, DimensionPalette dimensions) {
ResourceLocation location = new ResourceLocation(tag.getString("Type"));
AbstractBogeyBlock type = (AbstractBogeyBlock) ForgeRegistries.BLOCKS.getValue(location);
boolean upsideDown = tag.getBoolean("UpsideDown");
Couple<TravellingPoint> points = Couple.deserializeEach(tag.getList("Points", Tag.TAG_COMPOUND),
c -> TravellingPoint.read(c, graph, dimensions));
CompoundTag data = tag.getCompound(StandardBogeyTileEntity.BOGEY_DATA_KEY);
return new CarriageBogey(type, data, points.getFirst(), points.getSecond());
CompoundTag data = tag.getCompound(AbstractBogeyTileEntity.BOGEY_DATA_KEY);
return new CarriageBogey(type, upsideDown, data, points.getFirst(), points.getSecond());
}
public BogeyInstance createInstance(MaterialManager materialManager) {
@ -183,11 +202,15 @@ public class CarriageBogey {
private CompoundTag createBogeyData() {
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;
}
void setLeading() {
isLeading = true;
}
public boolean isUpsideDown() {
return type.canBeUpsideDown() && upsideDown;
}
}

View file

@ -162,11 +162,12 @@ public class CarriageContraption extends Contraption {
.getStep(), toLocalPos(pos));
}
if (blockState.getBlock() instanceof AbstractBogeyBlock) {
if (blockState.getBlock() instanceof AbstractBogeyBlock bogey) {
boolean captureTE = bogey.captureTileEntityForTrain();
bogeys++;
if (bogeys == 2)
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)

View file

@ -7,8 +7,6 @@ import com.jozufozu.flywheel.util.transform.TransformStack;
import com.mojang.blaze3d.vertex.PoseStack;
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.MultiBufferSource;
import net.minecraft.client.renderer.culling.Frustum;
@ -68,10 +66,9 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer
translateBogey(ms, bogey, bogeySpacing, viewYRot, viewXRot, 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,
overlay, (StandardBogeyTileEntity) be);
bogey.type.render(null, bogey.isUpsideDown(), bogey.wheelAngle.getValue(partialTicks), ms, partialTicks, buffers, light,
overlay, bogey.getStyle(), bogey.bogeyData);
ms.popPose();
}
@ -85,6 +82,8 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer
public static void translateBogey(PoseStack ms, CarriageBogey bogey, int bogeySpacing, float viewYRot,
float viewXRot, float partialTicks) {
boolean selfUpsideDown = bogey.isUpsideDown();
boolean leadingUpsideDown = bogey.carriage.leadingBogey().isUpsideDown();
TransformStack.cast(ms)
.rotateY(viewYRot + 90)
.rotateX(-viewXRot)
@ -95,7 +94,9 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer
.rotateY(-viewYRot - 90)
.rotateY(bogey.yaw.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) {

View file

@ -82,7 +82,7 @@ public class CarriageCouplingRenderer {
float margin = 3 / 16f;
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);
double stretch = ((anchor2.distanceTo(anchor) - 2 * margin) * 4) / couplingSegments;
for (int j = 0; j < couplingSegments; j++) {

View file

@ -88,7 +88,13 @@ public class CarriageSounds {
double distance2 = toBogey2.length();
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;
double distance = Math.min(distance1, distance2);

View file

@ -14,6 +14,9 @@ import java.util.UUID;
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.MutableObject;
@ -251,7 +254,7 @@ public class Navigation {
return;
}
}
topSpeed *= train.throttle;
double turnTopSpeed = Math.min(topSpeed, train.maxTurnSpeed());
@ -540,6 +543,23 @@ public class Navigation {
if (graph == null)
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<>();
boolean costRelevant = maxCost >= 0;
if (costRelevant) {
@ -579,7 +599,7 @@ public class Navigation {
.get(initialNode2);
if (initialEdge == null)
return;
double distanceToNode2 = forward ? initialEdge.getLength() - startingPoint.position : startingPoint.position;
frontier.add(new FrontierEntry(distanceToNode2, 0, initialNode1, initialNode2, initialEdge));
@ -659,6 +679,8 @@ public class Navigation {
continue;
for (Entry<TrackNode, TrackEdge> target : validTargets) {
if (!validTypes.contains(target.getValue().getTrackMaterial().trackType))
continue;
TrackNode newNode = target.getKey();
TrackEdge newEdge = target.getValue();
double newDistance = newEdge.getLength() + distance;

View file

@ -17,7 +17,7 @@ import java.util.function.Consumer;
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;
@ -317,7 +317,13 @@ public class Train {
if (leadingAnchor == null || trailingAnchor == null)
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++;
}
}
@ -379,7 +385,7 @@ public class Train {
int carriageType = first ? last ? Carriage.BOTH : Carriage.FIRST : last ? Carriage.LAST : Carriage.MIDDLE;
double actualDistance =
carriage.travel(level, graph, distance + totalStress, toFollowForward, toFollowBackward, carriageType);
blocked |= carriage.blocked;
blocked |= carriage.blocked || carriage.isOnIncompatibleTrack();
boolean onTwoBogeys = carriage.isOnTwoBogeys();
maxStress = Math.max(maxStress, onTwoBogeys ? carriage.bogeySpacing - carriage.getAnchorDiff() : 0);
@ -726,14 +732,16 @@ public class Train {
if (entity.getContraption()instanceof CarriageContraption cc)
cc.returnStorageForDisassembly(carriage.storage);
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();
for (CarriageBogey bogey : carriage.bogeys) {
if (bogey == null)
continue;
Vec3 bogeyPosition = bogey.getAnchorPosition();
if (bogeyPosition == null) continue;
BlockEntity be = level.getBlockEntity(new BlockPos(bogeyPosition));
if (!(be instanceof StandardBogeyTileEntity sbte))
if (!(be instanceof AbstractBogeyTileEntity sbte))
continue;
sbte.setBogeyData(bogey.bogeyData);
}
@ -957,7 +965,7 @@ public class Train {
occupiedObservers.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;
MutableObject<UUID> prevGroup = new MutableObject<>(null);

View file

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

View file

@ -115,13 +115,16 @@ public class TrainRelocator {
BlockPos blockPos = blockhit.getBlockPos();
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) {
for (int i = 0; i < toVisualise.size() - 1; i++) {
Vec3 vec1 = toVisualise.get(i);
Vec3 vec2 = toVisualise.get(i + 1);
Vec3 vec1 = toVisualise.get(i).add(offset);
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))
.colored(lastHoveredResult || i != toVisualise.size() - 2 ? 0x95CD41 : 0xEA5C2B)
.disableLineNormals()
.disableNormals()
.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 result = relocate(relocating, mc.level, blockPos, hoveredBezier, direction, lookAngle, true);
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,
direction, lookAngle, relocatingEntityId));
}
@ -182,7 +185,7 @@ public class TrainRelocator {
if (edge == null)
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();
ITurnListener ignoreTurns = probe.ignoreTurns();
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) {
CreateClient.OUTLINER.showLine(Pair.of(train, i), v1.add(0, -.825f, 0), v2.add(0, -.825f, 0))
.colored(valid ? 0x95CD41 : 0xEA5C2B)
.disableLineNormals()
.disableNormals()
.lineWidth(i % 2 == 1 ? 1 / 6f : 1 / 4f);
}

View file

@ -38,6 +38,7 @@ public class TravellingPoint {
public TrackEdge edge;
public double position;
public boolean blocked;
public boolean upsideDown;
public static enum SteerDirection {
NONE(0), LEFT(-1), RIGHT(1);
@ -64,11 +65,12 @@ public class 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.node2 = node2;
this.edge = edge;
this.position = position;
this.upsideDown = upsideDown;
}
public IEdgePointListener ignoreEdgePoints() {
@ -395,14 +397,22 @@ public class TravellingPoint {
}
public Vec3 getPosition() {
return getPositionWithOffset(0);
return getPosition(false);
}
public Vec3 getPosition(boolean flipped) {
return getPositionWithOffset(0, flipped);
}
public Vec3 getPositionWithOffset(double offset) {
return getPositionWithOffset(offset, false);
}
public Vec3 getPositionWithOffset(double offset, boolean flipUpsideDown) {
double t = (position + offset) / edge.getLength();
return edge.getPosition(t)
.add(edge.getNormal(node1, node2, t)
.scale(1));
.add(edge.getNormal(node1, node2, t)
.scale(upsideDown^flipUpsideDown ? -1 : 1));
}
public void migrateTo(List<GraphLocation> locations) {
@ -423,12 +433,13 @@ public class TravellingPoint {
tag.put("Nodes", nodes.map(TrackNode::getLocation)
.serializeEach(loc -> loc.write(dimensions)));
tag.putDouble("Position", position);
tag.putBoolean("UpsideDown", upsideDown);
return tag;
}
public static TravellingPoint read(CompoundTag tag, TrackGraph graph, DimensionPalette dimensions) {
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.deserializeEach(tag.getList("Nodes", Tag.TAG_COMPOUND), c -> TrackNodeLocation.read(c, dimensions))
@ -436,11 +447,11 @@ public class TravellingPoint {
: Couple.create(null, null);
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");
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.schedule.Schedule;
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.block.ProperWaterloggedBlock;
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.entity.player.Player;
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.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
@ -193,7 +192,8 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
Direction assemblyDirection;
int assemblyLength;
int[] bogeyLocations;
AbstractBogeyBlock[] bogeyTypes;
AbstractBogeyBlock<?>[] bogeyTypes;
boolean[] upsideDownBogeys;
int bogeyCount;
@Override
@ -270,28 +270,31 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
return false;
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;
if (!isValidBogeyOffset(bogeyOffset)) {
for (int i = -1; i <= 1; i++) {
BlockPos bogeyPos = pos.relative(assemblyDirection, i)
.offset(up);
BlockState blockState = level.getBlockState(bogeyPos);
if (blockState.getBlock() instanceof AbstractBogeyBlock bogey) {
BlockEntity be = level.getBlockEntity(bogeyPos);
if (!(be instanceof StandardBogeyTileEntity oldTE))
continue;
CompoundTag oldData = oldTE.getBogeyData();
BlockState newBlock = bogey.getNextSize(oldTE);
if (newBlock.getBlock() == bogey)
player.displayClientMessage(Lang.translateDirect("create.bogey.style.no_other_sizes")
.withStyle(ChatFormatting.RED), true);
level.setBlock(bogeyPos, newBlock, 3);
BlockEntity newEntity = level.getBlockEntity(bogeyPos);
if (!(newEntity instanceof StandardBogeyTileEntity newTE))
continue;
newTE.setBogeyData(oldData);
bogey.playRotateSound(level, bogeyPos);
return true;
for (boolean upsideDown : Iterate.falseAndTrue) {
for (int i = -1; i <= 1; i++) {
BlockPos bogeyPos = pos.relative(assemblyDirection, i)
.offset(upsideDown ? down : up);
BlockState blockState = level.getBlockState(bogeyPos);
if (blockState.getBlock() instanceof AbstractBogeyBlock<?> bogey) {
BlockEntity be = level.getBlockEntity(bogeyPos);
if (!(be instanceof AbstractBogeyTileEntity oldTE))
continue;
CompoundTag oldData = oldTE.getBogeyData();
BlockState newBlock = bogey.getNextSize(oldTE);
if (newBlock.getBlock() == bogey)
player.displayClientMessage(Lang.translateDirect("bogey.style.no_other_sizes")
.withStyle(ChatFormatting.RED), true);
level.setBlock(bogeyPos, newBlock, 3);
BlockEntity newEntity = level.getBlockEntity(bogeyPos);
if (!(newEntity instanceof AbstractBogeyTileEntity newTE))
continue;
newTE.setBogeyData(oldData);
bogey.playRotateSound(level, bogeyPos);
return true;
}
}
}
@ -304,7 +307,9 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
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)
.getDestroySpeed(level, targetPos) == -1) {
return false;
@ -312,7 +317,11 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
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);
player.displayClientMessage(Lang.translateDirect("train_assembly.bogey_created"), true);
SoundType soundtype = bogeyAnchor.getBlock()
@ -387,8 +396,11 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
bogeyLocations = new int[maxBogeyCount];
if (bogeyTypes == null)
bogeyTypes = new AbstractBogeyBlock[maxBogeyCount];
if (upsideDownBogeys == null)
upsideDownBogeys = new boolean[maxBogeyCount];
Arrays.fill(bogeyLocations, -1);
Arrays.fill(bogeyTypes, null);
Arrays.fill(upsideDownBogeys, false);
for (int i = 0; i < MAX_LENGTH; i++) {
if (i == MAX_LENGTH - 1) {
@ -401,10 +413,19 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
}
BlockState potentialBogeyState = level.getBlockState(bogeyOffset.offset(currentPos));
if (potentialBogeyState.getBlock() instanceof AbstractBogeyBlock bogey && bogeyIndex < bogeyLocations.length) {
bogeyTypes[bogeyIndex] = bogey;
bogeyLocations[bogeyIndex] = i;
bogeyIndex++;
BlockPos upsideDownBogeyOffset = new BlockPos(bogeyOffset.getX(), bogeyOffset.getY()*-1, bogeyOffset.getZ());
if (bogeyIndex < bogeyLocations.length) {
if (potentialBogeyState.getBlock() instanceof AbstractBogeyBlock<?> bogey && !bogey.isUpsideDown(potentialBogeyState)) {
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);
@ -564,7 +585,7 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
return;
}
points.add(new TravellingPoint(node, secondNode, edge, positionOnEdge));
points.add(new TravellingPoint(node, secondNode, edge, positionOnEdge, false));
}
secondNode = node;
@ -591,10 +612,11 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
spacing.add(bogeyLocations[bogeyIndex] - bogeyLocations[bogeyIndex - 1]);
CarriageContraption contraption = new CarriageContraption(assemblyDirection);
BlockPos bogeyPosOffset = trackPosition.offset(bogeyOffset);
BlockPos upsideDownBogeyPosOffset = trackPosition.offset(new BlockPos(bogeyOffset.getX(), bogeyOffset.getY() * -1, bogeyOffset.getZ()));
try {
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();
contraption.setSoundQueueOffset(offset);
if (!success) {
@ -607,26 +629,27 @@ public class StationTileEntity extends SmartTileEntity implements ITransformable
return;
}
AbstractBogeyBlock typeOfFirstBogey = bogeyTypes[bogeyIndex];
AbstractBogeyBlock<?> typeOfFirstBogey = bogeyTypes[bogeyIndex];
boolean firstBogeyIsUpsideDown = upsideDownBogeys[bogeyIndex];
BlockPos firstBogeyPos = contraption.anchor;
StandardBogeyTileEntity firstBogeyTileEntity = (StandardBogeyTileEntity) level.getBlockEntity(firstBogeyPos);
AbstractBogeyTileEntity firstBogeyTileEntity = (AbstractBogeyTileEntity) level.getBlockEntity(firstBogeyPos);
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;
BlockPos secondBogeyPos = contraption.getSecondBogeyPos();
int bogeySpacing = 0;
if (secondBogeyPos != null) {
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")),
contraptions.size() + 1);
return;
}
StandardBogeyTileEntity secondBogeyTileEntity =
(StandardBogeyTileEntity) level.getBlockEntity(secondBogeyPos);
AbstractBogeyTileEntity secondBogeyTileEntity =
(AbstractBogeyTileEntity) level.getBlockEntity(secondBogeyPos);
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));
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;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllBogeyStyles;
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.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.foundation.block.ITE;
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.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) {
super(props, size);
registerDefaultState(defaultBlockState().setValue(WATERLOGGED, false));
}
@Override
public TrackMaterial.TrackType getTrackType(BogeyStyle style) {
return TrackMaterial.TrackType.STANDARD;
}
@Override
public double getWheelPointSpacing() {
return 2;
@ -40,6 +47,11 @@ public class StandardBogeyBlock extends AbstractBogeyBlock implements ITE<Standa
return new Vec3(0, 7 / 32f, 1);
}
@Override
public BogeyStyle getDefaultStyle() {
return AllBogeyStyles.STANDARD;
}
@Override
public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter level, BlockPos pos,
Player player) {

View file

@ -1,112 +1,19 @@
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 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) {
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
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, 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);
public BogeyStyle getDefaultStyle() {
return AllBogeyStyles.STANDARD;
}
}

View file

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

View file

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

View file

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

View file

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

View file

@ -60,6 +60,7 @@ public class AllCommands {
.then(CameraDistanceCommand.register())
.then(CameraAngleCommand.register())
.then(FlySpeedCommand.register())
//.then(DebugValueCommand.register())
//.then(KillTPSCommand.register())
.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 ConfigFloat mountedZoomMultiplier = f(3, 0, "mountedZoomMultiplier", Comments.mountedZoomMultiplier);
public final ConfigBool showTrackGraphOnF3 = b(false, "showTrackGraphOnF3", Comments.showTrackGraphOnF3);
public final ConfigBool showExtendedTrackGraphOnF3 = b(false, "showExtendedTrackGraphOnF3", Comments.showExtendedTrackGraphOnF3);
@Override
public String getName() {
@ -147,6 +148,7 @@ public class CClient extends ConfigBase {
static String trains = "Railway related settings";
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 showExtendedTrackGraphOnF3 = "Additionally display materials of a Rail Network while f3 debug mode is active";
}
}

View file

@ -80,6 +80,7 @@ public class BuilderTransformers {
.build();
}
@SuppressWarnings("deprecation")
public static <B extends StandardBogeyBlock, P> NonNullUnaryOperator<BlockBuilder<B, P>> bogey() {
return b -> b.initialProperties(SharedProperties::softMetal)
.properties(p -> p.sound(SoundType.NETHERITE_BLOCK))
@ -88,7 +89,7 @@ public class BuilderTransformers {
.blockstate((c, p) -> BlockStateGen.horizontalAxisBlock(c, p, s -> p.models()
.getExistingFile(p.modLoc("block/track/bogey/top"))))
.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) {

View file

@ -398,7 +398,7 @@ public class WorldSectionElement extends AnimatedSceneElement {
aabbOutline.getParams()
.lineWidth(1 / 64f)
.colored(0xefefef)
.disableLineNormals();
.disableNormals();
aabbOutline.render(ms, (SuperRenderTypeBuffer) buffer, pt);
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.structureMovement.bearing.IBearingTileEntity;
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.PonderWorld;
@ -34,7 +34,7 @@ public class AnimateTileEntityInstruction extends TickingInstruction {
public static AnimateTileEntityInstruction bogey(BlockPos location, float totalDelta, int ticks) {
float movedPerTick = 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)),
(w) -> 0f);
}

View file

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

View file

@ -1,18 +1,15 @@
package com.simibubi.create.foundation.utility.outliner;
import java.util.Optional;
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.AllSpecialTextures;
import com.simibubi.create.foundation.render.RenderTypes;
import com.simibubi.create.foundation.render.SuperRenderTypeBuffer;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.RenderType;
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.Vec3;
@ -20,212 +17,85 @@ public class AABBOutline extends Outline {
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) {
setBounds(bb);
this.setBounds(bb);
}
public AABB getBounds() {
return bb;
@Override
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) {
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.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.SuperRenderTypeBuffer;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.client.renderer.RenderType;
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.phys.Vec3;
public class BlockClusterOutline extends Outline {
private final Cluster cluster;
private Cluster cluster;
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 BlockClusterOutline(Iterable<BlockPos> positions) {
public BlockClusterOutline(Iterable<BlockPos> selection) {
cluster = new Cluster();
positions.forEach(cluster::include);
selection.forEach(cluster::include);
}
@Override
public void render(PoseStack ms, SuperRenderTypeBuffer buffer, float pt) {
params.loadColor(colorTemp);
Vector4f color = colorTemp;
int lightmap = params.lightmap;
boolean disableLineNormals = params.disableLineNormals;
cluster.visibleEdges.forEach(edge -> {
Vec3 start = Vec3.atLowerCornerOf(edge.pos);
Direction direction = Direction.get(AxisDirection.POSITIVE, edge.axis);
renderAACuboidLine(ms, buffer, start, Vec3.atLowerCornerOf(edge.pos.relative(direction)));
});
renderFaces(ms, buffer, pt, color, lightmap);
renderEdges(ms, buffer, pt, color, lightmap, disableLineNormals);
}
protected void renderFaces(PoseStack ms, SuperRenderTypeBuffer buffer, float pt, Vector4f color, int lightmap) {
Optional<AllSpecialTextures> optionalFaceTexture = params.faceTexture;
if (!optionalFaceTexture.isPresent())
Optional<AllSpecialTextures> faceTexture = params.faceTexture;
if (!faceTexture.isPresent())
return;
AllSpecialTextures faceTexture = optionalFaceTexture.get();
PoseStack.Pose pose = ms.last();
RenderType renderType = RenderTypes.getOutlineTranslucent(faceTexture.getLocation(), true);
VertexConsumer consumer = buffer.getLateBuffer(renderType);
RenderType translucentType = RenderTypes.getOutlineTranslucent(faceTexture.get()
.getLocation(), true);
VertexConsumer builder = buffer.getLateBuffer(translucentType);
cluster.visibleFaces.forEach((face, axisDirection) -> {
Direction direction = Direction.get(axisDirection, face.axis);
BlockPos pos = face.pos;
if (axisDirection == AxisDirection.POSITIVE)
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) {
float lineWidth = params.getLineWidth();
if (lineWidth == 0)
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);
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();
VertexConsumer consumer = buffer.getBuffer(RenderTypes.getOutlineSolid());
ms.pushPose();
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) {
case DOWN -> {
// 0 1 2 3
pos0.set(0, 0, 1);
pos1.set(0, 0, 0);
pos2.set(1, 0, 0);
pos3.set(1, 0, 1);
normal.set(0, -1, 0);
case DOWN:
putQuad(ms, builder, xyz, Xyz, XyZ, xyZ, face);
break;
case EAST:
putQuad(ms, builder, XYz, XYZ, XyZ, Xyz, face);
break;
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) {
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);
ms.popPose();
}
private static class Cluster {

View file

@ -1,7 +1,6 @@
package com.simibubi.create.foundation.utility.outliner;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Vector4f;
import com.simibubi.create.foundation.render.SuperRenderTypeBuffer;
import net.minecraft.util.Mth;
@ -30,12 +29,7 @@ public class ChasingAABBOutline extends AABBOutline {
@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, interpolateBBs(prevBB, bb, pt), color, lightmap, disableLineNormals);
renderBB(ms, buffer, interpolateBBs(prevBB, bb, 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;
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 net.minecraft.util.Mth;
@ -12,50 +8,33 @@ import net.minecraft.world.phys.Vec3;
public class LineOutline extends Outline {
protected final Vector3f start = new Vector3f();
protected final Vector3f end = new Vector3f();
public LineOutline set(Vector3f start, Vector3f end) {
this.start.load(start);
this.start.load(end);
return this;
}
protected Vec3 start = Vec3.ZERO;
protected Vec3 end = Vec3.ZERO;
public LineOutline set(Vec3 start, Vec3 end) {
this.start.set((float) start.x, (float) start.y, (float) start.z);
this.end.set((float) end.x, (float) end.y, (float) end.z);
this.start = start;
this.end = end;
return this;
}
@Override
public void render(PoseStack ms, SuperRenderTypeBuffer buffer, float pt) {
float width = params.getLineWidth();
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);
renderCuboidLine(ms, buffer, start, end);
}
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) {
this.lockStart = lockStart;
}
@Override
public void tick() {}
public EndChasingLineOutline setProgress(float progress) {
prevProgress = this.progress;
this.progress = progress;
@ -63,24 +42,25 @@ public class LineOutline extends Outline {
}
@Override
protected void renderInner(PoseStack ms, VertexConsumer consumer, float pt, float width, Vector4f color, int lightmap, boolean disableNormals) {
float distanceToTarget = Mth.lerp(pt, prevProgress, progress);
Vector3f end;
if (lockStart) {
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);
public LineOutline set(Vec3 start, Vec3 end) {
if (!end.equals(this.end))
super.set(start, end);
return this;
}
@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.VertexConsumer;
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.foundation.render.RenderTypes;
import com.simibubi.create.foundation.render.SuperRenderTypeBuffer;
import com.simibubi.create.foundation.utility.AngleHelper;
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.texture.OverlayTexture;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.util.Mth;
import net.minecraft.world.phys.Vec3;
public abstract class Outline {
protected final OutlineParams params;
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();
protected OutlineParams params;
protected Matrix3f transformNormals; // TODO: not used?
public Outline() {
params = new OutlineParams();
}
public OutlineParams getParams() {
return params;
}
public abstract void render(PoseStack ms, SuperRenderTypeBuffer buffer, float pt);
public void tick() {}
public void bufferCuboidLine(PoseStack poseStack, VertexConsumer consumer, Vector3f start, Vector3f end, float width, Vector4f color, int lightmap, boolean disableNormals) {
Vector3f diff = this.diffPosTemp;
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 OutlineParams getParams() {
return params;
}
public void bufferCuboidLine(PoseStack.Pose pose, VertexConsumer consumer, Vector3f origin, Direction direction, float length, float width, Vector4f color, int lightmap, boolean disableNormals) {
Vector3f minPos = minPosTemp;
Vector3f maxPos = maxPosTemp;
float halfWidth = width / 2;
minPos.set(origin.x() - halfWidth, origin.y() - halfWidth, origin.z() - halfWidth);
maxPos.set(origin.x() + halfWidth, origin.y() + halfWidth, origin.z() + halfWidth);
switch (direction) {
case DOWN -> {
minPos.add(0, -length, 0);
}
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 renderCuboidLine(PoseStack ms, SuperRenderTypeBuffer buffer, Vec3 start, Vec3 end) {
Vec3 diff = end.subtract(start);
float hAngle = AngleHelper.deg(Mth.atan2(diff.x, diff.z));
float hDistance = (float) diff.multiply(1, 0, 1)
.length();
float vAngle = AngleHelper.deg(Mth.atan2(hDistance, diff.y)) - 90;
ms.pushPose();
TransformStack.cast(ms)
.translate(start)
.rotateY(hAngle).rotateX(vAngle);
renderAACuboidLine(ms, buffer, Vec3.ZERO, new Vec3(0, 0, diff.length()));
ms.popPose();
}
public void bufferCuboid(PoseStack.Pose pose, VertexConsumer consumer, Vector3f minPos, Vector3f maxPos, Vector4f color, int lightmap, boolean disableNormals) {
Vector4f posTransformTemp = this.posTransformTemp;
Vector3f normalTransformTemp = this.normalTransformTemp;
public void renderAACuboidLine(PoseStack ms, SuperRenderTypeBuffer buffer, Vec3 start, Vec3 end) {
float lineWidth = params.getLineWidth();
if (lineWidth == 0)
return;
float minX = minPos.x();
float minY = minPos.y();
float minZ = minPos.z();
float maxX = maxPos.x();
float maxY = maxPos.y();
float maxZ = maxPos.z();
VertexConsumer builder = buffer.getBuffer(RenderTypes.getOutlineSolid());
Matrix4f posMatrix = pose.pose();
posTransformTemp.set(minX, minY, maxZ, 1);
posTransformTemp.transform(posMatrix);
double x0 = posTransformTemp.x();
double y0 = posTransformTemp.y();
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);
Vec3 diff = end.subtract(start);
if (diff.x + diff.y + diff.z < 0) {
Vec3 temp = start;
start = end;
end = temp;
diff = diff.scale(-1);
}
normalTransformTemp.transform(normalMatrix);
float nx0 = normalTransformTemp.x();
float ny0 = normalTransformTemp.y();
float nz0 = normalTransformTemp.z();
consumer.vertex(x0, y0, z0)
.color(r, g, b, a)
.uv(0, 0)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx0, ny0, nz0)
.endVertex();
Vec3 extension = diff.normalize()
.scale(lineWidth / 2);
Vec3 plane = VecHelper.axisAlingedPlaneOf(diff);
Direction face = Direction.getNearest(diff.x, diff.y, diff.z);
Axis axis = face.getAxis();
consumer.vertex(x1, y1, z1)
.color(r, g, b, a)
.uv(0, 1)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx0, ny0, nz0)
.endVertex();
start = start.subtract(extension);
end = end.add(extension);
plane = plane.scale(lineWidth / 2);
consumer.vertex(x2, y2, z2)
.color(r, g, b, a)
.uv(1, 1)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx0, ny0, nz0)
.endVertex();
Vec3 a1 = plane.add(start);
Vec3 b1 = plane.add(end);
plane = VecHelper.rotate(plane, -90, axis);
Vec3 a2 = plane.add(start);
Vec3 b2 = plane.add(end);
plane = VecHelper.rotate(plane, -90, axis);
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)
.color(r, g, b, a)
.uv(1, 0)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx0, ny0, nz0)
.endVertex();
// up
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);
if (params.disableNormals) {
face = Direction.UP;
putQuad(ms, builder, b4, b3, b2, b1, face);
putQuad(ms, builder, a1, a2, a3, a4, face);
putQuad(ms, builder, a1, b1, b2, a2, face);
putQuad(ms, builder, a2, b2, b3, a3, face);
putQuad(ms, builder, a3, b3, b4, a4, face);
putQuad(ms, builder, a4, b4, b1, a1, face);
return;
}
normalTransformTemp.transform(normalMatrix);
float nx2 = normalTransformTemp.x();
float ny2 = normalTransformTemp.y();
float nz2 = normalTransformTemp.z();
consumer.vertex(x7, y7, z7)
.color(r, g, b, a)
.uv(0, 0)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx2, ny2, nz2)
.endVertex();
consumer.vertex(x2, y2, z2)
.color(r, g, b, a)
.uv(0, 1)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx2, ny2, nz2)
.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();
putQuad(ms, builder, b4, b3, b2, b1, face);
putQuad(ms, builder, a1, a2, a3, a4, face.getOpposite());
Vec3 vec = a1.subtract(a4);
face = Direction.getNearest(vec.x, vec.y, vec.z);
putQuad(ms, builder, a1, b1, b2, a2, face);
vec = VecHelper.rotate(vec, -90, axis);
face = Direction.getNearest(vec.x, vec.y, vec.z);
putQuad(ms, builder, a2, b2, b3, a3, face);
vec = VecHelper.rotate(vec, -90, axis);
face = Direction.getNearest(vec.x, vec.y, vec.z);
putQuad(ms, builder, a3, b3, b4, a4, face);
vec = VecHelper.rotate(vec, -90, axis);
face = Direction.getNearest(vec.x, vec.y, vec.z);
putQuad(ms, builder, a4, b4, b1, a1, face);
}
public void bufferQuad(PoseStack.Pose pose, VertexConsumer consumer, Vector3f pos0, Vector3f pos1, Vector3f pos2, Vector3f pos3, Vector4f color, int lightmap, Vector3f normal) {
bufferQuad(pose, consumer, pos0, pos1, pos2, pos3, color, 0, 0, 1, 1, lightmap, normal);
public void putQuad(PoseStack ms, VertexConsumer builder, Vec3 v1, Vec3 v2, Vec3 v3, Vec3 v4,
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) {
Vector4f posTransformTemp = this.posTransformTemp;
Vector3f normalTransformTemp = this.normalTransformTemp;
public void putQuadUV(PoseStack ms, VertexConsumer builder, Vec3 v1, Vec3 v2, Vec3 v3, Vec3 v4, float minU,
float minV, float maxU, float maxV, Direction normal) {
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);
posTransformTemp.transform(posMatrix);
double x0 = posTransformTemp.x();
double y0 = posTransformTemp.y();
double z0 = posTransformTemp.z();
protected void putVertex(PoseStack.Pose pose, VertexConsumer builder, float x, float y, float z, float u, float v, Direction normal) {
Color rgb = params.rgb;
if (transformNormals == null)
transformNormals = pose.normal();
posTransformTemp.set(pos1.x(), pos1.y(), pos1.z(), 1);
posTransformTemp.transform(posMatrix);
double x1 = posTransformTemp.x();
double y1 = posTransformTemp.y();
double z1 = posTransformTemp.z();
int xOffset = 0;
int yOffset = 0;
int zOffset = 0;
posTransformTemp.set(pos2.x(), pos2.y(), pos2.z(), 1);
posTransformTemp.transform(posMatrix);
double x2 = posTransformTemp.x();
double y2 = posTransformTemp.y();
double z2 = posTransformTemp.z();
if (normal != null) {
xOffset = normal.getStepX();
yOffset = normal.getStepY();
zOffset = normal.getStepZ();
}
posTransformTemp.set(pos3.x(), pos3.y(), pos3.z(), 1);
posTransformTemp.transform(posMatrix);
double x3 = posTransformTemp.x();
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)
builder.vertex(pose.pose(), x, y, z)
.color(rgb.getRedAsFloat(), rgb.getGreenAsFloat(), rgb.getBlueAsFloat(), rgb.getAlphaAsFloat() * params.alpha)
.uv(u, v)
.overlayCoords(OverlayTexture.NO_OVERLAY)
.uv2(lightmap)
.normal(nx, ny, nz)
.uv2(params.lightMap)
.normal(pose.normal(), xOffset, yOffset, zOffset)
.endVertex();
consumer.vertex(x1, y1, z1)
.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();
transformNormals = null;
}
public static class OutlineParams {
@ -507,9 +166,9 @@ public abstract class Outline {
protected Direction highlightedFace;
protected boolean fadeLineWidth;
protected boolean disableCull;
protected boolean disableLineNormals;
protected boolean disableNormals;
protected float alpha;
protected int lightmap;
protected int lightMap;
protected Color rgb;
private float lineWidth;
@ -519,7 +178,7 @@ public abstract class Outline {
lineWidth = 1 / 32f;
fadeLineWidth = true;
rgb = Color.WHITE;
lightmap = LightTexture.FULL_BRIGHT;
lightMap = LightTexture.FULL_BRIGHT;
}
// builder
@ -534,8 +193,8 @@ public abstract class Outline {
return this;
}
public OutlineParams lightmap(int light) {
lightmap = light;
public OutlineParams lightMap(int light) {
lightMap = light;
return this;
}
@ -564,8 +223,8 @@ public abstract class Outline {
return this;
}
public OutlineParams disableLineNormals() {
disableLineNormals = true;
public OutlineParams disableNormals() {
disableNormals = true;
return this;
}
@ -584,9 +243,6 @@ public abstract class Outline {
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.util.Mth;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
@ -32,7 +33,7 @@ public class Outliner {
public OutlineParams showLine(Object slot, Vec3 start, Vec3 end) {
if (!outlines.containsKey(slot)) {
LineOutline outline = new LineOutline();
addOutline(slot, outline);
outlines.put(slot, new OutlineEntry(outline));
}
OutlineEntry entry = outlines.get(slot);
entry.ticksTillRemoval = 1;
@ -43,7 +44,7 @@ public class Outliner {
public OutlineParams endChasingLine(Object slot, Vec3 start, Vec3 end, float chasingProgress, boolean lockStart) {
if (!outlines.containsKey(slot)) {
EndChasingLineOutline outline = new EndChasingLineOutline(lockStart);
addOutline(slot, outline);
outlines.put(slot, new OutlineEntry(outline));
}
OutlineEntry entry = outlines.get(slot);
entry.ticksTillRemoval = 1;
@ -75,11 +76,18 @@ public class Outliner {
public OutlineParams showCluster(Object slot, Iterable<BlockPos> selection) {
BlockClusterOutline outline = new BlockClusterOutline(selection);
addOutline(slot, outline);
return outline.getParams();
OutlineEntry entry = new OutlineEntry(outline);
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) {
if (outlines.containsKey(slot))
@ -105,19 +113,17 @@ public class Outliner {
// Utility
private void addOutline(Object slot, Outline outline) {
outlines.put(slot, new OutlineEntry(outline));
}
private void createAABBOutlineIfMissing(Object slot, AABB bb) {
if (!outlines.containsKey(slot) || !(outlines.get(slot).outline instanceof AABBOutline)) {
ChasingAABBOutline outline = new ChasingAABBOutline(bb);
addOutline(slot, outline);
outlines.put(slot, new OutlineEntry(outline));
}
}
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) {
@ -146,7 +152,7 @@ public class Outliner {
params.alpha = 1;
if (entry.isFading()) {
int prevTicks = entry.ticksTillRemoval + 1;
float fadeticks = OutlineEntry.FADE_TICKS;
float fadeticks = OutlineEntry.fadeTicks;
float lastAlpha = prevTicks >= 0 ? 1 : 1 + (prevTicks / fadeticks);
float currentAlpha = 1 + (entry.ticksTillRemoval / fadeticks);
float alpha = Mth.lerp(pt, lastAlpha, currentAlpha);
@ -160,35 +166,33 @@ public class Outliner {
}
public static class OutlineEntry {
public static final int FADE_TICKS = 8;
private final Outline outline;
private int ticksTillRemoval = 1;
static final int fadeTicks = 8;
private Outline outline;
private int ticksTillRemoval;
public OutlineEntry(Outline outline) {
this.outline = outline;
}
public Outline getOutline() {
return outline;
}
public int getTicksTillRemoval() {
return ticksTillRemoval;
}
public boolean isAlive() {
return ticksTillRemoval >= -FADE_TICKS;
}
public boolean isFading() {
return ticksTillRemoval < 0;
ticksTillRemoval = 1;
}
public void tick() {
ticksTillRemoval--;
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_illegal_pickup": "A mystical force is binding this Cart Contraption to the world",
"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"
}