mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-17 11:24:56 -04:00
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:
commit
e21294b363
@ -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();
|
||||
|
@ -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() {
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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();
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
@ -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) {
|
||||
|
@ -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(() -> {
|
||||
|
@ -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,8 +137,6 @@ public class OpenGLWindow {
|
||||
return mouseY;
|
||||
}
|
||||
|
||||
boolean escDown = false;
|
||||
|
||||
public float loop() {
|
||||
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
|
||||
if (!escDown) {
|
||||
|
@ -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,59 +68,178 @@ 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)) {
|
||||
|
||||
for (FaceOrientation orientation : FaceOrientation.values()) {
|
||||
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 (dependedBlock == null || !assetsLoader.getBlockModelLoader().isFull(dependedBlock)) {
|
||||
facesToDraw.add(orientation);
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
for (FaceOrientation orientation : FaceOrientation.values()) {
|
||||
if ((location.getX() == 0 && orientation == FaceOrientation.WEST) || (location.getX() == 15 && orientation == FaceOrientation.EAST)) {
|
||||
facesToDraw.add(orientation);
|
||||
continue;
|
||||
if (position.getY() != RenderConstants.CHUNK_MIN_Y) {
|
||||
// bottom
|
||||
prepareBlock(new BlockPosition(position.getX(), position.getY() - 1, position.getZ()), true);
|
||||
}
|
||||
if ((location.getY() == 0 && orientation == FaceOrientation.DOWN) || (location.getY() == 15 && orientation == FaceOrientation.UP)) {
|
||||
facesToDraw.add(orientation);
|
||||
continue;
|
||||
if (position.getY() != RenderConstants.CHUNK_MAX_Y) {
|
||||
// bottom
|
||||
prepareBlock(new BlockPosition(position.getX(), position.getY() + 1, position.getZ()), true);
|
||||
}
|
||||
if ((location.getZ() == 0 && orientation == FaceOrientation.NORTH) || (location.getZ() == 15 && orientation == FaceOrientation.SOUTH)) {
|
||||
facesToDraw.add(orientation);
|
||||
continue;
|
||||
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);
|
||||
}
|
||||
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)));
|
||||
};
|
||||
if (!isNeighbourFull) {
|
||||
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(".");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
private void prepareBlock(BlockPosition position, boolean trustEdges) {
|
||||
prepareBlock(position, GameWindow.getConnection().getPlayer().getWorld().getBlock(position), trustEdges);
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -14,5 +14,7 @@
|
||||
package de.bixilon.minosoft.render.blockModels.Face;
|
||||
|
||||
public enum Axis {
|
||||
X, Y, Z
|
||||
X,
|
||||
Y,
|
||||
Z
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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() {
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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()) {
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user