1 module server; 2 3 import std.stdio; 4 import std.range; 5 6 import derelict.enet.enet; 7 8 import connection; 9 import packets; 10 11 12 struct ServerSettings 13 { 14 ushort port; 15 size_t maxClients; 16 size_t numChannels; 17 uint incomingBandwidth; 18 uint outgoingBandwidth; 19 } 20 21 struct User 22 { 23 string name; 24 ENetPeer* peer; 25 } 26 27 struct UserStorage 28 { 29 private User*[UserId] users; 30 31 UserId addUser(ENetPeer* peer) 32 { 33 UserId id = nextPeerId; 34 User* user = new User; 35 user.peer = peer; 36 users[id] = user; 37 return id; 38 } 39 40 void removeUser(UserId id) 41 { 42 users.remove(id); 43 } 44 45 User* findUser(UserId id) 46 { 47 return users.get(id, null); 48 } 49 50 UserId nextPeerId() @property 51 { 52 return _nextPeerId++; 53 } 54 55 string[UserId] userNames() 56 { 57 string[UserId] names; 58 foreach(id, user; users) 59 { 60 names[id] = user.name; 61 } 62 63 return names; 64 } 65 66 string userName(UserId id) 67 { 68 return users[id].name; 69 } 70 71 ENetPeer* userPeer(UserId id) 72 { 73 return users[id].peer; 74 } 75 76 size_t length() 77 { 78 return users.length; 79 } 80 81 private UserId _nextPeerId = 1; 82 } 83 84 class Server : Connection 85 { 86 bool isRunning; 87 88 ENetAddress address; 89 ServerSettings settings; 90 91 UserStorage userStorage; 92 93 void start(ServerSettings _settings) 94 { 95 side = "Server"; 96 97 registerPacket!LoginPacket(&handleLoginPacket); 98 registerPacket!SessionInfoPacket; 99 registerPacket!UserLoggedInPacket; 100 registerPacket!UserLoggedOutPacket; 101 registerPacket!MessagePacket(&handleMessagePacket); 102 103 printPacketMap(); 104 105 settings = _settings; 106 107 address.host = ENET_HOST_ANY; 108 address.port = settings.port; 109 110 host = enet_host_create(&address, 111 settings.maxClients, 112 settings.numChannels, 113 settings.incomingBandwidth, 114 settings.outgoingBandwidth); 115 116 if (host is null) 117 { 118 writeln("Server: An error occured while trying to create an ENet server host"); 119 return; 120 } 121 122 isRunning = true; 123 } 124 125 void sendMessageTo(UserId userId, string message) 126 { 127 sendTo(only(userId), createPacket(MessagePacket(0, message))); 128 } 129 130 void handleCommand(string command, UserId userId) 131 { 132 import std.algorithm : splitter; 133 import std.string : format; 134 writefln("Server: %s Command> %s", userStorage.userName(userId), command); 135 136 if (command.length <= 1) 137 { 138 sendMessageTo(userId, "Invalid command"); 139 return; 140 } 141 142 // Split without leading '/' 143 auto splitted = command[1..$].splitter; 144 string commName = splitted.front; 145 splitted.popFront; 146 147 if (commName == "stop") 148 isRunning = false; 149 else 150 sendMessageTo(userId, format("Unknown command %s", commName)); 151 } 152 153 override void stop() 154 { 155 super.stop(); 156 writefln("Server: Stopped"); 157 } 158 159 /// Sending 160 void sendTo(R)(R users, ubyte[] data, ubyte channel = 0) 161 if (isInputRange!R && is(ElementType!R == UserId)) 162 { 163 ENetPacket *packet = enet_packet_create(data.ptr, data.length, 164 ENET_PACKET_FLAG_RELIABLE); 165 sendTo(users, packet, channel); 166 } 167 168 /// ditto 169 void sendTo(R)(R users, ENetPacket* packet, ubyte channel = 0) 170 if (isInputRange!R && is(ElementType!R == UserId)) 171 { 172 foreach(userId; users) 173 { 174 enet_peer_send(userStorage.userPeer(userId), channel, packet); 175 } 176 } 177 178 /// ditto 179 void sendToAll(ubyte[] data, ubyte channel = 0) 180 { 181 ENetPacket *packet = enet_packet_create(data.ptr, data.length, 182 ENET_PACKET_FLAG_RELIABLE); 183 sendToAll(packet, channel); 184 } 185 186 /// ditto 187 void sendToAll(ENetPacket* packet, ubyte channel = 0) 188 { 189 enet_host_broadcast(host, channel, packet); 190 } 191 192 //------------------------------------------------------------------------- 193 // Handlers 194 195 override void onConnect(ref ENetEvent event) 196 { 197 writefln("Server: A new client connected from %(%s.%):%s", 198 *cast(ubyte[4]*)(&event.peer.address.host), 199 event.peer.address.port); 200 201 event.peer.data = cast(void*)userStorage.addUser(event.peer); 202 enet_peer_timeout(event.peer, 0, 0, 2000); 203 } 204 205 void handleLoginPacket(ubyte[] packetData, UserId userId) 206 { 207 LoginPacket packet = unpackPacket!LoginPacket(packetData); 208 209 userStorage.findUser(userId).name = packet.userName; 210 writefln("Server: %s logged in", packet.userName); 211 212 sendTo(only(userId), createPacket(SessionInfoPacket(userId, userStorage.userNames))); 213 sendToAll(createPacket(UserLoggedInPacket(userId, packet.userName))); 214 } 215 216 void handleMessagePacket(ubyte[] packetData, UserId userId) 217 { 218 import std.algorithm : startsWith; 219 import std.string : strip; 220 221 MessagePacket packet = unpackPacket!MessagePacket(packetData); 222 223 packet.userId = userId; 224 string strippedMsg = packet.msg.strip; 225 226 if (strippedMsg.startsWith("/")) 227 { 228 handleCommand(strippedMsg, userId); 229 return; 230 } 231 232 writefln("Server: %s> %s", userStorage.userName(userId), packet.msg); 233 234 sendToAll(createPacket(packet)); 235 } 236 237 override void onDisconnect(ref ENetEvent event) 238 { 239 UserId userId = cast(UserId)event.peer.data; 240 241 writefln("Server: %s disconnected", userStorage.userName(userId)); 242 243 userStorage.removeUser(userId); 244 245 sendToAll(createPacket(UserLoggedOutPacket(userId))); 246 247 // Reset client's information 248 event.peer.data = null; 249 250 if (userStorage.length == 0) 251 isRunning = false; 252 } 253 }