//----------------------------------------------------------------------------- // Copyright (c) 2012 GarageGames, LLC // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. //----------------------------------------------------------------------------- function initServer() { echo("\n--------- Initializing " @ $appName @ ": Server Scripts ---------"); //load prefs //Force-load the defaults just so we don't have any mistakes exec( "data/clientServer/scripts/server/defaults.cs" ); //Then, if the user has saved preferences, we load those over-top the defaults %prefPath = getPrefpath(); if ( isFile( %prefPath @ "/serverPrefs.cs" ) ) exec( %prefPath @ "/serverPrefs.cs" ); exec( "data/clientServer/scripts/server/audio.cs" ); exec( "data/clientServer/scripts/server/commands.cs" ); exec( "data/clientServer/scripts/server/kickban.cs" ); exec( "data/clientServer/scripts/server/message.cs" ); exec( "data/clientServer/scripts/server/levelDownload.cs" ); exec( "data/clientServer/scripts/server/levelLoad.cs" ); exec( "data/clientServer/scripts/server/levelInfo.cs" ); exec( "data/clientServer/scripts/server/connectionToClient.cs" ); // Server::Status is returned in the Game Info Query and represents the // current status of the server. This string sould be very short. $Server::Status = "Unknown"; // Turn on testing/debug script functions $Server::TestCheats = false; // Specify where the mission files are. $Server::MissionFileSpec = "data/levels/*.mis"; } //----------------------------------------------------------------------------- function initDedicated() { enableWinConsole(true); echo("\n--------- Starting Dedicated Server ---------"); // Make sure this variable reflects the correct state. $Server::Dedicated = true; // The server isn't started unless a mission has been specified. if ($missionArg !$= "") { createServer("MultiPlayer", $missionArg); } else echo("No mission specified (use -mission filename)"); } /// Attempt to find an open port to initialize the server with function portInit(%port) { %failCount = 0; while(%failCount < 10 && !setNetPort(%port)) { echo("Port init failed on port " @ %port @ " trying next port."); %port++; %failCount++; } } /// Create a server of the given type, load the given level, and then /// create a local client connection to the server. // /// @return true if successful. function createAndConnectToLocalServer( %serverType, %level ) { if( !createServer( %serverType, %level ) ) return false; %conn = new GameConnection( ServerConnection ); RootGroup.add( ServerConnection ); %conn.setConnectArgs( $pref::Player::Name ); %conn.setJoinPassword( $Client::Password ); %result = %conn.connectLocal(); if( %result !$= "" ) { %conn.delete(); destroyServer(); MessageBoxOK("Error starting local server!", "There was an error when trying to connect to the local server."); if(isObject(MainMenuGui)) Canvas.setContent(MainMenuGui); return false; } return true; } /// Create a server with either a "SinglePlayer" or "MultiPlayer" type /// Specify the level to load on the server function createServer(%serverType, %level) { // Increase the server session number. This is used to make sure we're // working with the server session we think we are. $Server::Session++; if (%level $= "") { error("createServer(): level name unspecified"); return false; } // Make sure our level name is relative so that it can send // across the network correctly %level = makeRelativePath(%level, getWorkingDirectory()); destroyServer(); $missionSequence = 0; $Server::PlayerCount = 0; $Server::ServerType = %serverType; $Server::LoadFailMsg = ""; $Physics::isSinglePlayer = true; // Setup for multi-player, the network must have been // initialized before now. if (%serverType $= "MultiPlayer") { $Physics::isSinglePlayer = false; echo("Starting multiplayer mode"); // Make sure the network port is set to the correct pref. portInit($Pref::Server::Port); allowConnections(true); if ($pref::Net::DisplayOnMaster !$= "Never" ) schedule(0,0,startHeartbeat); } // Let the game initialize some things now that the // the server has been created onServerCreated(); loadMission(%level, true); $Game::running = true; return true; } function onServerCreated() { // Server::GameType is sent to the master server. // This variable should uniquely identify your game and/or mod. $Server::GameType = $appName; // Server::MissionType sent to the master server. Clients can // filter servers based on mission type. // $Server::MissionType = "Deathmatch"; // GameStartTime is the sim time the game started. Used to calculated // game elapsed time. $Game::StartTime = 0; // Create the server physics world. physicsInitWorld( "server" ); physicsStartSimulation("server"); %cnt = DatablockFilesList.count(); loadDatablockFiles( DatablockFilesList, true ); %cnt = DatablockFilesList.count(); // Keep track of when the game started $Game::StartTime = $Sim::Time; } /// Shut down the server function destroyServer() { $Server::ServerType = ""; $Server::Running = false; allowConnections(false); stopHeartbeat(); $missionRunning = false; // End any running levels and shut down the physics sim onServerDestroyed(); //physicsDestroy(); // Delete all the server objects if (isObject(ServerGroup)) ServerGroup.delete(); // Delete all the connections: while (ClientGroup.getCount()) { %client = ClientGroup.getObject(0); %client.delete(); } $Server::GuidList = ""; // Delete all the data blocks... deleteDataBlocks(); // Save any server settings %prefPath = getPrefpath(); echo( "Exporting server prefs..." ); export( "$Pref::Server::*", %prefPath@"/serverPrefs.cs", false ); BanList::Export(%prefPath@"/banlist.cs"); // Increase the server session number. This is used to make sure we're // working with the server session we think we are. $Server::Session++; } function onServerDestroyed() { physicsStopSimulation("server"); if (!isObject( MissionGroup )) return; echo("*** ENDING MISSION"); // Inform the game code we're done. if(TheLevelInfo.isMethod("onMissionEnded")) TheLevelInfo.onMissionEnded(); // Inform the clients for( %clientIndex = 0; %clientIndex < ClientGroup.getCount(); %clientIndex++ ) { // clear ghosts and paths from all clients %cl = ClientGroup.getObject( %clientIndex ); %cl.endMission(); %cl.resetGhosting(); %cl.clearPaths(); } // Delete everything MissionGroup.delete(); MissionCleanup.delete(); clearServerPaths(); } /// Guid list maintenance functions function addToServerGuidList( %guid ) { %count = getFieldCount( $Server::GuidList ); for ( %i = 0; %i < %count; %i++ ) { if ( getField( $Server::GuidList, %i ) == %guid ) return; } $Server::GuidList = $Server::GuidList $= "" ? %guid : $Server::GuidList TAB %guid; } function removeFromServerGuidList( %guid ) { %count = getFieldCount( $Server::GuidList ); for ( %i = 0; %i < %count; %i++ ) { if ( getField( $Server::GuidList, %i ) == %guid ) { $Server::GuidList = removeField( $Server::GuidList, %i ); return; } } } /// When the server is queried for information, the value of this function is /// returned as the status field of the query packet. This information is /// accessible as the ServerInfo::State variable. function onServerInfoQuery() { return "Doing Ok"; }