Merge remote-tracking branch 'origin/mc1.18/railways-api' into mc1.18/0.5.1-railways-api
This commit is contained in:
commit
ce6ecad0f2
76 changed files with 2344 additions and 708 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -42,4 +42,5 @@ local.properties
|
|||
# PDT-specific
|
||||
.buildpath
|
||||
|
||||
.DS_Store
|
||||
.DS_Store
|
||||
/libs/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -582,7 +582,7 @@ bf2b0310500213ff853c748c236eb5d01f61658e assets/create/blockstates/yellow_toolbo
|
|||
7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json
|
||||
b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json
|
||||
fcaad84ac4ebdb1e6d9301b77245ce855dbde503 assets/create/lang/en_ud.json
|
||||
fc2c57b8a2e8f364a2e74e8f64cffcb8c74b35f1 assets/create/lang/en_us.json
|
||||
8c536f441c4515d44faf340cefb2c0247b49033a 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
|
||||
|
@ -5316,6 +5316,7 @@ d99d5c67bdffff60789a19bd51a5c5267c75e0a4 data/create/tags/blocks/casing.json
|
|||
bc203f09dd7f48965d146d0bd035fb904cb75e7d data/create/tags/blocks/copycat_allow.json
|
||||
d4a3b66f4b763b9a2dcdea74b7273f0ae85cb335 data/create/tags/blocks/copycat_deny.json
|
||||
73c2c85233075d2854d209b71ff2160308a7919c data/create/tags/blocks/fan_transparent.json
|
||||
ad8fa04f7bbbafd70d0ce158af78a35e899301e2 data/create/tags/blocks/girdable_tracks.json
|
||||
5445d23a146003f0aa8de86643c4315d4afd4ef6 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
|
||||
|
@ -5323,6 +5324,7 @@ d4a3b66f4b763b9a2dcdea74b7273f0ae85cb335 data/create/tags/blocks/copycat_deny.js
|
|||
af314e7ec90377e69387523a4c9af19e0056734e 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
|
||||
|
|
|
@ -1852,6 +1852,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 [------------------------<-",
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"create:track"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"create:track"
|
||||
]
|
||||
}
|
|
@ -851,7 +851,7 @@ public class AllBlockEntityTypes {
|
|||
.renderer(() -> StationRenderer::new)
|
||||
.validBlocks(AllBlocks.TRACK_STATION)
|
||||
.register();
|
||||
|
||||
|
||||
public static final BlockEntityEntry<SlidingDoorBlockEntity> SLIDING_DOOR =
|
||||
REGISTRATE.blockEntity("sliding_door", SlidingDoorBlockEntity::new)
|
||||
.renderer(() -> SlidingDoorRenderer::new)
|
||||
|
@ -859,10 +859,10 @@ public class AllBlockEntityTypes {
|
|||
AllBlocks.BRASS_DOOR, AllBlocks.COPPER_DOOR)
|
||||
.register();
|
||||
|
||||
public static final BlockEntityEntry<CopycatBlockEntity> COPYCAT = REGISTRATE
|
||||
.blockEntity("copycat", CopycatBlockEntity::new)
|
||||
.validBlocks(AllBlocks.COPYCAT_PANEL, AllBlocks.COPYCAT_STEP)
|
||||
.register();
|
||||
public static final BlockEntityEntry<CopycatBlockEntity> COPYCAT =
|
||||
REGISTRATE.blockEntity("copycat", CopycatBlockEntity::new)
|
||||
.validBlocks(AllBlocks.COPYCAT_PANEL, AllBlocks.COPYCAT_STEP)
|
||||
.register();
|
||||
|
||||
public static final BlockEntityEntry<FlapDisplayBlockEntity> FLAP_DISPLAY = REGISTRATE
|
||||
.blockEntity("flap_display", FlapDisplayBlockEntity::new)
|
||||
|
|
|
@ -230,6 +230,9 @@ import com.simibubi.create.content.logistics.block.vault.ItemVaultBlock;
|
|||
import com.simibubi.create.content.logistics.block.vault.ItemVaultCTBehaviour;
|
||||
import com.simibubi.create.content.logistics.block.vault.ItemVaultItem;
|
||||
import com.simibubi.create.content.logistics.item.LecternControllerBlock;
|
||||
import com.simibubi.create.content.logistics.trains.BogeyRenderer;
|
||||
import com.simibubi.create.content.logistics.trains.BogeySizes;
|
||||
import com.simibubi.create.content.logistics.trains.TrackMaterial;
|
||||
import com.simibubi.create.content.logistics.trains.management.display.FlapDisplayBlock;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBlockItem;
|
||||
|
@ -718,7 +721,7 @@ public class AllBlocks {
|
|||
.onRegister(movementBehaviour(new BlazeBurnerMovementBehaviour()))
|
||||
.onRegister(interactionBehaviour(new BlazeBurnerInteractionBehaviour()))
|
||||
.item(BlazeBurnerBlockItem::withBlaze)
|
||||
.model(AssetLookup.<BlazeBurnerBlockItem>customBlockItemModel("blaze_burner", "block_with_blaze"))
|
||||
.model(AssetLookup.customBlockItemModel("blaze_burner", "block_with_blaze"))
|
||||
.build()
|
||||
.register();
|
||||
|
||||
|
@ -938,7 +941,7 @@ public class AllBlocks {
|
|||
.onRegister(assignDataBehaviour(new BoilerDisplaySource(), "boiler_status"))
|
||||
.addLayer(() -> RenderType::cutoutMipped)
|
||||
.item(FluidTankItem::new)
|
||||
.model(AssetLookup.<FluidTankItem>customBlockItemModel("_", "block_single_window"))
|
||||
.model(AssetLookup.customBlockItemModel("_", "block_single_window"))
|
||||
.build()
|
||||
.register();
|
||||
|
||||
|
@ -1541,7 +1544,7 @@ public class AllBlocks {
|
|||
.transform(customItemModel())
|
||||
.register();
|
||||
|
||||
public static final BlockEntry<TrackBlock> TRACK = REGISTRATE.block("track", TrackBlock::new)
|
||||
public static final BlockEntry<TrackBlock> TRACK = REGISTRATE.block("track", TrackMaterial.ANDESITE::createBlock)
|
||||
.initialProperties(Material.STONE)
|
||||
.properties(p -> p.color(MaterialColor.METAL)
|
||||
.strength(0.8F)
|
||||
|
@ -1552,6 +1555,8 @@ public class AllBlocks {
|
|||
.onRegister(CreateRegistrate.blockModel(() -> TrackModel::new))
|
||||
.blockstate(new TrackBlockStateGenerator()::generate)
|
||||
.tag(AllBlockTags.RELOCATION_NOT_SUPPORTED.tag)
|
||||
.tag(AllBlockTags.TRACKS.tag)
|
||||
.tag(AllBlockTags.GIRDABLE_TRACKS.tag)
|
||||
.lang("Train Track")
|
||||
.item(TrackBlockItem::new)
|
||||
.model((c, p) -> p.generated(c, Create.asResource("item/" + c.getName())))
|
||||
|
@ -1620,13 +1625,13 @@ public class AllBlocks {
|
|||
.register();
|
||||
|
||||
public static final BlockEntry<StandardBogeyBlock> SMALL_BOGEY =
|
||||
REGISTRATE.block("small_bogey", p -> new StandardBogeyBlock(p, false))
|
||||
REGISTRATE.block("small_bogey", p -> new StandardBogeyBlock(p, BogeySizes.SMALL))
|
||||
.properties(p -> p.color(MaterialColor.PODZOL))
|
||||
.transform(BuilderTransformers.bogey())
|
||||
.register();
|
||||
|
||||
public static final BlockEntry<StandardBogeyBlock> LARGE_BOGEY =
|
||||
REGISTRATE.block("large_bogey", p -> new StandardBogeyBlock(p, true))
|
||||
REGISTRATE.block("large_bogey", p -> new StandardBogeyBlock(p, BogeySizes.LARGE))
|
||||
.properties(p -> p.color(MaterialColor.PODZOL))
|
||||
.transform(BuilderTransformers.bogey())
|
||||
.register();
|
||||
|
|
122
src/main/java/com/simibubi/create/AllBogeyStyles.java
Normal file
122
src/main/java/com/simibubi/create/AllBogeyStyles.java
Normal file
|
@ -0,0 +1,122 @@
|
|||
package com.simibubi.create;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
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;
|
||||
import com.simibubi.create.content.logistics.trains.BogeySizes;
|
||||
import com.simibubi.create.content.logistics.trains.StandardBogeyRenderer.CommonStandardBogeyRenderer;
|
||||
import com.simibubi.create.content.logistics.trains.StandardBogeyRenderer.LargeStandardBogeyRenderer;
|
||||
import com.simibubi.create.content.logistics.trains.StandardBogeyRenderer.SmallStandardBogeyRenderer;
|
||||
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;
|
||||
|
||||
import net.minecraft.core.particles.ParticleOptions;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class AllBogeyStyles {
|
||||
public static final Map<ResourceLocation, BogeyStyle> BOGEY_STYLES = new HashMap<>();
|
||||
public static final Map<ResourceLocation, Map<ResourceLocation, BogeyStyle>> CYCLE_GROUPS = new HashMap<>();
|
||||
private static final Map<ResourceLocation, BogeyStyle> EMPTY_GROUP = ImmutableMap.of();
|
||||
|
||||
public static Map<ResourceLocation, BogeyStyle> getCycleGroup(ResourceLocation cycleGroup) {
|
||||
return CYCLE_GROUPS.getOrDefault(cycleGroup, EMPTY_GROUP);
|
||||
}
|
||||
|
||||
public static final String STANDARD_CYCLE_GROUP = "standard";
|
||||
|
||||
public static final BogeyStyle STANDARD =
|
||||
create("standard", STANDARD_CYCLE_GROUP).commonRenderer(CommonStandardBogeyRenderer::new)
|
||||
.displayName(Components.translatable("create.bogey.style.standard"))
|
||||
.size(BogeySizes.SMALL, SmallStandardBogeyRenderer::new, AllBlocks.SMALL_BOGEY)
|
||||
.size(BogeySizes.LARGE, LargeStandardBogeyRenderer::new, AllBlocks.LARGE_BOGEY)
|
||||
.build();
|
||||
|
||||
private static BogeyStyleBuilder create(String name, String cycleGroup) {
|
||||
return create(Create.asResource(name), Create.asResource(cycleGroup));
|
||||
}
|
||||
|
||||
public static BogeyStyleBuilder create(ResourceLocation name, ResourceLocation cycleGroup) {
|
||||
return new BogeyStyleBuilder(name, cycleGroup);
|
||||
}
|
||||
|
||||
public static void register() {}
|
||||
|
||||
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("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, ResourceLocation cycleGroup) {
|
||||
this.name = name;
|
||||
this.cycleGroup = cycleGroup;
|
||||
}
|
||||
|
||||
public BogeyStyleBuilder displayName(Component displayName) {
|
||||
this.displayName = displayName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BogeyStyleBuilder soundType(ResourceLocation soundType) {
|
||||
this.soundType = soundType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BogeyStyleBuilder defaultData(CompoundTag defaultData) {
|
||||
this.defaultData = defaultData;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BogeyStyleBuilder size(BogeySizes.BogeySize size, Supplier<? extends BogeyRenderer> renderer,
|
||||
BlockEntry<? extends AbstractBogeyBlock<?>> blockEntry) {
|
||||
this.size(size, renderer, blockEntry.getId());
|
||||
return this;
|
||||
}
|
||||
|
||||
public BogeyStyleBuilder size(BogeySizes.BogeySize size, Supplier<? extends BogeyRenderer> renderer,
|
||||
ResourceLocation location) {
|
||||
this.sizes.put(size, new BogeyStyle.SizeData(location, renderer, renderer.get()));
|
||||
return this;
|
||||
}
|
||||
|
||||
public BogeyStyleBuilder contactParticle(ParticleOptions contactParticle) {
|
||||
this.contactParticle = contactParticle;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BogeyStyleBuilder smokeParticle(ParticleOptions smokeParticle) {
|
||||
this.smokeParticle = smokeParticle;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BogeyStyleBuilder commonRenderer(Supplier<? extends CommonRenderer> commonRenderer) {
|
||||
this.commonRenderer = Optional.of(commonRenderer);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BogeyStyle build() {
|
||||
BogeyStyle entry =
|
||||
new BogeyStyle(name, cycleGroup, displayName, soundType, contactParticle, smokeParticle, defaultData, sizes, commonRenderer);
|
||||
BOGEY_STYLES.put(name, entry);
|
||||
CYCLE_GROUPS.computeIfAbsent(cycleGroup, l -> new HashMap<>()).put(name, entry);
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -81,6 +81,8 @@ public class AllTags {
|
|||
SAFE_NBT,
|
||||
SEATS,
|
||||
TOOLBOXES,
|
||||
TRACKS,
|
||||
GIRDABLE_TRACKS,
|
||||
TREE_ATTACHMENTS,
|
||||
VALVE_HANDLES,
|
||||
WINDMILL_SAILS,
|
||||
|
@ -132,6 +134,10 @@ public class AllTags {
|
|||
.is(tag);
|
||||
}
|
||||
|
||||
public boolean matches(ItemStack stack) {
|
||||
return stack != null && stack.getItem() instanceof BlockItem blockItem && matches(blockItem.getBlock());
|
||||
}
|
||||
|
||||
public boolean matches(BlockState state) {
|
||||
return state.is(tag);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ package com.simibubi.create;
|
|||
|
||||
import java.util.Random;
|
||||
|
||||
import com.simibubi.create.content.logistics.trains.BogeySizes;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
@ -127,6 +129,8 @@ public class Create {
|
|||
AllFeatures.register(modEventBus);
|
||||
AllPlacementModifiers.register(modEventBus);
|
||||
BuiltinRegistration.register(modEventBus);
|
||||
BogeySizes.init();
|
||||
AllBogeyStyles.register();
|
||||
|
||||
AllConfigs.register(modLoadingContext);
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import javax.annotation.Nullable;
|
|||
|
||||
import com.jozufozu.flywheel.api.MaterialManager;
|
||||
import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllTags;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.render.ActorInstance;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionMatrices;
|
||||
|
@ -62,7 +62,7 @@ public class DrillMovementBehaviour extends BlockBreakingMovementBehaviour {
|
|||
@Override
|
||||
public boolean canBreak(Level world, BlockPos breakingPos, BlockState state) {
|
||||
return super.canBreak(world, breakingPos, state) && !state.getCollisionShape(world, breakingPos)
|
||||
.isEmpty() && !AllBlocks.TRACK.has(state);
|
||||
.isEmpty() && !AllTags.AllBlockTags.TRACKS.matches(state);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@ package com.simibubi.create.content.contraptions.components.press;
|
|||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllRecipeTypes;
|
||||
import com.simibubi.create.AllTags;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.contraptions.components.crafter.MechanicalCraftingRecipe;
|
||||
import com.simibubi.create.content.contraptions.components.press.PressingBehaviour.Mode;
|
||||
|
@ -69,7 +69,7 @@ public class MechanicalPressBlockEntity extends BasinOperatingBlockEntity implem
|
|||
|
||||
public void onItemPressed(ItemStack result) {
|
||||
award(AllAdvancements.PRESS);
|
||||
if (AllBlocks.TRACK.isIn(result))
|
||||
if (AllTags.AllBlockTags.TRACKS.matches(result))
|
||||
tracksCreated += result.getCount();
|
||||
if (tracksCreated >= 1000) {
|
||||
award(AllAdvancements.TRACK_CRAFTING);
|
||||
|
|
|
@ -29,7 +29,7 @@ import com.simibubi.create.content.contraptions.fluids.tank.FluidTankBlock;
|
|||
import com.simibubi.create.content.curiosities.deco.SlidingDoorBlock;
|
||||
import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkBlock;
|
||||
import com.simibubi.create.content.logistics.block.vault.ItemVaultBlock;
|
||||
import com.simibubi.create.content.logistics.trains.IBogeyBlock;
|
||||
import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock;
|
||||
import com.simibubi.create.content.logistics.trains.ITrackBlock;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationBlock;
|
||||
import com.simibubi.create.foundation.config.ContraptionMovementSetting;
|
||||
|
@ -338,7 +338,7 @@ public class BlockMovementChecks {
|
|||
return direction == state.getValue(StickerBlock.FACING)
|
||||
&& !isNotSupportive(world.getBlockState(pos.relative(direction)), direction.getOpposite());
|
||||
}
|
||||
if (block instanceof IBogeyBlock bogey)
|
||||
if (block instanceof AbstractBogeyBlock bogey)
|
||||
return bogey.getStickySurfaces(world, pos, state)
|
||||
.contains(direction);
|
||||
if (block instanceof WhistleBlock)
|
||||
|
|
|
@ -64,7 +64,7 @@ import com.simibubi.create.content.curiosities.deco.SlidingDoorBlock;
|
|||
import com.simibubi.create.content.logistics.block.inventories.CreativeCrateBlockEntity;
|
||||
import com.simibubi.create.content.logistics.block.redstone.RedstoneContactBlock;
|
||||
import com.simibubi.create.content.logistics.block.vault.ItemVaultBlockEntity;
|
||||
import com.simibubi.create.content.logistics.trains.IBogeyBlock;
|
||||
import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock;
|
||||
import com.simibubi.create.foundation.blockEntity.IMultiBlockEntityContainer;
|
||||
import com.simibubi.create.foundation.blockEntity.behaviour.filtering.FilteringBehaviour;
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
|
@ -347,7 +347,7 @@ public abstract class Contraption {
|
|||
}
|
||||
|
||||
// Bogeys tend to have sticky sides
|
||||
if (state.getBlock()instanceof IBogeyBlock 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));
|
||||
|
|
|
@ -8,6 +8,7 @@ import java.util.Random;
|
|||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.AllShapes;
|
||||
import com.simibubi.create.AllTags;
|
||||
import com.simibubi.create.content.contraptions.base.KineticBlockEntity;
|
||||
import com.simibubi.create.content.contraptions.fluids.pipes.BracketBlock;
|
||||
import com.simibubi.create.content.contraptions.relays.elementary.BracketedBlockEntityBehaviour;
|
||||
|
@ -224,7 +225,7 @@ public class GirderBlock extends Block implements SimpleWaterloggedBlock, IWrenc
|
|||
for (Direction d2 : Iterate.directionsInAxis(axis == Axis.X ? Axis.Z : Axis.X)) {
|
||||
BlockState above = level.getBlockState(pos.above()
|
||||
.relative(d2));
|
||||
if (AllBlocks.TRACK.has(above)) {
|
||||
if (AllTags.AllBlockTags.GIRDABLE_TRACKS.matches(above)) {
|
||||
TrackShape shape = above.getValue(TrackBlock.SHAPE);
|
||||
if (shape == (axis == Axis.X ? TrackShape.XO : TrackShape.ZO))
|
||||
state = state.setValue(updateProperty, true);
|
||||
|
|
|
@ -9,7 +9,6 @@ import java.util.Optional;
|
|||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.content.curiosities.tools.BlueprintEntity.BlueprintCraftingInventory;
|
||||
import com.simibubi.create.content.curiosities.tools.BlueprintEntity.BlueprintSection;
|
||||
|
@ -106,7 +105,7 @@ public class BlueprintOverlayRenderer {
|
|||
|
||||
int tracks = info.requiredTracks;
|
||||
while (tracks > 0) {
|
||||
ingredients.add(Pair.of(AllBlocks.TRACK.asStack(Math.min(64, tracks)), info.hasRequiredTracks));
|
||||
ingredients.add(Pair.of(new ItemStack(info.trackMaterial.getTrackBlock().get(), Math.min(64, tracks)), info.hasRequiredTracks));
|
||||
tracks -= 64;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,361 @@
|
|||
package com.simibubi.create.content.logistics.trains;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
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;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
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.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;
|
||||
import com.simibubi.create.foundation.block.ProperWaterloggedBlock;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
import com.simibubi.create.foundation.utility.RegisteredObjects;
|
||||
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Rotation;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
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;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
public AbstractBogeyBlock(Properties pProperties, BogeySizes.BogeySize size) {
|
||||
super(pProperties);
|
||||
registerDefaultState(defaultBlockState().setValue(WATERLOGGED, false));
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
||||
builder.add(AXIS, WATERLOGGED);
|
||||
super.createBlockStateDefinition(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState updateShape(BlockState pState, Direction pDirection, BlockState pNeighborState,
|
||||
LevelAccessor pLevel, BlockPos pCurrentPos, BlockPos pNeighborPos) {
|
||||
updateWater(pLevel, pState, pCurrentPos);
|
||||
return pState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidState getFluidState(BlockState pState) {
|
||||
return fluidState(pState);
|
||||
}
|
||||
|
||||
static final EnumSet<Direction> STICKY_X = EnumSet.of(Direction.EAST, Direction.WEST);
|
||||
static final EnumSet<Direction> STICKY_Z = EnumSet.of(Direction.SOUTH, Direction.NORTH);
|
||||
|
||||
public EnumSet<Direction> getStickySurfaces(BlockGetter world, BlockPos pos, BlockState state) {
|
||||
return state.getValue(BlockStateProperties.HORIZONTAL_AXIS) == Direction.Axis.X ? STICKY_X : STICKY_Z;
|
||||
}
|
||||
|
||||
public abstract double getWheelPointSpacing();
|
||||
|
||||
public abstract double getWheelRadius();
|
||||
|
||||
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, BogeyStyle style, CompoundTag bogeyData) {
|
||||
if (style == null)
|
||||
style = getDefaultStyle();
|
||||
|
||||
final Optional<BogeyRenderer.CommonRenderer> commonRenderer
|
||||
= style.getInWorldCommonRenderInstance();
|
||||
final BogeyRenderer renderer = style.getInWorldRenderInstance(this.getSize());
|
||||
if (state != null) {
|
||||
ms.translate(.5f, .5f, .5f);
|
||||
if (state.getValue(AXIS) == Direction.Axis.X)
|
||||
ms.mulPose(Vector3f.YP.rotationDegrees(90));
|
||||
}
|
||||
ms.translate(0, -1.5 - 1 / 128f, 0);
|
||||
VertexConsumer vb = buffers.getBuffer(RenderType.cutoutMipped());
|
||||
if (bogeyData == null)
|
||||
bogeyData = new CompoundTag();
|
||||
renderer.render(bogeyData, wheelAngle, ms, light, vb, state == null);
|
||||
CompoundTag finalBogeyData = bogeyData;
|
||||
commonRenderer.ifPresent(common ->
|
||||
common.render(finalBogeyData, wheelAngle, ms, light, vb, state == null));
|
||||
}
|
||||
|
||||
public BogeySizes.BogeySize getSize() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
public Direction getBogeyUpDirection() {
|
||||
return Direction.UP;
|
||||
}
|
||||
|
||||
public boolean isTrackAxisAlongFirstCoordinate(BlockState state) {
|
||||
return state.getValue(AXIS) == Direction.Axis.X;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public BlockState getMatchingBogey(Direction upDirection, boolean axisAlongFirst) {
|
||||
if (upDirection != Direction.UP)
|
||||
return null;
|
||||
return defaultBlockState().setValue(AXIS, axisAlongFirst ? Direction.Axis.X : Direction.Axis.Z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand,
|
||||
BlockHitResult hit) {
|
||||
if (level.isClientSide)
|
||||
return InteractionResult.PASS;
|
||||
ItemStack stack = player.getItemInHand(hand);
|
||||
|
||||
if (!player.isShiftKeyDown() && stack.is(AllItems.WRENCH.get()) && !player.getCooldowns().isOnCooldown(stack.getItem())
|
||||
&& AllBogeyStyles.BOGEY_STYLES.size() > 1) {
|
||||
|
||||
BlockEntity be = level.getBlockEntity(pos);
|
||||
|
||||
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++) {
|
||||
if (validSizes.contains(size)) break;
|
||||
size = size.increment();
|
||||
}
|
||||
|
||||
sbte.setBogeyStyle(style);
|
||||
|
||||
CompoundTag defaultData = style.defaultData;
|
||||
sbte.setBogeyData(sbte.getBogeyData().merge(defaultData));
|
||||
|
||||
if (size == getSize()) {
|
||||
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 AbstractBogeyTileEntity newTileEntity))
|
||||
return InteractionResult.FAIL;
|
||||
newTileEntity.setBogeyData(oldData);
|
||||
player.displayClientMessage(Lang.translateDirect("bogey.style.updated_style_and_size")
|
||||
.append(": ").append(style.displayName), true);
|
||||
}
|
||||
|
||||
return InteractionResult.CONSUME;
|
||||
}
|
||||
|
||||
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();
|
||||
List<ResourceLocation> bogeyCycle = getBogeyBlockCycle();
|
||||
int indexOf = bogeyCycle.indexOf(RegisteredObjects.getKeyOrThrow(block));
|
||||
if (indexOf == -1)
|
||||
return state;
|
||||
int index = (indexOf + 1) % bogeyCycle.size();
|
||||
Direction bogeyUpDirection = getBogeyUpDirection();
|
||||
boolean trackAxisAlongFirstCoordinate = isTrackAxisAlongFirstCoordinate(state);
|
||||
|
||||
while (index != indexOf) {
|
||||
ResourceLocation id = bogeyCycle.get(index);
|
||||
Block newBlock = ForgeRegistries.BLOCKS.getValue(id);
|
||||
if (newBlock instanceof AbstractBogeyBlock<?> bogey) {
|
||||
BlockState matchingBogey = bogey.getMatchingBogey(bogeyUpDirection, trackAxisAlongFirstCoordinate);
|
||||
if (matchingBogey != null)
|
||||
return copyProperties(state, matchingBogey);
|
||||
}
|
||||
index = (index + 1) % bogeyCycle.size();
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
public BlockState getNextSize(Level level, BlockPos pos) {
|
||||
BlockEntity te = level.getBlockEntity(pos);
|
||||
if (te instanceof AbstractBogeyTileEntity sbte)
|
||||
return this.getNextSize(sbte);
|
||||
return level.getBlockState(pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
nextBlock = copyProperties(sbte.getBlockState(), nextBlock);
|
||||
return nextBlock;
|
||||
}
|
||||
|
||||
public BlockState getStateOfSize(AbstractBogeyTileEntity sbte, BogeySizes.BogeySize size) {
|
||||
BogeyStyle style = sbte.getStyle();
|
||||
BlockState state = style.getBlockOfSize(size).defaultBlockState();
|
||||
return copyProperties(sbte.getBlockState(), state);
|
||||
}
|
||||
|
||||
public BogeyStyle getNextStyle(Level level, BlockPos pos) {
|
||||
BlockEntity te = level.getBlockEntity(pos);
|
||||
if (te instanceof AbstractBogeyTileEntity sbte)
|
||||
return this.getNextStyle(sbte.getStyle());
|
||||
return getDefaultStyle();
|
||||
}
|
||||
|
||||
public BogeyStyle getNextStyle(BogeyStyle style) {
|
||||
Collection<BogeyStyle> allStyles = style.getCycleGroup().values();
|
||||
if (allStyles.size() <= 1)
|
||||
return style;
|
||||
List<BogeyStyle> list = new ArrayList<>(allStyles);
|
||||
return Iterate.cycleValue(list, style);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public @NotNull BlockState rotate(@NotNull BlockState pState, Rotation pRotation) {
|
||||
return switch (pRotation) {
|
||||
case COUNTERCLOCKWISE_90, CLOCKWISE_90 -> pState.cycle(AXIS);
|
||||
default -> pState;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@ import net.minecraft.util.Mth;
|
|||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.GameRules;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
|
@ -42,6 +43,7 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
public Couple<Integer> smoothing;
|
||||
public boolean primary;
|
||||
public boolean hasGirder;
|
||||
protected TrackMaterial trackMaterial;
|
||||
|
||||
// runtime
|
||||
|
||||
|
@ -58,19 +60,20 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
private AABB bounds;
|
||||
|
||||
public BezierConnection(Couple<BlockPos> positions, Couple<Vec3> starts, Couple<Vec3> axes, Couple<Vec3> normals,
|
||||
boolean primary, boolean girder) {
|
||||
boolean primary, boolean girder, TrackMaterial material) {
|
||||
tePositions = positions;
|
||||
this.starts = starts;
|
||||
this.axes = axes;
|
||||
this.normals = normals;
|
||||
this.primary = primary;
|
||||
this.hasGirder = girder;
|
||||
this.trackMaterial = material;
|
||||
resolved = false;
|
||||
}
|
||||
|
||||
public BezierConnection secondary() {
|
||||
BezierConnection bezierConnection =
|
||||
new BezierConnection(tePositions.swap(), starts.swap(), axes.swap(), normals.swap(), !primary, hasGirder);
|
||||
BezierConnection bezierConnection = new BezierConnection(tePositions.swap(), starts.swap(), axes.swap(),
|
||||
normals.swap(), !primary, hasGirder, trackMaterial);
|
||||
if (smoothing != null)
|
||||
bezierConnection.smoothing = smoothing.swap();
|
||||
return bezierConnection;
|
||||
|
@ -80,6 +83,26 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
return secondary().secondary();
|
||||
}
|
||||
|
||||
private static boolean coupleEquals(Couple<?> a, Couple<?> b) {
|
||||
return (a.getFirst()
|
||||
.equals(b.getFirst())
|
||||
&& a.getSecond()
|
||||
.equals(b.getSecond()))
|
||||
|| (a.getFirst() instanceof Vec3 aFirst && a.getSecond() instanceof Vec3 aSecond
|
||||
&& b.getFirst() instanceof Vec3 bFirst && b.getSecond() instanceof Vec3 bSecond
|
||||
&& aFirst.closerThan(bFirst, 1e-6) && aSecond.closerThan(bSecond, 1e-6));
|
||||
}
|
||||
|
||||
public boolean equalsSansMaterial(BezierConnection other) {
|
||||
return equalsSansMaterialInner(other) || equalsSansMaterialInner(other.secondary());
|
||||
}
|
||||
|
||||
private boolean equalsSansMaterialInner(BezierConnection other) {
|
||||
return this == other || (other != null && coupleEquals(this.tePositions, other.tePositions)
|
||||
&& coupleEquals(this.starts, other.starts) && coupleEquals(this.axes, other.axes)
|
||||
&& coupleEquals(this.normals, other.normals) && this.hasGirder == other.hasGirder);
|
||||
}
|
||||
|
||||
public BezierConnection(CompoundTag compound, BlockPos localTo) {
|
||||
this(Couple.deserializeEach(compound.getList("Positions", Tag.TAG_COMPOUND), NbtUtils::readBlockPos)
|
||||
.map(b -> b.offset(localTo)),
|
||||
|
@ -87,7 +110,7 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
.map(v -> v.add(Vec3.atLowerCornerOf(localTo))),
|
||||
Couple.deserializeEach(compound.getList("Axes", Tag.TAG_COMPOUND), VecHelper::readNBTCompound),
|
||||
Couple.deserializeEach(compound.getList("Normals", Tag.TAG_COMPOUND), VecHelper::readNBTCompound),
|
||||
compound.getBoolean("Primary"), compound.getBoolean("Girder"));
|
||||
compound.getBoolean("Primary"), compound.getBoolean("Girder"), TrackMaterial.deserialize(compound.getString("Material")));
|
||||
|
||||
if (compound.contains("Smoothing"))
|
||||
smoothing =
|
||||
|
@ -105,6 +128,7 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
compound.put("Starts", starts.serializeEach(VecHelper::writeNBTCompound));
|
||||
compound.put("Axes", axes.serializeEach(VecHelper::writeNBTCompound));
|
||||
compound.put("Normals", normals.serializeEach(VecHelper::writeNBTCompound));
|
||||
compound.putString("Material", getMaterial().id.toString());
|
||||
|
||||
if (smoothing != null)
|
||||
compound.put("Smoothing", smoothing.serializeEach(NBTHelper::intToCompound));
|
||||
|
@ -115,7 +139,7 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
public BezierConnection(FriendlyByteBuf buffer) {
|
||||
this(Couple.create(buffer::readBlockPos), Couple.create(() -> VecHelper.read(buffer)),
|
||||
Couple.create(() -> VecHelper.read(buffer)), Couple.create(() -> VecHelper.read(buffer)),
|
||||
buffer.readBoolean(), buffer.readBoolean());
|
||||
buffer.readBoolean(), buffer.readBoolean(), TrackMaterial.deserialize(buffer.readUtf()));
|
||||
if (buffer.readBoolean())
|
||||
smoothing = Couple.create(buffer::readVarInt);
|
||||
}
|
||||
|
@ -127,6 +151,7 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
normals.forEach(v -> VecHelper.write(v, buffer));
|
||||
buffer.writeBoolean(primary);
|
||||
buffer.writeBoolean(hasGirder);
|
||||
buffer.writeUtf(getMaterial().id.toString());
|
||||
buffer.writeBoolean(smoothing != null);
|
||||
if (smoothing != null)
|
||||
smoothing.forEach(buffer::writeVarInt);
|
||||
|
@ -333,7 +358,7 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
Inventory inv = player.getInventory();
|
||||
int tracks = getTrackItemCost();
|
||||
while (tracks > 0) {
|
||||
inv.placeItemBackInInventory(AllBlocks.TRACK.asStack(Math.min(64, tracks)));
|
||||
inv.placeItemBackInInventory(new ItemStack(getMaterial().getTrackBlock().get(), Math.min(64, tracks)));
|
||||
tracks -= 64;
|
||||
}
|
||||
int girders = getGirderItemCost();
|
||||
|
@ -361,7 +386,7 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
continue;
|
||||
Vec3 v = VecHelper.offsetRandomly(segment.position, level.random, .125f)
|
||||
.add(origin);
|
||||
ItemEntity entity = new ItemEntity(level, v.x, v.y, v.z, AllBlocks.TRACK.asStack());
|
||||
ItemEntity entity = new ItemEntity(level, v.x, v.y, v.z, new ItemStack(getMaterial().getTrackBlock().get()));
|
||||
entity.setDefaultPickUpDelay();
|
||||
level.addFreshEntity(entity);
|
||||
if (!hasGirder)
|
||||
|
@ -375,7 +400,7 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
}
|
||||
|
||||
public void spawnDestroyParticles(Level level) {
|
||||
BlockParticleOption data = new BlockParticleOption(ParticleTypes.BLOCK, AllBlocks.TRACK.getDefaultState());
|
||||
BlockParticleOption data = new BlockParticleOption(ParticleTypes.BLOCK, getMaterial().getTrackBlock().get().defaultBlockState());
|
||||
BlockParticleOption girderData =
|
||||
new BlockParticleOption(ParticleTypes.BLOCK, AllBlocks.METAL_GIRDER.getDefaultState());
|
||||
if (!(level instanceof ServerLevel slevel))
|
||||
|
@ -393,6 +418,14 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
}
|
||||
}
|
||||
|
||||
public TrackMaterial getMaterial() {
|
||||
return trackMaterial;
|
||||
}
|
||||
|
||||
public void setMaterial(TrackMaterial material) {
|
||||
trackMaterial = material;
|
||||
}
|
||||
|
||||
public static class Segment {
|
||||
|
||||
public int index;
|
||||
|
|
|
@ -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.StandardBogeyBlockEntity;
|
||||
import com.simibubi.create.content.logistics.trains.track.AbstractBogeyBlockEntity;
|
||||
import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer;
|
||||
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
|
@ -17,11 +17,11 @@ public class BogeyBlockEntityRenderer<T extends BlockEntity> extends SafeBlockEn
|
|||
protected void renderSafe(T be, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light,
|
||||
int overlay) {
|
||||
BlockState blockState = be.getBlockState();
|
||||
float angle = 0;
|
||||
if (be instanceof StandardBogeyBlockEntity sbte)
|
||||
angle = sbte.getVirtualAngle(partialTicks);
|
||||
if (blockState.getBlock()instanceof IBogeyBlock bogey)
|
||||
bogey.render(blockState, angle, ms, partialTicks, buffer, light, overlay);
|
||||
if (be instanceof AbstractBogeyBlockEntity sbte) {
|
||||
float angle = sbte.getVirtualAngle(partialTicks);
|
||||
if (blockState.getBlock() instanceof AbstractBogeyBlock<?> bogey)
|
||||
bogey.render(blockState, angle, ms, partialTicks, buffer, light, overlay, sbte.getStyle(), sbte.getBogeyData());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,309 @@
|
|||
package com.simibubi.create.content.logistics.trains;
|
||||
|
||||
import com.jozufozu.flywheel.api.MaterialManager;
|
||||
import com.jozufozu.flywheel.core.Materials;
|
||||
import com.jozufozu.flywheel.core.PartialModel;
|
||||
import com.jozufozu.flywheel.core.materials.model.ModelData;
|
||||
import com.jozufozu.flywheel.util.transform.Transform;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
|
||||
import com.simibubi.create.foundation.render.CachedBufferer;
|
||||
import com.simibubi.create.foundation.render.SuperByteBuffer;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class BogeyRenderer {
|
||||
Map<String, ModelData[]> contraptionModelData = new HashMap<>();
|
||||
|
||||
/**
|
||||
* A common interface for getting transform data for both in-world and in-contraption model data safely from a
|
||||
* partial model
|
||||
*
|
||||
* @param model The key for the model data to instantiate or retrieve
|
||||
* @param ms The posestack used for contraption model data
|
||||
* @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 inInstancedContraption, int size) {
|
||||
return (inInstancedContraption) ? transformContraptionModelData(keyFromModel(model), ms) : createModelData(model, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* A common interface for getting transform data for both in-world and in-contraption model data safely from a
|
||||
* blockstate
|
||||
*
|
||||
* @param state 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 size The amount of models needed
|
||||
* @return A generic transform which can be used for both in-world and in-contraption models
|
||||
*/
|
||||
public Transform<?>[] getTransformsFromBlockState(BlockState state, PoseStack ms, boolean inContraption, int size) {
|
||||
return inContraption ? transformContraptionModelData(keyFromModel(state), ms) : createModelData(state, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for calling both in-world and in-contraption rendering
|
||||
*
|
||||
* @param bogeyData Custom data stored on the bogey able to be used for rendering
|
||||
* @param wheelAngle The angle of the wheel
|
||||
* @param ms The posestack to render to
|
||||
* @param light (Optional) Light used for in-world rendering
|
||||
* @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, boolean inContraption);
|
||||
|
||||
/**
|
||||
* Used for calling in-contraption rendering ensuring that falsey data is handled correctly
|
||||
*
|
||||
* @param bogeyData Custom data stored on the bogey able to be used for rendering
|
||||
* @param wheelAngle The angle of the wheel
|
||||
* @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, true);
|
||||
}
|
||||
|
||||
public abstract BogeySizes.BogeySize getSize();
|
||||
|
||||
/**
|
||||
* Used to collect Contraption Model Data for in-contraption rendering, should not be utilised directly when
|
||||
* rendering to prevent render type mismatch
|
||||
*
|
||||
* @param key The key used to access the model
|
||||
* @param ms Posestack of the contraption to bind the model data to
|
||||
* @return A generic transform which can be used for both in-world and in-contraption models
|
||||
*/
|
||||
private Transform<?>[] transformContraptionModelData(String key, PoseStack ms) {
|
||||
ModelData[] modelData = contraptionModelData.get(key);
|
||||
Arrays.stream(modelData).forEach(modelDataElement -> modelDataElement.setTransform(ms));
|
||||
return modelData;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Used for in world rendering, creates a set count of model data to be rendered, allowing for a generic response
|
||||
* when rendering multiple models both in-world and in-contraption for example, with wheels
|
||||
*
|
||||
* @param model The partial model of the model data ot be made
|
||||
* @param size The Amount of models needed
|
||||
* @return A generic transform which can be used for both in-world and in-contraption models
|
||||
*/
|
||||
private Transform<?>[] createModelData(PartialModel model, int size) {
|
||||
BlockState air = Blocks.AIR.defaultBlockState();
|
||||
SuperByteBuffer[] data = { CachedBufferer.partial(model, air) };
|
||||
return expandArrayToLength(data, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for in world rendering, creates a set count of model data to be rendered, allowing for a generic response
|
||||
* when rendering multiple models both in-world and in-contraption for example, with wheels
|
||||
*
|
||||
* @param state The state of the model data to be made
|
||||
* @param size Amount of models needed
|
||||
* @return A generic transform which can be used for both in-world and in-contraption models
|
||||
*/
|
||||
private Transform<?>[] createModelData(BlockState state, int size) {
|
||||
SuperByteBuffer[] data = { CachedBufferer.block(state) };
|
||||
return expandArrayToLength(data, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to clone in-world models to a set size to allow for common handling of rendering with multiple
|
||||
* instances of the same model for example with wheels
|
||||
*
|
||||
* @param data An in-world model to be replicated
|
||||
* @param size Amount of models needed
|
||||
* @return A generic transform which can be used for both in-world and in-contraption models
|
||||
*/
|
||||
private Transform<?>[] expandArrayToLength(SuperByteBuffer[] data, int size) {
|
||||
return Arrays.stream(Collections.nCopies(size, data).toArray())
|
||||
.flatMap(inner -> Arrays.stream((SuperByteBuffer[]) inner))
|
||||
.toArray(SuperByteBuffer[]::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to collect or create a single model from a partial model used for both in-world and
|
||||
* in-contraption rendering
|
||||
*
|
||||
* @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 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 inInstancedContraption) {
|
||||
BlockState air = Blocks.AIR.defaultBlockState();
|
||||
return inInstancedContraption ? contraptionModelData.get(keyFromModel(model))[0].setTransform(ms)
|
||||
: CachedBufferer.partial(model, air);
|
||||
}
|
||||
|
||||
/**
|
||||
* A common interface for getting transform data for blockstates, for a single model
|
||||
*
|
||||
* @param state The state 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 model required
|
||||
* @return A generic transform which can be used for both in-world and in-contraption models
|
||||
*/
|
||||
public Transform<?> getTransformFromBlockState(BlockState state, PoseStack ms, boolean inContraption) {
|
||||
return (inContraption) ? contraptionModelData.get(keyFromModel(state))[0].setTransform(ms)
|
||||
: CachedBufferer.block(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides render implementations a point in setup to instantiate all model data to be needed
|
||||
*
|
||||
* @param materialManager The material manager
|
||||
*/
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public abstract void initialiseContraptionModelData(MaterialManager materialManager);
|
||||
|
||||
/**
|
||||
* Creates instances of models for in-world rendering to a set length from a provided partial model
|
||||
*
|
||||
* @param materialManager The material manager
|
||||
* @param model Partial model to be instanced
|
||||
* @param count Amount of models neeeded
|
||||
*/
|
||||
public void createModelInstances(MaterialManager materialManager, PartialModel model, int count) {
|
||||
ModelData[] modelData = new ModelData[count];
|
||||
materialManager.defaultSolid().material(Materials.TRANSFORMED)
|
||||
.getModel(model).createInstances(modelData);
|
||||
contraptionModelData.put(keyFromModel(model), modelData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates instances of models for in-contraption rendering to a set length from a provided blockstate
|
||||
*
|
||||
* @param materialManager The material manager
|
||||
* @param state Blockstate of the model to be created
|
||||
* @param count Amount of models needed
|
||||
*/
|
||||
public void createModelInstances(MaterialManager materialManager, BlockState state, int count) {
|
||||
ModelData[] modelData = new ModelData[count];
|
||||
materialManager.defaultSolid().material(Materials.TRANSFORMED)
|
||||
.getModel(state).createInstances(modelData);
|
||||
contraptionModelData.put(keyFromModel(state), modelData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a single instance of models for in-contraption rendering from a provided blockstate
|
||||
*
|
||||
* @param materialManager The material manager
|
||||
* @param state Blockstate of the model to be created
|
||||
*/
|
||||
public void createModelInstance(MaterialManager materialManager, BlockState state) {
|
||||
this.createModelInstances(materialManager, state, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create a single model instance for in-contraption rendering
|
||||
*
|
||||
* @param materialManager The material manager
|
||||
* @param models The type of model to create instances of
|
||||
*/
|
||||
public void createModelInstances(MaterialManager materialManager, PartialModel... models) {
|
||||
for (PartialModel model : models)
|
||||
createModelInstances(materialManager, model, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles scale for all model data and renders non contraption model data
|
||||
*
|
||||
* @param b The model data itself
|
||||
* @param ms Pose stack to render to
|
||||
* @param light light level of the scene
|
||||
* @param vb Vertex Consumber to render to
|
||||
* @param <B> Generic alias for both contraption and in-world model data
|
||||
*/
|
||||
|
||||
public static <B extends Transform<?>> void finalize(B b, PoseStack ms, int light, @Nullable VertexConsumer vb) {
|
||||
b.scale(1 - 1/512f);
|
||||
if (b instanceof SuperByteBuffer byteBuf && vb != null)
|
||||
byteBuf.light(light).renderInto(ms, vb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatic handling for setting empty transforms for all model data
|
||||
*
|
||||
*/
|
||||
|
||||
public void emptyTransforms() {
|
||||
for (ModelData[] data : contraptionModelData.values())
|
||||
for (ModelData model : data)
|
||||
model.setEmptyTransform();
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatic handling for updating all model data's light
|
||||
*
|
||||
* @param blockLight the blocklight to be applied
|
||||
* @param skyLight the skylight to be applied
|
||||
*/
|
||||
|
||||
public void updateLight(int blockLight, int skyLight) {
|
||||
for (ModelData[] data : contraptionModelData.values())
|
||||
for (ModelData model : data)
|
||||
model.setBlockLight(blockLight).setSkyLight(skyLight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatic handling for clearing all model data of a contraption
|
||||
*
|
||||
*/
|
||||
|
||||
public void remove() {
|
||||
for (ModelData[] data : contraptionModelData.values())
|
||||
for (ModelData model : data)
|
||||
model.delete();
|
||||
contraptionModelData.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a model key from a partial model, so it can be easily accessed
|
||||
*
|
||||
* @param partialModel the model we want a unique key for
|
||||
* @return Key of the model
|
||||
*/
|
||||
|
||||
private String keyFromModel(PartialModel partialModel) {
|
||||
return partialModel.getLocation().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a model key from a blockstate, so it can be easily accessed
|
||||
*
|
||||
* @param state Blockstate of the model
|
||||
* @return Key of the model
|
||||
*/
|
||||
|
||||
private String keyFromModel(BlockState state) {
|
||||
return state.toString();
|
||||
}
|
||||
|
||||
public static abstract class CommonRenderer extends BogeyRenderer {
|
||||
@Override
|
||||
public BogeySizes.BogeySize getSize() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package com.simibubi.create.content.logistics.trains;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class BogeySizes {
|
||||
private static final Collection<BogeySize> BOGEY_SIZES = new HashSet<>();
|
||||
public static final BogeySize SMALL = new BogeySize(Create.ID, "small", 6.5f / 16f);
|
||||
public static final BogeySize LARGE = new BogeySize(Create.ID, "large", 12.5f / 16f);
|
||||
|
||||
static {
|
||||
BOGEY_SIZES.add(SMALL);
|
||||
BOGEY_SIZES.add(LARGE);
|
||||
}
|
||||
|
||||
public static BogeySize addSize(String modId, String name, float size) {
|
||||
ResourceLocation location = new ResourceLocation(modId, name);
|
||||
return addSize(location, size);
|
||||
}
|
||||
|
||||
public static BogeySize addSize(ResourceLocation location, float size) {
|
||||
BogeySize customSize = new BogeySize(location, size);
|
||||
BOGEY_SIZES.add(customSize);
|
||||
return customSize;
|
||||
}
|
||||
|
||||
public static List<BogeySize> getAllSizesSmallToLarge() {
|
||||
return BOGEY_SIZES.stream()
|
||||
.sorted(Comparator.comparing(BogeySize::wheelRadius))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<BogeySize> getAllSizesLargeToSmall() {
|
||||
List<BogeySize> sizes = getAllSizesSmallToLarge();
|
||||
Collections.reverse(sizes);
|
||||
return sizes;
|
||||
}
|
||||
|
||||
public static int count() {
|
||||
return BOGEY_SIZES.size();
|
||||
}
|
||||
|
||||
public record BogeySize(ResourceLocation location, Float wheelRadius) {
|
||||
public BogeySize(String modId, String name, float wheelRadius) {
|
||||
this(new ResourceLocation(modId, name), wheelRadius);
|
||||
}
|
||||
|
||||
public BogeySize increment() {
|
||||
List<BogeySize> values = getAllSizesSmallToLarge();
|
||||
int ordinal = values.indexOf(this);
|
||||
return values.get((ordinal + 1) % values.size());
|
||||
}
|
||||
|
||||
public boolean is(BogeySize size) {
|
||||
return size.location == this.location;
|
||||
}
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
package com.simibubi.create.content.logistics.trains;
|
||||
|
||||
import static net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.api.MaterialManager;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.simibubi.create.content.contraptions.wrench.IWrenchable;
|
||||
import com.simibubi.create.content.logistics.trains.entity.BogeyInstance;
|
||||
import com.simibubi.create.content.logistics.trains.entity.CarriageBogey;
|
||||
import com.simibubi.create.foundation.utility.RegisteredObjects;
|
||||
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
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;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
public interface IBogeyBlock extends IWrenchable {
|
||||
|
||||
static final List<ResourceLocation> BOGEYS = new ArrayList<>();
|
||||
|
||||
public static void register(ResourceLocation block) {
|
||||
BOGEYS.add(block);
|
||||
}
|
||||
|
||||
public EnumSet<Direction> getStickySurfaces(BlockGetter world, BlockPos pos, BlockState state);
|
||||
|
||||
public double getWheelPointSpacing();
|
||||
|
||||
public double getWheelRadius();
|
||||
|
||||
public boolean allowsSingleBogeyCarriage();
|
||||
|
||||
public Vec3 getConnectorAnchorOffset();
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void render(@Nullable BlockState state, float wheelAngle, PoseStack ms, float partialTicks,
|
||||
MultiBufferSource buffers, int light, int overlay);
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public BogeyInstance createInstance(MaterialManager materialManager, CarriageBogey bogey);
|
||||
|
||||
public default Direction getBogeyUpDirection() {
|
||||
return Direction.UP;
|
||||
}
|
||||
|
||||
public boolean isTrackAxisAlongFirstCoordinate(BlockState state);
|
||||
|
||||
@Nullable
|
||||
public BlockState getMatchingBogey(Direction upDirection, boolean axisAlongFirst);
|
||||
|
||||
@Override
|
||||
default BlockState getRotatedBlockState(BlockState state, Direction targetedFace) {
|
||||
Block block = state.getBlock();
|
||||
int indexOf = BOGEYS.indexOf(RegisteredObjects.getKeyOrThrow(block));
|
||||
if (indexOf == -1)
|
||||
return state;
|
||||
|
||||
int index = (indexOf + 1) % BOGEYS.size();
|
||||
Direction bogeyUpDirection = getBogeyUpDirection();
|
||||
boolean trackAxisAlongFirstCoordinate = isTrackAxisAlongFirstCoordinate(state);
|
||||
|
||||
while (index != indexOf) {
|
||||
ResourceLocation id = BOGEYS.get(index);
|
||||
Block newBlock = ForgeRegistries.BLOCKS.getValue(id);
|
||||
if (newBlock instanceof IBogeyBlock bogey) {
|
||||
BlockState matchingBogey = bogey.getMatchingBogey(bogeyUpDirection, trackAxisAlongFirstCoordinate);
|
||||
if (matchingBogey != null)
|
||||
return matchingBogey.hasProperty(WATERLOGGED)
|
||||
? matchingBogey.setValue(WATERLOGGED, state.getValue(WATERLOGGED))
|
||||
: matchingBogey;
|
||||
}
|
||||
index = (index + 1) % BOGEYS.size();
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
@ -85,20 +86,38 @@ public interface ITrackBlock {
|
|||
Function<Vec3, Integer> yOffsetFactory = v -> getYOffsetAt(world, pos, state, v);
|
||||
|
||||
addToListIfConnected(connectedTo, list, offsetFactory, b -> shape.getNormal(), dimensionFactory,
|
||||
yOffsetFactory, axis, null);
|
||||
yOffsetFactory, 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, Function<Vec3, Integer> yOffsetFactory, Vec3 axis,
|
||||
BezierConnection viaTurn) {
|
||||
BezierConnection viaTurn, BiFunction<Boolean, Vec3, TrackMaterial> materialFactory) {
|
||||
|
||||
Vec3 firstOffset = offsetFactory.apply(0.5d, true);
|
||||
DiscoveredLocation firstLocation =
|
||||
new DiscoveredLocation(dimensionFactory.apply(true), firstOffset).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)
|
||||
.withYOffset(yOffsetFactory.apply(firstOffset));
|
||||
|
@ -106,6 +125,8 @@ public interface ITrackBlock {
|
|||
Vec3 secondOffset = offsetFactory.apply(0.5d, false);
|
||||
DiscoveredLocation secondLocation =
|
||||
new DiscoveredLocation(dimensionFactory.apply(false), secondOffset).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)
|
||||
.withYOffset(yOffsetFactory.apply(secondOffset));
|
||||
|
@ -169,4 +190,6 @@ public interface ITrackBlock {
|
|||
.normalize()) < 0 ? AxisDirection.POSITIVE : AxisDirection.NEGATIVE);
|
||||
}
|
||||
|
||||
TrackMaterial getMaterial();
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
package com.simibubi.create.content.logistics.trains;
|
||||
|
||||
import com.jozufozu.flywheel.api.MaterialManager;
|
||||
import com.jozufozu.flywheel.util.transform.Transform;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock;
|
||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.simibubi.create.AllBlockPartials.LARGE_BOGEY_WHEELS;
|
||||
import static com.simibubi.create.AllBlockPartials.BOGEY_PIN;
|
||||
import static com.simibubi.create.AllBlockPartials.BOGEY_DRIVE;
|
||||
import static com.simibubi.create.AllBlockPartials.BOGEY_PISTON;
|
||||
import static com.simibubi.create.AllBlockPartials.SMALL_BOGEY_WHEELS;
|
||||
import static com.simibubi.create.AllBlockPartials.BOGEY_FRAME;
|
||||
|
||||
public class StandardBogeyRenderer {
|
||||
public static class CommonStandardBogeyRenderer extends BogeyRenderer.CommonRenderer {
|
||||
@Override
|
||||
public void initialiseContraptionModelData(MaterialManager materialManager) {
|
||||
createModelInstances(materialManager, AllBlocks.SHAFT.getDefaultState()
|
||||
.setValue(ShaftBlock.AXIS, Direction.Axis.Z), 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(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, inInstancedContraption, 2);
|
||||
for (int i : Iterate.zeroAndOne) {
|
||||
shafts[i].translate(-.5f, .25f, i * -1)
|
||||
.centre()
|
||||
.rotateZ(wheelAngle)
|
||||
.unCentre();
|
||||
finalize(shafts[i], ms, light, vb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class SmallStandardBogeyRenderer extends BogeyRenderer {
|
||||
@Override
|
||||
public void initialiseContraptionModelData(MaterialManager materialManager) {
|
||||
createModelInstances(materialManager, SMALL_BOGEY_WHEELS, 2);
|
||||
createModelInstances(materialManager, BOGEY_FRAME);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BogeySizes.BogeySize getSize() {
|
||||
return BogeySizes.SMALL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(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, inInstancedContraption, 2);
|
||||
for (int side : Iterate.positiveAndNegative) {
|
||||
if (!inInstancedContraption)
|
||||
ms.pushPose();
|
||||
Transform<?> wheel = wheels[(side + 1)/2];
|
||||
wheel.translate(0, 12 / 16f, side)
|
||||
.rotateX(wheelAngle);
|
||||
finalize(wheel, ms, light, vb);
|
||||
if (!inInstancedContraption)
|
||||
ms.popPose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class LargeStandardBogeyRenderer extends BogeyRenderer {
|
||||
@Override
|
||||
public void initialiseContraptionModelData(MaterialManager materialManager) {
|
||||
createModelInstances(materialManager, LARGE_BOGEY_WHEELS, BOGEY_DRIVE, BOGEY_PISTON, BOGEY_PIN);
|
||||
createModelInstances(materialManager, AllBlocks.SHAFT.getDefaultState()
|
||||
.setValue(ShaftBlock.AXIS, Direction.Axis.X), 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BogeySizes.BogeySize getSize() {
|
||||
return BogeySizes.LARGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(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, inInstancedContraption, 2);
|
||||
|
||||
for (int i : Iterate.zeroAndOne) {
|
||||
Transform<?> secondShaft = secondaryShafts[i];
|
||||
secondShaft.translate(-.5f, .25f, .5f + i * -2)
|
||||
.centre()
|
||||
.rotateX(wheelAngle)
|
||||
.unCentre();
|
||||
finalize(secondShaft, ms, light, vb);
|
||||
}
|
||||
|
||||
Transform<?> bogeyDrive = getTransformFromPartial(BOGEY_DRIVE, ms, inInstancedContraption);
|
||||
finalize(bogeyDrive, ms, light, vb);
|
||||
|
||||
Transform<?> bogeyPiston = getTransformFromPartial(BOGEY_PISTON, ms, inInstancedContraption)
|
||||
.translate(0, 0, 1 / 4f * Math.sin(AngleHelper.rad(wheelAngle)));
|
||||
finalize(bogeyPiston, ms, light, vb);
|
||||
|
||||
if (!inInstancedContraption)
|
||||
ms.pushPose();
|
||||
|
||||
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, inInstancedContraption)
|
||||
.translate(0, 1, 0)
|
||||
.rotateX(wheelAngle)
|
||||
.translate(0, 1 / 4f, 0)
|
||||
.rotateX(-wheelAngle);
|
||||
finalize(bogeyPin, ms, light, vb);
|
||||
|
||||
if (!inInstancedContraption)
|
||||
ms.popPose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,13 +24,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() {
|
||||
|
@ -230,13 +236,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;
|
||||
}
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import com.simibubi.create.foundation.utility.outliner.Outliner;
|
|||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
|
@ -213,7 +214,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)
|
||||
|
@ -266,6 +267,17 @@ public class TrackGraphVisualizer {
|
|||
|
||||
yOffset = new Vec3(0, (other.hashCode() > hashCode ? 6 : 4) / 16f, 0);
|
||||
if (!edge.isTurn()) {
|
||||
if (extended) {
|
||||
Vec3 materialPos = edge.getPosition(graph, 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, .25, 0, .25)
|
||||
.move(0, -0.5, 0))
|
||||
.lineWidth(1 / 16f)
|
||||
.colored(graph.color);
|
||||
}
|
||||
CreateClient.OUTLINER.showLine(edge, edge.getPosition(graph, 0)
|
||||
.add(yOffset),
|
||||
edge.getPosition(graph, 1)
|
||||
|
@ -277,6 +289,17 @@ public class TrackGraphVisualizer {
|
|||
|
||||
Vec3 previous = null;
|
||||
BezierConnection turn = edge.getTurn();
|
||||
if (extended) {
|
||||
Vec3 materialPos = edge.getPosition(graph, 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, .25, 0, .25)
|
||||
.move(0, -0.5, 0))
|
||||
.lineWidth(1 / 16f)
|
||||
.colored(graph.color);
|
||||
}
|
||||
for (int i = 0; i <= turn.getSegmentCount(); i++) {
|
||||
Vec3 current = edge.getPosition(graph, i * 1f / turn.getSegmentCount());
|
||||
if (previous != null)
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
package com.simibubi.create.content.logistics.trains;
|
||||
|
||||
import static com.simibubi.create.content.logistics.trains.TrackMaterialFactory.make;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.jozufozu.flywheel.core.PartialModel;
|
||||
import com.simibubi.create.AllBlockPartials;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackBlock;
|
||||
import com.tterrag.registrate.util.nullness.NonNullSupplier;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.crafting.Ingredient;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
|
||||
public class TrackMaterial {
|
||||
public static final Map<ResourceLocation, TrackMaterial> ALL = new HashMap<>();
|
||||
|
||||
public static final TrackMaterial ANDESITE = make(Create.asResource("andesite"))
|
||||
.lang("Andesite")
|
||||
.block(NonNullSupplier.lazy(() -> AllBlocks.TRACK))
|
||||
.particle(Create.asResource("block/palettes/stone_types/polished/andesite_cut_polished"))
|
||||
.defaultModels()
|
||||
.build();
|
||||
|
||||
public final ResourceLocation id;
|
||||
public final String langName;
|
||||
public final NonNullSupplier<NonNullSupplier<? extends TrackBlock>> trackBlock;
|
||||
public final Ingredient sleeperIngredient;
|
||||
public final Ingredient railsIngredient;
|
||||
public final ResourceLocation particle;
|
||||
public final TrackType trackType;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
protected TrackModelHolder modelHolder;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public TrackModelHolder getModelHolder() {
|
||||
return modelHolder;
|
||||
}
|
||||
|
||||
public TrackMaterial(ResourceLocation id, String langName, NonNullSupplier<NonNullSupplier<? extends TrackBlock>> trackBlock,
|
||||
ResourceLocation particle, Ingredient sleeperIngredient, Ingredient railsIngredient,
|
||||
TrackType trackType, Supplier<Supplier<TrackModelHolder>> modelHolder) {
|
||||
this.id = id;
|
||||
this.langName = langName;
|
||||
this.trackBlock = trackBlock;
|
||||
this.sleeperIngredient = sleeperIngredient;
|
||||
this.railsIngredient = railsIngredient;
|
||||
this.particle = particle;
|
||||
this.trackType = trackType;
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> this.modelHolder = modelHolder.get().get());
|
||||
ALL.put(this.id, this);
|
||||
}
|
||||
|
||||
public NonNullSupplier<? extends TrackBlock> getTrackBlock() {
|
||||
return this.trackBlock.get();
|
||||
}
|
||||
|
||||
public TrackBlock createBlock(BlockBehaviour.Properties properties) {
|
||||
return this.trackType.factory.create(properties, this);
|
||||
}
|
||||
|
||||
public boolean isCustom(String modId) {
|
||||
return this.id.getNamespace().equals(modId);
|
||||
}
|
||||
|
||||
public static TrackMaterial[] allCustom(String modid) {
|
||||
return ALL.values().stream().filter(tm -> tm.isCustom(modid)).toArray(TrackMaterial[]::new);
|
||||
}
|
||||
|
||||
public static List<NonNullSupplier<? extends TrackBlock>> allCustomBlocks(String modid) {
|
||||
List<NonNullSupplier<? extends TrackBlock>> list = new ArrayList<>();
|
||||
for (TrackMaterial material : allCustom(modid)) {
|
||||
list.add(material.getTrackBlock());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static List<NonNullSupplier<? extends TrackBlock>> allBlocks() {
|
||||
List<NonNullSupplier<? extends TrackBlock>> list = new ArrayList<>();
|
||||
for (TrackMaterial material : ALL.values()) {
|
||||
list.add(material.getTrackBlock());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public String resourceName() {
|
||||
return this.id.getPath();
|
||||
}
|
||||
|
||||
public static TrackMaterial deserialize(String serializedName) {
|
||||
if (serializedName.isBlank()) // Data migrating from 0.5
|
||||
return ANDESITE;
|
||||
|
||||
ResourceLocation id = ResourceLocation.tryParse(serializedName);
|
||||
if (id != null)
|
||||
for (TrackMaterial material : ALL.values())
|
||||
if (material.id.equals(id))
|
||||
return material;
|
||||
|
||||
Create.LOGGER.error("Failed to locate serialized track material: " + serializedName);
|
||||
return ANDESITE;
|
||||
}
|
||||
|
||||
public static class TrackType {
|
||||
@FunctionalInterface
|
||||
protected interface TrackBlockFactory {
|
||||
TrackBlock create(BlockBehaviour.Properties properties, TrackMaterial material);
|
||||
}
|
||||
|
||||
public static final TrackType STANDARD = new TrackType(Create.asResource("standard"), TrackBlock::new);
|
||||
|
||||
public final ResourceLocation id;
|
||||
protected final TrackBlockFactory factory;
|
||||
|
||||
public TrackType(ResourceLocation id, TrackBlockFactory factory) {
|
||||
this.id = id;
|
||||
this.factory = factory;
|
||||
}
|
||||
}
|
||||
|
||||
public static TrackMaterial fromItem(Item item) {
|
||||
if (item instanceof BlockItem blockItem && blockItem.getBlock() instanceof ITrackBlock trackBlock)
|
||||
return trackBlock.getMaterial();
|
||||
return TrackMaterial.ANDESITE;
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public record TrackModelHolder(PartialModel tie, PartialModel segment_left, PartialModel segment_right) {
|
||||
static final TrackModelHolder DEFAULT = new TrackModelHolder(AllBlockPartials.TRACK_TIE, AllBlockPartials.TRACK_SEGMENT_LEFT, AllBlockPartials.TRACK_SEGMENT_RIGHT);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
package com.simibubi.create.content.logistics.trains;
|
||||
|
||||
import com.jozufozu.flywheel.core.PartialModel;
|
||||
import com.simibubi.create.AllTags;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackBlock;
|
||||
|
||||
import com.tterrag.registrate.util.nullness.NonNullSupplier;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.crafting.Ingredient;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class TrackMaterialFactory {
|
||||
private final ResourceLocation id;
|
||||
private String langName;
|
||||
private NonNullSupplier<NonNullSupplier<? extends TrackBlock>> trackBlock;
|
||||
private Ingredient sleeperIngredient = Ingredient.EMPTY;
|
||||
private Ingredient railsIngredient = Ingredient.fromValues(Stream.of(new Ingredient.TagValue(AllTags.forgeItemTag("nuggets/iron")), new Ingredient.TagValue(AllTags.forgeItemTag("nuggets/zinc"))));
|
||||
private ResourceLocation particle;
|
||||
private TrackMaterial.TrackType trackType = TrackMaterial.TrackType.STANDARD;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
private TrackMaterial.TrackModelHolder modelHolder;
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
private PartialModel tieModel;
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
private PartialModel leftSegmentModel;
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
private PartialModel rightSegmentModel;
|
||||
|
||||
public TrackMaterialFactory(ResourceLocation id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public static TrackMaterialFactory make(ResourceLocation id) { // Convenience function for static import
|
||||
return new TrackMaterialFactory(id);
|
||||
}
|
||||
|
||||
public TrackMaterialFactory lang(String langName) {
|
||||
this.langName = langName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TrackMaterialFactory block(NonNullSupplier<NonNullSupplier<? extends TrackBlock>> trackBlock) {
|
||||
this.trackBlock = trackBlock;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TrackMaterialFactory defaultModels() { // was setBuiltin
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> this.modelHolder = TrackMaterial.TrackModelHolder.DEFAULT);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TrackMaterialFactory sleeper(Ingredient sleeperIngredient) {
|
||||
this.sleeperIngredient = sleeperIngredient;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TrackMaterialFactory sleeper(ItemLike... items) {
|
||||
this.sleeperIngredient = Ingredient.of(items);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TrackMaterialFactory rails(Ingredient railsIngredient) {
|
||||
this.railsIngredient = railsIngredient;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TrackMaterialFactory rails(ItemLike... items) {
|
||||
this.railsIngredient = Ingredient.of(items);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TrackMaterialFactory noRecipeGen() {
|
||||
this.railsIngredient = Ingredient.EMPTY;
|
||||
this.sleeperIngredient = Ingredient.EMPTY;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TrackMaterialFactory particle(ResourceLocation particle) {
|
||||
this.particle = particle;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TrackMaterialFactory trackType(TrackMaterial.TrackType trackType) {
|
||||
this.trackType = trackType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TrackMaterialFactory standardModels() { // was defaultModels
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> {
|
||||
String namespace = id.getNamespace();
|
||||
String prefix = "block/track/" + id.getPath() + "/";
|
||||
tieModel = new PartialModel(new ResourceLocation(namespace, prefix + "tie"));
|
||||
leftSegmentModel = new PartialModel(new ResourceLocation(namespace, prefix + "segment_left"));
|
||||
rightSegmentModel = new PartialModel(new ResourceLocation(namespace, prefix + "segment_right"));
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public TrackMaterialFactory customModels(Supplier<Supplier<PartialModel>> tieModel, Supplier<Supplier<PartialModel>> leftSegmentModel, Supplier<Supplier<PartialModel>> rightSegmentModel) {
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> {
|
||||
this.tieModel = tieModel.get().get();
|
||||
this.leftSegmentModel = leftSegmentModel.get().get();
|
||||
this.rightSegmentModel = rightSegmentModel.get().get();
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public TrackMaterial build() {
|
||||
assert trackBlock != null;
|
||||
assert langName != null;
|
||||
assert particle != null;
|
||||
assert trackType != null;
|
||||
assert sleeperIngredient != null;
|
||||
assert railsIngredient != null;
|
||||
assert id != null;
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> {
|
||||
assert modelHolder != null;
|
||||
if (tieModel != null || leftSegmentModel != null || rightSegmentModel != null) {
|
||||
assert tieModel != null && leftSegmentModel != null && rightSegmentModel != null;
|
||||
modelHolder = new TrackMaterial.TrackModelHolder(tieModel, leftSegmentModel, rightSegmentModel);
|
||||
}
|
||||
});
|
||||
return new TrackMaterial(id, langName, trackBlock, particle, sleeperIngredient, railsIngredient, trackType, () -> () -> modelHolder);
|
||||
}
|
||||
}
|
|
@ -25,8 +25,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) {
|
||||
|
@ -122,9 +122,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);
|
||||
}
|
||||
|
||||
|
@ -137,6 +139,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)
|
||||
|
@ -176,6 +194,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;
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package com.simibubi.create.content.logistics.trains.entity;
|
||||
|
||||
import com.jozufozu.flywheel.api.MaterialManager;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import com.simibubi.create.content.logistics.trains.BogeyRenderer;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
|
||||
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, boolean inContraption) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialiseContraptionModelData(MaterialManager materialManager) {
|
||||
|
||||
}
|
||||
}
|
|
@ -1,235 +1,69 @@
|
|||
package com.simibubi.create.content.logistics.trains.entity;
|
||||
|
||||
import com.jozufozu.flywheel.api.Material;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.jozufozu.flywheel.api.MaterialManager;
|
||||
import com.jozufozu.flywheel.core.Materials;
|
||||
import com.jozufozu.flywheel.core.materials.model.ModelData;
|
||||
import com.jozufozu.flywheel.util.AnimationTickHolder;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllPartialModels;
|
||||
import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock;
|
||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.content.logistics.trains.BogeyRenderer;
|
||||
import com.simibubi.create.content.logistics.trains.BogeySizes;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.BlockAndTintGetter;
|
||||
import net.minecraft.world.level.LightLayer;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public sealed class BogeyInstance {
|
||||
public final class BogeyInstance {
|
||||
private final BogeySizes.BogeySize size;
|
||||
private final BogeyStyle style;
|
||||
|
||||
public final CarriageBogey bogey;
|
||||
private final ModelData[] shafts;
|
||||
public final BogeyRenderer renderer;
|
||||
public final Optional<BogeyRenderer.CommonRenderer> commonRenderer;
|
||||
|
||||
protected BogeyInstance(CarriageBogey bogey, MaterialManager materialManager) {
|
||||
public BogeyInstance(CarriageBogey bogey, BogeyStyle style, BogeySizes.BogeySize size,
|
||||
MaterialManager materialManager) {
|
||||
this.bogey = bogey;
|
||||
this.size = size;
|
||||
this.style = style;
|
||||
|
||||
shafts = new ModelData[2];
|
||||
|
||||
materialManager.defaultSolid()
|
||||
.material(Materials.TRANSFORMED)
|
||||
.getModel(AllBlocks.SHAFT.getDefaultState()
|
||||
.setValue(ShaftBlock.AXIS, Direction.Axis.Z))
|
||||
.createInstances(shafts);
|
||||
this.renderer = this.style.createRendererInstance(this.size);
|
||||
this.commonRenderer = this.style.getNewCommonRenderInstance();
|
||||
|
||||
commonRenderer.ifPresent(bogeyRenderer -> bogeyRenderer.initialiseContraptionModelData(materialManager));
|
||||
renderer.initialiseContraptionModelData(materialManager);
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
for (ModelData shaft : shafts)
|
||||
shaft.delete();
|
||||
}
|
||||
|
||||
public void hiddenFrame() {
|
||||
void hiddenFrame() {
|
||||
beginFrame(0, null);
|
||||
}
|
||||
|
||||
|
||||
public void beginFrame(float wheelAngle, PoseStack ms) {
|
||||
if (ms == null) {
|
||||
for (int i : Iterate.zeroAndOne)
|
||||
shafts[i].setEmptyTransform();
|
||||
renderer.emptyTransforms();
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i : Iterate.zeroAndOne)
|
||||
shafts[i].setTransform(ms)
|
||||
.translate(-.5f, .25f, i * -1)
|
||||
.centre()
|
||||
.rotateZ(wheelAngle)
|
||||
.unCentre();
|
||||
commonRenderer.ifPresent(bogeyRenderer -> bogeyRenderer.render(bogey.bogeyData, wheelAngle, ms));
|
||||
renderer.render(bogey.bogeyData, wheelAngle, ms);
|
||||
}
|
||||
|
||||
public void updateLight(BlockAndTintGetter world, CarriageContraptionEntity entity) {
|
||||
var lightPos = new BlockPos(getLightPos(entity));
|
||||
|
||||
updateLight(world.getBrightness(LightLayer.BLOCK, lightPos), world.getBrightness(LightLayer.SKY, lightPos));
|
||||
commonRenderer
|
||||
.ifPresent(bogeyRenderer -> bogeyRenderer.updateLight(world.getBrightness(LightLayer.BLOCK, lightPos),
|
||||
world.getBrightness(LightLayer.SKY, lightPos)));
|
||||
renderer.updateLight(world.getBrightness(LightLayer.BLOCK, lightPos),
|
||||
world.getBrightness(LightLayer.SKY, lightPos));
|
||||
}
|
||||
|
||||
private Vec3 getLightPos(CarriageContraptionEntity entity) {
|
||||
if (bogey.getAnchorPosition() != null) {
|
||||
return bogey.getAnchorPosition();
|
||||
} else {
|
||||
return entity.getLightProbePosition(AnimationTickHolder.getPartialTicks());
|
||||
}
|
||||
return bogey.getAnchorPosition() != null ? bogey.getAnchorPosition()
|
||||
: entity.getLightProbePosition(AnimationTickHolder.getPartialTicks());
|
||||
}
|
||||
|
||||
public void updateLight(int blockLight, int skyLight) {
|
||||
for (ModelData shaft : shafts) {
|
||||
shaft.setBlockLight(blockLight)
|
||||
.setSkyLight(skyLight);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Frame extends BogeyInstance {
|
||||
|
||||
private final ModelData frame;
|
||||
private final ModelData[] wheels;
|
||||
|
||||
public Frame(CarriageBogey bogey, MaterialManager materialManager) {
|
||||
super(bogey, materialManager);
|
||||
|
||||
frame = materialManager.defaultSolid()
|
||||
.material(Materials.TRANSFORMED)
|
||||
.getModel(AllPartialModels.BOGEY_FRAME)
|
||||
.createInstance();
|
||||
|
||||
wheels = new ModelData[2];
|
||||
|
||||
materialManager.defaultSolid()
|
||||
.material(Materials.TRANSFORMED)
|
||||
.getModel(AllPartialModels.SMALL_BOGEY_WHEELS)
|
||||
.createInstances(wheels);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginFrame(float wheelAngle, PoseStack ms) {
|
||||
super.beginFrame(wheelAngle, ms);
|
||||
|
||||
if (ms == null) {
|
||||
frame.setEmptyTransform();
|
||||
for (int side : Iterate.positiveAndNegative)
|
||||
wheels[(side + 1) / 2].setEmptyTransform();
|
||||
return;
|
||||
}
|
||||
|
||||
frame.setTransform(ms);
|
||||
|
||||
for (int side : Iterate.positiveAndNegative) {
|
||||
wheels[(side + 1) / 2].setTransform(ms)
|
||||
.translate(0, 12 / 16f, side)
|
||||
.rotateX(wheelAngle);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLight(int blockLight, int skyLight) {
|
||||
super.updateLight(blockLight, skyLight);
|
||||
frame.setBlockLight(blockLight)
|
||||
.setSkyLight(skyLight);
|
||||
for (ModelData wheel : wheels)
|
||||
wheel.setBlockLight(blockLight)
|
||||
.setSkyLight(skyLight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
super.remove();
|
||||
frame.delete();
|
||||
for (ModelData wheel : wheels)
|
||||
wheel.delete();
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Drive extends BogeyInstance {
|
||||
|
||||
private final ModelData[] secondShaft;
|
||||
private final ModelData drive;
|
||||
private final ModelData piston;
|
||||
private final ModelData wheels;
|
||||
private final ModelData pin;
|
||||
|
||||
public Drive(CarriageBogey bogey, MaterialManager materialManager) {
|
||||
super(bogey, materialManager);
|
||||
Material<ModelData> mat = materialManager.defaultSolid()
|
||||
.material(Materials.TRANSFORMED);
|
||||
|
||||
secondShaft = new ModelData[2];
|
||||
|
||||
mat.getModel(AllBlocks.SHAFT.getDefaultState()
|
||||
.setValue(ShaftBlock.AXIS, Direction.Axis.X))
|
||||
.createInstances(secondShaft);
|
||||
|
||||
drive = mat.getModel(AllPartialModels.BOGEY_DRIVE)
|
||||
.createInstance();
|
||||
piston = mat.getModel(AllPartialModels.BOGEY_PISTON)
|
||||
.createInstance();
|
||||
wheels = mat.getModel(AllPartialModels.LARGE_BOGEY_WHEELS)
|
||||
.createInstance();
|
||||
pin = mat.getModel(AllPartialModels.BOGEY_PIN)
|
||||
.createInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginFrame(float wheelAngle, PoseStack ms) {
|
||||
super.beginFrame(wheelAngle, ms);
|
||||
|
||||
if (ms == null) {
|
||||
for (int i : Iterate.zeroAndOne)
|
||||
secondShaft[i].setEmptyTransform();
|
||||
drive.setEmptyTransform();
|
||||
piston.setEmptyTransform();
|
||||
wheels.setEmptyTransform();
|
||||
pin.setEmptyTransform();
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i : Iterate.zeroAndOne)
|
||||
secondShaft[i].setTransform(ms)
|
||||
.translate(-.5f, .25f, .5f + i * -2)
|
||||
.centre()
|
||||
.rotateX(wheelAngle)
|
||||
.unCentre();
|
||||
|
||||
drive.setTransform(ms);
|
||||
piston.setTransform(ms)
|
||||
.translate(0, 0, 1 / 4f * Math.sin(AngleHelper.rad(wheelAngle)));
|
||||
|
||||
wheels.setTransform(ms)
|
||||
.translate(0, 1, 0)
|
||||
.rotateX(wheelAngle);
|
||||
pin.setTransform(ms)
|
||||
.translate(0, 1, 0)
|
||||
.rotateX(wheelAngle)
|
||||
.translate(0, 1 / 4f, 0)
|
||||
.rotateX(-wheelAngle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLight(int blockLight, int skyLight) {
|
||||
super.updateLight(blockLight, skyLight);
|
||||
for (ModelData shaft : secondShaft)
|
||||
shaft.setBlockLight(blockLight)
|
||||
.setSkyLight(skyLight);
|
||||
drive.setBlockLight(blockLight)
|
||||
.setSkyLight(skyLight);
|
||||
piston.setBlockLight(blockLight)
|
||||
.setSkyLight(skyLight);
|
||||
wheels.setBlockLight(blockLight)
|
||||
.setSkyLight(skyLight);
|
||||
pin.setBlockLight(blockLight)
|
||||
.setSkyLight(skyLight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
super.remove();
|
||||
for (ModelData shaft : secondShaft)
|
||||
shaft.delete();
|
||||
drive.delete();
|
||||
piston.delete();
|
||||
wheels.delete();
|
||||
pin.delete();
|
||||
}
|
||||
@FunctionalInterface
|
||||
interface BogeyInstanceFactory {
|
||||
BogeyInstance create(CarriageBogey bogey, BogeySizes.BogeySize size, MaterialManager materialManager);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
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;
|
||||
|
||||
import com.simibubi.create.content.logistics.trains.BogeyRenderer.CommonRenderer;
|
||||
import com.simibubi.create.content.logistics.trains.BogeySizes;
|
||||
|
||||
import net.minecraft.core.particles.ParticleOptions;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
|
||||
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;
|
||||
public final ResourceLocation soundType;
|
||||
public final ParticleOptions contactParticle;
|
||||
public final ParticleOptions smokeParticle;
|
||||
public final CompoundTag defaultData;
|
||||
|
||||
public BogeyStyle(ResourceLocation name, ResourceLocation cycleGroup, Component displayName, ResourceLocation soundType, ParticleOptions contactParticle, ParticleOptions smokeParticle,
|
||||
CompoundTag defaultData, Map<BogeySizes.BogeySize, SizeData> sizes, Optional<Supplier<? extends CommonRenderer>> commonRenderer) {
|
||||
this.name = name;
|
||||
this.cycleGroup = cycleGroup;
|
||||
this.displayName = displayName;
|
||||
this.soundType = soundType;
|
||||
this.contactParticle = contactParticle;
|
||||
this.smokeParticle = smokeParticle;
|
||||
this.defaultData = defaultData;
|
||||
|
||||
this.sizes = sizes;
|
||||
|
||||
this.commonRendererFactory = commonRenderer;
|
||||
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)
|
||||
.filter(sizes::containsKey)
|
||||
.findFirst()
|
||||
.map(size -> ForgeRegistries.BLOCKS.getValue(sizes.get(size).block()))
|
||||
.orElse(ForgeRegistries.BLOCKS.getValue(sizes.get(currentSize).block()));
|
||||
}
|
||||
|
||||
public Block getBlockOfSize(BogeySizes.BogeySize size) {
|
||||
return ForgeRegistries.BLOCKS.getValue(sizes.get(size).block());
|
||||
}
|
||||
|
||||
public Set<BogeySizes.BogeySize> validSizes() {
|
||||
return sizes.keySet();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public SoundEvent getSoundType() {
|
||||
AllSoundEvents.SoundEntry entry = AllSoundEvents.ALL.get(this.soundType);
|
||||
if (entry == null || entry.getMainEvent() == null) entry = AllSoundEvents.TRAIN2;
|
||||
return entry.getMainEvent();
|
||||
}
|
||||
|
||||
public BogeyRenderer createRendererInstance(BogeySizes.BogeySize size) {
|
||||
return this.sizes.get(size).createRenderInstance();
|
||||
}
|
||||
|
||||
public BogeyRenderer getInWorldRenderInstance(BogeySizes.BogeySize size) {
|
||||
SizeData sizeData = this.sizes.get(size);
|
||||
return sizeData != null ? sizeData.getInWorldInstance() : BackupBogeyRenderer.INSTANCE;
|
||||
}
|
||||
|
||||
public Optional<CommonRenderer> getInWorldCommonRenderInstance() {
|
||||
return this.commonRenderer;
|
||||
}
|
||||
|
||||
public Optional<CommonRenderer> getNewCommonRenderInstance() {
|
||||
return this.commonRendererFactory.map(Supplier::get);
|
||||
}
|
||||
|
||||
public BogeyInstance createInstance(CarriageBogey bogey, BogeySizes.BogeySize size, MaterialManager materialManager) {
|
||||
return new BogeyInstance(bogey, this, size, materialManager);
|
||||
}
|
||||
|
||||
public record SizeData(ResourceLocation block, Supplier<? extends BogeyRenderer> rendererFactory, BogeyRenderer instance) {
|
||||
public BogeyRenderer createRenderInstance() {
|
||||
return rendererFactory.get();
|
||||
}
|
||||
|
||||
public BogeyRenderer getInWorldInstance() {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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,26 +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(tp -> tp.getPosition(train.graph));
|
||||
} else {
|
||||
dce.rotationAnchors
|
||||
.setFirst(leadingBogey.points.getFirst() == point ? point.getPosition(train.graph)
|
||||
: pivoted(dce, dimension, point, leadingWheelSpacing));
|
||||
dce.rotationAnchors
|
||||
.setSecond(leadingBogey.points.getSecond() == point ? point.getPosition(train.graph)
|
||||
: pivoted(dce, dimension, point, leadingWheelSpacing));
|
||||
dce.rotationAnchors.setFirst(leadingBogey.points.getFirst() == point
|
||||
? point.getPosition(train.graph)
|
||||
: pivoted(dce, dimension, point, leadingWheelSpacing, leadingUpsideDown, trailingUpsideDown));
|
||||
dce.rotationAnchors.setSecond(leadingBogey.points.getSecond() == point
|
||||
? point.getPosition(train.graph)
|
||||
: pivoted(dce, dimension, point, leadingWheelSpacing, leadingUpsideDown, trailingUpsideDown));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -358,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(train.graph);
|
||||
boolean flipped = start != getLeadingPoint() && (leadingUpsideDown != trailingUpsideDown);
|
||||
Vec3 startVec = start.getPosition(train.graph, 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +1,21 @@
|
|||
package com.simibubi.create.content.logistics.trains.entity;
|
||||
|
||||
import static com.simibubi.create.content.logistics.trains.track.AbstractBogeyBlockEntity.BOGEY_DATA_KEY;
|
||||
import static com.simibubi.create.content.logistics.trains.track.AbstractBogeyBlockEntity.BOGEY_STYLE_KEY;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.api.MaterialManager;
|
||||
import com.simibubi.create.AllBogeyStyles;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock;
|
||||
import com.simibubi.create.content.logistics.trains.DimensionPalette;
|
||||
import com.simibubi.create.content.logistics.trains.IBogeyBlock;
|
||||
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
||||
import com.simibubi.create.content.logistics.trains.track.AbstractBogeyBlockEntity;
|
||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
import com.simibubi.create.foundation.utility.RegisteredObjects;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import com.simibubi.create.foundation.utility.animation.LerpedFloat;
|
||||
|
@ -27,11 +33,15 @@ import net.minecraftforge.registries.ForgeRegistries;
|
|||
|
||||
public class CarriageBogey {
|
||||
|
||||
public Carriage carriage;
|
||||
public static final String UPSIDE_DOWN_KEY = "UpsideDown";
|
||||
|
||||
public Carriage carriage;
|
||||
boolean isLeading;
|
||||
|
||||
IBogeyBlock type;
|
||||
public CompoundTag bogeyData;
|
||||
|
||||
AbstractBogeyBlock<?> type;
|
||||
boolean upsideDown;
|
||||
Couple<TravellingPoint> points;
|
||||
|
||||
LerpedFloat wheelAngle;
|
||||
|
@ -42,8 +52,15 @@ public class CarriageBogey {
|
|||
|
||||
int derailAngle;
|
||||
|
||||
public CarriageBogey(IBogeyBlock type, TravellingPoint point, TravellingPoint point2) {
|
||||
public CarriageBogey(AbstractBogeyBlock<?> type, boolean upsideDown, CompoundTag bogeyData, TravellingPoint point, TravellingPoint point2) {
|
||||
this.type = type;
|
||||
this.upsideDown = type.canBeUpsideDown() && upsideDown;
|
||||
point.upsideDown = this.upsideDown;
|
||||
point2.upsideDown = this.upsideDown;
|
||||
if (bogeyData == null || bogeyData.isEmpty())
|
||||
bogeyData = this.createBogeyData(); // Prevent Crash When Updating
|
||||
bogeyData.putBoolean(UPSIDE_DOWN_KEY, upsideDown);
|
||||
this.bogeyData = bogeyData;
|
||||
points = Couple.create(point, point2);
|
||||
wheelAngle = LerpedFloat.angular();
|
||||
yaw = LerpedFloat.angular();
|
||||
|
@ -100,11 +117,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() {
|
||||
|
@ -118,18 +139,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(carriage.train.graph)
|
||||
.getPosition(carriage.train.graph, flipUpsideDown)
|
||||
.add(points.getSecond()
|
||||
.getPosition(carriage.train.graph))
|
||||
.getPosition(carriage.train.graph, 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);
|
||||
|
@ -141,6 +169,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));
|
||||
}
|
||||
|
@ -150,23 +180,46 @@ public class CarriageBogey {
|
|||
tag.putString("Type", RegisteredObjects.getKeyOrThrow((Block) type)
|
||||
.toString());
|
||||
tag.put("Points", points.serializeEach(tp -> tp.write(dimensions)));
|
||||
tag.putBoolean("UpsideDown", upsideDown);
|
||||
bogeyData.putBoolean(UPSIDE_DOWN_KEY, upsideDown);
|
||||
NBTHelper.writeResourceLocation(bogeyData, BOGEY_STYLE_KEY, getStyle().name);
|
||||
tag.put(BOGEY_DATA_KEY, bogeyData);
|
||||
return tag;
|
||||
}
|
||||
|
||||
public static CarriageBogey read(CompoundTag tag, TrackGraph graph, DimensionPalette dimensions) {
|
||||
ResourceLocation location = new ResourceLocation(tag.getString("Type"));
|
||||
IBogeyBlock type = (IBogeyBlock) ForgeRegistries.BLOCKS.getValue(location);
|
||||
AbstractBogeyBlock<?> type = (AbstractBogeyBlock<?>) ForgeRegistries.BLOCKS.getValue(location);
|
||||
boolean upsideDown = tag.getBoolean("UpsideDown");
|
||||
Couple<TravellingPoint> points = Couple.deserializeEach(tag.getList("Points", Tag.TAG_COMPOUND),
|
||||
c -> TravellingPoint.read(c, graph, dimensions));
|
||||
CarriageBogey carriageBogey = new CarriageBogey(type, points.getFirst(), points.getSecond());
|
||||
return carriageBogey;
|
||||
CompoundTag data = tag.getCompound(AbstractBogeyBlockEntity.BOGEY_DATA_KEY);
|
||||
return new CarriageBogey(type, upsideDown, data, points.getFirst(), points.getSecond());
|
||||
}
|
||||
|
||||
public BogeyInstance createInstance(MaterialManager materialManager) {
|
||||
return type.createInstance(materialManager, this);
|
||||
return this.getStyle().createInstance(this, type.getSize(), materialManager);
|
||||
}
|
||||
|
||||
public BogeyStyle getStyle() {
|
||||
ResourceLocation location = NBTHelper.readResourceLocation(this.bogeyData, BOGEY_STYLE_KEY);
|
||||
BogeyStyle style = AllBogeyStyles.BOGEY_STYLES.get(location);
|
||||
return style != null ? style : AllBogeyStyles.STANDARD; // just for safety
|
||||
}
|
||||
|
||||
private CompoundTag createBogeyData() {
|
||||
BogeyStyle style = type != null ? type.getDefaultStyle() : AllBogeyStyles.STANDARD;
|
||||
CompoundTag nbt = style.defaultData != null ? style.defaultData : new CompoundTag();
|
||||
NBTHelper.writeResourceLocation(nbt, BOGEY_STYLE_KEY, style.name);
|
||||
nbt.putBoolean(UPSIDE_DOWN_KEY, isUpsideDown());
|
||||
return nbt;
|
||||
}
|
||||
|
||||
void setLeading() {
|
||||
isLeading = true;
|
||||
}
|
||||
|
||||
public boolean isUpsideDown() {
|
||||
return type.canBeUpsideDown() && upsideDown;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.ren
|
|||
import com.simibubi.create.content.contraptions.components.structureMovement.train.TrainCargoManager;
|
||||
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock;
|
||||
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel;
|
||||
import com.simibubi.create.content.logistics.trains.IBogeyBlock;
|
||||
import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
|
@ -71,7 +71,7 @@ public class CarriageContraption extends Contraption {
|
|||
// render
|
||||
public int portalCutoffMin;
|
||||
public int portalCutoffMax;
|
||||
|
||||
|
||||
static final IItemHandlerModifiable fallbackItems = new ItemStackHandler();
|
||||
static final IFluidHandler fallbackFluids = new FluidTank(0);
|
||||
|
||||
|
@ -162,11 +162,13 @@ public class CarriageContraption extends Contraption {
|
|||
.getStep(), toLocalPos(pos));
|
||||
}
|
||||
|
||||
if (blockState.getBlock() instanceof IBogeyBlock) {
|
||||
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)
|
||||
|
@ -235,7 +237,7 @@ public class CarriageContraption extends Contraption {
|
|||
protected MountedStorageManager getStorageForSpawnPacket() {
|
||||
return storageProxy;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected ContraptionType getType() {
|
||||
return ContraptionType.CARRIAGE;
|
||||
|
|
|
@ -13,6 +13,7 @@ import net.minecraft.client.renderer.culling.Frustum;
|
|||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.LightLayer;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer<CarriageContraptionEntity> {
|
||||
|
@ -37,7 +38,7 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer
|
|||
MultiBufferSource buffers, int overlay) {
|
||||
if (!entity.validForRender || entity.firstPositionUpdate)
|
||||
return;
|
||||
|
||||
|
||||
super.render(entity, yaw, partialTicks, ms, buffers, overlay);
|
||||
|
||||
Carriage carriage = entity.getCarriage();
|
||||
|
@ -65,8 +66,9 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer
|
|||
translateBogey(ms, bogey, bogeySpacing, viewYRot, viewXRot, partialTicks);
|
||||
|
||||
int light = getBogeyLightCoords(entity, bogey, partialTicks);
|
||||
|
||||
bogey.type.render(null, bogey.wheelAngle.getValue(partialTicks), ms, partialTicks, buffers, light,
|
||||
overlay);
|
||||
overlay, bogey.getStyle(), bogey.bogeyData);
|
||||
|
||||
ms.popPose();
|
||||
}
|
||||
|
@ -80,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)
|
||||
|
@ -90,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) {
|
||||
|
|
|
@ -7,6 +7,7 @@ import com.jozufozu.flywheel.util.AnimationTickHolder;
|
|||
import com.jozufozu.flywheel.util.transform.TransformStack;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Vector3f;
|
||||
import com.simibubi.create.content.logistics.trains.BogeyRenderer;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
|
||||
|
@ -31,7 +32,8 @@ public class CarriageContraptionInstance extends EntityInstance<CarriageContrapt
|
|||
if (carriage == null)
|
||||
return;
|
||||
|
||||
bogeys = carriage.bogeys.mapNotNullWithParam(CarriageBogey::createInstance, materialManager);
|
||||
bogeys = carriage.bogeys.mapNotNullWithParam((bogey, manager) ->
|
||||
bogey.getStyle().createInstance(bogey, bogey.type.getSize(), manager), materialManager);
|
||||
updateLight();
|
||||
}
|
||||
|
||||
|
@ -98,8 +100,10 @@ public class CarriageContraptionInstance extends EntityInstance<CarriageContrapt
|
|||
return;
|
||||
|
||||
bogeys.forEach(instance -> {
|
||||
if (instance != null)
|
||||
instance.remove();
|
||||
if (instance != null) {
|
||||
instance.commonRenderer.ifPresent(BogeyRenderer::remove);
|
||||
instance.renderer.remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -79,7 +79,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++) {
|
||||
|
|
|
@ -10,7 +10,6 @@ import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser;
|
|||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.Direction.Axis;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
@ -110,7 +109,7 @@ public class CarriageParticles {
|
|||
|
||||
m = m.add(contraptionMotion.scale(.75f));
|
||||
|
||||
level.addParticle(spark ? ParticleTypes.CRIT : ParticleTypes.POOF, v.x, v.y, v.z, m.x, m.y, m.z);
|
||||
level.addParticle(spark ? bogey.getStyle().contactParticle : bogey.getStyle().smokeParticle, v.x, v.y, v.z, m.x, m.y, m.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.simibubi.create.content.logistics.trains.entity;
|
|||
import com.simibubi.create.AllSoundEvents;
|
||||
import com.simibubi.create.AllSoundEvents.SoundEntry;
|
||||
import com.simibubi.create.content.logistics.trains.entity.Carriage.DimensionalCarriageEntity;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.animation.LerpedFloat;
|
||||
import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser;
|
||||
|
||||
|
@ -29,6 +30,9 @@ public class CarriageSounds {
|
|||
LoopingSound sharedWheelSoundSeated;
|
||||
LoopingSound sharedHonkSound;
|
||||
|
||||
Couple<SoundEvent> bogeySounds;
|
||||
SoundEvent closestBogeySound;
|
||||
|
||||
boolean arrived;
|
||||
|
||||
int tick;
|
||||
|
@ -36,6 +40,10 @@ public class CarriageSounds {
|
|||
|
||||
public CarriageSounds(CarriageContraptionEntity entity) {
|
||||
this.entity = entity;
|
||||
bogeySounds = entity.getCarriage().bogeys.map(bogey ->
|
||||
bogey != null && bogey.getStyle() != null ? bogey.getStyle().getSoundType()
|
||||
: AllSoundEvents.TRAIN2.getMainEvent());
|
||||
closestBogeySound = bogeySounds.getFirst();
|
||||
distanceFactor = LerpedFloat.linear();
|
||||
speedFactor = LerpedFloat.linear();
|
||||
approachFactor = LerpedFloat.linear();
|
||||
|
@ -79,6 +87,15 @@ public class CarriageSounds {
|
|||
double distance1 = toBogey1.length();
|
||||
double distance2 = toBogey2.length();
|
||||
|
||||
Couple<CarriageBogey> bogeys = entity.getCarriage().bogeys;
|
||||
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);
|
||||
Vec3 soundLocation = cam.add(toCarriage);
|
||||
|
@ -97,7 +114,7 @@ public class CarriageSounds {
|
|||
seatCrossfade.tickChaser();
|
||||
|
||||
minecartEsqueSound = playIfMissing(mc, minecartEsqueSound, AllSoundEvents.TRAIN.getMainEvent());
|
||||
sharedWheelSound = playIfMissing(mc, sharedWheelSound, AllSoundEvents.TRAIN2.getMainEvent());
|
||||
sharedWheelSound = playIfMissing(mc, sharedWheelSound, closestBogeySound);
|
||||
sharedWheelSoundSeated = playIfMissing(mc, sharedWheelSoundSeated, AllSoundEvents.TRAIN3.getMainEvent());
|
||||
|
||||
float volume = Math.min(Math.min(speedFactor.getValue(), distanceFactor.getValue() / 100),
|
||||
|
@ -205,7 +222,7 @@ public class CarriageSounds {
|
|||
public void submitSharedSoundVolume(Vec3 location, float volume) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
minecartEsqueSound = playIfMissing(mc, minecartEsqueSound, AllSoundEvents.TRAIN.getMainEvent());
|
||||
sharedWheelSound = playIfMissing(mc, sharedWheelSound, AllSoundEvents.TRAIN2.getMainEvent());
|
||||
sharedWheelSound = playIfMissing(mc, sharedWheelSound, closestBogeySound);
|
||||
sharedWheelSoundSeated = playIfMissing(mc, sharedWheelSoundSeated, AllSoundEvents.TRAIN3.getMainEvent());
|
||||
|
||||
boolean approach = true;
|
||||
|
|
|
@ -14,6 +14,8 @@ import java.util.UUID;
|
|||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.simibubi.create.content.logistics.trains.TrackMaterial;
|
||||
|
||||
import org.apache.commons.lang3.mutable.MutableDouble;
|
||||
import org.apache.commons.lang3.mutable.MutableObject;
|
||||
|
||||
|
@ -555,6 +557,21 @@ 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;
|
||||
|
||||
Map<TrackEdge, Integer> penalties = new IdentityHashMap<>();
|
||||
boolean costRelevant = maxCost >= 0;
|
||||
if (costRelevant) {
|
||||
|
@ -674,6 +691,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;
|
||||
|
|
|
@ -17,6 +17,10 @@ import java.util.function.Consumer;
|
|||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity;
|
||||
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
|
||||
import org.apache.commons.lang3.mutable.MutableBoolean;
|
||||
import org.apache.commons.lang3.mutable.MutableObject;
|
||||
|
||||
|
@ -124,7 +128,7 @@ public class Train {
|
|||
public int honkPitch;
|
||||
|
||||
public float accumulatedSteamRelease;
|
||||
|
||||
|
||||
int tickOffset;
|
||||
double[] stress;
|
||||
|
||||
|
@ -277,7 +281,7 @@ public class Train {
|
|||
int carriageCount = carriages.size();
|
||||
boolean stalled = false;
|
||||
double maxStress = 0;
|
||||
|
||||
|
||||
if (carriageWaitingForChunks != -1)
|
||||
distance = 0;
|
||||
|
||||
|
@ -313,11 +317,17 @@ 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++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (entries > 0)
|
||||
actual = total / entries;
|
||||
|
@ -369,13 +379,13 @@ public class Train {
|
|||
.getLeadingPoint();
|
||||
|
||||
double totalStress = derailed ? 0 : leadingStress + trailingStress;
|
||||
|
||||
|
||||
boolean first = i == 0;
|
||||
boolean last = i == carriageCount - 1;
|
||||
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);
|
||||
|
@ -722,9 +732,20 @@ 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 AbstractBogeyTileEntity sbte))
|
||||
continue;
|
||||
sbte.setBogeyData(bogey.bogeyData);
|
||||
}
|
||||
|
||||
offset += carriage.bogeySpacing;
|
||||
|
||||
if (i < carriageSpacing.size())
|
||||
|
@ -944,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);
|
||||
|
||||
|
|
|
@ -6,12 +6,13 @@ import java.util.Map;
|
|||
import java.util.UUID;
|
||||
|
||||
import com.simibubi.create.CreateClient;
|
||||
import com.simibubi.create.content.logistics.trains.IBogeyBlock;
|
||||
import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock;
|
||||
import com.simibubi.create.foundation.networking.SimplePacketBase;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.RegisteredObjects;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
|
@ -43,11 +44,13 @@ public class TrainPacket extends SimplePacketBase {
|
|||
int size = buffer.readVarInt();
|
||||
for (int i = 0; i < size; i++) {
|
||||
Couple<CarriageBogey> bogies = Couple.create(null, null);
|
||||
for (boolean first : Iterate.trueAndFalse) {
|
||||
if (!first && !buffer.readBoolean())
|
||||
for (boolean isFirst : Iterate.trueAndFalse) {
|
||||
if (!isFirst && !buffer.readBoolean())
|
||||
continue;
|
||||
IBogeyBlock type = (IBogeyBlock) ForgeRegistries.BLOCKS.getValue(buffer.readResourceLocation());
|
||||
bogies.set(first, new CarriageBogey(type, new TravellingPoint(), new TravellingPoint()));
|
||||
AbstractBogeyBlock<?> type = (AbstractBogeyBlock<?>) ForgeRegistries.BLOCKS.getValue(buffer.readResourceLocation());
|
||||
boolean upsideDown = buffer.readBoolean();
|
||||
CompoundTag data = buffer.readNbt();
|
||||
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));
|
||||
|
@ -85,6 +88,8 @@ 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);
|
||||
}
|
||||
|
|
|
@ -115,10 +115,13 @@ 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()
|
||||
|
@ -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.getChannel().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<>();
|
||||
|
|
|
@ -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,13 +397,18 @@ public class TravellingPoint {
|
|||
}
|
||||
|
||||
public Vec3 getPosition(@Nullable TrackGraph trackGraph) {
|
||||
return getPositionWithOffset(trackGraph, 0);
|
||||
return getPosition(trackGraph, false);
|
||||
}
|
||||
|
||||
public Vec3 getPositionWithOffset(@Nullable TrackGraph trackGraph, double offset) {
|
||||
public Vec3 getPosition(@Nullable TrackGraph trackGraph, boolean flipUpsideDown) {
|
||||
return getPositionWithOffset(trackGraph, 0, flipUpsideDown);
|
||||
}
|
||||
|
||||
public Vec3 getPositionWithOffset(@Nullable TrackGraph trackGraph, double offset, boolean flipUpsideDown) {
|
||||
double t = (position + offset) / edge.getLength();
|
||||
return edge.getPosition(trackGraph, t)
|
||||
.add(edge.getNormal(trackGraph, t));
|
||||
.add(edge.getNormal(trackGraph, t)
|
||||
.scale(upsideDown ^ flipUpsideDown ? -1 : 1));
|
||||
}
|
||||
|
||||
public void migrateTo(List<GraphLocation> locations) {
|
||||
|
@ -422,12 +429,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))
|
||||
|
@ -435,11 +443,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"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.ITr
|
|||
import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform;
|
||||
import com.simibubi.create.content.logistics.block.depot.DepotBehaviour;
|
||||
import com.simibubi.create.content.logistics.block.display.DisplayLinkBlock;
|
||||
import com.simibubi.create.content.logistics.trains.IBogeyBlock;
|
||||
import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock;
|
||||
import com.simibubi.create.content.logistics.trains.ITrackBlock;
|
||||
import com.simibubi.create.content.logistics.trains.TrackEdge;
|
||||
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
||||
|
@ -39,6 +39,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.AbstractBogeyTileEntity;
|
||||
import com.simibubi.create.foundation.advancement.AllAdvancements;
|
||||
import com.simibubi.create.foundation.block.ProperWaterloggedBlock;
|
||||
import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour;
|
||||
|
@ -52,6 +53,7 @@ import com.simibubi.create.foundation.utility.WorldAttached;
|
|||
import com.simibubi.create.foundation.utility.animation.LerpedFloat;
|
||||
import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser;
|
||||
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.BlockPos.MutableBlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
|
@ -67,6 +69,7 @@ import net.minecraft.world.InteractionHand;
|
|||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.SoundType;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.structure.BoundingBox;
|
||||
|
@ -192,7 +195,8 @@ public class StationBlockEntity extends SmartBlockEntity implements ITransformab
|
|||
Direction assemblyDirection;
|
||||
int assemblyLength;
|
||||
int[] bogeyLocations;
|
||||
IBogeyBlock[] bogeyTypes;
|
||||
AbstractBogeyBlock<?>[] bogeyTypes;
|
||||
boolean[] upsideDownBogeys;
|
||||
int bogeyCount;
|
||||
|
||||
@Override
|
||||
|
@ -269,14 +273,30 @@ public class StationBlockEntity extends SmartBlockEntity implements ITransformab
|
|||
return false;
|
||||
|
||||
BlockPos up = new BlockPos(track.getUpNormal(level, pos, state));
|
||||
BlockPos down = new BlockPos(track.getUpNormal(level, pos, state).scale(-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 IBogeyBlock bogey) {
|
||||
level.setBlock(bogeyPos, bogey.getRotatedBlockState(blockState, Direction.DOWN), 3);
|
||||
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))
|
||||
continue;
|
||||
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;
|
||||
}
|
||||
|
@ -291,7 +311,9 @@ public class StationBlockEntity extends SmartBlockEntity implements ITransformab
|
|||
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;
|
||||
|
@ -299,7 +321,11 @@ public class StationBlockEntity extends SmartBlockEntity implements ITransformab
|
|||
|
||||
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()
|
||||
|
@ -373,9 +399,12 @@ public class StationBlockEntity extends SmartBlockEntity implements ITransformab
|
|||
if (bogeyLocations == null)
|
||||
bogeyLocations = new int[maxBogeyCount];
|
||||
if (bogeyTypes == null)
|
||||
bogeyTypes = new IBogeyBlock[maxBogeyCount];
|
||||
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) {
|
||||
|
@ -388,10 +417,19 @@ public class StationBlockEntity extends SmartBlockEntity implements ITransformab
|
|||
}
|
||||
|
||||
BlockState potentialBogeyState = level.getBlockState(bogeyOffset.offset(currentPos));
|
||||
if (potentialBogeyState.getBlock() instanceof IBogeyBlock 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);
|
||||
|
@ -551,7 +589,7 @@ public class StationBlockEntity extends SmartBlockEntity implements ITransformab
|
|||
return;
|
||||
}
|
||||
|
||||
points.add(new TravellingPoint(node, secondNode, edge, positionOnEdge));
|
||||
points.add(new TravellingPoint(node, secondNode, edge, positionOnEdge, false));
|
||||
}
|
||||
|
||||
secondNode = node;
|
||||
|
@ -578,10 +616,11 @@ public class StationBlockEntity extends SmartBlockEntity implements ITransformab
|
|||
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) {
|
||||
|
@ -594,24 +633,28 @@ public class StationBlockEntity extends SmartBlockEntity implements ITransformab
|
|||
return;
|
||||
}
|
||||
|
||||
IBogeyBlock typeOfFirstBogey = bogeyTypes[bogeyIndex];
|
||||
AbstractBogeyBlock<?> typeOfFirstBogey = bogeyTypes[bogeyIndex];
|
||||
boolean firstBogeyIsUpsideDown = upsideDownBogeys[bogeyIndex];
|
||||
BlockPos firstBogeyPos = contraption.anchor;
|
||||
AbstractBogeyTileEntity firstBogeyTileEntity = (AbstractBogeyTileEntity) level.getBlockEntity(firstBogeyPos);
|
||||
CarriageBogey firstBogey =
|
||||
new CarriageBogey(typeOfFirstBogey, 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;
|
||||
}
|
||||
|
||||
AbstractBogeyTileEntity secondBogeyTileEntity =
|
||||
(AbstractBogeyTileEntity) level.getBlockEntity(secondBogeyPos);
|
||||
bogeySpacing = bogeyLocations[bogeyIndex + 1] - bogeyLocations[bogeyIndex];
|
||||
secondBogey = new CarriageBogey(bogeyTypes[bogeyIndex + 1], points.get(pointIndex + 2),
|
||||
points.get(pointIndex + 3));
|
||||
secondBogey = new CarriageBogey(bogeyTypes[bogeyIndex + 1], upsideDownBogeys[bogeyIndex + 1], secondBogeyTileEntity.getBogeyData(),
|
||||
points.get(pointIndex + 2), points.get(pointIndex + 3));
|
||||
bogeyIndex++;
|
||||
|
||||
} else if (!typeOfFirstBogey.allowsSingleBogeyCarriage()) {
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
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;
|
||||
|
||||
import static com.simibubi.create.content.logistics.trains.entity.CarriageBogey.UPSIDE_DOWN_KEY;
|
||||
|
||||
public abstract class AbstractBogeyTileEntity extends CachedRenderBBTileEntity {
|
||||
public static final String BOGEY_STYLE_KEY = "BogeyStyle";
|
||||
public static final 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);
|
||||
boolean upsideDown = false;
|
||||
if (getBlockState().getBlock() instanceof AbstractBogeyBlock<?> bogeyBlock)
|
||||
upsideDown = bogeyBlock.isUpsideDown(getBlockState());
|
||||
nbt.putBoolean(UPSIDE_DOWN_KEY, upsideDown);
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package com.simibubi.create.content.logistics.trains.track;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.AllTags;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBlockItem;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackBlockOutline.BezierPointSelection;
|
||||
import com.simibubi.create.foundation.networking.AllPackets;
|
||||
|
@ -117,7 +117,7 @@ public class CurvedTrackInteraction {
|
|||
if (event.isUseItem()) {
|
||||
ItemStack heldItem = player.getMainHandItem();
|
||||
Item item = heldItem.getItem();
|
||||
if (AllBlocks.TRACK.isIn(heldItem)) {
|
||||
if (AllTags.AllBlockTags.TRACKS.matches(heldItem)) {
|
||||
player.displayClientMessage(Lang.translateDirect("track.turn_start")
|
||||
.withStyle(ChatFormatting.RED), true);
|
||||
player.swing(InteractionHand.MAIN_HAND);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package com.simibubi.create.content.logistics.trains.track;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllTags;
|
||||
import com.simibubi.create.foundation.networking.SimplePacketBase;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
|
@ -14,7 +14,7 @@ public class PlaceExtendedCurvePacket extends SimplePacketBase {
|
|||
|
||||
boolean mainHand;
|
||||
boolean ctrlDown;
|
||||
|
||||
|
||||
public PlaceExtendedCurvePacket(boolean mainHand, boolean ctrlDown) {
|
||||
this.mainHand = mainHand;
|
||||
this.ctrlDown = ctrlDown;
|
||||
|
@ -36,7 +36,7 @@ public class PlaceExtendedCurvePacket extends SimplePacketBase {
|
|||
context.enqueueWork(() -> {
|
||||
ServerPlayer sender = context.getSender();
|
||||
ItemStack stack = sender.getItemInHand(mainHand ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND);
|
||||
if (!AllBlocks.TRACK.isIn(stack) || !stack.hasTag())
|
||||
if (!AllTags.AllBlockTags.TRACKS.matches(stack) || !stack.hasTag())
|
||||
return;
|
||||
CompoundTag tag = stack.getTag();
|
||||
tag.putBoolean("ExtendCurve", true);
|
||||
|
|
|
@ -1,87 +1,36 @@
|
|||
package com.simibubi.create.content.logistics.trains.track;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
import com.jozufozu.flywheel.api.MaterialManager;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import com.mojang.math.Vector3f;
|
||||
import com.simibubi.create.AllBlockEntityTypes;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllPartialModels;
|
||||
import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock;
|
||||
import com.simibubi.create.content.logistics.trains.IBogeyBlock;
|
||||
import com.simibubi.create.content.logistics.trains.entity.BogeyInstance;
|
||||
import com.simibubi.create.content.logistics.trains.entity.CarriageBogey;
|
||||
import com.simibubi.create.AllBogeyStyles;
|
||||
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.content.schematics.ItemRequirement;
|
||||
import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType;
|
||||
import com.simibubi.create.foundation.block.IBE;
|
||||
import com.simibubi.create.foundation.block.ProperWaterloggedBlock;
|
||||
import com.simibubi.create.foundation.render.CachedBufferer;
|
||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
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.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.Rotation;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition.Builder;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.level.block.state.properties.EnumProperty;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
public class StandardBogeyBlock extends Block
|
||||
implements IBogeyBlock, IBE<StandardBogeyBlockEntity>, ProperWaterloggedBlock, ISpecialBlockItemRequirement {
|
||||
public class StandardBogeyBlock extends AbstractBogeyBlock<StandardBogeyBlockEntity>
|
||||
implements IBE<StandardBogeyBlockEntity>, ProperWaterloggedBlock, ISpecialBlockItemRequirement {
|
||||
|
||||
public static final EnumProperty<Axis> AXIS = BlockStateProperties.HORIZONTAL_AXIS;
|
||||
private final boolean large;
|
||||
|
||||
public StandardBogeyBlock(Properties p_i48440_1_, boolean large) {
|
||||
super(p_i48440_1_);
|
||||
this.large = large;
|
||||
public StandardBogeyBlock(Properties props, BogeySizes.BogeySize size) {
|
||||
super(props, size);
|
||||
registerDefaultState(defaultBlockState().setValue(WATERLOGGED, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createBlockStateDefinition(Builder<Block, BlockState> builder) {
|
||||
builder.add(AXIS, WATERLOGGED);
|
||||
super.createBlockStateDefinition(builder);
|
||||
}
|
||||
|
||||
static final EnumSet<Direction> STICKY_X = EnumSet.of(Direction.EAST, Direction.WEST);
|
||||
static final EnumSet<Direction> STICKY_Z = EnumSet.of(Direction.SOUTH, Direction.NORTH);
|
||||
|
||||
@Override
|
||||
public EnumSet<Direction> getStickySurfaces(BlockGetter world, BlockPos pos, BlockState state) {
|
||||
return state.getValue(BlockStateProperties.HORIZONTAL_AXIS) == Axis.X ? STICKY_X : STICKY_Z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState updateShape(BlockState pState, Direction pDirection, BlockState pNeighborState,
|
||||
LevelAccessor pLevel, BlockPos pCurrentPos, BlockPos pNeighborPos) {
|
||||
updateWater(pLevel, pState, pCurrentPos);
|
||||
return pState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidState getFluidState(BlockState pState) {
|
||||
return fluidState(pState);
|
||||
public TrackMaterial.TrackType getTrackType(BogeyStyle style) {
|
||||
return TrackMaterial.TrackType.STANDARD;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -91,7 +40,7 @@ public class StandardBogeyBlock extends Block
|
|||
|
||||
@Override
|
||||
public double getWheelRadius() {
|
||||
return (large ? 12.5 : 6.5) / 16d;
|
||||
return (size == BogeySizes.LARGE ? 12.5 : 6.5) / 16d;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -100,122 +49,8 @@ public class StandardBogeyBlock extends Block
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean allowsSingleBogeyCarriage() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getMatchingBogey(Direction upDirection, boolean axisAlongFirst) {
|
||||
if (upDirection != Direction.UP)
|
||||
return null;
|
||||
return defaultBlockState().setValue(AXIS, axisAlongFirst ? Axis.X : Axis.Z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTrackAxisAlongFirstCoordinate(BlockState state) {
|
||||
return state.getValue(AXIS) == Axis.X;
|
||||
}
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void render(BlockState state, float wheelAngle, PoseStack ms, float partialTicks, MultiBufferSource buffers,
|
||||
int light, int overlay) {
|
||||
if (state != null) {
|
||||
ms.translate(.5f, .5f, .5f);
|
||||
if (state.getValue(AXIS) == Axis.X)
|
||||
ms.mulPose(Vector3f.YP.rotationDegrees(90));
|
||||
}
|
||||
|
||||
ms.translate(0, -1.5 - 1 / 128f, 0);
|
||||
|
||||
VertexConsumer vb = buffers.getBuffer(RenderType.cutoutMipped());
|
||||
BlockState air = Blocks.AIR.defaultBlockState();
|
||||
|
||||
for (int i : Iterate.zeroAndOne)
|
||||
CachedBufferer.block(AllBlocks.SHAFT.getDefaultState()
|
||||
.setValue(ShaftBlock.AXIS, Axis.Z))
|
||||
.translate(-.5f, .25f, i * -1)
|
||||
.centre()
|
||||
.rotateZ(wheelAngle)
|
||||
.unCentre()
|
||||
.light(light)
|
||||
.renderInto(ms, vb);
|
||||
|
||||
if (large) {
|
||||
renderLargeBogey(wheelAngle, ms, light, vb, air);
|
||||
} else {
|
||||
renderBogey(wheelAngle, ms, light, vb, air);
|
||||
}
|
||||
}
|
||||
|
||||
private void renderBogey(float wheelAngle, PoseStack ms, int light, VertexConsumer vb, BlockState air) {
|
||||
CachedBufferer.partial(AllPartialModels.BOGEY_FRAME, air)
|
||||
.scale(1 - 1 / 512f)
|
||||
.light(light)
|
||||
.renderInto(ms, vb);
|
||||
|
||||
for (int side : Iterate.positiveAndNegative) {
|
||||
ms.pushPose();
|
||||
CachedBufferer.partial(AllPartialModels.SMALL_BOGEY_WHEELS, air)
|
||||
.translate(0, 12 / 16f, side)
|
||||
.rotateX(wheelAngle)
|
||||
.light(light)
|
||||
.renderInto(ms, vb);
|
||||
ms.popPose();
|
||||
}
|
||||
}
|
||||
|
||||
private void renderLargeBogey(float wheelAngle, PoseStack ms, int light, VertexConsumer vb, BlockState air) {
|
||||
for (int i : Iterate.zeroAndOne)
|
||||
CachedBufferer.block(AllBlocks.SHAFT.getDefaultState()
|
||||
.setValue(ShaftBlock.AXIS, Axis.X))
|
||||
.translate(-.5f, .25f, .5f + i * -2)
|
||||
.centre()
|
||||
.rotateX(wheelAngle)
|
||||
.unCentre()
|
||||
.light(light)
|
||||
.renderInto(ms, vb);
|
||||
|
||||
CachedBufferer.partial(AllPartialModels.BOGEY_DRIVE, air)
|
||||
.scale(1 - 1 / 512f)
|
||||
.light(light)
|
||||
.renderInto(ms, vb);
|
||||
CachedBufferer.partial(AllPartialModels.BOGEY_PISTON, air)
|
||||
.translate(0, 0, 1 / 4f * Math.sin(AngleHelper.rad(wheelAngle)))
|
||||
.light(light)
|
||||
.renderInto(ms, vb);
|
||||
|
||||
ms.pushPose();
|
||||
CachedBufferer.partial(AllPartialModels.LARGE_BOGEY_WHEELS, air)
|
||||
.translate(0, 1, 0)
|
||||
.rotateX(wheelAngle)
|
||||
.light(light)
|
||||
.renderInto(ms, vb);
|
||||
CachedBufferer.partial(AllPartialModels.BOGEY_PIN, air)
|
||||
.translate(0, 1, 0)
|
||||
.rotateX(wheelAngle)
|
||||
.translate(0, 1 / 4f, 0)
|
||||
.rotateX(-wheelAngle)
|
||||
.light(light)
|
||||
.renderInto(ms, vb);
|
||||
ms.popPose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BogeyInstance createInstance(MaterialManager materialManager, CarriageBogey bogey) {
|
||||
if (large) {
|
||||
return new BogeyInstance.Drive(bogey, materialManager);
|
||||
} else {
|
||||
return new BogeyInstance.Frame(bogey, materialManager);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState rotate(BlockState pState, Rotation pRotation) {
|
||||
return switch (pRotation) {
|
||||
case COUNTERCLOCKWISE_90, CLOCKWISE_90 -> pState.cycle(AXIS);
|
||||
default -> pState;
|
||||
};
|
||||
public BogeyStyle getDefaultStyle() {
|
||||
return AllBogeyStyles.STANDARD;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -234,9 +69,4 @@ public class StandardBogeyBlock extends Block
|
|||
return AllBlockEntityTypes.BOGEY.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemRequirement getRequiredItems(BlockState state, BlockEntity be) {
|
||||
return new ItemRequirement(ItemUseType.CONSUME, AllBlocks.RAILWAY_CASING.asStack());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,40 +1,20 @@
|
|||
package com.simibubi.create.content.logistics.trains.track;
|
||||
|
||||
import com.simibubi.create.content.logistics.trains.IBogeyBlock;
|
||||
import com.simibubi.create.foundation.blockEntity.CachedRenderBBBlockEntity;
|
||||
import com.simibubi.create.foundation.utility.animation.LerpedFloat;
|
||||
import com.simibubi.create.AllBogeyStyles;
|
||||
import com.simibubi.create.content.logistics.trains.entity.BogeyStyle;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
|
||||
public class StandardBogeyBlockEntity extends CachedRenderBBBlockEntity {
|
||||
public class StandardBogeyBlockEntity extends AbstractBogeyBlockEntity {
|
||||
|
||||
public StandardBogeyBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
|
||||
super(type, pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AABB createRenderBoundingBox() {
|
||||
return super.createRenderBoundingBox().inflate(2);
|
||||
public BogeyStyle getDefaultStyle() {
|
||||
return AllBogeyStyles.STANDARD;
|
||||
}
|
||||
|
||||
// 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 IBogeyBlock type))
|
||||
return;
|
||||
double angleDiff = 360 * distanceMoved / (Math.PI * 2 * type.getWheelRadius());
|
||||
double newWheelAngle = (virtualAnimation.getValue() - angleDiff) % 360;
|
||||
virtualAnimation.setValue(newWheelAngle);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,12 +29,14 @@ import com.simibubi.create.AllBlockEntityTypes;
|
|||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllPartialModels;
|
||||
import com.simibubi.create.AllShapes;
|
||||
import com.simibubi.create.AllTags;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueEntity;
|
||||
import com.simibubi.create.content.contraptions.particle.CubeParticleData;
|
||||
import com.simibubi.create.content.contraptions.wrench.IWrenchable;
|
||||
import com.simibubi.create.content.curiosities.girder.GirderBlock;
|
||||
import com.simibubi.create.content.logistics.trains.BezierConnection;
|
||||
import com.simibubi.create.content.logistics.trains.ITrackBlock;
|
||||
import com.simibubi.create.content.logistics.trains.TrackMaterial;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNodeLocation;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNodeLocation.DiscoveredLocation;
|
||||
import com.simibubi.create.content.logistics.trains.TrackPropagator;
|
||||
|
@ -55,6 +57,8 @@ import com.simibubi.create.foundation.utility.Lang;
|
|||
import com.simibubi.create.foundation.utility.Pair;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
@ -113,11 +117,14 @@ public class TrackBlock extends Block
|
|||
public static final EnumProperty<TrackShape> SHAPE = EnumProperty.create("shape", TrackShape.class);
|
||||
public static final BooleanProperty HAS_BE = BooleanProperty.create("turn");
|
||||
|
||||
public TrackBlock(Properties p_49795_) {
|
||||
protected final TrackMaterial material;
|
||||
|
||||
public TrackBlock(Properties p_49795_, TrackMaterial material) {
|
||||
super(p_49795_);
|
||||
registerDefaultState(defaultBlockState().setValue(SHAPE, TrackShape.ZO)
|
||||
.setValue(HAS_BE, false)
|
||||
.setValue(WATERLOGGED, false));
|
||||
this.material = material;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -388,7 +395,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, v -> 0,
|
||||
axis, null);
|
||||
axis, null, (b, v) -> ITrackBlock.getMaterialSimple(world, v));
|
||||
} else
|
||||
list = ITrackBlock.super.getConnected(world, pos, state, linear, connectedTo);
|
||||
|
||||
|
@ -404,7 +411,8 @@ 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, bc::yOffsetAt, null, bc));
|
||||
b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, bc::yOffsetAt, null, bc,
|
||||
(b, v) -> ITrackBlock.getMaterialSimple(world, v, bc.getMaterial())));
|
||||
|
||||
if (trackTE.boundLocation == null || !(world instanceof ServerLevel level))
|
||||
return list;
|
||||
|
@ -416,7 +424,7 @@ public class TrackBlock extends Block
|
|||
return list;
|
||||
BlockPos boundPos = trackTE.boundLocation.getSecond();
|
||||
BlockState boundState = otherLevel.getBlockState(boundPos);
|
||||
if (!AllBlocks.TRACK.has(boundState))
|
||||
if (!AllTags.AllBlockTags.TRACKS.matches(boundState))
|
||||
return list;
|
||||
|
||||
Vec3 center = Vec3.atBottomCenterOf(pos)
|
||||
|
@ -430,7 +438,8 @@ 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(), v -> 0, axis, null);
|
||||
b -> b ? level.dimension() : otherLevel.dimension(), v -> 0, axis, null,
|
||||
(b, v) -> ITrackBlock.getMaterialSimple(b ? level : otherLevel, v));
|
||||
});
|
||||
|
||||
return list;
|
||||
|
@ -479,7 +488,7 @@ public class TrackBlock extends Block
|
|||
if (!entry.getValue()
|
||||
.isInside(pos))
|
||||
continue;
|
||||
if (world.getBlockEntity(entry.getKey())instanceof StationBlockEntity station)
|
||||
if (world.getBlockEntity(entry.getKey()) instanceof StationBlockEntity station)
|
||||
if (station.trackClicked(player, hand, this, state, pos))
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
@ -495,7 +504,7 @@ public class TrackBlock extends Block
|
|||
BlockPos girderPos = pPos.below()
|
||||
.offset(vec3.z * side, 0, vec3.x * side);
|
||||
BlockState girderState = pLevel.getBlockState(girderPos);
|
||||
if (girderState.getBlock()instanceof GirderBlock girderBlock
|
||||
if (girderState.getBlock() instanceof GirderBlock girderBlock
|
||||
&& !blockTicks.hasScheduledTick(girderPos, girderBlock))
|
||||
pLevel.scheduleTick(girderPos, girderBlock, 1);
|
||||
}
|
||||
|
@ -700,7 +709,7 @@ public class TrackBlock extends Block
|
|||
Vec3 normal = null;
|
||||
Vec3 offset = null;
|
||||
|
||||
if (bezierPoint != null && world.getBlockEntity(pos)instanceof TrackBlockEntity trackTE) {
|
||||
if (bezierPoint != null && world.getBlockEntity(pos) instanceof TrackBlockEntity trackTE) {
|
||||
BezierConnection bc = trackTE.connections.get(bezierPoint.curveTarget());
|
||||
if (bc != null) {
|
||||
double length = Mth.floor(bc.getLength() * 2);
|
||||
|
@ -745,7 +754,8 @@ public class TrackBlock extends Block
|
|||
msr.rotateCentered(Direction.UP, Mth.PI);
|
||||
}
|
||||
|
||||
if (bezierPoint == null && world.getBlockEntity(pos)instanceof TrackBlockEntity trackTE && trackTE.isTilted()) {
|
||||
if (bezierPoint == null && world.getBlockEntity(pos) instanceof TrackBlockEntity trackTE
|
||||
&& trackTE.isTilted()) {
|
||||
double yOffset = 0;
|
||||
for (BezierConnection bc : trackTE.connections.values())
|
||||
yOffset += bc.starts.getFirst().y - pos.getY();
|
||||
|
@ -771,7 +781,8 @@ public class TrackBlock extends Block
|
|||
|
||||
@Override
|
||||
public ItemRequirement getRequiredItems(BlockState state, BlockEntity be) {
|
||||
int trackAmount = 1;
|
||||
int sameTypeTrackAmount = 1;
|
||||
Object2IntMap<TrackMaterial> otherTrackAmounts = new Object2IntArrayMap<>();
|
||||
int girderAmount = 0;
|
||||
|
||||
if (be instanceof TrackBlockEntity track) {
|
||||
|
@ -779,15 +790,28 @@ public class TrackBlock extends Block
|
|||
.values()) {
|
||||
if (!bezierConnection.isPrimary())
|
||||
continue;
|
||||
trackAmount += bezierConnection.getTrackItemCost();
|
||||
TrackMaterial material = bezierConnection.getMaterial();
|
||||
if (material == getMaterial()) {
|
||||
sameTypeTrackAmount += bezierConnection.getTrackItemCost();
|
||||
} else {
|
||||
otherTrackAmounts.put(material, otherTrackAmounts.getOrDefault(material, 0) + 1);
|
||||
}
|
||||
girderAmount += bezierConnection.getGirderItemCost();
|
||||
}
|
||||
}
|
||||
|
||||
List<ItemStack> stacks = new ArrayList<>();
|
||||
while (trackAmount > 0) {
|
||||
stacks.add(AllBlocks.TRACK.asStack(Math.min(trackAmount, 64)));
|
||||
trackAmount -= 64;
|
||||
while (sameTypeTrackAmount > 0) {
|
||||
stacks.add(new ItemStack(state.getBlock(), Math.min(sameTypeTrackAmount, 64)));
|
||||
sameTypeTrackAmount -= 64;
|
||||
}
|
||||
for (TrackMaterial material : otherTrackAmounts.keySet()) {
|
||||
int amt = otherTrackAmounts.getOrDefault(material, 0);
|
||||
while (amt > 0) {
|
||||
stacks.add(new ItemStack(material.getTrackBlock()
|
||||
.get(), Math.min(amt, 64)));
|
||||
amt -= 64;
|
||||
}
|
||||
}
|
||||
while (girderAmount > 0) {
|
||||
stacks.add(AllBlocks.METAL_GIRDER.asStack(Math.min(girderAmount, 64)));
|
||||
|
@ -797,6 +821,11 @@ public class TrackBlock extends Block
|
|||
return new ItemRequirement(ItemUseType.CONSUME, stacks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackMaterial getMaterial() {
|
||||
return material;
|
||||
}
|
||||
|
||||
public static class RenderProperties extends ReducedDestroyEffects implements MultiPosDestructionHandler {
|
||||
@Override
|
||||
@Nullable
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.util.Set;
|
|||
|
||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllTags;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableBlockEntity;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform;
|
||||
import com.simibubi.create.content.logistics.trains.BezierConnection;
|
||||
|
@ -125,6 +126,9 @@ public class TrackBlockEntity extends SmartBlockEntity implements ITransformable
|
|||
}
|
||||
|
||||
public void addConnection(BezierConnection connection) {
|
||||
// don't replace existing connections with different materials
|
||||
if (connections.containsKey(connection.getKey()) && connection.equalsSansMaterial(connections.get(connection.getKey())))
|
||||
return;
|
||||
connections.put(connection.getKey(), connection);
|
||||
level.scheduleTick(worldPosition, getBlockState().getBlock(), 1);
|
||||
notifyUpdate();
|
||||
|
@ -326,7 +330,7 @@ public class TrackBlockEntity extends SmartBlockEntity implements ITransformable
|
|||
.getLevel(boundLocation.getFirst());
|
||||
if (otherLevel == null)
|
||||
return;
|
||||
if (AllBlocks.TRACK.has(otherLevel.getBlockState(boundLocation.getSecond())))
|
||||
if (AllTags.AllBlockTags.TRACKS.matches(otherLevel.getBlockState(boundLocation.getSecond())))
|
||||
otherLevel.destroyBlock(boundLocation.getSecond(), false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.simibubi.create.content.logistics.trains.track;
|
|||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllSoundEvents;
|
||||
import com.simibubi.create.AllTags;
|
||||
import com.simibubi.create.content.logistics.trains.ITrackBlock;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackPlacement.PlacementInfo;
|
||||
import com.simibubi.create.foundation.networking.AllPackets;
|
||||
|
@ -118,7 +119,7 @@ public class TrackBlockItem extends BlockItem {
|
|||
return InteractionResult.SUCCESS;
|
||||
|
||||
stack = player.getMainHandItem();
|
||||
if (AllBlocks.TRACK.isIn(stack)) {
|
||||
if (AllTags.AllBlockTags.TRACKS.matches(stack)) {
|
||||
stack.setTag(null);
|
||||
player.setItemInHand(pContext.getHand(), stack);
|
||||
}
|
||||
|
@ -161,7 +162,7 @@ public class TrackBlockItem extends BlockItem {
|
|||
@OnlyIn(Dist.CLIENT)
|
||||
public static void sendExtenderPacket(PlayerInteractEvent.RightClickBlock event) {
|
||||
ItemStack stack = event.getItemStack();
|
||||
if (!AllBlocks.TRACK.isIn(stack) || !stack.hasTag())
|
||||
if (!AllTags.AllBlockTags.TRACKS.matches(stack) || !stack.hasTag())
|
||||
return;
|
||||
if (Minecraft.getInstance().options.keySprint.isDown())
|
||||
AllPackets.getChannel()
|
||||
|
|
|
@ -8,8 +8,8 @@ import java.util.function.Consumer;
|
|||
import com.jozufozu.flywheel.util.transform.TransformStack;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllShapes;
|
||||
import com.simibubi.create.AllTags;
|
||||
import com.simibubi.create.content.logistics.trains.BezierConnection;
|
||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||
import com.simibubi.create.foundation.utility.AnimationTickHolder;
|
||||
|
@ -162,7 +162,7 @@ public class TrackBlockOutline {
|
|||
.rotateXRadians(angles.x)
|
||||
.translate(-.5, -.125f, -.5);
|
||||
|
||||
boolean holdingTrack = AllBlocks.TRACK.isIn(Minecraft.getInstance().player.getMainHandItem());
|
||||
boolean holdingTrack = AllTags.AllBlockTags.TRACKS.matches(Minecraft.getInstance().player.getMainHandItem());
|
||||
renderShape(AllShapes.TRACK_ORTHO.get(Direction.SOUTH), ms, vb, holdingTrack ? false : null);
|
||||
ms.popPose();
|
||||
}
|
||||
|
@ -190,7 +190,7 @@ public class TrackBlockOutline {
|
|||
ms.pushPose();
|
||||
ms.translate(pos.getX() - camPos.x, pos.getY() - camPos.y, pos.getZ() - camPos.z);
|
||||
|
||||
boolean holdingTrack = AllBlocks.TRACK.isIn(Minecraft.getInstance().player.getMainHandItem());
|
||||
boolean holdingTrack = AllTags.AllBlockTags.TRACKS.matches(Minecraft.getInstance().player.getMainHandItem());
|
||||
TrackShape shape = blockstate.getValue(TrackBlock.SHAPE);
|
||||
boolean canConnectFrom = !shape.isJunction()
|
||||
&& !(mc.level.getBlockEntity(pos)instanceof TrackBlockEntity tbe && tbe.isTilted());
|
||||
|
|
|
@ -20,6 +20,7 @@ import com.simibubi.create.AllPartialModels;
|
|||
import com.simibubi.create.content.logistics.trains.BezierConnection;
|
||||
import com.simibubi.create.content.logistics.trains.BezierConnection.GirderAngles;
|
||||
import com.simibubi.create.content.logistics.trains.BezierConnection.SegmentAngles;
|
||||
import com.simibubi.create.content.logistics.trains.TrackMaterial;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
|
||||
|
@ -38,7 +39,7 @@ public class TrackInstance extends BlockEntityInstance<TrackBlockEntity> {
|
|||
|
||||
@Override
|
||||
public void update() {
|
||||
if (blockEntity.connections.isEmpty())
|
||||
if (blockEntity.connections.isEmpty())
|
||||
return;
|
||||
|
||||
remove();
|
||||
|
@ -110,11 +111,13 @@ public class TrackInstance extends BlockEntityInstance<TrackBlockEntity> {
|
|||
leftLightPos = new BlockPos[segCount];
|
||||
rightLightPos = new BlockPos[segCount];
|
||||
|
||||
mat.getModel(AllPartialModels.TRACK_TIE)
|
||||
TrackMaterial.TrackModelHolder modelHolder = bc.getMaterial().getModelHolder();
|
||||
|
||||
mat.getModel(modelHolder.tie())
|
||||
.createInstances(ties);
|
||||
mat.getModel(AllPartialModels.TRACK_SEGMENT_LEFT)
|
||||
mat.getModel(modelHolder.segment_left())
|
||||
.createInstances(left);
|
||||
mat.getModel(AllPartialModels.TRACK_SEGMENT_RIGHT)
|
||||
mat.getModel(modelHolder.segment_right())
|
||||
.createInstances(right);
|
||||
|
||||
SegmentAngles[] segments = bc.getBakedSegments();
|
||||
|
|
|
@ -6,16 +6,17 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.jozufozu.flywheel.util.Color;
|
||||
import com.simibubi.create.AllSpecialTextures;
|
||||
import com.simibubi.create.AllTags;
|
||||
import com.simibubi.create.CreateClient;
|
||||
import com.simibubi.create.content.curiosities.tools.BlueprintOverlayRenderer;
|
||||
import com.simibubi.create.content.logistics.trains.BezierConnection;
|
||||
import com.simibubi.create.content.logistics.trains.ITrackBlock;
|
||||
import com.simibubi.create.content.logistics.trains.TrackMaterial;
|
||||
import com.simibubi.create.foundation.block.ProperWaterloggedBlock;
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||
import com.simibubi.create.foundation.utility.Color;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
|
@ -46,6 +47,7 @@ import net.minecraft.world.level.block.Block;
|
|||
import net.minecraft.world.level.block.EntityBlock;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.HitResult.Type;
|
||||
|
@ -57,6 +59,11 @@ import net.minecraftforge.items.ItemHandlerHelper;
|
|||
public class TrackPlacement {
|
||||
|
||||
public static class PlacementInfo {
|
||||
|
||||
public PlacementInfo(TrackMaterial material) {
|
||||
this.trackMaterial = material;
|
||||
}
|
||||
|
||||
BezierConnection curve = null;
|
||||
boolean valid = false;
|
||||
int end1Extent = 0;
|
||||
|
@ -68,6 +75,7 @@ public class TrackPlacement {
|
|||
|
||||
public int requiredPavement = 0;
|
||||
public boolean hasRequiredPavement = false;
|
||||
public final TrackMaterial trackMaterial;
|
||||
|
||||
// for visualisation
|
||||
Vec3 end1;
|
||||
|
@ -109,7 +117,7 @@ public class TrackPlacement {
|
|||
&& hoveringMaxed == maximiseTurn && lookAngle == hoveringAngle)
|
||||
return cached;
|
||||
|
||||
PlacementInfo info = new PlacementInfo();
|
||||
PlacementInfo info = new PlacementInfo(TrackMaterial.fromItem(stack.getItem()));
|
||||
hoveringMaxed = maximiseTurn;
|
||||
hoveringAngle = lookAngle;
|
||||
hoveringPos = pos2;
|
||||
|
@ -195,7 +203,7 @@ public class TrackPlacement {
|
|||
BlockPos targetPos2 = pos2.offset(offset2.x, offset2.y, offset2.z);
|
||||
info.curve = new BezierConnection(Couple.create(targetPos1, targetPos2),
|
||||
Couple.create(end1.add(offset1), end2.add(offset2)), Couple.create(normedAxis1, normedAxis2),
|
||||
Couple.create(normal1, normal2), true, girder);
|
||||
Couple.create(normal1, normal2), true, girder, TrackMaterial.fromItem(stack.getItem()));
|
||||
}
|
||||
|
||||
// S curve or Straight
|
||||
|
@ -355,7 +363,7 @@ public class TrackPlacement {
|
|||
info.curve = skipCurve ? null
|
||||
: new BezierConnection(Couple.create(targetPos1, targetPos2),
|
||||
Couple.create(end1.add(offset1), end2.add(offset2)), Couple.create(normedAxis1, normedAxis2),
|
||||
Couple.create(normal1, normal2), true, girder);
|
||||
Couple.create(normal1, normal2), true, girder, TrackMaterial.fromItem(stack.getItem()));
|
||||
|
||||
info.valid = true;
|
||||
|
||||
|
@ -400,7 +408,7 @@ public class TrackPlacement {
|
|||
continue;
|
||||
|
||||
ItemStack stackInSlot = (offhand ? inv.offhand : inv.items).get(i);
|
||||
boolean isTrack = AllBlocks.TRACK.isIn(stackInSlot);
|
||||
boolean isTrack = AllTags.AllBlockTags.TRACKS.matches(stackInSlot) && stackInSlot.is(stack.getItem());
|
||||
if (!isTrack && (!shouldPave || offhandItem.getItem() != stackInSlot.getItem()))
|
||||
continue;
|
||||
if (isTrack ? foundTracks >= tracks : foundPavement >= pavement)
|
||||
|
@ -473,6 +481,18 @@ public class TrackPlacement {
|
|||
info.requiredPavement += TrackPaver.paveCurve(level, info.curve, block, simulate, visited);
|
||||
}
|
||||
|
||||
private static BlockState copyProperties(BlockState from, BlockState onto) {
|
||||
for (Property property : onto.getProperties()) {
|
||||
if (from.hasProperty(property))
|
||||
onto = onto.setValue(property, from.getValue(property));
|
||||
}
|
||||
return onto;
|
||||
}
|
||||
|
||||
private static BlockState copyProperties(BlockState from, BlockState onto, boolean keepFrom) {
|
||||
return keepFrom ? from : copyProperties(from, onto);
|
||||
}
|
||||
|
||||
private static PlacementInfo placeTracks(Level level, PlacementInfo info, BlockState state1, BlockState state2,
|
||||
BlockPos targetPos1, BlockPos targetPos2, boolean simulate) {
|
||||
info.requiredTracks = 0;
|
||||
|
@ -500,7 +520,8 @@ public class TrackPlacement {
|
|||
Vec3 offset = axis.scale(i);
|
||||
BlockPos offsetPos = pos.offset(offset.x, offset.y, offset.z);
|
||||
BlockState stateAtPos = level.getBlockState(offsetPos);
|
||||
BlockState toPlace = state;
|
||||
// copy over all shared properties from the shaped state to the correct track material block
|
||||
BlockState toPlace = copyProperties(state, info.trackMaterial.getTrackBlock().get().defaultBlockState());
|
||||
|
||||
boolean canPlace = stateAtPos.getMaterial()
|
||||
.isReplaceable();
|
||||
|
@ -523,15 +544,16 @@ public class TrackPlacement {
|
|||
return info;
|
||||
|
||||
if (!simulate) {
|
||||
BlockState onto = info.trackMaterial.getTrackBlock().get().defaultBlockState();
|
||||
BlockState stateAtPos = level.getBlockState(targetPos1);
|
||||
level.setBlock(targetPos1, ProperWaterloggedBlock.withWater(level,
|
||||
(stateAtPos.getBlock() == state1.getBlock() ? stateAtPos : state1).setValue(TrackBlock.HAS_BE, true),
|
||||
targetPos1), 3);
|
||||
(AllTags.AllBlockTags.TRACKS.matches(stateAtPos) ? stateAtPos : copyProperties(state1, onto))
|
||||
.setValue(TrackBlock.HAS_BE, true), targetPos1), 3);
|
||||
|
||||
stateAtPos = level.getBlockState(targetPos2);
|
||||
level.setBlock(targetPos2, ProperWaterloggedBlock.withWater(level,
|
||||
(stateAtPos.getBlock() == state2.getBlock() ? stateAtPos : state2).setValue(TrackBlock.HAS_BE, true),
|
||||
targetPos2), 3);
|
||||
(AllTags.AllBlockTags.TRACKS.matches(stateAtPos) ? stateAtPos : copyProperties(state2, onto))
|
||||
.setValue(TrackBlock.HAS_BE, true), targetPos2), 3);
|
||||
}
|
||||
|
||||
BlockEntity te1 = level.getBlockEntity(targetPos1);
|
||||
|
@ -582,10 +604,10 @@ public class TrackPlacement {
|
|||
return;
|
||||
|
||||
InteractionHand hand = InteractionHand.MAIN_HAND;
|
||||
if (!AllBlocks.TRACK.isIn(stack)) {
|
||||
if (!AllTags.AllBlockTags.TRACKS.matches(stack)) {
|
||||
stack = player.getOffhandItem();
|
||||
hand = InteractionHand.OFF_HAND;
|
||||
if (!AllBlocks.TRACK.isIn(stack))
|
||||
if (!AllTags.AllBlockTags.TRACKS.matches(stack))
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,9 +3,6 @@ package com.simibubi.create.content.logistics.trains.track;
|
|||
import static com.simibubi.create.AllPartialModels.GIRDER_SEGMENT_BOTTOM;
|
||||
import static com.simibubi.create.AllPartialModels.GIRDER_SEGMENT_MIDDLE;
|
||||
import static com.simibubi.create.AllPartialModels.GIRDER_SEGMENT_TOP;
|
||||
import static com.simibubi.create.AllPartialModels.TRACK_SEGMENT_LEFT;
|
||||
import static com.simibubi.create.AllPartialModels.TRACK_SEGMENT_RIGHT;
|
||||
import static com.simibubi.create.AllPartialModels.TRACK_TIE;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
|
@ -14,6 +11,7 @@ import com.mojang.blaze3d.vertex.VertexConsumer;
|
|||
import com.simibubi.create.content.logistics.trains.BezierConnection;
|
||||
import com.simibubi.create.content.logistics.trains.BezierConnection.GirderAngles;
|
||||
import com.simibubi.create.content.logistics.trains.BezierConnection.SegmentAngles;
|
||||
import com.simibubi.create.content.logistics.trains.TrackMaterial;
|
||||
import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer;
|
||||
import com.simibubi.create.foundation.render.CachedBufferer;
|
||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||
|
@ -62,7 +60,9 @@ public class TrackRenderer extends SafeBlockEntityRenderer<TrackBlockEntity> {
|
|||
SegmentAngles segment = segments[i];
|
||||
int light = LevelRenderer.getLightColor(level, segment.lightPosition.offset(tePosition));
|
||||
|
||||
CachedBufferer.partial(TRACK_TIE, air)
|
||||
TrackMaterial.TrackModelHolder modelHolder = bc.getMaterial().getModelHolder();
|
||||
|
||||
CachedBufferer.partial(modelHolder.tie(), air)
|
||||
.mulPose(segment.tieTransform.pose())
|
||||
.mulNormal(segment.tieTransform.normal())
|
||||
.light(light)
|
||||
|
@ -70,7 +70,7 @@ public class TrackRenderer extends SafeBlockEntityRenderer<TrackBlockEntity> {
|
|||
|
||||
for (boolean first : Iterate.trueAndFalse) {
|
||||
Pose transform = segment.railTransforms.get(first);
|
||||
CachedBufferer.partial(first ? TRACK_SEGMENT_LEFT : TRACK_SEGMENT_RIGHT, air)
|
||||
CachedBufferer.partial(first ? modelHolder.segment_left() : modelHolder.segment_right(), air)
|
||||
.mulPose(transform.pose())
|
||||
.mulNormal(transform.normal())
|
||||
.light(light)
|
||||
|
|
|
@ -62,9 +62,11 @@ import net.minecraftforge.eventbus.api.EventPriority;
|
|||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.LogicalSide;
|
||||
import net.minecraftforge.fml.ModList;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||
import net.minecraftforge.forgespi.language.IModFileInfo;
|
||||
import net.minecraftforge.forgespi.locating.IModFile;
|
||||
import net.minecraftforge.registries.NewRegistryEvent;
|
||||
|
||||
@EventBusSubscriber
|
||||
public class CommonEvents {
|
||||
|
@ -90,7 +92,7 @@ public class CommonEvents {
|
|||
ToolboxHandler.playerLogin(player);
|
||||
Create.RAILWAYS.playerLogin(player);
|
||||
}
|
||||
|
||||
|
||||
@SubscribeEvent
|
||||
public static void playerLoggedOut(PlayerLoggedOutEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
@ -166,7 +168,7 @@ public class CommonEvents {
|
|||
public static void onEntityEnterSection(EntityEvent.EnteringSection event) {
|
||||
CarriageEntityHandler.onEntityEnterSection(event);
|
||||
}
|
||||
|
||||
|
||||
@SubscribeEvent
|
||||
public static void addReloadListeners(AddReloadListenerEvent event) {
|
||||
event.addListener(RecipeFinder.LISTENER);
|
||||
|
@ -248,7 +250,5 @@ public class CommonEvents {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -60,7 +60,8 @@ public class AllCommands {
|
|||
.then(CameraDistanceCommand.register())
|
||||
.then(CameraAngleCommand.register())
|
||||
.then(FlySpeedCommand.register())
|
||||
.then(KillTPSCommand.register())
|
||||
//.then(DebugValueCommand.register())
|
||||
//.then(KillTPSCommand.register())
|
||||
.build();
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}));
|
||||
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ import com.simibubi.create.content.curiosities.frames.CopycatBlock;
|
|||
import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock;
|
||||
import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock.Shape;
|
||||
import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelItem;
|
||||
import com.simibubi.create.content.logistics.trains.IBogeyBlock;
|
||||
import com.simibubi.create.content.logistics.trains.AbstractBogeyBlock;
|
||||
import com.simibubi.create.content.logistics.trains.track.StandardBogeyBlock;
|
||||
import com.simibubi.create.foundation.block.BlockStressDefaults;
|
||||
import com.simibubi.create.foundation.block.ItemUseOverrides;
|
||||
|
@ -95,6 +95,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))
|
||||
|
@ -103,7 +104,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 -> IBogeyBlock.register(RegisteredObjects.getKeyOrThrow(block)));
|
||||
.onRegister(block -> AbstractBogeyBlock.registerStandardBogey(RegisteredObjects.getKeyOrThrow(block)));
|
||||
}
|
||||
|
||||
public static <B extends CopycatBlock, P> NonNullUnaryOperator<BlockBuilder<B, P>> copycat() {
|
||||
|
|
|
@ -3,6 +3,8 @@ package com.simibubi.create.foundation.ponder.content;
|
|||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.logistics.trains.TrackMaterial;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackBlock;
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.ponder.PonderRegistrationHelper;
|
||||
import com.simibubi.create.foundation.ponder.PonderRegistry;
|
||||
|
@ -20,8 +22,15 @@ import com.simibubi.create.foundation.ponder.content.trains.TrainScenes;
|
|||
import com.simibubi.create.foundation.ponder.content.trains.TrainSignalScenes;
|
||||
import com.simibubi.create.foundation.ponder.content.trains.TrainStationScenes;
|
||||
|
||||
import com.tterrag.registrate.util.entry.BlockEntry;
|
||||
import com.tterrag.registrate.util.entry.ItemProviderEntry;
|
||||
|
||||
import net.minecraft.world.item.DyeColor;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
import net.minecraftforge.registries.RegistryObject;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class PonderIndex {
|
||||
|
||||
|
@ -320,7 +329,12 @@ public class PonderIndex {
|
|||
.addStoryBoard("threshold_switch", DetectorScenes::thresholdSwitch);
|
||||
|
||||
// Trains
|
||||
HELPER.forComponents(AllBlocks.TRACK)
|
||||
HELPER.forComponents(TrackMaterial.allBlocks().stream()
|
||||
.map((trackSupplier) -> new BlockEntry<TrackBlock>(
|
||||
// note: these blocks probably WON'T be in the Create Registrate, but a simple code trace reveals the Entry's registrate isn't used
|
||||
Create.REGISTRATE,
|
||||
RegistryObject.create(trackSupplier.get().getRegistryName(), ForgeRegistries.BLOCKS)))
|
||||
.toList())
|
||||
.addStoryBoard("train_track/placement", TrackScenes::placement)
|
||||
.addStoryBoard("train_track/portal", TrackScenes::portal)
|
||||
.addStoryBoard("train_track/chunks", TrackScenes::chunks);
|
||||
|
|
|
@ -7,7 +7,7 @@ import java.util.function.Function;
|
|||
import com.simibubi.create.content.contraptions.components.deployer.DeployerBlockEntity;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.bearing.IBearingBlockEntity;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyBlockEntity;
|
||||
import com.simibubi.create.content.logistics.trains.track.StandardBogeyBlockEntity;
|
||||
import com.simibubi.create.content.logistics.trains.track.AbstractBogeyBlockEntity;
|
||||
import com.simibubi.create.foundation.ponder.PonderScene;
|
||||
import com.simibubi.create.foundation.ponder.PonderWorld;
|
||||
|
||||
|
@ -34,7 +34,7 @@ public class AnimateBlockEntityInstruction extends TickingInstruction {
|
|||
public static AnimateBlockEntityInstruction bogey(BlockPos location, float totalDelta, int ticks) {
|
||||
float movedPerTick = totalDelta / ticks;
|
||||
return new AnimateBlockEntityInstruction(location, totalDelta, ticks,
|
||||
(w, f) -> castIfPresent(w, location, StandardBogeyBlockEntity.class)
|
||||
(w, f) -> castIfPresent(w, location, AbstractBogeyBlockEntity.class)
|
||||
.ifPresent(bte -> bte.animate(f.equals(totalDelta) ? 0 : movedPerTick)),
|
||||
(w) -> 0f);
|
||||
}
|
||||
|
|
|
@ -45,4 +45,13 @@ public class Iterate {
|
|||
public static List<BlockPos> hereBelowAndAbove(BlockPos pos) {
|
||||
return Arrays.asList(pos, pos.below(), pos.above());
|
||||
}
|
||||
|
||||
public static <T> T cycleValue(List<T> list, T current) {
|
||||
int currentIndex = list.indexOf(current);
|
||||
if (currentIndex == -1) {
|
||||
throw new IllegalArgumentException("Current value not found in list");
|
||||
}
|
||||
int nextIndex = (currentIndex + 1) % list.size();
|
||||
return list.get(nextIndex);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import net.minecraft.nbt.FloatTag;
|
|||
import net.minecraft.nbt.IntTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
|
||||
|
@ -118,4 +119,12 @@ public class NBTHelper {
|
|||
return compoundTag.getInt("V");
|
||||
}
|
||||
|
||||
public static void writeResourceLocation(CompoundTag nbt, String key, ResourceLocation location) {
|
||||
nbt.putString(key, location.toString());
|
||||
}
|
||||
|
||||
public static ResourceLocation readResourceLocation(CompoundTag nbt, String key) {
|
||||
return new ResourceLocation(nbt.getString(key));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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, Vec3 camera, float pt) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
ms.pushPose();
|
||||
|
||||
TransformStack.cast(ms)
|
||||
.translate(pos.x - camera.x, pos.y - camera.y, pos.z - camera.z)
|
||||
.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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
@ -81,6 +82,13 @@ public class Outliner {
|
|||
|
||||
//
|
||||
|
||||
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))
|
||||
outlines.get(slot).ticksTillRemoval = 1;
|
||||
|
|
|
@ -1002,8 +1002,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"
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue