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