1 /** 2 Copyright: Copyright (c) 2016 Andrey Penechko. 3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 module voxelman.blockentity.plugin; 7 8 import std.experimental.logger; 9 10 import pluginlib; 11 import voxelman.container.buffer; 12 import voxelman.math; 13 14 import derelict.imgui.imgui; 15 import voxelman.utils.textformatter; 16 import voxelman.utils.mapping; 17 18 import voxelman.block.utils; 19 import voxelman.core.config; 20 import voxelman.core.events; 21 import voxelman.core.packets; 22 import voxelman.core.chunkmesh; 23 import voxelman.world.storage.coordinates; 24 import voxelman.world.storage.worldbox; 25 26 import voxelman.block.plugin; 27 import voxelman.edit.plugin; 28 import voxelman.eventdispatcher.plugin; 29 import voxelman.graphics.plugin; 30 import voxelman.net.plugin; 31 import voxelman.world.clientworld; 32 import voxelman.worldinteraction.plugin; 33 34 public import voxelman.blockentity.blockentityaccess; 35 public import voxelman.blockentity.blockentitydata; 36 public import voxelman.blockentity.blockentitymap; 37 public import voxelman.blockentity.utils; 38 39 final class BlockEntityClient : IPlugin { 40 mixin IdAndSemverFrom!(voxelman.blockentity.plugininfo); 41 mixin BlockEntityCommon; 42 43 private ClientWorld clientWorld; 44 private WorldInteractionPlugin worldInteraction; 45 private BlockPluginClient blockPlugin; 46 private GraphicsPlugin graphics; 47 private NetClientPlugin connection; 48 49 override void init(IPluginManager pluginman) 50 { 51 clientWorld = pluginman.getPlugin!ClientWorld; 52 worldInteraction = pluginman.getPlugin!WorldInteractionPlugin; 53 blockPlugin = pluginman.getPlugin!BlockPluginClient; 54 graphics = pluginman.getPlugin!GraphicsPlugin; 55 56 EventDispatcherPlugin evDispatcher = pluginman.getPlugin!EventDispatcherPlugin; 57 evDispatcher.subscribeToEvent(&onUpdateEvent); 58 59 connection = pluginman.getPlugin!NetClientPlugin; 60 61 auto removeEntityTool = new class ITool 62 { 63 this() { name = "test.blockentity.block_entity"; } 64 65 bool placing; 66 WorldBox selection; 67 BlockWorldPos startingPos; 68 69 override void onUpdate() { 70 auto cursor = worldInteraction.sideBlockPos; 71 selection = worldBoxFromCorners(startingPos.xyz, 72 cursor.xyz, cast(DimentionId)cursor.w); 73 drawSelection(); 74 } 75 76 // remove 77 override void onMainActionRelease() { 78 if (placing) return; 79 auto blockId = worldInteraction.pickBlock(); 80 if (isBlockEntity(blockId)) { 81 connection.send(RemoveBlockEntityPacket(worldInteraction.blockPos.vector.arrayof)); 82 } 83 } 84 85 // place 86 override void onSecondaryActionPress() { 87 placing = true; 88 startingPos = worldInteraction.sideBlockPos; 89 } 90 override void onSecondaryActionRelease() { 91 if (placing) { 92 ulong sizeData = sizeToEntityData(selection.size); 93 ulong payload = payloadFromIdAndEntityData( 94 blockEntityMan.getId("multi"), sizeData); 95 connection.send(PlaceBlockEntityPacket(selection, payload)); 96 placing = false; 97 } 98 } 99 100 void drawSelection() { 101 if (placing) { 102 graphics.debugBatch.putCube(vec3(selection.position) - cursorOffset, 103 vec3(selection.size) + cursorOffset, Colors.blue, false); 104 } else { 105 if (!worldInteraction.cameraInSolidBlock) 106 { 107 worldInteraction.drawCursor(worldInteraction.sideBlockPos, Colors.blue); 108 } 109 } 110 } 111 }; 112 113 auto editPlugin = pluginman.getPlugin!EditPlugin; 114 editPlugin.registerTool(removeEntityTool); 115 } 116 117 void onUpdateEvent(ref UpdateEvent event) 118 { 119 auto blockId = worldInteraction.pickBlock(); 120 auto cwp = ChunkWorldPos(worldInteraction.blockPos); 121 igBegin("Debug"); 122 if (isBlockEntity(blockId)) 123 { 124 ushort blockIndex = blockIndexFromBlockId(blockId); 125 BlockEntityData entity = clientWorld.entityAccess.getBlockEntity(cwp, blockIndex); 126 with(BlockEntityType) final switch(entity.type) 127 { 128 case localBlockEntity: 129 BlockEntityInfo eInfo = blockEntityInfos[entity.id]; 130 auto entityBwp = BlockWorldPos(cwp, blockIndex); 131 WorldBox eVol = eInfo.boxHandler(entityBwp, entity); 132 133 igTextf("Entity(main): ind %s: id %s %s %s", 134 blockIndex, entity.id, eInfo.name, eVol); 135 if (eInfo.debugHandler) 136 eInfo.debugHandler(entityBwp, entity); 137 138 voxelman.world.storage.worldbox.putCube(graphics.debugBatch, eVol, Colors.red, false); 139 break; 140 case foreignBlockEntity: 141 auto mainPtr = entity.mainChunkPointer; 142 143 auto mainCwp = ChunkWorldPos(ivec3(cwp.xyz) - mainPtr.mainChunkOffset, cwp.w); 144 BlockEntityData mainEntity = clientWorld.entityAccess.getBlockEntity(mainCwp, mainPtr.blockIndex); 145 auto mainBwp = BlockWorldPos(mainCwp, mainPtr.blockIndex); 146 147 BlockEntityInfo eInfo = blockEntityInfos[mainPtr.entityId]; 148 WorldBox eVol = eInfo.boxHandler(mainBwp, mainEntity); 149 150 igTextf("Entity(other): ind %s mid %s mind %s moff %s", 151 blockIndex, mainPtr.entityId, 152 mainPtr.blockIndex, mainPtr.mainChunkOffset); 153 igTextf(" %s %s", eInfo.name, eVol); 154 155 voxelman.world.storage.worldbox.putCube(graphics.debugBatch, eVol, Colors.red, false); 156 break; 157 //case componentId: 158 // igTextf("Entity: @%s: entity id %s", blockIndex, entity.payload); break; 159 } 160 } 161 else 162 { 163 igTextf("Block: %s %s", blockId, blockPlugin.getBlocks()[blockId].name); 164 } 165 igEnd(); 166 } 167 } 168 169 final class BlockEntityServer : IPlugin { 170 mixin IdAndSemverFrom!(voxelman.blockentity.plugininfo); 171 mixin BlockEntityCommon; 172 } 173 174 mixin template BlockEntityCommon() 175 { 176 override void registerResourceManagers(void delegate(IResourceManager) reg) { 177 blockEntityMan = new BlockEntityManager; 178 blockEntityMan.regBlockEntity("unknown") // 0 179 .boxHandler(&nullBoxHandler); 180 blockEntityMan.regBlockEntity("multi") 181 .boxHandler(&multichunkBoxHandler) 182 .meshHandler(&multichunkMeshHandler); 183 //.debugHandler(&multichunkDebugHandler); 184 reg(blockEntityMan); 185 } 186 BlockEntityManager blockEntityMan; 187 188 BlockEntityInfoTable blockEntityInfos() { 189 return BlockEntityInfoTable(cast(immutable)blockEntityMan.blockEntityMapping.infoArray); 190 } 191 } 192 193 void multichunkMeshHandler( 194 Buffer!MeshVertex[] output, 195 BlockEntityData data, 196 ubyte[3] color, 197 ubyte sides, 198 //ivec3 worldPos, 199 ivec3 chunkPos, 200 ivec3 entityPos) 201 { 202 static ubyte[3] mainColor = [60,0,0]; 203 static ubyte[3] otherColor = [0,0,60]; 204 205 ubyte[3] col; 206 if (data.type == BlockEntityType.localBlockEntity) 207 col = mainColor; 208 else 209 col = otherColor; 210 211 makeColoredBlockMesh(output[Solidity.solid], col, 212 cast(ubyte)chunkPos.x, 213 cast(ubyte)chunkPos.y, 214 cast(ubyte)chunkPos.z, 215 sides); 216 } 217 218 WorldBox multichunkBoxHandler(BlockWorldPos bwp, BlockEntityData data) 219 { 220 ulong sizeData = data.entityData; 221 ivec3 size = entityDataToSize(sizeData); 222 return WorldBox(bwp.xyz, size, cast(ushort)bwp.w); 223 } 224 225 void multichunkDebugHandler(BlockWorldPos bwp, BlockEntityData data) 226 { 227 ulong sizeData = data.entityData; 228 ivec3 size = entityDataToSize(sizeData); 229 //auto vol = WorldBox(bwp.xyz, size, cast(ushort)bwp.w); 230 } 231 232 struct BlockEntityInfoSetter 233 { 234 private Mapping!(BlockEntityInfo)* mapping; 235 private size_t blockId; 236 private ref BlockEntityInfo info() {return (*mapping)[blockId]; } 237 238 ref BlockEntityInfoSetter color(ubyte[3] color ...) { info.color = color; return this; } 239 ref BlockEntityInfoSetter colorHex(uint hex) { info.color = [(hex>>16)&0xFF,(hex>>8)&0xFF,hex&0xFF]; return this; } 240 //ref BlockEntityInfoSetter isVisible(bool val) { info.isVisible = val; return this; } 241 ref BlockEntityInfoSetter meshHandler(BlockEntityMeshhandler val) { info.meshHandler = val; return this; } 242 ref BlockEntityInfoSetter sideSolidity(SolidityHandler val) { info.sideSolidity = val; return this; } 243 ref BlockEntityInfoSetter boxHandler(EntityBoxHandler val) { info.boxHandler = val; return this; } 244 ref BlockEntityInfoSetter debugHandler(EntityDebugHandler val) { info.debugHandler = val; return this; } 245 } 246 247 final class BlockEntityManager : IResourceManager 248 { 249 private: 250 Mapping!BlockEntityInfo blockEntityMapping; 251 252 public: 253 override string id() @property { return "voxelman.blockentity.blockentitymanager"; } 254 255 BlockEntityInfoSetter regBlockEntity(string name) { 256 size_t id = blockEntityMapping.put(BlockEntityInfo(name)); 257 assert(id <= ushort.max); 258 return BlockEntityInfoSetter(&blockEntityMapping, id); 259 } 260 261 ushort getId(string name) { 262 return cast(ushort)blockEntityMapping.id(name); 263 } 264 }