package com.example.minestom;
import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Player;
import net.minestom.server.event.GlobalEventHandler;
import net.minestom.server.event.player.PlayerBlockInteractEvent;
import net.minestom.server.event.player.PlayerLoginEvent;
import net.minestom.server.event.player.PlayerSpawnEvent;
import net.minestom.server.instance.InstanceContainer;
import net.minestom.server.instance.InstanceManager;
import net.minestom.server.instance.block.Block;
import net.minestom.server.timer.TaskSchedule;
import java.util.HashSet;
import java.util.Set;
public class GameOfLifeServer {
private static final int GRID_SIZE = 50;
private static final Block ALIVE_BLOCK = Block.WHITE_WOOL;
private static final Block DEAD_BLOCK = Block.AIR;
private static final Pos GRID_START = new Pos(0, 40, 0);
private final boolean[][] grid = new boolean[GRID_SIZE][GRID_SIZE];
private final Set<Player> players = new HashSet<>();
private InstanceContainer instance;
private boolean isRunning = false;
public static void main(String[] args) {
MinecraftServer minecraftServer = MinecraftServer.init();
GameOfLifeServer server = new GameOfLifeServer();
GlobalEventHandler globalEventHandler = MinecraftServer.getGlobalEventHandler();
globalEventHandler.addListener(PlayerLoginEvent.class, server::onPlayerLogin);
globalEventHandler.addListener(PlayerSpawnEvent.class, server::onPlayerSpawn);
globalEventHandler.addListener(PlayerBlockInteractEvent.class, server::onBlockInteract);
minecraftServer.start("0.0.0.0", 25565);
}
private void onPlayerLogin(PlayerLoginEvent event) {
Player player = event.getPlayer();
players.add(player);
player.sendMessage("§aWelcome to Conway's Game of Life!");
player.sendMessage("§eRight-click blocks to toggle cells. Type /start to begin simulation.");
}
private void onPlayerSpawn(PlayerSpawnEvent event) {
if (instance == null) {
InstanceManager instanceManager = MinecraftServer.getInstanceManager();
instance = instanceManager.createInstanceContainer();
instance.setGenerator(unit -> unit.modifier().fillHeight(0, 40, Block.GRASS_BLOCK));
initializeGrid();
}
event.getPlayer().setInstance(instance, GRID_START.add(0, 5, GRID_SIZE/2));
}
private void onBlockInteract(PlayerBlockInteractEvent event) {
if (isRunning) {
event.getPlayer().sendMessage("§cCannot modify grid while simulation is running!");
return;
}
Pos blockPos = event.getBlockPosition();
int x = blockPos.blockX() - GRID_START.blockX();
int z = blockPos.blockZ() - GRID_START.blockZ();
if (x >= 0 && x < GRID_SIZE && z >= 0 && z < GRID_SIZE) {
grid[x][z] = !grid[x][z];
updateBlock(x, z);
}
}
private void initializeGrid() {
// Initialize with some gliders for demonstration
// Glider 1
grid[1][2] = true;
grid[2][3] = true;
grid[3][1] = true;
grid[3][2] = true;
grid[3][3] = true;
// Glider 2
grid[10][12] = true;
grid[11][13] = true;
grid[12][11] = true;
grid[12][12] = true;
grid[12][13] = true;
// Update all blocks
for (int x = 0; x < GRID_SIZE; x++) {
for (int z = 0; z < GRID_SIZE; z++) {
updateBlock(x, z);
}
}
}
private void updateBlock(int x, int z) {
Pos pos = GRID_START.add(x, 0, z);
instance.setBlock(pos, grid[x][z] ? ALIVE_BLOCK : DEAD_BLOCK);
}
public void startSimulation() {
if (isRunning) return;
isRunning = true;
MinecraftServer.getSchedulerManager().scheduleTask(() -> {
if (!isRunning) return;
boolean[][] newGrid = new boolean[GRID_SIZE][GRID_SIZE];
for (int x = 0; x < GRID_SIZE; x++) {
for (int z = 0; z < GRID_SIZE; z++) {
int neighbors = countNeighbors(x, z);
if (grid[x][z]) {
// Any live cell with fewer than two live neighbors dies (underpopulation)
// Any live cell with more than three live neighbors dies (overpopulation)
newGrid[x][z] = neighbors == 2 || neighbors == 3;
} else {
// Any dead cell with exactly three live neighbors becomes a live cell (reproduction)
newGrid[x][z] = neighbors == 3;
}
}
}
// Update grid and blocks
for (int x = 0; x < GRID_SIZE; x++) {
for (int z = 0; z < GRID_SIZE; z++) {
if (grid[x][z] != newGrid[x][z]) {
grid[x][z] = newGrid[x][z];
updateBlock(x, z);
}
}
}
// Broadcast generation count
players.forEach(p -> p.sendMessage("§7Generation completed"));
}, TaskSchedule.tick(10), TaskSchedule.tick(10));
}
public void stopSimulation() {
isRunning = false;
players.forEach(p -> p.sendMessage("§aSimulation stopped. You can now modify the grid."));
}
private int countNeighbors(int x, int z) {
int count = 0;
for (int dx = -1; dx <= 1; dx++) {
for (int dz = -1; dz <= 1; dz++) {
if (dx == 0 && dz == 0) continue;
int nx = x + dx;
int nz = z + dz;
if (nx >= 0 && nx < GRID_SIZE && nz >= 0 && nz < GRID_SIZE && grid[nx][nz]) {
count++;
}
}
}
return count;
}
}