001 package com.croftsoft.apps.mars.net; 002 003 import java.io.*; 004 import java.net.*; 005 import java.util.*; 006 007 import com.croftsoft.core.lang.NullArgumentException; 008 import com.croftsoft.core.lang.lifecycle.Commissionable; 009 import com.croftsoft.core.math.MathConstants; 010 import com.croftsoft.core.role.Server; 011 import com.croftsoft.core.util.loop.FixedDelayLoopGovernor; 012 import com.croftsoft.core.util.loop.Loopable; 013 import com.croftsoft.core.util.loop.Looper; 014 015 import com.croftsoft.apps.mars.ai.TankOperator; 016 import com.croftsoft.apps.mars.model.World; 017 import com.croftsoft.apps.mars.net.request.FireRequest; 018 import com.croftsoft.apps.mars.net.request.MoveRequest; 019 import com.croftsoft.apps.mars.net.request.Request; 020 import com.croftsoft.apps.mars.net.request.ViewRequest; 021 022 /********************************************************************* 023 * Mars server. 024 * 025 * @version 026 * 2003-06-13 027 * @since 028 * 2003-05-13 029 * @author 030 * <a href="https://www.croftsoft.com/">David Wallace Croft</a> 031 *********************************************************************/ 032 033 public final class MarsServer 034 implements Commissionable, Server 035 ////////////////////////////////////////////////////////////////////// 036 ////////////////////////////////////////////////////////////////////// 037 { 038 039 private static final boolean DEBUG = true; 040 041 private static final double UPDATE_RATE = 30.0; 042 043 private static final long SAMPLE_PERIOD = 10 * 1000; 044 045 private static final long REQUEST_TIMEOUT = 10 * 1000; 046 047 // 048 049 private final String primaryFilename; 050 051 private final String fallbackFilename; 052 053 private final Looper looper; 054 055 // 056 057 private GameInitAccessor gameInitAccessor; 058 059 private NetGame netGame; 060 061 private long count; 062 063 private long startTime; 064 065 private long lastRequestTime; 066 067 ////////////////////////////////////////////////////////////////////// 068 ////////////////////////////////////////////////////////////////////// 069 070 public MarsServer ( 071 String primaryFilename, 072 String fallbackFilename ) 073 ////////////////////////////////////////////////////////////////////// 074 { 075 this.primaryFilename = primaryFilename; 076 077 this.fallbackFilename = fallbackFilename; 078 079 setGameInitAccessor ( GameInit.createDefaultGameInit ( ) ); 080 081 looper = new Looper ( 082 new Loopable ( ) 083 { 084 public boolean loop ( ) 085 { 086 return MarsServer.this.loop ( ); 087 } 088 }, 089 new FixedDelayLoopGovernor ( UPDATE_RATE ), 090 null, 091 ( String ) null, 092 Thread.MIN_PRIORITY, 093 true ); 094 } 095 096 ////////////////////////////////////////////////////////////////////// 097 ////////////////////////////////////////////////////////////////////// 098 099 public void setGameInitAccessor ( 100 GameInitAccessor gameInitAccessor ) 101 ////////////////////////////////////////////////////////////////////// 102 { 103 NullArgumentException.check ( 104 this.gameInitAccessor = gameInitAccessor ); 105 } 106 107 ////////////////////////////////////////////////////////////////////// 108 ////////////////////////////////////////////////////////////////////// 109 110 public void init ( ) 111 ////////////////////////////////////////////////////////////////////// 112 { 113 if ( primaryFilename != null ) 114 { 115 try 116 { 117 netGame = NetGame.load ( 118 gameInitAccessor, primaryFilename, fallbackFilename ); 119 } 120 catch ( FileNotFoundException ex ) 121 { 122 } 123 catch ( Exception ex ) 124 { 125 ex.printStackTrace ( ); 126 } 127 } 128 129 if ( netGame == null ) 130 { 131 netGame = new NetGame ( gameInitAccessor ); 132 } 133 134 startTime = System.currentTimeMillis ( ); 135 136 lastRequestTime = startTime; 137 138 looper.init ( ); 139 } 140 141 public Object serve ( Object requestObject ) 142 ////////////////////////////////////////////////////////////////////// 143 { 144 synchronized ( this ) 145 { 146 lastRequestTime = System.currentTimeMillis ( ); 147 148 if ( DEBUG ) 149 { 150 ++count; 151 } 152 } 153 154 if ( !( requestObject instanceof Request ) ) 155 { 156 throw new IllegalArgumentException ( ); 157 } 158 159 looper.start ( ); 160 161 Request request = ( Request ) requestObject; 162 163 String playerName = request.getPlayerName ( ); 164 165 if ( playerName == null ) 166 { 167 return netGame.getGameData ( ); 168 } 169 170 Player player = netGame.getPlayer ( playerName ); 171 172 if ( player == null ) 173 { 174 return netGame.getGameData ( ); 175 } 176 177 player.setLastRequestTime ( System.currentTimeMillis ( ) ); 178 179 if ( request instanceof ViewRequest ) 180 { 181 GameData gameData = player.getGameData ( ); 182 183 if ( gameData == null ) 184 { 185 gameData = netGame.getGameData ( ); 186 } 187 188 return gameData; 189 } 190 191 TankOperator tankOperator 192 = player.getSeriTank ( ).getTankOperator ( ); 193 194 if ( request instanceof MoveRequest ) 195 { 196 MoveRequest moveRequest = ( MoveRequest ) request; 197 198 tankOperator.go ( moveRequest.getDestination ( ) ); 199 200 return null; 201 } 202 203 if ( request instanceof FireRequest ) 204 { 205 tankOperator.fire ( ); 206 207 return null; 208 } 209 210 throw new IllegalArgumentException ( ); 211 } 212 213 public void destroy ( ) 214 ////////////////////////////////////////////////////////////////////// 215 { 216 looper.stop ( ); 217 218 looper.destroy ( ); 219 220 try 221 { 222 synchronized ( this ) 223 { 224 netGame.save ( primaryFilename, fallbackFilename ); 225 } 226 } 227 catch ( Exception ex ) 228 { 229 ex.printStackTrace ( ); 230 } 231 } 232 233 ////////////////////////////////////////////////////////////////////// 234 // private methods 235 ////////////////////////////////////////////////////////////////////// 236 237 private synchronized boolean loop ( ) 238 ////////////////////////////////////////////////////////////////////// 239 { 240 netGame.update ( ); 241 242 long currentTime = System.currentTimeMillis ( ); 243 244 if ( DEBUG ) 245 { 246 if ( currentTime >= startTime + SAMPLE_PERIOD ) 247 { 248 System.out.println ( "requests per second: " 249 + ( MathConstants.MILLISECONDS_PER_SECOND * count ) 250 / ( currentTime - startTime ) ); 251 252 startTime = currentTime; 253 254 count = 0; 255 } 256 } 257 258 if ( currentTime >= lastRequestTime + REQUEST_TIMEOUT ) 259 { 260 if ( DEBUG ) 261 { 262 System.out.println ( "MarsServer game loop pausing..." ); 263 } 264 265 return false; 266 } 267 268 return true; 269 } 270 271 ////////////////////////////////////////////////////////////////////// 272 ////////////////////////////////////////////////////////////////////// 273 }