63 #include "pol_global_config.h" 65 #include "../bscript/bobject.h" 66 #include "../bscript/escriptv.h" 67 #include "../clib/Debugging/ExceptionParser.h" 68 #include "../clib/Program/ProgramConfig.h" 69 #include "../clib/clib_endian.h" 70 #include "../clib/esignal.h" 71 #include "../clib/fileutil.h" 72 #include "../clib/kbhit.h" 73 #include "../clib/logfacility.h" 74 #include "../clib/passert.h" 75 #include "../clib/rawtypes.h" 76 #include "../clib/refptr.h" 77 #include "../clib/stlutil.h" 78 #include "../clib/streamsaver.h" 79 #include "../clib/threadhelp.h" 80 #include "../clib/timer.h" 81 #include "../clib/tracebuf.h" 82 #include "../plib/pkg.h" 83 #include "../plib/systemstate.h" 141 #include <format/format.h> 151 #include "../clib/mdump.h" 155 #include <gnu/libc-version.h> 166 #pragma warning( disable : 4127 ) // conditional expression is constant (needed because of FD_SET) 198 using namespace threadhelp;
200 #define CLIENT_CHECKPOINT( x ) client->checkpoint = x 209 msg->WriteFlipped<
u16>( chr->
x );
210 msg->WriteFlipped<
u16>( chr->
y );
212 msg->Write<
s8>( chr->
z );
215 msg->Write<
u8>( 0x7Fu );
227 client->
chr, [&](
Items::Item* item ) { send_item( client, item ); } );
233 client->
chr, [&](
Multi::UMulti* multi ) { send_multi( client, multi ); } );
251 &newz, &supporting_multi, &walkon ) )
253 client->
chr->
z =
static_cast<s8>( newz );
255 if ( supporting_multi !=
nullptr )
263 if ( this_house !=
nullptr )
272 if ( multi !=
nullptr )
330 const std::string& pkg_script_ecl,
bool offline =
false )
387 bool reconnecting =
false;
399 POLLOG.Format(
"Account {} selecting character {}\n" )
405 "Account {} with character {} doesn't fit MinCmdlevelToLogin from pol.cfg. Client " 406 "disconnected by Core.\n" )
420 "To much clients connected. Check MaximumClients and/or MaximumClientsBypassCmdLevel in " 421 "pol.cfg.\nAccount {} with character {} Client disconnected by Core.\n" )
429 if ( chosen_char->
client )
443 chosen_char->
client =
nullptr;
461 client->
chr = chosen_char;
462 chosen_char->
client = client;
470 if ( !chosen_char->
lastx && !chosen_char->
lasty )
472 chosen_char->
lastx = chosen_char->
x;
473 chosen_char->
lasty = chosen_char->
y;
492 [&](
Mobile::Character* zonechr ) { send_client_char_data( zonechr, client ); } );
502 transmit( client, msg,
sizeof *msg );
525 #define clock_t_to_ms( x ) ( x ) 564 catch (
const char* msg )
566 POLLOG.Format(
"Tasks Thread exits due to exception: {}\n" ) << msg;
569 catch ( std::string& str )
571 POLLOG.Format(
"Tasks Thread exits due to exception: {}\n" ) << str;
574 catch ( std::exception& ex )
576 POLLOG.Format(
"Tasks Thread exits due to exception: {}\n" ) << ex.what();
635 polclock_t script_clocksleft, scheduler_clocksleft;
650 if ( script_clocksleft < scheduler_clocksleft )
651 sleep_clocks = script_clocksleft;
653 sleep_clocks = scheduler_clocksleft;
654 }
while ( sleep_clocks <= 0 );
699 int timeouts_remaining = 1;
700 bool sent_wakeups =
false;
709 ERROR_PRINT <<
"########################################################\n";
710 ERROR_PRINT <<
"No clock movement in 30 seconds. Dumping thread status.\n";
719 tmp <<
"*Thread Info*\n";
720 tmp <<
"Semaphore TID: " <<
locker <<
"\n";
730 tmp <<
"Active Client Thread Checkpoint: " 735 << ( client->
acct ==
nullptr ?
"prelogin " : client->
acct->
name() ) <<
" " 738 tmp <<
"check_attack_after_move() Checkpoint: " 740 tmp <<
"Current Threads:" 744 for ( ThreadMap::Contents::const_iterator citr = contents.begin(); citr != contents.end();
747 tmp << ( *citr ).first <<
" - " << ( *citr ).second <<
"\n";
750 tmp <<
"Registered threads (ThreadMap): " << contents.size() <<
"\n";
767 --timeouts_remaining;
768 if ( timeouts_remaining == 0 )
771 timeouts_remaining = 5;
823 checkpoint(
"start combined scripts/tasks thread" );
836 std::vector<Realms::Realm*>::iterator itr;
839 std::ostringstream thname;
840 thname <<
"Decay_" << ( *itr )->name();
841 if ( ( *itr )->is_shadowrealm )
939 struct sockaddr client_addr;
940 socklen_t addrlen =
sizeof client_addr;
960 client->
csocket = client_socket;
961 memcpy( &client->
ipaddr, &client_addr,
sizeof client->
ipaddr );
963 client->
acct =
nullptr;
970 unsigned int ref_counted::_ctor_calls;
986 sw.
init(
"leftovers.txt" );
1016 std::string scriptname = pkg->dir() +
"start.ecl";
1028 typedef BOOL( WINAPI* DynHeapSetInformation )( PVOID HeapHandle,
1029 HEAP_INFORMATION_CLASS HeapInformationClass,
1030 PVOID HeapInformation,
1031 SIZE_T HeapInformationLength );
1033 const char* Use_low_fragmentation_Heap()
1037 HINSTANCE hKernel32;
1039 hKernel32 = LoadLibrary(
"Kernel32" );
1040 if ( hKernel32 !=
nullptr )
1042 DynHeapSetInformation ProcAdd;
1043 ProcAdd = (DynHeapSetInformation)GetProcAddress( hKernel32,
"HeapSetInformation" );
1044 if ( ProcAdd !=
nullptr )
1046 ULONG HeapFragValue = 2;
1048 if ( ( ProcAdd )( GetProcessHeap(), HeapCompatibilityInformation, &HeapFragValue,
1049 sizeof( HeapFragValue ) ) )
1051 FreeLibrary( hKernel32 );
1052 return "low-fragmentation Heap ...activated";
1056 FreeLibrary( hKernel32 );
1057 return "low-fragmentation Heap ...not activated";
1062 FreeLibrary( hKernel32 );
1063 return "low-fragmentation Heap ...not available on your Windows";
1067 return "low-fragmentation Heap ...not available on your Windows";
1070 return "low-fragmentation Heap ...disabled via ServSpecOpt";
1075 void Check_libc_version()
1077 const char* libc_version = gnu_get_libc_version();
1079 int main_version = 0;
1080 int sub_version = 0;
1084 if ( is >> main_version )
1087 if ( is >> delimiter >> sub_version )
1089 is >> delimiter >> build;
1093 POLLOG_ERROR <<
"Error in analyzing libc version string [" << libc_version
1094 <<
"]. Please contact Core-Team.\n";
1096 if ( main_version * 100000000 + sub_version * 10000 + build >= 2 * 100000000 + 3 * 10000 + 2 )
1097 POLLOG_INFO <<
"Found libc " << libc_version <<
" - ok\n";
1099 POLLOG_ERROR <<
"Found libc " << libc_version <<
" - Please update to 2.3.2 or above.\n";
1115 std::ofstream polpid;
1118 std::ios::out | std::ios::trunc );
1120 if ( polpid.is_open() )
1132 std::max( 2u, std::thread::hardware_concurrency() / 2 ),
"generic_task_thread" );
1144 << POL_COPYRIGHT <<
"\n\n";
1158 #ifdef PTHREAD_THREADS_MAX 1159 POLLOG_INFO <<
" Max Threads: " << PTHREAD_THREADS_MAX <<
"\n";
1165 << std::thread::hardware_concurrency() <<
" worldsave threads\n";
1196 Core::Check_libc_version();
1207 POLLOG_ERROR <<
"Unable to load Realms. Please make sure your Realms have been generated by " 1208 "UOConvert and your RealmDataPath is set correctly in Pol.cfg.\n";
1226 POLLOG_ERROR <<
"Unable to initialize sockets library.\n";
1297 <<
"+----------------------------------------------------------------------+\n" 1298 <<
"| Option ListenPort in pol.cfg is now only for non-multithreading |\n" 1299 <<
"| systems. If you still haven't done it, please read the documentation |\n" 1300 <<
"| on how to create a uoclients.cfg. |\n" 1301 <<
"+----------------------------------------------------------------------+\n" 1304 throw std::runtime_error(
1305 "ListenPort is no longer used for multithreading programs (Multithread == 1)." );
1319 POLLOG_INFO <<
"Initialization complete. POL is active. Ctrl-C to stop.\n\n";
1325 POLLOG.Format(
"{0:s} ({1:s}) compiled on {2:s} running.\n" )
1333 "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" 1334 "WARNING: Threading is disabled (Multithread==0 in pol.cfg). \n" 1335 " This setting is deprecated and will be removed from \n" 1336 " the next version of POL. It may not even work now! \n" 1337 " Only use this option if you really know what you are \n" 1338 " doing. And you probably don't. \n" 1339 "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" 1421 unsigned int dirty, clean;
1422 long long elapsed_ms;
1444 POLLOG_INFO <<
"Not writing data due to assertion failure.\n";
1446 POLLOG_INFO <<
"Not writing data due to pol.cfg InhibitSaves=1 setting.\n";
1458 catch ( std::exception& )
void install_signal_handlers()
void decay_thread_shadow(void *arg)
void pol_sleep_ms(unsigned int millis)
int assertion_shutdown_save_type
void display_unreaped_orphan_instances()
std::atomic< int > eobject_imp_count
unsigned short default_doubleclick_range
void allocate_intrinsic_weapon_serials()
void send_objects_newly_inrange(Network::Client *client)
void check_weather_region_change(bool force=false)
bool have_queued_data() const
virtual void walk_on(Mobile::Character *chr) POL_OVERRIDE
void run_reconnect_script(Mobile::Character *chr)
void login_complete(Client *c)
void check_incoming_data(void)
unsigned scripts_thread_checkpoint
void scripts_thread(void)
void quickconfig(const Plib::Package *pkg, const std::string &name_ecl)
const char * last_checkpoint
void MakeDirectory(const char *dir)
void apply_socket_options(SOCKET sck)
void textcmd_stoplog(Network::Client *client)
std::vector< Items::ItemDesc * > dynamic_item_descriptors
void char_select(Network::Client *client, PKTIN_5D *msg)
unsigned short max_clients
static void ready()
blocks till possible last commit finishes
std::string scripts_thread_script
volatile bool reload_configuration_signalled
bool walkheight(unsigned short x, unsigned short y, short oldz, short *newz, Multi::UMulti **pmulti, Items::Item **pwalkon, bool doors_block, Core::MOVEMODE movemode, short *gradual_boost=nullptr)
threadhelp::TaskThreadPool task_thread_pool
void SetCharacterWorldPosition(Mobile::Character *chr, Realms::WorldChangeReason reason)
std::atomic< int > pause_count
static void read_pol_config(bool initial_load)
bool EnableFlowControlPackets
std::string decint(unsigned short v)
unsigned short listen_port
polticks_t polticks_t_to_ms(polticks_t ticks)
static void check_console_commands(Clib::KeyboardHook *kb)
polclock_t calc_scheduler_clocksleft(polclock_t now)
std::unique_ptr< MessageTypeFilter > disconnected_filter
Mobile::Character * get_character(int index)
void start_aux_services()
unsigned char cmdlevel() const
void start_client_char(Network::Client *client)
void reload_configuration()
#define THREAD_CHECKPOINT(thread, check)
Core::WeatherRegion * weather_region
void debug_listen_thread(void)
void start_thread(void(*entry)(void *), const char *thread_name, void *arg)
std::atomic< size_t > script_passes_activity
unsigned short max_clients_bypass_cmdlevel
unsigned tasks_thread_checkpoint
void transmit(Client *client, const void *data, int len)
#define TRACEBUF_ADDELEM(tag, value)
void send_inrange_items(Network::Client *client)
void ClientTransmitThread()
void call_ondelete_scripts(Mobile::Character *chr)
void init_pool(unsigned int max_count, const std::string &name)
int init_sockets_library(void)
virtual void register_object(UObject *obj)
std::unique_ptr< SQLService > sql_service
bool has_active_characters()
Returns true if at least one character from this account is already logged in.
void display_leftover_objects()
virtual T * getregion(xcoord x, ycoord y, Realms::Realm *realm)
void CoreSetSysTrayToolTip(const std::string &text, Priority priority)
void start_uo_client_listeners(void)
void allocate_intrinsic_equipment_serials()
Deferred allocator for serials during startup, see comments in register_intrinsic_equipment() ...
bool process_data(Network::Client *client)
void handle_keep_alive(Network::Client *client, PKTBI_73 *msg)
void send_inrange_multis(Network::Client *client)
std::unique_ptr< Items::ItemDesc > empty_itemdesc
void on_loggon_party(Mobile::Character *chr)
Multi::UMulti * system_find_multi(u32 serial)
int xmain_outer(bool testing)
std::unique_ptr< Network::ClientTransmit > clientTransmit
bool call_script(const ScriptDef &script, Bscript::BObjectImp *param0)
virtual class UHouse * as_house()
void read_bannedips_config(bool initial_load)
void combined_thread(void)
void send_login_error(Network::Client *client, unsigned char reason)
void checkpoint(const char *msg, unsigned short minlvl)
Crypt::TCryptInfo client_encryption_version
void send_goxyz(Client *client, const Character *chr)
std::vector< Realms::Realm * > Realms
void stop_gameclock()
Stops the game clock and saves the current value into "gameclock".
NetworkManager networkManager
unsigned short height() const
void Send(Client *client, int len=-1) const
Core::MusicRegion * music_region
void CopyContents(Contents &out) const
polclock_t calc_script_clocksleft(polclock_t now)
unsigned short select_timeout_usecs
const char * name() const
void decay_single_thread(void *arg)
void handle_resync_request(Network::Client *client, PKTBI_22_SYNC *msg)
void display_bobjectimp_instances()
volatile bool report_status_signalled
void InitializeSystemTrayHandling()
typedef BOOL(WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess
const char * AddressToString(struct sockaddr *addr)
void send_highlight() const
int xmain_inner(bool testing)
void signal_catch_thread()
void textcmd_startlog(Network::Client *client)
void kill_disconnected_clients()
void send_realm_change(Client *client, Realms::Realm *realm)
std::atomic< clock_t > polclock_paused_at
SOCKET open_listen_socket(unsigned short port)
SettingsManager settingsManager
void disable_nagle(SOCKET sck)
static void InVisualRange(const UObject *obj, F &&f)
std::atomic< int > checkin_clock_times_out_at
struct timeval select_timeout
StateManager stateManager
unsigned check_attack_after_move_function_checkpoint
std::atomic< unsigned int > child_threads
unsigned int default_decay_time
UoClientProtocol uoclient_protocol
void step_scripts(polclock_t *clocksleft, bool *pactivity)
virtual void init(const std::string &filepath) POL_OVERRIDE
Core::JusticeRegion * justice_region
const Core::MessageTypeFilter * msgtype_filter
std::map< size_t, std::string > Contents
bool isReallyConnected() const
void position_changed(void)
int save_incremental(unsigned int &dirty, unsigned int &clean, long long &elapsed_ms)
void check_scheduled_tasks(polclock_t *clocksleft, bool *pactivity)
void ShutdownSystemTrayHandling()
ObjectStorageManager objStorageManager
unsigned short width() const
void run_logon_script(Mobile::Character *chr)
u32 UOExpansionFlagClient
static void logAllStackTraces()
Logs stack traces of all threads to stdout and error output.
bool run_script_to_completion(const char *filename, Bscript::BObjectImp *parameter)
void PrintContents(Clib::StreamWriter &sw) const
void send_startup(Network::Client *client)
void console_thread(void)
std::unique_ptr< MessageTypeFilter > game_filter
std::atomic< size_t > script_passes_noactivity
static void read_servspecopt()
bool passert_shutdown_due_to_assertion
void restart_all_clients()
void catch_signals_thread(void)
void load_intrinsic_weapons()
Creates the intrinsic wrestling weapon for PCs must be called at startup.
void send_client_char_data(Mobile::Character *chr, Network::Client *client)
bool can_delete_character(Mobile::Character *chr, int delete_by)
bool FileExists(const char *filename)
void thread_sleep_ms(unsigned millis)
int write_data(unsigned int &dirty_writes, unsigned int &clean_writes, long long &elapsed_ms)
bool gflag_in_system_startup
void send_season_info(Client *client)
bool clientHasCharacter(Client *c)
void tasks_thread_sleep(unsigned int millis)
virtual std::string name() const
void send_owncreate(Client *client, const Character *chr)
virtual void unregister_object(UObject *obj)
void call_chr_scripts(Mobile::Character *chr, const std::string &root_script_ecl, const std::string &pkg_script_ecl, bool offline=false)
static std::string build_target()
void send_map_difs(Client *client)
Sends number of maps used and number of map/static patches for each map.
const polclock_t POLCLOCKS_PER_SEC
#define LOGIN_ERROR_OTHER_CHAR_INUSE
void restart_pol_clocks()
Network::PolSocket polsocket
void threadstatus_thread(void)
std::atomic< bool > exit_signalled
void validate_intrinsic_shield_template()
Must be called at startup, validates the intrinsic shield element.
void wait_for_pulse(unsigned int millis)
void check_region_changes()
static std::string build_datetime()
void read_starting_locations()
void decay_thread(void *arg)
unsigned active_client_thread_checkpoint
unsigned scripts_thread_scriptPC
void Register(size_t pid, const std::string &name)
void display_executor_instances()
#define INC_PROFILEVAR(counter)