1 /**
2 Copyright: Copyright (c) 2014 Andrey Penechko.
3 License: a$(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4 Authors: Andrey Penechko.
5 */
6 
7 module client;
8 
9 import core.thread;
10 import std.conv : to;
11 import std.stdio : writefln, writeln;
12 import std.string : format;
13 import std.random : uniform;
14 
15 import derelict.enet.enet;
16 
17 import connection;
18 import packets;
19 
20 immutable randomNames = [
21 "Bob", "Steve", "Alanakai", "Tyler", "Carmine", "Randy", "Tim",
22 "Robbie", "Xavier", "Jerrell", "Clinton", "Bob", "Berry", "Maximo",
23 "Emmett", "Napoleon", "Jeffery", "Ali", "Hubert", "Jordan", "Rickey", "Jamey",
24 "Bret", "Gene", "Cornell", "Garret", "Randal", "Luther", "Raymundo", "Brady",
25 "Reid", "Asha", "Tari", "Isela", "Qiana", "Nada", "Nicole", "Waneta", "Mammie",
26 "Deedra", "Shizuko", "Tammy", "Rachelle", "Tu", "Yon", "Torie", "Lauryn",
27 "Nikia", "Alaina", "Kelsey", "Velva", "Luna", "Nicola", "Darla", "Kelle",
28 "Valarie", "Bernardina", "Isidra", ];
29 
30 class Client : Connection
31 {
32 	bool isRunning;
33 
34 	ENetAddress serverAddress;
35 	ENetPeer* server;
36 
37 	UserId myId;
38 	string myName;
39 
40 	string[UserId] userNames;
41 	
42 	string userName(UserId userId)
43 	{
44 		return userId in userNames ? userNames[userId] : format("? %s", userId);
45 	}
46 
47 	void start(string address = "127.0.0.1", ushort port = 1234)
48 	{
49 		registerPacket!LoginPacket;
50 		registerPacket!SessionInfoPacket(&handleSessionInfoPacket);
51 		registerPacket!UserLoggedInPacket(&handleUserLoggedInPacket);
52 		registerPacket!UserLoggedOutPacket(&handleUserLoggedOutPacket);
53 		registerPacket!MessagePacket(&handleMessagePacket);
54 
55 		enet_address_set_host(&serverAddress, cast(char*)address);
56 		serverAddress.port = port;
57 
58 		host = enet_host_create(null /* create a client host */,
59 			1 /* only allow 1 outgoing connection */,
60 			2,
61 			57600 / 8 /* 56K modem with 56 Kbps downstream bandwidth */,
62 			14400 / 8 /* 56K modem with 14 Kbps upstream bandwidth */);
63 
64 		if (host is null)
65 		{
66 			writeln("Client: An error occured while trying to create an ENet server host");
67 			return;
68 		}
69 
70 		server = enet_host_connect(host, &serverAddress, 2, 42);
71 		enet_peer_timeout(server, 0, 0, 5000);
72 
73 		if (server is null)
74 		{
75 			writeln("Client: An error occured while trying to create an ENet server peer");
76 			return;
77 		}
78 
79 		side = "Client";
80 
81 		writeln("Client: Started");
82 		isRunning = true;
83 	}
84 
85 	override void stop()
86 	{
87 		super.stop();
88 		writefln("Client: Stopped");
89 	}
90 
91 	void send(ubyte[] data, ubyte channel = 0)
92 	{
93 		ENetPacket* packet = enet_packet_create(data.ptr, data.length,
94 				ENET_PACKET_FLAG_RELIABLE);
95 		enet_peer_send(server, channel, packet);
96 	}
97 
98 	override void onConnect(ref ENetEvent event)
99 	{
100 		writefln("Client: Connection to 127.0.0.1:1234 established");
101 
102 		// generate random name
103 		myName = randomNames[uniform(0, randomNames.length)];
104 		send(createPacket(LoginPacket(myName)));
105 	}
106 
107 	void handleSessionInfoPacket(ubyte[] packetData, UserId peer)
108 	{
109 		SessionInfoPacket loginInfo = unpackPacket!SessionInfoPacket(packetData);
110 
111 		userNames = loginInfo.userNames;
112 		myId = loginInfo.yourId;
113 
114 		writefln("Client %s: my id is %s", myName[0], myId);
115 
116 		// Send 3 hello message packets.
117 		foreach(i; 0..3)
118 		{
119 			string str = format("hello from %s %s", myName, i);
120 			ubyte[] packet = createPacket(MessagePacket(0, str));
121 			send(packet);
122 		}
123 
124 		//send(createPacket(MessagePacket(0, "/stop")));
125 		flush();
126 	}
127 
128 	void handleUserLoggedInPacket(ubyte[] packetData, UserId peer)
129 	{
130 		UserLoggedInPacket newUser = unpackPacket!UserLoggedInPacket(packetData);
131 		userNames[newUser.userId] = newUser.userName;
132 		writefln("Client %s: %s has connected", myName[0], newUser.userName);
133 	}
134 
135 	void handleUserLoggedOutPacket(ubyte[] packetData, UserId peer)
136 	{
137 		UserLoggedOutPacket packet = unpackPacket!UserLoggedOutPacket(packetData);
138 		writefln("Client %s: %s has disconnected", myName[0], userName(packet.userId));
139 		userNames.remove(packet.userId);
140 	}
141 
142 	void handleMessagePacket(ubyte[] packetData, UserId peer)
143 	{
144 		MessagePacket msg = unpackPacket!MessagePacket(packetData);
145 		if (msg.userId == 0)
146 			writefln("Client %s: %s", myName[0], msg.msg);
147 		else
148 			writefln("Client %s: %s> %s", myName[0], userName(msg.userId), msg.msg);
149 	}
150 
151 	override void onDisconnect(ref ENetEvent event)
152 	{
153 		writefln("Client: disconnected with data %s", event.data);
154 
155 		// Reset server's information
156 		event.peer.data = null;
157 		
158 		isRunning = false;
159 	}
160 }