Moved game loop into OSystem. Eventually, the only responsibility of the

main function will be to instantiate the initial objects, and clean up
when we're done.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@404 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2005-05-02 19:36:05 +00:00
parent f5684caa4a
commit eb8254d133
9 changed files with 231 additions and 183 deletions

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: mainSDL.cxx,v 1.33 2005-05-01 18:57:20 stephena Exp $ // $Id: mainSDL.cxx,v 1.34 2005-05-02 19:35:57 stephena Exp $
//============================================================================ //============================================================================
#include <fstream> #include <fstream>
@ -23,11 +23,6 @@
#include <algorithm> #include <algorithm>
#include <cstdlib> #include <cstdlib>
#ifdef HAVE_GETTIMEOFDAY
#include <time.h>
#include <sys/time.h>
#endif
#include <SDL.h> #include <SDL.h>
#include "bspf.hxx" #include "bspf.hxx"
@ -50,48 +45,13 @@
#error Unsupported platform! #error Unsupported platform!
#endif #endif
static void mainGameLoop();
static Console* CreateConsole(const string& romfile); static Console* CreateConsole(const string& romfile);
static void Cleanup();
static uInt32 GetTicks();
static void SetupProperties(PropertiesSet& set); static void SetupProperties(PropertiesSet& set);
static void ShowInfo(const string& msg); static void Cleanup();
// Pointer to the main parent osystem object or the null pointer // Pointer to the main parent osystem object or the null pointer
static OSystem* theOSystem = (OSystem*) NULL; static OSystem* theOSystem = (OSystem*) NULL;
// Indicates whether to show information during program execution
static bool theShowInfoFlag;
/**
Prints given message based on 'theShowInfoFlag'
*/
static inline void ShowInfo(const string& msg)
{
if(theShowInfoFlag && msg != "")
cout << msg << endl;
}
/**
Returns number of ticks in microseconds
*/
#ifdef HAVE_GETTIMEOFDAY
inline uInt32 GetTicks()
{
timeval now;
gettimeofday(&now, 0);
return (uInt32) (now.tv_sec * 1000000 + now.tv_usec);
}
#else
inline uInt32 GetTicks()
{
return (uInt32) SDL_GetTicks() * 1000;
}
#endif
/** /**
Setup the properties set by first checking for a user file, Setup the properties set by first checking for a user file,
@ -123,7 +83,8 @@ void SetupProperties(PropertiesSet& set)
else else
set.load("", false); set.load("", false);
ShowInfo(buf.str()); if(theOSystem->settings().getBool("showinfo"))
cout << buf.str() << endl;
} }
@ -160,103 +121,6 @@ Console* CreateConsole(const string& romfile)
} }
// FIXME - move this into OSystem, so that different systems can make use
// of system-specific timers (probably more accurate than SDL can provide)
/**
Runs the main game loop until the current game exits.
*/
void mainGameLoop()
{
// These variables are common to both timing options
// and are needed to calculate the overall frames per second.
uInt32 frameTime = 0, numberOfFrames = 0;
if(theOSystem->settings().getBool("accurate")) // normal, CPU-intensive timing
{
// Set up accurate timing stuff
uInt32 startTime, delta;
uInt32 timePerFrame = (uInt32)(1000000.0 / (double) theOSystem->settings().getInt("framerate"));
// Set the base for the timers
frameTime = 0;
// Main game loop
for(;;)
{
// Exit if the user wants to quit
if(theOSystem->eventHandler().doExitGame() ||
theOSystem->eventHandler().doQuit())
break;
startTime = GetTicks();
theOSystem->eventHandler().poll();
theOSystem->frameBuffer().update();
// Now, waste time if we need to so that we are at the desired frame rate
for(;;)
{
delta = GetTicks() - startTime;
if(delta >= timePerFrame)
break;
}
frameTime += GetTicks() - startTime;
++numberOfFrames;
}
}
else // less accurate, less CPU-intensive timing
{
// Set up less accurate timing stuff
uInt32 startTime, virtualTime, currentTime;
uInt32 timePerFrame = (uInt32)(1000000.0 / (double) theOSystem->settings().getInt("framerate"));
// Set the base for the timers
virtualTime = GetTicks();
frameTime = 0;
// Main game loop
for(;;)
{
// Exit if the user wants to quit
if(theOSystem->eventHandler().doExitGame() ||
theOSystem->eventHandler().doQuit())
break;
startTime = GetTicks();
theOSystem->eventHandler().poll();
theOSystem->frameBuffer().update();
currentTime = GetTicks();
virtualTime += timePerFrame;
if(currentTime < virtualTime)
{
SDL_Delay((virtualTime - currentTime)/1000);
}
currentTime = GetTicks() - startTime;
frameTime += currentTime;
++numberOfFrames;
}
}
if(theShowInfoFlag)
{
double executionTime = (double) frameTime / 1000000.0;
double framesPerSecond = (double) numberOfFrames / executionTime;
cout << endl;
cout << numberOfFrames << " total frames drawn\n";
cout << framesPerSecond << " frames/second\n";
cout << endl;
cout << "Cartridge Name: " << theOSystem->console().properties().get("Cartridge.Name");
cout << endl;
cout << "Cartridge MD5: " << theOSystem->console().properties().get("Cartridge.MD5");
cout << endl << endl;
}
}
/** /**
Does general Cleanup in case any operation failed (or at end of program). Does general Cleanup in case any operation failed (or at end of program).
*/ */
@ -306,13 +170,12 @@ int main(int argc, char* argv[])
// Finally, make sure the settings are valid // Finally, make sure the settings are valid
// We do it once here, so the rest of the program can assume valid settings // We do it once here, so the rest of the program can assume valid settings
//FIXME theOSystem->settings().validate(); theOSystem->settings().validate();
// Create the event handler for the system // Create the event handler for the system
EventHandler handler(theOSystem); EventHandler handler(theOSystem);
// Cache some settings so they don't have to be repeatedly searched for // Cache some settings so they don't have to be repeatedly searched for
theShowInfoFlag = theOSystem->settings().getBool("showinfo");
bool theRomLauncherFlag = false;//true;//FIXMEtheSettings->getBool("romlauncher"); bool theRomLauncherFlag = false;//true;//FIXMEtheSettings->getBool("romlauncher");
// Create a properties set for us to use and set it up // Create a properties set for us to use and set it up
@ -354,9 +217,9 @@ int main(int argc, char* argv[])
*/ */
// Print message about the framerate // Print message about the framerate
ostringstream message; string framerate = "Framerate: " + theOSystem->settings().getString("framerate");
message << "Framerate: " << theOSystem->settings().getInt("framerate"); if(theOSystem->settings().getBool("showinfo"))
ShowInfo(message.str()); cout << framerate << endl;
//// Main loop //// //// Main loop ////
// Load a ROM and start the main game loop // Load a ROM and start the main game loop
@ -386,7 +249,7 @@ int main(int argc, char* argv[])
else else
{ {
if((theConsole = CreateConsole(romfile)) != NULL) if((theConsole = CreateConsole(romfile)) != NULL)
mainGameLoop(); theOSystem->mainGameLoop();
else else
break; break;
} }
@ -398,7 +261,7 @@ int main(int argc, char* argv[])
ostringstream romfile; ostringstream romfile;
romfile << argv[argc - 1]; romfile << argv[argc - 1];
theConsole = CreateConsole(romfile.str()); theConsole = CreateConsole(romfile.str());
mainGameLoop(); theOSystem->mainGameLoop();
} }
// Cleanup time ... // Cleanup time ...

View File

@ -13,20 +13,20 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: OSystem.hxx,v 1.6 2005-05-01 18:57:21 stephena Exp $ // $Id: OSystem.hxx,v 1.7 2005-05-02 19:36:05 stephena Exp $
//============================================================================ //============================================================================
#ifndef OSYSTEM_HXX #ifndef OSYSTEM_HXX
#define OSYSTEM_HXX #define OSYSTEM_HXX
class EventHandler;
class FrameBuffer;
class Sound;
class Settings;
class PropertiesSet; class PropertiesSet;
class Menu; class Menu;
class Browser; class Browser;
#include "EventHandler.hxx"
#include "FrameBuffer.hxx"
#include "Sound.hxx"
#include "Settings.hxx"
#include "Console.hxx" #include "Console.hxx"
#include "bspf.hxx" #include "bspf.hxx"
@ -37,7 +37,7 @@ class Browser;
other objects belong. other objects belong.
@author Stephen Anthony @author Stephen Anthony
@version $Id: OSystem.hxx,v 1.6 2005-05-01 18:57:21 stephena Exp $ @version $Id: OSystem.hxx,v 1.7 2005-05-02 19:36:05 stephena Exp $
*/ */
class OSystem class OSystem
{ {
@ -60,20 +60,6 @@ class OSystem
*/ */
void attach(EventHandler* eventhandler) { myEventHandler = eventhandler; } void attach(EventHandler* eventhandler) { myEventHandler = eventhandler; }
/**
Adds the specified framebuffer to the system.
@param framebuffer The framebuffer to add
*/
void attach(FrameBuffer* framebuffer) { myFrameBuffer = framebuffer; }
/**
Adds the specified sound device to the system.
@param sound The sound device to add
*/
void attach(Sound* sound) { mySound = sound; }
/** /**
Adds the specified settings object to the system. Adds the specified settings object to the system.
@ -256,6 +242,20 @@ class OSystem
// The following methods are system-specific and must be implemented // The following methods are system-specific and must be implemented
// in derived classes. // in derived classes.
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
/**
This method runs the main gaming loop. Since different platforms
may use different timing methods and/or algorithms, this method has
been abstracted to each platform.
*/
virtual void mainGameLoop() = 0;
/**
This method returns number of ticks in microseconds.
@return Current time in microseconds.
*/
virtual uInt32 getTicks() = 0;
/** /**
This method should be called to get the filename of a state file This method should be called to get the filename of a state file
given the state number. given the state number.

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: Settings.cxx,v 1.35 2005-05-01 18:57:21 stephena Exp $ // $Id: Settings.cxx,v 1.36 2005-05-02 19:36:05 stephena Exp $
//============================================================================ //============================================================================
#include <cassert> #include <cassert>
@ -47,12 +47,11 @@ Settings::Settings(OSystem* osystem)
set("fragsize", "512"); set("fragsize", "512");
set("fullscreen", "false"); set("fullscreen", "false");
set("grabmouse", "false"); set("grabmouse", "false");
set("volume", "-1"); set("volume", "100");
set("accurate", "false"); set("framerate", "60");
set("framerate", "-1");
set("keymap", ""); set("keymap", "");
set("joymap", ""); set("joymap", "");
set("zoom", "1"); set("zoom", "2");
set("showinfo", "false"); set("showinfo", "false");
set("mergeprops", "false"); set("mergeprops", "false");
set("paddle", "0"); set("paddle", "0");
@ -164,6 +163,62 @@ bool Settings::loadCommandLine(Int32 argc, char** argv)
return true; return true;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Settings::validate()
{
string s;
uInt32 i;
float f;
s = getString("video");
if(s != "soft" && s != "gl")
set("video", "soft");
#ifdef DISPLAY_OPENGL
s = getString("gl_filter");
if(s != "linear" && s != "nearest")
set("gl_filter", "nearest");
f = getFloat("gl_aspect");
if(f < 1.1 or f > 2.0)
set("gl_aspect", "2.0");
#endif
#ifdef SOUND_SUPPORT
i = getInt("fragsize");
if(i != 256 && i != 512 && i != 1024 && i != 2048 && i != 4096)
#ifdef WIN32
set("fragsize", "2048");
#else
set("fragsize", "512");
#endif
i = getInt("volume");
if(i < 0 || i > 100)
set("volume", "100");
#endif
i = getInt("framerate");
if(i < 1 || i > 300)
set("framerate", "60");
i = getInt("zoom");
if(i < 1 || i > 6)
set("zoom", "2");
i = getInt("paddle");
if(i < 0 || i > 3)
set("paddle", "0");
s = getString("palette");
if(s != "standard" && s != "original" && s != "z26")
set("palette", "standard");
s = getString("romname");
if(s != "romname" && s != "md5sum")
set("ssname", "romname");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Settings::usage() void Settings::usage()
{ {

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: Settings.hxx,v 1.21 2005-02-22 18:41:14 stephena Exp $ // $Id: Settings.hxx,v 1.22 2005-05-02 19:36:05 stephena Exp $
//============================================================================ //============================================================================
#ifndef SETTINGS_HXX #ifndef SETTINGS_HXX
@ -28,7 +28,7 @@ class OSystem;
This class provides an interface for accessing frontend specific settings. This class provides an interface for accessing frontend specific settings.
@author Stephen Anthony @author Stephen Anthony
@version $Id: Settings.hxx,v 1.21 2005-02-22 18:41:14 stephena Exp $ @version $Id: Settings.hxx,v 1.22 2005-05-02 19:36:05 stephena Exp $
*/ */
class Settings class Settings
{ {
@ -61,6 +61,12 @@ class Settings
*/ */
bool loadCommandLine(Int32 argc, char** argv); bool loadCommandLine(Int32 argc, char** argv);
/**
This method should be called *after* settings have been read,
to validate (and change, if necessary) any improper settings.
*/
void validate();
/** /**
This method should be called to display usage information. This method should be called to display usage information.
*/ */

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: GameInfoDialog.hxx,v 1.1 2005-03-27 03:07:34 stephena Exp $ // $Id: GameInfoDialog.hxx,v 1.2 2005-05-02 19:36:05 stephena Exp $
// //
// Based on code from ScummVM - Scumm Interpreter // Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project // Copyright (C) 2002-2004 The ScummVM project
@ -42,7 +42,7 @@ class GameInfoDialog : public Dialog
GameInfoDialog(OSystem* osystem, uInt16 x, uInt16 y, uInt16 w, uInt16 h); GameInfoDialog(OSystem* osystem, uInt16 x, uInt16 y, uInt16 w, uInt16 h);
~GameInfoDialog(); ~GameInfoDialog();
void setGameProfile(Properties& props) { myGameProperties = props; } void setGameProfile(Properties& props) { myGameProperties = &props; }
protected: protected:
ButtonWidget* myNextButton; ButtonWidget* myNextButton;
@ -63,7 +63,7 @@ class GameInfoDialog : public Dialog
void loadConfig() { displayInfo(); } void loadConfig() { displayInfo(); }
private: private:
Properties myGameProperties; Properties* myGameProperties;
}; };
#endif #endif

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: OSystemUNIX.cxx,v 1.3 2005-02-22 18:41:15 stephena Exp $ // $Id: OSystemUNIX.cxx,v 1.4 2005-05-02 19:36:05 stephena Exp $
//============================================================================ //============================================================================
#include <cstdlib> #include <cstdlib>
@ -28,6 +28,11 @@
#include "OSystem.hxx" #include "OSystem.hxx"
#include "OSystemUNIX.hxx" #include "OSystemUNIX.hxx"
#ifdef HAVE_GETTIMEOFDAY
#include <time.h>
#include <sys/time.h>
#endif
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
OSystemUNIX::OSystemUNIX() OSystemUNIX::OSystemUNIX()
{ {
@ -38,6 +43,108 @@ OSystemUNIX::~OSystemUNIX()
{ {
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void OSystemUNIX::mainGameLoop()
{
// These variables are common to both timing options
// and are needed to calculate the overall frames per second.
uInt32 frameTime = 0, numberOfFrames = 0;
uInt32 timePerFrame = (uInt32)(1000000.0 / (double) mySettings->getInt("framerate"));
if(mySettings->getBool("accurate")) // normal, CPU-intensive timing
{
// Set up accurate timing stuff
uInt32 startTime, delta;
// Set the base for the timers
frameTime = 0;
// Main game loop
for(;;)
{
// Exit if the user wants to quit
if(myEventHandler->doExitGame() || myEventHandler->doQuit())
break;
startTime = getTicks();
myEventHandler->poll();
myFrameBuffer->update();
// Now, waste time if we need to so that we are at the desired frame rate
for(;;)
{
delta = getTicks() - startTime;
if(delta >= timePerFrame)
break;
}
frameTime += getTicks() - startTime;
++numberOfFrames;
}
}
else // less accurate, less CPU-intensive timing
{
// Set up less accurate timing stuff
uInt32 startTime, virtualTime, currentTime;
// Set the base for the timers
virtualTime = getTicks();
frameTime = 0;
// Main game loop
for(;;)
{
// Exit if the user wants to quit
if(myEventHandler->doExitGame() || myEventHandler->doQuit())
break;
startTime = getTicks();
myEventHandler->poll();
myFrameBuffer->update();
currentTime = getTicks();
virtualTime += timePerFrame;
if(currentTime < virtualTime)
{
SDL_Delay((virtualTime - currentTime)/1000);
}
currentTime = getTicks() - startTime;
frameTime += currentTime;
++numberOfFrames;
}
}
if(mySettings->getBool("showinfo"))
{
double executionTime = (double) frameTime / 1000000.0;
double framesPerSecond = (double) numberOfFrames / executionTime;
cout << endl;
cout << numberOfFrames << " total frames drawn\n";
cout << framesPerSecond << " frames/second\n";
cout << endl;
cout << "Cartridge Name: " << myConsole->properties().get("Cartridge.Name");
cout << endl;
cout << "Cartridge MD5: " << myConsole->properties().get("Cartridge.MD5");
cout << endl << endl;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 OSystemUNIX::getTicks()
{
#ifdef HAVE_GETTIMEOFDAY
timeval now;
gettimeofday(&now, 0);
return (uInt32) (now.tv_sec * 1000000 + now.tv_usec);
#else
return (uInt32) SDL_GetTicks() * 1000;
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string OSystemUNIX::stateFilename(const string& md5, uInt32 state) string OSystemUNIX::stateFilename(const string& md5, uInt32 state)
{ {

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: OSystemUNIX.hxx,v 1.3 2005-02-22 18:41:16 stephena Exp $ // $Id: OSystemUNIX.hxx,v 1.4 2005-05-02 19:36:05 stephena Exp $
//============================================================================ //============================================================================
#ifndef OSYSTEM_UNIX_HXX #ifndef OSYSTEM_UNIX_HXX
@ -26,7 +26,7 @@
This class defines UNIX-like OS's (Linux) system specific settings. This class defines UNIX-like OS's (Linux) system specific settings.
@author Stephen Anthony @author Stephen Anthony
@version $Id: OSystemUNIX.hxx,v 1.3 2005-02-22 18:41:16 stephena Exp $ @version $Id: OSystemUNIX.hxx,v 1.4 2005-05-02 19:36:05 stephena Exp $
*/ */
class OSystemUNIX : public OSystem class OSystemUNIX : public OSystem
{ {
@ -42,6 +42,20 @@ class OSystemUNIX : public OSystem
virtual ~OSystemUNIX(); virtual ~OSystemUNIX();
public: public:
/**
This method runs the main gaming loop. Since different platforms
may use different timing methods and/or algorithms, this method has
been abstracted to each platform.
*/
virtual void mainGameLoop();
/**
This method returns number of ticks in microseconds.
@return Current time in microseconds.
*/
virtual uInt32 getTicks();
/** /**
This method should be called to get the filename of a state file This method should be called to get the filename of a state file
given the state number. given the state number.

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: SettingsUNIX.cxx,v 1.10 2005-02-22 18:41:16 stephena Exp $ // $Id: SettingsUNIX.cxx,v 1.11 2005-05-02 19:36:05 stephena Exp $
//============================================================================ //============================================================================
#include <cstdlib> #include <cstdlib>
@ -47,6 +47,10 @@ SettingsUNIX::SettingsUNIX(OSystem* osystem)
string userConfigFile = stelladir + "/stellarc"; string userConfigFile = stelladir + "/stellarc";
string systemConfigFile = "/etc/stellarc"; string systemConfigFile = "/etc/stellarc";
myOSystem->setConfigFiles(userConfigFile, systemConfigFile); myOSystem->setConfigFiles(userConfigFile, systemConfigFile);
// This argument is only valid for Linux/UNIX, and will eventually
// be removed
set("accurate", "false");
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: SettingsWin32.cxx,v 1.12 2004-09-14 19:10:28 stephena Exp $ // $Id: SettingsWin32.cxx,v 1.13 2005-05-02 19:36:05 stephena Exp $
//============================================================================ //============================================================================
#include <sstream> #include <sstream>
@ -66,7 +66,6 @@ SettingsWin32::SettingsWin32()
// Now create Win32 specific settings // Now create Win32 specific settings
set("video_driver", "windib"); // This seems to be much faster than DirectX set("video_driver", "windib"); // This seems to be much faster than DirectX
set("romdir", "roms"); set("romdir", "roms");
set("accurate", "false"); // Don't change this, or the sound will skip
set("fragsize", "2048"); // Anything less than this usually causes sound skipping set("fragsize", "2048"); // Anything less than this usually causes sound skipping
#ifdef SNAPSHOT_SUPPORT #ifdef SNAPSHOT_SUPPORT
set("ssdir", ".\\"); set("ssdir", ".\\");