2016-01-28 14:52:40 +01:00
|
|
|
/** @file
|
|
|
|
|
*
|
|
|
|
|
* @par History
|
|
|
|
|
* - 2005/02/23 Shinigami: ServSpecOpt DecayItems to enable/disable item decay
|
|
|
|
|
* - 2005/04/03 Shinigami: send_feature_enable() call moved from start_client_char()
|
|
|
|
|
* to send_start() to send before char selection
|
|
|
|
|
* - 2005/04/04 Shinigami: added can_delete_character( chr, delete_by )
|
2016-02-19 19:26:35 +01:00
|
|
|
* - 2005/06/15 Shinigami: ServSpecOpt UseWinLFH to enable/disable Windows XP/2003 low-fragmentation
|
|
|
|
|
* Heap
|
2016-01-28 14:52:40 +01:00
|
|
|
* added Check_for_WinXP_or_Win2003() and low_fragmentation_Heap()
|
|
|
|
|
* - 2005/06/20 Shinigami: added llog (needs defined MEMORYLEAK)
|
|
|
|
|
* - 2005/07/01 Shinigami: removed Check_for_WinXP_or_Win2003() and transformed call of
|
|
|
|
|
* Use_low_fragmentation_Heap() into Run-Time Dynamic Linking
|
|
|
|
|
* - 2005/10/13 Shinigami: added Check_libc_version() and printing a Warning if libc is to old
|
|
|
|
|
* - 2005/11/25 Shinigami: PKTBI_BF::TYPE_SESPAM will not block Inactivity-Check
|
|
|
|
|
* - 2005/11/28 MuadDib: Created check_inactivity() bool function to handle checking packets
|
|
|
|
|
* for ones to be considered "ignored" for inactivity. Returns true if
|
|
|
|
|
* the packet was one to be ignored.
|
|
|
|
|
* - 2005/11/28 MuadDib: Implemented check_inactivity() function in appropriate place.
|
|
|
|
|
* - 2006/03/01 MuadDib: Added connect = true to start_client_char so char creation can use.
|
|
|
|
|
* - 2006/03/03 MuadDib: Moved all instances of connected = true to start_client_char.
|
|
|
|
|
* - 2006/06/03 Shinigami: added little bit more logging @ pthread_create
|
|
|
|
|
* - 2006/06/05 Shinigami: added little bit more logging @ Client disconnects by Core
|
|
|
|
|
* - 2006/07/05 Shinigami: moved MakeDirectory("log") a little bit up
|
|
|
|
|
* - 2006/10/07 Shinigami: FreeBSD fix - changed some __linux__ to __unix__
|
|
|
|
|
* - 2007/03/08 Shinigami: added pthread_exit and _endhreadex to close threads
|
|
|
|
|
* - 2007/05/06 Shinigami: smaller bugfix in Check_libc_version()
|
|
|
|
|
* - 2007/06/17 Shinigami: Pergon-Linux-Release generates file "pol.pid"
|
|
|
|
|
* - 2007/07/08 Shinigami: added UO:KR login process
|
|
|
|
|
* - 2008/07/08 Turley: removed Checkpoint "initializing random number generator"
|
|
|
|
|
* - 2008/12/17 MuadDub: Added check when loading Realms for no realms existing.
|
|
|
|
|
* - 2009/01/19 Nando: added unload_aux_services() and unload_packages() to the shutdown cleanup
|
2016-02-19 19:26:35 +01:00
|
|
|
* - 2009/1/24 MuadDib: Added read_bannedips_config() and checkpoint for it after loading of
|
|
|
|
|
* pol.cfg
|
2016-01-28 14:52:40 +01:00
|
|
|
* - 2009/07/23 MuadDib: Updates for MSGOUT naming.
|
2016-02-19 19:26:35 +01:00
|
|
|
* - 2009/07/31 MuadDib: xmain_inner(): Force Client Disconnect to initiate cleanup of clients and
|
|
|
|
|
* chars, after shutdown,
|
2016-01-28 14:52:40 +01:00
|
|
|
* before other cleanups.
|
2016-02-19 19:26:35 +01:00
|
|
|
* - 2009/08/01 MuadDib: Removed send_tech_stuff(), send_betaclient_BF(), just_ignore_message(),
|
|
|
|
|
* and ignore_69() due to not used or obsolete.
|
|
|
|
|
* - 2009/08/03 MuadDib: Renaming of MSG_HANDLER_6017 and related, to MSG_HANDLER_V2 for better
|
|
|
|
|
* description
|
2016-01-28 14:52:40 +01:00
|
|
|
* Renamed secondary handler class to *_V2 for naming convention
|
|
|
|
|
* - 2009/08/14 Turley: fixed definition of PKTIN_5D
|
|
|
|
|
* - 2009/08/19 Turley: PKTIN_5D clientflag saved in client->UOExpansionFlagClient
|
|
|
|
|
* - 2009/09/03 MuadDib: Relocation of account related cpp/h
|
|
|
|
|
* Changes for multi related source file relocation
|
|
|
|
|
* - 2009/09/15 MuadDib: Multi registration/unregistration support added.
|
|
|
|
|
* - 2009/09/06 Turley: Changed Version checks to bitfield client->ClientType
|
|
|
|
|
* - 2009/09/22 MuadDib: Fix for lightlevel resets in client during login.
|
|
|
|
|
* - 2009/11/19 Turley: ssopt.core_sends_season & .core_handled_tags - Tomi
|
|
|
|
|
* - 2009/12/04 Turley: Crypto cleanup - Tomi
|
|
|
|
|
* - 2010/01/22 Turley: Speedhack Prevention System
|
2016-02-19 19:26:35 +01:00
|
|
|
* - 2010/03/28 Shinigami: Transmit Pointer as Pointer and not Int as Pointer within
|
|
|
|
|
* decay_thread_shadow
|
2018-04-03 04:13:03 +02:00
|
|
|
* - 2011/11/12 Tomi: Added extobj.cfg
|
2016-01-28 14:52:40 +01:00
|
|
|
*/
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2018-01-01 21:49:30 +01:00
|
|
|
#include "pol.h"
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2018-01-29 21:55:48 +01:00
|
|
|
#include <errno.h>
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2018-06-18 10:27:01 +02:00
|
|
|
#include "pol_global_config.h"
|
|
|
|
|
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "../bscript/bobject.h"
|
2014-11-15 00:12:04 +01:00
|
|
|
#include "../bscript/escriptv.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "../clib/Debugging/ExceptionParser.h"
|
2018-06-18 10:27:01 +02:00
|
|
|
#include "../clib/Program/ProgramConfig.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "../clib/clib_endian.h"
|
|
|
|
|
#include "../clib/esignal.h"
|
|
|
|
|
#include "../clib/fileutil.h"
|
|
|
|
|
#include "../clib/kbhit.h"
|
|
|
|
|
#include "../clib/logfacility.h"
|
2019-03-04 21:41:27 +01:00
|
|
|
#include "../clib/network/sockets.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "../clib/passert.h"
|
|
|
|
|
#include "../clib/rawtypes.h"
|
|
|
|
|
#include "../clib/refptr.h"
|
|
|
|
|
#include "../clib/stlutil.h"
|
|
|
|
|
#include "../clib/streamsaver.h"
|
|
|
|
|
#include "../clib/threadhelp.h"
|
|
|
|
|
#include "../clib/timer.h"
|
|
|
|
|
#include "../clib/tracebuf.h"
|
|
|
|
|
#include "../plib/pkg.h"
|
|
|
|
|
#include "../plib/systemstate.h"
|
2014-08-29 16:58:29 +02:00
|
|
|
#include "accounts/account.h"
|
2021-09-13 20:27:13 +02:00
|
|
|
#include "base/position.h"
|
2014-08-29 16:58:29 +02:00
|
|
|
#include "checkpnt.h"
|
2014-12-30 14:14:41 +01:00
|
|
|
#include "console.h"
|
2014-08-29 16:58:29 +02:00
|
|
|
#include "core.h"
|
|
|
|
|
#include "decay.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "extobj.h"
|
2014-08-29 16:58:29 +02:00
|
|
|
#include "fnsearch.h"
|
|
|
|
|
#include "gameclck.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "globals/network.h"
|
|
|
|
|
#include "globals/object_storage.h"
|
|
|
|
|
#include "globals/state.h"
|
|
|
|
|
#include "globals/uvars.h"
|
2015-10-02 21:30:14 +02:00
|
|
|
#include "item/armor.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "item/equipmnt.h"
|
|
|
|
|
#include "item/itemdesc.h"
|
2014-08-29 16:58:29 +02:00
|
|
|
#include "loadunld.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "menu.h"
|
2014-11-15 00:12:04 +01:00
|
|
|
#include "mobile/charactr.h"
|
|
|
|
|
#include "multi/house.h"
|
2014-08-29 16:58:29 +02:00
|
|
|
#include "multi/multi.h"
|
2014-11-15 00:12:04 +01:00
|
|
|
#include "network/cgdata.h"
|
|
|
|
|
#include "network/client.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "network/clientthread.h"
|
2014-11-15 00:12:04 +01:00
|
|
|
#include "network/clienttransmit.h"
|
|
|
|
|
#include "network/cliface.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "network/packethelper.h"
|
2014-11-15 00:12:04 +01:00
|
|
|
#include "network/packethooks.h"
|
|
|
|
|
#include "network/packets.h"
|
2018-12-30 21:35:54 +01:00
|
|
|
#include "network/pktboth.h"
|
|
|
|
|
#include "network/pktdef.h"
|
|
|
|
|
#include "network/pktin.h"
|
2018-12-30 21:58:07 +01:00
|
|
|
#include "network/sockio.h"
|
2014-11-15 00:12:04 +01:00
|
|
|
#include "party.h"
|
2014-08-29 16:58:29 +02:00
|
|
|
#include "polcfg.h"
|
2014-11-15 00:12:04 +01:00
|
|
|
#include "polclock.h"
|
2014-08-29 16:58:29 +02:00
|
|
|
#include "poldbg.h"
|
2014-11-15 00:12:04 +01:00
|
|
|
#include "polsem.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "polsig.h"
|
2014-08-29 16:58:29 +02:00
|
|
|
#include "polwww.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "profile.h"
|
|
|
|
|
#include "realms/WorldChangeReasons.h"
|
2015-09-18 19:11:46 +02:00
|
|
|
#include "realms/realm.h"
|
2021-08-23 07:58:42 +02:00
|
|
|
#include "regions/guardrgn.h"
|
|
|
|
|
#include "regions/miscrgn.h"
|
|
|
|
|
#include "regions/musicrgn.h"
|
2014-08-29 16:58:29 +02:00
|
|
|
#include "savedata.h"
|
|
|
|
|
#include "scrdef.h"
|
|
|
|
|
#include "scrsched.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "sqlscrobj.h"
|
|
|
|
|
#include "ssopt.h"
|
|
|
|
|
#include "testing/poltest.h"
|
2014-11-15 00:12:04 +01:00
|
|
|
#include "ufunc.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "uimport.h"
|
|
|
|
|
#include "uoclient.h"
|
2014-08-29 16:58:29 +02:00
|
|
|
#include "uoscrobj.h"
|
|
|
|
|
#include "uworld.h"
|
2024-01-16 17:55:42 +01:00
|
|
|
|
2014-12-30 14:14:41 +01:00
|
|
|
|
2014-11-23 15:22:57 +01:00
|
|
|
#ifndef NDEBUG
|
2018-02-04 13:18:30 +01:00
|
|
|
#include "containr.h"
|
2015-01-16 19:44:07 +01:00
|
|
|
#include "mobile/npc.h"
|
2014-11-23 15:22:57 +01:00
|
|
|
#endif
|
|
|
|
|
|
2014-08-29 16:58:29 +02:00
|
|
|
#ifdef _WIN32
|
2014-11-15 00:12:04 +01:00
|
|
|
#include <process.h>
|
2018-01-29 21:55:48 +01:00
|
|
|
|
|
|
|
|
#include "../clib/mdump.h"
|
2014-11-15 00:12:04 +01:00
|
|
|
#endif
|
|
|
|
|
|
2014-08-29 16:58:29 +02:00
|
|
|
#ifdef __linux__
|
|
|
|
|
#include <gnu/libc-version.h>
|
|
|
|
|
#endif
|
2014-11-02 13:50:25 +01:00
|
|
|
|
2014-11-15 00:12:04 +01:00
|
|
|
|
|
|
|
|
#include <cstdio>
|
|
|
|
|
#include <cstring>
|
2018-01-29 21:55:48 +01:00
|
|
|
#include <exception>
|
|
|
|
|
#include <iosfwd>
|
2014-11-02 13:50:25 +01:00
|
|
|
#include <string>
|
|
|
|
|
|
2014-12-30 14:14:41 +01:00
|
|
|
#ifdef _MSC_VER
|
2016-02-19 19:26:35 +01:00
|
|
|
#pragma warning( disable : 4127 ) // conditional expression is constant (needed because of FD_SET)
|
2014-12-30 14:14:41 +01:00
|
|
|
#endif
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
namespace Pol
|
|
|
|
|
{
|
|
|
|
|
namespace Bscript
|
|
|
|
|
{
|
|
|
|
|
void display_executor_instances();
|
|
|
|
|
void display_bobjectimp_instances();
|
2018-12-30 21:35:54 +01:00
|
|
|
} // namespace Bscript
|
2016-02-19 19:26:35 +01:00
|
|
|
namespace Items
|
|
|
|
|
{
|
|
|
|
|
void load_intrinsic_weapons();
|
|
|
|
|
void allocate_intrinsic_weapon_serials();
|
2018-12-30 21:35:54 +01:00
|
|
|
} // namespace Items
|
2016-02-19 19:26:35 +01:00
|
|
|
namespace Network
|
|
|
|
|
{
|
|
|
|
|
void load_aux_services();
|
|
|
|
|
void start_aux_services();
|
|
|
|
|
void read_bannedips_config( bool initial_load );
|
2018-12-30 21:35:54 +01:00
|
|
|
} // namespace Network
|
2016-02-19 19:26:35 +01:00
|
|
|
namespace Core
|
|
|
|
|
{
|
|
|
|
|
void cancel_all_trades();
|
|
|
|
|
void load_system_hooks();
|
|
|
|
|
bool load_realms();
|
|
|
|
|
void InitializeSystemTrayHandling();
|
|
|
|
|
void ShutdownSystemTrayHandling();
|
|
|
|
|
void start_uo_client_listeners( void );
|
|
|
|
|
void start_tasks();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
using namespace threadhelp;
|
|
|
|
|
|
|
|
|
|
void send_startup( Network::Client* client )
|
|
|
|
|
{
|
|
|
|
|
Mobile::Character* chr = client->chr;
|
|
|
|
|
Network::PktHelper::PacketOut<Network::PktOut_1B> msg;
|
|
|
|
|
msg->Write<u32>( chr->serial_ext );
|
|
|
|
|
msg->offset += 4; // u8 unk5, unk6, unk7, unk8
|
|
|
|
|
msg->WriteFlipped<u16>( chr->graphic );
|
2021-09-10 20:17:25 +02:00
|
|
|
msg->WriteFlipped<u16>( chr->x() );
|
|
|
|
|
msg->WriteFlipped<u16>( chr->y() );
|
2016-02-19 19:26:35 +01:00
|
|
|
msg->offset++; // u8 unk_15
|
2021-09-10 20:17:25 +02:00
|
|
|
msg->Write<s8>( chr->z() );
|
2016-02-19 19:26:35 +01:00
|
|
|
msg->Write<u8>( chr->facing );
|
|
|
|
|
msg->offset += 3; // u8 unk18,unk19,unk20
|
|
|
|
|
msg->Write<u8>( 0x7Fu );
|
|
|
|
|
msg->offset++; // u8 unk22
|
|
|
|
|
msg->offset += 4; // u16 map_startx, map_starty
|
2021-09-10 20:17:25 +02:00
|
|
|
msg->WriteFlipped<u16>( client->chr->realm()->width() );
|
|
|
|
|
msg->WriteFlipped<u16>( client->chr->realm()->height() );
|
2016-02-19 19:26:35 +01:00
|
|
|
msg->offset += 6; // u8 unk31, unk32, unk33, unk34, unk35, unk36
|
|
|
|
|
msg.Send( client );
|
|
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
void send_inrange_items( Network::Client* client )
|
|
|
|
|
{
|
2023-12-25 22:02:52 +01:00
|
|
|
WorldIterator<ItemFilter>::InMaxVisualRange( client->chr,
|
|
|
|
|
[&]( Items::Item* item )
|
|
|
|
|
{
|
|
|
|
|
if ( client->chr->in_visual_range( item ) )
|
|
|
|
|
send_item( client, item );
|
|
|
|
|
} );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
void send_inrange_multis( Network::Client* client )
|
|
|
|
|
{
|
2023-12-25 22:02:52 +01:00
|
|
|
WorldIterator<MultiFilter>::InMaxVisualRange( client->chr,
|
|
|
|
|
[&]( Multi::UMulti* multi )
|
|
|
|
|
{
|
|
|
|
|
if ( client->chr->in_visual_range( multi ) )
|
|
|
|
|
send_multi( client, multi );
|
|
|
|
|
} );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
void textcmd_startlog( Network::Client* client );
|
|
|
|
|
void textcmd_stoplog( Network::Client* client );
|
|
|
|
|
void start_client_char( Network::Client* client )
|
|
|
|
|
{
|
2018-11-03 13:14:53 +01:00
|
|
|
client->ready = true;
|
2016-12-07 23:34:16 +01:00
|
|
|
client->chr->connected( true );
|
2016-02-19 19:26:35 +01:00
|
|
|
|
|
|
|
|
// even if this stuff just gets queued, we still want the client to start
|
|
|
|
|
// getting data now.
|
|
|
|
|
client->pause();
|
|
|
|
|
|
|
|
|
|
Multi::UMulti* supporting_multi;
|
|
|
|
|
Items::Item* walkon;
|
|
|
|
|
short newz;
|
2024-07-07 15:32:29 +02:00
|
|
|
if ( client->chr->realm()->walkheight( client->chr, client->chr->pos2d(), client->chr->z(), &newz,
|
|
|
|
|
&supporting_multi, &walkon ) )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
2021-09-10 20:17:25 +02:00
|
|
|
client->chr->setposition( Pos4d( client->chr->pos() ).z( static_cast<s8>( newz ) ) );
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( supporting_multi != nullptr )
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
supporting_multi->register_object( client->chr );
|
2024-03-24 14:39:11 +01:00
|
|
|
if ( client->chr->registered_multi == 0 )
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2024-03-24 14:39:11 +01:00
|
|
|
client->chr->registered_multi = supporting_multi->serial;
|
|
|
|
|
supporting_multi->walk_on( client->chr );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
else
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2024-03-24 14:39:11 +01:00
|
|
|
if ( client->chr->registered_multi > 0 )
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2024-03-24 14:39:11 +01:00
|
|
|
Multi::UMulti* multi = system_find_multi( client->chr->registered_multi );
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( multi != nullptr )
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
multi->unregister_object( client->chr );
|
2014-08-29 16:58:29 +02:00
|
|
|
}
|
2024-03-24 14:39:11 +01:00
|
|
|
client->chr->registered_multi = 0;
|
2014-08-29 16:58:29 +02:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
client->chr->position_changed();
|
|
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
send_startup( client );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2021-09-10 20:17:25 +02:00
|
|
|
send_realm_change( client, client->chr->realm() );
|
2016-02-19 19:26:35 +01:00
|
|
|
send_map_difs( client );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( settingsManager.ssopt.core_sends_season )
|
|
|
|
|
send_season_info( client );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2023-12-25 22:02:52 +01:00
|
|
|
client->chr->lastpos = Pos4d( 0, 0, 0, nullptr );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2021-09-13 20:27:13 +02:00
|
|
|
client->gd->music_region =
|
|
|
|
|
gamestate.musicdef->getregion( Pos4d( 0, 0, 0, client->chr->realm() ) );
|
|
|
|
|
client->gd->justice_region =
|
|
|
|
|
gamestate.justicedef->getregion( Pos4d( 0, 0, 0, client->chr->realm() ) );
|
|
|
|
|
client->gd->weather_region =
|
|
|
|
|
gamestate.weatherdef->getregion( Pos4d( 0, 0, 0, client->chr->realm() ) );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
send_goxyz( client, client->chr );
|
|
|
|
|
client->chr->check_region_changes();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
client->chr->send_warmode();
|
|
|
|
|
login_complete( client );
|
|
|
|
|
client->chr->tellmove();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
client->chr->check_weather_region_change( true );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( settingsManager.ssopt.core_sends_season )
|
|
|
|
|
send_season_info( client );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
send_objects_newly_inrange( client );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
client->chr->send_highlight();
|
|
|
|
|
send_owncreate( client, client->chr );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
send_goxyz( client, client->chr );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
client->restart();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
client->chr->clear_gotten_item();
|
|
|
|
|
on_loggon_party( client->chr );
|
|
|
|
|
client->chr->send_buffs();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
// Moved login_complete higher to prevent weather regions from messing up client
|
|
|
|
|
// spell icon packets(made it look like it was raining spell icons from spellbook if logged
|
|
|
|
|
// into a weather region with rain.
|
2018-04-03 04:13:03 +02:00
|
|
|
// login_complete(client);
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
void call_chr_scripts( Mobile::Character* chr, const std::string& root_script_ecl,
|
|
|
|
|
const std::string& pkg_script_ecl, bool offline = false )
|
|
|
|
|
{
|
|
|
|
|
ScriptDef sd;
|
|
|
|
|
sd.quickconfig( root_script_ecl );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( sd.exists() )
|
|
|
|
|
{
|
|
|
|
|
call_script( sd, offline ? new Module::EOfflineCharacterRefObjImp( chr )
|
|
|
|
|
: new Module::ECharacterRefObjImp( chr ) );
|
|
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
for ( Plib::Packages::iterator itr = Plib::systemstate.packages.begin();
|
|
|
|
|
itr != Plib::systemstate.packages.end(); ++itr )
|
|
|
|
|
{
|
|
|
|
|
Plib::Package* pkg = *itr;
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
sd.quickconfig( pkg, pkg_script_ecl );
|
|
|
|
|
if ( sd.exists() )
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
call_script( sd, offline ? new Module::EOfflineCharacterRefObjImp( chr )
|
|
|
|
|
: new Module::ECharacterRefObjImp( chr ) );
|
2014-08-29 16:58:29 +02:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
void run_logon_script( Mobile::Character* chr )
|
|
|
|
|
{
|
|
|
|
|
call_chr_scripts( chr, "scripts/misc/logon.ecl", "logon.ecl" );
|
|
|
|
|
}
|
|
|
|
|
void run_reconnect_script( Mobile::Character* chr )
|
|
|
|
|
{
|
|
|
|
|
call_chr_scripts( chr, "scripts/misc/reconnect.ecl", "reconnect.ecl" );
|
|
|
|
|
}
|
|
|
|
|
bool can_delete_character( Mobile::Character* chr, int delete_by )
|
|
|
|
|
{
|
|
|
|
|
ScriptDef sd;
|
|
|
|
|
sd.quickconfig( "scripts/misc/candelete.ecl" );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( sd.exists() )
|
|
|
|
|
{
|
|
|
|
|
return call_script( sd, new Module::EOfflineCharacterRefObjImp( chr ),
|
|
|
|
|
new Bscript::BLong( delete_by ) );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void call_ondelete_scripts( Mobile::Character* chr )
|
|
|
|
|
{
|
|
|
|
|
call_chr_scripts( chr, "scripts/misc/ondelete.ecl", "ondelete.ecl", true );
|
|
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
// FIXME: Consider moving most of this into a function, so character
|
|
|
|
|
// creation can use the same code.
|
|
|
|
|
void char_select( Network::Client* client, PKTIN_5D* msg )
|
|
|
|
|
{
|
|
|
|
|
bool reconnecting = false;
|
|
|
|
|
int charidx = cfBEu32( msg->charidx );
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( ( charidx >= Plib::systemstate.config.character_slots ) || ( client->acct == nullptr ) ||
|
|
|
|
|
( client->acct->get_character( charidx ) == nullptr ) )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
send_login_error( client, LOGIN_ERROR_MISC );
|
|
|
|
|
client->Disconnect();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Mobile::Character* chosen_char = client->acct->get_character( charidx );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOGLN( "Account {} selecting character {}", client->acct->name(), chosen_char->name() );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( Plib::systemstate.config.min_cmdlevel_to_login > chosen_char->cmdlevel() )
|
|
|
|
|
{
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOGLN(
|
2016-02-19 19:26:35 +01:00
|
|
|
"Account {} with character {} doesn't fit MinCmdlevelToLogin from pol.cfg. Client "
|
2024-01-16 17:55:42 +01:00
|
|
|
"disconnected by Core.",
|
|
|
|
|
client->acct->name(), chosen_char->name() );
|
2016-02-19 19:26:35 +01:00
|
|
|
|
|
|
|
|
send_login_error( client, LOGIN_ERROR_MISC );
|
|
|
|
|
client->Disconnect();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
// Dave moved this from login.cpp so client cmdlevel can be checked before denying login
|
|
|
|
|
if ( ( ( std::count_if( networkManager.clients.begin(), networkManager.clients.end(),
|
|
|
|
|
clientHasCharacter ) ) >= Plib::systemstate.config.max_clients ) &&
|
|
|
|
|
( chosen_char->cmdlevel() < Plib::systemstate.config.max_clients_bypass_cmdlevel ) )
|
|
|
|
|
{
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOGLN(
|
2016-02-19 19:26:35 +01:00
|
|
|
"To much clients connected. Check MaximumClients and/or MaximumClientsBypassCmdLevel in "
|
2024-01-16 17:55:42 +01:00
|
|
|
"pol.cfg.\n"
|
|
|
|
|
"Account {} with character {} Client disconnected by Core.",
|
|
|
|
|
client->acct->name(), chosen_char->name() );
|
2016-02-19 19:26:35 +01:00
|
|
|
|
|
|
|
|
send_login_error( client, LOGIN_ERROR_MISC );
|
|
|
|
|
client->Disconnect();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( chosen_char->client )
|
|
|
|
|
{
|
|
|
|
|
// we're reattaching to a character that is in-game. If there is still
|
|
|
|
|
// a client attached, disconnect it.
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
chosen_char->client->gd->clear();
|
|
|
|
|
chosen_char->client->forceDisconnect();
|
2018-11-03 13:14:53 +01:00
|
|
|
chosen_char->client->ready = false;
|
2016-02-19 19:26:35 +01:00
|
|
|
chosen_char->client->msgtype_filter = networkManager.disconnected_filter.get();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
// disassociate the objects from each other.
|
2018-07-31 14:30:29 +02:00
|
|
|
chosen_char->client->acct = nullptr;
|
|
|
|
|
chosen_char->client->chr = nullptr;
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2018-07-31 14:30:29 +02:00
|
|
|
chosen_char->client = nullptr;
|
2016-02-19 19:26:35 +01:00
|
|
|
reconnecting = true;
|
|
|
|
|
}
|
|
|
|
|
else if ( !Plib::systemstate.config.allow_multi_clients_per_account &&
|
|
|
|
|
client->acct->has_active_characters() )
|
|
|
|
|
{
|
|
|
|
|
// We are trying to attach a new character, but AllowMultiCharacters is not set
|
|
|
|
|
send_login_error( client, LOGIN_ERROR_OTHER_CHAR_INUSE );
|
|
|
|
|
client->Disconnect();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// logging in a character that's offline.
|
|
|
|
|
SetCharacterWorldPosition( chosen_char, Realms::WorldChangeReason::PlayerEnter );
|
2016-12-07 23:34:16 +01:00
|
|
|
chosen_char->logged_in( true );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
client->chr = chosen_char;
|
|
|
|
|
chosen_char->client = client;
|
|
|
|
|
chosen_char->acct.set( client->acct );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
client->UOExpansionFlagClient = cfBEu32( msg->clientflags );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
client->msgtype_filter = networkManager.game_filter.get();
|
|
|
|
|
start_client_char( client );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2023-12-25 22:02:52 +01:00
|
|
|
if ( !chosen_char->lastpos.realm() )
|
|
|
|
|
chosen_char->lastpos = chosen_char->pos();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( !reconnecting )
|
|
|
|
|
run_logon_script( chosen_char );
|
|
|
|
|
else
|
|
|
|
|
run_reconnect_script( chosen_char );
|
|
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
void send_client_char_data( Mobile::Character* chr, Network::Client* client );
|
|
|
|
|
void handle_resync_request( Network::Client* client, PKTBI_22_SYNC* /*msg*/ )
|
|
|
|
|
{
|
|
|
|
|
send_goxyz( client, client->chr );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
client->send_pause(); // dave removed force=true 5/10/3, let uoclient.cfg option determine xflow
|
|
|
|
|
// packets (else this hangs 4.0.0e clients)
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2023-12-25 22:02:52 +01:00
|
|
|
Core::WorldIterator<Core::MobileFilter>::InRange( client->chr->pos(), client->chr->los_size(),
|
|
|
|
|
[&]( Mobile::Character* zonechr )
|
|
|
|
|
{ send_client_char_data( zonechr, client ); } );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
send_inrange_items( client );
|
|
|
|
|
send_inrange_multis( client );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
client->send_restart(); // dave removed force=true 5/10/3
|
|
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
void restart_all_clients()
|
|
|
|
|
{
|
|
|
|
|
if ( !networkManager.uoclient_protocol.EnableFlowControlPackets )
|
|
|
|
|
return;
|
|
|
|
|
for ( Clients::iterator itr = networkManager.clients.begin(), end = networkManager.clients.end();
|
|
|
|
|
itr != end; ++itr )
|
|
|
|
|
{
|
|
|
|
|
Network::Client* client = ( *itr );
|
|
|
|
|
if ( client->pause_count )
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
client->restart();
|
2014-08-29 16:58:29 +02:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
void polclock_checkin()
|
|
|
|
|
{
|
|
|
|
|
stateManager.checkin_clock_times_out_at = polclock() + 30 * POLCLOCKS_PER_SEC;
|
|
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
#define clock_t_to_ms( x ) ( x )
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
void tasks_thread( void )
|
|
|
|
|
{
|
|
|
|
|
polclock_t sleeptime;
|
|
|
|
|
bool activity;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
while ( !Clib::exit_signalled )
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
THREAD_CHECKPOINT( tasks, 1 );
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
PolLock lck;
|
|
|
|
|
polclock_checkin();
|
|
|
|
|
THREAD_CHECKPOINT( tasks, 2 );
|
|
|
|
|
INC_PROFILEVAR( scheduler_passes );
|
|
|
|
|
check_scheduled_tasks( &sleeptime, &activity );
|
|
|
|
|
THREAD_CHECKPOINT( tasks, 3 );
|
|
|
|
|
restart_all_clients();
|
|
|
|
|
THREAD_CHECKPOINT( tasks, 5 );
|
2014-08-29 16:58:29 +02:00
|
|
|
}
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
THREAD_CHECKPOINT( tasks, 6 );
|
|
|
|
|
if ( activity )
|
|
|
|
|
send_pulse();
|
2014-08-29 16:58:29 +02:00
|
|
|
else
|
2016-02-19 19:26:35 +01:00
|
|
|
INC_PROFILEVAR( noactivity_scheduler_passes );
|
|
|
|
|
THREAD_CHECKPOINT( tasks, 7 );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
passert( sleeptime > 0 );
|
|
|
|
|
|
2021-08-28 22:26:15 +02:00
|
|
|
TRACEBUF_ADDELEM( "tasks wait_for_pulse now", static_cast<u32>( polclock() ) );
|
|
|
|
|
TRACEBUF_ADDELEM( "tasks wait_for_pulse sleeptime", static_cast<u32>( sleeptime ) );
|
2016-02-19 19:26:35 +01:00
|
|
|
|
|
|
|
|
THREAD_CHECKPOINT( tasks, 8 );
|
2021-08-28 22:26:15 +02:00
|
|
|
tasks_thread_sleep( static_cast<u32>( polclock_t_to_ms( sleeptime ) ) );
|
2016-02-19 19:26:35 +01:00
|
|
|
THREAD_CHECKPOINT( tasks, 9 );
|
2014-08-29 16:58:29 +02:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
catch ( const char* msg )
|
|
|
|
|
{
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOGLN( "Tasks Thread exits due to exception: {}", msg );
|
2016-02-19 19:26:35 +01:00
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
catch ( std::string& str )
|
|
|
|
|
{
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOGLN( "Tasks Thread exits due to exception: {}", str );
|
2016-02-19 19:26:35 +01:00
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
catch ( std::exception& ex )
|
|
|
|
|
{
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOGLN( "Tasks Thread exits due to exception: {}", ex.what() );
|
2016-02-19 19:26:35 +01:00
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
void scripts_thread( void )
|
|
|
|
|
{
|
|
|
|
|
polclock_t sleeptime;
|
|
|
|
|
bool activity;
|
|
|
|
|
while ( !Clib::exit_signalled )
|
|
|
|
|
{
|
|
|
|
|
THREAD_CHECKPOINT( scripts, 0 );
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
PolLock lck;
|
|
|
|
|
polclock_checkin();
|
2021-08-28 22:26:15 +02:00
|
|
|
TRACEBUF_ADDELEM( "scripts thread now", static_cast<u32>( polclock() ) );
|
2016-02-19 19:26:35 +01:00
|
|
|
++stateManager.profilevars.script_passes;
|
|
|
|
|
THREAD_CHECKPOINT( scripts, 1 );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
step_scripts( &sleeptime, &activity );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
THREAD_CHECKPOINT( scripts, 50 );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
restart_all_clients();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
THREAD_CHECKPOINT( scripts, 52 );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( TaskScheduler::is_dirty() )
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
THREAD_CHECKPOINT( scripts, 53 );
|
|
|
|
|
|
|
|
|
|
wake_tasks_thread();
|
2014-08-29 16:58:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( activity )
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
++stateManager.profilevars.script_passes_activity;
|
2014-08-29 16:58:29 +02:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
else
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
++stateManager.profilevars.script_passes_noactivity;
|
2014-08-29 16:58:29 +02:00
|
|
|
}
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( sleeptime )
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
THREAD_CHECKPOINT( scripts, 54 );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2021-08-28 22:26:15 +02:00
|
|
|
wait_for_pulse( static_cast<u32>( polclock_t_to_ms( sleeptime ) ) );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
THREAD_CHECKPOINT( scripts, 55 );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
template <class T>
|
|
|
|
|
inline void Delete( T* p )
|
|
|
|
|
{
|
|
|
|
|
delete p;
|
|
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
template <class T>
|
|
|
|
|
class delete_ob
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
void operator()( T* p ) { delete p; }
|
|
|
|
|
};
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
void reap_thread( void )
|
|
|
|
|
{
|
|
|
|
|
while ( !Clib::exit_signalled )
|
|
|
|
|
{
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
PolLock lck;
|
|
|
|
|
polclock_checkin();
|
|
|
|
|
objStorageManager.objecthash.Reap();
|
|
|
|
|
for ( auto& item : gamestate.dynamic_item_descriptors )
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
delete item;
|
2014-08-29 16:58:29 +02:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
gamestate.dynamic_item_descriptors.clear();
|
2014-08-29 16:58:29 +02:00
|
|
|
}
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
threadhelp::thread_sleep_ms( 2000 );
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
void threadstatus_thread( void )
|
|
|
|
|
{
|
|
|
|
|
int timeouts_remaining = 1;
|
|
|
|
|
bool sent_wakeups = false;
|
|
|
|
|
// we want this thread to be the last out, so that it can report stuff at shutdown.
|
|
|
|
|
while ( !Clib::exit_signalled || threadhelp::child_threads > 1 )
|
|
|
|
|
{
|
2018-10-22 20:29:55 +02:00
|
|
|
if ( is_polclock_paused_at_zero() )
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
polclock_t now = polclock();
|
|
|
|
|
if ( now >= stateManager.checkin_clock_times_out_at )
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2024-01-12 06:51:44 +01:00
|
|
|
ERROR_PRINTLN(
|
|
|
|
|
"########################################################\n"
|
|
|
|
|
"No clock movement in 30 seconds. Dumping thread status." );
|
2016-02-19 19:26:35 +01:00
|
|
|
stateManager.polsig.report_status_signalled = true;
|
|
|
|
|
stateManager.checkin_clock_times_out_at = now + 30 * POLCLOCKS_PER_SEC;
|
2014-08-29 16:58:29 +02:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( stateManager.polsig.report_status_signalled )
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2024-01-12 06:51:44 +01:00
|
|
|
std::string tmp = fmt::format(
|
|
|
|
|
"*Thread Info*\n"
|
|
|
|
|
"Semaphore TID: {}\n",
|
|
|
|
|
locker );
|
2016-02-19 19:26:35 +01:00
|
|
|
|
2018-01-29 21:55:48 +01:00
|
|
|
if ( Plib::systemstate.config.log_traces_when_stuck )
|
2016-03-27 15:36:18 +02:00
|
|
|
Pol::Clib::ExceptionParser::logAllStackTraces();
|
2016-02-19 19:26:35 +01:00
|
|
|
|
2024-01-12 06:51:44 +01:00
|
|
|
fmt::format_to( std::back_inserter( tmp ),
|
|
|
|
|
"Scripts Thread Checkpoint: {}\n"
|
|
|
|
|
"Last Script: {} PC: {}\n"
|
|
|
|
|
"Escript Instruction Cycles: {}\n"
|
|
|
|
|
"Tasks Thread Checkpoint: {}\n"
|
|
|
|
|
"Active Client Thread Checkpoint: {}\n"
|
|
|
|
|
"Number of clients: {}\n",
|
|
|
|
|
stateManager.polsig.scripts_thread_checkpoint, Clib::scripts_thread_script,
|
|
|
|
|
Clib::scripts_thread_scriptPC, Bscript::escript_instr_cycles,
|
|
|
|
|
stateManager.polsig.tasks_thread_checkpoint,
|
|
|
|
|
stateManager.polsig.active_client_thread_checkpoint,
|
|
|
|
|
Core::networkManager.clients.size() );
|
2016-02-19 19:26:35 +01:00
|
|
|
for ( const auto& client : Core::networkManager.clients )
|
2024-01-12 06:51:44 +01:00
|
|
|
fmt::format_to( std::back_inserter( tmp ), " {} {} {}\n", client->ipaddrAsString(),
|
|
|
|
|
client->acct == nullptr ? "prelogin " : client->acct->name(),
|
|
|
|
|
client->session()->checkpoint );
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( stateManager.polsig.check_attack_after_move_function_checkpoint )
|
2024-01-12 06:51:44 +01:00
|
|
|
fmt::format_to( std::back_inserter( tmp ), "check_attack_after_move() Checkpoint: {}\n",
|
|
|
|
|
stateManager.polsig.check_attack_after_move_function_checkpoint );
|
|
|
|
|
tmp += "Current Threads:\n";
|
2016-02-19 19:26:35 +01:00
|
|
|
ThreadMap::Contents contents;
|
|
|
|
|
threadmap.CopyContents( contents );
|
|
|
|
|
for ( ThreadMap::Contents::const_iterator citr = contents.begin(); citr != contents.end();
|
|
|
|
|
++citr )
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2024-01-12 06:51:44 +01:00
|
|
|
fmt::format_to( std::back_inserter( tmp ), "{} - {}\n", ( *citr ).first, ( *citr ).second );
|
2014-08-29 16:58:29 +02:00
|
|
|
}
|
2024-01-12 06:51:44 +01:00
|
|
|
fmt::format_to( std::back_inserter( tmp ),
|
|
|
|
|
"Child threads (child_threads): {}\n"
|
|
|
|
|
"Registered threads (ThreadMap): {}",
|
|
|
|
|
threadhelp::child_threads, contents.size() );
|
2016-02-19 19:26:35 +01:00
|
|
|
stateManager.polsig.report_status_signalled = false;
|
2024-01-12 06:51:44 +01:00
|
|
|
ERROR_PRINTLN( tmp );
|
2014-08-29 16:58:29 +02:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( Clib::exit_signalled )
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( !sent_wakeups )
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
send_pulse();
|
|
|
|
|
wake_tasks_thread();
|
|
|
|
|
networkManager.clientTransmit->Cancel();
|
2014-08-29 16:58:29 +02:00
|
|
|
#ifdef HAVE_MYSQL
|
2016-02-19 19:26:35 +01:00
|
|
|
networkManager.sql_service->stop();
|
2014-08-29 16:58:29 +02:00
|
|
|
#endif
|
2016-02-19 19:26:35 +01:00
|
|
|
sent_wakeups = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
--timeouts_remaining;
|
|
|
|
|
if ( timeouts_remaining == 0 )
|
|
|
|
|
{
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "Waiting for {} child threads to exit", threadhelp::child_threads );
|
2016-02-19 19:26:35 +01:00
|
|
|
timeouts_remaining = 5;
|
2014-08-29 16:58:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
pol_sleep_ms( 1000 );
|
|
|
|
|
}
|
|
|
|
|
// cerr << "threadstatus thread exits." << endl;
|
|
|
|
|
signal_catch_thread();
|
|
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
void catch_signals_thread( void );
|
|
|
|
|
void reload_configuration();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
void console_thread( void )
|
|
|
|
|
{
|
2015-02-21 10:23:50 +01:00
|
|
|
#ifndef _WIN32
|
2016-02-19 19:26:35 +01:00
|
|
|
Clib::KeyboardHook kb; // local to have a defined deconstruction to uninstall the hook
|
2015-02-21 10:23:50 +01:00
|
|
|
#endif
|
2016-02-19 19:26:35 +01:00
|
|
|
while ( !Clib::exit_signalled )
|
|
|
|
|
{
|
|
|
|
|
pol_sleep_ms( 1000 );
|
2015-02-21 10:23:50 +01:00
|
|
|
#ifdef _WIN32
|
2016-02-19 19:26:35 +01:00
|
|
|
ConsoleCommand::check_console_commands();
|
2015-02-21 10:23:50 +01:00
|
|
|
#else
|
2016-02-19 19:26:35 +01:00
|
|
|
ConsoleCommand::check_console_commands( &kb );
|
|
|
|
|
if ( stateManager.polsig.reload_configuration_signalled )
|
|
|
|
|
{
|
|
|
|
|
PolLock lck;
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINT( "Reloading configuration..." );
|
2016-02-19 19:26:35 +01:00
|
|
|
stateManager.polsig.reload_configuration_signalled = false;
|
|
|
|
|
reload_configuration();
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "Done." );
|
2014-08-29 16:58:29 +02:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
void start_threads()
|
|
|
|
|
{
|
|
|
|
|
threadmap.Register( thread_pid(), "Main" );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( Plib::systemstate.config.web_server )
|
|
|
|
|
start_http_server();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2019-02-22 19:24:23 +01:00
|
|
|
checkpoint( "start tasks thread" );
|
|
|
|
|
threadhelp::start_thread( tasks_thread, "Tasks" );
|
|
|
|
|
checkpoint( "start scripts thread" );
|
|
|
|
|
threadhelp::start_thread( scripts_thread, "Scripts" );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( settingsManager.ssopt.decay_items )
|
|
|
|
|
{
|
|
|
|
|
checkpoint( "start decay thread" );
|
2024-07-14 17:34:17 +02:00
|
|
|
threadhelp::start_thread( Decay::decay_thread, "Decay", nullptr );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
checkpoint( "don't start decay thread" );
|
|
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
checkpoint( "start reap thread" );
|
|
|
|
|
threadhelp::start_thread( reap_thread, "Reap" );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
checkpoint( "start dbglisten thread" );
|
|
|
|
|
threadhelp::start_thread( debug_listen_thread, "DbgListn" );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
checkpoint( "start threadstatus thread" );
|
|
|
|
|
start_thread( threadstatus_thread, "ThreadStatus" );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
checkpoint( "start clienttransmit thread" );
|
|
|
|
|
start_thread( Network::ClientTransmitThread, "ClientTransmit" );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
|
|
|
|
#ifdef HAVE_MYSQL
|
2016-02-19 19:26:35 +01:00
|
|
|
checkpoint( "start sql service thread" );
|
|
|
|
|
start_sql_service();
|
2014-08-29 16:58:29 +02:00
|
|
|
#endif
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
|
|
|
|
#if REFPTR_DEBUG
|
2016-02-19 19:26:35 +01:00
|
|
|
unsigned int ref_counted::_ctor_calls;
|
2014-08-29 16:58:29 +02:00
|
|
|
#endif
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
void display_unreaped_orphan_instances();
|
|
|
|
|
void display_reftypes();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
void display_leftover_objects()
|
|
|
|
|
{
|
|
|
|
|
Bscript::display_executor_instances();
|
|
|
|
|
display_unreaped_orphan_instances();
|
2014-08-29 16:58:29 +02:00
|
|
|
#if BOBJECTIMP_DEBUG
|
2016-02-19 19:26:35 +01:00
|
|
|
Bscript::display_bobjectimp_instances();
|
2014-08-29 16:58:29 +02:00
|
|
|
#endif
|
2016-02-19 19:26:35 +01:00
|
|
|
display_reftypes();
|
Savefile rewrite (#601)
* rewrite of saving, replaced operator way with a generic add method, thus
not everywhere the formating of the savefiles is hardcoded.
since its the last spot which uses the old formating lib, remobed the
lib
* removed cmake of old format lib
* testscripts for load/save of UObject,Item,Armor,Weapon
* fixed: member faster_cast_recovery and faster_cast_recovery_mod getter returned
a wrong value
* wrong/missing docs
* test containers, lockable, map, spellbooks
fixed save bug in map and spellbook
removed ancient savestrategy experiments
* added corpse test
splitted testfiles
* fixed loading (ancient bug) and saving (PR bug) of Reportables
added tests for houses, boats, accounts and chars
* fixed include
* fix shutdown leak
* added npc tests
upload complete coretest folder also on failure
* do not write and load RegisteredHouse for NPCs two times
readded extra newline between accounts
* tests for guild, party, realm
added resource cfgs, but a test is not really possible since nothing of
interest is stored
* added datafile, storage test
* activated resource loading, 25year old bug, but since the stored values
are senseless it makes no real difference.
added a few wtf comments
catch all exceptions during formatting of log lines
* replaced .write with explixit .begin, .end and .comment.
for leftovers.txt the StreamSaver was also used, since the format is
different use directly ofstream
* added corechanges
2024-01-24 18:49:06 +01:00
|
|
|
{
|
|
|
|
|
std::ofstream ofs;
|
|
|
|
|
ofs.open( "leftovers.txt", std::ios::out | std::ios::trunc );
|
|
|
|
|
objStorageManager.objecthash.PrintContents( &ofs );
|
|
|
|
|
}
|
2024-01-10 18:29:10 +01:00
|
|
|
std::string tmp;
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( stateManager.uobjcount.uobject_count != 0 )
|
2024-01-10 18:29:10 +01:00
|
|
|
tmp += fmt::format( "Remaining UObjects: {}\n", stateManager.uobjcount.uobject_count );
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( stateManager.uobjcount.ucharacter_count != 0 )
|
2024-01-10 18:29:10 +01:00
|
|
|
tmp += fmt::format( "Remaining Mobiles: {}\n", stateManager.uobjcount.ucharacter_count );
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( stateManager.uobjcount.npc_count != 0 )
|
2024-01-10 18:29:10 +01:00
|
|
|
tmp += fmt::format( "Remaining NPCs: {}\n", stateManager.uobjcount.npc_count );
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( stateManager.uobjcount.uitem_count != 0 )
|
2024-01-10 18:29:10 +01:00
|
|
|
tmp += fmt::format( "Remaining Items: {}\n", stateManager.uobjcount.uitem_count );
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( stateManager.uobjcount.umulti_count != 0 )
|
2024-01-10 18:29:10 +01:00
|
|
|
tmp += fmt::format( "Remaining Multis: {}\n", stateManager.uobjcount.umulti_count );
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( stateManager.uobjcount.unreaped_orphans != 0 )
|
2024-01-10 18:29:10 +01:00
|
|
|
tmp += fmt::format( "Unreaped orphans: {}\n", stateManager.uobjcount.unreaped_orphans );
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( stateManager.uobjcount.uobj_count_echrref != 0 )
|
2024-01-10 18:29:10 +01:00
|
|
|
tmp +=
|
|
|
|
|
fmt::format( "Remaining EChrRef objects: {}\n", stateManager.uobjcount.uobj_count_echrref );
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( Bscript::executor_count )
|
2024-01-10 18:29:10 +01:00
|
|
|
tmp += fmt::format( "Remaining Executors: {}\n", Bscript::executor_count );
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( Bscript::eobject_imp_count )
|
2024-01-10 18:29:10 +01:00
|
|
|
tmp += fmt::format( "Remaining script objectimps: {}\n", Bscript::eobject_imp_count );
|
|
|
|
|
INFO_PRINT( tmp );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
void run_start_scripts()
|
|
|
|
|
{
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "Running startup script." );
|
2016-02-19 19:26:35 +01:00
|
|
|
run_script_to_completion( "start" );
|
|
|
|
|
for ( const auto& pkg : Plib::systemstate.packages )
|
|
|
|
|
{
|
|
|
|
|
std::string scriptname = pkg->dir() + "start.ecl";
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( Clib::FileExists( scriptname.c_str() ) )
|
|
|
|
|
{
|
|
|
|
|
ScriptDef script( "start", pkg, "" );
|
|
|
|
|
Bscript::BObject obj( run_script_to_completion( script ) );
|
2014-08-29 16:58:29 +02:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "Startup script complete." );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
2016-02-19 19:26:35 +01:00
|
|
|
typedef BOOL( WINAPI* DynHeapSetInformation )( PVOID HeapHandle,
|
|
|
|
|
HEAP_INFORMATION_CLASS HeapInformationClass,
|
|
|
|
|
PVOID HeapInformation,
|
|
|
|
|
SIZE_T HeapInformationLength );
|
|
|
|
|
|
|
|
|
|
const char* Use_low_fragmentation_Heap()
|
|
|
|
|
{
|
|
|
|
|
if ( settingsManager.ssopt.use_win_lfh )
|
|
|
|
|
{
|
|
|
|
|
HINSTANCE hKernel32;
|
|
|
|
|
|
|
|
|
|
hKernel32 = LoadLibrary( "Kernel32" );
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( hKernel32 != nullptr )
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
DynHeapSetInformation ProcAdd;
|
|
|
|
|
ProcAdd = (DynHeapSetInformation)GetProcAddress( hKernel32, "HeapSetInformation" );
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( ProcAdd != nullptr )
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
ULONG HeapFragValue = 2;
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2021-08-23 07:58:42 +02:00
|
|
|
if ( (ProcAdd)( GetProcessHeap(), HeapCompatibilityInformation, &HeapFragValue,
|
|
|
|
|
sizeof( HeapFragValue ) ) )
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2016-02-19 19:26:35 +01:00
|
|
|
FreeLibrary( hKernel32 );
|
|
|
|
|
return "low-fragmentation Heap ...activated";
|
2014-08-29 16:58:29 +02:00
|
|
|
}
|
|
|
|
|
else
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
FreeLibrary( hKernel32 );
|
|
|
|
|
return "low-fragmentation Heap ...not activated";
|
|
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
}
|
|
|
|
|
else
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
FreeLibrary( hKernel32 );
|
|
|
|
|
return "low-fragmentation Heap ...not available on your Windows";
|
|
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
else
|
|
|
|
|
return "low-fragmentation Heap ...not available on your Windows";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return "low-fragmentation Heap ...disabled via ServSpecOpt";
|
|
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef __linux__
|
2016-02-19 19:26:35 +01:00
|
|
|
void Check_libc_version()
|
|
|
|
|
{
|
|
|
|
|
const char* libc_version = gnu_get_libc_version();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
int main_version = 0;
|
|
|
|
|
int sub_version = 0;
|
|
|
|
|
int build = 0;
|
|
|
|
|
ISTRINGSTREAM is( libc_version );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( is >> main_version )
|
|
|
|
|
{
|
|
|
|
|
char delimiter;
|
|
|
|
|
if ( is >> delimiter >> sub_version )
|
|
|
|
|
{
|
|
|
|
|
is >> delimiter >> build;
|
2014-08-29 16:58:29 +02:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
else
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOG_ERRORLN( "Error in analyzing libc version string [{}]. Please contact Core-Team.",
|
|
|
|
|
libc_version );
|
2016-02-19 19:26:35 +01:00
|
|
|
|
|
|
|
|
if ( main_version * 100000000 + sub_version * 10000 + build >= 2 * 100000000 + 3 * 10000 + 2 )
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOG_INFOLN( "Found libc {} - ok", libc_version );
|
2016-02-19 19:26:35 +01:00
|
|
|
else
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOG_ERRORLN( "Found libc {} - Please update to 2.3.2 or above.", libc_version );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
} // namespace Core
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-12-14 17:05:34 +01:00
|
|
|
int xmain_inner( bool testing )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
2014-08-29 16:58:29 +02:00
|
|
|
#ifdef _WIN32
|
2016-02-19 19:26:35 +01:00
|
|
|
Clib::MiniDumper::Initialize();
|
|
|
|
|
// Aug. 15, 2006 Austin
|
|
|
|
|
// Added atexit() call to remove the tray icon.
|
|
|
|
|
atexit( Core::ShutdownSystemTrayHandling );
|
2014-08-29 16:58:29 +02:00
|
|
|
#else
|
|
|
|
|
#ifdef __linux__
|
2016-02-19 19:26:35 +01:00
|
|
|
std::ofstream polpid;
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
polpid.open( ( Plib::systemstate.config.pidfile_path + "pol.pid" ).c_str(),
|
|
|
|
|
std::ios::out | std::ios::trunc );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( polpid.is_open() )
|
2018-10-28 09:31:58 +01:00
|
|
|
polpid << Clib::tostring( getpid() );
|
2016-02-19 19:26:35 +01:00
|
|
|
else
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "Cannot create pid file in {}", Plib::systemstate.config.pidfile_path );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
polpid.close();
|
2014-08-29 16:58:29 +02:00
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
2018-04-29 19:51:50 +02:00
|
|
|
// problem with order of global construction, threads cannot be registered in the constructor of
|
|
|
|
|
// gamestate :(
|
2018-04-29 19:13:11 +02:00
|
|
|
Core::gamestate.task_thread_pool.init_pool(
|
|
|
|
|
std::max( 2u, std::thread::hardware_concurrency() / 2 ), "generic_task_thread" );
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
int res;
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
// for profiling:
|
|
|
|
|
// chdir( "d:\\pol" );
|
|
|
|
|
// PrintAllocationData();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Clib::MakeDirectory( "log" );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOG_INFOLN( "POL {} - {}\nCompiled on {}\n{}", POL_VERSION_ID,
|
|
|
|
|
Clib::ProgramConfig::build_target(), Clib::ProgramConfig::build_datetime(),
|
|
|
|
|
POL_COPYRIGHT );
|
2016-12-14 17:05:34 +01:00
|
|
|
if ( testing )
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOG_INFOLN( "TESTING MODE" );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOG_INFOLN(
|
|
|
|
|
"Sizes: \n"
|
|
|
|
|
" UObject: {}\n"
|
|
|
|
|
" Item: {}\n"
|
|
|
|
|
" UContainer: {}\n"
|
|
|
|
|
" Character: {}\n"
|
|
|
|
|
" Client: {}\n"
|
|
|
|
|
" NPC: {}",
|
|
|
|
|
sizeof( Core::UObject ), sizeof( Items::Item ), sizeof( Core::UContainer ),
|
|
|
|
|
sizeof( Mobile::Character ), sizeof( Network::Client ), sizeof( Mobile::NPC ) );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
|
|
|
|
#ifdef __unix__
|
|
|
|
|
#ifdef PTHREAD_THREADS_MAX
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOG_INFOLN( " Max Threads: {}", PTHREAD_THREADS_MAX );
|
2014-08-29 16:58:29 +02:00
|
|
|
#endif
|
|
|
|
|
#endif
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOG_INFOLN( "" );
|
2014-08-29 16:58:29 +02:00
|
|
|
#endif
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOG_INFOLN( "Using {} out of {} worldsave threads", Core::gamestate.task_thread_pool.size(),
|
|
|
|
|
std::thread::hardware_concurrency() );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::checkpoint( "installing signal handlers" );
|
|
|
|
|
Core::install_signal_handlers();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::checkpoint( "starting POL clocks" );
|
|
|
|
|
Core::start_pol_clocks();
|
|
|
|
|
Core::pause_pol_clocks();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOG_INFOLN( "Reading Configuration." );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::stateManager.gflag_in_system_startup = true;
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::checkpoint( "reading pol.cfg" );
|
|
|
|
|
Core::PolConfig::read_pol_config( true );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::checkpoint( "reading config/bannedips.cfg" );
|
|
|
|
|
Network::read_bannedips_config( true );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::checkpoint( "reading servspecopt.cfg" );
|
|
|
|
|
Core::ServSpecOpt::read_servspecopt();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::checkpoint( "reading extobj.cfg" );
|
|
|
|
|
Core::read_extobj();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::checkpoint( Core::Use_low_fragmentation_Heap() );
|
2014-08-29 16:58:29 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef __linux__
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::checkpoint( "checking libc version" );
|
|
|
|
|
Core::Check_libc_version();
|
2014-08-29 16:58:29 +02:00
|
|
|
#endif
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::checkpoint( "init default itemdesc defaults" );
|
|
|
|
|
Core::gamestate.empty_itemdesc->doubleclick_range =
|
|
|
|
|
Core::settingsManager.ssopt.default_doubleclick_range;
|
|
|
|
|
Core::gamestate.empty_itemdesc->decay_time = Core::settingsManager.ssopt.default_decay_time;
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::checkpoint( "loading POL map file" );
|
|
|
|
|
if ( !Core::load_realms() )
|
|
|
|
|
{
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOG_ERRORLN(
|
|
|
|
|
"Unable to load Realms. Please make sure your Realms have been generated by "
|
|
|
|
|
"UOConvert and your RealmDataPath is set correctly in Pol.cfg." );
|
2016-02-19 19:26:35 +01:00
|
|
|
return 1;
|
|
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
// PrintAllocationData();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::checkpoint( "initializing IPC structures" );
|
|
|
|
|
Core::init_ipc_vars();
|
|
|
|
|
threadhelp::init_threadhelp();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::InitializeSystemTrayHandling();
|
2014-08-29 16:58:29 +02:00
|
|
|
#endif
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::checkpoint( "initializing sockets library" );
|
|
|
|
|
res = Network::init_sockets_library();
|
|
|
|
|
if ( res < 0 )
|
|
|
|
|
{
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOG_ERRORLN( "Unable to initialize sockets library." );
|
2016-02-19 19:26:35 +01:00
|
|
|
return 1;
|
|
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::checkpoint( "loading configuration" );
|
|
|
|
|
Core::load_data();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::checkpoint( "loading system hooks" );
|
|
|
|
|
Core::load_system_hooks();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::checkpoint( "loading packet hooks" );
|
|
|
|
|
Network::load_packet_hooks();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::checkpoint( "loading auxservice configuration" );
|
|
|
|
|
Network::load_aux_services();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::checkpoint( "reading menus" );
|
|
|
|
|
Core::Menu::read_menus();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::checkpoint( "loading intrinsic weapons" );
|
|
|
|
|
Items::load_intrinsic_weapons();
|
|
|
|
|
Core::checkpoint( "validating intrinsic shield template" );
|
|
|
|
|
Items::validate_intrinsic_shield_template();
|
|
|
|
|
Core::checkpoint( "reading gameservers" );
|
|
|
|
|
Core::read_gameservers();
|
|
|
|
|
Core::checkpoint( "reading starting locations" );
|
|
|
|
|
Core::read_starting_locations();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-12-14 17:05:34 +01:00
|
|
|
if ( testing )
|
|
|
|
|
{
|
2022-10-16 19:39:25 +02:00
|
|
|
Items::allocate_intrinsic_equipment_serials();
|
|
|
|
|
Core::stateManager.gflag_in_system_startup = false;
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOG_INFOLN( "Running POL test suite." );
|
2021-08-23 07:58:42 +02:00
|
|
|
bool res_test = Testing::run_pol_tests();
|
2016-12-14 17:05:34 +01:00
|
|
|
Core::cancel_all_trades();
|
|
|
|
|
Core::stop_gameclock();
|
|
|
|
|
Core::gamestate.deinitialize();
|
2021-08-23 07:58:42 +02:00
|
|
|
return !res_test;
|
2016-12-14 17:05:34 +01:00
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
// PrintAllocationData();
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOG_INFOLN( "Reading data files:" );
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
Tools::Timer<> timer;
|
|
|
|
|
Core::checkpoint( "reading account data" );
|
|
|
|
|
Accounts::read_account_data();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::checkpoint( "reading data" );
|
|
|
|
|
Core::read_data();
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOG_INFOLN( "Done! {} milliseconds.", timer.ellapsed() );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Items::allocate_intrinsic_equipment_serials();
|
|
|
|
|
Core::stateManager.gflag_in_system_startup = false;
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
// PrintAllocationData();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::checkpoint( "running start scripts" );
|
|
|
|
|
Core::run_start_scripts();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::checkpoint( "starting client listeners" );
|
|
|
|
|
Core::start_uo_client_listeners();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOG_INFO( "Initialization complete. POL is active. Ctrl-C to stop.\n\n" );
|
2019-02-22 19:24:23 +01:00
|
|
|
|
|
|
|
|
DEINIT_STARTLOG();
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOGLN( "{0:s} ({1:s}) compiled on {2:s} running.", "POL ", POL_VERSION_ID,
|
|
|
|
|
Clib::ProgramConfig::build_target(), Clib::ProgramConfig::build_datetime() );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOG_INFOLN( "Game is active." );
|
2019-02-22 19:24:23 +01:00
|
|
|
|
|
|
|
|
Core::CoreSetSysTrayToolTip( "Running", Core::ToolTipPrioritySystem );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::restart_pol_clocks();
|
|
|
|
|
Core::polclock_checkin();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
// this is done right after reading globals from pol.txt:
|
|
|
|
|
// checkpoint( "starting game clock" );
|
|
|
|
|
// start_gameclock();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::checkpoint( "starting periodic tasks" );
|
|
|
|
|
Core::start_tasks();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2019-02-22 19:24:23 +01:00
|
|
|
Core::checkpoint( "starting threads" );
|
|
|
|
|
Core::start_threads();
|
|
|
|
|
Network::start_aux_services();
|
2024-01-28 15:49:55 +07:00
|
|
|
Core::networkManager.initialize();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
2019-02-22 19:24:23 +01:00
|
|
|
Core::console_thread();
|
|
|
|
|
Core::checkpoint( "exit signal detected" );
|
|
|
|
|
Core::CoreSetSysTrayToolTip( "Shutting down", Core::ToolTipPriorityShutdown );
|
2014-08-29 16:58:29 +02:00
|
|
|
#else
|
2019-02-22 19:24:23 +01:00
|
|
|
// On Linux, signals are directed to a particular thread, if we use pthread_sigmask like we're
|
|
|
|
|
// supposed to.
|
|
|
|
|
// therefore, we have to do this signal checking in this thread.
|
|
|
|
|
threadhelp::start_thread( Core::console_thread, "Console" );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2019-02-22 19:24:23 +01:00
|
|
|
Core::catch_signals_thread();
|
2014-08-29 16:58:29 +02:00
|
|
|
#endif
|
2019-02-22 19:24:23 +01:00
|
|
|
Core::checkpoint( "waiting for child threads to exit" );
|
|
|
|
|
// NOTE that it's possible that the thread_status thread not have exited yet..
|
|
|
|
|
// it signals the catch_signals_thread (this one) just before it exits.
|
|
|
|
|
// and on windows, we get here right after the console thread exits.
|
|
|
|
|
while ( threadhelp::child_threads )
|
|
|
|
|
{
|
|
|
|
|
Core::pol_sleep_ms( 1000 );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2019-02-22 19:24:23 +01:00
|
|
|
Core::checkpoint( "child threads have shut down" );
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::cancel_all_trades();
|
|
|
|
|
Core::stop_gameclock();
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOG_INFOLN( "Shutting down..." );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::checkpoint( "writing data" );
|
|
|
|
|
if ( Core::should_write_data() )
|
|
|
|
|
{
|
|
|
|
|
Core::CoreSetSysTrayToolTip( "Writing data files", Core::ToolTipPriorityShutdown );
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOG_INFO( "Writing data files..." );
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::PolLock lck;
|
|
|
|
|
unsigned int dirty, clean;
|
|
|
|
|
long long elapsed_ms;
|
|
|
|
|
int savetype;
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( Clib::passert_shutdown_due_to_assertion )
|
|
|
|
|
savetype = Plib::systemstate.config.assertion_shutdown_save_type;
|
|
|
|
|
else
|
|
|
|
|
savetype = Plib::systemstate.config.shutdown_save_type;
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
// TODO: full save if incremental_saves_disabled ?
|
|
|
|
|
// otherwise could have really, really bad timewarps
|
|
|
|
|
Tools::Timer<> timer;
|
|
|
|
|
if ( savetype == Core::SAVE_FULL )
|
|
|
|
|
Core::write_data( dirty, clean, elapsed_ms );
|
2014-08-29 16:58:29 +02:00
|
|
|
else
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::save_incremental( dirty, clean, elapsed_ms );
|
|
|
|
|
Core::SaveContext::ready();
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOG_INFOLN( "Data save completed in {} ms. {} total.", elapsed_ms, timer.ellapsed() );
|
2014-08-29 16:58:29 +02:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if ( Clib::passert_shutdown_due_to_assertion && Clib::passert_nosave )
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOG_INFOLN( "Not writing data due to assertion failure." );
|
2016-02-19 19:26:35 +01:00
|
|
|
else if ( Plib::systemstate.config.inhibit_saves )
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOG_INFOLN( "Not writing data due to pol.cfg InhibitSaves=1 setting." );
|
2014-08-29 16:58:29 +02:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::gamestate.deinitialize();
|
2020-08-03 20:30:27 +02:00
|
|
|
return Clib::exit_code;
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-12-14 17:05:34 +01:00
|
|
|
int xmain_outer( bool testing )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2016-12-14 17:05:34 +01:00
|
|
|
return xmain_inner( testing );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
catch ( std::exception& )
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( Core::stateManager.last_checkpoint != nullptr )
|
2014-08-29 16:58:29 +02:00
|
|
|
{
|
2024-01-16 17:55:42 +01:00
|
|
|
POLLOG_INFOLN( "Server Shutdown: {}", Core::stateManager.last_checkpoint );
|
2016-02-19 19:26:35 +01:00
|
|
|
// pol_sleep_ms( 10000 );
|
2014-08-29 16:58:29 +02:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
Core::gamestate.deinitialize();
|
2014-08-29 16:58:29 +02:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
throw;
|
2014-08-29 16:58:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
2018-12-30 21:35:54 +01:00
|
|
|
} // namespace Pol
|