diff --git a/src/main/java/electrosphere/client/block/BlockChunkData.java b/src/main/java/electrosphere/client/block/BlockChunkData.java index a57ad7d5..df99c8de 100644 --- a/src/main/java/electrosphere/client/block/BlockChunkData.java +++ b/src/main/java/electrosphere/client/block/BlockChunkData.java @@ -131,6 +131,14 @@ public class BlockChunkData { return rVal; } + /** + * Allocates the arrays in a given homogenous data chunk + */ + private void allocateFromHomogenous(){ + this.setType(new short[CHUNK_DATA_WIDTH * CHUNK_DATA_WIDTH * CHUNK_DATA_WIDTH]); + this.setMetadata(new short[CHUNK_DATA_WIDTH * CHUNK_DATA_WIDTH * CHUNK_DATA_WIDTH]); + } + /** * Gets the type data for the chunk * @return The type data @@ -179,6 +187,9 @@ public class BlockChunkData { * @return The type at that position */ public short getType(int x, int y, int z){ + if(this.type == null){ + this.allocateFromHomogenous(); + } return this.type[x * CHUNK_DATA_WIDTH * CHUNK_DATA_WIDTH + z * CHUNK_DATA_WIDTH + y]; } @@ -190,6 +201,9 @@ public class BlockChunkData { * @param type The type */ public void setType(int x, int y, int z, short type){ + if(this.type == null){ + this.allocateFromHomogenous(); + } this.type[x * CHUNK_DATA_WIDTH * CHUNK_DATA_WIDTH + z * CHUNK_DATA_WIDTH + y] = type; } @@ -201,9 +215,40 @@ public class BlockChunkData { * @param type The type */ public void setType(int x, int y, int z, int type){ + if(this.type == null){ + this.allocateFromHomogenous(); + } this.type[x * CHUNK_DATA_WIDTH * CHUNK_DATA_WIDTH + z * CHUNK_DATA_WIDTH + y] = (short)type; } + /** + * Sets a specific block's metadata + * @param x The x position + * @param y The y position + * @param z The z position + * @param metadata The metadata + */ + public void setMetadata(int x, int y, int z, short metadata){ + if(this.metadata == null){ + this.allocateFromHomogenous(); + } + this.metadata[x * CHUNK_DATA_WIDTH * CHUNK_DATA_WIDTH + z * CHUNK_DATA_WIDTH + y] = metadata; + } + + /** + * Sets a specific block's metadata + * @param x The x position + * @param y The y position + * @param z The z position + * @param metadata The metadata + */ + public void setMetadata(int x, int y, int z, int metadata){ + if(this.metadata == null){ + this.allocateFromHomogenous(); + } + this.metadata[x * CHUNK_DATA_WIDTH * CHUNK_DATA_WIDTH + z * CHUNK_DATA_WIDTH + y] = (short)metadata; + } + /** * Gets the metadata at a given position * @param x The x position @@ -212,6 +257,9 @@ public class BlockChunkData { * @return The metadata at that position */ public short getMetadata(int x, int y, int z){ + if(this.metadata == null){ + this.allocateFromHomogenous(); + } return this.metadata[x * CHUNK_DATA_WIDTH * CHUNK_DATA_WIDTH + z * CHUNK_DATA_WIDTH + y]; } diff --git a/src/main/java/electrosphere/client/block/cells/ClientBlockCellManager.java b/src/main/java/electrosphere/client/block/cells/ClientBlockCellManager.java index 3625236c..df7e3f16 100644 --- a/src/main/java/electrosphere/client/block/cells/ClientBlockCellManager.java +++ b/src/main/java/electrosphere/client/block/cells/ClientBlockCellManager.java @@ -684,6 +684,18 @@ public class ClientBlockCellManager { drawCell.setHasRequested(false); } + /** + * Marks a draw cell as homogenous or not + * @param worldX The world x position + * @param worldY The world y position + * @param worldZ The world z position + */ + public void markHomogenous(int worldX, int worldY, int worldZ, boolean homogenous){ + BlockDrawCell drawCell = this.getDrawCell(worldX, worldY, worldZ); + drawCell.ejectChunkData(); + drawCell.setHomogenous(homogenous); + } + /** * Requests all chunks for a given draw cell * @param cell The cell diff --git a/src/main/java/electrosphere/entity/state/equip/ServerToolbarState.java b/src/main/java/electrosphere/entity/state/equip/ServerToolbarState.java index 8db9ac25..77e04c82 100644 --- a/src/main/java/electrosphere/entity/state/equip/ServerToolbarState.java +++ b/src/main/java/electrosphere/entity/state/equip/ServerToolbarState.java @@ -131,6 +131,18 @@ public class ServerToolbarState implements BehaviorTree { if(targetPoint.getEquipClassWhitelist() != null && !targetPoint.getEquipClassWhitelist().contains(equipItemClass)){ targetPoint = equipInventoryState.getEquipPointFromSlot(toolbarData.getCombinedSlot()); } + + if(targetPoint == null){ + EquipPoint discoveredPoint = equipInventoryState.getEquipPointFromSlot(toolbarData.getPrimarySlot()); + String message = + "Failed to visually equip item slot!\n" + + "Primary Slot: " + toolbarData.getPrimarySlot() + "\n" + + "Discovered point: " + discoveredPoint.getBone() + "\n" + + "Item Class Whitelist: " + discoveredPoint.getEquipClassWhitelist() + "\n" + + "Equipped item class: " + equipItemClass + ; + throw new Error(message); + } // //Visual transforms diff --git a/src/main/java/electrosphere/game/data/item/Item.java b/src/main/java/electrosphere/game/data/item/Item.java index 1f0bdbca..667c6f69 100644 --- a/src/main/java/electrosphere/game/data/item/Item.java +++ b/src/main/java/electrosphere/game/data/item/Item.java @@ -138,6 +138,10 @@ public class Item extends CommonEntityType { meshUniformMap.put(RenderUtils.MESH_NAME_BLOCK_SINGLE,uniforms); modelData.setUniforms(meshUniformMap); + //set item class + rVal.equipData = new EquipData(); + rVal.equipData.equipClass = "tool"; + //set usage ItemUsage usage = new ItemUsage(); diff --git a/src/main/java/electrosphere/game/server/world/ServerWorldData.java b/src/main/java/electrosphere/game/server/world/ServerWorldData.java index 87c55cab..35b83388 100644 --- a/src/main/java/electrosphere/game/server/world/ServerWorldData.java +++ b/src/main/java/electrosphere/game/server/world/ServerWorldData.java @@ -1,5 +1,6 @@ package electrosphere.game.server.world; +import electrosphere.client.block.BlockChunkData; import electrosphere.server.block.manager.ServerBlockManager; import electrosphere.server.fluid.generation.DefaultFluidGenerator; import electrosphere.server.fluid.manager.ServerFluidManager; @@ -208,6 +209,15 @@ public class ServerWorldData { return chunk * ServerTerrainChunk.CHUNK_DIMENSION; } + /** + * Converts a real position to a local block grid position + * @param real The real position + * @return The local block grid position + */ + public int convertRealToLocalBlockSpace(double real){ + return (int)Math.floor(real * BlockChunkData.BLOCKS_PER_UNIT_DISTANCE % BlockChunkData.CHUNK_DATA_WIDTH); + } + /** * Converts a chunk space coordinate to a real space coordinate * @param chunk The position within the chunk @@ -277,6 +287,19 @@ public class ServerWorldData { ); } + /** + * Converts a real coordinate to a local block grid space coordinate + * @param position The real coordinate + * @return The local block grid space coordinate + */ + public Vector3i convertRealToLocalBlockSpace(Vector3d position){ + return new Vector3i( + convertRealToLocalBlockSpace(position.x), + convertRealToLocalBlockSpace(position.y), + convertRealToLocalBlockSpace(position.z) + ); + } + /** * Converts a world coordinate to a macro scale coordinate * @param worldPos The world position diff --git a/src/main/java/electrosphere/net/client/protocol/TerrainProtocol.java b/src/main/java/electrosphere/net/client/protocol/TerrainProtocol.java index 9cd32f5f..4671c389 100644 --- a/src/main/java/electrosphere/net/client/protocol/TerrainProtocol.java +++ b/src/main/java/electrosphere/net/client/protocol/TerrainProtocol.java @@ -7,6 +7,7 @@ import java.util.List; import org.joml.Vector3f; import org.joml.Vector3i; +import electrosphere.client.block.BlockChunkData; import electrosphere.client.scene.ClientWorldData; import electrosphere.client.terrain.cache.ChunkData; import electrosphere.collision.CollisionWorldData; @@ -172,6 +173,65 @@ public class TerrainProtocol implements ClientProtocolTemplate { } } } break; + case UPDATEBLOCK: { + // + //find what all drawcells might be updated by this voxel update + Vector3i worldPos = new Vector3i(message.getworldX(), message.getworldY(), message.getworldZ()); + List positionsToUpdate = new LinkedList(); + positionsToUpdate.add(worldPos); + if(message.getvoxelX() < 1){ + positionsToUpdate.add(new Vector3i(worldPos).sub(1,0,0)); + if(message.getvoxelY() < 1){ + positionsToUpdate.add(new Vector3i(worldPos).sub(1,1,0)); + if(message.getvoxelZ() < 1){ + positionsToUpdate.add(new Vector3i(worldPos).sub(1,1,1)); + } + } else { + if(message.getvoxelZ() < 1){ + positionsToUpdate.add(new Vector3i(worldPos).sub(1,0,1)); + } + } + } else { + if(message.getvoxelY() < 1){ + positionsToUpdate.add(new Vector3i(worldPos).sub(0,1,0)); + if(message.getvoxelZ() < 1){ + positionsToUpdate.add(new Vector3i(worldPos).sub(0,1,1)); + } + } else { + if(message.getvoxelZ() < 1){ + positionsToUpdate.add(new Vector3i(worldPos).sub(0,0,1)); + } + } + } + // + //update the block cache + if(Globals.clientBlockManager.containsChunkDataAtWorldPoint(worldPos.x, worldPos.y, worldPos.z, ChunkData.NO_STRIDE)){ + BlockChunkData data = Globals.clientBlockManager.getChunkDataAtWorldPoint(worldPos.x, worldPos.y, worldPos.z, ChunkData.NO_STRIDE); + if(data != null){ + data.setType( + message.getvoxelX(), + message.getvoxelY(), + message.getvoxelZ(), + message.getblockType() + ); + data.setHomogenousValue(BlockChunkData.NOT_HOMOGENOUS); + } + } + // + //mark all relevant drawcells as updateable + for(Vector3i worldPosToUpdate : positionsToUpdate){ + if( + worldPosToUpdate.x >= 0 && worldPosToUpdate.x < Globals.clientWorldData.getWorldDiscreteSize() && + worldPosToUpdate.y >= 0 && worldPosToUpdate.y < Globals.clientWorldData.getWorldDiscreteSize() && + worldPosToUpdate.z >= 0 && worldPosToUpdate.z < Globals.clientWorldData.getWorldDiscreteSize() + ){ + // + //mark terrain chunk for update + Globals.clientBlockCellManager.markUpdateable(worldPosToUpdate.x, worldPosToUpdate.y, worldPosToUpdate.z); + Globals.clientBlockCellManager.markHomogenous(worldPosToUpdate.x, worldPosToUpdate.y, worldPosToUpdate.z, false); + } + } + } break; case SENDFLUIDDATA: { Globals.clientFluidManager.attachFluidMessage(message); } break; diff --git a/src/main/java/electrosphere/net/parser/net/message/NetworkMessage.java b/src/main/java/electrosphere/net/parser/net/message/NetworkMessage.java index fe97a9ad..5b7b9c06 100644 --- a/src/main/java/electrosphere/net/parser/net/message/NetworkMessage.java +++ b/src/main/java/electrosphere/net/parser/net/message/NetworkMessage.java @@ -214,6 +214,11 @@ public abstract class NetworkMessage { rVal = TerrainMessage.parseSendReducedBlockDataMessage(byteBuffer); } break; + case TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATEBLOCK: + if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){ + rVal = TerrainMessage.parseUpdateBlockMessage(byteBuffer); + } + break; case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA: if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){ rVal = TerrainMessage.parseRequestFluidDataMessage(byteBuffer); diff --git a/src/main/java/electrosphere/net/parser/net/message/TerrainMessage.java b/src/main/java/electrosphere/net/parser/net/message/TerrainMessage.java index 05bb96cd..d16e07c2 100644 --- a/src/main/java/electrosphere/net/parser/net/message/TerrainMessage.java +++ b/src/main/java/electrosphere/net/parser/net/message/TerrainMessage.java @@ -23,6 +23,7 @@ public class TerrainMessage extends NetworkMessage { SENDREDUCEDCHUNKDATA, REQUESTREDUCEDBLOCKDATA, SENDREDUCEDBLOCKDATA, + UPDATEBLOCK, REQUESTFLUIDDATA, SENDFLUIDDATA, UPDATEFLUIDDATA, @@ -56,6 +57,8 @@ public class TerrainMessage extends NetworkMessage { int chunkResolution; float terrainWeight; int terrainValue; + int blockType; + int blockMetadata; /** * Constructor @@ -406,6 +409,34 @@ public class TerrainMessage extends NetworkMessage { this.terrainValue = terrainValue; } + /** + * Gets blockType + */ + public int getblockType() { + return blockType; + } + + /** + * Sets blockType + */ + public void setblockType(int blockType) { + this.blockType = blockType; + } + + /** + * Gets blockMetadata + */ + public int getblockMetadata() { + return blockMetadata; + } + + /** + * Sets blockMetadata + */ + public void setblockMetadata(int blockMetadata) { + this.blockMetadata = blockMetadata; + } + /** * Removes the packet header from the buffer * @param byteBuffer The buffer @@ -482,6 +513,12 @@ public class TerrainMessage extends NetworkMessage { } case TypeBytes.TERRAIN_MESSAGE_TYPE_SENDREDUCEDBLOCKDATA: return TerrainMessage.canParseSendReducedBlockDataMessage(byteBuffer); + case TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATEBLOCK: + if(byteBuffer.getRemaining() >= TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATEBLOCK_SIZE){ + return true; + } else { + return false; + } case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA: if(byteBuffer.getRemaining() >= TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA_SIZE){ return true; @@ -935,6 +972,40 @@ public class TerrainMessage extends NetworkMessage { return rVal; } + /** + * Parses a message of type UpdateBlock + */ + public static TerrainMessage parseUpdateBlockMessage(CircularByteBuffer byteBuffer){ + TerrainMessage rVal = new TerrainMessage(TerrainMessageType.UPDATEBLOCK); + stripPacketHeader(byteBuffer); + rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); + rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); + rVal.setworldZ(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); + rVal.setvoxelX(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); + rVal.setvoxelY(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); + rVal.setvoxelZ(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); + rVal.setblockType(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); + rVal.setblockMetadata(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); + return rVal; + } + + /** + * Constructs a message of type UpdateBlock + */ + public static TerrainMessage constructUpdateBlockMessage(int worldX,int worldY,int worldZ,int voxelX,int voxelY,int voxelZ,int blockType,int blockMetadata){ + TerrainMessage rVal = new TerrainMessage(TerrainMessageType.UPDATEBLOCK); + rVal.setworldX(worldX); + rVal.setworldY(worldY); + rVal.setworldZ(worldZ); + rVal.setvoxelX(voxelX); + rVal.setvoxelY(voxelY); + rVal.setvoxelZ(voxelZ); + rVal.setblockType(blockType); + rVal.setblockMetadata(blockMetadata); + rVal.serialize(); + return rVal; + } + /** * Parses a message of type RequestFluidData */ @@ -1402,6 +1473,45 @@ public class TerrainMessage extends NetworkMessage { rawBytes[26+i] = chunkData[i]; } break; + case UPDATEBLOCK: + rawBytes = new byte[2+4+4+4+4+4+4+4+4]; + //message header + rawBytes[0] = TypeBytes.MESSAGE_TYPE_TERRAIN; + //entity messaage header + rawBytes[1] = TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATEBLOCK; + intValues = ByteStreamUtils.serializeIntToBytes(worldX); + for(int i = 0; i < 4; i++){ + rawBytes[2+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeIntToBytes(worldY); + for(int i = 0; i < 4; i++){ + rawBytes[6+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeIntToBytes(worldZ); + for(int i = 0; i < 4; i++){ + rawBytes[10+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeIntToBytes(voxelX); + for(int i = 0; i < 4; i++){ + rawBytes[14+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeIntToBytes(voxelY); + for(int i = 0; i < 4; i++){ + rawBytes[18+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeIntToBytes(voxelZ); + for(int i = 0; i < 4; i++){ + rawBytes[22+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeIntToBytes(blockType); + for(int i = 0; i < 4; i++){ + rawBytes[26+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeIntToBytes(blockMetadata); + for(int i = 0; i < 4; i++){ + rawBytes[30+i] = intValues[i]; + } + break; case REQUESTFLUIDDATA: rawBytes = new byte[2+4+4+4]; //message header diff --git a/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java b/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java index cd786137..e58b6824 100644 --- a/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java +++ b/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java @@ -78,9 +78,10 @@ public class TypeBytes { public static final byte TERRAIN_MESSAGE_TYPE_SENDREDUCEDCHUNKDATA = 9; public static final byte TERRAIN_MESSAGE_TYPE_REQUESTREDUCEDBLOCKDATA = 10; public static final byte TERRAIN_MESSAGE_TYPE_SENDREDUCEDBLOCKDATA = 11; - public static final byte TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA = 12; - public static final byte TERRAIN_MESSAGE_TYPE_SENDFLUIDDATA = 13; - public static final byte TERRAIN_MESSAGE_TYPE_UPDATEFLUIDDATA = 14; + public static final byte TERRAIN_MESSAGE_TYPE_UPDATEBLOCK = 12; + public static final byte TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA = 13; + public static final byte TERRAIN_MESSAGE_TYPE_SENDFLUIDDATA = 14; + public static final byte TERRAIN_MESSAGE_TYPE_UPDATEFLUIDDATA = 15; /* Terrain packet sizes */ @@ -93,6 +94,7 @@ public class TypeBytes { public static final byte TERRAIN_MESSAGE_TYPE_REQUESTCHUNKDATA_SIZE = 14; public static final byte TERRAIN_MESSAGE_TYPE_REQUESTREDUCEDCHUNKDATA_SIZE = 18; public static final byte TERRAIN_MESSAGE_TYPE_REQUESTREDUCEDBLOCKDATA_SIZE = 18; + public static final byte TERRAIN_MESSAGE_TYPE_UPDATEBLOCK_SIZE = 34; public static final byte TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA_SIZE = 14; /* diff --git a/src/main/java/electrosphere/net/server/protocol/TerrainProtocol.java b/src/main/java/electrosphere/net/server/protocol/TerrainProtocol.java index 5583d81f..3b33980a 100644 --- a/src/main/java/electrosphere/net/server/protocol/TerrainProtocol.java +++ b/src/main/java/electrosphere/net/server/protocol/TerrainProtocol.java @@ -82,6 +82,7 @@ public class TerrainProtocol implements ServerProtocolTemplate { case RESPONSEMETADATA: case SPAWNPOSITION: case UPDATEVOXEL: + case UPDATEBLOCK: case SENDCHUNKDATA: case SENDFLUIDDATA: case REQUESTREDUCEDCHUNKDATA: diff --git a/src/main/java/electrosphere/server/block/editing/ServerBlockEditing.java b/src/main/java/electrosphere/server/block/editing/ServerBlockEditing.java index 6cc90b38..5e50bd43 100644 --- a/src/main/java/electrosphere/server/block/editing/ServerBlockEditing.java +++ b/src/main/java/electrosphere/server/block/editing/ServerBlockEditing.java @@ -1,9 +1,10 @@ package electrosphere.server.block.editing; -import org.joml.Vector3d; import org.joml.Vector3i; +import electrosphere.client.block.BlockChunkData; import electrosphere.server.datacell.Realm; +import electrosphere.server.datacell.interfaces.VoxelCellManager; /** * Provides utilities for editing block (particularly brushes, etc) @@ -23,8 +24,24 @@ public class ServerBlockEditing { * @param type The new type of block * @param metadata The new metadata for the block */ - public static void editBlockChunk(Realm realm, Vector3d worldPos, Vector3i voxelPos, short type, short metadata){ - throw new UnsupportedOperationException("Unimplemented"); + public static void editBlockChunk(Realm realm, Vector3i worldPos, Vector3i voxelPos, short type, short metadata){ + if(realm != null && realm.getDataCellManager() instanceof VoxelCellManager){ + VoxelCellManager voxelCellManager = (VoxelCellManager) realm.getDataCellManager(); + + BlockChunkData data; + if( + voxelPos.x < BlockChunkData.CHUNK_DATA_WIDTH && + voxelPos.y < BlockChunkData.CHUNK_DATA_WIDTH && + voxelPos.z < BlockChunkData.CHUNK_DATA_WIDTH && + voxelPos.x >= 0 && + voxelPos.y >= 0 && + voxelPos.z >= 0 && + (data = voxelCellManager.getBlocksAtPosition(worldPos)) != null + ){ + data.setType(voxelPos.x, voxelPos.y, voxelPos.z, type); + voxelCellManager.editBlock(worldPos, voxelPos, type, metadata); + } + } } } diff --git a/src/main/java/electrosphere/server/block/manager/ServerBlockManager.java b/src/main/java/electrosphere/server/block/manager/ServerBlockManager.java index fb800134..82a6333d 100644 --- a/src/main/java/electrosphere/server/block/manager/ServerBlockManager.java +++ b/src/main/java/electrosphere/server/block/manager/ServerBlockManager.java @@ -174,7 +174,8 @@ public class ServerBlockManager { if(chunkCache.containsChunk(worldPos.x,worldPos.y,worldPos.z,BlockChunkData.LOD_FULL_RES)){ BlockChunkData chunk = chunkCache.get(worldPos.x,worldPos.y,worldPos.z, BlockChunkData.LOD_FULL_RES); chunk.setType(voxelPos.x, voxelPos.y, voxelPos.z, type); - chunk.setType(voxelPos.x, voxelPos.y, voxelPos.z, metadata); + chunk.setMetadata(voxelPos.x, voxelPos.y, voxelPos.z, metadata); + chunk.setHomogenousValue(BlockChunkData.NOT_HOMOGENOUS); } } diff --git a/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java b/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java index 745e600c..cf9dbe7c 100644 --- a/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java +++ b/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java @@ -30,6 +30,7 @@ import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.net.parser.net.message.TerrainMessage; import electrosphere.net.server.player.Player; import electrosphere.net.server.protocol.TerrainProtocol; +import electrosphere.server.block.manager.ServerBlockManager; import electrosphere.server.content.ServerContentManager; import electrosphere.server.datacell.interfaces.DataCellManager; import electrosphere.server.datacell.interfaces.VoxelCellManager; @@ -872,4 +873,49 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager generationService.shutdownNow(); } + @Override + /** + * Gets the block chunk data at a given world position + */ + public BlockChunkData getBlocksAtPosition(Vector3i worldPosition) { + return this.serverWorldData.getServerBlockManager().getChunk(worldPosition.x, worldPosition.y, worldPosition.z); + } + + @Override + /** + * Edits a block chunk in the world + */ + public void editBlock(Vector3i worldPosition, Vector3i voxelPosition, short type, short metadata) { + terrainEditLock.acquireUninterruptibly(); + if( + worldPosition.x >= 0 && worldPosition.x < this.serverWorldData.getWorldSizeDiscrete() && + worldPosition.y >= 0 && worldPosition.y < this.serverWorldData.getWorldSizeDiscrete() && + worldPosition.z >= 0 && worldPosition.z < this.serverWorldData.getWorldSizeDiscrete() + ){ + ServerBlockManager serverBlockManager = this.serverWorldData.getServerBlockManager(); + //update terrain + int localVoxelX = voxelPosition.x; + int localVoxelY = voxelPosition.y; + int localVoxelZ = voxelPosition.z; + serverBlockManager.editBlockAtLocationToValue(worldPosition, voxelPosition, type, metadata); + + //update anything loaded + this.loadedCellsLock.lock(); + ServerDataCell cell = groundDataCells.get(this.getServerDataCellKey(worldPosition)); + if(cell != null){ + //update physics + this.createTerrainPhysicsEntities(worldPosition); + + //broadcast update + cell.broadcastNetworkMessage(TerrainMessage.constructUpdateBlockMessage( + worldPosition.x, worldPosition.y, worldPosition.z, + localVoxelX, localVoxelY, localVoxelZ, + type, metadata + )); + } + this.loadedCellsLock.unlock(); + } + terrainEditLock.release(); + } + } diff --git a/src/main/java/electrosphere/server/datacell/interfaces/VoxelCellManager.java b/src/main/java/electrosphere/server/datacell/interfaces/VoxelCellManager.java index 8c9b06c8..cbb1d8ce 100644 --- a/src/main/java/electrosphere/server/datacell/interfaces/VoxelCellManager.java +++ b/src/main/java/electrosphere/server/datacell/interfaces/VoxelCellManager.java @@ -2,6 +2,7 @@ package electrosphere.server.datacell.interfaces; import org.joml.Vector3i; +import electrosphere.client.block.BlockChunkData; import electrosphere.server.fluid.manager.ServerFluidChunk; import electrosphere.server.terrain.manager.ServerTerrainChunk; @@ -42,6 +43,22 @@ public interface VoxelCellManager { */ public void editChunk(Vector3i worldPosition, Vector3i voxelPosition, float weight, int type); + /** + * Gets the block data at a given world position + * @param worldPosition The position in world coordinates + * @return The BlockChunkData of data at that position, or null if it is out of bounds or otherwise doesn't exist + */ + public BlockChunkData getBlocksAtPosition(Vector3i worldPosition); + + /** + * Edits a single block voxel + * @param worldPosition The world position of the block to edit + * @param voxelPosition The local block grid position of the block to edit + * @param type The type of block to set the position to + * @param metadata The metadata associated with the block type + */ + public void editBlock(Vector3i worldPosition, Vector3i voxelPosition, short type, short metadata); + /** * Gets the fluid chunk at a given world position diff --git a/src/main/java/electrosphere/server/player/PlayerActions.java b/src/main/java/electrosphere/server/player/PlayerActions.java index 3b38badc..b62bcf15 100644 --- a/src/main/java/electrosphere/server/player/PlayerActions.java +++ b/src/main/java/electrosphere/server/player/PlayerActions.java @@ -1,6 +1,7 @@ package electrosphere.server.player; import org.joml.Vector3d; +import org.joml.Vector3i; import electrosphere.client.item.ItemActions; import electrosphere.engine.Globals; @@ -13,9 +14,11 @@ import electrosphere.game.data.creature.type.CreatureData; import electrosphere.game.data.creature.type.block.BlockVariant; import electrosphere.game.data.item.Item; import electrosphere.game.data.item.ItemUsage; +import electrosphere.game.server.world.ServerWorldData; import electrosphere.logger.LoggerInterface; import electrosphere.net.parser.net.message.InventoryMessage; import electrosphere.net.server.ServerConnectionHandler; +import electrosphere.server.block.editing.ServerBlockEditing; import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.utils.EntityLookupUtils; @@ -83,16 +86,27 @@ public class PlayerActions { private static void secondaryUsage(Entity playerEntity, Item item, InventoryMessage message){ ItemUsage secondaryUsage = item.getSecondaryUsage(); Realm playerRealm = Globals.realmManager.getEntityRealm(playerEntity); + + //entity spawning if(secondaryUsage.getSpawnEntityId() != null){ Vector3d spawnPos = new Vector3d(message.getviewTargetX(),message.getviewTargetY(),message.getviewTargetZ()); CommonEntityUtils.serverSpawnBasicObject(playerRealm, spawnPos, secondaryUsage.getSpawnEntityId()); } + + //voxel block editing if(secondaryUsage.getBlockId() != null){ - Vector3d spawnPos = new Vector3d(message.getviewTargetX(),message.getviewTargetY(),message.getviewTargetZ()); - LoggerInterface.loggerEngine.WARNING("Spawn block type " + secondaryUsage.getBlockId() + " at " + spawnPos); + ServerWorldData serverWorldData = playerRealm.getServerWorldData(); + + //clamp the placement pos to the block grid.. + Vector3d placementPos = new Vector3d(message.getviewTargetX(),message.getviewTargetY(),message.getviewTargetZ()); + Vector3i worldPos = serverWorldData.convertRealToWorldSpace(placementPos); + Vector3i blockPos = serverWorldData.convertRealToLocalBlockSpace(placementPos); + + + //actually edit + ServerBlockEditing.editBlockChunk(playerRealm, worldPos, blockPos, (short)(int)secondaryUsage.getBlockId(), (short)0); + LoggerInterface.loggerEngine.DEBUG("Place block type " + secondaryUsage.getBlockId() + " at " + placementPos + " -> " + worldPos + " " + blockPos); } } - - } diff --git a/src/net/terrain.json b/src/net/terrain.json index 8b5c8cd2..6e4e1c77 100644 --- a/src/net/terrain.json +++ b/src/net/terrain.json @@ -115,6 +115,15 @@ { "name" : "terrainValue", "type" : "FIXED_INT" + }, + + { + "name" : "blockType", + "type" : "FIXED_INT" + }, + { + "name" : "blockMetadata", + "type" : "FIXED_INT" } ], "messageTypes" : [ @@ -249,6 +258,20 @@ "chunkData" ] }, + { + "messageName" : "UpdateBlock", + "description" : "Tells the client to update a voxel's value", + "data" : [ + "worldX", + "worldY", + "worldZ", + "voxelX", + "voxelY", + "voxelZ", + "blockType", + "blockMetadata" + ] + }, { "messageName" : "RequestFluidData", "description" : "Requests a fluid data from the server",