1 module clientapp;
2 
3 import std.datetime;
4 import std.stdio;
5 import std.conv : to;
6 
7 
8 import derelict.enet.enet;
9 
10 import anchovy.gui;
11 import anchovy.graphics.windows.glfwwindow;
12 import anchovy.gui.application.application;
13 import anchovy.gui.databinding.list;
14 
15 import client;
16 import connection;
17 import packets;
18 
19 class MessageInputBehavior : EditBehavior
20 {
21 	void delegate() onEnter;
22 
23 	override bool keyPressed(Widget widget, KeyPressEvent event)
24 	{
25 		if (event.keyCode == KeyCode.KEY_ENTER)
26 		{
27 			if (onEnter) onEnter();
28 			return true;
29 		}
30 		else
31 		{
32 			return super.keyPressed(widget, event);
33 		}
34 	}
35 }
36 
37 class ChatClientApp : Application!GlfwWindow
38 {
39 	Client client;
40 	SimpleList!dstring messageList;
41 	Widget msgInput;
42 	MessageInputBehavior messageInput;
43 
44 	this(uvec2 windowSize, string caption)
45 	{
46 		super(windowSize, caption);
47 	}
48 
49 	override void update(double dt)
50 	{
51 		if (client) client.update(0);
52 
53 		fpsHelper.update(dt);
54 		timerManager.updateTimers(window.elapsedTime);
55 		context.update(dt);
56 	}
57 
58 	override void load(in string[] args)
59 	{
60 		renderer.setClearColor(Color(255,255,255));
61 		messageList = new SimpleList!dstring;
62 
63 		context.behaviorFactories["messageInput"] ~= delegate IWidgetBehavior (){return new MessageInputBehavior;};
64 
65 		templateManager.parseFile("chat.sdl");
66 
67 		auto mainLayer = context.createWidget("mainLayer");
68 		context.addRoot(mainLayer);
69 
70 		msgInput = context.getWidgetById("messsageInput");
71 		messageInput = msgInput.getWidgetBehavior!MessageInputBehavior();
72 		messageInput.onEnter = &onEnter;
73 
74 		context.getWidgetById("connect").addEventHandler(&onConnect);
75 		context.getWidgetById("messages").setProperty!("list", List!dstring)(messageList);
76 		messageList.push("first");
77 	}
78 
79 	override void unload()
80 	{
81 		if (client) client.stop();
82 	}
83 
84 	void printfln(Args...)(string fmt, Args args)
85 	{
86 		writefln(fmt, args);
87 		messageList.push(format(fmt, args).to!dstring);
88 	}
89 
90 	bool onConnect(Widget widget, PointerClickEvent event)
91 	{
92 		string address = context.getWidgetById("ip")["text"].coerce!string;
93 		ushort port = context.getWidgetById("port")["text"].coerce!ushort;
94 		string name = context.getWidgetById("nick")["text"].coerce!string;
95 
96 		if (!client)
97 		{
98 			client = new Client();
99 			client.registerPacketHandler!SessionInfoPacket(&handleSessionInfoPacket);
100 			client.registerPacketHandler!UserLoggedInPacket(&handleUserLoggedInPacket);
101 			client.registerPacketHandler!UserLoggedOutPacket(&handleUserLoggedOutPacket);
102 			client.registerPacketHandler!MessagePacket(&handleMessagePacket);
103 
104 			client.disconnectHandler = &onDisconnect;
105 
106 			client.start();
107 		}
108 
109 		writefln("%s", address);
110 
111 		client.connect(name, address, port);
112 
113 		return true;
114 	}
115 
116 	void onDisconnect()
117 	{
118 		printfln("Disconnected from server");
119 	}
120 
121 	void onEnter()
122 	{
123 		if (client && client.isRunning)
124 		{
125 			if (messageInput.text.length > 0)
126 			{
127 				writefln("enter");
128 				sendMessage(messageInput.text.to!string);
129 				messageInput.text = null;
130 			}
131 		}
132 	}
133 
134 	void sendMessage(string msg)
135 	{
136 		ubyte[] packet = client.createPacket(MessagePacket(0, msg));
137 		client.send(packet);
138 	}
139 
140 	void handleSessionInfoPacket(ubyte[] packetData, UserId peer)
141 	{
142 		SessionInfoPacket loginInfo = client.unpackPacket!SessionInfoPacket(packetData);
143 
144 		client.userNames = loginInfo.userNames;
145 		client.myId = loginInfo.yourId;
146 
147 		writefln("my id is %s", client.myId);
148 	}
149 
150 	void handleUserLoggedInPacket(ubyte[] packetData, UserId peer)
151 	{
152 		UserLoggedInPacket newUser = client.unpackPacket!UserLoggedInPacket(packetData);
153 		client.userNames[newUser.userId] = newUser.userName;
154 		printfln("%s has connected", newUser.userName);
155 	}
156 
157 	void handleUserLoggedOutPacket(ubyte[] packetData, UserId peer)
158 	{
159 		UserLoggedOutPacket packet = client.unpackPacket!UserLoggedOutPacket(packetData);
160 		printfln("%s has disconnected", client.userName(packet.userId));
161 		client.userNames.remove(packet.userId);
162 	}
163 
164 	void handleMessagePacket(ubyte[] packetData, UserId peer)
165 	{
166 		MessagePacket msg = client.unpackPacket!MessagePacket(packetData);
167 		if (msg.userId == 0)
168 			printfln("%s", msg.msg);
169 		else
170 			printfln("%s> %s", client.userName(msg.userId), msg.msg);
171 	}
172 
173 	override void closePressed()
174 	{
175 		isRunning = false;
176 	}
177 }
178 
179 version(linux)
180 {
181 	pragma(lib, "dl");
182 }
183 
184 void main(string[] args)
185 {
186 	DerelictENet.load();
187 
188 	int err = enet_initialize();
189 
190 	if (err != 0)
191 	{
192 		writefln("Error loading ENet library");
193 		return;
194 	}
195 	else
196 	{
197 		ENetVersion ever = enet_linked_version();
198 		writefln("Loaded ENet library v%s.%s.%s",
199 			ENET_VERSION_GET_MAJOR(ever),
200 			ENET_VERSION_GET_MINOR(ever),
201 			ENET_VERSION_GET_PATCH(ever));
202 	}
203 
204 	auto app = new ChatClientApp(uvec2(450, 500), "Chat");
205 	app.run(args);
206 }