1 /***
2 * Jetrix TetriNET Server
3 * Copyright (C) 2008 Emmanuel Bourg
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 package net.jetrix.agent;
21
22 import java.io.BufferedInputStream;
23 import java.io.BufferedWriter;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.OutputStreamWriter;
27 import java.io.Writer;
28 import java.net.Socket;
29 import java.util.Locale;
30
31 import net.jetrix.Message;
32 import net.jetrix.Protocol;
33 import net.jetrix.config.ServerConfig;
34 import net.jetrix.protocols.TetrinetProtocol;
35 import net.jetrix.messages.*;
36 import net.jetrix.messages.channel.*;
37 import net.jetrix.messages.channel.specials.*;
38
39 /***
40 * Tetrinet agent to log on a server as a player.
41 *
42 * @author Emmanuel Bourg
43 * @version $Revision: 848 $, $Date: 2010-05-03 22:51:32 +0200 (lun., 03 mai 2010) $
44 */
45 public class TetrinetAgent implements Agent
46 {
47 /*** The name of the agent. */
48 protected String clientName = "Jetrix";
49
50 /*** The version of the agent. */
51 protected String clientVersion = ServerConfig.VERSION;
52
53 /*** The name of the player. */
54 protected String name;
55
56 /*** The name of the team. */
57 protected String teamname;
58
59 /*** The hostname of the TetriNET server. */
60 private String hostname;
61
62 /*** The current slot assigned by the server. */
63 private int slot;
64
65 private Socket socket;
66 private InputStream in;
67 private Writer out;
68 private String encoding = "Cp1252";
69
70 protected Protocol protocol = new TetrinetProtocol();
71 private boolean running;
72
73 public TetrinetAgent(String name)
74 {
75 this.name = name;
76 }
77
78 public String getHostname()
79 {
80 return hostname;
81 }
82
83 public void connect(String hostname) throws IOException
84 {
85 connect(hostname, 31457, "1.13");
86 }
87
88 protected void connect(String hostname, int port, String version) throws IOException
89 {
90 if (running)
91 {
92 return;
93 }
94
95 this.hostname = hostname;
96
97 socket = new Socket(hostname, port);
98 socket.setSoTimeout(15000);
99
100 in = new BufferedInputStream(socket.getInputStream());
101 out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), encoding));
102
103 send(TetrinetProtocol.encode(name, version, socket.getInetAddress().getAddress(), false));
104
105
106 String line = protocol.readLine(in, encoding);
107 Message message = protocol.getMessage(line);
108 receive(message);
109
110 if (message instanceof NoConnectingMessage)
111 {
112 throw new IOException("Connexion rejected (noconnecting) : " + ((NoConnectingMessage) message).getText());
113 }
114
115 running = true;
116
117 socket.setSoTimeout(0);
118
119
120 new MessageListener().start();
121 }
122
123 private class MessageListener extends Thread
124 {
125 private MessageListener()
126 {
127 setName("listener");
128 }
129
130 public void run()
131 {
132 try
133 {
134 while (running)
135 {
136 String line = protocol.readLine(in, encoding);
137
138 Message message = protocol.getMessage(line);
139
140 receive(message);
141 }
142 }
143 catch (IOException e)
144 {
145 if (running)
146 {
147 e.printStackTrace();
148 running = false;
149 }
150 }
151 }
152 }
153
154 public void disconnect() throws IOException
155 {
156 if (socket != null)
157 {
158 running = false;
159 socket.close();
160 }
161 }
162
163 protected synchronized void send(String message) throws IOException
164 {
165 out.write(message);
166 out.write(protocol.getEOL());
167 out.flush();
168 }
169
170 public void send(Message message) throws IOException
171 {
172
173 if (message instanceof ChannelMessage)
174 {
175 ((ChannelMessage) message).setSlot(slot);
176 }
177
178 send(protocol.translate(message, Locale.getDefault()));
179 }
180
181 /***
182 * Join the specified channel
183 *
184 * @param channel
185 */
186 public void join(String channel) throws IOException
187 {
188 send(new PlineMessage("/join " + channel));
189 }
190
191 public final void receive(Message m)
192 {
193
194 onMessage(m);
195
196
197 if (m instanceof SpecialMessage) { onMessage((SpecialMessage) m); }
198 else if (m instanceof FieldMessage) { onMessage((FieldMessage) m); }
199 else if (m instanceof CommandMessage) { onMessage((CommandMessage) m); }
200 else if (m instanceof PlineMessage) { onMessage((PlineMessage) m); }
201 else if (m instanceof LevelMessage) { onMessage((LevelMessage) m); }
202 else if (m instanceof PlayerLostMessage) { onMessage((PlayerLostMessage) m); }
203 else if (m instanceof PlineActMessage) { onMessage((PlineActMessage) m); }
204 else if (m instanceof TeamMessage) { onMessage((TeamMessage) m); }
205 else if (m instanceof JoinMessage) { onMessage((JoinMessage) m); }
206 else if (m instanceof LeaveMessage) { onMessage((LeaveMessage) m); }
207 else if (m instanceof PlayerNumMessage) { onMessage((PlayerNumMessage) m); }
208 else if (m instanceof StartGameMessage) { onMessage((StartGameMessage) m); }
209 else if (m instanceof StopGameMessage) { onMessage((StopGameMessage) m); }
210 else if (m instanceof NewGameMessage) { onMessage((NewGameMessage) m); }
211 else if (m instanceof EndGameMessage) { onMessage((EndGameMessage) m); }
212 else if (m instanceof PauseMessage) { onMessage((PauseMessage) m); }
213 else if (m instanceof ResumeMessage) { onMessage((ResumeMessage) m); }
214 else if (m instanceof GmsgMessage) { onMessage((GmsgMessage) m); }
215 else if (m instanceof PlayerWonMessage) { onMessage((PlayerWonMessage) m); }
216 else if (m instanceof NoConnectingMessage) { onMessage((NoConnectingMessage) m); }
217 else
218 {
219
220 }
221
222
223 }
224
225 /***
226 * Message pre-processing. This method is called at the beginning of the
227 * <tt>process(Message m, List out)</tt> method and allow custom
228 * processing for all filtered messages.
229 */
230 public void onMessage(Message m) { }
231
232 public void onMessage(PlineMessage m) { }
233
234 public void onMessage(PlineActMessage m) { }
235
236 public void onMessage(NoConnectingMessage m) { }
237
238 public void onMessage(TeamMessage m) { }
239
240 public void onMessage(JoinMessage m) { }
241
242 public void onMessage(LeaveMessage m) { }
243
244 public void onMessage(PlayerNumMessage m)
245 {
246 this.slot = m.getSlot();
247
248
249 TeamMessage response = new TeamMessage();
250 response.setSlot(slot);
251 response.setName(teamname);
252
253 try
254 {
255 send(response);
256 }
257 catch (IOException e)
258 {
259 e.printStackTrace();
260 }
261 }
262
263 public void onMessage(StartGameMessage m) { }
264
265 public void onMessage(StopGameMessage m) { }
266
267 public void onMessage(NewGameMessage m) { }
268
269 public void onMessage(EndGameMessage m) { }
270
271 public void onMessage(PauseMessage m) { }
272
273 public void onMessage(ResumeMessage m) { }
274
275 public void onMessage(GmsgMessage m) { }
276
277 private void onMessage(SpecialMessage m)
278 {
279
280 onSpecial(m);
281
282
283 if (m instanceof LinesAddedMessage) { onMessage((LinesAddedMessage) m); }
284 else if (m instanceof AddLineMessage) { onMessage((AddLineMessage) m); }
285 else if (m instanceof ClearLineMessage) { onMessage((ClearLineMessage) m); }
286 else if (m instanceof ClearSpecialsMessage) { onMessage((ClearSpecialsMessage) m); }
287 else if (m instanceof RandomClearMessage) { onMessage((RandomClearMessage) m); }
288 else if (m instanceof BlockQuakeMessage) { onMessage((BlockQuakeMessage) m); }
289 else if (m instanceof BlockBombMessage) { onMessage((BlockBombMessage) m); }
290 else if (m instanceof GravityMessage) { onMessage((GravityMessage) m); }
291 else if (m instanceof NukeFieldMessage) { onMessage((NukeFieldMessage) m); }
292 else if (m instanceof SwitchFieldsMessage) { onMessage((SwitchFieldsMessage) m); }
293 }
294
295 /***
296 * Special block message pre-processing. This method is called for all
297 * specials filtered and allow custom processing for all specials
298 * (lines added, blockbomb switchs, etc...).
299 */
300 public void onSpecial(SpecialMessage m) { }
301
302 public void onMessage(LevelMessage m)
303 {
304 if (m.getLevel() == 0 && m.getSlot() == 0)
305 {
306 ClientInfoMessage response = new ClientInfoMessage();
307 response.setName(clientName);
308 response.setVersion(clientVersion);
309
310 try
311 {
312 send(response);
313 }
314 catch (IOException e)
315 {
316 e.printStackTrace();
317 }
318 }
319 }
320
321 public void onMessage(FieldMessage m) { }
322
323 public void onMessage(PlayerLostMessage m) { }
324
325 public void onMessage(PlayerWonMessage m) { }
326
327 public void onMessage(CommandMessage m) { }
328
329 public void onMessage(LinesAddedMessage m)
330 {
331 if (m instanceof OneLineAddedMessage) { onMessage((OneLineAddedMessage) m); }
332 else if (m instanceof TwoLinesAddedMessage) { onMessage((TwoLinesAddedMessage) m); }
333 else if (m instanceof FourLinesAddedMessage) { onMessage((FourLinesAddedMessage) m); }
334 }
335
336 public void onMessage(OneLineAddedMessage m) { }
337
338 public void onMessage(TwoLinesAddedMessage m) { }
339
340 public void onMessage(FourLinesAddedMessage m) { }
341
342 public void onMessage(AddLineMessage m) { }
343
344 public void onMessage(ClearLineMessage m) { }
345
346 public void onMessage(NukeFieldMessage m) { }
347
348 public void onMessage(RandomClearMessage m) { }
349
350 public void onMessage(SwitchFieldsMessage m) { }
351
352 public void onMessage(ClearSpecialsMessage m) { }
353
354 public void onMessage(GravityMessage m) { }
355
356 public void onMessage(BlockQuakeMessage m) { }
357
358 public void onMessage(BlockBombMessage m) { }
359
360 }