mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-15 02:15:34 -04:00
handle block changes
This commit is contained in:
parent
6be2ca79f3
commit
2605a35f68
@ -17,7 +17,17 @@ import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
data class BlockPosition(val x: Int, val y: Int, val z: Int) {
|
||||
|
||||
fun getChunkLocation(): ChunkLocation {
|
||||
return ChunkLocation(this.x / ProtocolDefinition.SECTION_WIDTH_X, this.z / ProtocolDefinition.SECTION_WIDTH_Z)
|
||||
val chunkX = if (this.x >= 0) {
|
||||
this.x / ProtocolDefinition.SECTION_WIDTH_X
|
||||
} else {
|
||||
((this.x + 1) / ProtocolDefinition.SECTION_WIDTH_X) - 1
|
||||
}
|
||||
val chunkY = if (this.z >= 0) {
|
||||
this.z / ProtocolDefinition.SECTION_WIDTH_Z
|
||||
} else {
|
||||
((this.z + 1) / ProtocolDefinition.SECTION_WIDTH_Z) - 1
|
||||
}
|
||||
return ChunkLocation(chunkX, chunkY)
|
||||
}
|
||||
|
||||
fun getInChunkLocation(): InChunkLocation {
|
||||
@ -32,6 +42,10 @@ data class BlockPosition(val x: Int, val y: Int, val z: Int) {
|
||||
return InChunkLocation(x, this.y, z)
|
||||
}
|
||||
|
||||
fun getSectionHeight(): Int {
|
||||
return y / ProtocolDefinition.SECTION_HEIGHT_Y
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "($x $y $z)"
|
||||
}
|
||||
|
@ -87,4 +87,13 @@ public class Chunk {
|
||||
public HashMap<Integer, ChunkSection> getSections() {
|
||||
return this.sections;
|
||||
}
|
||||
|
||||
public ChunkSection getSectionOrCreate(int sectionHeight) {
|
||||
ChunkSection section = this.sections.get(sectionHeight);
|
||||
if (section == null) {
|
||||
section = new ChunkSection();
|
||||
this.sections.put(sectionHeight, section);
|
||||
}
|
||||
return section;
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,10 @@ data class InChunkLocation(val x: Int, val y: Int, val z: Int) {
|
||||
return InChunkSectionLocation(x, y % ProtocolDefinition.SECTION_HEIGHT_Y, z)
|
||||
}
|
||||
|
||||
fun getSectionHeight(): Int {
|
||||
return y / ProtocolDefinition.SECTION_HEIGHT_Y
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "($x $y $z)"
|
||||
}
|
||||
|
@ -106,6 +106,7 @@ object ChunkPreparer {
|
||||
"minecraft:bedrock" -> 0
|
||||
"minecraft:dirt" -> 1
|
||||
"minecraft:stone" -> 2
|
||||
"minecraft:glass" -> 3
|
||||
else -> 2
|
||||
}
|
||||
}
|
||||
|
@ -8,9 +8,9 @@ import org.lwjgl.opengl.GL20;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.GL_TRIANGLES;
|
||||
import static org.lwjgl.opengl.GL11.glDrawArrays;
|
||||
import static org.lwjgl.opengl.GL15.glDeleteBuffers;
|
||||
import static org.lwjgl.opengl.GL15.glGenBuffers;
|
||||
import static org.lwjgl.opengl.GL30.glBindVertexArray;
|
||||
import static org.lwjgl.opengl.GL30.glGenVertexArrays;
|
||||
import static org.lwjgl.opengl.GL30.*;
|
||||
|
||||
public class Mesh {
|
||||
int vAO;
|
||||
@ -44,4 +44,9 @@ public class Mesh {
|
||||
glBindVertexArray(this.vAO);
|
||||
glDrawArrays(GL_TRIANGLES, 0, this.trianglesCount);
|
||||
}
|
||||
|
||||
public void unload() {
|
||||
glDeleteVertexArrays(this.vAO);
|
||||
glDeleteBuffers(this.vBO);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package de.bixilon.minosoft.gui.rendering
|
||||
|
||||
import de.bixilon.minosoft.data.world.ChunkLocation
|
||||
import de.bixilon.minosoft.protocol.network.Connection
|
||||
import org.lwjgl.*
|
||||
import org.lwjgl.glfw.Callbacks
|
||||
@ -10,6 +11,7 @@ import org.lwjgl.opengl.*
|
||||
import org.lwjgl.opengl.GL11.glClear
|
||||
import org.lwjgl.system.MemoryStack
|
||||
import org.lwjgl.system.MemoryUtil
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
|
||||
class RenderWindow(private val connection: Connection) {
|
||||
@ -24,9 +26,10 @@ class RenderWindow(private val connection: Connection) {
|
||||
private var lastFrame = 0.0
|
||||
lateinit var camera: Camera
|
||||
|
||||
val meshesToDraw = ConcurrentLinkedQueue<Mesh>()
|
||||
val renderQueue = ConcurrentLinkedQueue<Runnable>()
|
||||
|
||||
val chunkSectionsToDraw = ConcurrentHashMap<ChunkLocation, ConcurrentHashMap<Int, Mesh>>()
|
||||
|
||||
|
||||
fun init() {
|
||||
// Setup an error callback. The default implementation
|
||||
@ -108,11 +111,7 @@ class RenderWindow(private val connection: Connection) {
|
||||
}
|
||||
|
||||
fun startLoop() {
|
||||
// val world = World()
|
||||
// world.setChunk(ChunkLocation(0, 0), DummyData.getDummyChunk())
|
||||
// world.setChunk(ChunkLocation(1, 0), DummyData.getDummyChunk())
|
||||
|
||||
texture0 = TextureArray(arrayOf("/textures/bedrock.png", "/textures/dirt.png", "/textures/stone.png"))
|
||||
texture0 = TextureArray(arrayOf("/textures/bedrock.png", "/textures/dirt.png", "/textures/stone.png", "/textures/glass.png"))
|
||||
texture0.load()
|
||||
|
||||
shader = Shader("vertex.glsl", "fragment.glsl")
|
||||
@ -124,13 +123,6 @@ class RenderWindow(private val connection: Connection) {
|
||||
camera.calculateViewMatrix(shader)
|
||||
|
||||
|
||||
// for ((chunkLocation, chunk) in world.allChunks) {
|
||||
// for ((sectionHeight, section) in chunk.sections) {
|
||||
// meshesToDraw.add(Mesh(ChunkPreparer.prepareChunk(world, chunkLocation, sectionHeight, section), chunkLocation, sectionHeight))
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
var framesLastSecond = 0
|
||||
var lastCalcTime = glfwGetTime()
|
||||
while (!glfwWindowShouldClose(windowId)) {
|
||||
@ -147,8 +139,10 @@ class RenderWindow(private val connection: Connection) {
|
||||
|
||||
camera.calculateViewMatrix(shader)
|
||||
|
||||
for (mesh in meshesToDraw) {
|
||||
mesh.draw(shader)
|
||||
for ((_, map) in chunkSectionsToDraw) {
|
||||
for ((_, mesh) in map) {
|
||||
mesh.draw(shader)
|
||||
}
|
||||
}
|
||||
|
||||
glfwSwapBuffers(windowId) // swap the color buffers
|
||||
@ -157,17 +151,20 @@ class RenderWindow(private val connection: Connection) {
|
||||
// invoked during this call.
|
||||
glfwPollEvents()
|
||||
handleInput()
|
||||
camera.handleInput(deltaTime)
|
||||
if (glfwGetTime() - lastCalcTime >= 1.0) {
|
||||
glfwSetWindowTitle(windowId, "FPS: $framesLastSecond")
|
||||
lastCalcTime = glfwGetTime()
|
||||
framesLastSecond = 0
|
||||
}
|
||||
framesLastSecond++
|
||||
|
||||
for (renderQueueElement in renderQueue) {
|
||||
renderQueueElement.run()
|
||||
renderQueue.remove(renderQueueElement)
|
||||
}
|
||||
|
||||
camera.handleInput(deltaTime)
|
||||
|
||||
if (glfwGetTime() - lastCalcTime >= 0.5) {
|
||||
glfwSetWindowTitle(windowId, "FPS: ${framesLastSecond * 2}")
|
||||
lastCalcTime = glfwGetTime()
|
||||
framesLastSecond = 0
|
||||
}
|
||||
framesLastSecond++
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,8 +7,10 @@ import de.bixilon.minosoft.data.world.ChunkSection
|
||||
import de.bixilon.minosoft.gui.rendering.ChunkPreparer.prepareChunk
|
||||
import de.bixilon.minosoft.protocol.network.Connection
|
||||
import de.bixilon.minosoft.util.Util
|
||||
import de.bixilon.minosoft.util.logging.Log
|
||||
import glm_.vec3.Vec3
|
||||
import org.lwjgl.Version
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
@ -18,7 +20,7 @@ class Renderer(private val connection: Connection) {
|
||||
|
||||
fun start() {
|
||||
Thread({
|
||||
println("Hello LWJGL " + Version.getVersion() + "!")
|
||||
Log.info("Hello LWJGL " + Version.getVersion() + "!")
|
||||
renderWindow.init()
|
||||
renderWindow.startLoop()
|
||||
renderWindow.exit()
|
||||
@ -26,6 +28,7 @@ class Renderer(private val connection: Connection) {
|
||||
}
|
||||
|
||||
fun prepareChunk(chunkLocation: ChunkLocation, chunk: Chunk) {
|
||||
renderWindow.chunkSectionsToDraw[chunkLocation] = ConcurrentHashMap()
|
||||
for ((sectionHeight, section) in chunk.sections) {
|
||||
prepareChunkSection(chunkLocation, sectionHeight, section)
|
||||
}
|
||||
@ -34,8 +37,23 @@ class Renderer(private val connection: Connection) {
|
||||
fun prepareChunkSection(chunkLocation: ChunkLocation, sectionHeight: Int, section: ChunkSection) {
|
||||
executor.execute {
|
||||
val data = prepareChunk(connection.player.world, chunkLocation, sectionHeight, section)
|
||||
val sectionMap = renderWindow.chunkSectionsToDraw[chunkLocation]!!
|
||||
renderWindow.renderQueue.add {
|
||||
renderWindow.meshesToDraw.add(Mesh(data, chunkLocation, sectionHeight))
|
||||
sectionMap[sectionHeight]?.unload()
|
||||
sectionMap.remove(sectionHeight)
|
||||
sectionMap[sectionHeight] = Mesh(data, chunkLocation, sectionHeight)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun clearCache() {
|
||||
renderWindow.renderQueue.add {
|
||||
for ((location, map) in renderWindow.chunkSectionsToDraw) {
|
||||
for ((sectionHeight, mesh) in map) {
|
||||
mesh.unload()
|
||||
map.remove(sectionHeight)
|
||||
}
|
||||
renderWindow.chunkSectionsToDraw.remove(location)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -43,7 +61,6 @@ class Renderer(private val connection: Connection) {
|
||||
fun teleport(position: Location) {
|
||||
renderWindow.renderQueue.add {
|
||||
renderWindow.camera.setPosition(Vec3(position.x, position.y, position.z))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
package de.bixilon.minosoft.protocol.network;
|
||||
|
||||
import de.bixilon.minosoft.Minosoft;
|
||||
import de.bixilon.minosoft.config.StaticConfiguration;
|
||||
import de.bixilon.minosoft.data.Player;
|
||||
import de.bixilon.minosoft.data.VelocityHandler;
|
||||
import de.bixilon.minosoft.data.commands.CommandRootNode;
|
||||
@ -57,6 +58,7 @@ public class Connection {
|
||||
private final Player player;
|
||||
private final String hostname;
|
||||
private final Recipes recipes = new Recipes();
|
||||
private final Renderer renderer = new Renderer(this);
|
||||
private LinkedList<ServerAddress> addresses;
|
||||
private int desiredVersionNumber = -1;
|
||||
private ServerAddress address;
|
||||
@ -71,7 +73,6 @@ public class Connection {
|
||||
private CommandRootNode commandRootNode;
|
||||
private ConnectionPing connectionStatusPing;
|
||||
private ServerListPongEvent pong;
|
||||
private final Renderer renderer = new Renderer(this);
|
||||
|
||||
public Connection(int connectionId, String hostname, Player player) {
|
||||
this.connectionId = connectionId;
|
||||
@ -369,7 +370,9 @@ public class Connection {
|
||||
case FAILED_NO_RETRY -> handlePingCallbacks(null);
|
||||
case PLAY -> {
|
||||
Minosoft.CONNECTIONS.put(getConnectionId(), this);
|
||||
this.renderer.start();
|
||||
if (!StaticConfiguration.HEADLESS_MODE) {
|
||||
this.renderer.start();
|
||||
}
|
||||
|
||||
if (CLI.getCurrentConnection() == null) {
|
||||
CLI.setCurrentConnection(this);
|
||||
|
@ -17,6 +17,7 @@ import de.bixilon.minosoft.data.mappings.blocks.Block;
|
||||
import de.bixilon.minosoft.data.mappings.tweaker.VersionTweaker;
|
||||
import de.bixilon.minosoft.data.world.BlockPosition;
|
||||
import de.bixilon.minosoft.data.world.Chunk;
|
||||
import de.bixilon.minosoft.data.world.ChunkSection;
|
||||
import de.bixilon.minosoft.modding.event.events.BlockChangeEvent;
|
||||
import de.bixilon.minosoft.protocol.network.Connection;
|
||||
import de.bixilon.minosoft.protocol.packets.ClientboundPacket;
|
||||
@ -51,14 +52,18 @@ public class PacketBlockChange extends ClientboundPacket {
|
||||
}
|
||||
connection.fireEvent(new BlockChangeEvent(connection, this));
|
||||
|
||||
int sectionHeight = getPosition().getSectionHeight();
|
||||
ChunkSection section = chunk.getSectionOrCreate(sectionHeight);
|
||||
|
||||
// tweak
|
||||
if (!connection.getVersion().isFlattened()) {
|
||||
Block block = VersionTweaker.transformBlock(getBlock(), chunk, getPosition().getInChunkLocation());
|
||||
chunk.setBlock(getPosition().getInChunkLocation(), block);
|
||||
section.setBlock(getPosition().getInChunkLocation().getInChunkSectionLocation(), block);
|
||||
} else {
|
||||
chunk.setBlock(getPosition().getInChunkLocation(), getBlock());
|
||||
section.setBlock(getPosition().getInChunkLocation().getInChunkSectionLocation(), getBlock());
|
||||
}
|
||||
|
||||
connection.getRenderer().prepareChunkSection(getPosition().getChunkLocation(), sectionHeight, section);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -84,6 +84,8 @@ public class PacketChunkBulk extends ClientboundPacket {
|
||||
getChunks().forEach(((location, chunk) -> connection.fireEvent(new ChunkDataChangeEvent(connection, location, chunk))));
|
||||
|
||||
connection.getPlayer().getWorld().setChunks(getChunks());
|
||||
|
||||
getChunks().forEach(((location, chunk) -> connection.getRenderer().prepareChunk(location, chunk)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -17,6 +17,7 @@ import de.bixilon.minosoft.data.mappings.blocks.Block;
|
||||
import de.bixilon.minosoft.data.mappings.tweaker.VersionTweaker;
|
||||
import de.bixilon.minosoft.data.world.Chunk;
|
||||
import de.bixilon.minosoft.data.world.ChunkLocation;
|
||||
import de.bixilon.minosoft.data.world.ChunkSection;
|
||||
import de.bixilon.minosoft.data.world.InChunkLocation;
|
||||
import de.bixilon.minosoft.modding.event.events.MultiBlockChangeEvent;
|
||||
import de.bixilon.minosoft.protocol.network.Connection;
|
||||
@ -25,6 +26,7 @@ import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
|
||||
import de.bixilon.minosoft.util.logging.Log;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
import static de.bixilon.minosoft.protocol.protocol.ProtocolVersions.*;
|
||||
@ -99,6 +101,17 @@ public class PacketMultiBlockChange extends ClientboundPacket {
|
||||
chunk.setBlock(entry.getKey(), block);
|
||||
}
|
||||
}
|
||||
|
||||
HashSet<Integer> sectionHeights = new HashSet<>();
|
||||
|
||||
for (var entry : this.blocks.entrySet()) {
|
||||
sectionHeights.add(entry.getKey().getSectionHeight());
|
||||
}
|
||||
|
||||
for (var sectionHeight : sectionHeights) {
|
||||
ChunkSection section = chunk.getSectionOrCreate(sectionHeight);
|
||||
connection.getRenderer().prepareChunkSection(getLocation(), sectionHeight, section);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -89,6 +89,8 @@ public class PacketRespawn extends ClientboundPacket {
|
||||
connection.getPlayer().getWorld().setDimension(getDimension());
|
||||
connection.getPlayer().setSpawnConfirmed(false);
|
||||
connection.getPlayer().setGameMode(getGameMode());
|
||||
|
||||
connection.getRenderer().clearCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Loading…
x
Reference in New Issue
Block a user