mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-03 23:17:48 +01:00
Merge branch 'master' of https://github.com/Minestom/Minestom
This commit is contained in:
commit
f431674174
@ -125,6 +125,8 @@ dependencies {
|
||||
lwjglApi "org.lwjgl:lwjgl-opengl"
|
||||
lwjglApi "org.lwjgl:lwjgl-opengles"
|
||||
lwjglApi "org.lwjgl:lwjgl-glfw"
|
||||
lwjglApi "org.lwjgl:lwjgl-glfw"
|
||||
lwjglApi 'org.joml:joml:1.9.25'
|
||||
lwjglRuntimeOnly "org.lwjgl:lwjgl::$lwjglNatives"
|
||||
lwjglRuntimeOnly "org.lwjgl:lwjgl-opengl::$lwjglNatives"
|
||||
lwjglRuntimeOnly "org.lwjgl:lwjgl-opengles::$lwjglNatives"
|
||||
|
@ -24,8 +24,6 @@ import java.awt.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
|
||||
public class Demo {
|
||||
|
||||
public static void main(String[] args) {
|
||||
@ -45,11 +43,17 @@ public class Demo {
|
||||
LargeGraphics2DFramebuffer graphics2DFramebuffer = new LargeGraphics2DFramebuffer(512, 512);
|
||||
LargeGLFWFramebuffer glfwFramebuffer = new LargeGLFWFramebuffer(512, 512);
|
||||
|
||||
renderingLoop(0, directFramebuffer, Demo::directRendering);
|
||||
renderingLoop(101, graphics2DFramebuffer, Demo::graphics2DRendering);
|
||||
glfwFramebuffer.useMapColors();
|
||||
|
||||
glfwFramebuffer.changeRenderingThreadToCurrent();
|
||||
OpenGLRendering.init();
|
||||
glfwFramebuffer.unbindContextFromThread();
|
||||
|
||||
// renderingLoop(0, directFramebuffer, Demo::directRendering);
|
||||
// renderingLoop(101, graphics2DFramebuffer, Demo::graphics2DRendering);
|
||||
renderingLoop(201, glfwFramebuffer, f -> {});
|
||||
|
||||
glfwFramebuffer.setupRenderLoop(30, TimeUnit.MILLISECOND, Demo::openGLRendering);
|
||||
glfwFramebuffer.setupRenderLoop(15, TimeUnit.MILLISECOND, () -> OpenGLRendering.render(glfwFramebuffer));
|
||||
|
||||
for (int x = -2; x <= 2; x++) {
|
||||
for (int z = -2; z <= 2; z++) {
|
||||
@ -97,7 +101,7 @@ public class Demo {
|
||||
f.preparePacket(packet);
|
||||
sendPacket(packet);
|
||||
}
|
||||
}).repeat(30, TimeUnit.MILLISECOND).schedule();
|
||||
}).repeat(15, TimeUnit.MILLISECOND).schedule();
|
||||
}
|
||||
|
||||
private static void sendPacket(MapDataPacket packet) {
|
||||
@ -117,21 +121,4 @@ public class Demo {
|
||||
renderer.drawString("Here's a very very long string that needs multiple maps to fit", 0, 100);
|
||||
}
|
||||
|
||||
private static void openGLRendering() {
|
||||
glClearColor(0f, 0f, 0f, 1f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
|
||||
glVertex2f(0, -0.75f);
|
||||
glColor3f(1f, 0f, 0f);
|
||||
|
||||
glVertex2f(0.75f, 0.75f);
|
||||
glColor3f(0f, 1f, 0f);
|
||||
|
||||
glVertex2f(-0.75f, 0.75f);
|
||||
glColor3f(0f, 0f, 1f);
|
||||
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,218 @@
|
||||
package net.minestom.demo.largeframebuffers;
|
||||
|
||||
import net.minestom.server.map.MapColors;
|
||||
import net.minestom.server.map.framebuffers.LargeGLFWFramebuffer;
|
||||
import org.joml.Matrix4f;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.GLUtil;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
import static org.lwjgl.opengl.GL20.*;
|
||||
|
||||
public final class OpenGLRendering {
|
||||
|
||||
private static int vbo;
|
||||
private static int indexBuffer;
|
||||
private static final int VERTEX_SIZE = 5*4; // position + tex
|
||||
|
||||
// array of vertices (order: X,Y,Z, Tex U, Tex V)
|
||||
private static float[] vertices = {
|
||||
// front face
|
||||
-1f, -1f, -1f, 0, 0,
|
||||
1f, -1f, -1f, 1, 0,
|
||||
1f, 1f, -1f, 1, 1,
|
||||
-1f, 1f, -1f, 0, 1,
|
||||
|
||||
// back face
|
||||
-1f, -1f, 1f, 0, 1,
|
||||
1f, -1f, 1f, 1, 1,
|
||||
1f, 1f, 1f, 1, 0,
|
||||
-1f, 1f, 1f, 0, 0,
|
||||
};
|
||||
|
||||
private static int[] indices = {
|
||||
// south face
|
||||
0,1,2,
|
||||
2,3,0,
|
||||
|
||||
// north face
|
||||
4,5,6,
|
||||
6,7,4,
|
||||
|
||||
// west face
|
||||
0,4,7,
|
||||
7,3,0,
|
||||
|
||||
// east face
|
||||
1,5,6,
|
||||
6,2,1,
|
||||
|
||||
// top face
|
||||
3, 2, 6,
|
||||
6, 7, 3
|
||||
};
|
||||
private static int renderShader;
|
||||
private static Matrix4f projectionMatrix;
|
||||
private static Matrix4f viewMatrix;
|
||||
private static Matrix4f modelMatrix;
|
||||
private static int projectionUniform;
|
||||
private static int viewUniform;
|
||||
private static int modelUniform;
|
||||
private static int paletteTexture;
|
||||
private static int boxTexture;
|
||||
|
||||
static void init() {
|
||||
GLUtil.setupDebugMessageCallback();
|
||||
|
||||
paletteTexture = loadTexture("palette");
|
||||
boxTexture = loadTexture("box");
|
||||
|
||||
vbo = glGenBuffers();
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW);
|
||||
|
||||
indexBuffer = glGenBuffers();
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices, GL_STATIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, false, VERTEX_SIZE, 0); // position
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, false, VERTEX_SIZE, 3*4); // color
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
// prepare matrices and shader
|
||||
renderShader = glCreateProgram();
|
||||
projectionMatrix = new Matrix4f().setPerspective((float) (Math.PI/4f), 1f, 0.001f, 100f);
|
||||
viewMatrix = new Matrix4f().setLookAt(5f, 5f, 5f, 0, 0, 0, 0, -1, 0);
|
||||
modelMatrix = new Matrix4f().identity();
|
||||
int vertexShader = createShader("/shaders/vertex.glsl", GL_VERTEX_SHADER);
|
||||
int fragmentShader = createShader("/shaders/fragment.glsl", GL_FRAGMENT_SHADER);
|
||||
glAttachShader(renderShader, vertexShader);
|
||||
glAttachShader(renderShader, fragmentShader);
|
||||
glLinkProgram(renderShader);
|
||||
if(glGetProgrami(renderShader, GL_LINK_STATUS) == 0) {
|
||||
System.err.println("Link error: "+glGetProgramInfoLog(renderShader));
|
||||
}
|
||||
|
||||
projectionUniform = glGetUniformLocation(renderShader, "projection");
|
||||
viewUniform = glGetUniformLocation(renderShader, "view");
|
||||
modelUniform = glGetUniformLocation(renderShader, "model");
|
||||
int paletteSizeUniform = glGetUniformLocation(renderShader, "paletteSize");
|
||||
int paletteUniform = glGetUniformLocation(renderShader, "palette");
|
||||
int boxUniform = glGetUniformLocation(renderShader, "box");
|
||||
|
||||
glUseProgram(renderShader); {
|
||||
uploadMatrix(projectionUniform, projectionMatrix);
|
||||
uploadMatrix(viewUniform, viewMatrix);
|
||||
|
||||
glUniform1i(boxUniform, 0); // texture unit 0
|
||||
glUniform1i(paletteUniform, 1); // texture unit 1
|
||||
glUniform1f(paletteSizeUniform, 236);
|
||||
}
|
||||
}
|
||||
|
||||
private static int loadTexture(String filename) {
|
||||
int tex = glGenTextures();
|
||||
glBindTexture(GL_TEXTURE_2D, tex);
|
||||
BufferedImage image;
|
||||
try {
|
||||
image = ImageIO.read(OpenGLRendering.class.getResourceAsStream("/textures/"+filename+".png"));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException("Missing image "+filename, e);
|
||||
}
|
||||
ByteBuffer pixels = BufferUtils.createByteBuffer(image.getWidth()*image.getHeight()*4);
|
||||
for (int y = 0; y < image.getHeight(); y++) {
|
||||
for (int x = 0; x < image.getWidth(); x++) {
|
||||
int rgb = image.getRGB(x, y);
|
||||
int alpha = (rgb >> 24) & 0xFF;
|
||||
int red = (rgb >> 16) & 0xFF;
|
||||
int green = (rgb >> 8) & 0xFF;
|
||||
int blue = rgb & 0xFF;
|
||||
pixels.put((byte) red);
|
||||
pixels.put((byte) green);
|
||||
pixels.put((byte) blue);
|
||||
pixels.put((byte) alpha);
|
||||
}
|
||||
}
|
||||
pixels.flip();
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.getWidth(), image.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
|
||||
// closest neighbor required here, as pixels can have very different rgb values, and interpolation will break palette lookup
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
private static void uploadMatrix(int uniform, Matrix4f matrix) {
|
||||
float[] values = new float[4*4];
|
||||
matrix.get(values);
|
||||
glUniformMatrix4fv(uniform, false, values);
|
||||
}
|
||||
|
||||
private static int createShader(String filename, int type) {
|
||||
int shader = glCreateShader(type);
|
||||
try(BufferedReader reader = new BufferedReader(new InputStreamReader(OpenGLRendering.class.getResourceAsStream(filename)))) {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
String source = reader.lines().collect(Collectors.joining("\n"));
|
||||
glShaderSource(shader, source);
|
||||
glCompileShader(shader);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
|
||||
private static long lastTime = System.currentTimeMillis();
|
||||
|
||||
private static int frame = 0;
|
||||
|
||||
static void render(LargeGLFWFramebuffer framebuffer) {
|
||||
if(frame % 100 == 0) {
|
||||
long time = System.currentTimeMillis();
|
||||
long dt = time-lastTime;
|
||||
System.out.println(">> Render time for 100 frames: "+dt);
|
||||
System.out.println(">> Average time per frame: "+(dt/100.0));
|
||||
System.out.println(">> Average FPS: "+(1000.0/(dt/100.0)));
|
||||
lastTime = time;
|
||||
}
|
||||
frame++;
|
||||
|
||||
|
||||
glClearColor(MapColors.COLOR_BLACK.multiply53()/255.0f, 0f, 0f, 1f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
modelMatrix.rotateY((float) (Math.PI/60f));
|
||||
|
||||
// TODO: render texture
|
||||
glUseProgram(renderShader); {
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_2D, paletteTexture);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, boxTexture);
|
||||
|
||||
uploadMatrix(modelUniform, modelMatrix);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
|
||||
glDrawElements(GL_TRIANGLES, indices.length, GL_UNSIGNED_INT, 0);
|
||||
}
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package net.minestom.demo.largeframebuffers;
|
||||
|
||||
import net.minestom.server.map.MapColors;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class PaletteGenerator {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Map<Integer, Integer> colors = new HashMap<>();
|
||||
int highestIndex = 0;
|
||||
for(MapColors c : MapColors.values()) {
|
||||
if (c == MapColors.NONE)
|
||||
continue;
|
||||
for(MapColors.Multiplier m : MapColors.Multiplier.values()) {
|
||||
int index = ((int)m.apply(c)) & 0xFF;
|
||||
if(index > highestIndex) {
|
||||
highestIndex = index;
|
||||
}
|
||||
int rgb = MapColors.PreciseMapColor.toRGB(c, m);
|
||||
colors.put(index, rgb);
|
||||
}
|
||||
}
|
||||
|
||||
BufferedImage paletteTexture = new BufferedImage(highestIndex+1, 1, BufferedImage.TYPE_INT_ARGB);
|
||||
for (int i = 0; i <= highestIndex; i++) {
|
||||
int rgb = colors.getOrDefault(i, 0);
|
||||
int argb = (0xFF << 24) | (rgb & 0xFFFFFF);
|
||||
paletteTexture.setRGB(i, 0, argb);
|
||||
}
|
||||
|
||||
try {
|
||||
ImageIO.write(paletteTexture, "png", new File("src/lwjgl/resources/textures/palette.png"));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
@ -24,6 +24,8 @@ abstract class GLFWCapableBuffer {
|
||||
private final long glfwWindow;
|
||||
private final int width;
|
||||
private final int height;
|
||||
private final ByteBuffer colorsBuffer;
|
||||
private boolean onlyMapColors;
|
||||
|
||||
protected GLFWCapableBuffer(int width, int height) {
|
||||
this(width, height, GLFW_NATIVE_CONTEXT_API, GLFW_OPENGL_API);
|
||||
@ -36,6 +38,7 @@ abstract class GLFWCapableBuffer {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.colors = new byte[width*height];
|
||||
colorsBuffer = BufferUtils.createByteBuffer(width*height);
|
||||
this.pixels = BufferUtils.createByteBuffer(width*height*4);
|
||||
if(!glfwInit()) {
|
||||
throw new RuntimeException("Failed to init GLFW");
|
||||
@ -99,16 +102,22 @@ abstract class GLFWCapableBuffer {
|
||||
* Only call if you do not use {@link #render(Runnable)} nor {@link #setupRenderLoop(long, TimeUnit, Runnable)}
|
||||
*/
|
||||
public void prepareMapColors() {
|
||||
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int i = Framebuffer.index(x, y, width)*4;
|
||||
int red = pixels.get(i) & 0xFF;
|
||||
int green = pixels.get(i+1) & 0xFF;
|
||||
int blue = pixels.get(i+2) & 0xFF;
|
||||
int alpha = pixels.get(i+3) & 0xFF;
|
||||
int argb = (alpha << 24) | (red << 16) | (green << 8) | blue;
|
||||
colors[Framebuffer.index(x, y, width)] = MapColors.closestColor(argb).getIndex();
|
||||
if(onlyMapColors) {
|
||||
colorsBuffer.rewind();
|
||||
glReadPixels(0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE, colorsBuffer);
|
||||
colorsBuffer.get(colors);
|
||||
} else {
|
||||
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int i = Framebuffer.index(x, y, width)*4;
|
||||
int red = pixels.get(i) & 0xFF;
|
||||
int green = pixels.get(i+1) & 0xFF;
|
||||
int blue = pixels.get(i+2) & 0xFF;
|
||||
int alpha = pixels.get(i+3) & 0xFF;
|
||||
int argb = (alpha << 24) | (red << 16) | (green << 8) | blue;
|
||||
colors[Framebuffer.index(x, y, width)] = MapColors.closestColor(argb).getIndex();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -128,4 +137,20 @@ abstract class GLFWCapableBuffer {
|
||||
public int height() {
|
||||
return height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells this buffer that the **RED** channel contains the index of the map color to use.
|
||||
*
|
||||
* This allows for optimizations and fast rendering (because there is no need for a conversion)
|
||||
*/
|
||||
public void useMapColors() {
|
||||
onlyMapColors = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opposite to {@link #useMapColors()}
|
||||
*/
|
||||
public void useRGB() {
|
||||
onlyMapColors = false;
|
||||
}
|
||||
}
|
||||
|
33
src/lwjgl/resources/shaders/fragment.glsl
Normal file
33
src/lwjgl/resources/shaders/fragment.glsl
Normal file
@ -0,0 +1,33 @@
|
||||
#version 330
|
||||
|
||||
in vec2 uv;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform sampler2D box;
|
||||
uniform sampler2D palette;
|
||||
uniform float paletteSize;
|
||||
|
||||
void main() {
|
||||
vec3 vertexColor = texture(box, uv).rgb;
|
||||
|
||||
|
||||
// render in map colors
|
||||
int closest = 0;
|
||||
uint closestDistance = uint(2147483647);
|
||||
for(int i = 4; i < paletteSize; i++) {
|
||||
vec3 mapColor = texture(palette, vec2((i+0.5f)/paletteSize, 0.0)).rgb;
|
||||
int dr = int((mapColor.r - vertexColor.r)*255);
|
||||
int dg = int((mapColor.g - vertexColor.g)*255);
|
||||
int db = int((mapColor.b - vertexColor.b)*255);
|
||||
|
||||
uint d = uint(dr*dr)+uint(dg*dg)+uint(db*db);
|
||||
if(d < closestDistance) {
|
||||
closestDistance = d;
|
||||
closest = i;
|
||||
}
|
||||
}
|
||||
|
||||
fragColor = vec4(closest/255.0, closest/255.0, closest/255.0, 1.0);
|
||||
//fragColor = vec4(vertexColor, 1.0);
|
||||
}
|
16
src/lwjgl/resources/shaders/vertex.glsl
Normal file
16
src/lwjgl/resources/shaders/vertex.glsl
Normal file
@ -0,0 +1,16 @@
|
||||
#version 330
|
||||
|
||||
layout(location = 0) in vec3 pos;
|
||||
layout(location = 1) in vec2 texCoords;
|
||||
|
||||
out vec2 uv;
|
||||
|
||||
uniform mat4 projection;
|
||||
uniform mat4 view;
|
||||
uniform mat4 model;
|
||||
|
||||
void main() {
|
||||
mat4 mvp = projection * view * model;
|
||||
uv = texCoords;
|
||||
gl_Position = mvp * vec4(pos, 1.0);
|
||||
}
|
BIN
src/lwjgl/resources/textures/box.png
Normal file
BIN
src/lwjgl/resources/textures/box.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 274 B |
BIN
src/lwjgl/resources/textures/palette.png
Normal file
BIN
src/lwjgl/resources/textures/palette.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 876 B |
@ -65,9 +65,6 @@ public class MinecraftServer {
|
||||
|
||||
public static final String THREAD_NAME_TICK = "Ms-Tick";
|
||||
|
||||
public static final String THREAD_NAME_PATHFINDER = "Ms-PathFinding";
|
||||
public static final int THREAD_COUNT_PATHFINDER = 2;
|
||||
|
||||
public static final String THREAD_NAME_PACKET_WRITER = "Ms-PacketWriterPool";
|
||||
public static final int THREAD_COUNT_PACKET_WRITER = 2;
|
||||
|
||||
@ -136,7 +133,7 @@ public class MinecraftServer {
|
||||
private static MinecraftSessionService sessionService = authService.createMinecraftSessionService();
|
||||
|
||||
public static MinecraftServer init() {
|
||||
if(minecraftServer != null) // don't init twice
|
||||
if (minecraftServer != null) // don't init twice
|
||||
return minecraftServer;
|
||||
// warmup/force-init registries
|
||||
// without this line, registry types that are not loaded explicitly will have an internal empty registry in Registries
|
||||
|
@ -27,7 +27,6 @@ public class BenchmarkManager {
|
||||
threadMXBean.setThreadCpuTimeEnabled(true);
|
||||
|
||||
threads.add(THREAD_NAME_MAIN_UPDATE);
|
||||
threads.add(THREAD_NAME_PATHFINDER);
|
||||
threads.add(THREAD_NAME_PACKET_WRITER);
|
||||
threads.add(THREAD_NAME_BLOCK_BATCH);
|
||||
threads.add(THREAD_NAME_SCHEDULER);
|
||||
|
@ -7,7 +7,6 @@ import net.minestom.server.attribute.Attribute;
|
||||
import net.minestom.server.entity.ai.GoalSelector;
|
||||
import net.minestom.server.entity.ai.TargetSelector;
|
||||
import net.minestom.server.entity.pathfinding.PFPathingEntity;
|
||||
import net.minestom.server.entity.pathfinding.PathfinderManager;
|
||||
import net.minestom.server.event.entity.EntityAttackEvent;
|
||||
import net.minestom.server.event.item.ArmorEquipEvent;
|
||||
import net.minestom.server.instance.Chunk;
|
||||
@ -32,8 +31,6 @@ import java.util.function.Supplier;
|
||||
|
||||
public abstract class EntityCreature extends LivingEntity {
|
||||
|
||||
private static final PathfinderManager PATHFINDER_MANAGER = new PathfinderManager();
|
||||
|
||||
private PFPathingEntity pathingEntity = new PFPathingEntity(this);
|
||||
private HydrazinePathFinder pathFinder;
|
||||
private PathObject path;
|
||||
@ -123,24 +120,22 @@ public abstract class EntityCreature extends LivingEntity {
|
||||
|
||||
// Path finding
|
||||
{
|
||||
if (pathPosition != null && !pathLock.isLocked()) {
|
||||
PATHFINDER_MANAGER.getPool().execute(() -> {
|
||||
this.pathLock.lock();
|
||||
this.path = pathFinder.updatePathFor(pathingEntity);
|
||||
if (pathPosition != null) {
|
||||
this.pathLock.lock();
|
||||
this.path = pathFinder.updatePathFor(pathingEntity);
|
||||
|
||||
if (path != null) {
|
||||
final float speed = getAttributeValue(Attribute.MOVEMENT_SPEED);
|
||||
final Position targetPosition = pathingEntity.getTargetPosition();
|
||||
moveTowards(targetPosition, speed);
|
||||
} else {
|
||||
if (pathPosition != null) {
|
||||
this.pathPosition = null;
|
||||
this.pathFinder.reset();
|
||||
}
|
||||
if (path != null) {
|
||||
final float speed = getAttributeValue(Attribute.MOVEMENT_SPEED);
|
||||
final Position targetPosition = pathingEntity.getTargetPosition();
|
||||
moveTowards(targetPosition, speed);
|
||||
} else {
|
||||
if (pathPosition != null) {
|
||||
this.pathPosition = null;
|
||||
this.pathFinder.reset();
|
||||
}
|
||||
}
|
||||
|
||||
this.pathLock.unlock();
|
||||
});
|
||||
this.pathLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,7 +165,7 @@ public abstract class EntityCreature extends LivingEntity {
|
||||
public boolean addViewer(Player player) {
|
||||
final boolean result = super.addViewer(player);
|
||||
|
||||
PlayerConnection playerConnection = player.getPlayerConnection();
|
||||
final PlayerConnection playerConnection = player.getPlayerConnection();
|
||||
|
||||
EntityPacket entityPacket = new EntityPacket();
|
||||
entityPacket.entityId = getEntityId();
|
||||
|
@ -13,6 +13,15 @@ public class PFPathingEntity implements IPathingEntity {
|
||||
private float searchRange;
|
||||
private Position targetPosition;
|
||||
|
||||
// Capacities
|
||||
private boolean fireResistant;
|
||||
private boolean cautious;
|
||||
private boolean climber;
|
||||
private boolean swimmer;
|
||||
private boolean aquaphobic;
|
||||
private boolean avoidsDoorways;
|
||||
private boolean opensDoors;
|
||||
|
||||
public PFPathingEntity(EntityCreature entity) {
|
||||
this.entity = entity;
|
||||
this.searchRange = entity.getAttributeValue(Attribute.FOLLOW_RANGE);
|
||||
@ -41,6 +50,62 @@ public class PFPathingEntity implements IPathingEntity {
|
||||
this.searchRange = searchRange;
|
||||
}
|
||||
|
||||
public boolean isFireResistant() {
|
||||
return fireResistant;
|
||||
}
|
||||
|
||||
public void setFireResistant(boolean fireResistant) {
|
||||
this.fireResistant = fireResistant;
|
||||
}
|
||||
|
||||
public boolean isCautious() {
|
||||
return cautious;
|
||||
}
|
||||
|
||||
public void setCautious(boolean cautious) {
|
||||
this.cautious = cautious;
|
||||
}
|
||||
|
||||
public boolean isClimber() {
|
||||
return climber;
|
||||
}
|
||||
|
||||
public void setClimber(boolean climber) {
|
||||
this.climber = climber;
|
||||
}
|
||||
|
||||
public boolean isSwimmer() {
|
||||
return swimmer;
|
||||
}
|
||||
|
||||
public void setSwimmer(boolean swimmer) {
|
||||
this.swimmer = swimmer;
|
||||
}
|
||||
|
||||
public boolean isAquaphobic() {
|
||||
return aquaphobic;
|
||||
}
|
||||
|
||||
public void setAquaphobic(boolean aquaphobic) {
|
||||
this.aquaphobic = aquaphobic;
|
||||
}
|
||||
|
||||
public boolean isAvoidsDoorways() {
|
||||
return avoidsDoorways;
|
||||
}
|
||||
|
||||
public void setAvoidsDoorways(boolean avoidsDoorways) {
|
||||
this.avoidsDoorways = avoidsDoorways;
|
||||
}
|
||||
|
||||
public boolean isOpensDoors() {
|
||||
return opensDoors;
|
||||
}
|
||||
|
||||
public void setOpensDoors(boolean opensDoors) {
|
||||
this.opensDoors = opensDoors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Capabilities capabilities() {
|
||||
return new Capabilities() {
|
||||
@ -51,37 +116,37 @@ public class PFPathingEntity implements IPathingEntity {
|
||||
|
||||
@Override
|
||||
public boolean fireResistant() {
|
||||
return false;
|
||||
return fireResistant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cautious() {
|
||||
return false;
|
||||
return cautious;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean climber() {
|
||||
return true;
|
||||
return climber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean swimmer() {
|
||||
return true;
|
||||
return swimmer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean aquaphobic() {
|
||||
return false;
|
||||
return aquaphobic;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean avoidsDoorways() {
|
||||
return false;
|
||||
return avoidsDoorways;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean opensDoors() {
|
||||
return false;
|
||||
return opensDoors;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1,16 +0,0 @@
|
||||
package net.minestom.server.entity.pathfinding;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.utils.thread.MinestomThread;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
public final class PathfinderManager {
|
||||
|
||||
private ExecutorService pathfinderPool = new MinestomThread(MinecraftServer.THREAD_COUNT_PATHFINDER, MinecraftServer.THREAD_NAME_PATHFINDER);
|
||||
|
||||
public ExecutorService getPool() {
|
||||
return pathfinderPool;
|
||||
}
|
||||
|
||||
}
|
@ -86,19 +86,19 @@ public final class Chunk implements Viewable {
|
||||
}
|
||||
|
||||
public void UNSAFE_setCustomBlock(int x, int y, int z, short blockStateId, short customBlockId, Data data) {
|
||||
CustomBlock customBlock = BLOCK_MANAGER.getCustomBlock(customBlockId);
|
||||
final CustomBlock customBlock = BLOCK_MANAGER.getCustomBlock(customBlockId);
|
||||
Check.notNull(customBlock, "The custom block " + customBlockId + " does not exist or isn't registered");
|
||||
|
||||
UNSAFE_setCustomBlock(x, y, z, blockStateId, customBlock, data);
|
||||
}
|
||||
|
||||
protected void UNSAFE_setCustomBlock(int x, int y, int z, short blockStateId, CustomBlock customBlock, Data data) {
|
||||
UpdateConsumer updateConsumer = customBlock.hasUpdate() ? customBlock::update : null;
|
||||
final UpdateConsumer updateConsumer = customBlock.hasUpdate() ? customBlock::update : null;
|
||||
setBlock(x, y, z, blockStateId, customBlock.getCustomBlockId(), data, updateConsumer);
|
||||
}
|
||||
|
||||
public void UNSAFE_removeCustomBlock(int x, int y, int z) {
|
||||
int index = getBlockIndex(x, y, z);
|
||||
final int index = getBlockIndex(x, y, z);
|
||||
this.customBlocksId[index] = 0; // Set to none
|
||||
this.blocksData.remove(index);
|
||||
|
||||
@ -405,7 +405,6 @@ public final class Chunk implements Viewable {
|
||||
|
||||
/**
|
||||
* Used to verify if the chunk should still be kept in memory
|
||||
* having the chunk unloaded means no data is contained in it (blocks, data, etc...)
|
||||
*
|
||||
* @return true if the chunk is loaded
|
||||
*/
|
||||
|
@ -208,7 +208,7 @@ public interface EquipmentHandler {
|
||||
entityEquipmentPacket.slots = new EntityEquipmentPacket.Slot[]{slot};
|
||||
entityEquipmentPacket.itemStacks = new ItemStack[]{itemStack};
|
||||
|
||||
viewable.sendPacketToViewersAndSelf(entityEquipmentPacket);
|
||||
viewable.sendPacketToViewers(entityEquipmentPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,5 @@
|
||||
package net.minestom.server.item;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import net.minestom.server.chat.ColoredText;
|
||||
import net.minestom.server.data.Data;
|
||||
import net.minestom.server.data.DataContainer;
|
||||
@ -65,6 +64,11 @@ public class ItemStack implements DataContainer {
|
||||
this(material, amount, (short) 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new air item
|
||||
*
|
||||
* @return an air item
|
||||
*/
|
||||
public static ItemStack getAirItem() {
|
||||
return new ItemStack(Material.AIR, (byte) 0);
|
||||
}
|
||||
@ -145,10 +149,24 @@ public class ItemStack implements DataContainer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the item damage (durability)
|
||||
*
|
||||
* @return the item damagel
|
||||
*/
|
||||
public int getDamage() {
|
||||
return damage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the item damage (durability)
|
||||
*
|
||||
* @param damage the item damage
|
||||
*/
|
||||
public void setDamage(int damage) {
|
||||
this.damage = damage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the item amount
|
||||
* <p>
|
||||
@ -173,10 +191,6 @@ public class ItemStack implements DataContainer {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public void setDamage(int damage) {
|
||||
this.damage = damage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the special meta object for this item
|
||||
* <p>
|
||||
@ -406,7 +420,7 @@ public class ItemStack implements DataContainer {
|
||||
* @return true if the item has the flag {@code flag}, false otherwise
|
||||
*/
|
||||
public boolean hasItemFlag(ItemFlag flag) {
|
||||
int bitModifier = getBitModifier(flag);
|
||||
final int bitModifier = getBitModifier(flag);
|
||||
return (this.hideFlag & bitModifier) == bitModifier;
|
||||
}
|
||||
|
||||
@ -520,7 +534,7 @@ public class ItemStack implements DataContainer {
|
||||
* @throws NullPointerException if {@code stackingRule} is null
|
||||
*/
|
||||
public void setStackingRule(StackingRule stackingRule) {
|
||||
Check.notNull(stackingRule, "StackingRule cannot be null!");
|
||||
Check.notNull(stackingRule, "The stacking rule cannot be null!");
|
||||
this.stackingRule = stackingRule;
|
||||
}
|
||||
|
||||
@ -543,29 +557,6 @@ public class ItemStack implements DataContainer {
|
||||
return (byte) (1 << hideFlag.ordinal());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the item into a readable Json object
|
||||
* <p>
|
||||
* Mainly used to show an item in a message hover
|
||||
*
|
||||
* @return a {@link JsonObject} containing the item data
|
||||
*/
|
||||
public synchronized JsonObject toJsonObject() {
|
||||
JsonObject object = new JsonObject();
|
||||
object.addProperty("id", material.getId());
|
||||
object.addProperty("Damage", getDamage());
|
||||
object.addProperty("Count", getAmount());
|
||||
|
||||
if (hasDisplayName() || hasLore()) {
|
||||
JsonObject tagObject = new JsonObject();
|
||||
if (hasDisplayName()) {
|
||||
tagObject.addProperty("display", getDisplayName().toString());
|
||||
}
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the item meta based on the material type
|
||||
*
|
||||
|
@ -41,7 +41,7 @@ public class PlayerDiggingListener {
|
||||
if (instantBreak) {
|
||||
breakBlock(instance, player, blockPosition);
|
||||
} else {
|
||||
CustomBlock customBlock = instance.getCustomBlock(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ());
|
||||
final CustomBlock customBlock = instance.getCustomBlock(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ());
|
||||
if (customBlock != null) {
|
||||
int breakTime = customBlock.getBreakDelay(player, blockPosition);
|
||||
|
||||
@ -78,13 +78,13 @@ public class PlayerDiggingListener {
|
||||
breakBlock(instance, player, blockPosition);
|
||||
break;
|
||||
case DROP_ITEM_STACK:
|
||||
ItemStack droppedItemStack = player.getInventory().getItemInMainHand().clone();
|
||||
final ItemStack droppedItemStack = player.getInventory().getItemInMainHand().clone();
|
||||
dropItem(player, droppedItemStack, ItemStack.getAirItem());
|
||||
break;
|
||||
case DROP_ITEM:
|
||||
ItemStack handItem = player.getInventory().getItemInMainHand().clone();
|
||||
ItemStack droppedItemStack2 = handItem.clone();
|
||||
StackingRule handStackingRule = handItem.getStackingRule();
|
||||
final StackingRule handStackingRule = handItem.getStackingRule();
|
||||
|
||||
droppedItemStack2 = handStackingRule.apply(droppedItemStack2, 1);
|
||||
|
||||
@ -129,7 +129,7 @@ public class PlayerDiggingListener {
|
||||
}
|
||||
|
||||
private static void dropItem(Player player, ItemStack droppedItem, ItemStack handItem) {
|
||||
PlayerInventory playerInventory = player.getInventory();
|
||||
final PlayerInventory playerInventory = player.getInventory();
|
||||
if (player.dropItem(droppedItem)) {
|
||||
playerInventory.setItemInMainHand(handItem);
|
||||
} else {
|
||||
|
@ -307,7 +307,7 @@ public enum MapColors {
|
||||
}
|
||||
}
|
||||
|
||||
enum Multiplier {
|
||||
public enum Multiplier {
|
||||
x1_00(MapColors::baseColor, 1.00),
|
||||
x0_53(MapColors::multiply53, 0.53),
|
||||
x0_71(MapColors::multiply71, 0.71),
|
||||
|
Loading…
Reference in New Issue
Block a user