Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Polygonal2DRegion;
import com.sk89q.worldedit.regions.Region;
import lombok.Getter;
import net.buildtheearth.buildteamtools.BuildTeamTools;
import net.buildtheearth.buildteamtools.modules.generator.GeneratorModule;
import net.buildtheearth.buildteamtools.modules.generator.model.GeneratorComponent;
import net.buildtheearth.buildteamtools.modules.generator.model.GeneratorType;
Expand All @@ -20,8 +22,12 @@ public class Rail extends GeneratorComponent {

private final Set<UUID> preparingPlayers = ConcurrentHashMap.newKeySet();

@Getter
private final RailTypeManager railTypeManager;

public Rail() {
super(GeneratorType.RAIL);
railTypeManager = new RailTypeManager(BuildTeamTools.getInstance().getDataFolder());
}

@Override
Expand All @@ -38,7 +44,7 @@ public boolean checkForPlayer(Player player) {
"Rail Generator supports cuboid, polygonal and convex WorldEdit selections."
)));
player.closeInventory();
player.playSound(player.getLocation(), Sound.ENTITY_ITEM_BREAK, 1.0F, 1.0F);
playSound(player, Sound.ENTITY_ITEM_BREAK);
return false;
}

Expand Down Expand Up @@ -67,6 +73,10 @@ private void sendAlreadyGeneratingMessage(Player player) {
player.sendMessage(ChatHelper.PREFIX_COMPONENT.append(ChatHelper.getErrorComponent(
"Rail Generator is already running. Please wait until the current generation is finished."
)));
player.playSound(player.getLocation(), Sound.ENTITY_ITEM_BREAK, 1.0F, 1.0F);
playSound(player, Sound.ENTITY_ITEM_BREAK);
}

private void playSound(Player player, Sound sound) {
player.playSound(player, sound, 1.0F, 1.0F);
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package net.buildtheearth.buildteamtools.modules.generator.components.rail;

import com.alpsbte.alpslib.utils.GeneratorUtils;
import com.alpsbte.alpslib.utils.item.Item;
import com.cryptomorin.xseries.XMaterial;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes;
import org.bukkit.util.Vector;

Expand All @@ -17,45 +19,34 @@
final class RailBlockBuilder {

private static final Direction DEFAULT_FACING = Direction.EAST;
private static final XMaterial[] CENTER_MATERIALS = new XMaterial[]{
XMaterial.DEAD_FIRE_CORAL_BLOCK,
XMaterial.STONE,
XMaterial.COBBLESTONE
};
private static final String FACING_PROPERTY = "facing";
// Sleeper ends stick out one block beyond the rails, which sit at offset 1 from the track center.
private static final int SLEEPER_SIDE_OFFSET = 2;

private final List<Vector> controlPoints;
private final RailTerrainResolver terrainResolver;
private final RailType railType;
private final BlockType railBlockType;
private final RailPreparationProgress preparationProgress;
private final int railLaneCount;
private final int railLaneSpacing;
private final long terrainAdjustedPercentage;
private final long buildFinishedPercentage;

RailBlockBuilder(
List<Vector> controlPoints,
RailTerrainResolver terrainResolver,
RailType railType,
RailPreparationProgress preparationProgress,
int railLaneCount,
int railLaneSpacing,
long terrainAdjustedPercentage,
long buildFinishedPercentage
) {
this.controlPoints = controlPoints;
this.terrainResolver = terrainResolver;
this.railType = railType;
this.railBlockType = getRailBlockType(railType);
this.preparationProgress = preparationProgress;
this.railLaneCount = railLaneCount;
this.railLaneSpacing = railLaneSpacing;
this.terrainAdjustedPercentage = terrainAdjustedPercentage;
this.buildFinishedPercentage = buildFinishedPercentage;
}

Map<PositionKey, BlockState> build(List<Vector> path) {
Map<PositionKey, BlockState> build(List<List<Vector>> railCenterPaths) {
Map<PositionKey, BlockState> railBlocks = new LinkedHashMap<>();
List<List<Vector>> railCenterPaths = new RailLanePathBuilder(controlPoints, terrainResolver, railLaneCount, railLaneSpacing)
.createRailCenterPaths(path);
Set<PositionKey> centerPositions = getCenterPositions(railCenterPaths);
Map<PositionKey, RailSideBlock> sideBlocks = new LinkedHashMap<>();
int totalPathPoints = getTotalPathPointCount(railCenterPaths);
Expand All @@ -76,16 +67,21 @@ Map<PositionKey, BlockState> build(List<Vector> path) {
int processedSideBlocks = 0;

for (RailSideBlock sideBlock : sideBlocks.values()) {
railBlocks.put(sideBlock.key(), createAnvilBlockState(resolveSideBlockFacing(sideBlock, sideBlocks)));
railBlocks.put(sideBlock.key(), createRailBlockState(resolveSideBlockFacing(sideBlock, sideBlocks)));
processedSideBlocks++;
preparationProgress.update(preparationProgress.scale(processedSideBlocks, sideBlocks.size(), 86L, 89L));
}

if (railType.hasSleepers())
for (List<Vector> railCenterPath : railCenterPaths)
addSleeperBlocks(railBlocks, railCenterPath, centerPositions);

int processedCenterPoints = 0;

for (List<Vector> railCenterPath : railCenterPaths) {
for (Vector center : railCenterPath) {
railBlocks.put(PositionKey.from(center), createCenterBlockState(center));
for (int index = 0; index < railCenterPath.size(); index++) {
Vector center = railCenterPath.get(index);
railBlocks.put(PositionKey.from(center), createCenterBlockState(center, isSleeperPoint(index)));
processedCenterPoints++;
preparationProgress.update(preparationProgress.scale(processedCenterPoints, totalPathPoints, 89L, buildFinishedPercentage));
}
Expand All @@ -94,6 +90,50 @@ Map<PositionKey, BlockState> build(List<Vector> path) {
return railBlocks;
}

private boolean isSleeperPoint(int index) {
return railType.hasSleepers() && index % railType.getSleeperSpacing() == 0;
}

private void addSleeperBlocks(Map<PositionKey, BlockState> railBlocks, List<Vector> path, Set<PositionKey> centerPositions) {
BlockState sleeperBlockState = GeneratorUtils.getBlockState(railType.getSleeperBlock());

for (int index = 0; index < path.size(); index++) {
if (!isSleeperPoint(index))
continue;

Vector center = path.get(index);
RailStep step = getRailStep(path, index, new RailStep(1, 0));
RailStep perpendicularStep = new RailStep(-step.dz(), step.dx());

addSleeperBlock(railBlocks, center, perpendicularStep, SLEEPER_SIDE_OFFSET, sleeperBlockState, centerPositions);
addSleeperBlock(railBlocks, center, perpendicularStep, -SLEEPER_SIDE_OFFSET, sleeperBlockState, centerPositions);
}
}

private void addSleeperBlock(
Map<PositionKey, BlockState> railBlocks,
Vector center,
RailStep perpendicularStep,
int offset,
BlockState sleeperBlockState,
Set<PositionKey> centerPositions
) {
if (perpendicularStep.dx() == 0 && perpendicularStep.dz() == 0)
return;

int x = center.getBlockX() + perpendicularStep.dx() * offset;
int z = center.getBlockZ() + perpendicularStep.dz() * offset;
int y = terrainResolver.getNearestRailSurfaceY(x, z, center.getBlockY());

PositionKey key = PositionKey.of(x, y, z);

// Rails and track centers take precedence over sleeper ends.
if (centerPositions.contains(key) || railBlocks.containsKey(key))
return;

railBlocks.put(key, sleeperBlockState);
}

private int getTotalPathPointCount(List<List<Vector>> railCenterPaths) {
int totalPathPoints = 0;

Expand Down Expand Up @@ -247,22 +287,29 @@ private RailStep getStep(Vector from, Vector to) {
return new RailStep(dx, dz);
}

private BlockState createCenterBlockState(Vector position) {
return switch (railType) {
case STANDARD -> createStandardCenterBlockState(position);
};
}
private BlockState createCenterBlockState(Vector position, boolean sleeperPoint) {
if (sleeperPoint)
return GeneratorUtils.getBlockState(railType.getSleeperBlock());

private BlockState createStandardCenterBlockState(Vector position) {
List<XMaterial> blocksBelow = railType.getBlocksBelow();
int index = Math.floorMod(
position.getBlockX() * 31 + position.getBlockY() * 23 + position.getBlockZ() * 17,
CENTER_MATERIALS.length
blocksBelow.size()
);

return GeneratorUtils.getBlockState(CENTER_MATERIALS[index]);
return GeneratorUtils.getBlockState(blocksBelow.get(index));
}

private BlockState createAnvilBlockState(Direction direction) {
return GeneratorUtils.getBlockStateWithFacing(BlockTypes.ANVIL, direction);
private BlockState createRailBlockState(Direction direction) {
if (!railBlockType.getPropertyMap().containsKey(FACING_PROPERTY))
return railBlockType.getDefaultState();

return GeneratorUtils.getBlockStateWithFacing(railBlockType, direction);
}

private BlockType getRailBlockType(RailType railType) {
BlockType blockType = Item.convertXMaterialToWEBlockType(railType.getRailBlock());

return blockType == null ? BlockTypes.ANVIL : blockType;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@

public enum RailFlag implements Flag {

RAIL_TYPE("t", FlagType.RAIL_TYPE);
RAIL_TYPE("t", FlagType.RAIL_TYPE),
TRACK_COUNT("c", FlagType.INTEGER),
TRACK_SPACING("s", FlagType.INTEGER);

@Getter
private final String flag;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,22 @@ List<List<Vector>> createRailCenterPaths(List<Vector> path) {
return List.of(path);

List<List<Vector>> railCenterPaths = new ArrayList<>();
int sideLaneCount = (railLaneCount - 1) / 2;
double centerLaneIndex = (railLaneCount - 1) / 2.0;

for (int laneIndex = sideLaneCount; laneIndex >= 1; laneIndex--) {
List<Vector> leftLane = createShiftedRailLane(laneIndex * railLaneSpacing, 1);
// Lanes are spread symmetrically around the selected path. Even track counts
// have no lane on the path itself, only shifted lanes on both sides.
for (int laneIndex = 0; laneIndex < railLaneCount; laneIndex++) {
int offset = (int) Math.round((laneIndex - centerLaneIndex) * railLaneSpacing);

if (leftLane.size() >= 2)
railCenterPaths.add(leftLane);
}

railCenterPaths.add(path);
if (offset == 0) {
railCenterPaths.add(path);
continue;
}

for (int laneIndex = 1; laneIndex <= sideLaneCount; laneIndex++) {
List<Vector> rightLane = createShiftedRailLane(laneIndex * railLaneSpacing, -1);
List<Vector> shiftedLane = createShiftedRailLane(Math.abs(offset), offset > 0 ? 1 : -1);

if (rightLane.size() >= 2)
railCenterPaths.add(rightLane);
if (shiftedLane.size() >= 2)
railCenterPaths.add(shiftedLane);
}

return railCenterPaths;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ static RailLimits fromConfig() {
}

private static int getBoundedInt(FileConfiguration config, String path, int fallback, int minimum, int maximum) {
return Math.max(minimum, Math.min(maximum, config.getInt(path, fallback)));
return Math.clamp(config.getInt(path, fallback), minimum, maximum);
}

private static long getBoundedLong(FileConfiguration config, String path, long fallback, long minimum, long maximum) {
return Math.max(minimum, Math.min(maximum, config.getLong(path, fallback)));
return Math.clamp(config.getLong(path, fallback), minimum, maximum);
}
}
Loading