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 
24 	void connect(string address, ushort port)
25 	{
26 		enet_address_set_host(&serverAddress, address.toStringz);
27 		serverAddress.port = port;
28 
29 		server = enet_host_connect(host, &serverAddress, 2, 42);
30 		//enet_peer_timeout(server, 0, 0, 5000);
31 
32 		if (server is null)
33 		{
34 			error("An error occured while trying to create an ENet server peer");
35 			return;
36 		}
37 
38 		isConnecting = true;
39 	}
40 
41 	bool isConnected() @property
42 	{
43 		return host.connectedPeers > 0;
44 	}
45 
46 	void disconnect()
47 	{
48 		if (isConnecting)
49 			enet_peer_disconnect_now(server, 0);
50 		else
51 			enet_peer_disconnect(server, 0);
52 		isConnecting = false;
53 	}
54 
55 	void send(ubyte[] data, ubyte channel = 0)
56 	{
57 		if (!isRunning) return;
58 		ENetPacket* packet = enet_packet_create(data.ptr, data.length,
59 				ENET_PACKET_FLAG_RELIABLE);
60 		enet_peer_send(server, channel, packet);
61 	}
62 
63 	void send(P)(auto ref const(P) packet, ubyte channel = 0)
64 		if (is(P == struct))
65 	{
66 		if (packetId!P >= packetArray.length)
67 		{
68 			infof("Dropping packet %s: %s", P.stringof, packetId!P);
69 			return;
70 		}
71 
72 		send(createPacket(packet), channel);
73 	}
74 
75 	// Set id mapping for packets
76 	void setPacketMap(string[] packetNames)
77 	{
78 		import std.algorithm : countUntil, remove, SwapStrategy;
79 
80 		PacketInfo*[] newPacketArray;
81 		newPacketArray.reserve(packetNames.length);
82 
83 		static bool pred(PacketInfo* packetInfo, string packetName)
84 		{
85 			return packetInfo.name == packetName;
86 		}
87 
88 		foreach(i, packetName; packetNames)
89 		{
90 			ptrdiff_t index = countUntil!pred(packetArray, packetName);
91 			size_t newId = newPacketArray.length;
92 
93 			if (index > -1)
94 			{
95 				newPacketArray ~= packetArray[index];
96 				remove!(SwapStrategy.unstable)(packetArray, index);
97 			}
98 			else
99 			{
100 				newPacketArray ~= new PacketInfo(packetName);
101 			}
102 			newPacketArray[$-1].id = newId;
103 		}
104 
105 		packetArray = newPacketArray;
106 	}
107 
108 	override void update()
109 	{
110 		ENetEvent event;
111 		while (enet_host_service(host, &event, 0) > 0)
112 		{
113 			final switch (event.type)
114 			{
115 				case ENET_EVENT_TYPE_NONE:
116 					break;
117 				case ENET_EVENT_TYPE_CONNECT:
118 					isConnecting = false;
119 					onConnect(event);
120 					break;
121 				case ENET_EVENT_TYPE_RECEIVE:
122 					onPacketReceived(event);
123 					break;
124 				case ENET_EVENT_TYPE_DISCONNECT:
125 					onDisconnect(event);
126 					isConnecting = false;
127 					break;
128 			}
129 		}
130 	}
131 }