1 /** 2 Copyright: Copyright (c) 2015-2017 Andrey Penechko. 3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 7 module voxelman.worldinteraction.plugin; 8 9 import voxelman.log; 10 import core.time; 11 import std.datetime : StopWatch; 12 13 import pluginlib; 14 import voxelman.math; 15 import voxelman.core.config; 16 import voxelman.utils.trace : traceRay; 17 import voxelman.world.block; 18 19 import voxelman.core.events; 20 import voxelman.core.packets; 21 import voxelman.world.storage.coordinates; 22 import voxelman.world.storage.worldbox; 23 import voxelman.world.blockentity.blockentityaccess; 24 25 import voxelman.block.plugin; 26 import voxelman.eventdispatcher.plugin; 27 import voxelman.graphics.plugin; 28 import voxelman.input.plugin; 29 import voxelman.net.plugin; 30 import voxelman.world.clientworld; 31 32 33 enum cursorSize = vec3(1.02, 1.02, 1.02); 34 enum cursorOffset = vec3(0.01, 0.01, 0.01); 35 36 class WorldInteractionPlugin : IPlugin 37 { 38 NetClientPlugin connection; 39 EventDispatcherPlugin evDispatcher; 40 GraphicsPlugin graphics; 41 BlockPluginClient blockPlugin; 42 ClientWorld clientWorld; 43 44 // Cursor 45 bool cursorHit; 46 bool cameraInSolidBlock; 47 BlockWorldPos blockPos; 48 BlockWorldPos sideBlockPos; // blockPos + hitNormal 49 ivec3 hitNormal; 50 51 // Cursor rendering stuff 52 vec3 cursorPos; 53 vec3 lineStart, lineEnd; 54 bool traceVisible; 55 vec3 hitPosition; 56 Duration cursorTraceTime; 57 Batch traceBatch; 58 Batch hitBatch; 59 60 mixin IdAndSemverFrom!"voxelman.worldinteraction.plugininfo"; 61 62 override void init(IPluginManager pluginman) 63 { 64 connection = pluginman.getPlugin!NetClientPlugin; 65 blockPlugin = pluginman.getPlugin!BlockPluginClient; 66 evDispatcher = pluginman.getPlugin!EventDispatcherPlugin; 67 graphics = pluginman.getPlugin!GraphicsPlugin; 68 clientWorld = pluginman.getPlugin!ClientWorld; 69 70 evDispatcher.subscribeToEvent(&onUpdateEvent); 71 evDispatcher.subscribeToEvent(&drawDebug); 72 } 73 74 void onUpdateEvent(ref UpdateEvent event) 75 { 76 traceCursor(); 77 drawDebugCursor(); 78 } 79 80 BlockIdAndMeta pickBlock() 81 { 82 return clientWorld.worldAccess.getBlockIdAndMeta(blockPos); 83 } 84 85 void fillBox(WorldBox box, BlockId blockId, BlockMetadata blockMeta = 0) 86 { 87 connection.send(FillBlockBoxPacket(box, blockId, blockMeta)); 88 } 89 90 void traceCursor() 91 { 92 StopWatch sw; 93 sw.start(); 94 95 traceBatch.reset(); 96 97 cursorHit = traceRay( 98 &clientWorld.isBlockSolid, 99 graphics.camera.position, 100 graphics.camera.target, 101 600.0, // max distance 102 hitPosition, 103 hitNormal, 104 traceBatch); 105 106 if (cursorHit) { 107 import std.math : floor; 108 auto camPos = graphics.camera.position; 109 auto camBlock = ivec3(cast(int)floor(camPos.x), cast(int)floor(camPos.y), cast(int)floor(camPos.z)); 110 cameraInSolidBlock = BlockWorldPos(camBlock, 0) == BlockWorldPos(hitPosition, 0); 111 } else { 112 cameraInSolidBlock = false; 113 } 114 115 blockPos = BlockWorldPos(hitPosition, clientWorld.currentDimension); 116 sideBlockPos = BlockWorldPos(blockPos.xyz + hitNormal, clientWorld.currentDimension); 117 cursorTraceTime = cast(Duration)sw.peek; 118 } 119 120 void drawDebugCursor() 121 { 122 if (traceVisible) 123 { 124 traceBatch.putCube(cursorPos, cursorSize, Colors.black, false); 125 traceBatch.putLine(lineStart, lineEnd, Colors.black); 126 } 127 } 128 129 void drawCursor(BlockWorldPos block, Color4ub color) 130 { 131 graphics.debugBatch.putCube( 132 vec3(block.xyz) - cursorOffset, 133 cursorSize, color, false); 134 } 135 136 void drawDebug(ref RenderSolid3dEvent event) 137 { 138 //graphics.draw(hitBatch); 139 } 140 }