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.entity.plugin; 8 9 import std.experimental.logger; 10 import std.array : empty; 11 12 import cbor; 13 import pluginlib; 14 import datadriven.api; 15 16 import voxelman.eventdispatcher.plugin; 17 import voxelman.net.plugin; 18 import voxelman.core.events; 19 20 shared static this() 21 { 22 pluginRegistry.regClientPlugin(new EntityPluginClient); 23 pluginRegistry.regServerPlugin(new EntityPluginServer); 24 } 25 26 struct EntityManager 27 { 28 private EntityId lastEntityId; 29 30 EntityId nextEntityId() 31 { 32 return ++lastEntityId; 33 } 34 } 35 36 struct ComponentInfo 37 { 38 string name; 39 ComponentUnpacker unpacker; 40 TypeInfo componentType; 41 size_t id; 42 } 43 44 struct ComponentSyncPacket 45 { 46 size_t componentId; 47 ubyte[] componentData; 48 } 49 50 struct ProcessComponentsEvent { 51 float deltaTime; 52 Profiler profiler; 53 bool continuePropagation = true; 54 } 55 56 struct SyncComponentsEvent { 57 Profiler profiler; 58 bool continuePropagation = true; 59 } 60 61 final class EntityPluginClient : IPlugin 62 { 63 mixin EntityPluginCommon; 64 mixin EntityPluginClientImpl; 65 } 66 67 final class EntityPluginServer : IPlugin 68 { 69 mixin EntityPluginCommon; 70 mixin EntityPluginServerImpl; 71 } 72 73 alias ComponentUnpacker = void delegate(ubyte[] componentData); 74 75 mixin template EntityPluginCommon() 76 { 77 mixin IdAndSemverFrom!(voxelman.entity.plugininfo); 78 79 EventDispatcherPlugin evDispatcher; 80 EntityManager entityManager; 81 82 ComponentInfo*[] componentArray; 83 ComponentInfo*[TypeInfo] componentMap; 84 85 override void init(IPluginManager pluginman) 86 { 87 evDispatcher = pluginman.getPlugin!EventDispatcherPlugin; 88 evDispatcher.subscribeToEvent(&onUpdateEvent); 89 evDispatcher.subscribeToEvent(&onPostUpdateEvent); 90 connection = pluginman.getPlugin!(typeof(connection)); 91 connection.registerPacket!ComponentSyncPacket(&handleComponentSyncPacket); 92 } 93 94 void registerComponent(C)(ComponentUnpacker unpacker = null, string componentName = C.stringof) 95 { 96 size_t newId = componentArray.length; 97 ComponentInfo* cinfo = new ComponentInfo(componentName, unpacker, typeid(C), newId); 98 componentArray ~= cinfo; 99 assert(typeid(C) !in componentMap); 100 componentMap[typeid(C)] = cinfo; 101 } 102 103 void onUpdateEvent(ref UpdateEvent event) 104 { 105 evDispatcher.postEvent(ProcessComponentsEvent(event.deltaTime)); 106 } 107 108 void onPostUpdateEvent(ref PostUpdateEvent event) 109 { 110 evDispatcher.postEvent(SyncComponentsEvent()); 111 } 112 } 113 114 mixin template EntityPluginClientImpl() 115 { 116 NetClientPlugin connection; 117 118 void unpackComponents(Storage)(ref Storage storage, ubyte[] data) 119 { 120 storage.removeAll(); 121 while(!data.empty) 122 { 123 storage.add(decodeCborSingle!size_t(data), decodeCborSingle!(componentType!Storage)(data)); 124 } 125 } 126 127 void handleComponentSyncPacket(ubyte[] packetData, ClientId clientId) 128 { 129 auto componentId = decodeCborSingle!size_t(packetData); 130 131 if (componentId >= componentArray.length) 132 return; // out of range 133 134 auto unpacker = componentArray[componentId].unpacker; 135 if (unpacker is null) 136 return; // unpacker is not set 137 138 unpacker(packetData); 139 } 140 } 141 142 mixin template EntityPluginServerImpl() 143 { 144 NetServerPlugin connection; 145 146 void sendComponents(Storage)(Storage storage) 147 { 148 auto componentId = componentMap[typeid(componentType!Storage)].id; 149 auto packetData = createComponentPacket(componentId, storage); 150 if (packetData.length > 0) 151 connection.sendToAll(packetData); 152 } 153 154 ubyte[] createComponentPacket(Storage)(size_t componentId, Storage storage) 155 { 156 ubyte[] bufferTemp = connection.buffer; 157 size_t size; 158 159 size = encodeCbor(bufferTemp[], connection.packetId!ComponentSyncPacket); 160 size += encodeCbor(bufferTemp[size..$], componentId); 161 162 foreach(pair; storage.byKeyValue()) 163 { 164 size += encodeCbor(bufferTemp[size..$], pair.key); 165 size += encodeCbor(bufferTemp[size..$], pair.value); 166 } 167 168 return bufferTemp[0..size]; 169 } 170 171 void handleComponentSyncPacket(ubyte[] packetData, ClientId clientId) 172 { 173 } 174 }