mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-22 13:16:23 +00:00
First Commit
For Azeroth!
This commit is contained in:
210
src/server/worldserver/CMakeLists.txt
Normal file
210
src/server/worldserver/CMakeLists.txt
Normal file
@@ -0,0 +1,210 @@
|
||||
# Copyright (C)
|
||||
#
|
||||
# This file is free software; as a special exception the author gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
file(GLOB_RECURSE sources_CommandLine CommandLine/*.cpp CommandLine/*.h)
|
||||
file(GLOB_RECURSE sources_RemoteAccess RemoteAccess/*.cpp RemoteAccess/*.h)
|
||||
file(GLOB_RECURSE sources_TCSoap TCSoap/*.cpp TCSoap/*.h)
|
||||
file(GLOB_RECURSE sources_WorldThread WorldThread/*.cpp WorldThread/*.h)
|
||||
file(GLOB sources_localdir *.cpp *.h)
|
||||
|
||||
if (USE_COREPCH)
|
||||
set(worldserver_PCH_HDR PrecompiledHeaders/worldPCH.h)
|
||||
set(worldserver_PCH_SRC PrecompiledHeaders/worldPCH.cpp)
|
||||
endif()
|
||||
|
||||
set(worldserver_SRCS
|
||||
${worldserver_SRCS}
|
||||
${sources_CommandLine}
|
||||
${sources_RemoteAccess}
|
||||
${sources_TCSoap}
|
||||
${sources_WorldThread}
|
||||
${sources_localdir}
|
||||
)
|
||||
|
||||
if( WIN32 )
|
||||
set(worldserver_SRCS
|
||||
${worldserver_SRCS}
|
||||
${sources_windows_Debugging}
|
||||
)
|
||||
if ( MSVC )
|
||||
set(worldserver_SRCS
|
||||
${worldserver_SRCS}
|
||||
worldserver.rc
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include_directories(
|
||||
${CMAKE_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}/dep/g3dlite/include
|
||||
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour
|
||||
${CMAKE_SOURCE_DIR}/dep/gsoap
|
||||
${CMAKE_SOURCE_DIR}/dep/sockets/include
|
||||
${CMAKE_SOURCE_DIR}/dep/SFMT
|
||||
${CMAKE_SOURCE_DIR}/src/server/collision
|
||||
${CMAKE_SOURCE_DIR}/src/server/collision/Management
|
||||
${CMAKE_SOURCE_DIR}/src/server/collision/Models
|
||||
${CMAKE_SOURCE_DIR}/src/server/shared
|
||||
${CMAKE_SOURCE_DIR}/src/server/shared/Configuration
|
||||
${CMAKE_SOURCE_DIR}/src/server/shared/Cryptography
|
||||
${CMAKE_SOURCE_DIR}/src/server/shared/Cryptography/Authentication
|
||||
${CMAKE_SOURCE_DIR}/src/server/shared/Database
|
||||
${CMAKE_SOURCE_DIR}/src/server/shared/DataStores
|
||||
${CMAKE_SOURCE_DIR}/src/server/shared/Debugging
|
||||
${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic/LinkedReference
|
||||
${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic
|
||||
${CMAKE_SOURCE_DIR}/src/server/shared/Logging
|
||||
${CMAKE_SOURCE_DIR}/src/server/shared/Packets
|
||||
${CMAKE_SOURCE_DIR}/src/server/shared/Threading
|
||||
${CMAKE_SOURCE_DIR}/src/server/shared/Utilities
|
||||
${CMAKE_SOURCE_DIR}/src/server/game
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Accounts
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Achievements
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Addons
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/AI
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/AI/CoreAI
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/AI/ScriptedAI
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/AI/SmartScripts
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/AuctionHouse
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/AuctionHouse/AuctionHouseBot
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Battlefield
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Battlefield/Zones
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Battlegrounds
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Battlegrounds/Zones
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Calendar
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Chat
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Chat/Channels
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Combat
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Conditions
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/DataStores
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/DungeonFinding
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Entities
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Creature
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Corpse
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Entities/DynamicObject
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Entities/GameObject
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Item
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Item/Container
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Object
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Object/Updates
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Pet
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Player
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Totem
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Unit
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Vehicle
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Transport
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Events
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Globals
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Grids/Cells
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Grids/Notifiers
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Grids
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Groups
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Guilds
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Handlers
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Instances
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Loot
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Mails
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Maps
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Miscellaneous
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Movement
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Movement/MovementGenerators
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Movement/Waypoints
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/OutdoorPvP
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Pools
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/PrecompiledHeaders
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Quests
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Reputation
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Scripting
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Server/Protocol
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Server
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Skills
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Spells
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Spells/Auras
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Tools
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Warden
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Warden/Modules
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Weather
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/World
|
||||
${CMAKE_SOURCE_DIR}/src/server/game/Misc
|
||||
${CMAKE_SOURCE_DIR}/src/server/authserver/Server
|
||||
${CMAKE_SOURCE_DIR}/src/server/authserver/Realms
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/CommandLine
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/RemoteAccess
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/TCSoap
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/WorldThread
|
||||
${ACE_INCLUDE_DIR}
|
||||
${MYSQL_INCLUDE_DIR}
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
add_executable(worldserver
|
||||
${worldserver_SRCS}
|
||||
${worldserver_PCH_SRC}
|
||||
)
|
||||
|
||||
if( NOT WIN32 )
|
||||
set_target_properties(worldserver PROPERTIES
|
||||
COMPILE_DEFINITIONS _TRINITY_CORE_CONFIG="${CONF_DIR}/worldserver.conf"
|
||||
)
|
||||
endif()
|
||||
|
||||
add_dependencies(worldserver revision.h)
|
||||
|
||||
if( UNIX AND NOT NOJEM )
|
||||
set(worldserver_LINK_FLAGS "-pthread -lncurses ${worldserver_LINK_FLAGS}")
|
||||
endif()
|
||||
|
||||
set_target_properties(worldserver PROPERTIES LINK_FLAGS "${worldserver_LINK_FLAGS}")
|
||||
|
||||
target_link_libraries(worldserver
|
||||
game
|
||||
shared
|
||||
scripts
|
||||
collision
|
||||
g3dlib
|
||||
gsoap
|
||||
Detour
|
||||
${JEMALLOC_LIBRARY}
|
||||
${READLINE_LIBRARY}
|
||||
${TERMCAP_LIBRARY}
|
||||
${ACE_LIBRARY}
|
||||
${MYSQL_LIBRARY}
|
||||
${OPENSSL_LIBRARIES}
|
||||
${ZLIB_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
|
||||
if( WIN32 )
|
||||
if ( MSVC )
|
||||
add_custom_command(TARGET worldserver
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/worldserver.conf.dist ${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/
|
||||
)
|
||||
elseif ( MINGW )
|
||||
add_custom_command(TARGET worldserver
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/worldserver.conf.dist ${CMAKE_BINARY_DIR}/bin/
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if( UNIX )
|
||||
install(TARGETS worldserver DESTINATION bin)
|
||||
install(FILES worldserver.conf.dist DESTINATION ${CONF_DIR})
|
||||
elseif( WIN32 )
|
||||
install(TARGETS worldserver DESTINATION "${CMAKE_INSTALL_PREFIX}")
|
||||
install(FILES worldserver.conf.dist DESTINATION "${CMAKE_INSTALL_PREFIX}")
|
||||
endif()
|
||||
|
||||
# Generate precompiled header
|
||||
if( USE_COREPCH )
|
||||
add_cxx_pch(worldserver ${worldserver_PCH_HDR} ${worldserver_PCH_SRC})
|
||||
endif()
|
||||
207
src/server/worldserver/CommandLine/CliRunnable.cpp
Normal file
207
src/server/worldserver/CommandLine/CliRunnable.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/// \addtogroup Trinityd
|
||||
/// @{
|
||||
/// \file
|
||||
|
||||
#include "Common.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "World.h"
|
||||
#include "WorldSession.h"
|
||||
#include "Configuration/Config.h"
|
||||
|
||||
#include "AccountMgr.h"
|
||||
#include "Chat.h"
|
||||
#include "CliRunnable.h"
|
||||
#include "Language.h"
|
||||
#include "Log.h"
|
||||
#include "MapManager.h"
|
||||
#include "Player.h"
|
||||
#include "Util.h"
|
||||
|
||||
#if PLATFORM != PLATFORM_WINDOWS
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
|
||||
char* command_finder(const char* text, int state)
|
||||
{
|
||||
static int idx, len;
|
||||
const char* ret;
|
||||
ChatCommand* cmd = ChatHandler::getCommandTable();
|
||||
|
||||
if (!state)
|
||||
{
|
||||
idx = 0;
|
||||
len = strlen(text);
|
||||
}
|
||||
|
||||
while ((ret = cmd[idx].Name))
|
||||
{
|
||||
if (!cmd[idx].AllowConsole)
|
||||
{
|
||||
idx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
idx++;
|
||||
//printf("Checking %s \n", cmd[idx].Name);
|
||||
if (strncmp(ret, text, len) == 0)
|
||||
return strdup(ret);
|
||||
if (cmd[idx].Name == NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
return ((char*)NULL);
|
||||
}
|
||||
|
||||
char** cli_completion(const char* text, int start, int /*end*/)
|
||||
{
|
||||
char** matches = NULL;
|
||||
|
||||
if (start)
|
||||
rl_bind_key('\t', rl_abort);
|
||||
else
|
||||
matches = rl_completion_matches((char*)text, &command_finder);
|
||||
return matches;
|
||||
}
|
||||
|
||||
int cli_hook_func()
|
||||
{
|
||||
if (World::IsStopped())
|
||||
rl_done = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void utf8print(void* /*arg*/, const char* str)
|
||||
{
|
||||
#if PLATFORM == PLATFORM_WINDOWS
|
||||
wchar_t wtemp_buf[6000];
|
||||
size_t wtemp_len = 6000-1;
|
||||
if (!Utf8toWStr(str, strlen(str), wtemp_buf, wtemp_len))
|
||||
return;
|
||||
|
||||
char temp_buf[6000];
|
||||
CharToOemBuffW(&wtemp_buf[0], &temp_buf[0], wtemp_len+1);
|
||||
printf(temp_buf);
|
||||
#else
|
||||
{
|
||||
printf("%s", str);
|
||||
fflush(stdout);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void commandFinished(void*, bool /*success*/)
|
||||
{
|
||||
printf("TC> ");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
#ifdef linux
|
||||
// Non-blocking keypress detector, when return pressed, return 1, else always return 0
|
||||
int kb_hit_return()
|
||||
{
|
||||
struct timeval tv;
|
||||
fd_set fds;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(STDIN_FILENO, &fds);
|
||||
select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
|
||||
return FD_ISSET(STDIN_FILENO, &fds);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// %Thread start
|
||||
void CliRunnable::run()
|
||||
{
|
||||
///- Display the list of available CLI functions then beep
|
||||
//TC_LOG_INFO("server.worldserver", "");
|
||||
#if PLATFORM != PLATFORM_WINDOWS
|
||||
rl_attempted_completion_function = cli_completion;
|
||||
rl_event_hook = cli_hook_func;
|
||||
#endif
|
||||
|
||||
if (sConfigMgr->GetBoolDefault("BeepAtStart", true))
|
||||
printf("\a"); // \a = Alert
|
||||
|
||||
// print this here the first time
|
||||
// later it will be printed after command queue updates
|
||||
printf("TC>");
|
||||
|
||||
///- As long as the World is running (no World::m_stopEvent), get the command line and handle it
|
||||
while (!World::IsStopped())
|
||||
{
|
||||
fflush(stdout);
|
||||
|
||||
char *command_str ; // = fgets(commandbuf, sizeof(commandbuf), stdin);
|
||||
|
||||
#if PLATFORM == PLATFORM_WINDOWS
|
||||
char commandbuf[256];
|
||||
command_str = fgets(commandbuf, sizeof(commandbuf), stdin);
|
||||
#else
|
||||
command_str = readline("TC>");
|
||||
rl_bind_key('\t', rl_complete);
|
||||
#endif
|
||||
|
||||
if (command_str != NULL)
|
||||
{
|
||||
for (int x=0; command_str[x]; ++x)
|
||||
if (command_str[x] == '\r' || command_str[x] == '\n')
|
||||
{
|
||||
command_str[x] = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!*command_str)
|
||||
{
|
||||
#if PLATFORM == PLATFORM_WINDOWS
|
||||
printf("TC>");
|
||||
#else
|
||||
free(command_str);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string command;
|
||||
if (!consoleToUtf8(command_str, command)) // convert from console encoding to utf8
|
||||
{
|
||||
#if PLATFORM == PLATFORM_WINDOWS
|
||||
printf("TC>");
|
||||
#else
|
||||
free(command_str);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
sWorld->QueueCliCommand(new CliCommandHolder(NULL, command.c_str(), &utf8print, &commandFinished));
|
||||
#if PLATFORM != PLATFORM_WINDOWS
|
||||
add_history(command.c_str());
|
||||
free(command_str);
|
||||
#endif
|
||||
}
|
||||
else if (feof(stdin))
|
||||
{
|
||||
World::StopNow(SHUTDOWN_EXIT_CODE);
|
||||
}
|
||||
}
|
||||
}
|
||||
35
src/server/worldserver/CommandLine/CliRunnable.h
Normal file
35
src/server/worldserver/CommandLine/CliRunnable.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/// \addtogroup Trinityd
|
||||
/// @{
|
||||
/// \file
|
||||
|
||||
#ifndef __CLIRUNNABLE_H
|
||||
#define __CLIRUNNABLE_H
|
||||
|
||||
/// Command Line Interface handling thread
|
||||
class CliRunnable : public ACE_Based::Runnable
|
||||
{
|
||||
public:
|
||||
void run();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/// @}
|
||||
151
src/server/worldserver/Main.cpp
Normal file
151
src/server/worldserver/Main.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/// \addtogroup Trinityd Trinity Daemon
|
||||
/// @{
|
||||
/// \file
|
||||
|
||||
#include <openssl/opensslv.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <ace/Version.h>
|
||||
|
||||
#include "Common.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "Configuration/Config.h"
|
||||
|
||||
#include "Log.h"
|
||||
#include "Master.h"
|
||||
|
||||
#ifndef _TRINITY_CORE_CONFIG
|
||||
# define _TRINITY_CORE_CONFIG "worldserver.conf"
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "ServiceWin32.h"
|
||||
char serviceName[] = "worldserver";
|
||||
char serviceLongName[] = "SunwellCore world service";
|
||||
char serviceDescription[] = "SunwellCore World of Warcraft emulator world service";
|
||||
/*
|
||||
* -1 - not in service mode
|
||||
* 0 - stopped
|
||||
* 1 - running
|
||||
* 2 - paused
|
||||
*/
|
||||
int m_ServiceStatus = -1;
|
||||
#endif
|
||||
|
||||
WorldDatabaseWorkerPool WorldDatabase; ///< Accessor to the world database
|
||||
CharacterDatabaseWorkerPool CharacterDatabase; ///< Accessor to the character database
|
||||
LoginDatabaseWorkerPool LoginDatabase; ///< Accessor to the realm/login database
|
||||
|
||||
uint32 realmID; ///< Id of the realm
|
||||
|
||||
/// Print out the usage string for this program on the console.
|
||||
void usage(const char* prog)
|
||||
{
|
||||
printf("Usage:\n");
|
||||
printf(" %s [<options>]\n", prog);
|
||||
printf(" -c config_file use config_file as configuration file\n");
|
||||
#ifdef _WIN32
|
||||
printf(" Running as service functions:\n");
|
||||
printf(" --service run as service\n");
|
||||
printf(" -s install install service\n");
|
||||
printf(" -s uninstall uninstall service\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Launch the Trinity server
|
||||
extern int main(int argc, char** argv)
|
||||
{
|
||||
///- Command line parsing to get the configuration file name
|
||||
char const* cfg_file = _TRINITY_CORE_CONFIG;
|
||||
int c = 1;
|
||||
while (c < argc)
|
||||
{
|
||||
if (!strcmp(argv[c], "-c"))
|
||||
{
|
||||
if (++c >= argc)
|
||||
{
|
||||
printf("Runtime-Error: -c option requires an input argument");
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
cfg_file = argv[c];
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (strcmp(argv[c], "-s") == 0) // Services
|
||||
{
|
||||
if (++c >= argc)
|
||||
{
|
||||
printf("Runtime-Error: -s option requires an input argument");
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strcmp(argv[c], "install") == 0)
|
||||
{
|
||||
if (WinServiceInstall())
|
||||
printf("Installing service\n");
|
||||
return 1;
|
||||
}
|
||||
else if (strcmp(argv[c], "uninstall") == 0)
|
||||
{
|
||||
if (WinServiceUninstall())
|
||||
printf("Uninstalling service\n");
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Runtime-Error: unsupported option %s", argv[c]);
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(argv[c], "--service") == 0)
|
||||
WinServiceRun();
|
||||
#endif
|
||||
++c;
|
||||
}
|
||||
|
||||
if (!sConfigMgr->LoadInitial(cfg_file))
|
||||
{
|
||||
printf("Invalid or missing configuration file : %s\n", cfg_file);
|
||||
printf("Verify that the file exists and has \'[worldserver]' written in the top of the file!\n");
|
||||
return 1;
|
||||
}
|
||||
sLog->outString("Using configuration file %s.", cfg_file);
|
||||
|
||||
sLog->outString("Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION));
|
||||
sLog->outString("Using ACE version: %s", ACE_VERSION);
|
||||
|
||||
///- and run the 'Master'
|
||||
/// @todo Why do we need this 'Master'? Can't all of this be in the Main as for Realmd?
|
||||
int ret = sMaster->Run();
|
||||
|
||||
// at sMaster return function exist with codes
|
||||
// 0 - normal shutdown
|
||||
// 1 - shutdown at error
|
||||
// 2 - restart command used, this code can be used by restarter for restart Trinityd
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// @}
|
||||
505
src/server/worldserver/Master.cpp
Normal file
505
src/server/worldserver/Master.cpp
Normal file
@@ -0,0 +1,505 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
\ingroup Trinityd
|
||||
*/
|
||||
|
||||
#include <ace/Sig_Handler.h>
|
||||
|
||||
#include "Common.h"
|
||||
#include "SystemConfig.h"
|
||||
#include "SignalHandler.h"
|
||||
#include "World.h"
|
||||
#include "WorldRunnable.h"
|
||||
#include "WorldSocket.h"
|
||||
#include "WorldSocketMgr.h"
|
||||
#include "Configuration/Config.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "Database/DatabaseWorkerPool.h"
|
||||
|
||||
#include "CliRunnable.h"
|
||||
#include "Log.h"
|
||||
#include "Master.h"
|
||||
#include "RARunnable.h"
|
||||
#include "TCSoap.h"
|
||||
#include "Timer.h"
|
||||
#include "Util.h"
|
||||
#include "AuthSocket.h"
|
||||
#include "RealmList.h"
|
||||
|
||||
#include "BigNumber.h"
|
||||
#include "OpenSSLCrypto.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "ServiceWin32.h"
|
||||
extern int m_ServiceStatus;
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sched.h>
|
||||
#include <sys/resource.h>
|
||||
#define PROCESS_HIGH_PRIORITY -15 // [-20, 19], default is 0
|
||||
#endif
|
||||
|
||||
/// Handle worldservers's termination signals
|
||||
class WorldServerSignalHandler : public Trinity::SignalHandler
|
||||
{
|
||||
public:
|
||||
virtual void HandleSignal(int sigNum)
|
||||
{
|
||||
switch (sigNum)
|
||||
{
|
||||
case SIGINT:
|
||||
World::StopNow(RESTART_EXIT_CODE);
|
||||
break;
|
||||
case SIGTERM:
|
||||
#ifdef _WIN32
|
||||
case SIGBREAK:
|
||||
if (m_ServiceStatus != 1)
|
||||
#endif
|
||||
World::StopNow(SHUTDOWN_EXIT_CODE);
|
||||
break;
|
||||
/*case SIGSEGV:
|
||||
sLog->outString("ZOMG! SIGSEGV handled!");
|
||||
World::StopNow(SHUTDOWN_EXIT_CODE);
|
||||
break;*/
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class FreezeDetectorRunnable : public ACE_Based::Runnable
|
||||
{
|
||||
private:
|
||||
uint32 _loops;
|
||||
uint32 _lastChange;
|
||||
uint32 _delayTime;
|
||||
|
||||
public:
|
||||
FreezeDetectorRunnable(uint32 freezeDelay) : _loops(0), _lastChange(0), _delayTime(freezeDelay) {}
|
||||
|
||||
void run()
|
||||
{
|
||||
if (!_delayTime)
|
||||
return;
|
||||
|
||||
sLog->outString("Starting up anti-freeze thread (%u seconds max stuck time)...", _delayTime/1000);
|
||||
while (!World::IsStopped())
|
||||
{
|
||||
uint32 curtime = getMSTime();
|
||||
if (_loops != World::m_worldLoopCounter)
|
||||
{
|
||||
_lastChange = curtime;
|
||||
_loops = World::m_worldLoopCounter;
|
||||
}
|
||||
else if (getMSTimeDiff(_lastChange, curtime) > _delayTime)
|
||||
{
|
||||
sLog->outString("World Thread hangs, kicking out server!");
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
ACE_Based::Thread::Sleep(1000);
|
||||
}
|
||||
sLog->outString("Anti-freeze thread exiting without problems.");
|
||||
}
|
||||
};
|
||||
|
||||
/// Main function
|
||||
int Master::Run()
|
||||
{
|
||||
OpenSSLCrypto::threadsSetup();
|
||||
BigNumber seed1;
|
||||
seed1.SetRand(16 * 8);
|
||||
|
||||
sLog->outString("%s (worldserver-daemon)", _FULLVERSION);
|
||||
sLog->outString("<Ctrl-C> to stop.\n");
|
||||
|
||||
/// worldserver PID file creation
|
||||
std::string pidFile = sConfigMgr->GetStringDefault("PidFile", "");
|
||||
if (!pidFile.empty())
|
||||
{
|
||||
if (uint32 pid = CreatePIDFile(pidFile))
|
||||
sLog->outString("Daemon PID: %u\n", pid);
|
||||
else
|
||||
{
|
||||
sLog->outString("Cannot create PID file %s.\n", pidFile.c_str());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
///- Start the databases
|
||||
if (!_StartDB())
|
||||
return 1;
|
||||
|
||||
// set server offline (not connectable)
|
||||
LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = (flag & ~%u) | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, REALM_FLAG_INVALID, realmID);
|
||||
|
||||
///- Initialize the World
|
||||
sWorld->SetInitialWorldSettings();
|
||||
|
||||
///- Initialize the signal handlers
|
||||
WorldServerSignalHandler signalINT, signalTERM; //, signalSEGV
|
||||
#ifdef _WIN32
|
||||
WorldServerSignalHandler signalBREAK;
|
||||
#endif /* _WIN32 */
|
||||
|
||||
///- Register worldserver's signal handlers
|
||||
ACE_Sig_Handler handle;
|
||||
handle.register_handler(SIGINT, &signalINT);
|
||||
handle.register_handler(SIGTERM, &signalTERM);
|
||||
#ifdef _WIN32
|
||||
handle.register_handler(SIGBREAK, &signalBREAK);
|
||||
#endif
|
||||
//handle.register_handler(SIGSEGV, &signalSEGV);
|
||||
|
||||
///- Launch WorldRunnable thread
|
||||
ACE_Based::Thread worldThread(new WorldRunnable);
|
||||
worldThread.setPriority(ACE_Based::Highest);
|
||||
|
||||
ACE_Based::Thread* cliThread = NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (sConfigMgr->GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/)
|
||||
#else
|
||||
if (sConfigMgr->GetBoolDefault("Console.Enable", true))
|
||||
#endif
|
||||
{
|
||||
///- Launch CliRunnable thread
|
||||
cliThread = new ACE_Based::Thread(new CliRunnable);
|
||||
}
|
||||
|
||||
ACE_Based::Thread rarThread(new RARunnable);
|
||||
|
||||
// pussywizard:
|
||||
ACE_Based::Thread auctionLising_thread(new AuctionListingRunnable);
|
||||
auctionLising_thread.setPriority(ACE_Based::High);
|
||||
|
||||
#if defined(_WIN32) || defined(__linux__)
|
||||
|
||||
|
||||
///- Handle affinity for multiple processors and process priority
|
||||
uint32 affinity = sConfigMgr->GetIntDefault("UseProcessors", 0);
|
||||
bool highPriority = sConfigMgr->GetBoolDefault("ProcessPriority", false);
|
||||
|
||||
#ifdef _WIN32 // Windows
|
||||
|
||||
HANDLE hProcess = GetCurrentProcess();
|
||||
|
||||
if (affinity > 0)
|
||||
{
|
||||
ULONG_PTR appAff;
|
||||
ULONG_PTR sysAff;
|
||||
|
||||
if (GetProcessAffinityMask(hProcess, &appAff, &sysAff))
|
||||
{
|
||||
ULONG_PTR currentAffinity = affinity & appAff; // remove non accessible processors
|
||||
|
||||
if (!currentAffinity)
|
||||
sLog->outError("Processors marked in UseProcessors bitmask (hex) %x are not accessible for the worldserver. Accessible processors bitmask (hex): %x", affinity, appAff);
|
||||
else if (SetProcessAffinityMask(hProcess, currentAffinity))
|
||||
sLog->outString("Using processors (bitmask, hex): %x", currentAffinity);
|
||||
else
|
||||
sLog->outError("Can't set used processors (hex): %x", currentAffinity);
|
||||
}
|
||||
}
|
||||
|
||||
if (highPriority)
|
||||
{
|
||||
if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS))
|
||||
sLog->outString("worldserver process priority class set to HIGH");
|
||||
else
|
||||
sLog->outError("Can't set worldserver process priority class.");
|
||||
}
|
||||
|
||||
#else // Linux
|
||||
|
||||
if (affinity > 0)
|
||||
{
|
||||
cpu_set_t mask;
|
||||
CPU_ZERO(&mask);
|
||||
|
||||
for (unsigned int i = 0; i < sizeof(affinity) * 8; ++i)
|
||||
if (affinity & (1 << i))
|
||||
CPU_SET(i, &mask);
|
||||
|
||||
if (sched_setaffinity(0, sizeof(mask), &mask))
|
||||
sLog->outError("Can't set used processors (hex): %x, error: %s", affinity, strerror(errno));
|
||||
else
|
||||
{
|
||||
CPU_ZERO(&mask);
|
||||
sched_getaffinity(0, sizeof(mask), &mask);
|
||||
sLog->outString("Using processors (bitmask, hex): %lx", *(__cpu_mask*)(&mask));
|
||||
}
|
||||
}
|
||||
|
||||
if (highPriority)
|
||||
{
|
||||
if (setpriority(PRIO_PROCESS, 0, PROCESS_HIGH_PRIORITY))
|
||||
sLog->outError("Can't set worldserver process priority class, error: %s", strerror(errno));
|
||||
else
|
||||
sLog->outString("worldserver process priority class set to %i", getpriority(PRIO_PROCESS, 0));
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Start soap serving thread
|
||||
ACE_Based::Thread* soapThread = NULL;
|
||||
if (sConfigMgr->GetBoolDefault("SOAP.Enabled", false))
|
||||
{
|
||||
TCSoapRunnable* runnable = new TCSoapRunnable();
|
||||
runnable->SetListenArguments(sConfigMgr->GetStringDefault("SOAP.IP", "127.0.0.1"), uint16(sConfigMgr->GetIntDefault("SOAP.Port", 7878)));
|
||||
soapThread = new ACE_Based::Thread(runnable);
|
||||
}
|
||||
|
||||
// Start up freeze catcher thread
|
||||
ACE_Based::Thread* freezeThread = NULL;
|
||||
if (uint32 freezeDelay = sConfigMgr->GetIntDefault("MaxCoreStuckTime", 0))
|
||||
{
|
||||
FreezeDetectorRunnable* runnable = new FreezeDetectorRunnable(freezeDelay*1000);
|
||||
freezeThread = new ACE_Based::Thread(runnable);
|
||||
freezeThread->setPriority(ACE_Based::Highest);
|
||||
}
|
||||
|
||||
///- Launch the world listener socket
|
||||
uint16 worldPort = uint16(sWorld->getIntConfig(CONFIG_PORT_WORLD));
|
||||
std::string bindIp = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0");
|
||||
if (sWorldSocketMgr->StartNetwork(worldPort, bindIp.c_str()) == -1)
|
||||
{
|
||||
sLog->outError("Failed to start network");
|
||||
World::StopNow(ERROR_EXIT_CODE);
|
||||
// go down and shutdown the server
|
||||
}
|
||||
|
||||
// set server online (allow connecting now)
|
||||
LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag & ~%u, population = 0 WHERE id = '%u'", REALM_FLAG_INVALID, realmID);
|
||||
|
||||
sLog->outString("%s (worldserver-daemon) ready...", _FULLVERSION);
|
||||
|
||||
// when the main thread closes the singletons get unloaded
|
||||
// since worldrunnable uses them, it will crash if unloaded after master
|
||||
worldThread.wait();
|
||||
rarThread.wait();
|
||||
auctionLising_thread.wait();
|
||||
|
||||
if (soapThread)
|
||||
{
|
||||
soapThread->wait();
|
||||
soapThread->destroy();
|
||||
delete soapThread;
|
||||
}
|
||||
|
||||
if (freezeThread)
|
||||
{
|
||||
freezeThread->wait();
|
||||
delete freezeThread;
|
||||
}
|
||||
|
||||
// set server offline
|
||||
LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realmID);
|
||||
|
||||
///- Clean database before leaving
|
||||
ClearOnlineAccounts();
|
||||
|
||||
_StopDB();
|
||||
|
||||
sLog->outString("Halting process...");
|
||||
|
||||
if (cliThread)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
||||
// this only way to terminate CLI thread exist at Win32 (alt. way exist only in Windows Vista API)
|
||||
//_exit(1);
|
||||
// send keyboard input to safely unblock the CLI thread
|
||||
INPUT_RECORD b[4];
|
||||
HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
|
||||
b[0].EventType = KEY_EVENT;
|
||||
b[0].Event.KeyEvent.bKeyDown = TRUE;
|
||||
b[0].Event.KeyEvent.uChar.AsciiChar = 'X';
|
||||
b[0].Event.KeyEvent.wVirtualKeyCode = 'X';
|
||||
b[0].Event.KeyEvent.wRepeatCount = 1;
|
||||
|
||||
b[1].EventType = KEY_EVENT;
|
||||
b[1].Event.KeyEvent.bKeyDown = FALSE;
|
||||
b[1].Event.KeyEvent.uChar.AsciiChar = 'X';
|
||||
b[1].Event.KeyEvent.wVirtualKeyCode = 'X';
|
||||
b[1].Event.KeyEvent.wRepeatCount = 1;
|
||||
|
||||
b[2].EventType = KEY_EVENT;
|
||||
b[2].Event.KeyEvent.bKeyDown = TRUE;
|
||||
b[2].Event.KeyEvent.dwControlKeyState = 0;
|
||||
b[2].Event.KeyEvent.uChar.AsciiChar = '\r';
|
||||
b[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
|
||||
b[2].Event.KeyEvent.wRepeatCount = 1;
|
||||
b[2].Event.KeyEvent.wVirtualScanCode = 0x1c;
|
||||
|
||||
b[3].EventType = KEY_EVENT;
|
||||
b[3].Event.KeyEvent.bKeyDown = FALSE;
|
||||
b[3].Event.KeyEvent.dwControlKeyState = 0;
|
||||
b[3].Event.KeyEvent.uChar.AsciiChar = '\r';
|
||||
b[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
|
||||
b[3].Event.KeyEvent.wVirtualScanCode = 0x1c;
|
||||
b[3].Event.KeyEvent.wRepeatCount = 1;
|
||||
DWORD numb;
|
||||
WriteConsoleInput(hStdIn, b, 4, &numb);
|
||||
|
||||
cliThread->wait();
|
||||
|
||||
#else
|
||||
|
||||
cliThread->destroy();
|
||||
|
||||
#endif
|
||||
|
||||
delete cliThread;
|
||||
}
|
||||
|
||||
// for some unknown reason, unloading scripts here and not in worldrunnable
|
||||
// fixes a memory leak related to detaching threads from the module
|
||||
//UnloadScriptingModule();
|
||||
|
||||
OpenSSLCrypto::threadsCleanup();
|
||||
// Exit the process with specified return value
|
||||
return World::GetExitCode();
|
||||
}
|
||||
|
||||
/// Initialize connection to the databases
|
||||
bool Master::_StartDB()
|
||||
{
|
||||
MySQL::Library_Init();
|
||||
|
||||
sLog->SetLogDB(false);
|
||||
std::string dbstring;
|
||||
uint8 async_threads, synch_threads;
|
||||
|
||||
dbstring = sConfigMgr->GetStringDefault("WorldDatabaseInfo", "");
|
||||
if (dbstring.empty())
|
||||
{
|
||||
sLog->outError("World database not specified in configuration file");
|
||||
return false;
|
||||
}
|
||||
|
||||
async_threads = uint8(sConfigMgr->GetIntDefault("WorldDatabase.WorkerThreads", 1));
|
||||
if (async_threads < 1 || async_threads > 32)
|
||||
{
|
||||
sLog->outError("World database: invalid number of worker threads specified. "
|
||||
"Please pick a value between 1 and 32.");
|
||||
return false;
|
||||
}
|
||||
|
||||
synch_threads = uint8(sConfigMgr->GetIntDefault("WorldDatabase.SynchThreads", 1));
|
||||
///- Initialise the world database
|
||||
if (!WorldDatabase.Open(dbstring, async_threads, synch_threads))
|
||||
{
|
||||
sLog->outError("Cannot connect to world database %s", dbstring.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
///- Get character database info from configuration file
|
||||
dbstring = sConfigMgr->GetStringDefault("CharacterDatabaseInfo", "");
|
||||
if (dbstring.empty())
|
||||
{
|
||||
sLog->outError("Character database not specified in configuration file");
|
||||
return false;
|
||||
}
|
||||
|
||||
async_threads = uint8(sConfigMgr->GetIntDefault("CharacterDatabase.WorkerThreads", 1));
|
||||
if (async_threads < 1 || async_threads > 32)
|
||||
{
|
||||
sLog->outError("Character database: invalid number of worker threads specified. "
|
||||
"Please pick a value between 1 and 32.");
|
||||
return false;
|
||||
}
|
||||
|
||||
synch_threads = uint8(sConfigMgr->GetIntDefault("CharacterDatabase.SynchThreads", 2));
|
||||
|
||||
///- Initialise the Character database
|
||||
if (!CharacterDatabase.Open(dbstring, async_threads, synch_threads))
|
||||
{
|
||||
sLog->outError("Cannot connect to Character database %s", dbstring.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
///- Get login database info from configuration file
|
||||
dbstring = sConfigMgr->GetStringDefault("LoginDatabaseInfo", "");
|
||||
if (dbstring.empty())
|
||||
{
|
||||
sLog->outError("Login database not specified in configuration file");
|
||||
return false;
|
||||
}
|
||||
|
||||
async_threads = uint8(sConfigMgr->GetIntDefault("LoginDatabase.WorkerThreads", 1));
|
||||
if (async_threads < 1 || async_threads > 32)
|
||||
{
|
||||
sLog->outError("Login database: invalid number of worker threads specified. "
|
||||
"Please pick a value between 1 and 32.");
|
||||
return false;
|
||||
}
|
||||
|
||||
synch_threads = uint8(sConfigMgr->GetIntDefault("LoginDatabase.SynchThreads", 1));
|
||||
///- Initialise the login database
|
||||
if (!LoginDatabase.Open(dbstring, async_threads, synch_threads))
|
||||
{
|
||||
sLog->outError("Cannot connect to login database %s", dbstring.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
///- Get the realm Id from the configuration file
|
||||
realmID = sConfigMgr->GetIntDefault("RealmID", 0);
|
||||
if (!realmID || realmID > 8) // pussywizard: above 8 spoils 8-bit online mask for the accounts
|
||||
{
|
||||
sLog->outError("Realm ID not defined in configuration file");
|
||||
return false;
|
||||
}
|
||||
sLog->outString("Realm running as realm ID %d", realmID);
|
||||
|
||||
///- Initialize the DB logging system
|
||||
sLog->SetRealmID(realmID);
|
||||
|
||||
///- Clean the database before starting
|
||||
ClearOnlineAccounts();
|
||||
|
||||
///- Insert version info into DB
|
||||
WorldDatabase.PExecute("UPDATE version SET core_version = '%s', core_revision = '%s'", _FULLVERSION, _HASH); // One-time query
|
||||
|
||||
sWorld->LoadDBVersion();
|
||||
|
||||
sLog->outString("Using World DB: %s", sWorld->GetDBVersion());
|
||||
return true;
|
||||
}
|
||||
|
||||
void Master::_StopDB()
|
||||
{
|
||||
CharacterDatabase.Close();
|
||||
WorldDatabase.Close();
|
||||
LoginDatabase.Close();
|
||||
|
||||
MySQL::Library_End();
|
||||
}
|
||||
|
||||
/// Clear 'online' status for all accounts with characters in this realm
|
||||
void Master::ClearOnlineAccounts()
|
||||
{
|
||||
// Reset online status for all accounts with characters on the current realm
|
||||
// pussywizard: tc query would set online=0 even if logged in on another realm >_>
|
||||
LoginDatabase.DirectPExecute("UPDATE account SET online = online & ~(1<<(%u-1)) WHERE online & (1<<(%u-1))", realmID, realmID);
|
||||
|
||||
// Reset online status for all characters
|
||||
CharacterDatabase.DirectExecute("UPDATE characters SET online = 0 WHERE online <> 0");
|
||||
}
|
||||
45
src/server/worldserver/Master.h
Normal file
45
src/server/worldserver/Master.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/// \addtogroup Trinityd
|
||||
/// @{
|
||||
/// \file
|
||||
|
||||
#ifndef _MASTER_H
|
||||
#define _MASTER_H
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
/// Start the server
|
||||
class Master
|
||||
{
|
||||
public:
|
||||
int Run();
|
||||
|
||||
private:
|
||||
bool _StartDB();
|
||||
void _StopDB();
|
||||
|
||||
void ClearOnlineAccounts();
|
||||
};
|
||||
|
||||
#define sMaster ACE_Singleton<Master, ACE_Null_Mutex>::instance()
|
||||
|
||||
#endif
|
||||
|
||||
/// @}
|
||||
1
src/server/worldserver/PrecompiledHeaders/worldPCH.cpp
Normal file
1
src/server/worldserver/PrecompiledHeaders/worldPCH.cpp
Normal file
@@ -0,0 +1 @@
|
||||
#include "worldPCH.h"
|
||||
8
src/server/worldserver/PrecompiledHeaders/worldPCH.h
Normal file
8
src/server/worldserver/PrecompiledHeaders/worldPCH.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#include "WorldSocket.h" // must be first to make ACE happy with ACE includes in it
|
||||
|
||||
#include "Common.h"
|
||||
#include "World.h"
|
||||
#include "Log.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "Configuration/Config.h"
|
||||
#include "Util.h"
|
||||
84
src/server/worldserver/RemoteAccess/RARunnable.cpp
Normal file
84
src/server/worldserver/RemoteAccess/RARunnable.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
\ingroup Trinityd
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "Config.h"
|
||||
#include "Log.h"
|
||||
#include "RARunnable.h"
|
||||
#include "World.h"
|
||||
|
||||
#include <ace/Reactor_Impl.h>
|
||||
#include <ace/TP_Reactor.h>
|
||||
#include <ace/Dev_Poll_Reactor.h>
|
||||
#include <ace/Acceptor.h>
|
||||
#include <ace/SOCK_Acceptor.h>
|
||||
|
||||
#include "RASocket.h"
|
||||
|
||||
RARunnable::RARunnable()
|
||||
{
|
||||
ACE_Reactor_Impl* imp;
|
||||
|
||||
#if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL)
|
||||
imp = new ACE_Dev_Poll_Reactor();
|
||||
imp->max_notify_iterations (128);
|
||||
imp->restart (1);
|
||||
#else
|
||||
imp = new ACE_TP_Reactor();
|
||||
imp->max_notify_iterations (128);
|
||||
#endif
|
||||
|
||||
m_Reactor = new ACE_Reactor (imp, 1);
|
||||
}
|
||||
|
||||
RARunnable::~RARunnable()
|
||||
{
|
||||
delete m_Reactor;
|
||||
}
|
||||
|
||||
void RARunnable::run()
|
||||
{
|
||||
if (!sConfigMgr->GetBoolDefault("Ra.Enable", false))
|
||||
return;
|
||||
|
||||
ACE_Acceptor<RASocket, ACE_SOCK_ACCEPTOR> acceptor;
|
||||
|
||||
uint16 raPort = uint16(sConfigMgr->GetIntDefault("Ra.Port", 3443));
|
||||
std::string stringIp = sConfigMgr->GetStringDefault("Ra.IP", "0.0.0.0");
|
||||
ACE_INET_Addr listenAddress(raPort, stringIp.c_str());
|
||||
|
||||
if (acceptor.open(listenAddress, m_Reactor) == -1)
|
||||
{
|
||||
sLog->outError("Trinity RA can not bind to port %d on %s", raPort, stringIp.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
sLog->outString("Starting Trinity RA on port %d on %s", raPort, stringIp.c_str());
|
||||
|
||||
while (!World::IsStopped())
|
||||
{
|
||||
ACE_Time_Value interval(0, 100000);
|
||||
if (m_Reactor->run_reactor_event_loop(interval) == -1)
|
||||
break;
|
||||
}
|
||||
|
||||
;//sLog->outStaticDebug("Trinity RA thread exiting");
|
||||
}
|
||||
43
src/server/worldserver/RemoteAccess/RARunnable.h
Normal file
43
src/server/worldserver/RemoteAccess/RARunnable.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/// \addtogroup Trinityd
|
||||
/// @{
|
||||
/// \file
|
||||
|
||||
#ifndef _TRINITY_RARUNNABLE_H_
|
||||
#define _TRINITY_RARUNNABLE_H_
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include <ace/Reactor.h>
|
||||
|
||||
class RARunnable : public ACE_Based::Runnable
|
||||
{
|
||||
public:
|
||||
RARunnable();
|
||||
virtual ~RARunnable();
|
||||
void run();
|
||||
|
||||
private:
|
||||
ACE_Reactor* m_Reactor;
|
||||
|
||||
};
|
||||
|
||||
#endif /* _TRINITY_RARUNNABLE_H_ */
|
||||
|
||||
/// @}
|
||||
426
src/server/worldserver/RemoteAccess/RASocket.cpp
Normal file
426
src/server/worldserver/RemoteAccess/RASocket.cpp
Normal file
@@ -0,0 +1,426 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
\ingroup Trinityd
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "Configuration/Config.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "AccountMgr.h"
|
||||
#include "Log.h"
|
||||
#include "RASocket.h"
|
||||
#include "Util.h"
|
||||
#include "World.h"
|
||||
#include "SHA1.h"
|
||||
|
||||
RASocket::RASocket()
|
||||
{
|
||||
_minLevel = uint8(sConfigMgr->GetIntDefault("RA.MinLevel", 3));
|
||||
_commandExecuting = false;
|
||||
}
|
||||
|
||||
int RASocket::open(void *)
|
||||
{
|
||||
ACE_INET_Addr remoteAddress;
|
||||
|
||||
if (peer().get_remote_addr(remoteAddress) == -1)
|
||||
{
|
||||
sLog->outError("RASocket::open: peer().get_remote_addr error is %s", ACE_OS::strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
sLog->outRemote("Incoming connection from %s", remoteAddress.get_host_addr());
|
||||
|
||||
return activate();
|
||||
}
|
||||
|
||||
int RASocket::handle_close(ACE_HANDLE /*handle*/, ACE_Reactor_Mask /*mask*/)
|
||||
{
|
||||
sLog->outRemote("Closing connection");
|
||||
peer().close_reader();
|
||||
wait();
|
||||
// While the above wait() will wait for the ::svc() to finish, it will not wait for the async event
|
||||
// RASocket::commandfinished to be completed. Calling destroy() before the latter function ends
|
||||
// will lead to using a freed pointer -> crash.
|
||||
while (_commandExecuting.value())
|
||||
ACE_OS::sleep(1);
|
||||
|
||||
destroy();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RASocket::send(const std::string& line)
|
||||
{
|
||||
#ifdef MSG_NOSIGNAL
|
||||
ssize_t n = peer().send(line.c_str(), line.length(), MSG_NOSIGNAL);
|
||||
#else
|
||||
ssize_t n = peer().send(line.c_str(), line.length());
|
||||
#endif // MSG_NOSIGNAL
|
||||
|
||||
return n == ssize_t(line.length()) ? 0 : -1;
|
||||
}
|
||||
|
||||
int RASocket::recv_line(ACE_Message_Block& buffer)
|
||||
{
|
||||
char byte;
|
||||
for (;;)
|
||||
{
|
||||
ssize_t n = peer().recv(&byte, sizeof(byte));
|
||||
|
||||
if (n < 0)
|
||||
return -1;
|
||||
|
||||
if (n == 0)
|
||||
{
|
||||
// EOF, connection was closed
|
||||
errno = ECONNRESET;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ACE_ASSERT(n == sizeof(byte));
|
||||
|
||||
if (byte == '\n')
|
||||
break;
|
||||
else if (byte == '\r') /* Ignore CR */
|
||||
continue;
|
||||
else if (buffer.copy(&byte, sizeof(byte)) == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char nullTerm = '\0';
|
||||
if (buffer.copy(&nullTerm, sizeof(nullTerm)) == -1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RASocket::recv_line(std::string& out_line)
|
||||
{
|
||||
char buf[4096];
|
||||
|
||||
ACE_Data_Block db(sizeof (buf),
|
||||
ACE_Message_Block::MB_DATA,
|
||||
buf,
|
||||
0,
|
||||
0,
|
||||
ACE_Message_Block::DONT_DELETE,
|
||||
0);
|
||||
|
||||
ACE_Message_Block message_block(&db,
|
||||
ACE_Message_Block::DONT_DELETE,
|
||||
0);
|
||||
|
||||
if (recv_line(message_block) == -1)
|
||||
{
|
||||
sLog->outRemote("Recv error %s", ACE_OS::strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
out_line = message_block.rd_ptr();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RASocket::process_command(const std::string& command)
|
||||
{
|
||||
if (command.length() == 0)
|
||||
return 0;
|
||||
|
||||
sLog->outRemote("Got command: %s", command.c_str());
|
||||
|
||||
// handle quit, exit and logout commands to terminate connection
|
||||
if (command == "quit" || command == "exit" || command == "logout") {
|
||||
(void) send("Bye\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
_commandExecuting = true;
|
||||
CliCommandHolder* cmd = new CliCommandHolder(this, command.c_str(), &RASocket::zprint, &RASocket::commandFinished);
|
||||
sWorld->QueueCliCommand(cmd);
|
||||
|
||||
// wait for result
|
||||
ACE_Message_Block* mb;
|
||||
for (;;)
|
||||
{
|
||||
if (getq(mb) == -1)
|
||||
return -1;
|
||||
|
||||
if (mb->msg_type() == ACE_Message_Block::MB_BREAK)
|
||||
{
|
||||
mb->release();
|
||||
break;
|
||||
}
|
||||
|
||||
if (send(std::string(mb->rd_ptr(), mb->length())) == -1)
|
||||
{
|
||||
mb->release();
|
||||
return -1;
|
||||
}
|
||||
|
||||
mb->release();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RASocket::check_access_level(const std::string& user)
|
||||
{
|
||||
std::string safeUser = user;
|
||||
|
||||
AccountMgr::normalizeString(safeUser);
|
||||
|
||||
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ACCESS);
|
||||
stmt->setString(0, safeUser);
|
||||
PreparedQueryResult result = LoginDatabase.Query(stmt);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
sLog->outRemote("User %s does not exist in database", user.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
if (fields[1].GetUInt8() < _minLevel)
|
||||
{
|
||||
sLog->outRemote("User %s has no privilege to login", user.c_str());
|
||||
return -1;
|
||||
}
|
||||
else if (fields[2].GetInt32() != -1)
|
||||
{
|
||||
sLog->outRemote("User %s has to be assigned on all realms (with RealmID = '-1')", user.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RASocket::check_password(const std::string& user, const std::string& pass)
|
||||
{
|
||||
std::string safe_user = user;
|
||||
AccountMgr::normalizeString(safe_user);
|
||||
|
||||
std::string safe_pass = pass;
|
||||
AccountMgr::normalizeString(safe_pass);
|
||||
|
||||
std::string hash = AccountMgr::CalculateShaPassHash(safe_user, safe_pass);
|
||||
|
||||
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD_BY_NAME);
|
||||
|
||||
stmt->setString(0, safe_user);
|
||||
stmt->setString(1, hash);
|
||||
|
||||
PreparedQueryResult result = LoginDatabase.Query(stmt);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
sLog->outRemote("Wrong password for user: %s", user.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RASocket::authenticate()
|
||||
{
|
||||
if (send(std::string("Username: ")) == -1)
|
||||
return -1;
|
||||
|
||||
std::string user;
|
||||
if (recv_line(user) == -1)
|
||||
return -1;
|
||||
|
||||
if (send(std::string("Password: ")) == -1)
|
||||
return -1;
|
||||
|
||||
std::string pass;
|
||||
if (recv_line(pass) == -1)
|
||||
return -1;
|
||||
|
||||
sLog->outRemote("Login attempt for user: %s", user.c_str());
|
||||
|
||||
if (check_access_level(user) == -1)
|
||||
return -1;
|
||||
|
||||
if (check_password(user, pass) == -1)
|
||||
return -1;
|
||||
|
||||
sLog->outRemote("User login: %s", user.c_str());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int RASocket::subnegotiate()
|
||||
{
|
||||
char buf[1024];
|
||||
|
||||
ACE_Data_Block db(sizeof (buf),
|
||||
ACE_Message_Block::MB_DATA,
|
||||
buf,
|
||||
0,
|
||||
0,
|
||||
ACE_Message_Block::DONT_DELETE,
|
||||
0);
|
||||
|
||||
ACE_Message_Block message_block(&db,
|
||||
ACE_Message_Block::DONT_DELETE,
|
||||
0);
|
||||
|
||||
const size_t recv_size = message_block.space();
|
||||
|
||||
// Wait a maximum of 1000ms for negotiation packet - not all telnet clients may send it
|
||||
ACE_Time_Value waitTime = ACE_Time_Value(1);
|
||||
const ssize_t n = peer().recv(message_block.wr_ptr(),
|
||||
recv_size, &waitTime);
|
||||
|
||||
if (n <= 0)
|
||||
return int(n);
|
||||
|
||||
if (n >= 1024)
|
||||
{
|
||||
sLog->outRemote("RASocket::subnegotiate: allocated buffer 1024 bytes was too small for negotiation packet, size: %u", uint32(n));
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf[n] = '\0';
|
||||
|
||||
#ifdef _DEBUG
|
||||
for (uint8 i = 0; i < n; )
|
||||
{
|
||||
uint8 iac = buf[i];
|
||||
if (iac == 0xFF) // "Interpret as Command" (IAC)
|
||||
{
|
||||
uint8 command = buf[++i];
|
||||
std::stringstream ss;
|
||||
switch (command)
|
||||
{
|
||||
case 0xFB: // WILL
|
||||
ss << "WILL ";
|
||||
break;
|
||||
case 0xFC: // WON'T
|
||||
ss << "WON'T ";
|
||||
break;
|
||||
case 0xFD: // DO
|
||||
ss << "DO ";
|
||||
break;
|
||||
case 0xFE: // DON'T
|
||||
ss << "DON'T ";
|
||||
break;
|
||||
default:
|
||||
return -1; // not allowed
|
||||
}
|
||||
|
||||
uint8 param = buf[++i];
|
||||
ss << uint32(param);
|
||||
sLog->outRemote(ss.str().c_str());
|
||||
}
|
||||
++i;
|
||||
}
|
||||
#endif
|
||||
|
||||
//! Just send back end of subnegotiation packet
|
||||
uint8 const reply[2] = {0xFF, 0xF0};
|
||||
|
||||
#ifdef MSG_NOSIGNAL
|
||||
return int(peer().send(reply, 2, MSG_NOSIGNAL));
|
||||
#else
|
||||
return int(peer().send(reply, 2));
|
||||
#endif // MSG_NOSIGNAL
|
||||
}
|
||||
|
||||
int RASocket::svc(void)
|
||||
{
|
||||
//! Subnegotiation may differ per client - do not react on it
|
||||
subnegotiate();
|
||||
|
||||
if (send("Authentication required\r\n") == -1)
|
||||
return -1;
|
||||
|
||||
if (authenticate() == -1)
|
||||
{
|
||||
(void) send("Authentication failed\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// send motd
|
||||
if (send(std::string(sWorld->GetMotd()) + "\r\n") == -1)
|
||||
return -1;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
// show prompt
|
||||
if (send("TC> ") == -1)
|
||||
return -1;
|
||||
|
||||
std::string line;
|
||||
|
||||
if (recv_line(line) == -1)
|
||||
return -1;
|
||||
|
||||
if (process_command(line) == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RASocket::zprint(void* callbackArg, const char * szText)
|
||||
{
|
||||
if (!szText || !callbackArg)
|
||||
return;
|
||||
|
||||
RASocket* socket = static_cast<RASocket*>(callbackArg);
|
||||
size_t sz = strlen(szText);
|
||||
|
||||
ACE_Message_Block* mb = new ACE_Message_Block(sz);
|
||||
mb->copy(szText, sz);
|
||||
|
||||
ACE_Time_Value tv = ACE_Time_Value::zero;
|
||||
if (socket->putq(mb, &tv) == -1)
|
||||
{
|
||||
sLog->outRemote("Failed to enqueue message, queue is full or closed. Error is %s", ACE_OS::strerror(errno));
|
||||
mb->release();
|
||||
}
|
||||
}
|
||||
|
||||
void RASocket::commandFinished(void* callbackArg, bool /*success*/)
|
||||
{
|
||||
if (!callbackArg)
|
||||
return;
|
||||
|
||||
RASocket* socket = static_cast<RASocket*>(callbackArg);
|
||||
|
||||
ACE_Message_Block* mb = new ACE_Message_Block();
|
||||
|
||||
mb->msg_type(ACE_Message_Block::MB_BREAK);
|
||||
|
||||
// the message is 0 size control message to tell that command output is finished
|
||||
// hence we don't put timeout, because it shouldn't increase queue size and shouldn't block
|
||||
if (socket->putq(mb->duplicate()) == -1)
|
||||
{
|
||||
// getting here is bad, command can't be marked as complete
|
||||
//sLog->outDebug(LOG_FILTER_REMOTECOMMAND, "Failed to enqueue command end message. Error is %s", ACE_OS::strerror(errno));
|
||||
}
|
||||
|
||||
mb->release();
|
||||
|
||||
socket->_commandExecuting = false;
|
||||
}
|
||||
64
src/server/worldserver/RemoteAccess/RASocket.h
Normal file
64
src/server/worldserver/RemoteAccess/RASocket.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/// \addtogroup Trinityd
|
||||
/// @{
|
||||
/// \file
|
||||
|
||||
#ifndef _RASOCKET_H
|
||||
#define _RASOCKET_H
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include <ace/Synch_Traits.h>
|
||||
#include <ace/Svc_Handler.h>
|
||||
#include <ace/SOCK_Stream.h>
|
||||
#include <ace/SOCK_Acceptor.h>
|
||||
|
||||
/// Remote Administration socket
|
||||
class RASocket : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_MT_SYNCH>
|
||||
{
|
||||
public:
|
||||
RASocket();
|
||||
virtual ~RASocket() { }
|
||||
|
||||
virtual int svc();
|
||||
virtual int open(void* = 0);
|
||||
virtual int handle_close(ACE_HANDLE = ACE_INVALID_HANDLE, ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK);
|
||||
|
||||
private:
|
||||
int recv_line(std::string& outLine);
|
||||
int recv_line(ACE_Message_Block& buffer);
|
||||
int process_command(const std::string& command);
|
||||
int authenticate();
|
||||
int subnegotiate(); ///< Used by telnet protocol RFC 854 / 855
|
||||
int check_access_level(const std::string& user);
|
||||
int check_password(const std::string& user, const std::string& pass);
|
||||
int send(const std::string& line);
|
||||
|
||||
static void zprint(void* callbackArg, const char* szText);
|
||||
static void commandFinished(void* callbackArg, bool success);
|
||||
|
||||
private:
|
||||
uint8 _minLevel; ///< Minimum security level required to connect
|
||||
ACE_Atomic_Op<ACE_Thread_Mutex, bool> _commandExecuting;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/// @}
|
||||
157
src/server/worldserver/TCSoap/TCSoap.cpp
Normal file
157
src/server/worldserver/TCSoap/TCSoap.cpp
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "TCSoap.h"
|
||||
#include "soapH.h"
|
||||
#include "soapStub.h"
|
||||
|
||||
void TCSoapRunnable::run()
|
||||
{
|
||||
struct soap soap;
|
||||
soap_init(&soap);
|
||||
soap_set_imode(&soap, SOAP_C_UTFSTRING);
|
||||
soap_set_omode(&soap, SOAP_C_UTFSTRING);
|
||||
|
||||
// check every 3 seconds if world ended
|
||||
soap.accept_timeout = 3;
|
||||
soap.recv_timeout = 5;
|
||||
soap.send_timeout = 5;
|
||||
if (!soap_valid_socket(soap_bind(&soap, _host.c_str(), _port, 100)))
|
||||
{
|
||||
sLog->outError("TCSoap: couldn't bind to %s:%d", _host.c_str(), _port);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
sLog->outString("TCSoap: bound to http://%s:%d", _host.c_str(), _port);
|
||||
|
||||
while (!World::IsStopped())
|
||||
{
|
||||
if (!soap_valid_socket(soap_accept(&soap)))
|
||||
continue; // ran into an accept timeout
|
||||
|
||||
;//sLog->outDebug(LOG_FILTER_NETWORKIO, "TCSoap: accepted connection from IP=%d.%d.%d.%d", (int)(soap.ip>>24)&0xFF, (int)(soap.ip>>16)&0xFF, (int)(soap.ip>>8)&0xFF, (int)soap.ip&0xFF);
|
||||
struct soap* thread_soap = soap_copy(&soap);// make a safe copy
|
||||
|
||||
ACE_Message_Block* mb = new ACE_Message_Block(sizeof(struct soap*));
|
||||
ACE_OS::memcpy(mb->wr_ptr(), &thread_soap, sizeof(struct soap*));
|
||||
process_message(mb);
|
||||
}
|
||||
|
||||
soap_done(&soap);
|
||||
}
|
||||
|
||||
void TCSoapRunnable::process_message(ACE_Message_Block* mb)
|
||||
{
|
||||
ACE_TRACE (ACE_TEXT ("SOAPWorkingThread::process_message"));
|
||||
|
||||
struct soap* soap;
|
||||
ACE_OS::memcpy(&soap, mb->rd_ptr (), sizeof(struct soap*));
|
||||
mb->release();
|
||||
|
||||
soap_serve(soap);
|
||||
soap_destroy(soap); // dealloc C++ data
|
||||
soap_end(soap); // dealloc data and clean up
|
||||
soap_done(soap); // detach soap struct
|
||||
free(soap);
|
||||
}
|
||||
/*
|
||||
Code used for generating stubs:
|
||||
|
||||
int ns1__executeCommand(char* command, char** result);
|
||||
*/
|
||||
int ns1__executeCommand(soap* soap, char* command, char** result)
|
||||
{
|
||||
// security check
|
||||
if (!soap->userid || !soap->passwd)
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_NETWORKIO, "TCSoap: Client didn't provide login information");
|
||||
return 401;
|
||||
}
|
||||
|
||||
uint32 accountId = AccountMgr::GetId(soap->userid);
|
||||
if (!accountId)
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_NETWORKIO, "TCSoap: Client used invalid username '%s'", soap->userid);
|
||||
return 401;
|
||||
}
|
||||
|
||||
if (!AccountMgr::CheckPassword(accountId, soap->passwd))
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_NETWORKIO, "TCSoap: invalid password for account '%s'", soap->userid);
|
||||
return 401;
|
||||
}
|
||||
|
||||
if (AccountMgr::GetSecurity(accountId) < SEC_ADMINISTRATOR)
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_NETWORKIO, "TCSoap: %s's gmlevel is too low", soap->userid);
|
||||
return 403;
|
||||
}
|
||||
|
||||
if (!command || !*command)
|
||||
return soap_sender_fault(soap, "Command can not be empty", "The supplied command was an empty string");
|
||||
|
||||
;//sLog->outDebug(LOG_FILTER_NETWORKIO, "TCSoap: got command '%s'", command);
|
||||
SOAPCommand connection;
|
||||
|
||||
// commands are executed in the world thread. We have to wait for them to be completed
|
||||
{
|
||||
// CliCommandHolder will be deleted from world, accessing after queueing is NOT save
|
||||
CliCommandHolder* cmd = new CliCommandHolder(&connection, command, &SOAPCommand::print, &SOAPCommand::commandFinished);
|
||||
sWorld->QueueCliCommand(cmd);
|
||||
}
|
||||
|
||||
// wait for callback to complete command
|
||||
|
||||
int acc = connection.pendingCommands.acquire();
|
||||
if (acc)
|
||||
{
|
||||
sLog->outError("TCSoap: Error while acquiring lock, acc = %i, errno = %u", acc, errno);
|
||||
}
|
||||
|
||||
// alright, command finished
|
||||
|
||||
char* printBuffer = soap_strdup(soap, connection.m_printBuffer.c_str());
|
||||
if (connection.hasCommandSucceeded())
|
||||
{
|
||||
*result = printBuffer;
|
||||
return SOAP_OK;
|
||||
}
|
||||
else
|
||||
return soap_sender_fault(soap, printBuffer, printBuffer);
|
||||
}
|
||||
|
||||
void SOAPCommand::commandFinished(void* soapconnection, bool success)
|
||||
{
|
||||
SOAPCommand* con = (SOAPCommand*)soapconnection;
|
||||
con->setCommandSuccess(success);
|
||||
con->pendingCommands.release();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Namespace Definition Table
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct Namespace namespaces[] =
|
||||
{ { "SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/", NULL, NULL }, // must be first
|
||||
{ "SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/", NULL, NULL }, // must be second
|
||||
{ "xsi", "http://www.w3.org/1999/XMLSchema-instance", "http://www.w3.org/*/XMLSchema-instance", NULL },
|
||||
{ "xsd", "http://www.w3.org/1999/XMLSchema", "http://www.w3.org/*/XMLSchema", NULL },
|
||||
{ "ns1", "urn:TC", NULL, NULL }, // "ns1" namespace prefix
|
||||
{ NULL, NULL, NULL, NULL }
|
||||
};
|
||||
88
src/server/worldserver/TCSoap/TCSoap.h
Normal file
88
src/server/worldserver/TCSoap/TCSoap.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _TCSOAP_H
|
||||
#define _TCSOAP_H
|
||||
|
||||
#include "Define.h"
|
||||
#include "AccountMgr.h"
|
||||
|
||||
#include <ace/Semaphore.h>
|
||||
#include <ace/Task.h>
|
||||
#include <Threading.h>
|
||||
|
||||
class TCSoapRunnable : public ACE_Based::Runnable
|
||||
{
|
||||
public:
|
||||
TCSoapRunnable() : _port(0) { }
|
||||
|
||||
void run();
|
||||
|
||||
void SetListenArguments(const std::string& host, uint16 port)
|
||||
{
|
||||
_host = host;
|
||||
_port = port;
|
||||
}
|
||||
|
||||
private:
|
||||
void process_message(ACE_Message_Block* mb);
|
||||
|
||||
std::string _host;
|
||||
uint16 _port;
|
||||
};
|
||||
|
||||
class SOAPCommand
|
||||
{
|
||||
public:
|
||||
SOAPCommand():
|
||||
pendingCommands(0, USYNC_THREAD, "pendingCommands"), m_success(false)
|
||||
{
|
||||
}
|
||||
|
||||
~SOAPCommand()
|
||||
{
|
||||
}
|
||||
|
||||
void appendToPrintBuffer(const char* msg)
|
||||
{
|
||||
m_printBuffer += msg;
|
||||
}
|
||||
|
||||
ACE_Semaphore pendingCommands;
|
||||
|
||||
void setCommandSuccess(bool val)
|
||||
{
|
||||
m_success = val;
|
||||
}
|
||||
|
||||
bool hasCommandSucceeded() const
|
||||
{
|
||||
return m_success;
|
||||
}
|
||||
|
||||
static void print(void* callbackArg, const char* msg)
|
||||
{
|
||||
((SOAPCommand*)callbackArg)->appendToPrintBuffer(msg);
|
||||
}
|
||||
|
||||
static void commandFinished(void* callbackArg, bool success);
|
||||
|
||||
bool m_success;
|
||||
std::string m_printBuffer;
|
||||
};
|
||||
|
||||
#endif
|
||||
136
src/server/worldserver/WorldThread/WorldRunnable.cpp
Normal file
136
src/server/worldserver/WorldThread/WorldRunnable.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
\ingroup Trinityd
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "World.h"
|
||||
#include "WorldSocketMgr.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "BattlegroundMgr.h"
|
||||
#include "MapManager.h"
|
||||
#include "Timer.h"
|
||||
#include "WorldRunnable.h"
|
||||
#include "OutdoorPvPMgr.h"
|
||||
#include "AvgDiffTracker.h"
|
||||
#include "AsyncAuctionListing.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "ServiceWin32.h"
|
||||
extern int m_ServiceStatus;
|
||||
#endif
|
||||
|
||||
/// Heartbeat for the World
|
||||
void WorldRunnable::run()
|
||||
{
|
||||
uint32 realCurrTime = 0;
|
||||
uint32 realPrevTime = getMSTime();
|
||||
|
||||
sScriptMgr->OnStartup();
|
||||
|
||||
///- While we have not World::m_stopEvent, update the world
|
||||
while (!World::IsStopped())
|
||||
{
|
||||
++World::m_worldLoopCounter;
|
||||
realCurrTime = getMSTime();
|
||||
|
||||
uint32 diff = getMSTimeDiff(realPrevTime, realCurrTime);
|
||||
|
||||
sWorld->Update( diff );
|
||||
realPrevTime = realCurrTime;
|
||||
|
||||
uint32 executionTimeDiff = getMSTimeDiff(realCurrTime, getMSTime());
|
||||
devDiffTracker.Update(executionTimeDiff);
|
||||
avgDiffTracker.Update(executionTimeDiff > WORLD_SLEEP_CONST ? executionTimeDiff : WORLD_SLEEP_CONST);
|
||||
|
||||
if (executionTimeDiff < WORLD_SLEEP_CONST)
|
||||
ACE_Based::Thread::Sleep(WORLD_SLEEP_CONST-executionTimeDiff);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (m_ServiceStatus == 0)
|
||||
World::StopNow(SHUTDOWN_EXIT_CODE);
|
||||
|
||||
while (m_ServiceStatus == 2)
|
||||
Sleep(1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
sLog->SetLogDB(false);
|
||||
|
||||
sScriptMgr->OnShutdown();
|
||||
|
||||
sWorld->KickAll(); // save and kick all players
|
||||
sWorld->UpdateSessions( 1 ); // real players unload required UpdateSessions call
|
||||
|
||||
// unload battleground templates before different singletons destroyed
|
||||
sBattlegroundMgr->DeleteAllBattlegrounds();
|
||||
|
||||
sWorldSocketMgr->StopNetwork();
|
||||
|
||||
sMapMgr->UnloadAll(); // unload all grids (including locked in memory)
|
||||
sObjectAccessor->UnloadAll(); // unload 'i_player2corpse' storage and remove from world
|
||||
sScriptMgr->Unload();
|
||||
sOutdoorPvPMgr->Die();
|
||||
}
|
||||
|
||||
void AuctionListingRunnable::run()
|
||||
{
|
||||
sLog->outString("Starting up Auction House Listing thread...");
|
||||
while (!World::IsStopped())
|
||||
{
|
||||
if (AsyncAuctionListingMgr::IsAuctionListingAllowed())
|
||||
{
|
||||
uint32 diff = AsyncAuctionListingMgr::GetDiff();
|
||||
AsyncAuctionListingMgr::ResetDiff();
|
||||
|
||||
if (AsyncAuctionListingMgr::GetTempList().size() || AsyncAuctionListingMgr::GetList().size())
|
||||
{
|
||||
TRINITY_GUARD(ACE_Thread_Mutex, AsyncAuctionListingMgr::GetLock());
|
||||
|
||||
{
|
||||
TRINITY_GUARD(ACE_Thread_Mutex, AsyncAuctionListingMgr::GetTempLock());
|
||||
for (std::list<AuctionListItemsDelayEvent>::iterator itr = AsyncAuctionListingMgr::GetTempList().begin(); itr != AsyncAuctionListingMgr::GetTempList().end(); ++itr)
|
||||
AsyncAuctionListingMgr::GetList().push_back( (*itr) );
|
||||
AsyncAuctionListingMgr::GetTempList().clear();
|
||||
}
|
||||
|
||||
for (std::list<AuctionListItemsDelayEvent>::iterator itr = AsyncAuctionListingMgr::GetList().begin(); itr != AsyncAuctionListingMgr::GetList().end(); ++itr)
|
||||
{
|
||||
if ((*itr)._msTimer <= diff)
|
||||
(*itr)._msTimer = 0;
|
||||
else
|
||||
(*itr)._msTimer -= diff;
|
||||
}
|
||||
|
||||
for (std::list<AuctionListItemsDelayEvent>::iterator itr = AsyncAuctionListingMgr::GetList().begin(); itr != AsyncAuctionListingMgr::GetList().end(); ++itr)
|
||||
if ((*itr)._msTimer == 0)
|
||||
{
|
||||
if ((*itr).Execute())
|
||||
AsyncAuctionListingMgr::GetList().erase(itr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ACE_Based::Thread::Sleep(1);
|
||||
}
|
||||
sLog->outString("Auction House Listing thread exiting without problems.");
|
||||
}
|
||||
39
src/server/worldserver/WorldThread/WorldRunnable.h
Normal file
39
src/server/worldserver/WorldThread/WorldRunnable.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/// \addtogroup Trinityd
|
||||
/// @{
|
||||
/// \file
|
||||
|
||||
#ifndef __WORLDRUNNABLE_H
|
||||
#define __WORLDRUNNABLE_H
|
||||
|
||||
/// Heartbeat thread for the World
|
||||
class WorldRunnable : public ACE_Based::Runnable
|
||||
{
|
||||
public:
|
||||
void run();
|
||||
};
|
||||
|
||||
class AuctionListingRunnable : public ACE_Based::Runnable
|
||||
{
|
||||
public:
|
||||
void run();
|
||||
};
|
||||
#endif
|
||||
/// @}
|
||||
15
src/server/worldserver/resource.h
Normal file
15
src/server/worldserver/resource.h
Normal file
@@ -0,0 +1,15 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by SunwellCore.rc
|
||||
//
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 101
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1000
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
2946
src/server/worldserver/worldserver.conf.dist
Normal file
2946
src/server/worldserver/worldserver.conf.dist
Normal file
File diff suppressed because it is too large
Load Diff
BIN
src/server/worldserver/worldserver.ico
Normal file
BIN
src/server/worldserver/worldserver.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 133 KiB |
94
src/server/worldserver/worldserver.rc
Normal file
94
src/server/worldserver/worldserver.rc
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "resource.h"
|
||||
#include "revision.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "windows.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Icon
|
||||
//
|
||||
|
||||
// Icon with lowest ID value placed first to ensure application icon
|
||||
// remains consistent on all systems.
|
||||
IDI_APPICON ICON "worldserver.ico"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Neutre (Par défaut système) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUSD)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_NEUTRAL, SUBLANG_SYS_DEFAULT
|
||||
#pragma code_page(1252)
|
||||
#endif //_WIN32
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION VER_FILEVERSION
|
||||
PRODUCTVERSION VER_PRODUCTVERSION
|
||||
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
|
||||
#ifndef _DEBUG
|
||||
FILEFLAGS 0
|
||||
#else
|
||||
#define VER_PRERELEASE VS_FF_PRERELEASE
|
||||
#define VER_PRIVATEBUILD VS_FF_PRIVATEBUILD
|
||||
#define VER_DEBUG 0
|
||||
FILEFLAGS (VER_PRIVATEBUILD|VER_PRERELEASE|VER_DEBUG)
|
||||
#endif
|
||||
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_APP
|
||||
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "080004b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", VER_COMPANYNAME_STR
|
||||
VALUE "FileDescription", "World Server Daemon"
|
||||
VALUE "FileVersion", VER_FILEVERSION_STR
|
||||
VALUE "InternalName", "worldserver"
|
||||
VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR
|
||||
VALUE "OriginalFilename", "worldserver.exe"
|
||||
VALUE "ProductName", "World Server"
|
||||
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
|
||||
END
|
||||
END
|
||||
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x800, 1200
|
||||
END
|
||||
END
|
||||
#endif
|
||||
Reference in New Issue
Block a user