diff options
-rw-r--r-- | src/ch/epfl/xblast/server/Server.java | 177 |
1 files changed, 103 insertions, 74 deletions
diff --git a/src/ch/epfl/xblast/server/Server.java b/src/ch/epfl/xblast/server/Server.java index 58f3c07..6d1d62f 100644 --- a/src/ch/epfl/xblast/server/Server.java +++ b/src/ch/epfl/xblast/server/Server.java | |||
@@ -22,119 +22,148 @@ public class Server { | |||
22 | public static final int DEFAULT_PORT = 2016; | 22 | public static final int DEFAULT_PORT = 2016; |
23 | private static final int DEFAULT_EXPECTED_CLIENTS = PlayerID.values().length; | 23 | private static final int DEFAULT_EXPECTED_CLIENTS = PlayerID.values().length; |
24 | 24 | ||
25 | private static InetSocketAddress listeningInterface(String host, int port) { | 25 | private static class Channel { |
26 | if (Objects.isNull(host)) | ||
27 | return new InetSocketAddress(port); | ||
28 | else | ||
29 | return new InetSocketAddress(host, port); | ||
30 | } | ||
31 | 26 | ||
32 | private static DatagramChannel openChannel(InetSocketAddress iface) { | 27 | private static InetSocketAddress listeningInterface(String host, int port) { |
33 | try { | 28 | if (Objects.isNull(host)) |
34 | DatagramChannel chan = DatagramChannel.open(StandardProtocolFamily.INET); | 29 | return new InetSocketAddress(port); |
35 | chan.bind(iface); | 30 | else |
36 | return chan; | 31 | return new InetSocketAddress(host, port); |
37 | } catch (IOException e) { | ||
38 | e.printStackTrace(); | ||
39 | System.exit(1); | ||
40 | return null; | ||
41 | } | 32 | } |
42 | } | ||
43 | 33 | ||
44 | private static Optional<Map.Entry<SocketAddress, Byte>> receiveByte(DatagramChannel chan, boolean block) { | 34 | private static DatagramChannel openChannel(InetSocketAddress iface) { |
45 | try { | 35 | try { |
46 | ByteBuffer buf = ByteBuffer.allocate(1); | 36 | DatagramChannel chan = DatagramChannel.open(StandardProtocolFamily.INET); |
47 | chan.configureBlocking(block); | 37 | chan.bind(iface); |
48 | SocketAddress client = chan.receive(buf); | 38 | return chan; |
39 | } catch (IOException e) { | ||
40 | e.printStackTrace(); | ||
41 | System.exit(1); | ||
42 | return null; | ||
43 | } | ||
44 | } | ||
49 | 45 | ||
50 | if (Objects.isNull(client) || buf.position() == 0) | 46 | private final DatagramChannel channel; |
51 | throw new IOException(); | ||
52 | 47 | ||
53 | return Optional.of(new AbstractMap.SimpleImmutableEntry<>(client, buf.get(0))); | 48 | Channel(InetSocketAddress iface) { |
54 | } catch (IOException e) { | 49 | this.channel = openChannel(iface); |
55 | return Optional.empty(); | ||
56 | } | 50 | } |
57 | } | ||
58 | 51 | ||
59 | private static Optional<Map.Entry<SocketAddress, PlayerAction>> receiveAction(DatagramChannel chan, boolean block) { | 52 | Channel(String host, Integer port) { |
60 | try { | 53 | this(listeningInterface(host, Optional.ofNullable(port).orElse(DEFAULT_PORT))); |
61 | Map.Entry<SocketAddress, Byte> actionByte = receiveByte(chan, block).get(); | 54 | } |
62 | PlayerAction playerAction = PlayerAction.fromByte(actionByte.getValue()); | 55 | |
63 | return Optional.of(new AbstractMap.SimpleImmutableEntry<>(actionByte.getKey(), playerAction)); | 56 | void closeChannel() { |
64 | } catch (NoSuchElementException | IllegalArgumentException e) { | 57 | try { |
65 | return Optional.empty(); | 58 | this.channel.close(); |
59 | } catch (IOException e) { | ||
60 | e.printStackTrace(); | ||
61 | } | ||
66 | } | 62 | } |
67 | } | ||
68 | 63 | ||
69 | private static Map.Entry<SocketAddress, PlayerAction> acceptAction(DatagramChannel chan) { | 64 | List<SocketAddress> acceptRegistrations(int registrations) { |
70 | Optional<Map.Entry<SocketAddress, PlayerAction>> action; | 65 | List<SocketAddress> clients = new ArrayList<>(registrations); |
71 | 66 | ||
72 | do { | 67 | while (clients.size() < registrations) { |
73 | action = receiveAction(chan, true); | 68 | SocketAddress client = this.acceptRegistration(); |
74 | } while (!action.isPresent()); | 69 | if (!clients.contains(client)) |
70 | clients.add(client); | ||
71 | } | ||
75 | 72 | ||
76 | return action.get(); | 73 | return Collections.unmodifiableList(clients); |
77 | } | 74 | } |
78 | 75 | ||
79 | private static Map<SocketAddress, PlayerAction> collectActions(DatagramChannel chan) { | 76 | Map<SocketAddress, PlayerAction> collectActions() { |
80 | Map<SocketAddress, PlayerAction> actions = new HashMap<>(); | 77 | Map<SocketAddress, PlayerAction> actions = new HashMap<>(); |
81 | Optional<Map.Entry<SocketAddress, PlayerAction>> action; | 78 | Optional<Map.Entry<SocketAddress, PlayerAction>> action; |
82 | 79 | ||
83 | while (true) { | 80 | while (true) { |
84 | action = receiveAction(chan, false); | 81 | action = this.receiveAction(false); |
85 | if (!action.isPresent()) break; | 82 | if (!action.isPresent()) break; |
86 | actions.put(action.get().getKey(), action.get().getValue()); | 83 | actions.put(action.get().getKey(), action.get().getValue()); |
84 | } | ||
85 | |||
86 | return Collections.unmodifiableMap(actions); | ||
87 | } | 87 | } |
88 | 88 | ||
89 | return Collections.unmodifiableMap(actions); | 89 | private Optional<Map.Entry<SocketAddress, Byte>> receiveByte(boolean block) { |
90 | } | 90 | try { |
91 | ByteBuffer buf = ByteBuffer.allocate(1); | ||
92 | this.channel.configureBlocking(block); | ||
93 | SocketAddress client = this.channel.receive(buf); | ||
91 | 94 | ||
92 | private static SocketAddress acceptRegistration(DatagramChannel chan) { | 95 | if (Objects.isNull(client) || buf.position() == 0) |
93 | Map.Entry<SocketAddress, PlayerAction> clientAction; | 96 | throw new IOException(); |
94 | 97 | ||
95 | do { | 98 | return Optional.of(new AbstractMap.SimpleImmutableEntry<>(client, buf.get(0))); |
96 | clientAction = acceptAction(chan); | 99 | } catch (IOException e) { |
97 | } while (clientAction.getValue() != PlayerAction.JOIN_GAME); | 100 | return Optional.empty(); |
101 | } | ||
102 | } | ||
98 | 103 | ||
99 | return clientAction.getKey(); | 104 | private Optional<Map.Entry<SocketAddress, PlayerAction>> receiveAction(boolean block) { |
100 | } | 105 | try { |
106 | Map.Entry<SocketAddress, Byte> actionByte = this.receiveByte(block).get(); | ||
107 | PlayerAction playerAction = PlayerAction.fromByte(actionByte.getValue()); | ||
108 | return Optional.of(new AbstractMap.SimpleImmutableEntry<>(actionByte.getKey(), playerAction)); | ||
109 | } catch (NoSuchElementException | IllegalArgumentException e) { | ||
110 | return Optional.empty(); | ||
111 | } | ||
112 | } | ||
113 | |||
114 | private Map.Entry<SocketAddress, PlayerAction> acceptAction() { | ||
115 | Optional<Map.Entry<SocketAddress, PlayerAction>> action; | ||
101 | 116 | ||
102 | private static List<SocketAddress> acceptRegistrations(DatagramChannel chan, int registrations) { | 117 | do { |
103 | List<SocketAddress> clients = new ArrayList<>(registrations); | 118 | action = this.receiveAction(true); |
119 | } while (!action.isPresent()); | ||
104 | 120 | ||
105 | while (clients.size() < registrations) { | 121 | return action.get(); |
106 | SocketAddress client = acceptRegistration(chan); | 122 | } |
107 | if (!clients.contains(client)) | 123 | |
108 | clients.add(client); | 124 | private SocketAddress acceptRegistration() { |
125 | Map.Entry<SocketAddress, PlayerAction> clientAction; | ||
126 | |||
127 | do { | ||
128 | clientAction = this.acceptAction(); | ||
129 | } while (clientAction.getValue() != PlayerAction.JOIN_GAME); | ||
130 | |||
131 | return clientAction.getKey(); | ||
109 | } | 132 | } |
110 | 133 | ||
111 | return Collections.unmodifiableList(clients); | ||
112 | } | 134 | } |
113 | 135 | ||
114 | private final InetSocketAddress iface; | 136 | private final Channel channel; |
115 | private final int expectedClients; | 137 | private final int expectedClients; |
116 | private Map<SocketAddress, PlayerID> registeredClients; | 138 | |
139 | private Map<SocketAddress, PlayerID> registeredClientsMap; | ||
140 | private Map<PlayerID, SocketAddress> playersAddressMap; | ||
117 | 141 | ||
118 | public Server(String iface, Integer port, Integer expectedClients) { | 142 | public Server(String iface, Integer port, Integer expectedClients) { |
119 | this.iface = listeningInterface(iface, Optional.ofNullable(port).orElse(DEFAULT_PORT)); | 143 | this.channel = new Channel(iface, port); |
120 | this.expectedClients = Optional.ofNullable(expectedClients).orElse(DEFAULT_EXPECTED_CLIENTS); | 144 | this.expectedClients = Optional.ofNullable(expectedClients).orElse(DEFAULT_EXPECTED_CLIENTS); |
121 | } | 145 | } |
122 | 146 | ||
123 | public void run() { | 147 | public void run() { |
124 | DatagramChannel chan = openChannel(this.iface); | 148 | this.acceptClientRegistrations(); |
125 | List<SocketAddress> clients = acceptRegistrations(chan, this.expectedClients); | 149 | this.runGame(); |
126 | this.registeredClients = Lists.linearAdjustedMap(clients, Arrays.asList(PlayerID.values())); | 150 | this.channel.closeChannel(); |
151 | } | ||
127 | 152 | ||
128 | System.out.println(this.registeredClients); | 153 | private void acceptClientRegistrations() { |
154 | List<SocketAddress> clients = this.channel.acceptRegistrations(this.expectedClients); | ||
155 | this.registeredClientsMap = Lists.linearAdjustedMap(clients, Arrays.asList(PlayerID.values())); | ||
156 | this.playersAddressMap = Lists.invertMap(this.registeredClientsMap); | ||
157 | } | ||
129 | 158 | ||
159 | private void runGame() { | ||
130 | try { | 160 | try { |
131 | Thread.sleep(10000); | 161 | Thread.sleep(10000); |
132 | } catch (InterruptedException e) { | 162 | } catch (InterruptedException e) { |
133 | e.printStackTrace(); | 163 | e.printStackTrace(); |
134 | } | 164 | } |
135 | 165 | ||
136 | Map<SocketAddress, PlayerAction> actions = collectActions(chan); | 166 | Map<SocketAddress, PlayerAction> actions = this.channel.collectActions(); |
137 | System.out.println(actions); | ||