View Javadoc

1   /*
2    *   Magic-Project is a turn based strategy simulator
3    *   Copyright (C) 2003-2007 Fabrice Daugan
4    *
5    *   This program is free software; you can redistribute it and/or modify it 
6    * under the terms of the GNU General Public License as published by the Free 
7    * Software Foundation; either version 2 of the License, or (at your option) any
8    * later version.
9    *
10   *   This program is distributed in the hope that it will be useful, but WITHOUT 
11   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12   * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 
13   * details.
14   *
15   *   You should have received a copy of the GNU General Public License along  
16   * with this program; if not, write to the Free Software Foundation, Inc., 
17   * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18   */
19  package net.sf.magicproject.network;
20  
21  import java.net.ServerSocket;
22  import java.net.SocketException;
23  import java.net.SocketTimeoutException;
24  
25  import javax.swing.JOptionPane;
26  
27  import net.sf.magicproject.action.PayMana;
28  import net.sf.magicproject.action.WaitActivatedChoice;
29  import net.sf.magicproject.clickable.targetable.player.Opponent;
30  import net.sf.magicproject.clickable.targetable.player.You;
31  import net.sf.magicproject.deckbuilder.Deck;
32  import net.sf.magicproject.deckbuilder.MdbLoader;
33  import net.sf.magicproject.stack.StackManager;
34  import net.sf.magicproject.token.IdConst;
35  import net.sf.magicproject.tools.Configuration;
36  import net.sf.magicproject.tools.Log;
37  import net.sf.magicproject.tools.MToolKit;
38  import net.sf.magicproject.ui.MagicUIComponents;
39  import net.sf.magicproject.ui.component.LoaderConsole;
40  import net.sf.magicproject.ui.i18n.LanguageManager;
41  
42  import org.apache.commons.io.IOUtils;
43  
44  /***
45   * a multi-client server
46   * 
47   * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan </a>
48   * @since 0.2c
49   */
50  public class Server extends NetworkActor implements IdMessages {
51  
52  	/***
53  	 * create a new server for a specified port, play name, nickName and password
54  	 * required (null if none)
55  	 * 
56  	 * @param deck
57  	 *          the deck of this server
58  	 * @param passwd
59  	 *          is the password needed to connect to this play
60  	 */
61  	public Server(Deck deck, char[] passwd) {
62  		super(deck, passwd);
63  		LoaderConsole.beginTask(LanguageManager
64  				.getString("wiz_network.waitingforopponent"));
65  	}
66  
67  	/***
68  	 * If this thread was constructed using a separate <code>Runnable</code> run
69  	 * object, then that <code>Runnable</code> object's <code>run</code>
70  	 * method is called; otherwise, this method does nothing and returns.
71  	 * <p>
72  	 * Subclasses of <code>Thread</code> should override this method.
73  	 * 
74  	 * @see java.lang.Thread#start()
75  	 * @see java.lang.Thread#Thread(java.lang.ThreadGroup, java.lang.Runnable,
76  	 *      java.lang.String)
77  	 * @see java.lang.Runnable#run()
78  	 */
79  	@Override
80  	public void run() {
81  		// Création de la socket de connexion
82  		try {
83  			serverSocket = new ServerSocket(port, 1);
84  			// enable timout
85  			serverSocket.setSoTimeout(2000);
86  
87  			// accept any client
88  			clientSocket = null;
89  			LoaderConsole.beginTask(LanguageManager
90  					.getString("wiz_network.creatingconnection"), 2);
91  			while (clientSocket == null && !cancelling) {
92  				try {
93  					clientSocket = serverSocket.accept();
94  				} catch (SocketException timeout) {
95  					if (!"socket closed".equals(timeout.getMessage())) {
96  						throw timeout;
97  					}
98  				} catch (SocketTimeoutException timeout) {
99  					/*
100 					 * timeout of 'accept()' method, nothing to do, we look if we're still
101 					 * running
102 					 */
103 				}
104 			}
105 
106 			// stopping?
107 			if (cancelling) {
108 				Log.info(LanguageManager.getString("wiz_network.canceledcreation"));
109 				cancelConnexion();
110 				return;
111 			}
112 
113 			// Un client s'est connecté...
114 
115 			LoaderConsole.beginTask(LanguageManager
116 					.getString("wiz_network.incomming")
117 					+ " : " + clientSocket.getInetAddress().toString(), 5);
118 
119 			// si pb dans la suite, il faudra liberer les deux sockets
120 			outBin = clientSocket.getOutputStream();
121 			inBin = clientSocket.getInputStream();
122 			// socketListener = new SocketListener(inBin);
123 
124 			if (passwd != null && passwd.length > 0) {
125 				// a password is needed to connect to this server
126 				MToolKit.writeString(outBin, STR_PASSWD);
127 				if (MToolKit.readString(inBin).equals(passwd)) {
128 					MToolKit.writeString(outBin, STR_OK);
129 				} else {
130 					// wrong password, this client client will be disconnected
131 					MToolKit.writeString(outBin, STR_WRONGPASSWD);
132 					// close stream
133 					IOUtils.closeQuietly(inBin);
134 					IOUtils.closeQuietly(outBin);
135 					// free pointers
136 					outBin = null;
137 					inBin = null;
138 				}
139 			} else {
140 				MToolKit.writeString(outBin, STR_OK);
141 			}
142 
143 			// check version of client
144 			String clientVersion = MToolKit.readString(inBin);
145 			if (IdConst.VERSION.equals(clientVersion)) {
146 				MToolKit.writeString(outBin, STR_OK);
147 			} else {
148 				// two different versions
149 				MToolKit.writeString(outBin, STR_WRONGVERSION);
150 				LoaderConsole.beginTask(LanguageManager
151 						.getString("wiz_network.differentversionClientpb")
152 						+ " (" + clientVersion + ")", 10);
153 				IOUtils.closeQuietly(inBin);
154 				IOUtils.closeQuietly(outBin);
155 				// free pointers
156 				outBin = null;
157 				inBin = null;
158 			}
159 
160 			if (outBin != null) {
161 
162 				// enter in the main loop
163 				// Opponent is ...
164 				String clientName = MToolKit.readString(inBin);
165 				LoaderConsole.beginTask(LanguageManager
166 						.getString("wiz_network.opponentis")
167 						+ clientName, 10);
168 				// I am ...
169 				MToolKit.writeString(outBin, nickName);
170 
171 				// exchange shared string settings
172 				((You) StackManager.PLAYERS[0]).sendSettings(outBin);
173 				((Opponent) StackManager.PLAYERS[1]).readSettings(clientName, nickName,
174 						inBin);
175 
176 				// stopping?
177 				if (cancelling) {
178 					cancelConnexion();
179 					return;
180 				}
181 
182 				// set and send the random seed
183 				long seed = MToolKit.random.nextLong();
184 				MToolKit.random.setSeed(seed);
185 				MToolKit.writeString(outBin, Long.toString(seed));
186 				Log.info("Seed = " + seed);
187 
188 				// write mana use option
189 				PayMana.useMana = Configuration.getBoolean("useMana", true);
190 				MToolKit.writeString(outBin, PayMana.useMana ? "1" : "0");
191 
192 				// write opponent response option
193 				WaitActivatedChoice.opponentResponse = Configuration.getBoolean(
194 						"opponnentresponse", true);
195 				MToolKit.writeString(outBin, WaitActivatedChoice.opponentResponse ? "1"
196 						: "0");
197 
198 				// Who starts?
199 				final StartingOption startingOption = StartingOption.values()[Configuration
200 						.getInt("whoStarts", StartingOption.random.ordinal())];
201 				MToolKit.writeString(outBin, String.valueOf(Configuration.getInt(
202 						"whoStarts", 0)));
203 				final boolean serverStarts;
204 				switch (startingOption) {
205 				case random:
206 				default:
207 					serverStarts = MToolKit.random.nextBoolean();
208 					break;
209 				case server:
210 					serverStarts = true;
211 					break;
212 				case client:
213 					serverStarts = false;
214 				}
215 
216 				if (serverStarts) {
217 					// server begins
218 					LoaderConsole.beginTask(LanguageManager
219 							.getString("wiz_network.youwillstarts")
220 							+ " (mode=" + startingOption.getLocaleValue() + ")", 15);
221 					StackManager.idActivePlayer = 0;
222 					StackManager.idCurrentPlayer = 0;
223 				} else {
224 					// client begins
225 					LoaderConsole.beginTask(LanguageManager
226 							.getString("wiz_network.opponentwillstart")
227 							+ " (mode=" + startingOption.getLocaleValue() + ")", 15);
228 					StackManager.idActivePlayer = 1;
229 					StackManager.idCurrentPlayer = 1;
230 				}
231 
232 				// load rules from the mdb file
233 				dbStream = MdbLoader.loadMDB(MToolKit.mdbFile,
234 						StackManager.idActivePlayer);
235 
236 				// receive and validate her/his deck
237 				LoaderConsole.beginTask(LanguageManager
238 						.getString("wiz_network.receivingdeck"), 25);
239 				readAndValidateOpponentDeck();
240 
241 				// stopping?
242 				if (cancelling) {
243 					cancelConnexion();
244 					return;
245 				}
246 
247 				// send our deck
248 				LoaderConsole.beginTask(LanguageManager
249 						.getString("wiz_network.sendingdeck"), 55);
250 				deck.send(outBin);
251 				StackManager.PLAYERS[0].zoneManager.giveCards(deck, dbStream);
252 
253 				// stopping?
254 				if (cancelling) {
255 					cancelConnexion();
256 					return;
257 				}
258 
259 				MToolKit.writeString(outBin, "%EOF%");
260 
261 				// free resources
262 				outBin.flush();
263 
264 				// stopping?
265 				if (cancelling) {
266 					cancelConnexion();
267 					return;
268 				}
269 
270 				initBigPipe();
271 				MagicUIComponents.magicForm.initGame();
272 			}
273 		} catch (Throwable e) {
274 			NetworkActor.cancelling = true;
275 			LoaderConsole.endTask();
276 			cancelConnexion();
277 			JOptionPane.showMessageDialog(MagicUIComponents.magicForm,
278 					LanguageManager.getString("wiz_server.error") + " : "
279 							+ e.getMessage(), LanguageManager.getString("error"),
280 					JOptionPane.WARNING_MESSAGE);
281 			Log.error(e);
282 			return;
283 		}
284 	}
285 
286 	@Override
287 	public void closeConnexion() {
288 		super.closeConnexion();
289 		// close stream
290 		if (serverSocket != null) {
291 			try {
292 				serverSocket.close();
293 			} catch (Exception e) {
294 				// Nothing to do
295 			}
296 		}
297 	}
298 
299 	/***
300 	 * the server's socket of this connexion
301 	 */
302 	public ServerSocket serverSocket;
303 
304 }