Minestom Cellular Automata Server (Conway's Game of Life)
A Minestom server implementing Conway's Game of Life cellular automata with player interaction
Description
This snippet creates a Minestom server that simulates Conway’s Game of Life on a 50x50 grid. Players can interact with the simulation by placing and removing cells. The simulation runs in discrete steps rather than real-time.
Code
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; }}
package com.example.minestom;import net.minestom.server.MinecraftServer;import net.minestom.server.command.CommandSender;import net.minestom.server.command.builder.Command;import net.minestom.server.command.builder.arguments.ArgumentType;public class CommandManager { public static void registerCommands(GameOfLifeServer server) { Command startCommand = new Command("start"); startCommand.setDefaultExecutor((sender, context) -> { if (!(sender instanceof CommandSender)) return; server.startSimulation(); sender.sendMessage("§aStarted Game of Life simulation!"); }); Command stopCommand = new Command("stop"); stopCommand.setDefaultExecutor((sender, context) -> { if (!(sender instanceof CommandSender)) return; server.stopSimulation(); sender.sendMessage("§cStopped Game of Life simulation!"); }); Command clearCommand = new Command("clear"); clearCommand.setDefaultExecutor((sender, context) -> { if (!(sender instanceof CommandSender)) return; if (server.isRunning()) { sender.sendMessage("§cCannot clear while simulation is running!"); return; } for (int x = 0; x < GameOfLifeServer.GRID_SIZE; x++) { for (int z = 0; z < GameOfLifeServer.GRID_SIZE; z++) { server.grid[x][z] = false; server.updateBlock(x, z); } } sender.sendMessage("§aGrid cleared!"); }); MinecraftServer.getCommandManager().register(startCommand); MinecraftServer.getCommandManager().register(stopCommand); MinecraftServer.getCommandManager().register(clearCommand); }}
package com.example.minestom;public class Main { public static void main(String[] args) { GameOfLifeServer server = new GameOfLifeServer(); CommandManager.registerCommands(server); GameOfLifeServer.main(args); }}
Comments
No comments yet. Be the first to comment!
Please login to leave a comment.