Merge remote-tracking branch 'origin/render' into render

# Conflicts:
#	src/main/java/de/bixilon/minosoft/render/WorldRenderer.java
#	src/main/java/de/bixilon/minosoft/render/blockModels/BlockModelInterface.java
#	src/main/java/de/bixilon/minosoft/render/blockModels/Face/RenderConstants.java
#	src/main/java/de/bixilon/minosoft/render/blockModels/specialModels/CropModel.java
#	src/main/java/de/bixilon/minosoft/render/blockModels/specialModels/DoorModel.java
#	src/main/java/de/bixilon/minosoft/render/blockModels/specialModels/StairsModel.java
#	src/main/java/de/bixilon/minosoft/render/blockModels/subBlocks/SubBlock.java
#	src/main/java/de/bixilon/minosoft/render/blockModels/subBlocks/SubBlockPosition.java
#	src/main/java/de/bixilon/minosoft/render/texture/InFaceUV.java
This commit is contained in:
Lukas 2020-09-30 21:57:58 +02:00
commit e21294b363
38 changed files with 419 additions and 359 deletions

View File

@ -105,7 +105,7 @@ public class Minosoft {
public static void checkClientToken() {
if (config.getString(GameConfiguration.CLIENT_TOKEN) == null || config.getString(GameConfiguration.CLIENT_TOKEN).equals("randomGenerated")) {
config.putString(GameConfiguration.CLIENT_TOKEN, UUID.randomUUID().toString());
config.saveToFile(Config.configFileName);
config.saveToFile();
}
}
@ -125,7 +125,7 @@ public class Minosoft {
if (account == null) {
selectedAccount = null;
config.putString(GameConfiguration.ACCOUNT_SELECTED, null);
config.saveToFile(Config.configFileName);
config.saveToFile();
return;
}
MojangAccount.RefreshStates refreshState = account.refreshToken();

View File

@ -30,6 +30,7 @@ import java.util.UUID;
public class Configuration {
final LinkedHashMap<String, Object> config;
final Thread thread;
public Configuration(String filename) throws IOException {
File file = new File(Config.homeDir + "config/" + filename);
@ -50,6 +51,45 @@ public class Configuration {
FileInputStream inputStream = new FileInputStream(file);
config = yml.load(inputStream);
inputStream.close();
final File finalFile = file;
thread = new Thread(() -> {
while (true) {
// wait for interrupt
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException ignored) {
}
// write config to temp file, delete original config, rename temp file to original file to avoid conflicts if minosoft gets closed while saving the config
File tempFile = new File(Config.homeDir + "config/" + filename + ".tmp");
Yaml yaml = new Yaml();
FileWriter writer;
try {
writer = new FileWriter(tempFile);
} catch (IOException e) {
e.printStackTrace();
return;
}
synchronized (config) {
yaml.dump(config, writer);
}
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
if (finalFile.exists()) {
finalFile.delete();
}
if (!tempFile.renameTo(finalFile)) {
Log.fatal("An error occurred while saving the config file");
} else {
Log.verbose(String.format("Configuration saved to file %s", filename));
}
}
});
thread.setName("IO-Thread");
thread.start();
}
public boolean getBoolean(String path) {
@ -173,35 +213,8 @@ public class Configuration {
config.remove(path);
}
public void saveToFile(String filename) {
Thread thread = new Thread(() -> {
// write config to temp file, delete original config, rename temp file to original file to avoid conflicts if minosoft gets closed while saving the config
File tempFile = new File(Config.homeDir + "config/" + filename + ".tmp");
File file = new File(Config.homeDir + "config/" + filename);
Yaml yaml = new Yaml();
FileWriter writer;
try {
writer = new FileWriter(tempFile);
} catch (IOException e) {
e.printStackTrace();
return;
}
synchronized (config) {
yaml.dump(config, writer);
}
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
if (!file.delete() || !tempFile.renameTo(file)) {
Log.fatal("An error occurred while saving the config file");
} else {
Log.verbose(String.format("Configuration saved to file %s", filename));
}
});
thread.setName("IO-Thread");
thread.start();
public void saveToFile() {
thread.interrupt();
}
public HashBiMap<String, MojangAccount> getMojangAccounts() {

View File

@ -22,13 +22,12 @@ import de.bixilon.minosoft.game.datatypes.player.PlayerListItem;
import de.bixilon.minosoft.game.datatypes.scoreboard.ScoreboardManager;
import de.bixilon.minosoft.game.datatypes.world.BlockPosition;
import de.bixilon.minosoft.game.datatypes.world.World;
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition;
import de.bixilon.minosoft.util.mojang.api.MojangAccount;
import java.util.HashMap;
import java.util.UUID;
import static de.bixilon.minosoft.protocol.protocol.ProtocolDefinition.PLAYER_INVENTORY_ID;
public class Player {
final MojangAccount account;
final ScoreboardManager scoreboardManager = new ScoreboardManager();
@ -52,7 +51,7 @@ public class Player {
public Player(MojangAccount account) {
this.account = account;
// create our own inventory without any properties
inventories.put(PLAYER_INVENTORY_ID, new Inventory(null));
inventories.put(ProtocolDefinition.PLAYER_INVENTORY_ID, new Inventory(null));
}
public String getPlayerName() {
@ -136,11 +135,11 @@ public class Player {
}
public Inventory getPlayerInventory() {
return getInventory(PLAYER_INVENTORY_ID);
return getInventory(ProtocolDefinition.PLAYER_INVENTORY_ID);
}
public void setPlayerInventory(Slot[] data) {
setInventory(PLAYER_INVENTORY_ID, data);
setInventory(ProtocolDefinition.PLAYER_INVENTORY_ID, data);
}
public Inventory getInventory(int id) {

View File

@ -73,7 +73,7 @@ public class Block {
out.append("rotation=");
out.append(getRotation());
}
if (properties.size() > 0) {
if (!properties.isEmpty()) {
if (out.length() > 0) {
out.append(", ");
} else {
@ -91,7 +91,7 @@ public class Block {
@Override
public int hashCode() {
int ret = mod.hashCode() * identifier.hashCode() * rotation.hashCode();
if (properties.size() > 0) {
if (!properties.isEmpty()) {
ret *= properties.hashCode();
}
return ret;

View File

@ -13,6 +13,7 @@
package de.bixilon.minosoft.game.datatypes.world;
import de.bixilon.minosoft.render.blockModels.Face.RenderConstants;
import de.bixilon.minosoft.render.utility.Vec3;
public class BlockPosition {
@ -21,7 +22,6 @@ public class BlockPosition {
final int z;
public BlockPosition(int x, int y, int z) {
// y min -2048, max 2047
this.x = x;
this.y = y;
this.z = z;
@ -34,9 +34,9 @@ public class BlockPosition {
}
public BlockPosition(ChunkLocation chunkLocation, Byte height, ChunkNibbleLocation nibbleLocation) {
this.x = chunkLocation.getX() * 16 + nibbleLocation.getX();
this.y = height * 16 + nibbleLocation.getY();
this.z = chunkLocation.getZ() * 16 + nibbleLocation.getZ();
this.x = chunkLocation.getX() * RenderConstants.SECTION_WIDTH + nibbleLocation.getX();
this.y = height * RenderConstants.SECTION_HEIGHT + nibbleLocation.getY();
this.z = chunkLocation.getZ() * RenderConstants.SECTION_WIDTH + nibbleLocation.getZ();
}
public int getX() {
@ -61,8 +61,9 @@ public class BlockPosition {
}
public ChunkLocation getChunkLocation() {
int x = getX() / 16;
int z = getZ() / 16;
int x = getX() / RenderConstants.SECTION_WIDTH;
int z = getZ() / RenderConstants.SECTION_WIDTH;
//ToDo
if (getX() < 0) {
x--;
}
@ -83,13 +84,13 @@ public class BlockPosition {
}
public InChunkLocation getInChunkLocation() {
int x = getX() % 16;
int x = getX() % RenderConstants.SECTION_WIDTH;
if (x < 0) {
x = 16 + x;
x += RenderConstants.SECTION_WIDTH;
}
int z = getZ() % 16;
int z = getZ() % RenderConstants.SECTION_WIDTH;
if (z < 0) {
z = 16 + z;
z += RenderConstants.SECTION_WIDTH;
}
return new InChunkLocation(x, getY(), z);
}

View File

@ -14,30 +14,25 @@
package de.bixilon.minosoft.game.datatypes.world;
import de.bixilon.minosoft.game.datatypes.objectLoader.blocks.Block;
import de.bixilon.minosoft.game.datatypes.objectLoader.blocks.Blocks;
import de.bixilon.minosoft.render.blockModels.Face.RenderConstants;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Collection of 16 chunks nibbles
*/
public class Chunk {
final HashMap<Byte, ChunkNibble> nibbles;
final ConcurrentHashMap<Byte, ChunkNibble> nibbles;
public Chunk(HashMap<Byte, ChunkNibble> chunks) {
public Chunk(ConcurrentHashMap<Byte, ChunkNibble> chunks) {
this.nibbles = chunks;
}
public Block getBlock(int x, int y, int z) {
if (x > 15 || y > 255 || z > 15 || x < 0 || y < 0 || z < 0) {
throw new IllegalArgumentException(String.format("Invalid chunk location %s %s %s", x, y, z));
}
byte section = (byte) (y / 16);
if (nibbles.get(section) == null) {
return Blocks.nullBlock;
}
return nibbles.get(section).getBlock(x, y % 16, z);
byte section = (byte) (y / RenderConstants.SECTION_HEIGHT);
return nibbles.get(section).getBlock(x, y % RenderConstants.SECTION_HEIGHT, z);
}
public Block getBlock(InChunkLocation location) {
@ -45,20 +40,19 @@ public class Chunk {
}
public void setBlock(int x, int y, int z, Block block) {
byte section = (byte) (y / 16);
createSection(section);
nibbles.get(section).setBlock(x, y % 16, z, block);
byte section = (byte) (y / RenderConstants.SECTION_HEIGHT);
createSectionIfNotExist(section);
nibbles.get(section).setBlock(x, y % RenderConstants.SECTION_HEIGHT, z, block);
}
public void setBlock(InChunkLocation location, Block block) {
byte section = (byte) (location.getY() / 16);
createSection(section);
byte section = (byte) (location.getY() / RenderConstants.SECTION_HEIGHT);
createSectionIfNotExist(section);
nibbles.get(section).setBlock(location.getChunkNibbleLocation(), block);
}
void createSection(byte section) {
void createSectionIfNotExist(byte section) {
if (nibbles.get(section) == null) {
// nibble was empty before, creating it
nibbles.put(section, new ChunkNibble());
}
}
@ -69,7 +63,7 @@ public class Chunk {
}
}
public HashMap<Byte, ChunkNibble> getNibbles() {
public ConcurrentHashMap<Byte, ChunkNibble> getNibbles() {
return nibbles;
}
}

View File

@ -14,25 +14,29 @@
package de.bixilon.minosoft.game.datatypes.world;
import de.bixilon.minosoft.game.datatypes.objectLoader.blocks.Block;
import de.bixilon.minosoft.game.datatypes.objectLoader.blocks.Blocks;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
/**
* Collection of 16x16x16 blocks
*/
public class ChunkNibble {
final HashMap<ChunkNibbleLocation, Block> blocks;
final ConcurrentHashMap<ChunkNibbleLocation, Block> blocks;
public ChunkNibble(HashMap<ChunkNibbleLocation, Block> blocks) {
public ChunkNibble(ConcurrentHashMap<ChunkNibbleLocation, Block> blocks) {
this.blocks = blocks;
}
public ChunkNibble() {
// empty
this.blocks = new HashMap<>();
this.blocks = new ConcurrentHashMap<>();
}
public Block getBlock(ChunkNibbleLocation loc) {
if (!blocks.containsKey(loc)) {
return null;
}
return blocks.get(loc);
}
@ -41,14 +45,18 @@ public class ChunkNibble {
}
public void setBlock(int x, int y, int z, Block block) {
blocks.put(new ChunkNibbleLocation(x, y, z), block);
setBlock(new ChunkNibbleLocation(x, y, z), block);
}
public void setBlock(ChunkNibbleLocation location, Block block) {
if (block == null || block.equals(Blocks.nullBlock)) {
blocks.remove(location);
return;
}
blocks.put(location, block);
}
public HashMap<ChunkNibbleLocation, Block> getBlocks() {
public ConcurrentHashMap<ChunkNibbleLocation, Block> getBlocks() {
return blocks;
}
}

View File

@ -13,21 +13,14 @@
package de.bixilon.minosoft.game.datatypes.world;
/**
* Chunk X, Y and Z location (max 16x16x16)
*/
import de.bixilon.minosoft.render.blockModels.Face.RenderConstants;
public class InChunkLocation {
final int x;
final int y;
final int z;
public InChunkLocation(int x, int y, int z) {
// x 0 - 16
// y 0 - 255
// z 0 - 16
if (x > 15 || y > 255 || z > 15 || x < 0 || y < 0 || z < 0) {
throw new IllegalArgumentException(String.format("Invalid chunk location %s %s %s", x, y, z));
}
this.x = x;
this.y = y;
this.z = z;
@ -55,7 +48,7 @@ public class InChunkLocation {
}
public ChunkNibbleLocation getChunkNibbleLocation() {
return new ChunkNibbleLocation(getX(), getY() % 16, getZ());
return new ChunkNibbleLocation(getX(), getY() % RenderConstants.SECTION_HEIGHT, getZ());
}
@Override

View File

@ -17,20 +17,20 @@ import de.bixilon.minosoft.game.datatypes.entities.Entity;
import de.bixilon.minosoft.game.datatypes.objectLoader.blocks.Block;
import de.bixilon.minosoft.game.datatypes.objectLoader.blocks.Blocks;
import de.bixilon.minosoft.game.datatypes.objectLoader.dimensions.Dimension;
import de.bixilon.minosoft.render.GameWindow;
import de.bixilon.minosoft.util.nbt.tag.CompoundTag;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Collection of ChunkColumns
*/
public class World {
final HashMap<ChunkLocation, Chunk> chunks = new HashMap<>();
final HashMap<Integer, Entity> entities = new HashMap<>();
final ConcurrentHashMap<ChunkLocation, Chunk> chunks = new ConcurrentHashMap<>();
final ConcurrentHashMap<Integer, Entity> entities = new ConcurrentHashMap<>();
final String name;
final HashMap<BlockPosition, CompoundTag> blockEntityMeta = new HashMap<>();
final ConcurrentHashMap<BlockPosition, CompoundTag> blockEntityMeta = new ConcurrentHashMap<>();
boolean hardcore;
boolean raining;
Dimension dimension; // used for sky color, etc
@ -47,7 +47,7 @@ public class World {
return chunks.get(loc);
}
public HashMap<ChunkLocation, Chunk> getAllChunks() {
public ConcurrentHashMap<ChunkLocation, Chunk> getAllChunks() {
return chunks;
}
@ -65,7 +65,6 @@ public class World {
public void setBlock(BlockPosition pos, Block block) {
if (getChunk(pos.getChunkLocation()) != null) {
getChunk(pos.getChunkLocation()).setBlock(pos.getInChunkLocation(), block);
GameWindow.getRenderer().prepareChunkNibble(pos.getChunkLocation(), (byte) (pos.getY() / 16), getChunk(pos.getChunkLocation()).getNibbles().get((byte) (pos.getY() / 16)));
}
// do nothing if chunk is unloaded
}
@ -76,14 +75,10 @@ public class World {
public void setChunk(ChunkLocation location, Chunk chunk) {
chunks.put(location, chunk);
GameWindow.getRenderer().queueChunk(location, chunk);
}
public void setChunks(HashMap<ChunkLocation, Chunk> chunkMap) {
for (Map.Entry<ChunkLocation, Chunk> set : chunkMap.entrySet()) {
chunks.put(set.getKey(), set.getValue());
}
GameWindow.getRenderer().queueChunkBulk(chunkMap);
chunkMap.forEach(chunks::put);
}
public boolean isHardcore() {
@ -135,7 +130,7 @@ public class World {
return blockEntityMeta.get(position);
}
public void setBlockEntityData(HashMap<BlockPosition, CompoundTag> blockEntities) {
public void setBlockEntityData(ConcurrentHashMap<BlockPosition, CompoundTag> blockEntities) {
for (Map.Entry<BlockPosition, CompoundTag> entrySet : blockEntities.entrySet()) {
blockEntityMeta.put(entrySet.getKey(), entrySet.getValue());
}

View File

@ -13,7 +13,6 @@
package de.bixilon.minosoft.gui.main;
import de.bixilon.minosoft.Config;
import de.bixilon.minosoft.Minosoft;
import de.bixilon.minosoft.protocol.network.Connection;
import de.bixilon.minosoft.protocol.protocol.ConnectionReasons;
@ -95,12 +94,12 @@ public class Server {
public void saveToConfig() {
Minosoft.getConfig().putServer(this);
Minosoft.getConfig().saveToFile(Config.configFileName);
Minosoft.getConfig().saveToFile();
}
public void delete() {
Minosoft.getConfig().removeServer(this);
Minosoft.getConfig().saveToFile(Config.configFileName);
Minosoft.getConfig().saveToFile();
}
public Connection getLastPing() {

View File

@ -13,7 +13,6 @@
package de.bixilon.minosoft.gui.main;
import de.bixilon.minosoft.Config;
import de.bixilon.minosoft.Minosoft;
import de.bixilon.minosoft.config.GameConfiguration;
import de.bixilon.minosoft.logging.Log;
@ -43,7 +42,7 @@ public class SettingsWindow implements Initializable {
}
Log.setLevel(newLevel);
Minosoft.getConfig().putString(GameConfiguration.GENERAL_LOG_LEVEL, newLevel.name());
Minosoft.getConfig().saveToFile(Config.configFileName);
Minosoft.getConfig().saveToFile();
}));
}
}

View File

@ -24,10 +24,10 @@ import de.bixilon.minosoft.util.ChunkUtil;
import de.bixilon.minosoft.util.Util;
import de.bixilon.minosoft.util.nbt.tag.CompoundTag;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
public class PacketChunkData implements ClientboundPacket {
final HashMap<BlockPosition, CompoundTag> blockEntities = new HashMap<>();
final ConcurrentHashMap<BlockPosition, CompoundTag> blockEntities = new ConcurrentHashMap<>();
ChunkLocation location;
Chunk chunk;
CompoundTag heightMap;
@ -122,7 +122,7 @@ public class PacketChunkData implements ClientboundPacket {
return chunk;
}
public HashMap<BlockPosition, CompoundTag> getBlockEntities() {
public ConcurrentHashMap<BlockPosition, CompoundTag> getBlockEntities() {
return blockEntities;
}

View File

@ -55,7 +55,7 @@ public class PacketMultiBlockChange implements ClientboundPacket {
byte pos = buffer.readByte();
byte y = buffer.readByte();
int blockId = buffer.readVarInt();
blocks.put(new InChunkLocation((pos & 0xF0 >>> 4) & 0xF, y, pos & 0xF), buffer.getConnection().getMapping().getBlockById(blockId));
blocks.put(new InChunkLocation((pos >>> 4) & 0xF, y, pos & 0xF), buffer.getConnection().getMapping().getBlockById(blockId));
}
return true;
}

View File

@ -38,10 +38,10 @@ import de.bixilon.minosoft.protocol.packets.clientbound.status.PacketStatusRespo
import de.bixilon.minosoft.protocol.packets.serverbound.login.PacketEncryptionResponse;
import de.bixilon.minosoft.protocol.packets.serverbound.play.PacketKeepAliveResponse;
import de.bixilon.minosoft.protocol.packets.serverbound.play.PacketResourcePackStatus;
import de.bixilon.minosoft.util.nbt.tag.CompoundTag;
import de.bixilon.minosoft.util.nbt.tag.StringTag;
import de.bixilon.minosoft.render.GameWindow;
import de.bixilon.minosoft.render.utility.Vec3;
import de.bixilon.minosoft.util.nbt.tag.CompoundTag;
import de.bixilon.minosoft.util.nbt.tag.StringTag;
import javax.crypto.SecretKey;
import java.math.BigInteger;
@ -67,7 +67,7 @@ public class PacketHandler {
if (version == null) {
Log.fatal(String.format("Server is running on unknown version or a invalid version was forced (version=%d, brand=\"%s\")", versionId, pkg.getResponse().getServerBrand()));
} else {
connection.setVersion(version);
connection.setVersion(version);
}
Log.info(String.format("Status response received: %s/%s online. MotD: '%s'", pkg.getResponse().getPlayerOnline(), pkg.getResponse().getMaxPlayers(), pkg.getResponse().getMotd().getColoredMessage()));
connection.handlePingCallbacks(pkg.getResponse());
@ -172,6 +172,7 @@ public class PacketHandler {
public void handle(PacketChunkBulk pkg) {
connection.getPlayer().getWorld().setChunks(pkg.getChunkMap());
GameWindow.getRenderer().queueChunkBulk(pkg.getChunkMap());
}
public void handle(PacketUpdateHealth pkg) {
@ -288,7 +289,8 @@ public class PacketHandler {
}
public void handle(PacketBlockChange pkg) {
connection.getPlayer().getWorld().setBlock(pkg.getPosition(), pkg.getBlock());
connection.getPlayer().getWorld().getChunk(pkg.getPosition().getChunkLocation()).setBlock(pkg.getPosition().getInChunkLocation(), pkg.getBlock());
GameWindow.getRenderer().queueBlock(pkg.getPosition(), pkg.getBlock());
}
public void handle(PacketMultiBlockChange pkg) {
@ -298,6 +300,7 @@ public class PacketHandler {
return;
}
chunk.setBlocks(pkg.getBlocks());
GameWindow.getRenderer().queueChunk(pkg.getLocation(), chunk);
}
public void handle(PacketRespawn pkg) {
@ -328,6 +331,7 @@ public class PacketHandler {
public void handle(PacketChunkData pkg) {
connection.getPlayer().getWorld().setChunk(pkg.getLocation(), pkg.getChunk());
connection.getPlayer().getWorld().setBlockEntityData(pkg.getBlockEntities());
GameWindow.getRenderer().queueChunk(pkg.getLocation(), pkg.getChunk());
}
public void handle(PacketEntityEffect pkg) {

View File

@ -25,13 +25,12 @@ public class GameWindow {
private static final int WIDTH = 800;
private static final int HEIGHT = 800;
private static final boolean FULLSCREEN = false;
public static boolean paused = false;
private static OpenGLWindow openGLWindow;
private static WorldRenderer renderer;
private static Connection connection;
private static PlayerController playerController;
private static boolean running = false;
public static boolean paused = false;
public static void prepare() {
Thread guiLoaderThread = new Thread(() -> {
@ -42,7 +41,7 @@ public class GameWindow {
renderer.init();
Log.info("Finished loading game Assets");
try {
while (! running) {
while (!running) {
Thread.sleep(100);
}
openGLWindow.start();
@ -100,7 +99,7 @@ public class GameWindow {
}
public static void pause() {
paused = ! paused;
paused = !paused;
openGLWindow.mouseEnable(paused);
}
}

View File

@ -28,6 +28,7 @@ import static org.lwjgl.system.MemoryUtil.NULL;
public class OpenGLWindow {
private final boolean fullscreen;
boolean escDown = false;
private long window;
private int width, height;
private double mouseX;
@ -51,8 +52,9 @@ public class OpenGLWindow {
public void init() {
GLFWErrorCallback.createPrint(System.err).set();
if (!glfwInit())
if (!glfwInit()) {
throw new IllegalStateException("Unable to initialize GLFW");
}
glfwDefaultWindowHints();
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
@ -66,8 +68,9 @@ public class OpenGLWindow {
}
window = glfwCreateWindow(width, height, "RENDER", NULL, NULL);
if (window == NULL)
if (window == NULL) {
throw new RuntimeException("Failed to create the GLFW window");
}
try (MemoryStack stack = stackPush()) {
IntBuffer pWidth = stack.mallocInt(1); // int*
@ -77,11 +80,7 @@ public class OpenGLWindow {
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
glfwSetWindowPos(
window,
(vidmode.width() - pWidth.get(0)) / 2,
(vidmode.height() - pHeight.get(0)) / 2
);
glfwSetWindowPos(window, (vidmode.width() - pWidth.get(0)) / 2, (vidmode.height() - pHeight.get(0)) / 2);
}
glfwMakeContextCurrent(window);
@ -138,11 +137,9 @@ public class OpenGLWindow {
return mouseY;
}
boolean escDown = false;
public float loop() {
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
if (! escDown) {
if (!escDown) {
GameWindow.pause();
escDown = true;
}

View File

@ -17,14 +17,18 @@ import de.bixilon.minosoft.game.datatypes.objectLoader.blocks.Block;
import de.bixilon.minosoft.game.datatypes.objectLoader.blocks.Blocks;
import de.bixilon.minosoft.game.datatypes.world.*;
import de.bixilon.minosoft.logging.Log;
import de.bixilon.minosoft.protocol.network.Connection;
import de.bixilon.minosoft.render.blockModels.Face.FaceOrientation;
import javafx.util.Pair;
import org.apache.commons.collections.primitives.ArrayFloatList;
import de.bixilon.minosoft.render.blockModels.Face.RenderConstants;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import static org.lwjgl.opengl.GL11.*;
@ -32,32 +36,29 @@ public class WorldRenderer {
private final ConcurrentHashMap<ChunkLocation, ConcurrentHashMap<Byte, ArrayFloatList>> faces;
private AssetsLoader assetsLoader;
private LinkedBlockingQueue<Pair<ChunkLocation, Chunk>> queuedChunks;
private LinkedBlockingQueue<Runnable> queuedMapData;
public WorldRenderer() {
faces = new ConcurrentHashMap<>();
}
public void init() {
queuedChunks = new LinkedBlockingQueue<>();
queuedMapData = new LinkedBlockingQueue<>();
assetsLoader = new AssetsLoader();
}
public void startChunkPreparation(Connection connection) {
Thread chunkLoadThread = new Thread(() -> {
while (GameWindow.getConnection() == null) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
while (true) {
try {
Pair<ChunkLocation, Chunk> current = queuedChunks.take();
prepareChunk(current.getKey(), current.getValue());
queuedMapData.take().run();
//Log.verbose(String.format("Count of faces: %d", getCountOfFaces()));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
chunkLoadThread.setName(String.format("%d/ChunkLoading", 0)); // TODO: connection ID
chunkLoadThread.setName(String.format("%d/ChunkLoading", connection.getConnectionId()));
chunkLoadThread.start();
assetsLoader = new AssetsLoader();
}
@ -67,60 +68,179 @@ public class WorldRenderer {
}
public void queueChunk(ChunkLocation location, Chunk chunk) {
queuedChunks.add(new Pair<>(location, chunk));
queuedMapData.add(() -> prepareChunk(location, chunk));
}
public void prepareChunk(ChunkLocation location, Chunk chunk) {
public void queueChunkNibble(ChunkLocation location, byte sectionHeight, ChunkNibble nibble) {
queuedMapData.add(() -> prepareChunkNibble(location, sectionHeight, nibble));
}
public void queueBlock(BlockPosition position, Block block) {
queuedMapData.add(() -> prepareBlock(position, block, false));
}
private void prepareChunk(ChunkLocation location, Chunk chunk) {
// clear or create current chunk
faces.put(location, new ConcurrentHashMap<>());
chunk.getNibbles().forEach(((height, chunkNibble) -> {
prepareChunkNibble(location, height, chunkNibble);
}));
ConcurrentHashMap<Byte, ChunkNibbleLocation> chunkFaces = new ConcurrentHashMap<>();
chunk.getNibbles().forEach(((height, chunkNibble) -> chunkFaces.put(height, getFacesForChunkNibble(location, height, chunkNibble))));
faces.put(location, chunkFaces);
}
public void prepareChunkNibble(ChunkLocation chunkLocation, byte height, ChunkNibble nibble) {
private void prepareChunkNibble(ChunkLocation chunkLocation, byte sectionHeight, ChunkNibble nibble) {
faces.get(chunkLocation).put(sectionHeight, getFacesForChunkNibble(chunkLocation, sectionHeight, nibble));
}
private ConcurrentHashMap<ChunkNibbleLocation, ArrayFloatList> getFacesForChunkNibble(ChunkLocation chunkLocation, byte sectionHeight, ChunkNibble nibble) {
HashMap<ChunkLocation, Chunk> world = GameWindow.getConnection().getPlayer().getWorld().getAllChunks();
// clear or create current chunk nibble
ArrayFloatList nibbleMap = new ArrayFloatList();
faces.get(chunkLocation).put(height, nibbleMap);
ConcurrentHashMap<ChunkNibbleLocation, ArrayFloatList> nibbleMap = new ConcurrentHashMap<>();
faces.get(chunkLocation).put(sectionHeight, nibbleMap);
HashMap<ChunkNibbleLocation, Block> nibbleBlocks = nibble.getBlocks();
nibbleBlocks.forEach((location, block) -> {
HashSet<FaceOrientation> facesToDraw = new HashSet<>();
if (block.equals(Blocks.nullBlock)) {
return;
}
for (FaceOrientation orientation : FaceOrientation.values()) {
if ((location.getX() == 0 && orientation == FaceOrientation.WEST) || (location.getX() == 15 && orientation == FaceOrientation.EAST)) {
facesToDraw.add(orientation);
continue;
}
if ((location.getY() == 0 && orientation == FaceOrientation.DOWN) || (location.getY() == 15 && orientation == FaceOrientation.UP)) {
facesToDraw.add(orientation);
continue;
}
if ((location.getZ() == 0 && orientation == FaceOrientation.NORTH) || (location.getZ() == 15 && orientation == FaceOrientation.SOUTH)) {
facesToDraw.add(orientation);
continue;
}
boolean isNeighbourFull = switch (orientation) {
case DOWN -> assetsLoader.getBlockModelLoader().isFull(nibbleBlocks.get(new ChunkNibbleLocation(location.getX(), location.getY() - 1, location.getZ())));
case UP -> assetsLoader.getBlockModelLoader().isFull(nibbleBlocks.get(new ChunkNibbleLocation(location.getX(), location.getY() + 1, location.getZ())));
case WEST -> assetsLoader.getBlockModelLoader().isFull(nibbleBlocks.get(new ChunkNibbleLocation(location.getX() - 1, location.getY(), location.getZ())));
case EAST -> assetsLoader.getBlockModelLoader().isFull(nibbleBlocks.get(new ChunkNibbleLocation(location.getX() + 1, location.getY(), location.getZ())));
case NORTH -> assetsLoader.getBlockModelLoader().isFull(nibbleBlocks.get(new ChunkNibbleLocation(location.getX(), location.getY(), location.getZ() - 1)));
case SOUTH -> assetsLoader.getBlockModelLoader().isFull(nibbleBlocks.get(new ChunkNibbleLocation(location.getX(), location.getY(), location.getZ() + 1)));
Block dependedBlock = switch (orientation) {
case DOWN -> {
if (location.getY() == RenderConstants.SECTIONS_MIN_Y) {
// need to check upper section (nibble)
if (sectionHeight == RenderConstants.SECTIONS_MIN_Y) {
// y = 0, there can't be any blocks below me
yield null;
}
// check if block over us is a full block
byte bottomSection = (byte) (sectionHeight - 1);
if (!world.get(chunkLocation).getNibbles().containsKey(bottomSection)) {
yield null;
}
yield world.get(chunkLocation).getNibbles().get(bottomSection).getBlock(location.getX(), RenderConstants.SECTIONS_MAX_Y, location.getZ());
}
yield nibbleBlocks.get(new ChunkNibbleLocation(location.getX(), location.getY() - 1, location.getZ()));
}
case UP -> {
if (location.getY() == RenderConstants.SECTIONS_MAX_Y) {
// need to check upper section (nibble)
if (sectionHeight == RenderConstants.SECTIONS_MAX_Y) {
// y = 255, there can't be any blocks above me
yield null;
}
// check if block over us is a full block
byte upperSection = (byte) (sectionHeight + 1);
if (!world.get(chunkLocation).getNibbles().containsKey(upperSection)) {
yield null;
}
yield world.get(chunkLocation).getNibbles().get(upperSection).getBlock(location.getX(), RenderConstants.SECTIONS_MIN_Y, location.getZ());
}
yield nibbleBlocks.get(new ChunkNibbleLocation(location.getX(), location.getY() + 1, location.getZ()));
}
case WEST -> {
if (location.getX() == RenderConstants.SECTIONS_MIN_X) {
ChunkNibble otherChunkNibble = getChunkNibbleOfWorld(world, new ChunkLocation(chunkLocation.getX() - 1, chunkLocation.getZ()), sectionHeight);
if (otherChunkNibble != null) {
yield otherChunkNibble.getBlock(RenderConstants.SECTIONS_MAX_X, location.getY(), location.getZ());
}
}
yield nibbleBlocks.get(new ChunkNibbleLocation(location.getX() - 1, location.getY(), location.getZ()));
}
case EAST -> {
if (location.getX() == RenderConstants.SECTIONS_MIN_X) {
ChunkNibble otherChunkNibble = getChunkNibbleOfWorld(world, new ChunkLocation(chunkLocation.getX() + 1, chunkLocation.getZ()), sectionHeight);
if (otherChunkNibble != null) {
yield otherChunkNibble.getBlock(RenderConstants.SECTIONS_MAX_X, location.getY(), location.getZ());
}
}
yield nibbleBlocks.get(new ChunkNibbleLocation(location.getX() + 1, location.getY(), location.getZ()));
}
case NORTH -> {
if (location.getZ() == RenderConstants.SECTIONS_MIN_Z) {
ChunkNibble otherChunkNibble = getChunkNibbleOfWorld(world, new ChunkLocation(chunkLocation.getX(), chunkLocation.getZ() - 1), sectionHeight);
if (otherChunkNibble != null) {
yield otherChunkNibble.getBlock(location.getX(), location.getY(), RenderConstants.SECTIONS_MAX_Z);
}
}
yield nibbleBlocks.get(new ChunkNibbleLocation(location.getX(), location.getY(), location.getZ() - 1));
}
case SOUTH -> {
if (location.getZ() == RenderConstants.SECTIONS_MAX_Z) {
ChunkNibble otherChunkNibble = getChunkNibbleOfWorld(world, new ChunkLocation(chunkLocation.getX(), chunkLocation.getZ() + 1), sectionHeight);
if (otherChunkNibble != null) {
yield otherChunkNibble.getBlock(location.getX(), location.getY(), RenderConstants.SECTIONS_MIN_Z);
}
}
yield nibbleBlocks.get(new ChunkNibbleLocation(location.getX(), location.getY(), location.getZ() + 1));
}
};
if (!isNeighbourFull) {
if (dependedBlock == null || !assetsLoader.getBlockModelLoader().isFull(dependedBlock)) {
facesToDraw.add(orientation);
}
}
if (facesToDraw.size() > 0) {
faces.get(chunkLocation).put(height, assetsLoader.getBlockModelLoader().prepare(block, facesToDraw, new BlockPosition(chunkLocation, height, location)));
if (!location.equals(new ChunkNibbleLocation(0,0,0))) {
Log.debug(".");
if (!facesToDraw.isEmpty()) {
nibbleMap.put(location, assetsLoader.getBlockModelLoader().prepare(block, facesToDraw));
}
}
return nibbleMap;
}
private void prepareBlock(BlockPosition position, Block block, boolean trustEdges) {
HashSet<FaceOrientation> facesToDraw = new HashSet<>();
if (block != null && !block.equals(Blocks.nullBlock)) {
for (FaceOrientation orientation : FaceOrientation.values()) {
Block dependedBlock = switch (orientation) {
case DOWN -> {
if (position.getY() == RenderConstants.CHUNK_MIN_Y) {
facesToDraw.add(orientation);
yield null;
}
yield GameWindow.getConnection().getPlayer().getWorld().getBlock(new BlockPosition(position.getX(), position.getY() - 1, position.getZ()));
}
case UP -> {
if (position.getY() == RenderConstants.CHUNK_MAX_Y) {
facesToDraw.add(orientation);
yield null;
}
yield GameWindow.getConnection().getPlayer().getWorld().getBlock(new BlockPosition(position.getX(), position.getY() + 1, position.getZ()));
}
case NORTH -> GameWindow.getConnection().getPlayer().getWorld().getBlock(new BlockPosition(position.getX(), position.getY(), position.getZ() - 1));
case SOUTH -> GameWindow.getConnection().getPlayer().getWorld().getBlock(new BlockPosition(position.getX(), position.getY(), position.getZ() + 1));
case WEST -> GameWindow.getConnection().getPlayer().getWorld().getBlock(new BlockPosition(position.getX() - 1, position.getY(), position.getZ()));
case EAST -> GameWindow.getConnection().getPlayer().getWorld().getBlock(new BlockPosition(position.getX() + 1, position.getY(), position.getZ()));
};
if (dependedBlock == null || !assetsLoader.getBlockModelLoader().isFull(dependedBlock)) {
facesToDraw.add(orientation);
}
}
});
}
}
ConcurrentHashMap<ChunkNibbleLocation, ArrayFloatList> nibbleMap = faces.get(position.getChunkLocation()).get((byte) (position.getY() / RenderConstants.SECTION_HEIGHT));
if (facesToDraw.size() == 0) {
// remove all faces
nibbleMap.remove(position.getInChunkLocation().getChunkNibbleLocation());
} else {
nibbleMap.put(position.getInChunkLocation().getChunkNibbleLocation(), assetsLoader.getBlockModelLoader().prepare(block, facesToDraw, position));
}
if (trustEdges) {
return;
}
if (position.getY() != RenderConstants.CHUNK_MIN_Y) {
// bottom
prepareBlock(new BlockPosition(position.getX(), position.getY() - 1, position.getZ()), true);
}
if (position.getY() != RenderConstants.CHUNK_MAX_Y) {
// bottom
prepareBlock(new BlockPosition(position.getX(), position.getY() + 1, position.getZ()), true);
}
prepareBlock(new BlockPosition(position.getX() + 1, position.getY(), position.getZ()), true);
prepareBlock(new BlockPosition(position.getX() - 1, position.getY(), position.getZ()), true);
prepareBlock(new BlockPosition(position.getX(), position.getY(), position.getZ() + 1), true);
prepareBlock(new BlockPosition(position.getX(), position.getY(), position.getZ() - 1), true);
}
private void prepareBlock(BlockPosition position, boolean trustEdges) {
prepareBlock(position, GameWindow.getConnection().getPlayer().getWorld().getBlock(position), trustEdges);
}
public void draw() {
@ -142,4 +262,12 @@ public class WorldRenderer {
public AssetsLoader getAssetsLoader() {
return assetsLoader;
}
private ChunkNibble getChunkNibbleOfWorld(ConcurrentHashMap<ChunkLocation, Chunk> world, ChunkLocation location, byte sectionHeight) {
if (world.containsKey(location) && world.get(location).getNibbles().containsKey(sectionHeight)) {
return world.get(location).getNibbles().get(sectionHeight);
}
return null;
}
}

View File

@ -48,8 +48,7 @@ public class BlockConfiguration {
}
BlockProperties property = properties.get(json.get(propertyName).getAsString());
if (property == null) {
throw new RuntimeException(String.format("Unknown block property: %s -> %s",
propertyName, json.get(propertyName).getAsString()));
throw new RuntimeException(String.format("Unknown block property: %s -> %s", propertyName, json.get(propertyName).getAsString()));
}
blockProperties.add(property);
}
@ -67,8 +66,7 @@ public class BlockConfiguration {
}
public boolean equals(BlockConfiguration blockConfiguration) {
return rotation.equals(blockConfiguration.getRotation()) &&
blockProperties.equals(blockConfiguration.getBlockProperties());
return rotation.equals(blockConfiguration.getRotation()) && blockProperties.equals(blockConfiguration.getBlockProperties());
}
public boolean contains(Block block) {

View File

@ -16,9 +16,6 @@ package de.bixilon.minosoft.render.blockModels;
import de.bixilon.minosoft.game.datatypes.objectLoader.blocks.Block;
public class BlockConfigurationTrue extends BlockConfiguration {
public BlockConfigurationTrue() {
}
@Override
public boolean contains(Block block) {
return true;

View File

@ -3,11 +3,11 @@
* Copyright (C) 2020 Lukas Eisenhauer
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
@ -25,14 +25,13 @@ import de.bixilon.minosoft.render.blockModels.Face.FaceOrientation;
import de.bixilon.minosoft.render.blockModels.subBlocks.SubBlock;
import de.bixilon.minosoft.render.texture.TextureLoader;
import org.apache.commons.collections.primitives.ArrayFloatList;
import de.bixilon.minosoft.util.Util;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import static de.bixilon.minosoft.util.Util.readJsonFromFile;
public interface BlockModelInterface {
ArrayFloatList prepare(Block block, HashSet<FaceOrientation> facesToDraw, BlockPosition position);
boolean isFull();
@ -72,11 +71,9 @@ public interface BlockModelInterface {
String path = Config.homeDir + "assets/" + mod + "/models/block/" + identifier + ".json";
JsonObject json = null;
try {
json = readJsonFromFile(path);
json = Util.readJsonFromFile(path);
} catch (IOException e) {
e.printStackTrace();
}
if (json == null) {
Log.warn("File not found: " + path);
return null;
}

View File

@ -21,6 +21,7 @@ import de.bixilon.minosoft.game.datatypes.world.BlockPosition;
import de.bixilon.minosoft.render.blockModels.Face.FaceOrientation;
import de.bixilon.minosoft.render.blockModels.specialModels.*;
import de.bixilon.minosoft.render.texture.TextureLoader;
import de.bixilon.minosoft.util.Util;
import org.apache.commons.collections.primitives.ArrayFloatList;
import java.io.IOException;
@ -28,7 +29,6 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import static de.bixilon.minosoft.util.Util.readJsonAsset;
public class BlockModelLoader {
private final HashMap<String, HashMap<String, BlockModelInterface>> blockDescriptionMap;
@ -40,7 +40,7 @@ public class BlockModelLoader {
tints = new HashMap<>();
textures = new HashMap<>();
try {
JsonObject json = readJsonAsset("mapping/blockModels.json");
JsonObject json = Util.readJsonAsset("mapping/blockModels.json");
String mod = "minecraft";
tints.put(mod, readTints(json));
textures.put(mod, loadModels(json.get("blocks").getAsJsonObject(), mod));
@ -95,7 +95,6 @@ public class BlockModelLoader {
HashSet<String> result = new HashSet<>();
try {
String type = "";
if (block.has("type")) {
type = block.get("type").getAsString();
}

View File

@ -14,5 +14,7 @@
package de.bixilon.minosoft.render.blockModels.Face;
public enum Axis {
X, Y, Z
X,
Y,
Z
}

View File

@ -14,18 +14,20 @@
package de.bixilon.minosoft.render.blockModels.Face;
public class RenderConstants {
public static final int TEXTURE_PACK_RES = 16;
public static final int TEXTURE_PACK_RESOLUTION = 16;
public static final int BLOCK_RESOLUTION = 16;
public static final int texturePackRes = 16;
public static final byte SECTION_HEIGHT = 16;
public static final byte SECTION_WIDTH = 16;
public static final byte SECTIONS_PER_CHUNK = 16;
public static final int BLOCK_RES = 16;
public static final byte SECTIONS_MIN_X = 0;
public static final byte SECTIONS_MIN_Y = 0;
public static final byte SECTIONS_MIN_Z = 0;
public static final byte SECTIONS_MAX_X = SECTION_WIDTH - 1;
public static final byte SECTIONS_MAX_Y = SECTION_HEIGHT - 1;
public static final byte SECTIONS_MAX_Z = SECTION_WIDTH - 1;
public static final int[][] faceDir = new int[][]{
{1, 0, 0},
{-1, 0, 0},
{0, 1, 0},
{0, -1, 0},
{0, 0, 1},
{0, 0, -1}
};
public static final byte CHUNK_MIN_Y = 0;
public static final int CHUNK_MAX_Y = SECTION_HEIGHT * SECTIONS_PER_CHUNK - 1;
}

View File

@ -38,14 +38,12 @@ public class BlockModel implements BlockModelInterface {
blockConfigurationStates = new HashMap<>();
if (block.has("blockModel")) {
blockConfigurationStates.put(new BlockConfigurationTrue(),
BlockModelInterface.load(mod, block.get("blockModel").getAsString()));
blockConfigurationStates.put(new BlockConfigurationTrue(), BlockModelInterface.load(mod, block.get("blockModel").getAsString()));
} else if (block.has("states")) {
for (JsonElement element : block.get("states").getAsJsonArray()) {
JsonObject state = element.getAsJsonObject();
BlockConfiguration configuration = new BlockConfiguration(state.get("properties").getAsJsonObject());
blockConfigurationStates.put(configuration,
BlockModelInterface.load(mod, state.get("blockModel").getAsString()));
blockConfigurationStates.put(configuration, BlockModelInterface.load(mod, state.get("blockModel").getAsString()));
}
}
// TODO

View File

@ -35,9 +35,7 @@ public class CropModel implements BlockModelInterface {
int stages = block.get("stages").getAsInt();
modelMap = new HashMap<>();
for (int i = 0; i < stages; i++) {
modelMap.put(String.format("%s%d", "AGE_", i),
BlockModelInterface.load(mod,
String.format("%s%d", block.get("base_name").getAsString(), i)));
modelMap.put(String.format("%s%d", "AGE_", i), BlockModelInterface.load(mod, String.format("%s%d", block.get("base_name").getAsString(), i)));
}
}
@ -48,6 +46,7 @@ public class CropModel implements BlockModelInterface {
}
}
throw new RuntimeException("failed to prepare block: " + block.toString());
throw new RuntimeException("Failed to prepare block: " + block.toString());
}
public boolean isFull() {

View File

@ -3,11 +3,11 @@
* Copyright (C) 2020 Lukas Eisenhauer
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/

View File

@ -19,26 +19,21 @@ import de.bixilon.minosoft.game.datatypes.world.BlockPosition;
import de.bixilon.minosoft.render.blockModels.Face.Axis;
import org.apache.commons.collections.primitives.ArrayFloatList;
import static de.bixilon.minosoft.render.blockModels.Face.RenderConstants.BLOCK_RES;
import static org.lwjgl.opengl.GL11.glVertex3f;
import static de.bixilon.minosoft.render.blockModels.Face.RenderConstants.BLOCK_RESOLUTION;
public class SubBlockPosition {
public float x;
public float y;
public float z;
private static final SubBlockPosition middlePos = new SubBlockPosition(8, 8, 8);
private static final SubBlockRotation westRotator = new SubBlockRotation(middlePos, Axis.Y, 90);
private static final SubBlockRotation eastRotator = new SubBlockRotation(middlePos, Axis.Y, 270);
private static final SubBlockRotation southRotator = new SubBlockRotation(middlePos, Axis.Y, 180);
private static final SubBlockRotation xAxisRotator = new SubBlockRotation(middlePos, Axis.Z, 90);
private static final SubBlockRotation zAxisRotator = new SubBlockRotation(middlePos, Axis.X, 90);
private static final SubBlockRotation downRotator = new SubBlockRotation(middlePos, Axis.X, 90);
private static final SubBlockRotation downAltRotator = new SubBlockRotation(middlePos, Axis.X, 180);
private static final SubBlockRotation upRotator = new SubBlockRotation(middlePos, Axis.X, -90);
public float x;
public float y;
public float z;
public SubBlockPosition(JsonArray json) {
@ -54,24 +49,11 @@ public class SubBlockPosition {
}
public static SubBlockPosition add(SubBlockPosition pos1, SubBlockPosition pos2) {
return new SubBlockPosition(
pos1.x + pos2.x,
pos1.y + pos2.y,
pos1.z + pos2.z);
return new SubBlockPosition(pos1.x + pos2.x, pos1.y + pos2.y, pos1.z + pos2.z);
}
public static SubBlockPosition subtract(SubBlockPosition pos1, SubBlockPosition pos2) {
return new SubBlockPosition(
pos1.x - pos2.x,
pos1.y - pos2.y,
pos1.z - pos2.z);
}
public void draw(BlockPosition pos) {
glVertex3f(
pos.getX() + x / BLOCK_RES,
pos.getY() + y / BLOCK_RES,
pos.getZ() + z / BLOCK_RES);
return new SubBlockPosition(pos1.x - pos2.x, pos1.y - pos2.y, pos1.z - pos2.z);
}
public SubBlockPosition rotated(Block block) {
@ -105,9 +87,9 @@ public class SubBlockPosition {
public ArrayFloatList getFloats(BlockPosition position) {
ArrayFloatList result = new ArrayFloatList();
result.add(x / BLOCK_RES + position.getX());
result.add(y / BLOCK_RES + position.getY());
result.add(z / BLOCK_RES + position.getZ());
result.add(x / BLOCK_RESOLUTION + position.getX());
result.add(y / BLOCK_RESOLUTION + position.getY());
result.add(z / BLOCK_RESOLUTION + position.getZ());
return result;
}
}

View File

@ -17,13 +17,11 @@ import com.google.gson.JsonObject;
import de.bixilon.minosoft.render.blockModels.Face.Axis;
import javafx.util.Pair;
import static java.lang.StrictMath.cos;
import static java.lang.StrictMath.sin;
public class SubBlockRotation {
private final SubBlockPosition origin;
private Axis direction;
private final float angle;
private Axis direction;
public SubBlockRotation(SubBlockPosition origin, Axis direction, float angle) {
this.origin = origin;
@ -44,13 +42,9 @@ public class SubBlockRotation {
public static Pair<Float, Float> rotate(float x, float y, float angle) {
float angleRad = (float) Math.toRadians(angle);
float newX = x * (float) cos(angleRad) + y * (float) sin(angleRad);
float newY = -x * (float) sin(angleRad) + y * (float) cos(angleRad);
return new Pair<>(
newX,
newY
);
float newX = x * (float) StrictMath.cos(angleRad) + y * (float) StrictMath.sin(angleRad);
float newY = -x * (float) StrictMath.sin(angleRad) + y * (float) StrictMath.cos(angleRad);
return new Pair<>(newX, newY);
}
public SubBlockPosition apply(SubBlockPosition position) {

View File

@ -16,8 +16,6 @@ package de.bixilon.minosoft.render.movement;
import de.bixilon.minosoft.render.GameWindow;
import de.bixilon.minosoft.render.utility.Vec3;
import static de.bixilon.minosoft.render.utility.Vec3.normalize;
import static java.lang.StrictMath.*;
import static org.lwjgl.opengl.GL11.glRotatef;
public class CameraMovement {
@ -61,10 +59,10 @@ public class CameraMovement {
}
Vec3 front = new Vec3();
front.x = (float) -(sin(toRadians(yaw)) * cos(toRadians(pitch)));
front.x = (float) -(StrictMath.sin(StrictMath.toRadians(yaw)) * StrictMath.cos(StrictMath.toRadians(pitch)));
front.y = 0;
front.z = (float) ((cos(toRadians(yaw))) * cos(toRadians(pitch)));
cameraFront = normalize(front);
front.z = (float) ((StrictMath.cos(StrictMath.toRadians(yaw))) * StrictMath.cos(StrictMath.toRadians(pitch)));
cameraFront = Vec3.normalize(front);
}
public void loop() {

View File

@ -17,11 +17,9 @@ import de.bixilon.minosoft.game.datatypes.world.BlockPosition;
import de.bixilon.minosoft.game.datatypes.world.World;
import de.bixilon.minosoft.render.GameWindow;
import de.bixilon.minosoft.render.blockModels.BlockModelLoader;
import de.bixilon.minosoft.render.utility.AdditionalMath;
import de.bixilon.minosoft.render.utility.Vec3;
import static de.bixilon.minosoft.render.utility.AdditionalMath.betterRound;
import static de.bixilon.minosoft.render.utility.AdditionalMath.valuesBetween;
public class CollisionHandler {
private final World world;
private final PlayerController controller;
@ -93,14 +91,11 @@ public class CollisionHandler {
private boolean isPositionValid(Vec3 testPos) {
float width = controller.getPlayerWidth();
int[] xPositions = valuesBetween(betterRound(testPos.x + width),
betterRound(testPos.x - width));
int[] xPositions = AdditionalMath.valuesBetween(AdditionalMath.betterRound(testPos.x + width), AdditionalMath.betterRound(testPos.x - width));
int[] yPositions = valuesBetween(betterRound(testPos.y),
betterRound(testPos.y + controller.getPlayerHeight()));
int[] yPositions = AdditionalMath.valuesBetween(AdditionalMath.betterRound(testPos.y), AdditionalMath.betterRound(testPos.y + controller.getPlayerHeight()));
int[] zPositions = valuesBetween(betterRound(testPos.z + width),
betterRound(testPos.z - width));
int[] zPositions = AdditionalMath.valuesBetween(AdditionalMath.betterRound(testPos.z + width), AdditionalMath.betterRound(testPos.z - width));
for (int xPos : xPositions) {
for (int yPos : yPositions) {

View File

@ -18,14 +18,13 @@ import de.bixilon.minosoft.game.datatypes.world.World;
import de.bixilon.minosoft.render.GameWindow;
import de.bixilon.minosoft.render.utility.Vec3;
import static de.bixilon.minosoft.render.utility.Vec3.mul;
import static org.lwjgl.opengl.GL11.glTranslatef;
public class PlayerController {
private static final float playerHeight = 1.8f;
private static final float playerWidth = 0.25f;
private static final float gravity = 13;
public Vec3 oldPos;
CameraMovement cameraMovement;
PlayerMovement playerMovement;
Vec3 playerPos = new Vec3(); // the feet position of the player
@ -33,7 +32,6 @@ public class PlayerController {
private boolean onGround;
private boolean enableGravity;
private CollisionHandler collisionHandler;
public Vec3 oldPos;
public PlayerController(long window) {
cameraMovement = new CameraMovement();
@ -78,7 +76,7 @@ public class PlayerController {
collisionHandler.handleCollisions();
}
public boolean isEnableGravity() {
public boolean isGravityEnabled() {
return enableGravity;
}
@ -91,7 +89,7 @@ public class PlayerController {
}
private void applyVelocity(float deltaTime) {
playerPos.add(mul(playerVelocity, deltaTime));
playerPos.add(Vec3.mul(playerVelocity, deltaTime));
}
private void handleGravity(float deltaTime) {
@ -110,6 +108,10 @@ public class PlayerController {
return onGround;
}
public void setOnGround(boolean onGround) {
this.onGround = onGround;
}
public void jump() {
playerVelocity.y = 10;
onGround = false;
@ -122,8 +124,4 @@ public class PlayerController {
public float getPlayerHeight() {
return playerHeight;
}
public void setOnGround(boolean onGround) {
this.onGround = onGround;
}
}

View File

@ -16,8 +16,6 @@ package de.bixilon.minosoft.render.movement;
import de.bixilon.minosoft.render.GameWindow;
import de.bixilon.minosoft.render.utility.Vec3;
import static de.bixilon.minosoft.render.utility.Vec3.cross;
import static de.bixilon.minosoft.render.utility.Vec3.mul;
import static org.lwjgl.glfw.GLFW.*;
public class PlayerMovement {
@ -36,25 +34,25 @@ public class PlayerMovement {
float cameraSpeed = FLY_SPEED / deltaTime;
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) {
playerPos.add(mul(cameraFront, -cameraSpeed * deltaTime));
playerPos.add(Vec3.mul(cameraFront, -cameraSpeed * deltaTime));
}
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) {
playerPos.add(mul(cameraFront, cameraSpeed * deltaTime));
playerPos.add(Vec3.mul(cameraFront, cameraSpeed * deltaTime));
}
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) {
playerPos.add(mul(cross(CAMERA_UP, cameraFront), -cameraSpeed * deltaTime));
playerPos.add(Vec3.mul(Vec3.cross(CAMERA_UP, cameraFront), -cameraSpeed * deltaTime));
}
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) {
playerPos.add(mul(cross(CAMERA_UP, cameraFront), cameraSpeed * deltaTime));
playerPos.add(Vec3.mul(Vec3.cross(CAMERA_UP, cameraFront), cameraSpeed * deltaTime));
}
if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) {
if (!GameWindow.getPlayerController().isEnableGravity()) {
if (!GameWindow.getPlayerController().isGravityEnabled()) {
playerPos.add(0, -cameraSpeed * deltaTime, 0);
}
}
if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) {
if (!GameWindow.getPlayerController().isEnableGravity()) {
if (!GameWindow.getPlayerController().isGravityEnabled()) {
playerPos.add(0, cameraSpeed * deltaTime, 0);
}
if (GameWindow.getPlayerController().isOnGround()) {

View File

@ -16,8 +16,7 @@ package de.bixilon.minosoft.render.texture;
import com.google.gson.JsonArray;
import de.bixilon.minosoft.render.GameWindow;
import org.apache.commons.collections.primitives.ArrayFloatList;
import static de.bixilon.minosoft.render.blockModels.Face.RenderConstants.texturePackRes;
import de.bixilon.minosoft.render.blockModels.Face.RenderConstants;
public class InFaceUV {
public final int u1, v1, u2, v2;
@ -37,12 +36,10 @@ public class InFaceUV {
}
public void prepare(float texture) {
realU1 = texture + u1 * GameWindow.getRenderer().getAssetsLoader().getTextureLoader().getStep()
/ texturePackRes;
realU2 = texture + u2 * GameWindow.getRenderer().getAssetsLoader().getTextureLoader().getStep()
/ texturePackRes;
realV1 = (float) v1 / texturePackRes;
realV2 = (float) v2 / texturePackRes;
realU1 = texture + u1 * GameWindow.getRenderer().getAssetsLoader().getTextureLoader().getStep() / RenderConstants.TEXTURE_PACK_RESOLUTION;
realU2 = texture + u2 * GameWindow.getRenderer().getAssetsLoader().getTextureLoader().getStep() / RenderConstants.TEXTURE_PACK_RESOLUTION;
realV1 = (float) v1 / RenderConstants.TEXTURE_PACK_RESOLUTION;
realV2 = (float) v2 / RenderConstants.TEXTURE_PACK_RESOLUTION;
}
public ArrayFloatList getFloats(int i) {

View File

@ -14,6 +14,7 @@
package de.bixilon.minosoft.render.texture;
import de.bixilon.minosoft.Config;
import de.bixilon.minosoft.render.blockModels.Face.RenderConstants;
import de.matthiasmann.twl.utils.PNGDecoder;
import javax.imageio.ImageIO;
@ -27,16 +28,15 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import static de.bixilon.minosoft.render.blockModels.Face.RenderConstants.TEXTURE_PACK_RES;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL30.glGenerateMipmap;
public class TextureLoader {
private final HashMap<String, HashMap<String, Integer>> textureCoordinates;
private final HashMap<String, HashMap<String, BufferedImage>> images;
private int textureID;
private float step;
private int totalTextures = 0;
private HashMap<String, HashMap<String, BufferedImage>> images;
public TextureLoader(HashMap<String, HashSet<String>> textures, HashMap<String, HashMap<String, float[]>> tints) {
textureCoordinates = new HashMap<>();
@ -46,8 +46,7 @@ public class TextureLoader {
}
combineTextures();
try {
PNGDecoder decoder = new PNGDecoder(new FileInputStream(
Config.homeDir + "assets/allTextures.png"));
PNGDecoder decoder = new PNGDecoder(new FileInputStream(Config.homeDir + "assets/allTextures.png"));
ByteBuffer buf = ByteBuffer.allocateDirect(decoder.getWidth() * decoder.getHeight() * 4);
decoder.decode(buf, decoder.getWidth() * 4, PNGDecoder.Format.RGBA);
textureID = bindTexture(buf, decoder.getWidth(), decoder.getHeight());
@ -99,20 +98,19 @@ public class TextureLoader {
// greatly improves performance in opengl
// TEXTURE_PACK_RESxTEXTURE_PACK_RES textures only
int imageLength = 1;
while (totalTextures * TEXTURE_PACK_RES > imageLength) {
while (totalTextures * RenderConstants.TEXTURE_PACK_RESOLUTION > imageLength) {
imageLength *= 2; //figure out the right length for the image
}
BufferedImage totalImage = new BufferedImage(imageLength, TEXTURE_PACK_RES,
BufferedImage.TYPE_4BYTE_ABGR);
BufferedImage totalImage = new BufferedImage(imageLength, RenderConstants.TEXTURE_PACK_RESOLUTION, BufferedImage.TYPE_4BYTE_ABGR);
int currentPos = 0;
for (Map.Entry<String, HashMap<String, BufferedImage>> mod : images.entrySet()) {
HashMap<String, Integer> modMap = new HashMap<>();
for (Map.Entry<String, BufferedImage> texture : mod.getValue().entrySet()) {
for (int y = 0; y < TEXTURE_PACK_RES; y++) {
for (int xPixel = 0; xPixel < TEXTURE_PACK_RES; xPixel++) {
for (int y = 0; y < RenderConstants.TEXTURE_PACK_RESOLUTION; y++) {
for (int xPixel = 0; xPixel < RenderConstants.TEXTURE_PACK_RESOLUTION; xPixel++) {
int rgb = texture.getValue().getRGB(xPixel, y);
totalImage.setRGB(currentPos * TEXTURE_PACK_RES + xPixel, y, rgb);
totalImage.setRGB(currentPos * RenderConstants.TEXTURE_PACK_RESOLUTION + xPixel, y, rgb);
}
}
modMap.put(texture.getKey(), currentPos++);
@ -126,7 +124,7 @@ public class TextureLoader {
} catch (IOException e) {
e.printStackTrace();
}
step = (float) 1 / (float) imageLength * TEXTURE_PACK_RES;
step = (float) 1 / (float) imageLength * RenderConstants.TEXTURE_PACK_RESOLUTION;
}
private int bindTexture(ByteBuffer buf, int width, int height) {
@ -134,8 +132,7 @@ public class TextureLoader {
int textureID = glGenTextures();
glBindTexture(GL_TEXTURE_2D, textureID);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width,
height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf);
glGenerateMipmap(GL_TEXTURE_2D);
//disable smoothing out of textures
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

View File

@ -13,11 +13,10 @@
package de.bixilon.minosoft.render.utility;
import static java.lang.Math.abs;
public class AdditionalMath {
public static int[] valuesBetween(int x, int y) {
int[] result = new int[abs(x - y) + 1];
int[] result = new int[Math.abs(x - y) + 1];
if (x > y) {
for (int z = y; z <= x; z++) {
result[x - z] = z;

View File

@ -15,8 +15,6 @@ package de.bixilon.minosoft.render.utility;
import de.bixilon.minosoft.game.datatypes.entities.Location;
import static java.lang.Math.pow;
import static java.lang.Math.sqrt;
public class Vec3 {
public float x, y, z;
@ -38,44 +36,27 @@ public class Vec3 {
}
public static Vec3 add(Vec3 v1, Vec3 v2) {
return new Vec3(
v1.x + v2.x,
v1.y + v2.y,
v1.z + v2.z
);
return new Vec3(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
}
public static Vec3 mul(Vec3 v, float n) {
return new Vec3(
v.x * n,
v.y * n,
v.z * n
);
return new Vec3(v.x * n, v.y * n, v.z * n);
}
public static Vec3 mul(Vec3 v1, Vec3 v2) {
return new Vec3(
v1.x * v2.x,
v1.y * v2.y,
v1.z * v2.z
);
return new Vec3(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z);
}
public static Vec3 normalize(Vec3 v) {
float l = v.len();
Vec3 out = v;
out.x /= l;
out.y /= l;
out.z /= l;
return out;
v.x /= l;
v.y /= l;
v.z /= l;
return v;
}
public static Vec3 cross(Vec3 v1, Vec3 v2) {
return new Vec3(
v1.y * v2.z - v1.z * v2.y,
v1.z * v2.x - v1.x * v2.z,
v1.x * v2.y - v1.y * v2.x
);
return new Vec3(v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z, v1.x * v2.y - v1.y * v2.x);
}
public void add(Vec3 v) {
@ -92,7 +73,7 @@ public class Vec3 {
}
public float len() {
return (float) sqrt(pow(x, 2) + pow(y, 2) + pow(z, 2));
return (float) Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2));
}
public void normalize() {

View File

@ -22,8 +22,9 @@ import de.bixilon.minosoft.game.datatypes.world.palette.Palette;
import de.bixilon.minosoft.logging.Log;
import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition;
import de.bixilon.minosoft.render.blockModels.Face.RenderConstants;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
public final class ChunkUtil {
public static Chunk readChunkPacket(InByteBuffer buffer, short sectionBitMask, short addBitMask, boolean groundUpContinuous, boolean containsSkyLight) {
@ -34,7 +35,7 @@ public final class ChunkUtil {
}
//chunk
byte sections = BitByte.getBitCount(sectionBitMask);
int totalBytes = 4096 * sections; // 16 * 16 * 16 * sections; Section Width * Section Height * Section Width * sections
int totalBytes = RenderConstants.SECTION_HEIGHT * RenderConstants.SECTION_WIDTH * RenderConstants.SECTION_WIDTH * sections;
int halfBytes = totalBytes / 2; // half bytes
byte[] blockTypes = buffer.readBytes(totalBytes);
@ -44,22 +45,22 @@ public final class ChunkUtil {
if (containsSkyLight) {
skyLight = buffer.readBytes(halfBytes);
}
byte[] addBlockTypes = buffer.readBytes(Integer.bitCount(addBitMask) * 2048); // 16 * 16 * 16 * addBlocks / 2
byte[] addBlockTypes = buffer.readBytes(Integer.bitCount(addBitMask) * RenderConstants.SECTION_HEIGHT * RenderConstants.SECTION_WIDTH * RenderConstants.SECTION_WIDTH / 2);
if (groundUpContinuous) {
byte[] biomes = buffer.readBytes(256);
byte[] biomes = buffer.readBytes(RenderConstants.SECTION_WIDTH * RenderConstants.SECTION_WIDTH);
}
//parse data
int arrayPos = 0;
HashMap<Byte, ChunkNibble> nibbleMap = new HashMap<>();
for (byte c = 0; c < 16; c++) { // max sections per chunks in chunk column
ConcurrentHashMap<Byte, ChunkNibble> nibbleMap = new ConcurrentHashMap<>();
for (byte c = 0; c < RenderConstants.SECTIONS_PER_CHUNK; c++) { // max sections per chunks in chunk column
if (BitByte.isBitSet(sectionBitMask, c)) {
HashMap<ChunkNibbleLocation, Block> blockMap = new HashMap<>();
ConcurrentHashMap<ChunkNibbleLocation, Block> blockMap = new ConcurrentHashMap<>();
for (int nibbleY = 0; nibbleY < 16; nibbleY++) {
for (int nibbleZ = 0; nibbleZ < 16; nibbleZ++) {
for (int nibbleX = 0; nibbleX < 16; nibbleX++) {
for (int nibbleY = 0; nibbleY < RenderConstants.SECTION_HEIGHT; nibbleY++) {
for (int nibbleZ = 0; nibbleZ < RenderConstants.SECTION_WIDTH; nibbleZ++) {
for (int nibbleX = 0; nibbleX < RenderConstants.SECTION_WIDTH; nibbleX++) {
short singeBlockId = (short) (blockTypes[arrayPos] & 0xFF);
byte singleMeta;
@ -99,7 +100,7 @@ public final class ChunkUtil {
return null;
}
byte sections = BitByte.getBitCount(sectionBitMask);
int totalBlocks = 4096 * sections; // 16 * 16 * 16 * sections; Section Width * Section Height * Section Width * sections
int totalBlocks = RenderConstants.SECTION_HEIGHT * RenderConstants.SECTION_WIDTH * RenderConstants.SECTION_WIDTH * sections;
int halfBytes = totalBlocks / 2; // half bytes
short[] blockData = buffer.readLEShorts(totalBlocks); // blocks >>> 4, data & 0xF
@ -111,20 +112,20 @@ public final class ChunkUtil {
}
if (groundUpContinuous) {
byte[] biomes = buffer.readBytes(256);
byte[] biomes = buffer.readBytes(RenderConstants.SECTION_WIDTH * RenderConstants.SECTION_WIDTH);
}
int arrayPos = 0;
HashMap<Byte, ChunkNibble> nibbleMap = new HashMap<>();
for (byte c = 0; c < 16; c++) { // max sections per chunks in chunk column
ConcurrentHashMap<Byte, ChunkNibble> nibbleMap = new ConcurrentHashMap<>();
for (byte c = 0; c < RenderConstants.SECTIONS_PER_CHUNK; c++) { // max sections per chunks in chunk column
if (!BitByte.isBitSet(sectionBitMask, c)) {
continue;
}
HashMap<ChunkNibbleLocation, Block> blockMap = new HashMap<>();
ConcurrentHashMap<ChunkNibbleLocation, Block> blockMap = new ConcurrentHashMap<>();
for (int nibbleY = 0; nibbleY < 16; nibbleY++) {
for (int nibbleZ = 0; nibbleZ < 16; nibbleZ++) {
for (int nibbleX = 0; nibbleX < 16; nibbleX++) {
for (int nibbleY = 0; nibbleY < RenderConstants.SECTION_HEIGHT; nibbleY++) {
for (int nibbleZ = 0; nibbleZ < RenderConstants.SECTION_WIDTH; nibbleZ++) {
for (int nibbleX = 0; nibbleX < RenderConstants.SECTION_WIDTH; nibbleX++) {
int blockId = blockData[arrayPos] & 0xFFFF;
Block block = buffer.getConnection().getMapping().getBlockById(blockId);
if (block.equals(Blocks.nullBlock)) {
@ -141,8 +142,8 @@ public final class ChunkUtil {
return new Chunk(nibbleMap);
}
// really big thanks to: https://wiki.vg/index.php?title=Chunk_Format&oldid=13712
HashMap<Byte, ChunkNibble> nibbleMap = new HashMap<>();
for (byte c = 0; c < 16; c++) { // max sections per chunks in chunk column
ConcurrentHashMap<Byte, ChunkNibble> nibbleMap = new ConcurrentHashMap<>();
for (byte c = 0; c < RenderConstants.SECTIONS_PER_CHUNK; c++) { // max sections per chunks in chunk column
if (!BitByte.isBitSet(sectionBitMask, c)) {
continue;
}
@ -155,10 +156,10 @@ public final class ChunkUtil {
long[] data = buffer.readLongArray(buffer.readVarInt());
HashMap<ChunkNibbleLocation, Block> blockMap = new HashMap<>();
for (int nibbleY = 0; nibbleY < 16; nibbleY++) {
for (int nibbleZ = 0; nibbleZ < 16; nibbleZ++) {
for (int nibbleX = 0; nibbleX < 16; nibbleX++) {
ConcurrentHashMap<ChunkNibbleLocation, Block> blockMap = new ConcurrentHashMap<>();
for (int nibbleY = 0; nibbleY < RenderConstants.SECTION_HEIGHT; nibbleY++) {
for (int nibbleZ = 0; nibbleZ < RenderConstants.SECTION_WIDTH; nibbleZ++) {
for (int nibbleX = 0; nibbleX < RenderConstants.SECTION_WIDTH; nibbleX++) {
int blockNumber = (((nibbleY * 16) + nibbleZ) * 16) + nibbleX;
int startLong = (blockNumber * palette.getBitsPerBlock()) / 64;
@ -203,7 +204,7 @@ public final class ChunkUtil {
nibbleMap.put(c, new ChunkNibble(blockMap));
}
if (buffer.getProtocolId() < 552) {
byte[] biomes = buffer.readBytes(256);
byte[] biomes = buffer.readBytes(RenderConstants.SECTION_WIDTH * RenderConstants.SECTION_WIDTH);
}
return new Chunk(nibbleMap);
}

View File

@ -14,7 +14,6 @@
package de.bixilon.minosoft.util.mojang.api;
import com.google.gson.JsonObject;
import de.bixilon.minosoft.Config;
import de.bixilon.minosoft.Minosoft;
import de.bixilon.minosoft.util.Util;
@ -92,7 +91,7 @@ public class MojangAccount {
public void saveToConfig() {
Minosoft.getConfig().putMojangAccount(this);
Minosoft.getConfig().saveToFile(Config.configFileName);
Minosoft.getConfig().saveToFile();
}
@Override
@ -103,7 +102,7 @@ public class MojangAccount {
public void delete() {
Minosoft.getAccountList().remove(this.getUserId());
Minosoft.getConfig().removeAccount(this);
Minosoft.getConfig().saveToFile(Config.configFileName);
Minosoft.getConfig().saveToFile();
}
@Override