View Javadoc

    1   /*
    2    * All Rights Reserved.
    3    * Copyright (C) 1999-2005 Tsukuba Bunko.
    4    *
    5    * Licensed under the BSD License ("the License"); you may not use
    6    * this file except in compliance with the License.
    7    * You may obtain a copy of the License at
    8    *
    9    *       http://www.tsukuba-bunko.org/licenses/LICENSE.txt
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   * $Id: PekoSystem.java,v 1.5 2005/11/23 05:41:43 ppoi Exp $
    18   */
    19  package tsukuba_bunko.peko;
    20
    21  import java.awt.Point;
    22
    23  import java.awt.event.WindowEvent;
    24  import java.awt.event.WindowAdapter;
    25
    26  import java.io.BufferedReader;
    27  import java.io.IOException;
    28  import java.io.InputStream;
    29  import java.io.InputStreamReader;
    30
    31  import java.net.URL;
    32
    33  import java.util.List;
    34
    35  import javax.swing.Icon;
    36  import javax.swing.ImageIcon;
    37  import javax.swing.JFrame;
    38  import javax.swing.JOptionPane;
    39
    40  import tsukuba_bunko.peko.canvas.CanvasManager;
    41
    42  import tsukuba_bunko.peko.resource.ResourceManager;
    43
    44  import tsukuba_bunko.peko.scenario.ScenarioProcessor;
    45
    46  import tsukuba_bunko.peko.session.Session;
    47  import tsukuba_bunko.peko.session.SessionManager;
    48
    49
    50  /***
    51   * "Peko" Visual Novel System のメインクラスです。
    52   * @author	$Author: ppoi $
    53   * @version	$Revision: 1.5 $
    54   */
    55  public class PekoSystem	{
    56
    57  	/***
    58  	 * 唯一の <code>PekoSystem</code> のインスタンス
    59  	 */
    60  	private static PekoSystem	_instance = null;
    61
    62
    63  	/***
    64  	 * <code>PekoSysmtem</code> のバージョン情報
    65  	 */
    66  	private Object[]	_versionInfo = null;
    67
    68  	/***
    69  	 * メインウィンドウ
    70  	 */
    71  	private JFrame	_mainWindow = null;
    72
    73  	/***
    74  	 * CanvasManager
    75  	 */
    76  	private CanvasManager	_canvasManager = null;
    77
    78  	/***
    79  	 * ScenrioProcessor
    80  	 */
    81  	private ScenarioProcessor	_scenarioProcessor = null;
    82
    83  	/***
    84  	 * SessionManager
    85  	 */
    86  	private SessionManager	_sessionManager = null;
    87
    88  	/***
    89  	 * ActionControler
    90  	 */
    91  	private ActionControler	_actionControler = null;
    92
    93  	/***
    94  	 * スタートフラグ
    95  	 */
    96  	private boolean	_started = false;
    97
    98
    99  	/***
    100 	 * <code>PekoSystem</code> のインスタンスを作成します。
    101 	 */
    102 	protected PekoSystem()
    103 	{
    104 		super();
    105 	}
    106
    107
    108 	/***
    109 	 * PVNS を開始します。
    110 	 */
    111 	public void start()
    112 	{
    113 		if( _started )	{
    114 			return;
    115 		}
    116
    117 		Point	location = (Point)_sessionManager.getSystemSaveData().getEntry( "windowLocation" );
    118 		if( location != null )	{
    119 			_mainWindow.setLocation( location );
    120 		}
    121 		else	{
    122 			_mainWindow.setLocationRelativeTo( null );
    123 		}
    124
    125 		_mainWindow.setVisible( true );
    126 		synchronized( _mainWindow )	{
    127 			try	{
    128 				if( !_mainWindow.isShowing() )	{
    129 					_mainWindow.wait();
    130 					Logger.debug( "[system] window opened." );
    131 				}
    132 			}
    133 			catch( InterruptedException ie )	{
    134 				Logger.debug( "[system] interrupted in waiting for opening window." );
    135 			}
    136 		}
    137 		_actionControler.returnTitle( true );
    138 	}
    139
    140 	/***
    141 	 * PVNS を終了します。
    142 	 */
    143 	public void exit()
    144 	{
    145 		boolean	last = _actionControler.isActive();
    146 		_actionControler.setActive( false );
    147 		ResourceManager	resources = ResourceManager.getInstance();
    148 		String	title = (String)resources.getResource( "peko.dialog.exit.title" );
    149 		String	message = (String)resources.getResource( "peko.dialog.exit.message" );
    150 		if( JOptionPane.OK_OPTION != JOptionPane.showConfirmDialog(_mainWindow, message, title, JOptionPane.OK_CANCEL_OPTION) )	{
    151 			_actionControler.setActive( last );
    152 			return;
    153 		}
    154 		_mainWindow.dispose();
    155
    156 		try	{
    157 			_sessionManager.getSystemSaveData().addEntry( "windowLocation", _mainWindow.getLocation() );
    158 			_sessionManager.saveSystemSaveData();
    159 		}
    160 		catch( Exception e )	{
    161 			Logger.error( MessageIDs.SYS6001E );
    162 		}
    163
    164 		Logger.info( "Bye!" );
    165 		System.exit( 0 );
    166 	}
    167
    168 	/***
    169 	 * タイトル画面画像を表示します。
    170 	 */
    171 	public void showTitle()
    172 	{
    173 		try	{
    174 			if( _started )	{
    175 				_scenarioProcessor.exit();
    176 				_canvasManager.clearAll();
    177 			}
    178 			else	{
    179 				_canvasManager.getStageCanvas().setUsingEffect( false );
    180 				_canvasManager.clearAll();
    181 				_canvasManager.getStageCanvas().setUsingEffect( true );
    182 				_started = true;
    183 			}
    184 			gc();
    185
    186 			_mainWindow.setTitle( (String)ResourceManager.getInstance().getResource("game-info.title") );
    187 			boolean	first = true;
    188 			while( true )	{
    189 				String	id = _canvasManager.showTitle( first );
    190 				if( id == null )	{
    191 					Logger.debug( "[system] canceled." );
    192 					break;
    193 				}
    194 				else if( "start".equals(id) )	{
    195 					ResourceManager	resources = ResourceManager.getInstance();
    196 					String	startPage = (String)resources.getResource( "peko.system.start-scene" );
    197 					if( startPage == null )	{
    198 						Logger.fatal( "[system] not specified scenario.start-scene." );
    199 						throw new InitializationError( "[system] not specified scenario.start-scene." );
    200 					}
    201 					else	{
    202 						_canvasManager.clearAll();
    203 						_sessionManager.initializeSession();
    204 						gc();
    205 						_scenarioProcessor.playScenario( startPage, _sessionManager.getSession() );
    206 					}
    207 					break;
    208 				}
    209 				else if( "resume".equals(id) )	{
    210 					if( load() )	{
    211 						break;
    212 					}
    213 				}
    214 				else if( "exit".equals(id) )	{
    215 					exit();
    216 				}
    217 				first = false;
    218 			}
    219 		}
    220 		catch( Exception e )	{
    221 			Logger.fatal( "[system] fatal error occured during saving states.", e );
    222 			JOptionPane.showMessageDialog( _mainWindow, "ERROR!", "Error!", JOptionPane.ERROR_MESSAGE );
    223 		}
    224 	}
    225
    226 	/***
    227 	 * セーブします。
    228 	 */
    229 	public void save()
    230 	{
    231 		try	{
    232 			Session	session = _sessionManager.getSession();
    233 			_canvasManager.saveState( session );
    234 			_sessionManager.saveCurrentSession();
    235 		}
    236 		catch( Exception e )	{
    237 			Logger.fatal( "[system] fatal error occured during saving states.", e );
    238 			JOptionPane.showMessageDialog( _mainWindow, "[system] fatal error occured during saving states.", "Error!", JOptionPane.ERROR_MESSAGE );
    239 			return;
    240 		}
    241
    242 		try	{
    243 			_sessionManager.saveSystemSaveData();
    244 		}
    245 		catch( Exception e )	{
    246 			Logger.fatal( "[system] fatal error occured during saving states.", e );
    247 			PekoSystem.showErrorDialog( "A fatal error occured during saving states", e, true );
    248 		}
    249 	}
    250
    251 	/***
    252 	 * ロードします。
    253 	 */
    254 	public boolean load()
    255 	{
    256 		boolean	result = false;
    257 		try	{
    258 			_actionControler.setPlayModeToNormal();
    259 			if( _sessionManager.load() )	{
    260 				_scenarioProcessor.exit();
    261 				_canvasManager.clearAll();
    262 				gc();
    263
    264 				Session	session = _sessionManager.getSession();
    265 				_mainWindow.setTitle( session.getSceneContext().getSceneTitle() + " - " + ResourceManager.getInstance().getResource("game-info.title") );
    266 				_canvasManager.resume( session );
    267 				gc();
    268 				_scenarioProcessor.playScenario( session.getSceneContext().getSceneName(), session );
    269 				result = true;
    270 			}
    271 			else	{
    272 				result = false;
    273 			}
    274 		}
    275 		catch( Exception e )	{
    276 			Logger.fatal( "[system] fatal error occured during saving states.", e );
    277 			JOptionPane.showMessageDialog( _mainWindow, "[system] fatal error occured during saving states.", "Error!", JOptionPane.ERROR_MESSAGE );
    278 		}
    279 		return result;
    280 	}
    281
    282 	/***
    283 	 * システムのバージョン情報ダイアログを表示します。
    284 	 */
    285 	public void showSystemVersionInfo()
    286 	{
    287 		ImageIcon	icon = null;
    288 		URL	iconURL = getClass().getClassLoader().getResource( "pvns-logo.gif" );
    289 		if( iconURL != null )	{
    290 			icon = new ImageIcon( iconURL, "PVNS Logo" );
    291 		}
    292 		JOptionPane.showMessageDialog( _mainWindow, _versionInfo, (String)_versionInfo[0], JOptionPane.INFORMATION_MESSAGE, icon );
    293 	}
    294
    295 	/***
    296 	 * ゲームのバージョン情報ダイアログを表示します。
    297 	 */
    298 	public void showGameVersionInfo()
    299 	{
    300 		ResourceManager	resources = ResourceManager.getInstance();
    301
    302 		Icon	icon = (Icon)resources.getResource( "game-info.logo", true );
    303 		List	texts = new java.util.ArrayList();
    304 		String[]	props = { "game-info.title", "game-info.version", "game-info.publisher", "game-info.copyright" };
    305 		for( int i = 0; i < props.length; ++i )	{
    306 			String	var = (String)resources.getResource( props[i], true );
    307 			if( var != null )	{
    308 				texts.add( var );
    309 			}
    310 		}
    311
    312 		List	additionalInfo = (List)resources.getResource( "game-info.additional-info", true );
    313 		if( (additionalInfo != null) && !additionalInfo.isEmpty() )	{
    314 			if( !texts.isEmpty() )	{
    315 				texts.add( " " );
    316 			}
    317 			texts.addAll( additionalInfo );
    318 		}
    319
    320 		if( !texts.isEmpty() )	{
    321 			JOptionPane.showMessageDialog( _mainWindow, texts.toArray(), (String)resources.getResource("game-info.title"), JOptionPane.INFORMATION_MESSAGE, icon );
    322 		}
    323 	}
    324
    325 	/***
    326 	 * PVNS のバージョン情報を取得します.
    327 	 * @return	バージョン情報
    328 	 */
    329 	public Object[] getPekoSystemVersion()
    330 	{
    331 		return _versionInfo;
    332 	}
    333
    334 	/***
    335 	 * メインウィンドウを取得します。
    336 	 * @return	メインウィンドウ
    337 	 */
    338 	public JFrame getMainWindow()
    339 	{
    340 		return _mainWindow;
    341 	}
    342
    343 	/***
    344 	 * CanvasManager を取得します。
    345 	 * @return	CanvasManager
    346 	 */
    347 	public CanvasManager getCanvasManager()
    348 	{
    349 		return _canvasManager;
    350 	}
    351
    352 	/***
    353 	 * ActionControler を取得します。
    354 	 * @return	ActionControler
    355 	 */
    356 	public ActionControler getActionControler()
    357 	{
    358 		return _actionControler;
    359 	}
    360
    361
    362 	/***
    363 	 * "Peko" のバージョン情報を準備します。
    364 	 */
    365 	private void prepareVersionInfo()
    366 	{
    367 		try	{
    368 			InputStream	is = PekoSystem.class.getResourceAsStream( "version.txt" );
    369 			if( is != null )	{
    370 				BufferedReader	reader = new BufferedReader( new InputStreamReader(is, "Shift_JIS") );
    371 				String	line = reader.readLine();
    372 				List	lines = new java.util.ArrayList();
    373 				while( line != null )	{
    374 					lines.add( line );
    375 					line = reader.readLine();
    376 				}
    377 				reader.close();
    378 				is.close();
    379 				_versionInfo = lines.toArray();
    380 			}
    381 			else	{
    382 				Logger.error( "[system] missing version.txt." );
    383 				Logger.debug( "[system] using embeded version info." );
    384 				_versionInfo = new Object[]{ "\"Peko\" Visual Novel System", "version 1.0", "All Rights Reserved.", "(c)Copyright by Tsukuba Bunko." };
    385 			}
    386 		}
    387 		catch( IOException ioe )	{
    388 			Logger.error( "[system] fail to read version info.", ioe );
    389 			Logger.debug( "[system] using embeded version info." );
    390 			_versionInfo = new Object[]{ "\"Peko\" Visual Novel System", "version 1.0", "All Rights Reserved.", "(c)Copyright by Tsukuba Bunko." };
    391 		}
    392 	}
    393
    394 	/***
    395 	 * メインウィンドウを準備します。
    396 	 */
    397 	private void prepareMainWindow()
    398 	{
    399 		JFrame	window = new JFrame( (String)_versionInfo[0] );
    400 		_mainWindow = window;
    401
    402 		window.setDefaultCloseOperation( JFrame.DO_NOTHING_ON_CLOSE );
    403 		window.addWindowListener( new WindowAdapter()	{
    404 				public void windowOpened( WindowEvent ev )
    405 				{
    406 					synchronized( _mainWindow )	{
    407 						_mainWindow.notify();
    408 					}
    409 				}
    410 				public void windowClosing( WindowEvent ev )
    411 				{
    412 					exit();
    413 				}
    414 			});
    415 	}
    416
    417 	/***
    418 	 * ResourceManager を初期化します.
    419 	 * @throws	InitializationError	初期化に失敗した場合
    420 	 */
    421 	private void prepareResources()
    422 	{
    423 		try	{
    424 			ResourceManager.getInstance();
    425 		}
    426 		catch( Exception e )	{
    427 			throw new InitializationError();
    428 		}
    429 	}
    430
    431 	/***
    432 	 * CanvasManager を初期化します。
    433 	 */
    434 	private void prepareCanvasManager()
    435 	{
    436 		_canvasManager = new CanvasManager();
    437 		_canvasManager.initialize();
    438 	}
    439
    440 	/***
    441 	 * ScenarioProcessor を準備します。
    442 	 */
    443 	private void prepareScenarioProcessor()
    444 	{
    445 		_scenarioProcessor = new ScenarioProcessor();
    446 	}
    447
    448 	/***
    449 	 * SessionManager を準備します。
    450 	 */
    451 	private void prepareSessionManager()
    452 	{
    453 		_sessionManager = new SessionManager();
    454 	}
    455
    456 	/***
    457 	 * ActionControler を準備します。
    458 	 */
    459 	private void prepareActionControler()
    460 	{
    461 		ActionControler	controler = new ActionControler();
    462 		_canvasManager.getTextCanvas().addMouseListener( controler );
    463 		_canvasManager.getStageCanvas().addMouseListener( controler );
    464 		_mainWindow.addKeyListener( controler );
    465 		_actionControler = controler;
    466 	}
    467
    468 	/***
    469 	 * 強制的にガベッジコレクタを起動します。
    470 	 */
    471 	private void gc()
    472 	{
    473 		Runtime	runtime = Runtime.getRuntime();
    474 		long	before = runtime.freeMemory();
    475
    476 		System.runFinalization();
    477 		System.gc();
    478
    479 		long	after = runtime.freeMemory();
    480 		Logger.debug( "[system] run gc. before=" + before + ", after=" + after );
    481 	}
    482
    483 	/***
    484 	 * 唯一の <code>PekoSystem</code> のインスタンスを取得します.
    485 	 * @return	唯一の <code>PekoSystem</code> のインスタンス
    486 	 */
    487 	public static PekoSystem getInstance()
    488 	{
    489 		if( _instance == null )	{
    490 			synchronized( PekoSystem.class )	{
    491 				if( _instance == null )	{
    492 					_instance = new PekoSystem();
    493 					_instance.prepareVersionInfo();
    494 					_instance.prepareResources();
    495 					_instance.prepareSessionManager();
    496 					_instance.prepareMainWindow();
    497 					_instance.prepareCanvasManager();
    498 					_instance.prepareActionControler();
    499 					_instance.prepareScenarioProcessor();
    500 				}
    501 			}
    502 		}
    503 		return _instance;
    504 	}
    505
    506 	/***
    507 	 * エラーダイアログを表示します。
    508 	 * @param	message	エラーメッセージ
    509 	 * @param	e	例外オブジェクト
    510 	 * @param	exit	強制終了する場合 <code>true</code>、しない場合 <code>false</code>
    511 	 */
    512 	public static void showErrorDialog( String message, Throwable e, boolean exit )
    513 	{
    514 		if( message == null )	{
    515 			message = e.getMessage();
    516 		}
    517
    518 		StackTraceElement[]	stackTrace = e.getStackTrace();
    519 		Object[]	messages = new Object[ stackTrace.length + 2 ];
    520 		for( int i = 0; i < stackTrace.length; ++i )	{
    521 			messages[i + 1] = stackTrace[i];
    522 		}
    523 		messages[0] = "Fatal Error :" + message;
    524 		messages[1] = e.getClass().getName() + " : " + e.getMessage();
    525 		JOptionPane.showMessageDialog( null, messages, "FATAL ERROR ! -\"Peko\" Visual Novel System", JOptionPane.ERROR_MESSAGE );
    526 		if( exit )	{
    527 			System.exit( -1 );
    528 		}
    529 	}
    530
    531
    532 	/***
    533 	 * "Peko" Visual Novel System を起動します。
    534 	 */
    535 	public static void main( String[] args )
    536 		throws Exception
    537 	{
    538 		Logger.prepare();
    539 		try	{
    540 			PekoSystem	system = PekoSystem.getInstance();
    541 			Object[]	versionInfo = system.getPekoSystemVersion();
    542 			Logger.info( (String)versionInfo[0] );
    543 			Logger.info( (String)versionInfo[1] );
    544
    545 			system.start();
    546 		}
    547 		catch( Throwable e )	{
    548 			showErrorDialog( null, e, true );
    549 		}
    550 	}
    551 }