1 /**
2 Copyright: Copyright (c) 2014-2016 Andrey Penechko.
3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4 Authors: Andrey Penechko.
5 */
6 
7 module netlib.baseclient;
8 
9 import core.thread;
10 import std.conv : to;
11 import std.string : toStringz;
12 import std.experimental.logger;
13 
14 import derelict.enet.enet;
15 
16 import netlib.connection;
17 
18 abstract class BaseClient : Connection
19 {
20 	ENetAddress serverAddress;
21 	ENetPeer* server;
22 	bool isConnecting;
23 	bool isConnected;
24 
25 	void connect(string address, ushort port)
26 	{
27 		ENetAddress addr;
28 		enet_address_set_host(&addr, address.toStringz);
29 		addr.port = port;
30 
31 		if (isConnecting)
32 		{
33 			if (addr == serverAddress)
34 			{
35 				return;
36 			}
37 			else
38 			{
39 				disconnect();
40 			}
41 		}
42 		serverAddress = addr;
43 		connect();
44 	}
45 
46 	void connect()
47 	{
48 		server = enet_host_connect(host, &serverAddress, 2, 42);
49 		//enet_peer_timeout(server, 0, 0, 5000);
50 
51 		if (server is null)
52 		{
53 			error("An error occured while trying to create an ENet server peer");
54 			return;
55 		}
56 
57 		isConnecting = true;
58 	}
59 
60 	void disconnect()
61 	{
62 		if (isConnecting)
63 		{
64 			enet_peer_disconnect_now(server, 0);
65 			isConnecting = false;
66 		}
67 		else
68 		{
69 			enet_peer_disconnect(server, 0);
70 		}
71 	}
72 
73 	void send(ubyte[] data, ubyte channel = 0)
74 	{
75 		if (!isRunning) return;
76 		ENetPacket* packet = enet_packet_create(data.ptr, data.length,
77 				ENET_PACKET_FLAG_RELIABLE);
78 		enet_peer_send(server, channel, packet);
79 	}
80 
81 	void send(P)(auto ref const(P) packet, ubyte channel = 0)
82 		if (is(P == struct))
83 	{
84 		if (packetId!P >= packetArray.length)
85 		{
86 			infof("Dropping packet %s: %s", P.stringof, packetId!P);
87 			return;
88 		}
89 
90 		send(createPacket(packet), channel);
91 	}
92 
93 	// Set id mapping for packets
94 	void setPacketMap(string[] packetNames)
95 	{
96 		import std.algorithm : countUntil, remove, SwapStrategy;
97 
98 		PacketInfo*[] newPacketArray;
99 		newPacketArray.reserve(packetNames.length);
100 
101 		static bool pred(PacketInfo* packetInfo, string packetName)
102 		{
103 			return packetInfo.name == packetName;
104 		}
105 
106 		foreach(i, packetName; packetNames)
107 		{
108 			ptrdiff_t index = countUntil!pred(packetArray, packetName);
109 			size_t newId = newPacketArray.length;
110 
111 			if (index > -1)
112 			{
113 				newPacketArray ~= packetArray[index];
114 				remove!(SwapStrategy.unstable)(packetArray, index);
115 			}
116 			else
117 			{
118 				newPacketArray ~= new PacketInfo(packetName);
119 			}
120 			newPacketArray[$-1].id = newId;
121 		}
122 
123 		packetArray = newPacketArray;
124 	}
125 
126 	override void update()
127 	{
128 		ENetEvent event;
129 		while (enet_host_service(host, &event, 0) > 0)
130 		{
131 			final switch (event.type)
132 			{
133 				case ENET_EVENT_TYPE_NONE:
134 					break;
135 				case ENET_EVENT_TYPE_CONNECT:
136 					isConnecting = false;
137 					isConnected = true;
138 					onConnect(event);
139 					break;
140 				case ENET_EVENT_TYPE_RECEIVE:
141 					onPacketReceived(event);
142 					break;
143 				case ENET_EVENT_TYPE_DISCONNECT:
144 					onDisconnect(event);
145 					isConnecting = false;
146 					isConnected = false;
147 					break;
148 			}
149 		}
150 	}
151 }