Skip to content
Draft
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
6 changes: 6 additions & 0 deletions src/main/java/io/github/mal32/endergames/EnderGames.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
import com.mojang.brigadier.tree.LiteralCommandNode;
import io.github.mal32.endergames.worlds.game.GameWorld;
import io.github.mal32.endergames.worlds.lobby.LobbyWorld;
import io.github.mal32.endergames.worlds.lobby.MapManager;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import io.papermc.paper.command.brigadier.Commands;
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents;
import java.util.ArrayList;
import java.util.Objects;
import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit;
Expand All @@ -33,6 +35,10 @@ public static boolean playerIsInGameWorld(Player player) {
return Objects.equals(world, "game");
}

public void sendNewMapPixelsToLobby(ArrayList<MapPixel> pixelBatch) {
MapManager.addToMapWall(pixelBatch);
}

@Override
public void onEnable() {
final int PLUGIN_ID = 25844;
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/io/github/mal32/endergames/MapPixel.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package io.github.mal32.endergames;

import java.awt.*;

public record MapPixel(int x, int y, Color color) {}
105 changes: 80 additions & 25 deletions src/main/java/io/github/mal32/endergames/worlds/game/LoadPhase.java
Original file line number Diff line number Diff line change
@@ -1,31 +1,48 @@
package io.github.mal32.endergames.worlds.game;

import io.github.mal32.endergames.EnderGames;
import io.github.mal32.endergames.MapPixel;
import java.awt.Color;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
import org.bukkit.*;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.block.structure.Mirror;
import org.bukkit.block.structure.StructureRotation;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scheduler.BukkitTask;
import org.bukkit.structure.Structure;
import org.bukkit.structure.StructureManager;
import org.bukkit.util.BlockVector;

public class LoadPhase extends AbstractPhase {
final int loadDelayIncrease = 5;
private final ArrayList<BukkitTask> loadTasks = new ArrayList<>();
int loadDelayTicks = 0;
private final Queue<Location> chunksToLoad = new LinkedList<>() {};
private final BukkitTask chunkGenWorker;
private final int MAP_SIZE = 600;

public LoadPhase(EnderGames plugin, GameWorld manager, Location spawnLocation) {
super(plugin, manager, spawnLocation);

placeSpawnPlatform();

var startLoadTask =
Bukkit.getScheduler().runTaskLater(this.plugin, this::loadSpawnChunks, 20 * 5);
loadTasks.add(startLoadTask);
scheduleChunks();
plugin.getComponentLogger().info("" + chunksToLoad.size());

BukkitScheduler scheduler = plugin.getServer().getScheduler();
final int CHUNK_GEN_DELAY_TICKS = 1;
chunkGenWorker =
scheduler.runTaskTimer(plugin, this::chunkGenWorker, 20 * 5, CHUNK_GEN_DELAY_TICKS);
}

@Override
public void disable() {
super.disable();

chunkGenWorker.cancel();
}

public void placeSpawnPlatform() {
Expand All @@ -40,43 +57,81 @@ public void placeSpawnPlatform() {
structure.place(location, true, StructureRotation.NONE, Mirror.NONE, 0, 1.0f, new Random());
}

private void loadSpawnChunks() {
final int loadRadius = 8;
private void scheduleChunks() {
final int LOAD_RADIUS_CHUNKS = (int) Math.ceil(((float) MAP_SIZE) / 16); // 32
var location = spawnLocation.clone();

chunksToLoad.add(location.clone());

int invert = 1;
for (int i = 0; i < loadRadius; i++) {
for (int i = 0; i < LOAD_RADIUS_CHUNKS; i++) {
for (int k = 0; k < i; k++) {
location.add(invert * 16, 0, 0);
scheduleChunkLoad(location.clone());
chunksToLoad.add(location.clone());
}
for (int k = 0; k < i; k++) {
location.add(0, 0, invert * 16);
scheduleChunkLoad(location.clone());
chunksToLoad.add(location.clone());
}

invert *= -1;
}
}

private void scheduleChunkLoad(Location location) {
var chunkLoadTask =
Bukkit.getScheduler()
.runTaskLater(
plugin, () -> location.getWorld().getChunkAt(location).load(true), loadDelayTicks);
loadTasks.add(chunkLoadTask);
private void chunkGenWorker() {
if (chunksToLoad.isEmpty()) {
chunkGenWorker.cancel();
return;
}
Location location = chunksToLoad.poll();

loadDelayTicks += loadDelayIncrease;
}
Chunk chunk = location.getWorld().getChunkAt(location);
chunk.load(true);

@Override
public void disable() {
super.disable();
Location spawnHorizontalLocation = spawnLocation.clone();
spawnHorizontalLocation.setY(0);

ArrayList<MapPixel> pixelBatch = new ArrayList<>();

for (BukkitTask task : loadTasks) {
if (task == null || task.isCancelled()) continue;
for (int x = 0; x < 16; x++) {
for (int y = 0; y < 16; y++) {
Location blockHorizontalLocation = location.clone().add(x, 0, y);
Block highestBlock = spawnLocation.getWorld().getHighestBlockAt(blockHorizontalLocation);
Color color = getBlockColor(highestBlock);

task.cancel();
Location delta = blockHorizontalLocation.clone().subtract(spawnHorizontalLocation);
Location inverted = delta.multiply(-1);
int mapX = (int) inverted.getX() + (MAP_SIZE / 2);
int mapY = (int) inverted.getZ() + (MAP_SIZE / 2);
if (mapX >= 0 && mapX < MAP_SIZE && mapY >= 0 && mapY < MAP_SIZE) {
pixelBatch.add(new MapPixel(mapX, mapY, color));
}
}
}

plugin.sendNewMapPixelsToLobby(pixelBatch);
}

private static Color getBlockColor(Block block) {
var blockBukkitColor = block.getBlockData().getMapColor();
Color blockColor =
new Color(
blockBukkitColor.getRed(), blockBukkitColor.getGreen(), blockBukkitColor.getBlue());

Block aboveHighest = block.getRelative(0, 1, 0);
var adjacentBlocks =
new Block[] {
aboveHighest.getRelative(0, 0, 1),
aboveHighest.getRelative(1, 0, 0),
aboveHighest.getRelative(-1, 0, 0),
aboveHighest.getRelative(0, 0, -1)
};
for (Block adjacent : adjacentBlocks) {
if (adjacent.isSolid() && !adjacent.isLiquid()) {
blockColor = blockColor.darker();
}
}

return blockColor;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@ public class LobbyWorld extends AbstractWorld {
private final World lobbyWorld = Objects.requireNonNull(Bukkit.getWorld("world_enga_lobby"));
private final Location spawnLocation = new Location(lobbyWorld, 0, 64, 0);
private final ParkourManager pmanager;
//private final MapManager mapmanager;

public LobbyWorld(EnderGames plugin) {
super(plugin);
this.pmanager = new ParkourManager(plugin);
//this.mapmanager = new MapManager(plugin);

this.menuManager = new MenuManager(this.plugin);

Expand Down
137 changes: 137 additions & 0 deletions src/main/java/io/github/mal32/endergames/worlds/lobby/MapManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package io.github.mal32.endergames.worlds.lobby;

import java.awt.Color;
import java.util.ArrayList;
import java.util.HashSet;

import io.github.mal32.endergames.MapPixel;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.*;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.MapMeta;
import org.bukkit.map.MapCanvas;
import org.bukkit.map.MapRenderer;
import org.bukkit.map.MapView;
import org.bukkit.plugin.java.JavaPlugin;

record MapTile(int x, int y) {
}

public class MapManager {

private static final int MATRIX_SIZE = 600;
private static final int TILE = 128;
private static final int TILES = 5; // 5x5
private static final int TOTAL_PIXELS = TILES * TILE; // 640
// center 600 inside 640 -> margin 40 total -> 20 on each side
private static final int CENTER_OFFSET = (TOTAL_PIXELS - MATRIX_SIZE) / 2;
private final JavaPlugin plugin;

Check warning on line 31 in src/main/java/io/github/mal32/endergames/worlds/lobby/MapManager.java

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/main/java/io/github/mal32/endergames/worlds/lobby/MapManager.java#L31

Perhaps 'plugin' could be replaced by a local variable.

public MapManager(JavaPlugin plugin) {
this.plugin = plugin;
}

private static Color[][] matrix = new Color[MATRIX_SIZE][MATRIX_SIZE];

private static void addChunkPixelsToMatrix(ArrayList<MapPixel> chunkPixels) {
for (MapPixel pixel : chunkPixels) {
matrix[pixel.y()][pixel.x()] = pixel.color();
}
}

private static int getTileIndexOfCoordinate(int coord) {
int coord_with_border = coord + CENTER_OFFSET;
return coord_with_border / TILE;
}

private static HashSet<MapTile> getChangedMapTiles(ArrayList<MapPixel> chunkPixels) {
HashSet<MapTile> changedMapTiles = new HashSet<MapTile>();

int[] arr = { 0, 15, 239, 255 }; // index of 4 corner points of chunk
for (int value : arr) {
MapTile mapTile = new MapTile(getTileIndexOfCoordinate(chunkPixels.get(value).x()), getTileIndexOfCoordinate(chunkPixels.get(value).y()));
changedMapTiles.add(mapTile);
}
return changedMapTiles;
}

private static ItemStack generateMapFromMatrix(MapTile mapTile, World world) {
MapView view = Bukkit.createMap(world);

final int originX = mapTile.x() * TILE - CENTER_OFFSET;
final int originY = mapTile.y() * TILE - CENTER_OFFSET;

// remove default renderers
for (MapRenderer r : view.getRenderers())
view.removeRenderer(r);

view.addRenderer(new MapRenderer() {
private boolean rendered = false;

@Override
public void render(MapView mapView, MapCanvas canvas, Player player) {
if (rendered)
return;

for (int py = 0; py < TILE; py++) {
for (int px = 0; px < TILE; px++) {
int srcX = originX + px;
int srcY = originY + py;

// If inside the 600x600 matrix, use that color; otherwise use null ->
// transparent
Color c = (srcX >= 0 && srcX < MATRIX_SIZE && srcY >= 0 && srcY < MATRIX_SIZE)
? matrix[srcY][srcX]
: null; // null = show base pixel / transparent for this renderer

canvas.setPixelColor(px, py, c);
}
}
rendered = true;
}
});

ItemStack filled = new ItemStack(Material.FILLED_MAP);
MapMeta meta = (MapMeta) filled.getItemMeta();
meta.setMapView(view);
filled.setItemMeta(meta);

return filled;
}

private static void placeMapInFrame(MapTile mapTile, ItemStack map, World world) {
final int startX = 3; // left
final int startY = 75; // top
final int z = 7;

int x = startX - mapTile.x(); // left → right: 3,2,1,0,-1
int y = startY - mapTile.y(); // top → bottom: 75,74,73,72,71

Bukkit.getLogger().info("Placing map at " + x + ", " + y);

Location center = new Location(world, x + 0.5, y + 0.5, z + 0.5);

for (Entity e : world.getNearbyEntities(center, 0.6, 0.6, 0.6)) {
if (e instanceof GlowItemFrame) { // or ItemFrame if not using glow frames
ItemFrame frame = (ItemFrame) e;
frame.setItem(map, false);
break;
}
}
}

public static void addToMapWall(ArrayList<MapPixel> chunkPixels) {
World world = Bukkit.getWorld("world_enga_lobby");
addChunkPixelsToMatrix(chunkPixels);
HashSet<MapTile> changedMapTiles = getChangedMapTiles(chunkPixels);
for (MapTile mapTile : changedMapTiles) {
ItemStack map = generateMapFromMatrix(mapTile, world);
placeMapInFrame(mapTile, map, world);
Bukkit.getLogger().info(mapTile.toString());
}
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
package io.github.mal32.endergames.worlds.lobby; // adjust package

package io.github.mal32.endergames.worlds.lobby;
import java.io.File;
import java.io.IOException;
import java.util.*;
Expand Down
Loading