Add z-shift to staircase.
Add broken game of life implementation.
This commit is contained in:
@@ -4,6 +4,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import de.nicolasklier.custom_structures.events.PlayerTick;
|
||||
import de.nicolasklier.custom_structures.items.GameOfLifeSpawner;
|
||||
import de.nicolasklier.custom_structures.items.StructureSpawner;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.item.v1.FabricItemSettings;
|
||||
@@ -22,6 +23,9 @@ public class CustomStructures implements ModInitializer {
|
||||
|
||||
public static final Item STRUCTURE_SPAWNER = new StructureSpawner(new FabricItemSettings().group(ItemGroup.MISC)
|
||||
.maxCount(1));
|
||||
|
||||
public static final Item GOL_SPAWNER = new GameOfLifeSpawner(new FabricItemSettings().group(ItemGroup.MISC)
|
||||
.maxCount(1));
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
@@ -30,6 +34,7 @@ public class CustomStructures implements ModInitializer {
|
||||
// Proceed with mild caution.
|
||||
|
||||
Registry.register(Registry.ITEM, new Identifier("customstructures", "structure_spawner"), STRUCTURE_SPAWNER);
|
||||
Registry.register(Registry.ITEM, new Identifier("customstructures", "gameoflife_spawner"), GOL_SPAWNER);
|
||||
|
||||
new PlayerTick();
|
||||
}
|
||||
|
||||
145
src/main/java/de/nicolasklier/custom_structures/GameOfLife.java
Normal file
145
src/main/java/de/nicolasklier/custom_structures/GameOfLife.java
Normal file
@@ -0,0 +1,145 @@
|
||||
package de.nicolasklier.custom_structures;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import de.nicolasklier.custom_structures.utils.Vector2;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
public class GameOfLife {
|
||||
|
||||
public static final Logger LOGGER = LoggerFactory.getLogger("customstructure:gameoflife");
|
||||
|
||||
private boolean[][] grid; // Finished grid
|
||||
private boolean[][] wGrid; // Working grid
|
||||
private int size;
|
||||
|
||||
/**
|
||||
* Position within Minecraft world.
|
||||
*/
|
||||
private BlockPos pos;
|
||||
|
||||
public GameOfLife(int size, BlockPos pos) {
|
||||
this.size = size;
|
||||
this.pos = pos;
|
||||
|
||||
long begin = System.currentTimeMillis();
|
||||
grid = new boolean[size][size];
|
||||
wGrid = new boolean[size][size];
|
||||
|
||||
for (int x = 0; x < size; x++) {
|
||||
for (int y = 0; y < size; y++) {
|
||||
grid[x][y] = false;
|
||||
wGrid[x][y] = false;
|
||||
}
|
||||
}
|
||||
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
LOGGER.info("Initialized grid with " + (size ^ size) + " (" + size + "x" + size + ") cells in " + (end - begin) + "ms.");
|
||||
}
|
||||
|
||||
public boolean[][] getGrid() {
|
||||
return grid;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public BlockPos getPosition() {
|
||||
return pos;
|
||||
}
|
||||
|
||||
// Look away.
|
||||
private int booleanToInt(boolean bool ) {
|
||||
return bool ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Project out of bounds coordinates on finite space.
|
||||
* @param c Coordinates
|
||||
* @return Fixed coordinates
|
||||
*/
|
||||
private Vector2 project(Vector2 c) {
|
||||
// Do nothing if coordinate is within bounds.
|
||||
if ((c.x > 0 && c.y > 0) && (c.x < size && c.y < size))
|
||||
return c;
|
||||
|
||||
// If x/y is negative, move them to the end of the array.
|
||||
if (c.x < 0) c.x = size + c.x;
|
||||
if (c.y < 0) c.y = size + c.y;
|
||||
|
||||
// If x/y are greater than our size, move them to the beginning of the array.
|
||||
if (c.x >= size) c.x = c.x % size;
|
||||
if (c.y >= size) c.y = c.y % size;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* 0 0 1
|
||||
* 0 C 1
|
||||
* 1 0 0
|
||||
*
|
||||
* C = Our target cell.
|
||||
* Result should be three according to Moore' neighborhood
|
||||
*
|
||||
* @param c Coordinate to check
|
||||
**/
|
||||
private int getNeighbours(Vector2 c) {
|
||||
return booleanToInt(getCell(new Vector2(c.x - 1, c.y + 1))) + // Top left
|
||||
booleanToInt(getCell(new Vector2(c.x, c.y + 1))) + // Top center
|
||||
booleanToInt(getCell(new Vector2(c.x + 1, c.y + 1))) + // Top right
|
||||
booleanToInt(getCell(new Vector2(c.x - 1, c.y))) + // Left
|
||||
booleanToInt(getCell(new Vector2(c.x + 1, c.y))) + // Right
|
||||
booleanToInt(getCell(new Vector2(c.x - 1, c.y - 1))) + // Bottom left
|
||||
booleanToInt(getCell(new Vector2(c.x, c.y - 1))) + // Bottom center
|
||||
booleanToInt(getCell(new Vector2(c.x + 1, c.y - 1))); // Bottom right
|
||||
}
|
||||
|
||||
public void createCell(Vector2 c) {
|
||||
c = project(c);
|
||||
grid[c.x][c.y] = true;
|
||||
}
|
||||
|
||||
public void killCell(Vector2 c) {
|
||||
c = project(c);
|
||||
grid[c.x][c.y] = false;
|
||||
}
|
||||
|
||||
public boolean getCell(Vector2 c) {
|
||||
Vector2 proj = project(c);
|
||||
|
||||
return grid[proj.x][proj.y];
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate next generation.
|
||||
*/
|
||||
public void tick() {
|
||||
System.out.println("Tick!");
|
||||
|
||||
// Copy current displayed grid to a working grid.
|
||||
wGrid = grid;
|
||||
|
||||
for (int x = 0; x < size; x++) {
|
||||
for (int y = 0; y < size; y++) {
|
||||
Vector2 c = new Vector2(x, y);
|
||||
int neighbours = getNeighbours(c);
|
||||
|
||||
if (wGrid[x][y]) {
|
||||
if (neighbours < 2) wGrid[x][y] = false;
|
||||
else if (neighbours == 2 || neighbours == 3) wGrid[x][y] = true;
|
||||
else if (neighbours > 3) wGrid[x][y] = false;
|
||||
} else {
|
||||
// Creates new alive cell because of reproduction.
|
||||
if (neighbours == 3) wGrid[x][y] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grid = wGrid;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +1,22 @@
|
||||
package de.nicolasklier.custom_structures.events;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import de.nicolasklier.custom_structures.CustomStructures;
|
||||
import de.nicolasklier.custom_structures.GameOfLife;
|
||||
import de.nicolasklier.custom_structures.utils.BlockStatePosition;
|
||||
import de.nicolasklier.custom_structures.utils.Vector2;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
import net.minecraft.sound.SoundEvents;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
public class PlayerTick {
|
||||
|
||||
public static HashMap<BlockPos, BlockState> queue = new HashMap<>();
|
||||
public static Iterator<BlockPos> queueKeys;
|
||||
public static List<BlockStatePosition> queue = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* How many ticks to wait until the next block will be placed.
|
||||
@@ -22,6 +24,9 @@ public class PlayerTick {
|
||||
public static int placeDelay = 3;
|
||||
private static int tickCount = 0;
|
||||
|
||||
public static GameOfLife gof;
|
||||
public static boolean gofStart = false;
|
||||
|
||||
public PlayerTick() {
|
||||
registerClientEndTick();
|
||||
|
||||
@@ -42,26 +47,56 @@ public class PlayerTick {
|
||||
|
||||
tickCount = 0;
|
||||
|
||||
// Game of Life simulation
|
||||
if (gof != null && gofStart) {
|
||||
|
||||
// Get current state of the field.
|
||||
for (int x = 0; x < gof.getSize(); x++) {
|
||||
for (int z = 0; z < gof.getSize(); z++) {
|
||||
BlockPos pos = gof.getPosition().add(x, 0, z);
|
||||
|
||||
// System.out.println("Search at " + pos.toShortString() + ": " + instance.world.getBlockState(pos).getBlock().getName());
|
||||
|
||||
if (instance.world.getBlockState(pos).getBlock() == Blocks.OBSIDIAN) {
|
||||
gof.createCell(new Vector2(x, z));
|
||||
} else {
|
||||
gof.killCell(new Vector2(x, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gof.tick();
|
||||
|
||||
// Set new simulated field
|
||||
for (int x = 0; x < gof.getSize(); x++) {
|
||||
for (int z = 0; z < gof.getSize(); z++) {
|
||||
BlockPos pos = gof.getPosition().add(x, 0, z);
|
||||
|
||||
// System.out.println("Search at " + pos.toShortString() + ": " + instance.world.getBlockState(pos).getBlock().getName());
|
||||
|
||||
if (gof.getCell(Vector2.fromBlockPos(pos))) {
|
||||
instance.getServer().getOverworld().setBlockState(pos, Blocks.OBSIDIAN.getDefaultState());
|
||||
} else {
|
||||
instance.getServer().getOverworld().setBlockState(pos, Blocks.AIR.getDefaultState());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (queue.isEmpty())
|
||||
return;
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
if (queueKeys == null || !queueKeys.hasNext())
|
||||
return;
|
||||
for (int i = 0; i < 50; i++) {
|
||||
if (queue.isEmpty())
|
||||
break;
|
||||
|
||||
BlockPos pos = queueKeys.next();
|
||||
BlockState state = queue.get(pos);
|
||||
BlockStatePosition block = queue.remove(0);
|
||||
|
||||
if (state == null)
|
||||
return;
|
||||
//CustomStructures.LOGGER.info("Built at " + pos.toShortString() + "\t Q:" + queue.size());
|
||||
|
||||
//CustomStructures.LOGGER.info("Build at " + pos.toShortString() + "\t Q:" + queue.size());
|
||||
|
||||
instance.getServer().getOverworld().setBlockState(pos, state, Block.NOTIFY_NEIGHBORS);
|
||||
instance.world.addBlockBreakParticles(pos, state);
|
||||
instance.world.playSound(pos, SoundEvents.BLOCK_STONE_PLACE, SoundCategory.BLOCKS, 1f, 1f, true);
|
||||
|
||||
queue.remove(pos);
|
||||
instance.getServer().getOverworld().setBlockState(block.pos, block.state, Block.NOTIFY_LISTENERS);
|
||||
instance.world.addBlockBreakParticles(block.pos, block.state);
|
||||
instance.world.playSound(block.pos, SoundEvents.BLOCK_STONE_PLACE, SoundCategory.BLOCKS, 1f, 1f, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,12 +5,9 @@ import io.github.cottonmc.cotton.gui.widget.WButton;
|
||||
import io.github.cottonmc.cotton.gui.widget.WGridPanel;
|
||||
import io.github.cottonmc.cotton.gui.widget.WLabel;
|
||||
import io.github.cottonmc.cotton.gui.widget.WSlider;
|
||||
import io.github.cottonmc.cotton.gui.widget.WSprite;
|
||||
import io.github.cottonmc.cotton.gui.widget.data.Axis;
|
||||
import io.github.cottonmc.cotton.gui.widget.data.Insets;
|
||||
import net.minecraft.client.gui.hud.MessageIndicator.Icon;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
public class SettingsGui extends LightweightGuiDescription {
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package de.nicolasklier.custom_structures.items;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import de.nicolasklier.custom_structures.GameOfLife;
|
||||
import de.nicolasklier.custom_structures.Helper;
|
||||
import de.nicolasklier.custom_structures.events.PlayerTick;
|
||||
import de.nicolasklier.custom_structures.guis.SettingsGui;
|
||||
import de.nicolasklier.custom_structures.guis.SettingsScreen;
|
||||
import de.nicolasklier.custom_structures.structures.Generations;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.TypedActionResult;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.hit.HitResult;
|
||||
import net.minecraft.util.hit.HitResult.Type;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class GameOfLifeSpawner extends Item {
|
||||
|
||||
public GameOfLifeSpawner(Settings settings) {
|
||||
super(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedActionResult<ItemStack> use(World world, PlayerEntity user, Hand hand) {
|
||||
MinecraftClient client = MinecraftClient.getInstance();
|
||||
|
||||
// Block event on server-side.
|
||||
if(!world.isClient()) {
|
||||
return TypedActionResult.success(user.getStackInHand(hand));
|
||||
}
|
||||
|
||||
// If the player is sneaking, we open a setting menu.
|
||||
if (client.player.isSneaking()) {
|
||||
PlayerTick.gofStart = !PlayerTick.gofStart;
|
||||
} else {
|
||||
HitResult hit = Helper.raycastInDirection(client, client.getTickDelta(), client.cameraEntity.getRotationVec(client.getTickDelta()));
|
||||
|
||||
Generations gen = new Generations();
|
||||
|
||||
if (hit.getType() == Type.BLOCK) {
|
||||
BlockHitResult result = (BlockHitResult) hit;
|
||||
|
||||
final int SPACE = 100;
|
||||
BlockPos pos = result.getBlockPos();
|
||||
PlayerTick.gof = new GameOfLife(SPACE, pos.add(0, 1, 0));
|
||||
|
||||
// Build box around simulation
|
||||
// Ground
|
||||
for (int x = 0; x < SPACE; x++) {
|
||||
for (int z = 0; z < SPACE; z++) {
|
||||
if (x == 0 || x == SPACE - 1) {
|
||||
if (z == 0 || z == SPACE - 1) {
|
||||
client.getServer().getOverworld().setBlockState(pos.add(x, 1, z), Blocks.QUARTZ_SLAB.getDefaultState());
|
||||
}
|
||||
}
|
||||
client.getServer().getOverworld().setBlockState(pos.add(x, 0, z), Blocks.QUARTZ_BLOCK.getDefaultState());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TypedActionResult.success(user.getStackInHand(hand));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,10 +25,14 @@ public class StructureSpawner extends Item {
|
||||
|
||||
@Override
|
||||
public TypedActionResult<ItemStack> use(World world, PlayerEntity user, Hand hand) {
|
||||
System.out.println("Used item!");
|
||||
|
||||
MinecraftClient client = MinecraftClient.getInstance();
|
||||
|
||||
// Block event on server-side.
|
||||
if(!world.isClient()) {
|
||||
return TypedActionResult.success(user.getStackInHand(hand));
|
||||
}
|
||||
|
||||
System.out.println("Used item!");
|
||||
|
||||
// If the player is sneaking, we open a setting menu.
|
||||
if (client.player.isSneaking()) {
|
||||
@@ -47,6 +51,7 @@ public class StructureSpawner extends Item {
|
||||
options.width = 5;
|
||||
options.height = 20;
|
||||
options.noise = new StaircaseNoiseOptions();
|
||||
options.noise.shiftZ = true;
|
||||
options.noise.threshold = 0.64f;
|
||||
options.minecartTrack = true;
|
||||
options.mirror = true;
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
package de.nicolasklier.custom_structures.structures;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
import org.spongepowered.noise.module.source.Perlin;
|
||||
|
||||
import de.nicolasklier.custom_structures.CustomStructures;
|
||||
import de.nicolasklier.custom_structures.events.PlayerTick;
|
||||
import de.nicolasklier.custom_structures.utils.BlockStatePosition;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
@@ -32,8 +29,9 @@ public class Generations {
|
||||
}
|
||||
|
||||
public void spawnStaircase(BlockPos at, StaircaseOptions options) {
|
||||
Map<BlockPos, BlockState> placeQueue = new HashMap<>();
|
||||
MinecraftClient instance = MinecraftClient.getInstance();
|
||||
List<BlockStatePosition> placeQueue = new ArrayList<>();
|
||||
|
||||
MinecraftClient instance = MinecraftClient.getInstance();
|
||||
int length = options.height * options.stretch * (options.mirror ? 2 : 1);
|
||||
|
||||
Random rng = new Random();
|
||||
@@ -46,6 +44,11 @@ public class Generations {
|
||||
: 0;
|
||||
int minecartRedstoneTorchStep = 0;
|
||||
|
||||
/**
|
||||
* Since how many blocks are we going straight?
|
||||
*/
|
||||
int straightBlocks = 0;
|
||||
|
||||
int y = -(options.weight);
|
||||
int step = 0;
|
||||
|
||||
@@ -66,6 +69,32 @@ public class Generations {
|
||||
while (true) {
|
||||
x++;
|
||||
|
||||
BlockPos currentShift = null;
|
||||
BlockPos nextShift = null;
|
||||
|
||||
// Calculate z-shift
|
||||
if (noise != null) {
|
||||
double currentShiftNoise = noise.get(x + 1_000, -5_000, 0);
|
||||
double nextShiftNoise = noise.get(x + 1_000 + 1, -5_000, 0);
|
||||
|
||||
currentShift = currentShiftNoise < options.noise.shiftRightThreshold ? new BlockPos(0, 0, 1) :
|
||||
(currentShiftNoise > options.noise.shiftRightThreshold && currentShiftNoise < options.noise.shiftLeftThreshold ? new BlockPos(0, 0, -1) : BlockPos.ORIGIN);
|
||||
|
||||
nextShift = nextShiftNoise < options.noise.shiftRightThreshold ? new BlockPos(0, 0, 1) :
|
||||
(nextShiftNoise > options.noise.shiftRightThreshold && nextShiftNoise < options.noise.shiftLeftThreshold ? new BlockPos(0, 0, -1) : BlockPos.ORIGIN);
|
||||
|
||||
if (currentShift.getZ() == 0) {
|
||||
straightBlocks++;
|
||||
} else {
|
||||
// Block shift if we shifted one block before. The reason is that rails are buggy.
|
||||
if (straightBlocks < 1) {
|
||||
currentShift = BlockPos.ORIGIN;
|
||||
nextShift = BlockPos.ORIGIN;
|
||||
}
|
||||
straightBlocks = 0;
|
||||
}
|
||||
}
|
||||
|
||||
boolean isMirroring = y > options.height && options.mirror || reachedTop;
|
||||
|
||||
if (isMirroring) {
|
||||
@@ -88,6 +117,11 @@ public class Generations {
|
||||
else y++;
|
||||
}
|
||||
|
||||
// Shift staircase if enabled.
|
||||
if (options.noise.shiftZ) {
|
||||
at = at.add(currentShift);
|
||||
}
|
||||
|
||||
System.out.println("Noise: " + noise.get(x, 0, 0) + " | X: " + x + " Y: " + y);
|
||||
} else {
|
||||
if (step >= options.stretch) {
|
||||
@@ -113,7 +147,7 @@ public class Generations {
|
||||
} else {
|
||||
if (noise.get(x + 1, 0, 0) < options.noise.threshold) {
|
||||
isNextHeight = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (options.stretch > 1) {
|
||||
@@ -132,25 +166,21 @@ public class Generations {
|
||||
// From left to right
|
||||
for (int z2 = 0; z2 <= options.width; z2 += (options.width - 1) / options.fenceHorizontalDensity) {
|
||||
// Place fence manually on ground because the loop below offsets by one.
|
||||
placeQueue.put(at.add(x + 1, 0, z2), getRandomFance(rng));
|
||||
placeQueue.add(new BlockStatePosition(new BlockPos(x + 1, 0, z2), getRandomFance(rng)));
|
||||
|
||||
int y2 = y + 2;
|
||||
while (true) {
|
||||
break;
|
||||
Material mat = instance.getServer().getOverworld().getBlockState(new BlockPos(x, y2, z2)).getMaterial();
|
||||
if (mat == Material.AIR || mat == Material.WATER) {
|
||||
placeQueue.put(at.add(x, y2, z2), getRandomFance(rng));
|
||||
placeQueue.put(at.add(x + 1, y2 + 1, z2), getRandomFance(rng));
|
||||
for (int y2 = y + options.weight; y > -64; y2--) {
|
||||
BlockPos pos = new BlockPos(x, y2, z2);
|
||||
Block mat = instance.getServer().getOverworld().getBlockState(pos).getBlock();
|
||||
|
||||
System.out.println("Fence " + pos.toShortString() + "\t(" + mat.toString() + ")");
|
||||
|
||||
if (mat == Blocks.AIR || mat == Blocks.WATER) {
|
||||
System.out.println("Set fence at " + pos.toShortString());
|
||||
placeQueue.add(new BlockStatePosition(new BlockPos(x, y2, z2), getRandomFance(rng)));
|
||||
placeQueue.add(new BlockStatePosition(new BlockPos(x + 1, y2 + 1, z2), getRandomFance(rng)));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
System.out.println("Fence stuff " + y2 + "(" + mat.toString() + ")");
|
||||
|
||||
if (y2 <= -64)
|
||||
break;
|
||||
|
||||
y2--;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
@@ -171,7 +201,7 @@ public class Generations {
|
||||
// Building imperfection
|
||||
if (rng.nextFloat() < 0.001) continue;
|
||||
|
||||
placeQueue.put(at.add(x, y + j, z), block.getDefaultState());
|
||||
placeQueue.add(new BlockStatePosition(at.add(x, y + j, z), block.getDefaultState()));
|
||||
}
|
||||
|
||||
Direction facing = isMirroring ? Direction.WEST : Direction.EAST;
|
||||
@@ -184,7 +214,7 @@ public class Generations {
|
||||
stairState = stairState.with(Properties.HORIZONTAL_FACING, facing);
|
||||
|
||||
if (rng.nextFloat() < options.chanceSlap / 100f) {
|
||||
placeQueue.put(at.add(x, y + options.weight, z), Blocks.SMOOTH_STONE_SLAB.getDefaultState());
|
||||
placeQueue.add(new BlockStatePosition(at.add(x, y + options.weight, z), Blocks.SMOOTH_STONE_SLAB.getDefaultState()));
|
||||
} else {
|
||||
//CustomStructures.LOGGER.info("Noise [" + x + ", " + y + ", " + z + "]: " + noise.get(x, y + options.weight, z));
|
||||
if (noise.get(x, y + options.weight, 0) < options.chanceWoodStair / 100f) {
|
||||
@@ -197,40 +227,52 @@ public class Generations {
|
||||
.with(Properties.HORIZONTAL_FACING, stairState.get(Properties.HORIZONTAL_FACING));
|
||||
}
|
||||
|
||||
placeQueue.put(at.add(x, y + options.weight, z), stairState);
|
||||
placeQueue.add(new BlockStatePosition(at.add(x, y + options.weight, z), stairState));
|
||||
}
|
||||
} else {
|
||||
if (rng.nextFloat() < 0.04) {
|
||||
placeQueue.put(at.add(x, y + options.weight - 1, z), Blocks.GLOWSTONE.getDefaultState());
|
||||
if (rng.nextFloat() < options.chanceGlowstone / 100) {
|
||||
placeQueue.add(new BlockStatePosition(at.add(x, y + options.weight - 1, z), Blocks.GLOWSTONE.getDefaultState()));
|
||||
}
|
||||
}
|
||||
|
||||
// Build wall
|
||||
if ((z == 0 || z == options.width - 1) && options.wallHeight > 0) {
|
||||
for (int y2 = 0; y2 < options.wallHeight; y2++) {
|
||||
placeQueue.put(at.add(x, y + y2 + options.weight, z), Blocks.OAK_PLANKS.getDefaultState());
|
||||
placeQueue.add(new BlockStatePosition(at.add(x, y + y2 + options.weight, z), Blocks.OAK_PLANKS.getDefaultState()));
|
||||
}
|
||||
|
||||
placeQueue.put(at.add(x, y + options.wallHeight + options.weight, z), Blocks.OAK_FENCE.getDefaultState());
|
||||
placeQueue.put(at.add(x, y + options.wallHeight + options.weight + 1, z), Blocks.OAK_FENCE.getDefaultState());
|
||||
placeQueue.put(at.add(x, y + options.wallHeight + options.weight + 2, z), Blocks.OAK_PLANKS.getDefaultState());
|
||||
placeQueue.add(new BlockStatePosition(at.add(x, y + options.wallHeight + options.weight, z), Blocks.OAK_FENCE.getDefaultState()));
|
||||
placeQueue.add(new BlockStatePosition(at.add(x, y + options.wallHeight + options.weight + 1, z), Blocks.OAK_FENCE.getDefaultState()));
|
||||
placeQueue.add(new BlockStatePosition(at.add(x, y + options.wallHeight + options.weight + 2, z), Blocks.OAK_PLANKS.getDefaultState()));
|
||||
|
||||
if (isNextHeight) {
|
||||
placeQueue.put(at.add(x, y + options.wallHeight + options.weight + 3, z), Blocks.OAK_STAIRS.getDefaultState()
|
||||
.with(Properties.HORIZONTAL_FACING, facing));
|
||||
placeQueue.add(new BlockStatePosition(at.add(x, y + options.wallHeight + options.weight + 3, z), Blocks.OAK_STAIRS.getDefaultState()
|
||||
.with(Properties.HORIZONTAL_FACING, facing)));
|
||||
}
|
||||
}
|
||||
|
||||
// Minecart rails
|
||||
if (minecartTrackPosition > 0 && z == minecartTrackPosition) {
|
||||
System.array
|
||||
// Place additional rail if we shift staircase to left or right.
|
||||
if (noise != null && options.noise.shiftZ) {
|
||||
placeQueue.add(new BlockStatePosition(at.add(x, y + options.weight, z).add(nextShift), Blocks.RAIL.getDefaultState()));
|
||||
}
|
||||
|
||||
if (minecartRedstoneTorchStep >= 4) {
|
||||
placeQueue.put(at.add(x, y + options.weight - 2, z), Blocks.REDSTONE_TORCH.getDefaultState());
|
||||
placeQueue.put(at.add(x, y + options.weight, z), Blocks.POWERED_RAIL.getDefaultState());
|
||||
|
||||
minecartRedstoneTorchStep = 0;
|
||||
|
||||
// Don't place powered rail because they can only go straight.
|
||||
if (noise != null && options.noise.shiftZ) {
|
||||
if (nextShift.getZ() != 0) {
|
||||
placeQueue.add(new BlockStatePosition(at.add(x, y + options.weight, z).add(nextShift), Blocks.RAIL.getDefaultState()));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
placeQueue.add(new BlockStatePosition(at.add(x, y + options.weight - 2, z), Blocks.REDSTONE_TORCH.getDefaultState()));
|
||||
placeQueue.add(new BlockStatePosition(at.add(x, y + options.weight, z), Blocks.POWERED_RAIL.getDefaultState()));
|
||||
} else {
|
||||
placeQueue.put(at.add(x, y + options.weight, z), Blocks.RAIL.getDefaultState());
|
||||
placeQueue.add(new BlockStatePosition(at.add(x, y + options.weight, z), Blocks.RAIL.getDefaultState()));
|
||||
}
|
||||
|
||||
minecartRedstoneTorchStep++;
|
||||
@@ -240,12 +282,8 @@ public class Generations {
|
||||
step++;
|
||||
}
|
||||
|
||||
PlayerTick.queue.putAll(placeQueue);
|
||||
|
||||
Set<BlockPos> set = placeQueue.keySet();
|
||||
List<BlockPos> list = new ArrayList<>(set);
|
||||
//Collections.shuffle(list);
|
||||
PlayerTick.queueKeys = list.iterator();
|
||||
PlayerTick.queue.addAll(placeQueue);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,15 @@ public class StaircaseNoiseOptions {
|
||||
*/
|
||||
public float threshold = 0.7f;
|
||||
|
||||
/**
|
||||
* If set to true, the staircase will change its z-coordinate based on the noise.
|
||||
*/
|
||||
public boolean shiftZ = false;
|
||||
|
||||
public double shiftLeftThreshold = 0.55;
|
||||
|
||||
public double shiftRightThreshold = 0.4;
|
||||
|
||||
public Random rng = new Random();
|
||||
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ public class StaircaseOptions {
|
||||
/**
|
||||
* Value between 0% and 100% being the chance to spawn glowstone.
|
||||
*/
|
||||
public short chanceGlowstone = 4;
|
||||
public short chanceGlowstone = 0;
|
||||
|
||||
/**
|
||||
* Value between 0% and 100% being the chance to spawn mossy cobblestone.
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package de.nicolasklier.custom_structures.utils;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
/**
|
||||
* Tiny struct like class to store position and block state in one object.
|
||||
*
|
||||
*/
|
||||
public class BlockStatePosition {
|
||||
|
||||
public BlockPos pos;
|
||||
public BlockState state;
|
||||
|
||||
public BlockStatePosition(BlockPos pos, BlockState state) {
|
||||
this.pos = pos;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package de.nicolasklier.custom_structures.utils;
|
||||
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
public class Vector2 {
|
||||
|
||||
public int x, y;
|
||||
|
||||
public Vector2(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.x + " " + this.y;
|
||||
}
|
||||
|
||||
public static Vector2 fromBlockPos(BlockPos pos) {
|
||||
// Minecraft's coordinates are flipped.
|
||||
return new Vector2(pos.getX(), pos.getZ());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "item/generated",
|
||||
"textures": {
|
||||
"layer0": "customstructures:item/gameoflife_spawner"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 258 B |
Reference in New Issue
Block a user