This commit is contained in:
LunarAkai 2024-03-22 00:16:12 +01:00
commit e46929b4b4
8 changed files with 260 additions and 148 deletions

View file

@ -15,11 +15,16 @@ import org.bukkit.entity.Display;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.util.Transformation;
import org.joml.Vector2i;
import org.joml.Vector3f;
import com.google.common.base.Preconditions;
import de.lunarakai.minecleaner.game.BoardSize;
import de.lunarakai.minecleaner.game.Cell;
import de.lunarakai.minecleaner.game.Cell.CellType;
import de.lunarakai.minecleaner.game.Game;
import de.lunarakai.minecleaner.game.Tile.TileType;
import de.lunarakai.minecleaner.utils.MinecleanerHeads;
import net.md_5.bungee.api.ChatColor;
public class MinecleanerArena {
private final MinecleanerPlugin plugin;
@ -30,6 +35,7 @@ public class MinecleanerArena {
private final BlockFace orientation;
private ArenaStatus arenaStatus = ArenaStatus.INACTIVE;
private UUID[] blockDisplays = new UUID[81]; // todo needs to be of size boardSizes[widthIndex]
private TileType[] currentMinecleaerTileTypesState;
private Player currentPlayer;
private long currentGameStartTime;
@ -163,6 +169,7 @@ public class MinecleanerArena {
loc.set(location.getX() + 0.11 - (d1x * fz) / 3.0 + d0x * 0.501 + d1x * 1.847, location.getY() - 0.9725 + fxf / 3.0, location.getZ() + 0.45 - (d1z * fz) / 3.0 + d0z * 0.501 + d1z * 1.847);
// Todo: ItemDisplay für Köpfe
Display blockDisplay = world.spawn(loc, BlockDisplay.class, blockdisplay -> {
Transformation transformation = blockdisplay.getTransformation();
Transformation newTransform;
@ -203,9 +210,20 @@ public class MinecleanerArena {
arenaSection.set("blockdisplays", blockDisplays);
}
private void setDiplayBlock(int x, int y, Material block) {
UUID blockDisplayId = blockDisplays[x + y *9];
Entity blockDisplay = blockDisplayId != null ? location.getWorld().getEntity(blockDisplayId) : null;
if(blockDisplay instanceof BlockDisplay) {
BlockDisplay display = (BlockDisplay) blockDisplay;
display.setBlock(block.createBlockData());
}
}
public void startNewGame() {
currentMinecleanerGame = new Game();
currentMinecleanerGame = new Game(plugin, 9, 12);
currentMinecleanerGame.start();
//currentMinecleaerTileTypes = currentMinecleanerGame.getMinecleanerPuzzle(widthIndex, widthIndex);
arenaStatus = ArenaStatus.PLAYING;
}
@ -219,6 +237,13 @@ public class MinecleanerArena {
public void removePlayer() {
this.arenaStatus = ArenaStatus.INACTIVE;
this.currentPlayer = null;
this.currentMinecleanerGame = null;
for(int x = 0; x < 9; x++) {
for(int y = 0; y < 9; y++) {
setDiplayBlock(x, y, Material.BEDROCK);
}
}
}
// block displays dont get removed
@ -228,7 +253,7 @@ public class MinecleanerArena {
for(int fy = 0; fy < 9; fy++) {
UUID blockDisplayUuid = blockDisplays[fx + fy * 9];
Entity blockDisplayEntity = blockDisplayUuid != null ? world.getEntity(blockDisplayUuid) : null;
if(blockDisplayEntity instanceof Display blockDisplay) {
if(blockDisplayEntity instanceof Display blockdisplay) {
blockDisplayEntity.remove();
}
}
@ -238,24 +263,137 @@ public class MinecleanerArena {
public void flagCell(int x, int y) {
if(currentMinecleanerGame != null) {
int id = x + y * 9;
boolean unflaggedCell = currentMinecleanerGame.flag(x, y);
if(!unflaggedCell) {
Cell cell = currentMinecleanerGame.getCell(x, y);
Player player = this.currentPlayer;
player.sendMessage(ChatColor.GOLD + "Cell: Pos(" + cell.position.x + "," + cell.position.y + "):" + " Is Flagged: " + cell.flagged + " ,Exploded: "
+ cell.exploded + " Is Revealed: " + cell.revealed + ", CellType: " + cell.getType());
if(cell.getType() == CellType.Number) {
player.sendMessage(ChatColor.GREEN + " Number: " + cell.number);
}
if(!cell.isRevealed() && !cell.isFlagged()) {
// todo set flag head on block display
} else {
currentMinecleanerGame.flag(x, y);
setDiplayBlock(x, y, Material.ORANGE_CONCRETE);
} else if(!cell.isRevealed() && cell.isFlagged() ){
// todo set normal head on block display
setDiplayBlock(x, y, Material.BEDROCK);
} else {
return;
}
}
}
private boolean isRevealedCell(int x, int y) {
Cell cell = currentMinecleanerGame.getCell(x, y);
if(cell.revealed) {
return true;
}
return false;
}
public void revealCell(int x, int y) {
if(currentMinecleanerGame != null) {
int id = x + y * 9;
// todo check if cell is flagged already
//int id = x + y * 9;
Cell cell = currentMinecleanerGame.getCell(x, y);
Player player = this.currentPlayer;
player.sendMessage(ChatColor.GOLD + "Cell: Pos(" + cell.position.x + "," + cell.position.y + "):" + " Is Flagged: " + cell.flagged + " ,Exploded: "
+ cell.exploded + " Is Revealed: " + cell.revealed + ", CellType: " + cell.getType());
if(cell.getType() == CellType.Number) {
player.sendMessage(ChatColor.GREEN + " Number: " + cell.number);
}
currentMinecleanerGame.reveal(x, y);
setBlockForCellType(x, y, cell);
ArrayList<Cell> floodedCells = currentMinecleanerGame.getfloodedCells();
if(floodedCells != null) {
player.sendMessage(ChatColor.GREEN + " Flooded Cells: [" + floodedCells.size() + "]");
for(int i = 0; i < floodedCells.size(); i++) {
Vector2i pos = floodedCells.get(i).position;
player.sendMessage(ChatColor.GREEN + " Cell(" + pos.x + pos.y + ")");
setBlockForCellType(pos.x, pos.y, floodedCells.get(i));
}
}
// Todo: Logic for flood
// todo update block of blockdisplay
}
}
private void setBlockForCellType(int x, int y, Cell cell) {
switch (cell.getType()) {
case Empty: {
if(!cell.isRevealed() || !cell.isFlagged() || !cell.isExploded()) {
setDiplayBlock(x, y, Material.GRAY_CONCRETE);
}
break;
}
case Number: {
if(!cell.isRevealed() || !cell.isFlagged() || !cell.isExploded()) {
switch(cell.number) {
case 1: {
setDiplayBlock(x, y, Material.LIME_CONCRETE_POWDER);
break;
}
case 2: {
setDiplayBlock(x, y, Material.GREEN_CONCRETE_POWDER);
break;
}
case 3: {
setDiplayBlock(x, y, Material.YELLOW_CONCRETE_POWDER);
break;
}
case 4: {
setDiplayBlock(x, y, Material.ORANGE_CONCRETE_POWDER);
break;
}
case 5: {
setDiplayBlock(x, y, Material.RED_CONCRETE_POWDER);
break;
}
case 6: {
setDiplayBlock(x, y, Material.LIGHT_BLUE_CONCRETE_POWDER);
break;
}
case 7: {
setDiplayBlock(x, y, Material.BLUE_CONCRETE_POWDER);
break;
}
case 8: {
setDiplayBlock(x, y, Material.BLACK_CONCRETE_POWDER);
break;
}
default: {
break;
}
}
}
break;
}
case Mine: {
if(cell.exploded) {
setDiplayBlock(x, y, Material.YELLOW_CONCRETE);
}
setDiplayBlock(x, y, Material.TNT);
break;
}
default: {
// Invalid
break;
}
}
}
private int matchWidthIndexToActualWidth(int widthIndex) {
switch (widthIndex) {
case 0:

View file

@ -49,7 +49,7 @@ public class MinecleanerListener implements Listener {
Player player = e.getPlayer();
//RayTraceResult rayTraceResult = player.getWorld().rayTraceBlocks(player.getEyeLocation(), player.getEyeLocation().getDirection(), 64.0);
RayTraceResult r2 = player.rayTraceBlocks(64.0);
RayTraceResult r2 = player.rayTraceBlocks(20.0);
//Location loc = e.getInteractionPoint().clone().subtract(arena.getLocation()).subtract(0.5, 0.5, 0.5); // null on left-click
@ -62,15 +62,17 @@ public class MinecleanerListener implements Listener {
if(r2 != null) {
Vector hitPos = r2.getHitPosition();
//Vector hitPos = rayTraceResult.getHitPosition();
Location loc = player.getLocation().add(hitPos.subtract(arena.getLocation().toVector())).clone().subtract(arena.getLocation()).subtract(0.5, 0.5, 0.5); // substract 0.5, 0.5, 0.5
Vector substract = new Vector(0.5, 0.5, 0.5);
Location loc = hitPos.subtract(arena.getLocation().toVector()).subtract(substract).toLocation(player.getWorld()); //(0.5, 0.5, 0.5); // substract 0.5, 0.5, 0.5
double lx = loc.getX();
double ly = loc.getY();
double lz = loc.getZ();
player.sendMessage(ChatColor.GRAY + "lx: " + lx + " ,ly: " + ly + " ,lz: " + lz);
double dy = ly + 2.5; // 1.5
player.sendMessage(ChatColor.GRAY + "dy: " + dy);
double dz = -d1x * lx - d1z * lz + 2.0; // 1.5
player.sendMessage(ChatColor.GRAY + "dz: " + dz);
//player.sendMessage(ChatColor.GRAY + "lx: " + lx + " ,ly: " + ly + " ,lz: " + lz);
double dy = ly + 1.5; // 1.5
//player.sendMessage(ChatColor.GRAY + "dy: " + dy);
double dz = -d1x * lx - d1z * lz + 1.5; // 1.5
//player.sendMessage(ChatColor.GRAY + "dz: " + dz);
double blockx = (dy / 3.0) * 9.0;
double blockz = (dz / 3.0) * 9.0;
@ -96,8 +98,8 @@ public class MinecleanerListener implements Listener {
}
*/
player.sendMessage(ChatColor.GRAY + "blockx: " + blockx + " ,blockz: " + blockz);
player.sendMessage(ChatColor.GRAY + "blockxInt: " + blockxInt + " ,blockzInt: " + blockzInt);
//player.sendMessage(ChatColor.GRAY + "blockx: " + blockx + " ,blockz: " + blockz);
// player.sendMessage(ChatColor.GRAY + "blockxInt: " + blockxInt + " ,blockzInt: " + blockzInt);
if (blockx >= 0.1 && blockx <= 0.9 && blockz >= 0.1 && blockz <= 0.9) {
boolean hasRightClicked = false;
@ -107,7 +109,7 @@ public class MinecleanerListener implements Listener {
// TODO Doesnt show messages for Cells: [ROW] [>5] (6, 7, 8 are missing)
player.sendMessage("Arena click! " + blockxInt + " " + blockzInt + " Right Clicked: " + hasRightClicked);
//plugin.getManager().handleFieldClick(e.getPlayer(), blockxInt, blockzInt, hasRightClicked);
plugin.getManager().handleFieldClick(e.getPlayer(), blockxInt, blockzInt, hasRightClicked);
}
}

View file

@ -10,6 +10,7 @@ import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import com.google.common.base.Preconditions;
import de.iani.cubesidestats.api.PlayerStatistics;
import de.iani.cubesidestats.api.PlayerStatisticsQueryKey;
@ -86,6 +87,20 @@ public class MinecleanerManager {
return confirmPlayingInventory;
}
public void handleFieldClick(@NotNull Player player, int x, int y, boolean hasRightClicked) {
MinecleanerArena arena = plugin.getArenaList().getPlayerArena(player);
Preconditions.checkArgument(arena != null, "player is in no arena");
Preconditions.checkState(arena.getArenaStatus() == ArenaStatus.PLAYING, "not running");
if(hasRightClicked) {
// flag
arena.flagCell(x, y);
} else {
// reveal
arena.revealCell(x, y);
}
}
public void getStatisticsForPlayer(OfflinePlayer player, Consumer<PlayerStatisticsData> callback) {
List<StatisticsQueryKey> keys = new ArrayList<>();
PlayerStatistics pStatistics = plugin.getCubesideStatistics().getStatistics(player.getUniqueId());

View file

@ -1,76 +0,0 @@
package de.lunarakai.minecleaner;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.joml.Vector2d;
import org.joml.Vector2i;
public class MinecleanerRayTrace {
MinecleanerPlugin plugin;
Location arenaFieldCenterLocation;
Location playerEyeLocation;
// get center of arena field -> define as (0,0) for now
// -> get clicked block
// --> get clicked cell on that block
// ---> get distance from clicked cell to arena center
// ----> do math idk??
/* Example on Board with Width Index 0 (9*9)
*
*
* | |
* ------|----------------------------------------------------------------|--
* (8,x) | (8,0) (8,1) (8,2) (8,3) (8,4) (8,5) (8,6) (8,7) (8,8) |
* | |
* (7,x) | (7,0) (7,1) (7,2) (7,3) (7,4) (7,5) (7,6) (7,7) (7,8) |
* | |
* (6,x) | (6,0) (6,1) (6,2) (6,3) (6,4) (6,5) (6,6) (6,7) (6,8) |
* | |
* (5,x) | (5,0) (5,1) (5,2) (5,3) (5,4) (5,5) (5,6) (5,7) (5,8) |
* | |
* (4,x) | (4,0) (4,1) (4,2) (4,3) (4,4) (4,5) (4,6) (4,7) (4,8) |
* | |
* (3,x) | (3,0) (3,1) (3,2) (3,3) (3,4) (3,5) (3,6) (3,7) (3,8) |
* | |
* (2,x) | (2,0) (2,1) (2,2) (2,3) (2,4) (2,5) (2,6) (2,7) (2,8) |
* | |
* (1,x) | (1,0) (1,1) (1,2) (1,3) (1,4) (1,5) (1,6) (1,7) (1,8) |
* | |
* (0,x) | (0,0) (0,1) (0,2) (0,3) (0,4) (0,5) (0,6) (0,7) (0,8) |
* ------|----------------------------------------------------------------|--
* | (y,0) (y,1) (y,2) (y,3) (y,4) (y,5) (y,6) (y,7) (y,8) |
*/
public MinecleanerRayTrace(MinecleanerPlugin plugin, MinecleanerArena arena, Player player) {
this.plugin = plugin;
this.playerEyeLocation = player.getEyeLocation();
arenaFieldCenterLocation = arena.getLocation().add(0.5, 0.5, 0.5);
}
public Vector2i getClickedCellPosition(Location rayTracedBlock) {
Vector2d fieldCenter = new Vector2d(4.0,4.0);
Vector2d blockVector = new Vector2d(rayTracedBlock.toVector().getX(), rayTracedBlock.toVector().getZ());
//double lengthblockVector = blockVector.length();
double distanceBlockFromFieldCenter = fieldCenter.sub(blockVector).length();
double distanceFieldCenterPlayerEyeLocation = returnDistanceBetweenTwoLocations(playerEyeLocation, arenaFieldCenterLocation);
return null;
}
private double returnDistanceBetweenTwoLocations(Location loc1, Location loc2) {
double distance = loc1.distance(loc2);
return distance;
}
}

View file

@ -1,6 +1,6 @@
package de.lunarakai.minecleaner.game;
import org.joml.Vector3i;
import org.joml.Vector2i;
public class Cell {
public enum CellType {
@ -11,9 +11,10 @@ public class Cell {
}
public Vector3i position;
public Vector2i position;
public CellType type;
public int number;
public boolean revealed;
public boolean flagged;
public boolean exploded;
@ -26,4 +27,26 @@ public class Cell {
return type;
}
public void setRevealed() {
this.revealed = true;
}
public boolean isRevealed() {
return revealed;
}
public void setFlaggedState(boolean flag) {
this.flagged = flag;
}
public boolean isFlagged() {
return flagged;
}
public void setExploded() {
this.exploded = true;
}
public boolean isExploded() {
return revealed;
}
}

View file

@ -1,18 +1,32 @@
package de.lunarakai.minecleaner.game;
import org.joml.Vector3i;
import java.util.ArrayList;
import org.joml.Vector2i;
import de.lunarakai.minecleaner.MinecleanerPlugin;
import de.lunarakai.minecleaner.utils.MathUtils;
public class Game {
public boolean gameover;
private MinecleanerPlugin plugin;
private int width;
private int height;
private int mineCount;
public int width;
public int height;
private int mineCount = 10;
private Cell[][] state;
private boolean gameover;
private Board board;
private BoardSize boardSize;
private Tilemap tilemap;
private ArrayList<Cell> floodedCells;
public Game(MinecleanerPlugin plugin, int width, int mineCount) {
this.plugin = plugin;
this.width = width;
this.height = width;
this.mineCount = mineCount;
this.floodedCells = new ArrayList<>();
}
private void onValidate() {
mineCount = MathUtils.clamp(mineCount, 0, width*height);
@ -20,15 +34,6 @@ public class Game {
public void start() {
board = new Board();
int[] _boardSizes = boardSize.boardSizes;
int[] _mineCounter = boardSize.mineCounter;
int _boardSizeIndex = 0;
width = _boardSizes[_boardSizeIndex];
height = _boardSizes[_boardSizeIndex];
mineCount = _mineCounter[_boardSizeIndex];
newGame();
}
@ -51,7 +56,7 @@ public class Game {
for (int x = 0; x < width; x ++) {
for (int y = 0; y < height; y++) {
Cell cell = new Cell();
cell.position = new Vector3i(x, 0, y);
cell.position = new Vector2i(x, y);
cell.setType(Cell.CellType.Empty);
state[x][y] = cell;
}
@ -99,6 +104,10 @@ public class Game {
}
}
public Tilemap getMinecleanerTilemap() {
return tilemap;
}
private int countMines(int cellX, int cellY) {
int count = 0;
@ -119,78 +128,76 @@ public class Game {
return count;
}
public boolean flag(int x, int y) {
// TODO: Vector3 worldPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition); <- Unity
//Vector3i cellPosition = null; // TODO board.tilemap.WorldToCell(worldPosition); <- Unity
public void flag(int x, int y) {
Cell cell = getCell(x, y);
if (cell.getType() == Cell.CellType.Invalid || cell.revealed) {
return false;
}
boolean isFlaggedAlready = false;
if(cell.flagged) {
isFlaggedAlready = true;
if (cell.getType() == Cell.CellType.Invalid || cell.isRevealed()) {
return;
}
cell.flagged = !cell.flagged;
state[x][y] = cell;
board.draw(state, tilemap);
return isFlaggedAlready;
return;
}
public boolean reveal(int x, int y) {
// TODO: Vector3 worldPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition); <- Unity
//Vector3i cellPosition = null; // TODO board.tilemap.WorldToCell(worldPosition); <- Unity
public void reveal(int x, int y) {
Cell cell = getCell(x, y);
if(cell.getType() == Cell.CellType.Invalid || cell.revealed || cell.flagged) {
return false;
if(cell.getType() == Cell.CellType.Invalid || cell.isRevealed() || cell.flagged) {
return;
}
boolean hitMine = false;
//boolean hitMine = false;
switch (cell.getType()) {
case Mine:
case Mine: {
explode(cell);
hitMine = true;
break;
case Empty:
}
case Empty: {
if(!floodedCells.isEmpty()) {
floodedCells.clear();
}
flood(cell);
checkWinCondition();
break;
default:
cell.revealed = true;
}
default: {
cell.setRevealed();
state[x][y] = cell;
checkWinCondition();
break;
}
}
board.draw(state, tilemap);
return hitMine;
}
public void flood(Cell cell) {
if(cell.revealed) return;
if(cell.getType() == Cell.CellType.Mine || cell.getType() == Cell.CellType.Invalid) return;
if(cell.isRevealed()) return;
if(cell.getType() == Cell.CellType.Mine || cell.getType() == Cell.CellType.Invalid || cell.position != null) return;
cell.revealed = true;
state[cell.position.x][cell.position.z] = cell;
cell.setRevealed();
floodedCells.add(cell);
state[cell.position.x][cell.position.y] = cell;
if(cell.getType() == Cell.CellType.Empty) {
flood(getCell(cell.position.x -1, cell.position.z));
flood(getCell(cell.position.x +1, cell.position.z));
flood(getCell(cell.position.x, cell.position.z -1));
flood(getCell(cell.position.x, cell.position.z +1));
flood(getCell(cell.position.x -1, cell.position.y));
flood(getCell(cell.position.x +1, cell.position.y));
flood(getCell(cell.position.x, cell.position.y -1));
flood(getCell(cell.position.x, cell.position.y +1));
}
// TODO return cellpos of flooded cell to update the block displays
// TODO: return cellpos of flooded cell to update the block displays
}
private void explode(Cell cell) {
gameover = true;
cell.revealed = true;
cell.exploded = true;
state[cell.position.x][cell.position.z] = cell;
state[cell.position.x][cell.position.y] = cell;
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
@ -227,7 +234,7 @@ public class Game {
}
}
private Cell getCell(int x, int y) {
public Cell getCell(int x, int y) {
if(isValid(x,y)) {
return state[x][y];
} else {
@ -238,4 +245,8 @@ public class Game {
private boolean isValid(int x, int y) {
return x >= 0 && x < width && y >= 0 && y < height;
}
public ArrayList<Cell> getfloodedCells() {
return floodedCells;
}
}

View file

@ -15,7 +15,6 @@ public class Tile {
TileMine,
TileExploded,
TileFlag,
}
public Tile.TileType tileType;

View file

@ -1,6 +1,6 @@
package de.lunarakai.minecleaner.game;
import org.joml.Vector3i;
import org.joml.Vector2i;
public class Tilemap {
@ -26,9 +26,9 @@ public class Tilemap {
}
}
// Set method
public void setTile(Vector3i pos, Tile.TileType tileType) {
public void setTile(Vector2i pos, Tile.TileType tileType) {
int x = pos.x();
int y = pos.z();
int y = pos.y();
if (x >= 0 && x < tiles.length && y >= 0 && y < tiles[0].length) {
tiles[x][y].setTileType(tileType);