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 }