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 }