mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-15 10:25:06 -04:00
rendering: proper light
This commit is contained in:
parent
312486cfb4
commit
93c1e32a49
@ -1,243 +0,0 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.data;
|
||||
|
||||
import de.bixilon.minosoft.data.accounts.Account;
|
||||
import de.bixilon.minosoft.data.entities.entities.player.PlayerEntity;
|
||||
import de.bixilon.minosoft.data.inventory.Inventory;
|
||||
import de.bixilon.minosoft.data.inventory.InventoryProperties;
|
||||
import de.bixilon.minosoft.data.inventory.InventorySlots;
|
||||
import de.bixilon.minosoft.data.inventory.Slot;
|
||||
import de.bixilon.minosoft.data.player.PlayerListItem;
|
||||
import de.bixilon.minosoft.data.scoreboard.ScoreboardManager;
|
||||
import de.bixilon.minosoft.data.text.ChatComponent;
|
||||
import de.bixilon.minosoft.data.world.BlockPosition;
|
||||
import de.bixilon.minosoft.data.world.World;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
|
||||
import static de.bixilon.minosoft.protocol.protocol.ProtocolDefinition.PLAYER_INVENTORY_ID;
|
||||
|
||||
public class Player {
|
||||
public final HashMap<UUID, PlayerListItem> playerList = new HashMap<>();
|
||||
private final Account account;
|
||||
private final ScoreboardManager scoreboardManager = new ScoreboardManager();
|
||||
private final World world = new World();
|
||||
private final HashMap<Integer, Inventory> inventories = new HashMap<>();
|
||||
private float health;
|
||||
private int food;
|
||||
private float saturation;
|
||||
private BlockPosition spawnPosition;
|
||||
private GameModes gameMode;
|
||||
private byte selectedSlot;
|
||||
private int level;
|
||||
private int totalExperience;
|
||||
private PlayerEntity entity;
|
||||
private boolean spawnConfirmed;
|
||||
private UUID uuid;
|
||||
private String playerName;
|
||||
|
||||
private ChatComponent tabHeader = ChatComponent.valueOf("");
|
||||
private ChatComponent tabFooter = ChatComponent.valueOf("");
|
||||
|
||||
public Player(Account account) {
|
||||
this.account = account;
|
||||
this.uuid = account.getUUID();
|
||||
this.playerName = account.getUsername();
|
||||
// create our own inventory without any properties
|
||||
this.inventories.put(PLAYER_INVENTORY_ID, new Inventory(null));
|
||||
}
|
||||
|
||||
public String getPlayerName() {
|
||||
return this.playerName;
|
||||
}
|
||||
|
||||
public void setPlayerName(String playerName) {
|
||||
this.playerName = playerName;
|
||||
}
|
||||
|
||||
|
||||
public UUID getPlayerUUID() {
|
||||
return this.uuid;
|
||||
}
|
||||
|
||||
public void setPlayerUUID(UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public Account getAccount() {
|
||||
return this.account;
|
||||
}
|
||||
|
||||
public float getHealth() {
|
||||
return this.health;
|
||||
}
|
||||
|
||||
public void setHealth(float health) {
|
||||
this.health = health;
|
||||
}
|
||||
|
||||
public int getFood() {
|
||||
return this.food;
|
||||
}
|
||||
|
||||
public void setFood(int food) {
|
||||
this.food = food;
|
||||
}
|
||||
|
||||
public float getSaturation() {
|
||||
return this.saturation;
|
||||
}
|
||||
|
||||
public void setSaturation(float saturation) {
|
||||
this.saturation = saturation;
|
||||
}
|
||||
|
||||
public BlockPosition getSpawnPosition() {
|
||||
return this.spawnPosition;
|
||||
}
|
||||
|
||||
public void setSpawnPosition(BlockPosition spawnPosition) {
|
||||
this.spawnPosition = spawnPosition;
|
||||
}
|
||||
|
||||
public GameModes getGameMode() {
|
||||
return this.gameMode;
|
||||
}
|
||||
|
||||
public void setGameMode(GameModes gameMode) {
|
||||
this.gameMode = gameMode;
|
||||
}
|
||||
|
||||
public World getWorld() {
|
||||
return this.world;
|
||||
}
|
||||
|
||||
public byte getSelectedSlot() {
|
||||
return this.selectedSlot;
|
||||
}
|
||||
|
||||
public void setSelectedSlot(byte selectedSlot) {
|
||||
this.selectedSlot = selectedSlot;
|
||||
}
|
||||
|
||||
public int getLevel() {
|
||||
return this.level;
|
||||
}
|
||||
|
||||
public void setLevel(int level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public int getTotalExperience() {
|
||||
return this.totalExperience;
|
||||
}
|
||||
|
||||
public void setTotalExperience(int totalExperience) {
|
||||
this.totalExperience = totalExperience;
|
||||
}
|
||||
|
||||
public Inventory getPlayerInventory() {
|
||||
return getInventory(PLAYER_INVENTORY_ID);
|
||||
}
|
||||
|
||||
public void setPlayerInventory(Slot[] data) {
|
||||
setInventory(PLAYER_INVENTORY_ID, data);
|
||||
}
|
||||
|
||||
public void setInventory(int windowId, Slot[] data) {
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
setSlot(windowId, i, data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void setSlot(int windowId, int slot, Slot data) {
|
||||
this.inventories.get(windowId).setSlot(slot, data);
|
||||
}
|
||||
|
||||
public Inventory getInventory(int id) {
|
||||
return this.inventories.get(id);
|
||||
}
|
||||
|
||||
public Slot getSlot(int windowId, InventorySlots.InventoryInterface slot, int versionId) {
|
||||
return getSlot(windowId, slot.getId(versionId));
|
||||
}
|
||||
|
||||
public Slot getSlot(int windowId, int slot) {
|
||||
return this.inventories.get(windowId).getSlot(slot);
|
||||
}
|
||||
|
||||
public void setSlot(int windowId, InventorySlots.InventoryInterface slot, int versionId, Slot data) {
|
||||
setSlot(windowId, slot.getId(versionId), data);
|
||||
}
|
||||
|
||||
public void createInventory(InventoryProperties properties) {
|
||||
this.inventories.put(properties.getWindowId(), new Inventory(properties));
|
||||
}
|
||||
|
||||
public void deleteInventory(int windowId) {
|
||||
this.inventories.remove(windowId);
|
||||
}
|
||||
|
||||
public boolean isSpawnConfirmed() {
|
||||
return this.spawnConfirmed;
|
||||
}
|
||||
|
||||
public void setSpawnConfirmed(boolean spawnConfirmed) {
|
||||
this.spawnConfirmed = spawnConfirmed;
|
||||
}
|
||||
|
||||
public ScoreboardManager getScoreboardManager() {
|
||||
return this.scoreboardManager;
|
||||
}
|
||||
|
||||
public HashMap<UUID, PlayerListItem> getPlayerList() {
|
||||
return this.playerList;
|
||||
}
|
||||
|
||||
public PlayerListItem getPlayerListItem(String name) {
|
||||
// only legacy
|
||||
for (PlayerListItem listItem : this.playerList.values()) {
|
||||
if (listItem.getName().equals(name)) {
|
||||
return listItem;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ChatComponent getTabHeader() {
|
||||
return this.tabHeader;
|
||||
}
|
||||
|
||||
public void setTabHeader(ChatComponent tabHeader) {
|
||||
this.tabHeader = tabHeader;
|
||||
}
|
||||
|
||||
public ChatComponent getTabFooter() {
|
||||
return this.tabFooter;
|
||||
}
|
||||
|
||||
public void setTabFooter(ChatComponent tabFooter) {
|
||||
this.tabFooter = tabFooter;
|
||||
}
|
||||
|
||||
public PlayerEntity getEntity() {
|
||||
return this.entity;
|
||||
}
|
||||
|
||||
public void setEntity(PlayerEntity entity) {
|
||||
this.entity = entity;
|
||||
}
|
||||
}
|
104
src/main/java/de/bixilon/minosoft/data/Player.kt
Normal file
104
src/main/java/de/bixilon/minosoft/data/Player.kt
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
package de.bixilon.minosoft.data
|
||||
|
||||
import de.bixilon.minosoft.data.accounts.Account
|
||||
import de.bixilon.minosoft.data.entities.entities.player.PlayerEntity
|
||||
import de.bixilon.minosoft.data.inventory.Inventory
|
||||
import de.bixilon.minosoft.data.inventory.InventoryProperties
|
||||
import de.bixilon.minosoft.data.inventory.InventorySlots.InventoryInterface
|
||||
import de.bixilon.minosoft.data.inventory.Slot
|
||||
import de.bixilon.minosoft.data.player.PlayerListItem
|
||||
import de.bixilon.minosoft.data.scoreboard.ScoreboardManager
|
||||
import de.bixilon.minosoft.data.text.ChatComponent
|
||||
import de.bixilon.minosoft.data.world.BlockPosition
|
||||
import de.bixilon.minosoft.data.world.World
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
import java.util.*
|
||||
|
||||
class Player(val account: Account) {
|
||||
val playerList = HashMap<UUID, PlayerListItem>()
|
||||
val scoreboardManager = ScoreboardManager()
|
||||
val world = World()
|
||||
private val inventories = HashMap<Int, Inventory>()
|
||||
var health = 0f
|
||||
var food = 0
|
||||
var saturation = 0f
|
||||
var spawnPosition: BlockPosition? = null
|
||||
var gameMode: GameModes? = null
|
||||
var selectedSlot: Byte = 0
|
||||
var level = 0
|
||||
var totalExperience = 0
|
||||
var entity: PlayerEntity? = null
|
||||
var isSpawnConfirmed = false
|
||||
var playerUUID: UUID = account.uuid
|
||||
var playerName: String = account.username
|
||||
var tabHeader = ChatComponent.valueOf("")!!
|
||||
var tabFooter = ChatComponent.valueOf("")!!
|
||||
|
||||
val playerInventory: Inventory?
|
||||
get() = getInventory(ProtocolDefinition.PLAYER_INVENTORY_ID)
|
||||
|
||||
fun setPlayerInventory(data: Array<Slot?>) {
|
||||
setInventory(ProtocolDefinition.PLAYER_INVENTORY_ID, data)
|
||||
}
|
||||
|
||||
fun setInventory(windowId: Int, data: Array<Slot?>) {
|
||||
for (i in data.indices) {
|
||||
setSlot(windowId, i, data[i])
|
||||
}
|
||||
}
|
||||
|
||||
fun setSlot(windowId: Int, slot: Int, data: Slot?) {
|
||||
inventories[windowId]!!.setSlot(slot, data)
|
||||
}
|
||||
|
||||
fun getInventory(id: Int): Inventory? {
|
||||
return inventories[id]
|
||||
}
|
||||
|
||||
fun getSlot(windowId: Int, slot: InventoryInterface, versionId: Int): Slot {
|
||||
return getSlot(windowId, slot.getId(versionId))
|
||||
}
|
||||
|
||||
fun getSlot(windowId: Int, slot: Int): Slot {
|
||||
return inventories[windowId]!!.getSlot(slot)
|
||||
}
|
||||
|
||||
fun setSlot(windowId: Int, slot: InventoryInterface, versionId: Int, data: Slot?) {
|
||||
setSlot(windowId, slot.getId(versionId), data)
|
||||
}
|
||||
|
||||
fun createInventory(properties: InventoryProperties) {
|
||||
inventories[properties.windowId] = Inventory(properties)
|
||||
}
|
||||
|
||||
fun deleteInventory(windowId: Int) {
|
||||
inventories.remove(windowId)
|
||||
}
|
||||
|
||||
fun getPlayerListItem(name: String): PlayerListItem? {
|
||||
// only legacy
|
||||
for (listItem in playerList.values) {
|
||||
if (listItem.name == name) {
|
||||
return listItem
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
init {
|
||||
// create our own inventory without any properties
|
||||
inventories[ProtocolDefinition.PLAYER_INVENTORY_ID] = Inventory(null)
|
||||
}
|
||||
}
|
@ -45,12 +45,15 @@ data class BlockPosition(val x: Int, val y: Int, val z: Int) {
|
||||
return InChunkPosition(x, this.y, z)
|
||||
}
|
||||
|
||||
infix operator fun plus(vec3: Vec3): BlockPosition {
|
||||
infix operator fun plus(vec3: Vec3?): BlockPosition {
|
||||
if (vec3 == null) {
|
||||
return this
|
||||
}
|
||||
return BlockPosition((x + vec3.x).toInt(), (y + vec3.y).toInt(), (z + vec3.z).toInt())
|
||||
}
|
||||
|
||||
operator fun plus(directions: Directions): BlockPosition {
|
||||
return this + directions.directionVector
|
||||
infix operator fun plus(directions: Directions?): BlockPosition {
|
||||
return this + directions?.directionVector
|
||||
}
|
||||
|
||||
fun getInChunkSectionPosition(): InChunkSectionPosition {
|
||||
|
@ -12,6 +12,7 @@
|
||||
*/
|
||||
package de.bixilon.minosoft.data.world
|
||||
|
||||
import de.bixilon.minosoft.data.Directions
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
import glm_.vec3.Vec3
|
||||
|
||||
@ -34,10 +35,17 @@ data class InChunkPosition(val x: Int, val y: Int, val z: Int) {
|
||||
}
|
||||
}
|
||||
|
||||
operator fun plus(vec3: Vec3): InChunkPosition {
|
||||
operator fun plus(vec3: Vec3?): InChunkPosition {
|
||||
if (vec3 == null) {
|
||||
return this
|
||||
}
|
||||
return InChunkPosition((x + vec3.x).toInt(), (y + vec3.y).toInt(), (z + vec3.z).toInt())
|
||||
}
|
||||
|
||||
operator fun plus(direction: Directions?): InChunkPosition {
|
||||
return this + direction?.directionVector
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "($x $y $z)"
|
||||
}
|
||||
|
@ -55,6 +55,11 @@ data class InChunkSectionPosition(val x: Int, val y: Int, val z: Int) {
|
||||
return InChunkSectionPosition(nextX, nextY, nextZ)
|
||||
}
|
||||
|
||||
|
||||
fun isEdge(): Boolean {
|
||||
return x == 0 || y == 0 || z == 0 || x == ProtocolDefinition.SECTION_MAX_X || y == ProtocolDefinition.SECTION_MAX_Y || z == ProtocolDefinition.SECTION_MAX_Z
|
||||
}
|
||||
|
||||
operator fun plus(directions: Directions): InChunkSectionPosition {
|
||||
return this + directions.directionVector
|
||||
}
|
||||
|
@ -13,10 +13,12 @@
|
||||
package de.bixilon.minosoft.data.world
|
||||
|
||||
import com.google.common.collect.HashBiMap
|
||||
import de.bixilon.minosoft.data.Difficulties
|
||||
import de.bixilon.minosoft.data.entities.block.BlockEntityMetaData
|
||||
import de.bixilon.minosoft.data.entities.entities.Entity
|
||||
import de.bixilon.minosoft.data.mappings.Dimension
|
||||
import de.bixilon.minosoft.data.mappings.blocks.BlockState
|
||||
import de.bixilon.minosoft.data.world.light.WorldLightAccessor
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
@ -30,7 +32,9 @@ class World {
|
||||
var isHardcore = false
|
||||
var isRaining = false
|
||||
var dimension: Dimension? = null
|
||||
|
||||
var difficulty: Difficulties? = null
|
||||
var difficultyLocked = false
|
||||
val worldLightAccessor = WorldLightAccessor(this)
|
||||
|
||||
fun getBlockInfo(blockPosition: BlockPosition): BlockInfo? {
|
||||
val chunkLocation = blockPosition.getChunkPosition()
|
||||
|
@ -13,24 +13,28 @@
|
||||
|
||||
package de.bixilon.minosoft.data.world.light
|
||||
|
||||
import de.bixilon.minosoft.data.Directions
|
||||
import de.bixilon.minosoft.data.world.BlockPosition
|
||||
import de.bixilon.minosoft.data.world.InChunkPosition
|
||||
import de.bixilon.minosoft.data.world.World
|
||||
|
||||
class ChunkLightAccessor(
|
||||
val blockLightLevel: MutableMap<InChunkPosition, Byte> = mutableMapOf(),
|
||||
val skyLightLevel: MutableMap<InChunkPosition, Byte> = mutableMapOf(),
|
||||
val world: World,
|
||||
private val blockLightLevel: MutableMap<Int, MutableMap<InChunkPosition, Byte>> = mutableMapOf(),
|
||||
private val skyLightLevel: MutableMap<Int, MutableMap<InChunkPosition, Byte>> = mutableMapOf(),
|
||||
) : LightAccessor {
|
||||
override fun getLightLevel(blockPosition: BlockPosition, direction: Directions): Int {
|
||||
val inChunkPosition = blockPosition.getInChunkPosition()
|
||||
val lightLevel = blockLightLevel[inChunkPosition] ?: skyLightLevel[inChunkPosition]
|
||||
|
||||
if (lightLevel == null) {
|
||||
return 1
|
||||
override fun getSkyLight(blockPosition: BlockPosition): Byte {
|
||||
return skyLightLevel[blockPosition.getSectionHeight()]?.get(blockPosition.getInChunkPosition()) ?: 0
|
||||
}
|
||||
|
||||
return lightLevel.toInt()
|
||||
override fun getBlockLight(blockPosition: BlockPosition): Byte {
|
||||
return blockLightLevel[blockPosition.getSectionHeight()]?.get(blockPosition.getInChunkPosition()) ?: 0
|
||||
}
|
||||
|
||||
fun merge(chunkLightAccessor: ChunkLightAccessor) {
|
||||
for ((sectionHeight, section) in chunkLightAccessor.blockLightLevel) {
|
||||
blockLightLevel[sectionHeight] = section
|
||||
}
|
||||
|
||||
for ((sectionHeight, section) in chunkLightAccessor.skyLightLevel) {
|
||||
skyLightLevel[sectionHeight] = section
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,19 +13,15 @@
|
||||
|
||||
package de.bixilon.minosoft.data.world.light
|
||||
|
||||
import de.bixilon.minosoft.data.Directions
|
||||
import de.bixilon.minosoft.data.world.BlockPosition
|
||||
|
||||
object DummyLightAccessor : LightAccessor {
|
||||
override fun getSkyLight(blockPosition: BlockPosition): Byte {
|
||||
return 15
|
||||
}
|
||||
|
||||
override fun getLightLevel(blockPosition: BlockPosition, direction: Directions): Int {
|
||||
return when (direction) {
|
||||
Directions.NORTH -> 5
|
||||
Directions.SOUTH -> 7
|
||||
Directions.DOWN -> 3
|
||||
Directions.UP -> 9
|
||||
Directions.WEST -> 11
|
||||
Directions.EAST -> 13
|
||||
}
|
||||
override fun getBlockLight(blockPosition: BlockPosition): Byte {
|
||||
return 15
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,10 +13,21 @@
|
||||
|
||||
package de.bixilon.minosoft.data.world.light
|
||||
|
||||
import de.bixilon.minosoft.data.Directions
|
||||
import de.bixilon.minosoft.data.world.BlockPosition
|
||||
|
||||
interface LightAccessor {
|
||||
|
||||
fun getLightLevel(blockPosition: BlockPosition, direction: Directions): Int
|
||||
fun getSkyLight(blockPosition: BlockPosition): Byte
|
||||
|
||||
fun getBlockLight(blockPosition: BlockPosition): Byte
|
||||
|
||||
fun getLightLevel(blockPosition: BlockPosition): Byte {
|
||||
val blockLight = getBlockLight(blockPosition)
|
||||
val skyLight = getSkyLight(blockPosition)
|
||||
if (blockLight > skyLight) {
|
||||
return blockLight
|
||||
}
|
||||
return skyLight
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2021 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.data.world.light
|
||||
|
||||
import de.bixilon.minosoft.data.world.BlockPosition
|
||||
import de.bixilon.minosoft.data.world.World
|
||||
|
||||
class WorldLightAccessor(
|
||||
private val world: World,
|
||||
) : LightAccessor {
|
||||
override fun getSkyLight(blockPosition: BlockPosition): Byte {
|
||||
return world.chunks[blockPosition.getChunkPosition()]?.lightAccessor?.getSkyLight(blockPosition) ?: 0
|
||||
}
|
||||
|
||||
override fun getBlockLight(blockPosition: BlockPosition): Byte {
|
||||
return world.chunks[blockPosition.getChunkPosition()]?.lightAccessor?.getBlockLight(blockPosition) ?: 0
|
||||
}
|
||||
}
|
@ -29,7 +29,7 @@ class ChunkMesh {
|
||||
private var vbo: Int = 0
|
||||
private var trianglesCount: Int = 0
|
||||
|
||||
fun addVertex(position: Vec3, textureCoordinates: Vec2, texture: Texture, tintColor: RGBColor?, lightLevel: Float = 0.9f) {
|
||||
fun addVertex(position: Vec3, textureCoordinates: Vec2, texture: Texture, tintColor: RGBColor?, lightLevel: Byte = 14) {
|
||||
data.add(position.x)
|
||||
data.add(position.y)
|
||||
data.add(position.z)
|
||||
@ -48,7 +48,7 @@ class ChunkMesh {
|
||||
data.add(Float.fromBits(tintColor.color))
|
||||
}
|
||||
|
||||
data.add(lightLevel)
|
||||
data.add(lightLevel / MAX_LIGHT_LEVEL)
|
||||
}
|
||||
|
||||
fun load() {
|
||||
@ -99,5 +99,6 @@ class ChunkMesh {
|
||||
|
||||
companion object {
|
||||
private const val FLOATS_PER_VERTEX = 11
|
||||
private const val MAX_LIGHT_LEVEL = 15f
|
||||
}
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ class WorldRenderer(private val connection: Connection, private val world: World
|
||||
blockInfo.block.tintColor?.let { tintColor = it }
|
||||
}
|
||||
|
||||
blockInfo.block.getBlockRenderer(blockPosition).render(blockInfo, chunk.lightAccessor!!, tintColor, blockPosition, mesh, neighborBlocks)
|
||||
blockInfo.block.getBlockRenderer(blockPosition).render(blockInfo, world.worldLightAccessor, tintColor, blockPosition, mesh, neighborBlocks)
|
||||
}
|
||||
return mesh
|
||||
}
|
||||
|
@ -92,7 +92,8 @@ class BlockRenderer(data: JsonObject, parent: BlockModel) {
|
||||
continue
|
||||
}
|
||||
|
||||
element.render(tintColor, lightAccessor.getLightLevel(position, direction) / 15f, textureMapping, modelMatrix, direction, mesh)
|
||||
// ToDo: Lightning is determined by cullface attribute
|
||||
element.render(tintColor, lightAccessor.getLightLevel(position + direction), textureMapping, modelMatrix, direction, mesh)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ class ElementRenderer(element: BlockModelElement, rotation: Vec3, uvLock: Boolea
|
||||
}
|
||||
|
||||
|
||||
fun render(tintColor: RGBColor?, lightLevel: Float, textureMapping: MutableMap<String, Texture>, modelMatrix: Mat4, direction: Directions, mesh: ChunkMesh) {
|
||||
fun render(tintColor: RGBColor?, lightLevel: Byte, textureMapping: MutableMap<String, Texture>, modelMatrix: Mat4, direction: Directions, mesh: ChunkMesh) {
|
||||
val realDirection = directionMapping[direction]!!
|
||||
val positionTemplate = BlockModelElement.FACE_POSITION_MAP_TEMPLATE[realDirection.ordinal]
|
||||
|
||||
|
@ -59,6 +59,15 @@ class HUDDebugScreenElement(private val hudTextElement: HUDTextElement) : HUDTex
|
||||
"Facing ${getFacing()}",
|
||||
"Dimension ${hudTextElement.connection.player.world.dimension}",
|
||||
"Biome ${camera.currentBiome}",
|
||||
"",
|
||||
"Difficulty ${hudTextElement.connection.player.world.difficulty?.name?.toLowerCase()}, ${
|
||||
if (hudTextElement.connection.player.world.difficultyLocked) {
|
||||
"locked"
|
||||
} else {
|
||||
"unlocked"
|
||||
}
|
||||
}",
|
||||
"Client light: ${hudTextElement.connection.player.world.worldLightAccessor.getLightLevel(camera.blockPosition)} (sky=${hudTextElement.connection.player.world.worldLightAccessor.getSkyLight(camera.blockPosition)}, block=${hudTextElement.connection.player.world.worldLightAccessor.getBlockLight(camera.blockPosition)})"
|
||||
))
|
||||
chatComponents[FontBindings.RIGHT_UP]!!.addAll(listOf(
|
||||
"Java: ${Runtime.version()} ${System.getProperty("sun.arch.data.model")}bit",
|
||||
@ -160,7 +169,8 @@ class HUDDebugScreenElement(private val hudTextElement: HUDTextElement) : HUDTex
|
||||
private fun getFacing(): String {
|
||||
val yaw = hudTextElement.renderWindow.camera.yaw
|
||||
val pitch = hudTextElement.renderWindow.camera.pitch
|
||||
return "${Directions.byDirection(camera.cameraFront).name.toLowerCase()} (${formatRotation(yaw)} / ${formatRotation(pitch)})"
|
||||
val direction = Directions.byDirection(camera.cameraFront)
|
||||
return "${Directions.byDirection(camera.cameraFront).name.toLowerCase()} (${direction.directionVector} (${formatRotation(yaw)} / ${formatRotation(pitch)})"
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.protocol.packets.clientbound.play;
|
||||
|
||||
import de.bixilon.minosoft.data.Difficulties;
|
||||
import de.bixilon.minosoft.protocol.packets.ClientboundPacket;
|
||||
import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
|
||||
import de.bixilon.minosoft.util.logging.Log;
|
||||
|
||||
import static de.bixilon.minosoft.protocol.protocol.ProtocolVersions.V_19W11A;
|
||||
|
||||
public class PacketServerDifficulty extends ClientboundPacket {
|
||||
Difficulties difficulty;
|
||||
boolean locked;
|
||||
|
||||
@Override
|
||||
public boolean read(InByteBuffer buffer) {
|
||||
this.difficulty = Difficulties.byId(buffer.readUnsignedByte());
|
||||
if (buffer.getVersionId() > V_19W11A) {
|
||||
this.locked = buffer.readBoolean();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log() {
|
||||
Log.protocol(String.format("[IN] Received server difficulty (difficulty=%s)", this.difficulty));
|
||||
}
|
||||
|
||||
public Difficulties getDifficulty() {
|
||||
return this.difficulty;
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
package de.bixilon.minosoft.protocol.packets.clientbound.play
|
||||
|
||||
import de.bixilon.minosoft.data.Difficulties
|
||||
import de.bixilon.minosoft.protocol.network.Connection
|
||||
import de.bixilon.minosoft.protocol.packets.ClientboundPacket
|
||||
import de.bixilon.minosoft.protocol.protocol.InByteBuffer
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions
|
||||
import de.bixilon.minosoft.util.logging.Log
|
||||
|
||||
class PacketServerDifficulty : ClientboundPacket() {
|
||||
lateinit var difficulty: Difficulties
|
||||
var locked = false
|
||||
|
||||
override fun read(buffer: InByteBuffer): Boolean {
|
||||
difficulty = Difficulties.byId(buffer.readUnsignedByte().toInt())
|
||||
if (buffer.versionId > ProtocolVersions.V_19W11A) {
|
||||
locked = buffer.readBoolean()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun handle(connection: Connection) {
|
||||
connection.player.world.difficulty = difficulty
|
||||
connection.player.world.difficultyLocked = locked
|
||||
}
|
||||
|
||||
override fun log() {
|
||||
Log.protocol("[IN] Received server difficulty (difficulty=$difficulty, locked=${locked})")
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@
|
||||
package de.bixilon.minosoft.protocol.packets.clientbound.play
|
||||
|
||||
import de.bixilon.minosoft.data.world.ChunkPosition
|
||||
import de.bixilon.minosoft.data.world.light.ChunkLightAccessor
|
||||
import de.bixilon.minosoft.data.world.light.LightAccessor
|
||||
import de.bixilon.minosoft.protocol.network.Connection
|
||||
import de.bixilon.minosoft.protocol.packets.ClientboundPacket
|
||||
@ -27,7 +28,7 @@ class PacketUpdateLight : ClientboundPacket() {
|
||||
override fun read(buffer: InByteBuffer): Boolean {
|
||||
position = ChunkPosition(buffer.readVarInt(), buffer.readVarInt())
|
||||
|
||||
if (position == ChunkPosition(-1, 21)) {
|
||||
if (position == ChunkPosition(-6, 20)) {
|
||||
Log.debug("")
|
||||
}
|
||||
if (buffer.versionId >= ProtocolVersions.V_1_16_PRE3) {
|
||||
@ -61,7 +62,11 @@ class PacketUpdateLight : ClientboundPacket() {
|
||||
|
||||
override fun handle(connection: Connection) {
|
||||
val chunk = connection.player.world.getOrCreateChunk(position!!)
|
||||
if (chunk.lightAccessor != null && chunk.lightAccessor is ChunkLightAccessor && lightAccessor is ChunkLightAccessor) {
|
||||
(chunk.lightAccessor as ChunkLightAccessor).merge(lightAccessor as ChunkLightAccessor)
|
||||
} else {
|
||||
chunk.lightAccessor = lightAccessor
|
||||
}
|
||||
connection.renderer.renderWindow.worldRenderer.prepareChunk(position!!, chunk)
|
||||
}
|
||||
}
|
||||
|
@ -60,8 +60,8 @@ public final class ChunkUtil {
|
||||
// parse data
|
||||
int arrayPos = 0;
|
||||
HashMap<Integer, ChunkSection> sectionMap = new HashMap<>();
|
||||
for (int c = 0; c < ProtocolDefinition.SECTIONS_PER_CHUNK; c++) { // max sections per chunks in chunk column
|
||||
if (BitByte.isBitSet(sectionBitMasks[0], c)) {
|
||||
for (int sectionHeight = dimension.getLowestSection(); sectionHeight < dimension.getHighestSection(); sectionHeight++) { // max sections per chunks in chunk column
|
||||
if (BitByte.isBitSet(sectionBitMasks[0], sectionHeight)) {
|
||||
HashMap<InChunkSectionPosition, BlockInfo> blockMap = new HashMap<>();
|
||||
|
||||
for (int nibbleY = 0; nibbleY < ProtocolDefinition.SECTION_HEIGHT_Y; nibbleY++) {
|
||||
@ -73,13 +73,13 @@ public final class ChunkUtil {
|
||||
if (arrayPos % 2 == 0) {
|
||||
// high bits
|
||||
singleMeta = (byte) (meta[arrayPos / 2] & 0xF);
|
||||
if (BitByte.isBitSet(addBitMask, c)) {
|
||||
if (BitByte.isBitSet(addBitMask, sectionHeight)) {
|
||||
singeBlockId = (short) ((singeBlockId << 4) | (addBlockTypes[arrayPos / 2] >>> 4));
|
||||
}
|
||||
} else {
|
||||
// low 4 bits
|
||||
singleMeta = (byte) ((meta[arrayPos / 2] >>> 4) & 0xF);
|
||||
if (BitByte.isBitSet(addBitMask, c)) {
|
||||
if (BitByte.isBitSet(addBitMask, sectionHeight)) {
|
||||
singeBlockId = (short) ((singeBlockId << 4) | (addBlockTypes[arrayPos / 2] & 0xF));
|
||||
}
|
||||
}
|
||||
@ -95,7 +95,7 @@ public final class ChunkUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
sectionMap.put(dimension.getLowestSection() + c, new ChunkSection(blockMap)); // ToDo
|
||||
sectionMap.put(dimension.getLowestSection() + sectionHeight, new ChunkSection(blockMap)); // ToDo
|
||||
}
|
||||
}
|
||||
return new ChunkData(sectionMap, new DummyBiomeAccessor(buffer.getConnection().getMapping().getBiomeRegistry().get(0)), DummyLightAccessor.INSTANCE);
|
||||
@ -122,8 +122,8 @@ public final class ChunkUtil {
|
||||
|
||||
int arrayPos = 0;
|
||||
HashMap<Integer, ChunkSection> sectionMap = new HashMap<>();
|
||||
for (int c = 0; c < ProtocolDefinition.SECTIONS_PER_CHUNK; c++) { // max sections per chunks in chunk column
|
||||
if (!BitByte.isBitSet(sectionBitMasks[0], c)) {
|
||||
for (int sectionHeight = dimension.getLowestSection(); sectionHeight < dimension.getHighestSection(); sectionHeight++) { // max sections per chunks in chunk column
|
||||
if (!BitByte.isBitSet(sectionBitMasks[0], sectionHeight)) {
|
||||
continue;
|
||||
}
|
||||
HashMap<InChunkSectionPosition, BlockInfo> blockMap = new HashMap<>();
|
||||
@ -142,15 +142,15 @@ public final class ChunkUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
sectionMap.put(dimension.getLowestSection() + c, new ChunkSection(blockMap));
|
||||
sectionMap.put(dimension.getLowestSection() + sectionHeight, new ChunkSection(blockMap));
|
||||
}
|
||||
return new ChunkData(sectionMap, new DummyBiomeAccessor(buffer.getConnection().getMapping().getBiomeRegistry().get(0)), DummyLightAccessor.INSTANCE); // ToDo
|
||||
}
|
||||
// really big thanks to: https://wiki.vg/index.php?title=Chunk_Format&oldid=13712
|
||||
HashMap<Integer, ChunkSection> sectionMap = new HashMap<>();
|
||||
BitSet sectionBitSet = BitSet.valueOf(sectionBitMasks);
|
||||
for (int c = 0; c < sectionBitSet.length(); c++) { // max sections per chunks in chunk column
|
||||
if (!sectionBitSet.get(c)) {
|
||||
for (int sectionHeight = dimension.getLowestSection(); sectionHeight < sectionBitSet.length(); sectionHeight++) { // max sections per chunks in chunk column
|
||||
if (!sectionBitSet.get(sectionHeight)) {
|
||||
continue;
|
||||
}
|
||||
if (buffer.getVersionId() >= V_18W43A) {
|
||||
@ -206,7 +206,7 @@ public final class ChunkUtil {
|
||||
// ToDo
|
||||
}
|
||||
|
||||
sectionMap.put(dimension.getLowestSection() + c, new ChunkSection(blockMap));
|
||||
sectionMap.put(dimension.getLowestSection() + sectionHeight, new ChunkSection(blockMap));
|
||||
}
|
||||
ChunkData chunkData = new ChunkData();
|
||||
chunkData.setBlocks(sectionMap);
|
||||
|
@ -16,7 +16,6 @@ package de.bixilon.minosoft.util.chunk
|
||||
import de.bixilon.minosoft.data.mappings.Dimension
|
||||
import de.bixilon.minosoft.data.world.InChunkPosition
|
||||
import de.bixilon.minosoft.data.world.light.ChunkLightAccessor
|
||||
import de.bixilon.minosoft.data.world.light.DummyLightAccessor
|
||||
import de.bixilon.minosoft.data.world.light.LightAccessor
|
||||
import de.bixilon.minosoft.protocol.protocol.InByteBuffer
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions
|
||||
@ -26,16 +25,16 @@ object LightUtil {
|
||||
|
||||
fun readLightPacket(buffer: InByteBuffer, skyLightMask: LongArray, blockLightMask: LongArray, emptyBlockLightMask: LongArray, emptySkyLightMask: LongArray, dimension: Dimension): LightAccessor {
|
||||
// ToDo
|
||||
val blockLight = readLightArray(buffer, BitSet.valueOf(blockLightMask), dimension)
|
||||
if (!dimension.hasSkyLight) {
|
||||
return ChunkLightAccessor(blockLight, world = buffer.connection.player.world)
|
||||
val skyLight = if (dimension.hasSkyLight) {
|
||||
readLightArray(buffer, BitSet.valueOf(skyLightMask), dimension)
|
||||
} else {
|
||||
mutableMapOf()
|
||||
}
|
||||
val skyLight = readLightArray(buffer, BitSet.valueOf(skyLightMask), dimension)
|
||||
return DummyLightAccessor
|
||||
return ChunkLightAccessor(blockLight, skyLight, buffer.connection.player.world)
|
||||
val blockLight = readLightArray(buffer, BitSet.valueOf(blockLightMask), dimension)
|
||||
return ChunkLightAccessor(blockLight, skyLight)
|
||||
}
|
||||
|
||||
private fun readLightArray(buffer: InByteBuffer, lightMask: BitSet, dimension: Dimension): MutableMap<InChunkPosition, Byte> {
|
||||
private fun readLightArray(buffer: InByteBuffer, lightMask: BitSet, dimension: Dimension): MutableMap<Int, MutableMap<InChunkPosition, Byte>> {
|
||||
var highestSectionIndex = dimension.highestSection + 1
|
||||
val lowesSectionIndex = dimension.lowestSection - 1
|
||||
if (buffer.versionId >= ProtocolVersions.V_20W49A) {
|
||||
@ -43,10 +42,11 @@ object LightUtil {
|
||||
highestSectionIndex = lightMask.length()
|
||||
}
|
||||
|
||||
val lightLevels: MutableMap<InChunkPosition, Byte> = mutableMapOf()
|
||||
val lightLevels: MutableMap<Int, MutableMap<InChunkPosition, Byte>> = mutableMapOf()
|
||||
|
||||
|
||||
for ((arrayIndex, c) in (lowesSectionIndex until highestSectionIndex).withIndex()) { // light sections
|
||||
for ((arrayIndex, sectionHeight) in (lowesSectionIndex until highestSectionIndex).withIndex()) { // light sections
|
||||
val currentSectionLightLevel: MutableMap<InChunkPosition, Byte> = mutableMapOf()
|
||||
if (!lightMask[arrayIndex]) {
|
||||
continue
|
||||
}
|
||||
@ -55,12 +55,13 @@ object LightUtil {
|
||||
for (y in 0 until 16) {
|
||||
for (z in 0 until 16) {
|
||||
for (x in 0 until 16 step 2) {
|
||||
lightLevels[InChunkPosition(x, y + c * 16, z)] = (lightArray[index].toInt() and 0x0F).toByte()
|
||||
lightLevels[InChunkPosition(x + 1, y + c * 16, z)] = ((lightArray[index].toInt() ushr 4) and 0x0F).toByte()
|
||||
currentSectionLightLevel[InChunkPosition(x, y + sectionHeight * 16, z)] = (lightArray[index].toInt() and 0x0F).toByte()
|
||||
currentSectionLightLevel[InChunkPosition(x + 1, y + sectionHeight * 16, z)] = ((lightArray[index].toInt() ushr 4) and 0x0F).toByte()
|
||||
index++
|
||||
}
|
||||
}
|
||||
}
|
||||
lightLevels[sectionHeight] = currentSectionLightLevel
|
||||
}
|
||||
return lightLevels
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user