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