1 /**
2 Copyright: Copyright (c) 2015-2016 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 std.experimental.logger;
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.block.utils;
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.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 shared static this()
34 {
35 	pluginRegistry.regClientPlugin(new WorldInteractionPlugin);
36 }
37 
38 enum cursorSize = vec3(1.02, 1.02, 1.02);
39 enum cursorOffset = vec3(0.01, 0.01, 0.01);
40 
41 class WorldInteractionPlugin : IPlugin
42 {
43 	NetClientPlugin connection;
44 	EventDispatcherPlugin evDispatcher;
45 	GraphicsPlugin graphics;
46 	BlockPluginClient blockPlugin;
47 	ClientWorld clientWorld;
48 
49 	// Cursor
50 	bool cursorHit;
51 	bool cameraInSolidBlock;
52 	BlockWorldPos blockPos;
53 	BlockWorldPos sideBlockPos; // blockPos + hitNormal
54 	ivec3 hitNormal;
55 
56 	// Cursor rendering stuff
57 	vec3 cursorPos;
58 	vec3 lineStart, lineEnd;
59 	bool traceVisible;
60 	vec3 hitPosition;
61 	Duration cursorTraceTime;
62 	Batch traceBatch;
63 	Batch hitBatch;
64 
65 	mixin IdAndSemverFrom!(voxelman.worldinteraction.plugininfo);
66 
67 	override void init(IPluginManager pluginman)
68 	{
69 		connection = pluginman.getPlugin!NetClientPlugin;
70 		blockPlugin = pluginman.getPlugin!BlockPluginClient;
71 		evDispatcher = pluginman.getPlugin!EventDispatcherPlugin;
72 		graphics = pluginman.getPlugin!GraphicsPlugin;
73 		clientWorld = pluginman.getPlugin!ClientWorld;
74 
75 		evDispatcher.subscribeToEvent(&onUpdateEvent);
76 		evDispatcher.subscribeToEvent(&drawDebug);
77 	}
78 
79 	void onUpdateEvent(ref UpdateEvent event)
80 	{
81 		traceCursor();
82 		drawDebugCursor();
83 	}
84 
85 	BlockId pickBlock()
86 	{
87 		return clientWorld.worldAccess.getBlock(blockPos);
88 	}
89 
90 	void fillBox(WorldBox box, BlockId blockId)
91 	{
92 		connection.send(FillBlockBoxPacket(box, blockId));
93 	}
94 
95 	void traceCursor()
96 	{
97 		StopWatch sw;
98 		sw.start();
99 
100 		auto isBlockSolid = (ivec3 blockWorldPos) {
101 			auto block = clientWorld.worldAccess.getBlock(
102 				BlockWorldPos(blockWorldPos, clientWorld.currentDimention));
103 			return blockPlugin.getBlocks()[block].isVisible;
104 		};
105 
106 		traceBatch.reset();
107 
108 		cursorHit = traceRay(
109 			isBlockSolid,
110 			graphics.camera.position,
111 			graphics.camera.target,
112 			600.0, // max distance
113 			hitPosition,
114 			hitNormal,
115 			traceBatch);
116 
117 		if (cursorHit) {
118 			import std.math : floor;
119 			auto camPos = graphics.camera.position;
120 			auto camBlock = ivec3(cast(int)floor(camPos.x), cast(int)floor(camPos.y), cast(int)floor(camPos.z));
121 			cameraInSolidBlock = BlockWorldPos(camBlock, 0) == BlockWorldPos(hitPosition, 0);
122 		} else {
123 			cameraInSolidBlock = false;
124 		}
125 
126 		blockPos = BlockWorldPos(hitPosition, clientWorld.currentDimention);
127 		sideBlockPos = BlockWorldPos(blockPos.xyz + hitNormal, clientWorld.currentDimention);
128 		cursorTraceTime = cast(Duration)sw.peek;
129 	}
130 
131 	void drawDebugCursor()
132 	{
133 		if (traceVisible)
134 		{
135 			traceBatch.putCube(cursorPos, cursorSize, Colors.black, false);
136 			traceBatch.putLine(lineStart, lineEnd, Colors.black);
137 		}
138 	}
139 
140 	void drawCursor(BlockWorldPos block, Color3ub color)
141 	{
142 		graphics.debugBatch.putCube(
143 			vec3(block.xyz) - cursorOffset,
144 			cursorSize, color, false);
145 	}
146 
147 	void drawDebug(ref RenderSolid3dEvent event)
148 	{
149 		//graphics.draw(hitBatch);
150 	}
151 }