View Javadoc

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         // block until the playernum message is received
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         // start the message listener
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         // set the slot for channel messages
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         // overwritable pre processing
194         onMessage(m);
195 
196         // message dispatching
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             // nothing, log an error ?
220         }
221 
222         // todo add onMessage(DisconnectedMessage)
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         // repond with the team name
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         // message pre-processing
280         onSpecial(m);
281 
282         // message dispatching
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 }