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.entity.plugin;
8 
9 import voxelman.log;
10 import std.array : empty;
11 
12 import cbor;
13 import pluginlib;
14 import datadriven;
15 import voxelman.container.buffer;
16 import voxelman.core.events;
17 
18 import voxelman.eventdispatcher.plugin;
19 import voxelman.net.plugin;
20 import voxelman.world.clientworld;
21 import voxelman.world.serverworld;
22 import voxelman.world.storage : IoManager, StringMap, IoKey, PluginDataLoader, PluginDataSaver, IoStorageType;
23 
24 import voxelman.entity.entityobservermanager;
25 
26 
27 struct ProcessComponentsEvent {
28 	float deltaTime;
29 }
30 
31 struct ComponentSyncPacket
32 {
33 	ubyte[] data;
34 }
35 
36 struct ComponentSyncStartPacket {}
37 struct ComponentSyncEndPacket {}
38 
39 /// Use EntityComponentRegistry to receive EntityManager pointer.
40 final class EntityComponentRegistry : IResourceManager
41 {
42 	EntityManager* eman;
43 	override string id() @property { return "voxelman.entity.componentregistry"; }
44 }
45 
46 mixin template EntityPluginCommon()
47 {
48 	private EntityComponentRegistry componentRegistry;
49 	private EntityManager eman;
50 	private EntityObserverManager entityObserverManager;
51 	private EntityIdManager eidMan;
52 
53 	override void registerResourceManagers(void delegate(IResourceManager) registerHandler)
54 	{
55 		componentRegistry = new EntityComponentRegistry();
56 		eman.eidMan = &eidMan;
57 		componentRegistry.eman = &eman;
58 		registerHandler(componentRegistry);
59 	}
60 }
61 
62 immutable string componentMapKey = "voxelman.entity.componentmap";
63 
64 final class EntityPluginClient : IPlugin
65 {
66 	mixin IdAndSemverFrom!"voxelman.entity.plugininfo";
67 	mixin EntityPluginCommon;
68 
69 	private EventDispatcherPlugin evDispatcher;
70 	private NetClientPlugin connection;
71 	private ClientWorld clientWorld;
72 
73 	override void init(IPluginManager pluginman)
74 	{
75 		evDispatcher = pluginman.getPlugin!EventDispatcherPlugin;
76 		evDispatcher.subscribeToEvent(&onUpdateEvent);
77 		clientWorld = pluginman.getPlugin!ClientWorld;
78 		connection = pluginman.getPlugin!NetClientPlugin;
79 		connection.registerPacket!ComponentSyncStartPacket(&handleComponentSyncStartPacket);
80 		connection.registerPacket!ComponentSyncPacket(&handleComponentSyncPacket);
81 		connection.registerPacket!ComponentSyncEndPacket(&handleComponentSyncEndPacket);
82 	}
83 
84 	private void onUpdateEvent(ref UpdateEvent event)
85 	{
86 		evDispatcher.postEvent(ProcessComponentsEvent(event.deltaTime));
87 	}
88 
89 	private void handleComponentSyncStartPacket(ubyte[] packetData)
90 	{
91 		eman.removeSerializedComponents(IoStorageType.network);
92 	}
93 
94 	private void handleComponentSyncPacket(ubyte[] packetData)
95 	{
96 		auto packet = unpackPacketNoDup!ComponentSyncPacket(packetData);
97 
98 		NetworkLoader netLoader;
99 		netLoader.stringMap = &clientWorld.serverStrings;
100 
101 		ubyte[] data = packet.data;
102 		while(!data.empty)
103 		{
104 			ubyte[4] _key = data[$-4..$];
105 			uint key = *cast(uint*)&_key;
106 			uint entrySize = *cast(uint*)(data[$-4-4..$-4].ptr);
107 			ubyte[] entry = data[$-4-4-entrySize..$-4-4];
108 			netLoader.ioKeyToData[key] = entry;
109 			data = data[0..$-4-4-entrySize];
110 		}
111 
112 		enum bool clearComponents = false;
113 		eman.load(netLoader, clearComponents);
114 		netLoader.ioKeyToData.clear();
115 	}
116 
117 	private void handleComponentSyncEndPacket(ubyte[] packetData)
118 	{
119 
120 	}
121 }
122 
123 final class EntityPluginServer : IPlugin
124 {
125 	mixin IdAndSemverFrom!"voxelman.entity.plugininfo";
126 	mixin EntityPluginCommon;
127 
128 	EventDispatcherPlugin evDispatcher;
129 	NetServerPlugin connection;
130 	EntityObserverManager entityObserverManager;
131 
132 	override void registerResources(IResourceManagerRegistry resmanRegistry)
133 	{
134 		auto ioman = resmanRegistry.getResourceManager!IoManager;
135 		ioman.registerWorldLoadSaveHandlers(&load, &save);
136 		entityObserverManager.netSaver.stringMap = ioman.getStringMap();
137 		entityObserverManager.eman = &eman;
138 	}
139 
140 	override void init(IPluginManager pluginman)
141 	{
142 		evDispatcher = pluginman.getPlugin!EventDispatcherPlugin;
143 		evDispatcher.subscribeToEvent(&onUpdateEvent);
144 		evDispatcher.subscribeToEvent(&onPostUpdateEvent);
145 		connection = pluginman.getPlugin!NetServerPlugin;
146 		connection.registerPacket!ComponentSyncStartPacket();
147 		connection.registerPacket!ComponentSyncPacket();
148 		connection.registerPacket!ComponentSyncEndPacket();
149 
150 		entityObserverManager.connection = connection;
151 		auto world = pluginman.getPlugin!ServerWorld;
152 		entityObserverManager.chunkObserverManager = world.chunkObserverManager;
153 	}
154 
155 	private void onUpdateEvent(ref UpdateEvent event)
156 	{
157 		evDispatcher.postEvent(ProcessComponentsEvent(event.deltaTime));
158 	}
159 
160 	private void onPostUpdateEvent(ref PostUpdateEvent)
161 	{
162 		entityObserverManager.sendEntitiesToObservers();
163 	}
164 
165 	private void load(ref PluginDataLoader loader)
166 	{
167 		eman.eidMan.load(loader);
168 		eman.load(loader);
169 	}
170 
171 	private void save(ref PluginDataSaver saver)
172 	{
173 		eman.eidMan.save(saver);
174 		eman.save(saver);
175 	}
176 }
177 
178 struct NetworkSaver
179 {
180 	StringMap* stringMap;
181 	package Buffer!ubyte buffer;
182 	package size_t prevDataLength;
183 
184 	IoStorageType storageType() { return IoStorageType.network; }
185 
186 	Buffer!ubyte* beginWrite() {
187 		prevDataLength = buffer.data.length;
188 		return &buffer;
189 	}
190 
191 	void endWrite(ref IoKey key) {
192 		uint entrySize = cast(uint)(buffer.data.length - prevDataLength);
193 		// dont write empty entries, since loader will return empty array for non-existing entries
194 		if (entrySize == 0) return;
195 		buffer.put(*cast(ubyte[4]*)&entrySize);
196 		uint int_key = stringMap.get(key);
197 		buffer.put(*cast(ubyte[4]*)&int_key);
198 	}
199 
200 	void reset() { buffer.clear(); }
201 
202 	ubyte[] data() { return buffer.data; }
203 }
204 
205 struct NetworkLoader
206 {
207 	StringMap* stringMap;
208 	ubyte[][uint] ioKeyToData;
209 
210 	IoStorageType storageType() { return IoStorageType.network; }
211 
212 	ubyte[] readEntryRaw(ref IoKey key) {
213 		uint intKey = stringMap.get(key);
214 		auto data = ioKeyToData.get(intKey, null);
215 		return data;
216 	}
217 }