1 /**
2 Copyright: Copyright (c) 2015-2018 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 core.time : MonoTime, Duration;
12 
13 import pluginlib;
14 import voxelman.math;
15 import voxelman.core.config;
16 import voxelman.geometry.gridraytrace : 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 	vec3 cameraPos() { return graphics.camera.position; }
45 	vec3 cameraTraget() { return graphics.camera.target; }
46 
47 	// Cursor
48 	bool cursorHit;
49 	bool cameraInSolidBlock;
50 	BlockWorldPos blockPos;
51 	BlockWorldPos sideBlockPos; // blockPos + hitNormal
52 	ivec3 hitNormal;
53 
54 	// Cursor rendering stuff
55 	vec3 cursorPos;
56 	vec3 lineStart, lineEnd;
57 	bool traceVisible;
58 	ivec3 hitPosition;
59 	Duration cursorTraceTime;
60 	Batch traceBatch;
61 	Batch hitBatch;
62 
63 	mixin IdAndSemverFrom!"voxelman.worldinteraction.plugininfo";
64 
65 	override void init(IPluginManager pluginman)
66 	{
67 		connection = pluginman.getPlugin!NetClientPlugin;
68 		blockPlugin = pluginman.getPlugin!BlockPluginClient;
69 		evDispatcher = pluginman.getPlugin!EventDispatcherPlugin;
70 		graphics = pluginman.getPlugin!GraphicsPlugin;
71 		clientWorld = pluginman.getPlugin!ClientWorld;
72 
73 		evDispatcher.subscribeToEvent(&onUpdateEvent);
74 		evDispatcher.subscribeToEvent(&drawDebug);
75 	}
76 
77 	void onUpdateEvent(ref UpdateEvent event)
78 	{
79 		traceCursor();
80 		drawDebugCursor();
81 	}
82 
83 	BlockIdAndMeta pickBlock()
84 	{
85 		return clientWorld.worldAccess.getBlockIdAndMeta(blockPos);
86 	}
87 
88 	void fillBox(WorldBox box, BlockId blockId, BlockMetadata blockMeta = 0)
89 	{
90 		connection.send(FillBlockBoxPacket(box, blockId, blockMeta));
91 	}
92 
93 	void traceCursor()
94 	{
95 		MonoTime startTime = MonoTime.currTime;
96 
97 		traceBatch.reset();
98 
99 		cursorHit = traceRay(
100 			&clientWorld.isBlockSolid,
101 			graphics.camera.position,
102 			graphics.camera.target,
103 			600.0, // max distance
104 			hitPosition,
105 			hitNormal,
106 			traceBatch);
107 
108 		if (cursorHit) {
109 			import std.math : floor;
110 			auto camPos = graphics.camera.position;
111 			auto camBlock = ivec3(cast(int)floor(camPos.x), cast(int)floor(camPos.y), cast(int)floor(camPos.z));
112 			cameraInSolidBlock = BlockWorldPos(camBlock, 0) == BlockWorldPos(hitPosition, 0);
113 		} else {
114 			cameraInSolidBlock = false;
115 		}
116 
117 		blockPos = BlockWorldPos(hitPosition, clientWorld.currentDimension);
118 		sideBlockPos = BlockWorldPos(blockPos.xyz + hitNormal, clientWorld.currentDimension);
119 		cursorTraceTime = MonoTime.currTime - startTime;
120 	}
121 
122 	void drawDebugCursor()
123 	{
124 		if (traceVisible)
125 		{
126 			traceBatch.putCube(cursorPos, cursorSize, Colors.black, false);
127 			traceBatch.putLine(lineStart, lineEnd, Colors.black);
128 		}
129 	}
130 
131 	void drawCursor(BlockWorldPos block, Color4ub color)
132 	{
133 		if (!cameraInSolidBlock && cursorHit)
134 		{
135 			graphics.debugBatch.putCube(
136 				vec3(block.xyz) - cursorOffset,
137 				cursorSize, color, false);
138 		}
139 	}
140 
141 	void drawDebug(ref RenderSolid3dEvent event)
142 	{
143 		//graphics.draw(hitBatch);
144 	}
145 }