diff --git a/src/main/java/de/bixilon/minosoft/Minosoft.java b/src/main/java/de/bixilon/minosoft/Minosoft.java index 36586ba46..74ab5c2c4 100644 --- a/src/main/java/de/bixilon/minosoft/Minosoft.java +++ b/src/main/java/de/bixilon/minosoft/Minosoft.java @@ -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(); diff --git a/src/main/java/de/bixilon/minosoft/config/Configuration.java b/src/main/java/de/bixilon/minosoft/config/Configuration.java index b2cfaef7d..dd1213631 100644 --- a/src/main/java/de/bixilon/minosoft/config/Configuration.java +++ b/src/main/java/de/bixilon/minosoft/config/Configuration.java @@ -30,6 +30,7 @@ import java.util.UUID; public class Configuration { final LinkedHashMap 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 getMojangAccounts() { diff --git a/src/main/java/de/bixilon/minosoft/game/datatypes/Player.java b/src/main/java/de/bixilon/minosoft/game/datatypes/Player.java index b3f3c5bd3..c57658949 100644 --- a/src/main/java/de/bixilon/minosoft/game/datatypes/Player.java +++ b/src/main/java/de/bixilon/minosoft/game/datatypes/Player.java @@ -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) { diff --git a/src/main/java/de/bixilon/minosoft/game/datatypes/objectLoader/blocks/Block.java b/src/main/java/de/bixilon/minosoft/game/datatypes/objectLoader/blocks/Block.java index 42418c8a5..a22b95cdf 100644 --- a/src/main/java/de/bixilon/minosoft/game/datatypes/objectLoader/blocks/Block.java +++ b/src/main/java/de/bixilon/minosoft/game/datatypes/objectLoader/blocks/Block.java @@ -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; diff --git a/src/main/java/de/bixilon/minosoft/game/datatypes/world/BlockPosition.java b/src/main/java/de/bixilon/minosoft/game/datatypes/world/BlockPosition.java index 52d1d82f9..271571c71 100644 --- a/src/main/java/de/bixilon/minosoft/game/datatypes/world/BlockPosition.java +++ b/src/main/java/de/bixilon/minosoft/game/datatypes/world/BlockPosition.java @@ -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); } diff --git a/src/main/java/de/bixilon/minosoft/game/datatypes/world/Chunk.java b/src/main/java/de/bixilon/minosoft/game/datatypes/world/Chunk.java index b5e636736..ec94869e0 100644 --- a/src/main/java/de/bixilon/minosoft/game/datatypes/world/Chunk.java +++ b/src/main/java/de/bixilon/minosoft/game/datatypes/world/Chunk.java @@ -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 nibbles; + final ConcurrentHashMap nibbles; - public Chunk(HashMap chunks) { + public Chunk(ConcurrentHashMap 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 getNibbles() { + public ConcurrentHashMap getNibbles() { return nibbles; } } diff --git a/src/main/java/de/bixilon/minosoft/game/datatypes/world/ChunkNibble.java b/src/main/java/de/bixilon/minosoft/game/datatypes/world/ChunkNibble.java index 2445e1a28..01f633b34 100644 --- a/src/main/java/de/bixilon/minosoft/game/datatypes/world/ChunkNibble.java +++ b/src/main/java/de/bixilon/minosoft/game/datatypes/world/ChunkNibble.java @@ -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 blocks; + final ConcurrentHashMap blocks; - public ChunkNibble(HashMap blocks) { + public ChunkNibble(ConcurrentHashMap 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 getBlocks() { + public ConcurrentHashMap getBlocks() { return blocks; } } diff --git a/src/main/java/de/bixilon/minosoft/game/datatypes/world/InChunkLocation.java b/src/main/java/de/bixilon/minosoft/game/datatypes/world/InChunkLocation.java index 06c9c3bb4..8ec71d63d 100644 --- a/src/main/java/de/bixilon/minosoft/game/datatypes/world/InChunkLocation.java +++ b/src/main/java/de/bixilon/minosoft/game/datatypes/world/InChunkLocation.java @@ -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 diff --git a/src/main/java/de/bixilon/minosoft/game/datatypes/world/World.java b/src/main/java/de/bixilon/minosoft/game/datatypes/world/World.java index a5acd585d..c21864766 100644 --- a/src/main/java/de/bixilon/minosoft/game/datatypes/world/World.java +++ b/src/main/java/de/bixilon/minosoft/game/datatypes/world/World.java @@ -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 chunks = new HashMap<>(); - final HashMap entities = new HashMap<>(); + final ConcurrentHashMap chunks = new ConcurrentHashMap<>(); + final ConcurrentHashMap entities = new ConcurrentHashMap<>(); final String name; - final HashMap blockEntityMeta = new HashMap<>(); + final ConcurrentHashMap 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 getAllChunks() { + public ConcurrentHashMap 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 chunkMap) { - for (Map.Entry 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 blockEntities) { + public void setBlockEntityData(ConcurrentHashMap blockEntities) { for (Map.Entry entrySet : blockEntities.entrySet()) { blockEntityMeta.put(entrySet.getKey(), entrySet.getValue()); } diff --git a/src/main/java/de/bixilon/minosoft/gui/main/Server.java b/src/main/java/de/bixilon/minosoft/gui/main/Server.java index 0cc1f91cf..abdb12646 100644 --- a/src/main/java/de/bixilon/minosoft/gui/main/Server.java +++ b/src/main/java/de/bixilon/minosoft/gui/main/Server.java @@ -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() { diff --git a/src/main/java/de/bixilon/minosoft/gui/main/SettingsWindow.java b/src/main/java/de/bixilon/minosoft/gui/main/SettingsWindow.java index bd382f45f..65a29ca27 100644 --- a/src/main/java/de/bixilon/minosoft/gui/main/SettingsWindow.java +++ b/src/main/java/de/bixilon/minosoft/gui/main/SettingsWindow.java @@ -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(); })); } } diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChunkData.java b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChunkData.java index da59b57e0..ed2b09332 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChunkData.java +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChunkData.java @@ -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 blockEntities = new HashMap<>(); + final ConcurrentHashMap blockEntities = new ConcurrentHashMap<>(); ChunkLocation location; Chunk chunk; CompoundTag heightMap; @@ -122,7 +122,7 @@ public class PacketChunkData implements ClientboundPacket { return chunk; } - public HashMap getBlockEntities() { + public ConcurrentHashMap getBlockEntities() { return blockEntities; } diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketMultiBlockChange.java b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketMultiBlockChange.java index d46cd8750..54f9cbe68 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketMultiBlockChange.java +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketMultiBlockChange.java @@ -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; } diff --git a/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketHandler.java b/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketHandler.java index e003f3c01..68e6809d7 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketHandler.java +++ b/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketHandler.java @@ -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) { diff --git a/src/main/java/de/bixilon/minosoft/render/GameWindow.java b/src/main/java/de/bixilon/minosoft/render/GameWindow.java index 0e118cfdb..93c41253d 100644 --- a/src/main/java/de/bixilon/minosoft/render/GameWindow.java +++ b/src/main/java/de/bixilon/minosoft/render/GameWindow.java @@ -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); } } diff --git a/src/main/java/de/bixilon/minosoft/render/OpenGLWindow.java b/src/main/java/de/bixilon/minosoft/render/OpenGLWindow.java index 027a0ad92..30fc446d0 100644 --- a/src/main/java/de/bixilon/minosoft/render/OpenGLWindow.java +++ b/src/main/java/de/bixilon/minosoft/render/OpenGLWindow.java @@ -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; } diff --git a/src/main/java/de/bixilon/minosoft/render/WorldRenderer.java b/src/main/java/de/bixilon/minosoft/render/WorldRenderer.java index df03fe8e0..198af9b72 100644 --- a/src/main/java/de/bixilon/minosoft/render/WorldRenderer.java +++ b/src/main/java/de/bixilon/minosoft/render/WorldRenderer.java @@ -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> faces; private AssetsLoader assetsLoader; - private LinkedBlockingQueue> queuedChunks; + private LinkedBlockingQueue 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 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 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 getFacesForChunkNibble(ChunkLocation chunkLocation, byte sectionHeight, ChunkNibble nibble) { + HashMap world = GameWindow.getConnection().getPlayer().getWorld().getAllChunks(); // clear or create current chunk nibble - ArrayFloatList nibbleMap = new ArrayFloatList(); - faces.get(chunkLocation).put(height, nibbleMap); + ConcurrentHashMap nibbleMap = new ConcurrentHashMap<>(); + faces.get(chunkLocation).put(sectionHeight, nibbleMap); HashMap nibbleBlocks = nibble.getBlocks(); nibbleBlocks.forEach((location, block) -> { HashSet 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 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 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 world, ChunkLocation location, byte sectionHeight) { + if (world.containsKey(location) && world.get(location).getNibbles().containsKey(sectionHeight)) { + return world.get(location).getNibbles().get(sectionHeight); + } + return null; + } + } diff --git a/src/main/java/de/bixilon/minosoft/render/blockModels/BlockConfiguration.java b/src/main/java/de/bixilon/minosoft/render/blockModels/BlockConfiguration.java index 2aeb386ea..b87200eb5 100644 --- a/src/main/java/de/bixilon/minosoft/render/blockModels/BlockConfiguration.java +++ b/src/main/java/de/bixilon/minosoft/render/blockModels/BlockConfiguration.java @@ -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) { diff --git a/src/main/java/de/bixilon/minosoft/render/blockModels/BlockConfigurationTrue.java b/src/main/java/de/bixilon/minosoft/render/blockModels/BlockConfigurationTrue.java index 0acf8e3c3..fe8933df0 100644 --- a/src/main/java/de/bixilon/minosoft/render/blockModels/BlockConfigurationTrue.java +++ b/src/main/java/de/bixilon/minosoft/render/blockModels/BlockConfigurationTrue.java @@ -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; diff --git a/src/main/java/de/bixilon/minosoft/render/blockModels/BlockModelInterface.java b/src/main/java/de/bixilon/minosoft/render/blockModels/BlockModelInterface.java index c011198fb..c2e69191f 100644 --- a/src/main/java/de/bixilon/minosoft/render/blockModels/BlockModelInterface.java +++ b/src/main/java/de/bixilon/minosoft/render/blockModels/BlockModelInterface.java @@ -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 . - * + * * 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 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; } diff --git a/src/main/java/de/bixilon/minosoft/render/blockModels/BlockModelLoader.java b/src/main/java/de/bixilon/minosoft/render/blockModels/BlockModelLoader.java index 996d04bf6..62a31bd3b 100644 --- a/src/main/java/de/bixilon/minosoft/render/blockModels/BlockModelLoader.java +++ b/src/main/java/de/bixilon/minosoft/render/blockModels/BlockModelLoader.java @@ -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> 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 result = new HashSet<>(); try { String type = ""; - if (block.has("type")) { type = block.get("type").getAsString(); } diff --git a/src/main/java/de/bixilon/minosoft/render/blockModels/Face/Axis.java b/src/main/java/de/bixilon/minosoft/render/blockModels/Face/Axis.java index 59265e311..743801507 100644 --- a/src/main/java/de/bixilon/minosoft/render/blockModels/Face/Axis.java +++ b/src/main/java/de/bixilon/minosoft/render/blockModels/Face/Axis.java @@ -14,5 +14,7 @@ package de.bixilon.minosoft.render.blockModels.Face; public enum Axis { - X, Y, Z + X, + Y, + Z } diff --git a/src/main/java/de/bixilon/minosoft/render/blockModels/Face/RenderConstants.java b/src/main/java/de/bixilon/minosoft/render/blockModels/Face/RenderConstants.java index 8921d1b43..516c85604 100644 --- a/src/main/java/de/bixilon/minosoft/render/blockModels/Face/RenderConstants.java +++ b/src/main/java/de/bixilon/minosoft/render/blockModels/Face/RenderConstants.java @@ -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; } diff --git a/src/main/java/de/bixilon/minosoft/render/blockModels/specialModels/BlockModel.java b/src/main/java/de/bixilon/minosoft/render/blockModels/specialModels/BlockModel.java index 8334943af..c8e921606 100644 --- a/src/main/java/de/bixilon/minosoft/render/blockModels/specialModels/BlockModel.java +++ b/src/main/java/de/bixilon/minosoft/render/blockModels/specialModels/BlockModel.java @@ -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 diff --git a/src/main/java/de/bixilon/minosoft/render/blockModels/specialModels/CropModel.java b/src/main/java/de/bixilon/minosoft/render/blockModels/specialModels/CropModel.java index 82707ce99..74f65edf4 100644 --- a/src/main/java/de/bixilon/minosoft/render/blockModels/specialModels/CropModel.java +++ b/src/main/java/de/bixilon/minosoft/render/blockModels/specialModels/CropModel.java @@ -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() { diff --git a/src/main/java/de/bixilon/minosoft/render/blockModels/specialModels/FenceModel.java b/src/main/java/de/bixilon/minosoft/render/blockModels/specialModels/FenceModel.java index 585d66f85..0f545d5a1 100644 --- a/src/main/java/de/bixilon/minosoft/render/blockModels/specialModels/FenceModel.java +++ b/src/main/java/de/bixilon/minosoft/render/blockModels/specialModels/FenceModel.java @@ -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 . - * + * * This software is not affiliated with Mojang AB, the original developer of Minecraft. */ diff --git a/src/main/java/de/bixilon/minosoft/render/blockModels/subBlocks/SubBlockPosition.java b/src/main/java/de/bixilon/minosoft/render/blockModels/subBlocks/SubBlockPosition.java index e197e2b6f..ef894636b 100644 --- a/src/main/java/de/bixilon/minosoft/render/blockModels/subBlocks/SubBlockPosition.java +++ b/src/main/java/de/bixilon/minosoft/render/blockModels/subBlocks/SubBlockPosition.java @@ -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; } } diff --git a/src/main/java/de/bixilon/minosoft/render/blockModels/subBlocks/SubBlockRotation.java b/src/main/java/de/bixilon/minosoft/render/blockModels/subBlocks/SubBlockRotation.java index 1e889fcb3..73f3507cb 100644 --- a/src/main/java/de/bixilon/minosoft/render/blockModels/subBlocks/SubBlockRotation.java +++ b/src/main/java/de/bixilon/minosoft/render/blockModels/subBlocks/SubBlockRotation.java @@ -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 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) { diff --git a/src/main/java/de/bixilon/minosoft/render/movement/CameraMovement.java b/src/main/java/de/bixilon/minosoft/render/movement/CameraMovement.java index d9fd6ebf9..cdb152acf 100644 --- a/src/main/java/de/bixilon/minosoft/render/movement/CameraMovement.java +++ b/src/main/java/de/bixilon/minosoft/render/movement/CameraMovement.java @@ -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() { diff --git a/src/main/java/de/bixilon/minosoft/render/movement/CollisionHandler.java b/src/main/java/de/bixilon/minosoft/render/movement/CollisionHandler.java index ff189e523..cfcacc675 100644 --- a/src/main/java/de/bixilon/minosoft/render/movement/CollisionHandler.java +++ b/src/main/java/de/bixilon/minosoft/render/movement/CollisionHandler.java @@ -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) { diff --git a/src/main/java/de/bixilon/minosoft/render/movement/PlayerController.java b/src/main/java/de/bixilon/minosoft/render/movement/PlayerController.java index c84f2cfc6..0d0bb1023 100644 --- a/src/main/java/de/bixilon/minosoft/render/movement/PlayerController.java +++ b/src/main/java/de/bixilon/minosoft/render/movement/PlayerController.java @@ -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; - } } diff --git a/src/main/java/de/bixilon/minosoft/render/movement/PlayerMovement.java b/src/main/java/de/bixilon/minosoft/render/movement/PlayerMovement.java index b5b4a80bf..fd21bd787 100644 --- a/src/main/java/de/bixilon/minosoft/render/movement/PlayerMovement.java +++ b/src/main/java/de/bixilon/minosoft/render/movement/PlayerMovement.java @@ -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()) { diff --git a/src/main/java/de/bixilon/minosoft/render/texture/InFaceUV.java b/src/main/java/de/bixilon/minosoft/render/texture/InFaceUV.java index 8f01c8fab..9ec95a157 100644 --- a/src/main/java/de/bixilon/minosoft/render/texture/InFaceUV.java +++ b/src/main/java/de/bixilon/minosoft/render/texture/InFaceUV.java @@ -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) { diff --git a/src/main/java/de/bixilon/minosoft/render/texture/TextureLoader.java b/src/main/java/de/bixilon/minosoft/render/texture/TextureLoader.java index 62cfd22b7..55a9b26e1 100644 --- a/src/main/java/de/bixilon/minosoft/render/texture/TextureLoader.java +++ b/src/main/java/de/bixilon/minosoft/render/texture/TextureLoader.java @@ -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> textureCoordinates; + private final HashMap> images; private int textureID; private float step; private int totalTextures = 0; - private HashMap> images; public TextureLoader(HashMap> textures, HashMap> 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> mod : images.entrySet()) { HashMap modMap = new HashMap<>(); for (Map.Entry 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); diff --git a/src/main/java/de/bixilon/minosoft/render/utility/AdditionalMath.java b/src/main/java/de/bixilon/minosoft/render/utility/AdditionalMath.java index 20d6f5b06..221b6696a 100644 --- a/src/main/java/de/bixilon/minosoft/render/utility/AdditionalMath.java +++ b/src/main/java/de/bixilon/minosoft/render/utility/AdditionalMath.java @@ -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; diff --git a/src/main/java/de/bixilon/minosoft/render/utility/Vec3.java b/src/main/java/de/bixilon/minosoft/render/utility/Vec3.java index 1c1fbc9e1..b8ed06b76 100644 --- a/src/main/java/de/bixilon/minosoft/render/utility/Vec3.java +++ b/src/main/java/de/bixilon/minosoft/render/utility/Vec3.java @@ -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() { diff --git a/src/main/java/de/bixilon/minosoft/util/ChunkUtil.java b/src/main/java/de/bixilon/minosoft/util/ChunkUtil.java index a61606332..5079ba473 100644 --- a/src/main/java/de/bixilon/minosoft/util/ChunkUtil.java +++ b/src/main/java/de/bixilon/minosoft/util/ChunkUtil.java @@ -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 nibbleMap = new HashMap<>(); - for (byte c = 0; c < 16; c++) { // max sections per chunks in chunk column + ConcurrentHashMap 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 blockMap = new HashMap<>(); + ConcurrentHashMap 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 nibbleMap = new HashMap<>(); - for (byte c = 0; c < 16; c++) { // max sections per chunks in chunk column + ConcurrentHashMap 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 blockMap = new HashMap<>(); + ConcurrentHashMap 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 nibbleMap = new HashMap<>(); - for (byte c = 0; c < 16; c++) { // max sections per chunks in chunk column + ConcurrentHashMap 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 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 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); } diff --git a/src/main/java/de/bixilon/minosoft/util/mojang/api/MojangAccount.java b/src/main/java/de/bixilon/minosoft/util/mojang/api/MojangAccount.java index def15d439..697b6d059 100644 --- a/src/main/java/de/bixilon/minosoft/util/mojang/api/MojangAccount.java +++ b/src/main/java/de/bixilon/minosoft/util/mojang/api/MojangAccount.java @@ -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