Turn to target
- Bezier turn segments between tracks can now be hovered as if they were blocks - Bezier turns can now be destroyed by breaking any of their segments - Signals and Stations can now be pointed to anywhere on a track, not only to physical blocks - Added a basic collision shape for straight tracks
This commit is contained in:
parent
99a6836a1d
commit
b970c0029f
40 changed files with 828 additions and 88 deletions
|
@ -543,22 +543,22 @@ bf2b0310500213ff853c748c236eb5d01f61658e assets/create/blockstates/yellow_toolbo
|
|||
7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json
|
||||
b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json
|
||||
7fbb25c577025ff61388c54c43401d8bb80723dd assets/create/lang/en_ud.json
|
||||
0a3b09db8a3bd71570afc1452d62a1fa6bd22baa assets/create/lang/en_us.json
|
||||
7ac6b939d4d1b574806ac3fa3ec495498c9c00a6 assets/create/lang/unfinished/de_de.json
|
||||
58a1b86058fcebf323e2208ba26df584d42f9f97 assets/create/lang/unfinished/es_cl.json
|
||||
1419151466490bfa42b84a99e0e296b54e1aeec5 assets/create/lang/unfinished/es_es.json
|
||||
a366bd2c9b80079b9c42572623165497b6d49531 assets/create/lang/unfinished/fr_fr.json
|
||||
b21c2d0a7cdf713492ab1eb85061df8c73a9d9b9 assets/create/lang/unfinished/it_it.json
|
||||
9874ddfacd2effec2eb852ea9cc009923e372ae5 assets/create/lang/unfinished/ja_jp.json
|
||||
0334b52e3e84870e84fce1e485c6153456dc84e9 assets/create/lang/unfinished/ko_kr.json
|
||||
7f0bd618c72b9743832a7133db0359f546b48f5e assets/create/lang/unfinished/nl_nl.json
|
||||
f6826d25ea7aca1db76e806a44434f64fb11e6b2 assets/create/lang/unfinished/pl_pl.json
|
||||
5ff6c067e106418b32dbb97b3bce56a6990eaf67 assets/create/lang/unfinished/pt_br.json
|
||||
8e639a6e5337e7723c454b3d01dd70e9715318fe assets/create/lang/unfinished/pt_pt.json
|
||||
763413532441a056bd88bbcea394fcf9e50e8c29 assets/create/lang/unfinished/ro_ro.json
|
||||
24430fe32f666e6df5fa9185dabedbe9746155d2 assets/create/lang/unfinished/ru_ru.json
|
||||
9955890700831881c15b3df9d720448c09ae341e assets/create/lang/unfinished/zh_cn.json
|
||||
7294335fc11c054fb761a251493b17866f01f0c2 assets/create/lang/unfinished/zh_tw.json
|
||||
7cd7e879350cbb56393165c24062fda5676466b9 assets/create/lang/en_us.json
|
||||
10e938a41280ab88265f59b293cf1a19ea012f18 assets/create/lang/unfinished/de_de.json
|
||||
8b17b8042e844f53bf2ae605c0a7d5b6f9e470ee assets/create/lang/unfinished/es_cl.json
|
||||
4bc7d56deb76a73fa7af16e21b7a95d00d1c1b3c assets/create/lang/unfinished/es_es.json
|
||||
200deeabcf50a3d91387f90528154f3d0ebea8a4 assets/create/lang/unfinished/fr_fr.json
|
||||
d806ae2e13f9415b79ce7c7928c8e93ec93dd9bb assets/create/lang/unfinished/it_it.json
|
||||
5a0afa8b1ccc8b9dcbd0b0353aed8a3d14398059 assets/create/lang/unfinished/ja_jp.json
|
||||
b851295ec91158c2f6e4b8433ff13057367c5694 assets/create/lang/unfinished/ko_kr.json
|
||||
fe7e927998605dfa186b0bed7c179b0a92e5da5b assets/create/lang/unfinished/nl_nl.json
|
||||
352ef01578bc2fedd31ad95c8f48069ee2714240 assets/create/lang/unfinished/pl_pl.json
|
||||
bc5bddb12f2b01c034e7bf8619ebc8ea3136a526 assets/create/lang/unfinished/pt_br.json
|
||||
67a9b9769fe289213f95c9f9680b4fa2922930de assets/create/lang/unfinished/pt_pt.json
|
||||
38ec533de9f914ca5c8209e31cba9b3e06c734b7 assets/create/lang/unfinished/ro_ro.json
|
||||
556d68b3d26152f1a3a25a568cd1b98b844c66a6 assets/create/lang/unfinished/ru_ru.json
|
||||
4239813d57b74da7eb654a66342769e111679729 assets/create/lang/unfinished/zh_cn.json
|
||||
78ef5f771b4d1bb62dc2d4eca06124d28696e8b2 assets/create/lang/unfinished/zh_tw.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
|
||||
|
|
|
@ -1412,6 +1412,8 @@
|
|||
"create.track.leave_slope_ascending": "Cannot leave this slope while ascending",
|
||||
"create.track.leave_slope_descending": "Cannot leave this slope while descending",
|
||||
"create.track.turn_90": "Can only turn up to 90 Degrees",
|
||||
"create.track.junction_start": "Cannot start connection from a Junction",
|
||||
"create.track.turn_start": "Cannot start connection from a Turn",
|
||||
|
||||
"create.station.create_train": "Create new Train",
|
||||
"create.station.disassemble_train": "Disassemble Train",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 1518",
|
||||
"_": "Missing Localizations: 1520",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1413,6 +1413,8 @@
|
|||
"create.track.leave_slope_ascending": "UNLOCALIZED: Cannot leave this slope while ascending",
|
||||
"create.track.leave_slope_descending": "UNLOCALIZED: Cannot leave this slope while descending",
|
||||
"create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees",
|
||||
"create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction",
|
||||
"create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn",
|
||||
|
||||
"create.station.create_train": "UNLOCALIZED: Create new Train",
|
||||
"create.station.disassemble_train": "UNLOCALIZED: Disassemble Train",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 529",
|
||||
"_": "Missing Localizations: 531",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1413,6 +1413,8 @@
|
|||
"create.track.leave_slope_ascending": "UNLOCALIZED: Cannot leave this slope while ascending",
|
||||
"create.track.leave_slope_descending": "UNLOCALIZED: Cannot leave this slope while descending",
|
||||
"create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees",
|
||||
"create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction",
|
||||
"create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn",
|
||||
|
||||
"create.station.create_train": "UNLOCALIZED: Create new Train",
|
||||
"create.station.disassemble_train": "UNLOCALIZED: Disassemble Train",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 200",
|
||||
"_": "Missing Localizations: 202",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1413,6 +1413,8 @@
|
|||
"create.track.leave_slope_ascending": "UNLOCALIZED: Cannot leave this slope while ascending",
|
||||
"create.track.leave_slope_descending": "UNLOCALIZED: Cannot leave this slope while descending",
|
||||
"create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees",
|
||||
"create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction",
|
||||
"create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn",
|
||||
|
||||
"create.station.create_train": "UNLOCALIZED: Create new Train",
|
||||
"create.station.disassemble_train": "UNLOCALIZED: Disassemble Train",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 1780",
|
||||
"_": "Missing Localizations: 1782",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1413,6 +1413,8 @@
|
|||
"create.track.leave_slope_ascending": "UNLOCALIZED: Cannot leave this slope while ascending",
|
||||
"create.track.leave_slope_descending": "UNLOCALIZED: Cannot leave this slope while descending",
|
||||
"create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees",
|
||||
"create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction",
|
||||
"create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn",
|
||||
|
||||
"create.station.create_train": "UNLOCALIZED: Create new Train",
|
||||
"create.station.disassemble_train": "UNLOCALIZED: Disassemble Train",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 1469",
|
||||
"_": "Missing Localizations: 1471",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1413,6 +1413,8 @@
|
|||
"create.track.leave_slope_ascending": "UNLOCALIZED: Cannot leave this slope while ascending",
|
||||
"create.track.leave_slope_descending": "UNLOCALIZED: Cannot leave this slope while descending",
|
||||
"create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees",
|
||||
"create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction",
|
||||
"create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn",
|
||||
|
||||
"create.station.create_train": "UNLOCALIZED: Create new Train",
|
||||
"create.station.disassemble_train": "UNLOCALIZED: Disassemble Train",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 195",
|
||||
"_": "Missing Localizations: 197",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1413,6 +1413,8 @@
|
|||
"create.track.leave_slope_ascending": "UNLOCALIZED: Cannot leave this slope while ascending",
|
||||
"create.track.leave_slope_descending": "UNLOCALIZED: Cannot leave this slope while descending",
|
||||
"create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees",
|
||||
"create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction",
|
||||
"create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn",
|
||||
|
||||
"create.station.create_train": "UNLOCALIZED: Create new Train",
|
||||
"create.station.disassemble_train": "UNLOCALIZED: Disassemble Train",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 195",
|
||||
"_": "Missing Localizations: 197",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1413,6 +1413,8 @@
|
|||
"create.track.leave_slope_ascending": "UNLOCALIZED: Cannot leave this slope while ascending",
|
||||
"create.track.leave_slope_descending": "UNLOCALIZED: Cannot leave this slope while descending",
|
||||
"create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees",
|
||||
"create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction",
|
||||
"create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn",
|
||||
|
||||
"create.station.create_train": "UNLOCALIZED: Create new Train",
|
||||
"create.station.disassemble_train": "UNLOCALIZED: Disassemble Train",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 2133",
|
||||
"_": "Missing Localizations: 2135",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1413,6 +1413,8 @@
|
|||
"create.track.leave_slope_ascending": "UNLOCALIZED: Cannot leave this slope while ascending",
|
||||
"create.track.leave_slope_descending": "UNLOCALIZED: Cannot leave this slope while descending",
|
||||
"create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees",
|
||||
"create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction",
|
||||
"create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn",
|
||||
|
||||
"create.station.create_train": "UNLOCALIZED: Create new Train",
|
||||
"create.station.disassemble_train": "UNLOCALIZED: Disassemble Train",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 568",
|
||||
"_": "Missing Localizations: 570",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1413,6 +1413,8 @@
|
|||
"create.track.leave_slope_ascending": "UNLOCALIZED: Cannot leave this slope while ascending",
|
||||
"create.track.leave_slope_descending": "UNLOCALIZED: Cannot leave this slope while descending",
|
||||
"create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees",
|
||||
"create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction",
|
||||
"create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn",
|
||||
|
||||
"create.station.create_train": "UNLOCALIZED: Create new Train",
|
||||
"create.station.disassemble_train": "UNLOCALIZED: Disassemble Train",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 1380",
|
||||
"_": "Missing Localizations: 1382",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1413,6 +1413,8 @@
|
|||
"create.track.leave_slope_ascending": "UNLOCALIZED: Cannot leave this slope while ascending",
|
||||
"create.track.leave_slope_descending": "UNLOCALIZED: Cannot leave this slope while descending",
|
||||
"create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees",
|
||||
"create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction",
|
||||
"create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn",
|
||||
|
||||
"create.station.create_train": "UNLOCALIZED: Create new Train",
|
||||
"create.station.disassemble_train": "UNLOCALIZED: Disassemble Train",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 1752",
|
||||
"_": "Missing Localizations: 1754",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1413,6 +1413,8 @@
|
|||
"create.track.leave_slope_ascending": "UNLOCALIZED: Cannot leave this slope while ascending",
|
||||
"create.track.leave_slope_descending": "UNLOCALIZED: Cannot leave this slope while descending",
|
||||
"create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees",
|
||||
"create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction",
|
||||
"create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn",
|
||||
|
||||
"create.station.create_train": "UNLOCALIZED: Create new Train",
|
||||
"create.station.disassemble_train": "UNLOCALIZED: Disassemble Train",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 196",
|
||||
"_": "Missing Localizations: 198",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1413,6 +1413,8 @@
|
|||
"create.track.leave_slope_ascending": "UNLOCALIZED: Cannot leave this slope while ascending",
|
||||
"create.track.leave_slope_descending": "UNLOCALIZED: Cannot leave this slope while descending",
|
||||
"create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees",
|
||||
"create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction",
|
||||
"create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn",
|
||||
|
||||
"create.station.create_train": "UNLOCALIZED: Create new Train",
|
||||
"create.station.disassemble_train": "UNLOCALIZED: Disassemble Train",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 573",
|
||||
"_": "Missing Localizations: 575",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1413,6 +1413,8 @@
|
|||
"create.track.leave_slope_ascending": "UNLOCALIZED: Cannot leave this slope while ascending",
|
||||
"create.track.leave_slope_descending": "UNLOCALIZED: Cannot leave this slope while descending",
|
||||
"create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees",
|
||||
"create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction",
|
||||
"create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn",
|
||||
|
||||
"create.station.create_train": "UNLOCALIZED: Create new Train",
|
||||
"create.station.disassemble_train": "UNLOCALIZED: Disassemble Train",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 195",
|
||||
"_": "Missing Localizations: 197",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1413,6 +1413,8 @@
|
|||
"create.track.leave_slope_ascending": "UNLOCALIZED: Cannot leave this slope while ascending",
|
||||
"create.track.leave_slope_descending": "UNLOCALIZED: Cannot leave this slope while descending",
|
||||
"create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees",
|
||||
"create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction",
|
||||
"create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn",
|
||||
|
||||
"create.station.create_train": "UNLOCALIZED: Create new Train",
|
||||
"create.station.disassemble_train": "UNLOCALIZED: Disassemble Train",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 587",
|
||||
"_": "Missing Localizations: 589",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1413,6 +1413,8 @@
|
|||
"create.track.leave_slope_ascending": "UNLOCALIZED: Cannot leave this slope while ascending",
|
||||
"create.track.leave_slope_descending": "UNLOCALIZED: Cannot leave this slope while descending",
|
||||
"create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees",
|
||||
"create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction",
|
||||
"create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn",
|
||||
|
||||
"create.station.create_train": "UNLOCALIZED: Create new Train",
|
||||
"create.station.disassemble_train": "UNLOCALIZED: Disassemble Train",
|
||||
|
|
|
@ -234,6 +234,7 @@ import net.minecraft.world.level.block.Blocks;
|
|||
import net.minecraft.world.level.block.SoundType;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraft.world.level.block.state.properties.PistonType;
|
||||
import net.minecraft.world.level.material.Material;
|
||||
import net.minecraft.world.level.material.MaterialColor;
|
||||
import net.minecraft.world.level.storage.loot.LootPool;
|
||||
import net.minecraft.world.level.storage.loot.LootTable;
|
||||
|
@ -1336,7 +1337,10 @@ public class AllBlocks {
|
|||
.register();
|
||||
|
||||
public static final BlockEntry<TrackBlock> TRACK = REGISTRATE.block("track", TrackBlock::new)
|
||||
.initialProperties(() -> Blocks.RAIL)
|
||||
.initialProperties(Material.DECORATION)
|
||||
.properties(p -> p.strength(0.8F)
|
||||
.sound(SoundType.METAL)
|
||||
.noOcclusion())
|
||||
.addLayer(() -> RenderType::cutoutMipped)
|
||||
.transform(pickaxeOnly())
|
||||
.blockstate(new TrackBlockStateGenerator()::generate)
|
||||
|
|
|
@ -178,6 +178,8 @@ public class AllShapes {
|
|||
TRACK_CROSS_DIAG = shape(TRACK_DIAG.get(SOUTH)).add(TRACK_DIAG.get(EAST))
|
||||
.build(),
|
||||
|
||||
TRACK_COLLISION = shape(0, 0, 0, 16, 2, 16).build(),
|
||||
|
||||
TRACK_FALLBACK = shape(0, 0, 0, 16, 4, 16).build(),
|
||||
|
||||
BASIN_BLOCK_SHAPE = shape(0, 2, 0, 16, 16, 16).erase(2, 2, 2, 14, 16, 14)
|
||||
|
|
|
@ -17,6 +17,7 @@ import net.minecraft.nbt.NbtUtils;
|
|||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
@ -42,6 +43,8 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
private double radius;
|
||||
private double handleLength;
|
||||
|
||||
private AABB bounds;
|
||||
|
||||
public BezierConnection(Couple<BlockPos> positions, Couple<Vec3> starts, Couple<Vec3> axes, Couple<Vec3> normals,
|
||||
boolean primary, boolean girder) {
|
||||
tePositions = positions;
|
||||
|
@ -148,6 +151,11 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
return currentT + distance / dx;
|
||||
|
||||
}
|
||||
|
||||
public AABB getBounds() {
|
||||
resolve();
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public Vec3 getNormal(double t) {
|
||||
resolve();
|
||||
|
@ -202,12 +210,15 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
stepLUT[0] = 1;
|
||||
float combinedDistance = 0;
|
||||
|
||||
bounds = new AABB(end1, end2);
|
||||
|
||||
// determine step lut
|
||||
{
|
||||
Vec3 previous = end1;
|
||||
for (int i = 0; i <= segments; i++) {
|
||||
float t = i / (float) segments;
|
||||
Vec3 result = VecHelper.bezier(end1, end2, finish1, finish2, t);
|
||||
bounds = bounds.minmax(new AABB(result, result));
|
||||
if (i > 0) {
|
||||
combinedDistance += result.distanceTo(previous) / length;
|
||||
stepLUT[i] = (float) (t / combinedDistance);
|
||||
|
@ -215,6 +226,8 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
previous = result;
|
||||
}
|
||||
}
|
||||
|
||||
bounds = bounds.inflate(1.375f);
|
||||
}
|
||||
|
||||
private void determineHandles(Vec3 end1, Vec3 end2, Vec3 axis1, Vec3 axis2) {
|
||||
|
|
|
@ -12,6 +12,7 @@ import com.jozufozu.flywheel.core.PartialModel;
|
|||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNodeLocation.DiscoveredLocation;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour.RenderedTrackOverlayType;
|
||||
import com.simibubi.create.content.logistics.trains.track.BezierTrackPointLocation;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackBlock;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackShape;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
|
@ -105,7 +106,7 @@ public interface ITrackBlock {
|
|||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public PartialModel prepareTrackOverlay(BlockGetter world, BlockPos pos, BlockState state,
|
||||
AxisDirection direction, PoseStack transform, RenderedTrackOverlayType type);
|
||||
BezierTrackPointLocation bezierPoint, AxisDirection direction, PoseStack transform, RenderedTrackOverlayType type);
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public PartialModel prepareAssemblyOverlay(BlockGetter world, BlockPos pos, BlockState state, Direction direction,
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
package com.simibubi.create.content.logistics.trains.management.edgePoint;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackTileEntity;
|
||||
import com.simibubi.create.foundation.networking.TileEntityConfigurationPacket;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
public class CurvedTrackSelectionPacket extends TileEntityConfigurationPacket<TrackTileEntity> {
|
||||
|
||||
private BlockPos targetPos;
|
||||
private boolean front;
|
||||
private int segment;
|
||||
private int slot;
|
||||
|
||||
public CurvedTrackSelectionPacket(BlockPos pos, BlockPos targetPos, int segment, boolean front, int slot) {
|
||||
super(pos);
|
||||
this.targetPos = targetPos;
|
||||
this.segment = segment;
|
||||
this.front = front;
|
||||
this.slot = slot;
|
||||
}
|
||||
|
||||
public CurvedTrackSelectionPacket(FriendlyByteBuf buffer) {
|
||||
super(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeSettings(FriendlyByteBuf buffer) {
|
||||
buffer.writeBlockPos(targetPos);
|
||||
buffer.writeVarInt(segment);
|
||||
buffer.writeBoolean(front);
|
||||
buffer.writeVarInt(slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readSettings(FriendlyByteBuf buffer) {
|
||||
targetPos = buffer.readBlockPos();
|
||||
segment = buffer.readVarInt();
|
||||
front = buffer.readBoolean();
|
||||
slot = buffer.readVarInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applySettings(ServerPlayer player, TrackTileEntity te) {
|
||||
if (!te.getBlockPos()
|
||||
.closerThan(player.blockPosition(), 48)) {
|
||||
Create.LOGGER.warn(player.getScoreboardName() + " too far away from targeted track");
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.getInventory().selected != slot)
|
||||
return;
|
||||
ItemStack stack = player.getInventory()
|
||||
.getItem(slot);
|
||||
if (!(stack.getItem() instanceof TrackTargetingBlockItem))
|
||||
return;
|
||||
|
||||
if (player.isSteppingCarefully() && stack.hasTag()) {
|
||||
player.displayClientMessage(Lang.translate("track_target.clear"), true);
|
||||
stack.setTag(null);
|
||||
return;
|
||||
}
|
||||
|
||||
CompoundTag stackTag = stack.getOrCreateTag();
|
||||
stackTag.put("SelectedPos", NbtUtils.writeBlockPos(pos));
|
||||
stackTag.putBoolean("SelectedDirection", front);
|
||||
|
||||
CompoundTag bezierNbt = new CompoundTag();
|
||||
bezierNbt.putInt("Segment", segment);
|
||||
bezierNbt.put("Key", NbtUtils.writeBlockPos(targetPos));
|
||||
bezierNbt.putBoolean("FromStack", true);
|
||||
stackTag.put("Bezier", bezierNbt);
|
||||
|
||||
player.displayClientMessage(Lang.translate("track_target.set"), true);
|
||||
stack.setTag(stackTag);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applySettings(TrackTileEntity te) {}
|
||||
|
||||
}
|
|
@ -6,19 +6,25 @@ import javax.annotation.Nullable;
|
|||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.logistics.trains.BezierConnection;
|
||||
import com.simibubi.create.content.logistics.trains.GraphLocation;
|
||||
import com.simibubi.create.content.logistics.trains.ITrackBlock;
|
||||
import com.simibubi.create.content.logistics.trains.TrackEdge;
|
||||
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
||||
import com.simibubi.create.content.logistics.trains.TrackGraphHelper;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNode;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNodeLocation;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNodeLocation.DiscoveredLocation;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SingleTileEdgePoint;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint;
|
||||
import com.simibubi.create.content.logistics.trains.track.BezierTrackPointLocation;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackTileEntity;
|
||||
import com.simibubi.create.foundation.render.CachedBufferer;
|
||||
import com.simibubi.create.foundation.render.SuperByteBuffer;
|
||||
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
|
||||
import net.minecraft.client.renderer.LevelRenderer;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
|
@ -39,6 +45,7 @@ public class TrackTargetingBehaviour<T extends TrackEdgePoint> extends TileEntit
|
|||
public static final BehaviourType<TrackTargetingBehaviour<?>> TYPE = new BehaviourType<>();
|
||||
|
||||
private BlockPos targetTrack;
|
||||
private BezierTrackPointLocation targetBezier;
|
||||
private AxisDirection targetDirection;
|
||||
private UUID id;
|
||||
|
||||
|
@ -62,6 +69,13 @@ public class TrackTargetingBehaviour<T extends TrackEdgePoint> extends TileEntit
|
|||
nbt.putBoolean("TargetDirection", targetDirection == AxisDirection.POSITIVE);
|
||||
if (migrationData != null && !clientPacket)
|
||||
nbt.put("Migrate", migrationData);
|
||||
if (targetBezier != null) {
|
||||
CompoundTag bezierNbt = new CompoundTag();
|
||||
bezierNbt.putInt("Segment", targetBezier.segment());
|
||||
bezierNbt.put("Key", NbtUtils.writeBlockPos(targetBezier.curveTarget()
|
||||
.subtract(getPos())));
|
||||
nbt.put("Bezier", bezierNbt);
|
||||
}
|
||||
super.write(nbt, clientPacket);
|
||||
}
|
||||
|
||||
|
@ -74,6 +88,12 @@ public class TrackTargetingBehaviour<T extends TrackEdgePoint> extends TileEntit
|
|||
migrationData = nbt.getCompound("Migrate");
|
||||
if (clientPacket)
|
||||
edgePoint = null;
|
||||
if (nbt.contains("Bezier")) {
|
||||
CompoundTag bezierNbt = nbt.getCompound("Bezier");
|
||||
BlockPos key = NbtUtils.readBlockPos(bezierNbt.getCompound("Key"));
|
||||
targetBezier = new BezierTrackPointLocation(bezierNbt.contains("FromStack") ? key : key.offset(getPos()),
|
||||
bezierNbt.getInt("Segment"));
|
||||
}
|
||||
super.read(nbt, clientPacket);
|
||||
}
|
||||
|
||||
|
@ -195,7 +215,13 @@ public class TrackTargetingBehaviour<T extends TrackEdgePoint> extends TileEntit
|
|||
return targetDirection;
|
||||
}
|
||||
|
||||
public BezierTrackPointLocation getTargetBezier() {
|
||||
return targetBezier;
|
||||
}
|
||||
|
||||
public GraphLocation determineGraphLocation() {
|
||||
if (targetBezier != null)
|
||||
return determineBezierGraphLocation();
|
||||
Level level = getWorld();
|
||||
BlockPos pos = getGlobalPosition();
|
||||
BlockState state = getTrackBlockState();
|
||||
|
@ -204,13 +230,57 @@ public class TrackTargetingBehaviour<T extends TrackEdgePoint> extends TileEntit
|
|||
.get(0));
|
||||
}
|
||||
|
||||
public GraphLocation determineBezierGraphLocation() {
|
||||
Level level = getWorld();
|
||||
BlockPos pos = getGlobalPosition();
|
||||
BlockState state = getTrackBlockState();
|
||||
if (!(state.getBlock() instanceof ITrackBlock track))
|
||||
return null;
|
||||
if (!(level.getBlockEntity(pos) instanceof TrackTileEntity trackTE))
|
||||
return null;
|
||||
BezierConnection bc = trackTE.getConnections()
|
||||
.get(targetBezier.curveTarget());
|
||||
if (bc == null || !bc.isPrimary())
|
||||
return null;
|
||||
|
||||
TrackNodeLocation targetLoc = new TrackNodeLocation(bc.starts.getSecond());
|
||||
for (DiscoveredLocation location : track.getConnected(level, pos, state, true, null)) {
|
||||
TrackGraph graph = Create.RAILWAYS.sided(level)
|
||||
.getGraph(level, location);
|
||||
if (graph == null)
|
||||
continue;
|
||||
TrackNode targetNode = graph.locateNode(targetLoc);
|
||||
if (targetNode == null)
|
||||
continue;
|
||||
TrackNode node = graph.locateNode(location);
|
||||
TrackEdge edge = graph.getConnectionsFrom(node)
|
||||
.get(targetNode);
|
||||
if (edge == null)
|
||||
continue;
|
||||
|
||||
GraphLocation graphLocation = new GraphLocation();
|
||||
graphLocation.graph = graph;
|
||||
graphLocation.edge = Couple.create(location, targetLoc);
|
||||
graphLocation.position = (targetBezier.segment() + 1) / 2f;
|
||||
if (targetDirection == AxisDirection.POSITIVE) {
|
||||
graphLocation.edge = graphLocation.edge.swap();
|
||||
graphLocation.position = edge.getLength(node, targetNode) - graphLocation.position;
|
||||
}
|
||||
|
||||
return graphLocation;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static enum RenderedTrackOverlayType {
|
||||
STATION, SIGNAL, DUAL_SIGNAL;
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void render(LevelAccessor level, BlockPos pos, AxisDirection direction, int tintColor, PoseStack ms,
|
||||
MultiBufferSource buffer, int light, int overlay, RenderedTrackOverlayType type) {
|
||||
public static void render(LevelAccessor level, BlockPos pos, AxisDirection direction,
|
||||
BezierTrackPointLocation bezier, int tintColor, PoseStack ms, MultiBufferSource buffer, int light, int overlay,
|
||||
RenderedTrackOverlayType type) {
|
||||
BlockState trackState = level.getBlockState(pos);
|
||||
Block block = trackState.getBlock();
|
||||
if (!(block instanceof ITrackBlock))
|
||||
|
@ -220,8 +290,8 @@ public class TrackTargetingBehaviour<T extends TrackEdgePoint> extends TileEntit
|
|||
ms.translate(pos.getX(), pos.getY(), pos.getZ());
|
||||
|
||||
ITrackBlock track = (ITrackBlock) block;
|
||||
SuperByteBuffer sbb =
|
||||
CachedBufferer.partial(track.prepareTrackOverlay(level, pos, trackState, direction, ms, type), trackState);
|
||||
SuperByteBuffer sbb = CachedBufferer
|
||||
.partial(track.prepareTrackOverlay(level, pos, trackState, bezier, direction, ms, type), trackState);
|
||||
sbb.light(LevelRenderer.getLightColor(level, pos));
|
||||
sbb.renderInto(ms, buffer.getBuffer(RenderType.cutoutMipped()));
|
||||
|
||||
|
|
|
@ -2,10 +2,16 @@ package com.simibubi.create.content.logistics.trains.management.edgePoint;
|
|||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.simibubi.create.content.logistics.trains.ITrackBlock;
|
||||
import com.simibubi.create.content.logistics.trains.track.BezierTrackPointLocation;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackBlockOutline.BezierPointSelection;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackTileEntity;
|
||||
import com.simibubi.create.foundation.networking.AllPackets;
|
||||
import com.simibubi.create.foundation.render.SuperRenderTypeBuffer;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction.AxisDirection;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
|
@ -19,6 +25,8 @@ 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;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
public class TrackTargetingBlockItem extends BlockItem {
|
||||
|
||||
|
@ -45,8 +53,9 @@ public class TrackTargetingBlockItem extends BlockItem {
|
|||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
if (state.getBlock()instanceof ITrackBlock track) {
|
||||
if (track.getTrackAxes(level, pos, state).size() > 1) {
|
||||
if (state.getBlock() instanceof ITrackBlock track) {
|
||||
if (track.getTrackAxes(level, pos, state)
|
||||
.size() > 1) {
|
||||
player.displayClientMessage(Lang.translate("track_target.no_junctions")
|
||||
.withStyle(ChatFormatting.RED), true);
|
||||
return InteractionResult.FAIL;
|
||||
|
@ -84,6 +93,9 @@ public class TrackTargetingBlockItem extends BlockItem {
|
|||
return InteractionResult.FAIL;
|
||||
}
|
||||
|
||||
if (tag.contains("Bezier"))
|
||||
teTag.put("Bezier", tag.getCompound("Bezier"));
|
||||
|
||||
teTag.put("TargetTrack", NbtUtils.writeBlockPos(selectedPos.subtract(placedPos)));
|
||||
tag.put("BlockEntityTag", teTag);
|
||||
|
||||
|
@ -99,6 +111,20 @@ public class TrackTargetingBlockItem extends BlockItem {
|
|||
return useOn;
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public boolean useOnCurve(BezierPointSelection selection, ItemStack stack) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
LocalPlayer player = mc.player;
|
||||
TrackTileEntity te = selection.te();
|
||||
BezierTrackPointLocation loc = selection.loc();
|
||||
boolean front = player.getLookAngle()
|
||||
.dot(selection.direction()) < 0;
|
||||
|
||||
AllPackets.channel.sendToServer(new CurvedTrackSelectionPacket(te.getBlockPos(), loc.curveTarget(),
|
||||
loc.segment(), front, player.getInventory().selected));
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void clientTick() {
|
||||
|
||||
}
|
||||
|
|
|
@ -53,8 +53,8 @@ public class SignalRenderer extends SafeTileEntityRenderer<SignalTileEntity> {
|
|||
|
||||
ms.pushPose();
|
||||
ms.translate(-pos.getX(), -pos.getY(), -pos.getZ());
|
||||
TrackTargetingBehaviour.render(level, targetPosition, target.getTargetDirection(), 0xd0cccc, ms, buffer, light,
|
||||
overlay,
|
||||
TrackTargetingBehaviour.render(level, targetPosition, target.getTargetDirection(), target.getTargetBezier(),
|
||||
0xd0cccc, ms, buffer, light, overlay,
|
||||
overlayState == OverlayState.DUAL ? RenderedTrackOverlayType.DUAL_SIGNAL : RenderedTrackOverlayType.SIGNAL);
|
||||
ms.popPose();
|
||||
|
||||
|
|
|
@ -63,8 +63,8 @@ public class StationRenderer extends SafeTileEntityRenderer<StationTileEntity> {
|
|||
partialTicks, ms, buffer, light, overlay);
|
||||
ms.pushPose();
|
||||
ms.translate(-pos.getX(), -pos.getY(), -pos.getZ());
|
||||
TrackTargetingBehaviour.render(level, targetPosition, target.getTargetDirection(), 0xCC993B, ms, buffer,
|
||||
light, overlay, RenderedTrackOverlayType.STATION);
|
||||
TrackTargetingBehaviour.render(level, targetPosition, target.getTargetDirection(), target.getTargetBezier(),
|
||||
0xCC993B, ms, buffer, light, overlay, RenderedTrackOverlayType.STATION);
|
||||
ms.popPose();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -319,7 +319,7 @@ public class ScheduleScreen extends AbstractSimiContainerScreen<ScheduleContaine
|
|||
if (schedule.savedProgress == i && !schedule.entries.isEmpty()) {
|
||||
matrixStack.pushPose();
|
||||
float expectedY = scrollOffset + topPos + yOffset + 4;
|
||||
float actualY = Mth.clamp(expectedY, 49, 197);
|
||||
float actualY = Mth.clamp(expectedY, topPos + 18, topPos + 170);
|
||||
matrixStack.translate(0, actualY, 0);
|
||||
(expectedY == actualY ? AllGuiTextures.SCHEDULE_POINTER : AllGuiTextures.SCHEDULE_POINTER_OFFSCREEN)
|
||||
.render(matrixStack, leftPos, 0);
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package com.simibubi.create.content.logistics.trains.track;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
||||
public record BezierTrackPointLocation(BlockPos curveTarget, int segment) {
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package com.simibubi.create.content.logistics.trains.track;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.logistics.trains.TrackPropagator;
|
||||
import com.simibubi.create.foundation.networking.TileEntityConfigurationPacket;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.SoundType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
public class CurvedTrackDestroyPacket extends TileEntityConfigurationPacket<TrackTileEntity> {
|
||||
|
||||
private BlockPos targetPos;
|
||||
private BlockPos soundSource;
|
||||
|
||||
public CurvedTrackDestroyPacket(BlockPos pos, BlockPos targetPos, BlockPos soundSource) {
|
||||
super(pos);
|
||||
this.targetPos = targetPos;
|
||||
this.soundSource = soundSource;
|
||||
}
|
||||
|
||||
public CurvedTrackDestroyPacket(FriendlyByteBuf buffer) {
|
||||
super(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeSettings(FriendlyByteBuf buffer) {
|
||||
buffer.writeBlockPos(targetPos);
|
||||
buffer.writeBlockPos(soundSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readSettings(FriendlyByteBuf buffer) {
|
||||
targetPos = buffer.readBlockPos();
|
||||
soundSource = buffer.readBlockPos();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applySettings(ServerPlayer player, TrackTileEntity te) {
|
||||
if (!te.getBlockPos()
|
||||
.closerThan(player.blockPosition(), 48)) {
|
||||
Create.LOGGER.warn(player.getScoreboardName() + " too far away from destroyed Curve track");
|
||||
return;
|
||||
}
|
||||
|
||||
Level level = te.getLevel();
|
||||
te.removeConnection(targetPos);
|
||||
if (level.getBlockEntity(targetPos) instanceof TrackTileEntity other)
|
||||
other.removeConnection(pos);
|
||||
|
||||
BlockState blockState = te.getBlockState();
|
||||
TrackPropagator.onRailRemoved(level, pos, blockState);
|
||||
|
||||
SoundType soundtype = blockState.getSoundType(level, pos, player);
|
||||
if (soundtype == null)
|
||||
return;
|
||||
|
||||
level.playSound(null, soundSource, soundtype.getBreakSound(), SoundSource.BLOCKS,
|
||||
(soundtype.getVolume() + 1.0F) / 2.0F, soundtype.getPitch() * 0.8F);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applySettings(TrackTileEntity te) {}
|
||||
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
package com.simibubi.create.content.logistics.trains.track;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
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;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.particles.BlockParticleOption;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.SoundType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.client.event.InputEvent.ClickInputEvent;
|
||||
|
||||
public class CurvedTrackInteraction {
|
||||
|
||||
static final int breakerId = new Object().hashCode();
|
||||
|
||||
static int breakTicks;
|
||||
static int breakTimeout;
|
||||
static float breakProgress;
|
||||
static BlockPos breakPos;
|
||||
|
||||
public static void clientTick() {
|
||||
BezierPointSelection result = TrackBlockOutline.result;
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
LocalPlayer player = mc.player;
|
||||
ClientLevel level = mc.level;
|
||||
|
||||
if (mc.options.keyAttack.isDown() && result != null) {
|
||||
breakPos = result.te()
|
||||
.getBlockPos();
|
||||
BlockState blockState = level.getBlockState(breakPos);
|
||||
if (blockState.isAir()) {
|
||||
resetBreakProgress();
|
||||
return;
|
||||
}
|
||||
|
||||
if (breakTicks % 4.0F == 0.0F) {
|
||||
SoundType soundtype = blockState.getSoundType(level, breakPos, player);
|
||||
mc.getSoundManager()
|
||||
.play(new SimpleSoundInstance(soundtype.getHitSound(), SoundSource.BLOCKS,
|
||||
(soundtype.getVolume() + 1.0F) / 8.0F, soundtype.getPitch() * 0.5F,
|
||||
new BlockPos(result.vec())));
|
||||
}
|
||||
|
||||
boolean creative = player.getAbilities().instabuild;
|
||||
|
||||
breakTicks++;
|
||||
breakTimeout = 2;
|
||||
breakProgress += creative ? 0.25f : blockState.getDestroyProgress(player, level, breakPos);
|
||||
|
||||
Vec3 vec = VecHelper.offsetRandomly(result.vec(), level.random, 0.25f);
|
||||
level.addParticle(new BlockParticleOption(ParticleTypes.BLOCK, blockState), vec.x, vec.y, vec.z, 0, 0, 0);
|
||||
|
||||
int progress = (int) (breakProgress * 10.0F) - 1;
|
||||
level.destroyBlockProgress(player.getId(), breakPos, progress);
|
||||
player.swing(InteractionHand.MAIN_HAND);
|
||||
|
||||
if (breakProgress >= 1) {
|
||||
AllPackets.channel.sendToServer(new CurvedTrackDestroyPacket(breakPos, result.loc()
|
||||
.curveTarget(), new BlockPos(result.vec())));
|
||||
resetBreakProgress();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (breakTimeout == 0)
|
||||
return;
|
||||
if (--breakTimeout > 0)
|
||||
return;
|
||||
|
||||
resetBreakProgress();
|
||||
}
|
||||
|
||||
private static void resetBreakProgress() {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
ClientLevel level = mc.level;
|
||||
|
||||
if (breakPos != null && level != null)
|
||||
level.destroyBlockProgress(mc.player.getId(), breakPos, -1);
|
||||
|
||||
breakProgress = 0;
|
||||
breakTicks = 0;
|
||||
breakPos = null;
|
||||
}
|
||||
|
||||
public static boolean onClickInput(ClickInputEvent event) {
|
||||
BezierPointSelection result = TrackBlockOutline.result;
|
||||
if (result == null)
|
||||
return false;
|
||||
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
LocalPlayer player = mc.player;
|
||||
ClientLevel level = mc.level;
|
||||
|
||||
if (player == null || level == null)
|
||||
return false;
|
||||
|
||||
if (event.isUseItem()) {
|
||||
ItemStack heldItem = player.getMainHandItem();
|
||||
if (AllBlocks.TRACK.isIn(heldItem)) {
|
||||
player.displayClientMessage(Lang.translate("track.turn_start")
|
||||
.withStyle(ChatFormatting.RED), true);
|
||||
player.swing(InteractionHand.MAIN_HAND);
|
||||
return true;
|
||||
}
|
||||
if (heldItem.getItem() instanceof TrackTargetingBlockItem ttbi && ttbi.useOnCurve(result, heldItem)) {
|
||||
player.swing(InteractionHand.MAIN_HAND);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (event.isAttack())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -32,11 +32,14 @@ import com.simibubi.create.content.logistics.trains.TrackNodeLocation.Discovered
|
|||
import com.simibubi.create.content.logistics.trains.TrackPropagator;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour.RenderedTrackOverlayType;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationTileEntity;
|
||||
import com.simibubi.create.foundation.block.render.DestroyProgressRenderingHandler;
|
||||
import com.simibubi.create.foundation.block.render.ReducedDestroyEffects;
|
||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.renderer.LevelRenderer;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Direction.Axis;
|
||||
|
@ -68,6 +71,7 @@ import net.minecraft.world.level.material.PushReaction;
|
|||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
import net.minecraft.world.phys.shapes.Shapes;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
import net.minecraft.world.ticks.LevelTickAccess;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
|
@ -92,7 +96,7 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
|||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void initializeClient(Consumer<IBlockRenderProperties> consumer) {
|
||||
consumer.accept(new ReducedDestroyEffects());
|
||||
consumer.accept(new RenderProperties());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -318,6 +322,17 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
|||
return AllShapes.TRACK_FALLBACK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getCollisionShape(BlockState pState, BlockGetter pLevel, BlockPos pPos,
|
||||
CollisionContext pContext) {
|
||||
switch (pState.getValue(SHAPE)) {
|
||||
case AE, AW, AN, AS:
|
||||
return Shapes.empty();
|
||||
default:
|
||||
return AllShapes.TRACK_COLLISION;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockEntity newBlockEntity(BlockPos p_153215_, BlockState state) {
|
||||
if (!state.getValue(HAS_TURN))
|
||||
|
@ -419,24 +434,60 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
|||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public PartialModel prepareTrackOverlay(BlockGetter world, BlockPos pos, BlockState state, AxisDirection direction,
|
||||
PoseStack ms, RenderedTrackOverlayType type) {
|
||||
Vec3 axis = state.getValue(SHAPE)
|
||||
.getAxes()
|
||||
.get(0);
|
||||
Vec3 directionVec = axis.scale(direction.getStep())
|
||||
.normalize();
|
||||
Vec3 normal = getUpNormal(world, pos, state);
|
||||
Vec3 angles = TrackRenderer.getModelAngles(normal, directionVec);
|
||||
public PartialModel prepareTrackOverlay(BlockGetter world, BlockPos pos, BlockState state,
|
||||
BezierTrackPointLocation bezierPoint, AxisDirection direction, PoseStack ms, RenderedTrackOverlayType type) {
|
||||
TransformStack msr = TransformStack.cast(ms);
|
||||
|
||||
TransformStack.cast(ms)
|
||||
.centre()
|
||||
Vec3 axis = null;
|
||||
Vec3 diff = null;
|
||||
Vec3 normal = null;
|
||||
Vec3 offset = null;
|
||||
|
||||
if (bezierPoint != null && world.getBlockEntity(pos) instanceof TrackTileEntity trackTE) {
|
||||
BezierConnection bc = trackTE.connections.get(bezierPoint.curveTarget());
|
||||
if (bc != null) {
|
||||
double length = Mth.floor(bc.getLength() * 2);
|
||||
int seg = bezierPoint.segment() + 1;
|
||||
double t = seg / length;
|
||||
double tpre = (seg - 1) / length;
|
||||
double tpost = (seg + 1) / length;
|
||||
|
||||
offset = bc.getPosition(t);
|
||||
normal = bc.getNormal(t);
|
||||
diff = bc.getPosition(tpost)
|
||||
.subtract(bc.getPosition(tpre))
|
||||
.normalize();
|
||||
|
||||
msr.translate(offset.subtract(Vec3.atBottomCenterOf(pos)));
|
||||
msr.translate(0, -4 / 16f, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (normal == null) {
|
||||
axis = state.getValue(SHAPE)
|
||||
.getAxes()
|
||||
.get(0);
|
||||
diff = axis.scale(direction.getStep())
|
||||
.normalize();
|
||||
normal = getUpNormal(world, pos, state);
|
||||
}
|
||||
|
||||
Vec3 angles = TrackRenderer.getModelAngles(normal, diff);
|
||||
|
||||
msr.centre()
|
||||
.rotateYRadians(angles.y)
|
||||
.rotateXRadians(angles.x)
|
||||
.unCentre()
|
||||
.translate(0, axis.y != 0 ? 7 / 16f : 0, axis.y != 0 ? direction.getStep() * 2.5f / 16f : 0)
|
||||
.scale(type == RenderedTrackOverlayType.STATION ? 1 + 1 / 512f : 1);
|
||||
.unCentre();
|
||||
|
||||
if (axis != null)
|
||||
msr.translate(0, axis.y != 0 ? 7 / 16f : 0, axis.y != 0 ? direction.getStep() * 2.5f / 16f : 0);
|
||||
else {
|
||||
msr.translate(0, 4 / 16f, 0);
|
||||
if (direction == AxisDirection.NEGATIVE)
|
||||
msr.rotateCentered(Direction.UP, Mth.PI);
|
||||
}
|
||||
|
||||
msr.scale(type == RenderedTrackOverlayType.STATION ? 1 + 1 / 512f : 1);
|
||||
return type == RenderedTrackOverlayType.STATION ? AllBlockPartials.TRACK_STATION_OVERLAY
|
||||
: type == RenderedTrackOverlayType.SIGNAL ? AllBlockPartials.TRACK_SIGNAL_OVERLAY
|
||||
: AllBlockPartials.TRACK_SIGNAL_DUAL_OVERLAY;
|
||||
|
@ -448,4 +499,16 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
|||
&& state1.setValue(HAS_TURN, false) == state2.setValue(HAS_TURN, false);
|
||||
}
|
||||
|
||||
public static class RenderProperties extends ReducedDestroyEffects implements DestroyProgressRenderingHandler {
|
||||
@Override
|
||||
public boolean renderDestroyProgress(ClientLevel level, LevelRenderer renderer, int breakerId, BlockPos pos,
|
||||
int progress, BlockState blockState) {
|
||||
BlockEntity blockEntity = level.getBlockEntity(pos);
|
||||
if (blockEntity instanceof TrackTileEntity track)
|
||||
for (BlockPos trackPos : track.connections.keySet())
|
||||
renderer.destroyBlockProgress(trackPos.hashCode(), trackPos, progress);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import com.simibubi.create.foundation.utility.Lang;
|
|||
import com.simibubi.create.foundation.utility.Pair;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction.AxisDirection;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
|
@ -45,6 +46,14 @@ public class TrackBlockItem extends BlockItem {
|
|||
Vec3 lookAngle = player.getLookAngle();
|
||||
|
||||
if (!isFoil(stack)) {
|
||||
if (state.getBlock() instanceof TrackBlock track && track.getTrackAxes(level, pos, state)
|
||||
.size() > 1) {
|
||||
if (!level.isClientSide)
|
||||
player.displayClientMessage(Lang.translate("track.junction_start")
|
||||
.withStyle(ChatFormatting.RED), true);
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
if (select(level, pos, lookAngle, stack))
|
||||
return InteractionResult.SUCCESS;
|
||||
return super.useOn(pContext);
|
||||
|
@ -81,7 +90,7 @@ public class TrackBlockItem extends BlockItem {
|
|||
if (level.isClientSide)
|
||||
return InteractionResult.SUCCESS;
|
||||
|
||||
if (offhandItem.getItem()instanceof BlockItem blockItem) {
|
||||
if (offhandItem.getItem() instanceof BlockItem blockItem) {
|
||||
Block block = blockItem.getBlock();
|
||||
if (block == null)
|
||||
return InteractionResult.SUCCESS;
|
||||
|
|
|
@ -1,31 +1,165 @@
|
|||
package com.simibubi.create.content.logistics.trains.track;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
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.content.logistics.trains.BezierConnection;
|
||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||
import com.simibubi.create.foundation.utility.AnimationTickHolder;
|
||||
import com.simibubi.create.foundation.utility.RaycastHelper;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import com.simibubi.create.foundation.utility.WorldAttached;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
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.util.Mth;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult.Type;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.phys.shapes.Shapes;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.DrawSelectionEvent;
|
||||
import net.minecraftforge.common.ForgeMod;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||
|
||||
@EventBusSubscriber(Dist.CLIENT)
|
||||
public class TrackBlockOutline {
|
||||
|
||||
public static WorldAttached<Map<BlockPos, TrackTileEntity>> TRACKS_WITH_TURNS =
|
||||
new WorldAttached<>(w -> new HashMap<>());
|
||||
|
||||
static BezierPointSelection result;
|
||||
|
||||
public static void pickCurves() {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
if (!(mc.cameraEntity instanceof LocalPlayer player))
|
||||
return;
|
||||
if (mc.level == null)
|
||||
return;
|
||||
|
||||
Vec3 origin = player.getEyePosition(AnimationTickHolder.getPartialTicks(mc.level));
|
||||
|
||||
double maxRange = mc.hitResult == null ? Double.MAX_VALUE
|
||||
: mc.hitResult.getLocation()
|
||||
.distanceToSqr(origin);
|
||||
|
||||
result = null;
|
||||
|
||||
AttributeInstance range = player.getAttribute(ForgeMod.REACH_DISTANCE.get());
|
||||
Vec3 target = RaycastHelper.getTraceTarget(player, Math.min(maxRange, range.getValue()) + 1, origin);
|
||||
Map<BlockPos, TrackTileEntity> turns = TRACKS_WITH_TURNS.get(mc.level);
|
||||
|
||||
for (TrackTileEntity te : turns.values()) {
|
||||
for (BezierConnection bc : te.connections.values()) {
|
||||
if (!bc.isPrimary())
|
||||
continue;
|
||||
|
||||
AABB bounds = bc.getBounds();
|
||||
if (!bounds.contains(origin) && bounds.clip(origin, target)
|
||||
.isEmpty())
|
||||
continue;
|
||||
|
||||
float[] stepLUT = bc.getStepLUT();
|
||||
int segments = (int) (bc.getLength() * 2);
|
||||
AABB segmentBounds = AllShapes.TRACK_ORTHO.get(Direction.SOUTH)
|
||||
.bounds();
|
||||
segmentBounds = segmentBounds.move(-.5, segmentBounds.getYsize() / -2, -.5);
|
||||
|
||||
int bestSegment = -1;
|
||||
double bestDistance = Double.MAX_VALUE;
|
||||
double newMaxRange = maxRange;
|
||||
|
||||
for (int i = 0; i < stepLUT.length - 2; i++) {
|
||||
float t = stepLUT[i] * i / segments;
|
||||
float t1 = stepLUT[i + 1] * (i + 1) / segments;
|
||||
float t2 = stepLUT[i + 2] * (i + 2) / segments;
|
||||
|
||||
Vec3 v1 = bc.getPosition(t);
|
||||
Vec3 v2 = bc.getPosition(t2);
|
||||
Vec3 diff = v2.subtract(v1);
|
||||
Vec3 angles = TrackRenderer.getModelAngles(bc.getNormal(t1), diff);
|
||||
|
||||
Vec3 anchor = v1.add(diff.scale(.5));
|
||||
Vec3 localOrigin = origin.subtract(anchor);
|
||||
Vec3 localDirection = target.subtract(origin);
|
||||
localOrigin = VecHelper.rotate(localOrigin, AngleHelper.deg(-angles.x), Axis.X);
|
||||
localOrigin = VecHelper.rotate(localOrigin, AngleHelper.deg(-angles.y), Axis.Y);
|
||||
localDirection = VecHelper.rotate(localDirection, AngleHelper.deg(-angles.x), Axis.X);
|
||||
localDirection = VecHelper.rotate(localDirection, AngleHelper.deg(-angles.y), Axis.Y);
|
||||
|
||||
Optional<Vec3> clip = segmentBounds.clip(localOrigin, localOrigin.add(localDirection));
|
||||
if (clip.isEmpty())
|
||||
continue;
|
||||
|
||||
if (bestSegment != -1 && bestDistance < clip.get()
|
||||
.distanceToSqr(0, 0.25f, 0))
|
||||
continue;
|
||||
|
||||
double distanceToSqr = clip.get()
|
||||
.distanceToSqr(localOrigin);
|
||||
if (distanceToSqr > maxRange)
|
||||
continue;
|
||||
|
||||
bestSegment = i;
|
||||
newMaxRange = distanceToSqr;
|
||||
bestDistance = clip.get()
|
||||
.distanceToSqr(0, 0.25f, 0);
|
||||
|
||||
BezierTrackPointLocation location = new BezierTrackPointLocation(bc.getKey(), i);
|
||||
result = new BezierPointSelection(te, location, anchor, angles, diff.normalize());
|
||||
}
|
||||
|
||||
if (bestSegment != -1)
|
||||
maxRange = newMaxRange;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == null)
|
||||
return;
|
||||
|
||||
if (mc.hitResult != null && mc.hitResult.getType() != Type.MISS) {
|
||||
Vec3 priorLoc = mc.hitResult.getLocation();
|
||||
mc.hitResult = BlockHitResult.miss(priorLoc, Direction.UP, new BlockPos(priorLoc));
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawCurveSelection(PoseStack ms, MultiBufferSource buffer) {
|
||||
BezierPointSelection result = TrackBlockOutline.result;
|
||||
if (result == null)
|
||||
return;
|
||||
|
||||
VertexConsumer vb = buffer.getBuffer(RenderType.lines());
|
||||
Vec3 vec = result.vec();
|
||||
Vec3 angles = result.angles();
|
||||
TransformStack.cast(ms)
|
||||
.pushPose()
|
||||
.translate(vec.x, vec.y + .125f, vec.z)
|
||||
.rotateYRadians(angles.y)
|
||||
.rotateXRadians(angles.x)
|
||||
.translate(-.5, -.125f, -.5);
|
||||
|
||||
boolean holdingTrack = AllBlocks.TRACK.isIn(Minecraft.getInstance().player.getMainHandItem());
|
||||
renderShape(AllShapes.TRACK_ORTHO.get(Direction.SOUTH), ms, vb, holdingTrack ? false : null);
|
||||
ms.popPose();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void drawCustomBlockSelection(DrawSelectionEvent.HighlightBlock event) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
|
@ -41,41 +175,63 @@ public class TrackBlockOutline {
|
|||
|
||||
VertexConsumer vb = event.getMultiBufferSource()
|
||||
.getBuffer(RenderType.lines());
|
||||
PoseStack ms = event.getPoseStack();
|
||||
|
||||
ms.pushPose();
|
||||
Vec3 camPos = event.getCamera()
|
||||
.getPosition();
|
||||
|
||||
PoseStack ms = event.getPoseStack();
|
||||
|
||||
ms.pushPose();
|
||||
ms.translate(pos.getX() - camPos.x, pos.getY() - camPos.y, pos.getZ() - camPos.z);
|
||||
|
||||
walkShapes(blockstate.getValue(TrackBlock.SHAPE), TransformStack.cast(ms), s -> {
|
||||
boolean holdingTrack = AllBlocks.TRACK.isIn(Minecraft.getInstance().player.getMainHandItem());
|
||||
TrackShape shape = blockstate.getValue(TrackBlock.SHAPE);
|
||||
boolean isJunction = shape.isJunction();
|
||||
walkShapes(shape, TransformStack.cast(ms), s -> {
|
||||
renderShape(s, ms, vb, holdingTrack ? !isJunction : null);
|
||||
event.setCanceled(true);
|
||||
PoseStack.Pose transform = ms.last();
|
||||
s.forAllEdges((x1, y1, z1, x2, y2, z2) -> {
|
||||
float xDiff = (float) (x2 - x1);
|
||||
float yDiff = (float) (y2 - y1);
|
||||
float zDiff = (float) (z2 - z1);
|
||||
float length = Mth.sqrt(xDiff * xDiff + yDiff * yDiff + zDiff * zDiff);
|
||||
|
||||
xDiff /= length;
|
||||
yDiff /= length;
|
||||
zDiff /= length;
|
||||
|
||||
vb.vertex(transform.pose(), (float) x1, (float) y1, (float) z1)
|
||||
.color(0f, 0f, 0f, .4f)
|
||||
.normal(transform.normal(), xDiff, yDiff, zDiff)
|
||||
.endVertex();
|
||||
vb.vertex(transform.pose(), (float) x2, (float) y2, (float) z2)
|
||||
.color(0f, 0f, 0f, .4f)
|
||||
.normal(transform.normal(), xDiff, yDiff, zDiff)
|
||||
.endVertex();
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
ms.popPose();
|
||||
}
|
||||
|
||||
private static void renderShape(VoxelShape s, PoseStack ms, VertexConsumer vb, Boolean valid) {
|
||||
PoseStack.Pose transform = ms.last();
|
||||
s.forAllEdges((x1, y1, z1, x2, y2, z2) -> {
|
||||
float xDiff = (float) (x2 - x1);
|
||||
float yDiff = (float) (y2 - y1);
|
||||
float zDiff = (float) (z2 - z1);
|
||||
float length = Mth.sqrt(xDiff * xDiff + yDiff * yDiff + zDiff * zDiff);
|
||||
|
||||
xDiff /= length;
|
||||
yDiff /= length;
|
||||
zDiff /= length;
|
||||
|
||||
float r = 0f;
|
||||
float g = 0f;
|
||||
float b = 0f;
|
||||
|
||||
if (valid != null && valid) {
|
||||
g = 1f;
|
||||
b = 1f;
|
||||
r = 1f;
|
||||
}
|
||||
|
||||
if (valid != null && !valid) {
|
||||
r = 1f;
|
||||
b = 0.125f;
|
||||
g = 0.25f;
|
||||
}
|
||||
|
||||
vb.vertex(transform.pose(), (float) x1, (float) y1, (float) z1)
|
||||
.color(r, g, b, .4f)
|
||||
.normal(transform.normal(), xDiff, yDiff, zDiff)
|
||||
.endVertex();
|
||||
vb.vertex(transform.pose(), (float) x2, (float) y2, (float) z2)
|
||||
.color(r, g, b, .4f)
|
||||
.normal(transform.normal(), xDiff, yDiff, zDiff)
|
||||
.endVertex();
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private static final VoxelShape LONG_CROSS =
|
||||
|
@ -115,4 +271,8 @@ public class TrackBlockOutline {
|
|||
renderer.accept(LONG_ORTHO);
|
||||
}
|
||||
|
||||
public static record BezierPointSelection(TrackTileEntity te, BezierTrackPointLocation loc, Vec3 vec, Vec3 angles,
|
||||
Vec3 direction) {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -334,7 +334,7 @@ public class TrackPlacement {
|
|||
|
||||
boolean canPlace = stateAtPos.getMaterial()
|
||||
.isReplaceable();
|
||||
if (stateAtPos.getBlock()instanceof ITrackBlock trackAtPos) {
|
||||
if (stateAtPos.getBlock() instanceof ITrackBlock trackAtPos) {
|
||||
toPlace = trackAtPos.overlay(level, offsetPos, stateAtPos, toPlace);
|
||||
canPlace = true;
|
||||
}
|
||||
|
@ -413,7 +413,8 @@ public class TrackPlacement {
|
|||
.withStyle(ChatFormatting.GREEN), true);
|
||||
else if (info.message != null)
|
||||
player.displayClientMessage(Lang.translate(info.message)
|
||||
.withStyle(ChatFormatting.RED), true);
|
||||
.withStyle(info.message.equals("track.second_point") ? ChatFormatting.WHITE : ChatFormatting.RED),
|
||||
true);
|
||||
|
||||
animation.chase(info.valid ? 1 : 0, 0.25, Chaser.EXP);
|
||||
animation.tickChaser();
|
||||
|
|
|
@ -49,6 +49,13 @@ public class TrackTileEntity extends SmartTileEntity implements ITransformableTE
|
|||
return connections;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
super.initialize();
|
||||
if (!level.isClientSide && hasInteractableConnections())
|
||||
registerToCurveInteraction();
|
||||
}
|
||||
|
||||
private void validateConnections() {
|
||||
Set<BlockPos> invalid = new HashSet<>();
|
||||
for (Entry<BlockPos, BezierConnection> entry : connections.entrySet()) {
|
||||
|
@ -63,7 +70,7 @@ public class TrackTileEntity extends SmartTileEntity implements ITransformableTE
|
|||
}
|
||||
|
||||
connectionsValidated = true;
|
||||
for (BlockPos blockPos : invalid)
|
||||
for (BlockPos blockPos : invalid)
|
||||
removeConnection(blockPos);
|
||||
}
|
||||
|
||||
|
@ -117,6 +124,11 @@ public class TrackTileEntity extends SmartTileEntity implements ITransformableTE
|
|||
}
|
||||
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedRenderDispatcher.enqueueUpdate(this));
|
||||
|
||||
if (hasInteractableConnections())
|
||||
registerToCurveInteraction();
|
||||
else
|
||||
removeFromCurveInteraction();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -136,6 +148,13 @@ public class TrackTileEntity extends SmartTileEntity implements ITransformableTE
|
|||
level.scheduleTick(worldPosition, getBlockState().getBlock(), 1);
|
||||
}
|
||||
|
||||
public boolean hasInteractableConnections() {
|
||||
for (BezierConnection connection : connections.values())
|
||||
if (connection.isPrimary())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(StructureTransform transform) {
|
||||
if (transform.rotationAxis != Axis.Y)
|
||||
|
@ -173,4 +192,31 @@ public class TrackTileEntity extends SmartTileEntity implements ITransformableTE
|
|||
connections = transformedConnections;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRemoved() {
|
||||
super.setRemoved();
|
||||
if (level.isClientSide)
|
||||
removeFromCurveInteraction();
|
||||
}
|
||||
|
||||
private void registerToCurveInteraction() {
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::registerToCurveInteractionUnsafe);
|
||||
}
|
||||
|
||||
private void removeFromCurveInteraction() {
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::removeFromCurveInteractionUnsafe);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
private void registerToCurveInteractionUnsafe() {
|
||||
TrackBlockOutline.TRACKS_WITH_TURNS.get(level)
|
||||
.put(worldPosition, this);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
private void removeFromCurveInteractionUnsafe() {
|
||||
TrackBlockOutline.TRACKS_WITH_TURNS.get(level)
|
||||
.remove(worldPosition);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -38,6 +38,8 @@ import com.simibubi.create.content.logistics.trains.entity.CarriageCouplingRende
|
|||
import com.simibubi.create.content.logistics.trains.entity.TrainRelocator;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBlockItem;
|
||||
import com.simibubi.create.content.logistics.trains.management.schedule.TrainHatArmorLayer;
|
||||
import com.simibubi.create.content.logistics.trains.track.CurvedTrackInteraction;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackBlockOutline;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackPlacement;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackRemoval;
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
|
@ -159,6 +161,7 @@ public class ClientEvents {
|
|||
TrackRemoval.clientTick();
|
||||
TrainRelocator.clientTick();
|
||||
DataGathererBlockItem.clientTick();
|
||||
CurvedTrackInteraction.clientTick();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
|
@ -205,6 +208,7 @@ public class ClientEvents {
|
|||
ms.translate(-cameraPos.x(), -cameraPos.y(), -cameraPos.z());
|
||||
SuperRenderTypeBuffer buffer = SuperRenderTypeBuffer.getInstance();
|
||||
|
||||
TrackBlockOutline.drawCurveSelection(ms, buffer);
|
||||
TrackTargetingBlockItem.render(ms, buffer);
|
||||
CouplingRenderer.renderAll(ms, buffer);
|
||||
CarriageCouplingRenderer.renderAll(ms, buffer);
|
||||
|
|
|
@ -4,6 +4,7 @@ import com.simibubi.create.CreateClient;
|
|||
import com.simibubi.create.content.curiosities.toolbox.ToolboxHandlerClient;
|
||||
import com.simibubi.create.content.logistics.item.LinkedControllerClientHandler;
|
||||
import com.simibubi.create.content.logistics.trains.entity.TrainRelocator;
|
||||
import com.simibubi.create.content.logistics.trains.track.CurvedTrackInteraction;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringHandler;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueHandler;
|
||||
|
||||
|
@ -60,6 +61,11 @@ public class InputEvents {
|
|||
public static void onClickInput(ClickInputEvent event) {
|
||||
if (Minecraft.getInstance().screen != null)
|
||||
return;
|
||||
|
||||
if (CurvedTrackInteraction.onClickInput(event)) {
|
||||
event.setCanceled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getKeyMapping() == Minecraft.getInstance().options.keyPickItem) {
|
||||
if (ToolboxHandlerClient.onPickItem())
|
||||
|
|
|
@ -5,6 +5,7 @@ import org.spongepowered.asm.mixin.injection.At;
|
|||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackBlockOutline;
|
||||
import com.simibubi.create.foundation.block.BigOutlines;
|
||||
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
|
@ -18,6 +19,7 @@ public class GameRendererMixin {
|
|||
@Inject(at = @At("TAIL"), method = "pick")
|
||||
private void bigShapePick(CallbackInfo ci) {
|
||||
BigOutlines.pick();
|
||||
TrackBlockOutline.pickCurves();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -49,11 +49,13 @@ import com.simibubi.create.content.logistics.packet.TunnelFlapPacket;
|
|||
import com.simibubi.create.content.logistics.trains.TrackGraphSyncPacket;
|
||||
import com.simibubi.create.content.logistics.trains.entity.TrainPacket;
|
||||
import com.simibubi.create.content.logistics.trains.entity.TrainRelocationPacket;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.CurvedTrackSelectionPacket;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroupPacket;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationEditPacket;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.TrainEditPacket;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.TrainEditPacket.TrainEditReturnPacket;
|
||||
import com.simibubi.create.content.logistics.trains.management.schedule.ScheduleEditPacket;
|
||||
import com.simibubi.create.content.logistics.trains.track.CurvedTrackDestroyPacket;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackRemovalPacket;
|
||||
import com.simibubi.create.content.schematics.packet.ConfigureSchematicannonPacket;
|
||||
import com.simibubi.create.content.schematics.packet.InstantSchematicPacket;
|
||||
|
@ -122,6 +124,8 @@ public enum AllPackets {
|
|||
CONTROLS_INPUT(ControlsInputPacket.class, ControlsInputPacket::new, PLAY_TO_SERVER),
|
||||
REMOVE_TRACKS(TrackRemovalPacket.class, TrackRemovalPacket::new, PLAY_TO_SERVER),
|
||||
CONFIGURE_DATA_GATHERER(DataGathererConfigurationPacket.class, DataGathererConfigurationPacket::new, PLAY_TO_SERVER),
|
||||
DESTROY_CURVED_TRACK(CurvedTrackDestroyPacket.class, CurvedTrackDestroyPacket::new, PLAY_TO_SERVER),
|
||||
SELECT_CURVED_TRACK(CurvedTrackSelectionPacket.class, CurvedTrackSelectionPacket::new, PLAY_TO_SERVER),
|
||||
|
||||
// Server to Client
|
||||
SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new, PLAY_TO_CLIENT),
|
||||
|
|
|
@ -636,6 +636,8 @@
|
|||
"create.track.leave_slope_ascending": "Cannot leave this slope while ascending",
|
||||
"create.track.leave_slope_descending": "Cannot leave this slope while descending",
|
||||
"create.track.turn_90": "Can only turn up to 90 Degrees",
|
||||
"create.track.junction_start": "Cannot start connection from a Junction",
|
||||
"create.track.turn_start": "Cannot start connection from a Turn",
|
||||
|
||||
"create.station.create_train": "Create new Train",
|
||||
"create.station.disassemble_train": "Disassemble Train",
|
||||
|
|
Loading…
Reference in a new issue