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.net.plugin;
8 
9 import derelict.enet.enet;
10 
11 import pluginlib;
12 public import netlib;
13 import derelict.enet.enet;
14 
15 import voxelman.core.config;
16 import voxelman.net.events;
17 import voxelman.core.events;
18 import voxelman.core.packets;
19 import voxelman.net.packets;
20 
21 import voxelman.eventdispatcher.plugin;
22 import voxelman.config.configmanager;
23 
24 shared static this()
25 {
26 	pluginRegistry.regClientPlugin(new NetClientPlugin);
27 	pluginRegistry.regServerPlugin(new NetServerPlugin);
28 }
29 
30 mixin template NetCommon()
31 {
32 	mixin IdAndSemverFrom!(voxelman.net.plugininfo);
33 	private EventDispatcherPlugin evDispatcher;
34 
35 	override void preInit() {
36 		import voxelman.utils.libloader;
37 		loadEnet([getLibName(BUILD_TO_ROOT_PATH, "enet")]);
38 
39 		connection.connectHandler = &onConnect;
40 		connection.disconnectHandler = &onDisconnect;
41 		voxelman.net.packets.registerPackets(connection);
42 		voxelman.core.packets.registerPackets(connection);
43 	}
44 
45 	override void init(IPluginManager pluginman) {
46 		evDispatcher = pluginman.getPlugin!EventDispatcherPlugin;
47 	}
48 }
49 
50 final class NetClientPlugin : IPlugin
51 {
52 	mixin NetCommon;
53 
54 	BaseClient connection;
55 	alias connection this;
56 
57 	this() {
58 		connection = new class BaseClient{};
59 	}
60 
61 	void onConnect(ref ENetEvent event) {
62 		evDispatcher.postEvent(ThisClientConnectedEvent());
63 	}
64 
65 	void onDisconnect(ref ENetEvent event) {
66 		event.peer.data = null;
67 		evDispatcher.postEvent(ThisClientDisconnectedEvent(event.data));
68 	}
69 }
70 
71 final class NetServerPlugin : IPlugin
72 {
73 private:
74 	ConfigOption portOpt;
75 	EventDispatcherPlugin evDispatcher;
76 
77 public:
78 	mixin NetCommon;
79 
80 	BaseServer connection;
81 	alias connection this;
82 
83 	override void registerResources(IResourceManagerRegistry resmanRegistry)
84 	{
85 		ConfigManager config = resmanRegistry.getResourceManager!ConfigManager;
86 		portOpt = config.registerOption!ushort("port", 1234);
87 	}
88 
89 	this()
90 	{
91 		connection = new class BaseServer{};
92 	}
93 
94 	override void init(IPluginManager pluginman)
95 	{
96 		evDispatcher = pluginman.getPlugin!EventDispatcherPlugin;
97 		evDispatcher.subscribeToEvent(&handleGameStartEvent);
98 		evDispatcher.subscribeToEvent(&onPreUpdateEvent);
99 		evDispatcher.subscribeToEvent(&onPostUpdateEvent);
100 		evDispatcher.subscribeToEvent(&handleGameStopEvent);
101 	}
102 
103 	override void postInit()
104 	{
105 		//connection.shufflePackets();
106 		connection.printPacketMap();
107 	}
108 
109 	void handleGameStartEvent(ref GameStartEvent event)
110 	{
111 		ConnectionSettings settings = {null, 32, 2, 0, 0};
112 		connection.start(settings, ENET_HOST_ANY, portOpt.get!ushort);
113 		static if (ENABLE_RLE_PACKET_COMPRESSION)
114 			enet_host_compress_with_range_coder(connection.host);
115 	}
116 
117 	void onConnect(ref ENetEvent event) {
118 		auto clientId = connection.clientStorage.addClient(event.peer);
119 		event.peer.data = cast(void*)clientId;
120 
121 		evDispatcher.postEvent(ClientConnectedEvent(clientId));
122 	}
123 
124 	void onDisconnect(ref ENetEvent event) {
125 		ClientId clientId = cast(ClientId)event.peer.data;
126 		event.peer.data = null;
127 		connection.clientStorage.removeClient(clientId);
128 		evDispatcher.postEvent(ClientDisconnectedEvent(clientId));
129 	}
130 
131 	void onPreUpdateEvent(ref PreUpdateEvent event)
132 	{
133 		connection.update();
134 	}
135 
136 	void onPostUpdateEvent(ref PostUpdateEvent event)
137 	{
138 		connection.flush();
139 	}
140 
141 	void handleGameStopEvent(ref GameStopEvent event)
142 	{
143 		connection.sendToAll(MessagePacket(0, "Stopping server"));
144 		connection.disconnectAll();
145 		while (connection.clientStorage.length)
146 		{
147 			connection.update();
148 		}
149 		connection.stop();
150 	}
151 }