BlueMap/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/RenderTask.java

188 lines
4.5 KiB
Java

package de.bluecolored.bluemap.sponge;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Deque;
import java.util.List;
import java.util.UUID;
import com.flowpowered.math.vector.Vector2d;
import com.flowpowered.math.vector.Vector2i;
public class RenderTask {
private final UUID uuid;
private String name;
private final MapType mapType;
private Deque<Vector2i> renderTiles;
private long firstTileTime;
private long additionalRunTime;
private int renderedTiles;
public RenderTask(String name, MapType mapType) {
this.uuid = UUID.randomUUID();
this.name = name;
this.mapType = mapType;
this.renderTiles = new ArrayDeque<>();
this.firstTileTime = -1;
this.additionalRunTime = 0;
this.renderedTiles = 0;
}
public void optimizeQueue() {
//Find a good grid size to match the MCAWorlds chunk-cache size of 500
Vector2d sortGridSize = new Vector2d(20, 20).div(mapType.getTileRenderer().getHiresModelManager().getTileSize().toDouble().div(16)).ceil().max(1, 1);
synchronized (renderTiles) {
Vector2i[] array = renderTiles.toArray(new Vector2i[renderTiles.size()]);
Arrays.sort(array, (v1, v2) -> {
Vector2i v1SortGridPos = v1.toDouble().div(sortGridSize).floor().toInt();
Vector2i v2SortGridPos = v2.toDouble().div(sortGridSize).floor().toInt();
if (v1SortGridPos != v2SortGridPos){
int v1Dist = v1SortGridPos.distanceSquared(Vector2i.ZERO);
int v2Dist = v2SortGridPos.distanceSquared(Vector2i.ZERO);
if (v1Dist < v2Dist) return -1;
if (v1Dist > v2Dist) return 1;
}
if (v1.getY() < v1.getY()) return -1;
if (v1.getY() > v1.getY()) return 1;
if (v1.getX() < v1.getX()) return -1;
if (v1.getX() > v1.getX()) return 1;
return 0;
});
renderTiles.clear();
for (Vector2i tile : array) {
renderTiles.add(tile);
}
}
}
public void addTile(Vector2i tile) {
synchronized (renderTiles) {
renderTiles.add(tile);
}
}
public void addTiles(Collection<Vector2i> tiles) {
synchronized (renderTiles) {
renderTiles.addAll(tiles);
}
}
public RenderTicket poll() {
synchronized (renderTiles) {
Vector2i tile = renderTiles.poll();
if (tile != null) {
renderedTiles++;
if (firstTileTime < 0) firstTileTime = System.currentTimeMillis();
return new RenderTicket(mapType, tile);
} else {
return null;
}
}
}
/**
* Pauses the render-time counter.
* So if the rendering gets paused, the statistics remain correct.
* It will resume as soon as a new ticket gets polled
*/
public void pause() {
synchronized (renderTiles) {
additionalRunTime += System.currentTimeMillis() - firstTileTime;
firstTileTime = -1;
}
}
public long getActiveTime() {
if (firstTileTime < 0) return additionalRunTime;
return (System.currentTimeMillis() - firstTileTime) + additionalRunTime;
}
public UUID getUuid() {
return uuid;
}
public String getName() {
return name;
}
public MapType getMapType() {
return mapType;
}
public int getRenderedTileCount() {
return renderedTiles;
}
public int getRemainingTileCount() {
return renderTiles.size();
}
public boolean isFinished() {
return renderTiles.isEmpty();
}
public void write(DataOutputStream out) throws IOException {
synchronized (renderTiles) {
pause();
out.writeUTF(name);
out.writeUTF(mapType.getId());
out.writeLong(additionalRunTime);
out.writeInt(renderedTiles);
out.writeInt(renderTiles.size());
for (Vector2i tile : renderTiles) {
out.writeInt(tile.getX());
out.writeInt(tile.getY());
}
}
}
public static RenderTask read(DataInputStream in) throws IOException {
String name = in.readUTF();
String mapId = in.readUTF();
MapType mapType = null;
for (MapType map : SpongePlugin.getInstance().getMapTypes()) {
if (map.getId().equals(mapId)) {
mapType = map;
break;
}
}
if (mapType == null) throw new IOException("Map type with id '" + mapId + "' does not exist!");
RenderTask task = new RenderTask(name, mapType);
task.additionalRunTime = in.readLong();
task.renderedTiles = in.readInt();
int tileCount = in.readInt();
List<Vector2i> tiles = new ArrayList<>();
for (int i = 0; i < tileCount; i++) {
int x = in.readInt();
int y = in.readInt();
Vector2i tile = new Vector2i(x, y);
tiles.add(tile);
}
task.addTiles(tiles);
return task;
}
}