@@ -357,11 +357,15 @@ bool CP2MMServerPlugin::Load(CreateInterfaceFn interfaceFactory, const CreateInt
357357
358358 // Make sure -allowspectators is there so we get our 33 max players.
359359 if (!CommandLine ()->FindParm (" -allowspectators" ))
360+ {
361+ Log (INFO, true , R"( Missing "-allowspectators" launch parameter, adding!)" );
360362 CommandLine ()->AppendParm (" -allowspectators" , " " );
363+ }
361364
362365 // big ol' try catch because game has a TerminateProcess handler for exceptions...
363366 // why this wasn't here is mystifying, - 10/2024 NULLderef
364- try {
367+ try
368+ {
365369 // Byte patches
366370
367371 // "Steam not running." error fix for dedicated servers. This only works for dedicated servrs when the plugin file is named "ghostinj" and server is run with -usegh.
@@ -373,10 +377,12 @@ bool CP2MMServerPlugin::Load(CreateInterfaceFn interfaceFactory, const CreateInt
373377 Memory::ReplacePattern (" server" , " 0F B6 87 04 05 00 00 8B 16" , " EB 14 87 04 05 00 00 8B 16" );
374378
375379 // Partner disconnects.
380+ Log (INFO, true , " Patching partner disconnect event..." );
376381 Memory::ReplacePattern (" server" , " 51 50 FF D2 83 C4 10 E8" , " 51 50 90 90 83 C4 10 E8" );
377382 Memory::ReplacePattern (" server" , " 74 28 3B 75 FC" , " EB 28 3B 75 FC" );
378383
379384 // Max players -> 33
385+ Log (INFO, true , " Patching patching max players..." );
380386 Memory::ReplacePattern (" server" , " 83 C0 02 89 01" , " 83 C0 20 89 01" );
381387 Memory::ReplacePattern (" engine" , " 85 C0 78 13 8B 17" , " 31 C0 04 21 8B 17" );
382388 uintptr_t svPtr = *static_cast <uintptr_t *>(Memory::Scanner::Scan<void *>(ENGINEDLL, " 74 0A B9 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B E5" , 3 ));
@@ -386,41 +392,37 @@ bool CP2MMServerPlugin::Load(CreateInterfaceFn interfaceFactory, const CreateInt
386392 this ->sv = reinterpret_cast <CBaseServer*>(svPtr);
387393
388394 // Prevent disconnect by "STEAM validation rejected".
395+ Log (INFO, true , R"( Patching "STEAM validation rejected" disconnection...)" );
389396 Memory::ReplacePattern (" engine" , " 01 74 7D 8B" , " 01 EB 7D 8B" );
390397
391- // Fix sv_password.
398+ // Fix sv_password so passwords can be used on servers.
399+ Log (INFO, true , " Fixing sv_password..." );
392400 Memory::ReplacePattern (" engine" , " 0F 95 C1 51 8D 4D E8" , " 03 C9 90 51 8D 4D E8" );
393401
394- // runtime max 0.03 -> 0.05
402+ // Increase runtime max form 0.03 to 0.05.
403+ // Helps add some more leeway to some things we do in VScript without the engine complaining and shutting down the rest of the script.
404+ Log (INFO, true , " Patching max runtime for VScript..." );
395405 Memory::ReplacePattern (" vscript" , " 00 00 00 E0 51 B8 9E 3F" , " 9a 99 99 99 99 99 a9 3f" );
396406
397- // MinHook initialization and hooking
407+ // MinHook initialization and hooking.
398408 Log (INFO, true , " Initializing MinHook and hooking functions..." );
399409 MH_Initialize ();
400410
401411 // NoSteamLogon disconnect hook patch.
412+ Log (INFO, true , " Hooking CSteam3Server::OnGSClientDenyHelper..." );
402413 MH_CreateHook (
403414 (LPVOID)Memory::Scanner::Scan<void *>(ENGINEDLL, " 55 8B EC 83 EC 08 53 56 57 8B F1 E8 ?? ?? ?? ?? 8B" ),
404415 &CSteam3Server__OnGSClientDenyHelper_hook, reinterpret_cast <void **>(&CSteam3Server__OnGSClientDenyHelper_orig)
405416 );
406417
407- // Hook onto the function which defines what Atlas's and PBody's models are.
408- MH_CreateHook (
409- Memory::Rel32 (Memory::Scanner::Scan (SERVERDLL, " E8 ?? ?? ?? ?? 83 C4 40 50" , 1 )),
410- &GetBallBotModel_hook, reinterpret_cast <void **>(&GetBallBotModel_orig)
411- );
412- MH_CreateHook (
413- Memory::Rel32 (Memory::Scanner::Scan (SERVERDLL, " E8 ?? ?? ?? ?? 83 C4 04 50 8B 45 10 8B 10" , 1 )),
414- &GetEggBotModel_hook, reinterpret_cast <void **>(&GetEggBotModel_orig)
415- );
416-
417418 // For p2mm_instantrespawn.
418419 MH_CreateHook (
419420 Memory::Scanner::Scan (SERVERDLL, " 53 8B DC 83 EC 08 83 E4 F0 83 C4 04 55 8B 6B ?? 89 6C 24 ?? 8B EC A1 ?? ?? ?? ?? F3 0F 10 40 ?? F3 0F 58 05 ?? ?? ?? ?? 83 EC 28 56 57 6A 00 51 8B F1 F3 0F 11 04 24 E8 ?? ?? ?? ?? 6A 03" ),
420421 &CPortal_Player__PlayerDeathThink_hook, reinterpret_cast <void **>(&CPortal_Player__PlayerDeathThink_orig)
421422 );
422423
423424 // "respawn" function hook for getting a VScript "game event" call out of it.
425+ Log (INFO, true , " Hooking respawn function call..." );
424426 MH_CreateHook (
425427 Memory::Scanner::Scan (SERVERDLL, " 55 8B EC A1 ?? ?? ?? ?? 80 78 ?? ?? 75 ?? 80 78" ),
426428 &respawn_hook, reinterpret_cast <void **>(&respawn_orig)
@@ -436,15 +438,34 @@ bool CP2MMServerPlugin::Load(CreateInterfaceFn interfaceFactory, const CreateInt
436438 switch (g_P2MMServerPlugin.m_iCurGameIndex )
437439 {
438440 case PORTAL_STORIES_MEL:
441+ // Valve's compiler for P2 inlined the GetBallBotModel and GetEggBotModel functions here,
442+ // so this also needs to be forced to return a different string.
443+ Log (INFO, true , " Hooking CPortal_Player::GetPlayerModelName..." );
439444 MH_CreateHook (
440445 Memory::Scanner::Scan (SERVERDLL, " 55 8B EC 81 EC 10 01 00 00 53 8B 1D" ),
441446 &CPortal_Player__GetPlayerModelName_hook, reinterpret_cast <void **>(&CPortal_Player__GetPlayerModelName_orig)
442447 );
448+
449+ // Hook onto the function which defines what Atlas's and PBody's models are.
450+ Log (INFO, true , " Hooking GetBallBotModel..." );
451+ MH_CreateHook (
452+ Memory::Rel32 (Memory::Scanner::Scan (SERVERDLL, " E8 ?? ?? ?? ?? 83 C4 40 50" , 1 )),
453+ &GetBallBotModel_hook, reinterpret_cast <void **>(&GetBallBotModel_orig)
454+ );
455+ Log (INFO, true , " Hooking GetEggBotModel..." );
456+ MH_CreateHook (
457+ Memory::Rel32 (Memory::Scanner::Scan (SERVERDLL, " E8 ?? ?? ?? ?? 83 C4 04 50 8B 45 10 8B 10" , 1 )),
458+ &GetEggBotModel_hook, reinterpret_cast <void **>(&GetEggBotModel_orig)
459+ );
460+ break ;
443461 }
444-
462+
463+ Log (INFO, true , " Enabling hooks..." );
445464 MH_EnableHook (MH_ALL_HOOKS);
446- } catch (const std::exception& ex) {
447- Log (INFO, false , " Failed to load plugin! :( Exception: \" %s\" " , ex.what ());
465+ } catch (const std::exception& ex)
466+ {
467+ assert (0 && " Failed to implement patch or hook!" );
468+ Log (INFO, false , R"( Failed to load plugin! :( Exception: "%s")" , ex.what ());
448469 this ->m_bNoUnload = true ;
449470 return false ;
450471 }
@@ -465,7 +486,7 @@ void CP2MMServerPlugin::Unload(void)
465486 if (m_bNoUnload)
466487 {
467488 m_bNoUnload = false ;
468- MessageBox (this ->m_hWnd , " P2:MM ran into a error when starting! Please check the console for more info!" , " P2:MM Startup Error" , MB_OK | MB_ICONERROR);
489+ MessageBox (this ->m_hWnd , " P2:MM ran into a error when starting!\n Please check the console for more info!" , " P2:MM Startup Error" , MB_OK | MB_ICONERROR);
469490 return ;
470491 }
471492
@@ -480,16 +501,20 @@ void CP2MMServerPlugin::Unload(void)
480501 Log (INFO, true , " Unblocking console commands..." );
481502 for (const char * conCommand : forbiddenConCommands)
482503 {
483- ConCommandBase* commandBase = g_pCVar->FindCommandBase (conCommand);
484- if (commandBase)
504+ if (ConCommandBase* commandBase = g_pCVar->FindCommandBase (conCommand))
485505 commandBase->AddFlags (FCVAR_GAMEDLL);
486506 }
487507
488508 // Remove -allowspectators so max player count is indeed back to 2 and not 3.
489509 if (CommandLine ()->FindParm (" -allowspectators" ))
510+ {
511+ Log (INFO, true , R"( Removing "-allowspectators" launch parameter"...)" );
490512 CommandLine ()->RemoveParm (" -allowspectators" );
513+ }
491514
515+ Log (INFO, true , " Unregistering ConVars..." );
492516 ConVar_Unregister ();
517+
493518 Log (INFO, true , " Disconnecting tier libraries..." );
494519 DisconnectTier2Libraries ();
495520 DisconnectTier1Libraries ();
@@ -507,21 +532,26 @@ void CP2MMServerPlugin::Unload(void)
507532 Memory::ReplacePattern (" server" , " EB 14 87 04 05 00 00 8B 16" , " 0F B6 87 04 05 00 00 8B 16" );
508533
509534 // Partner disconnects
535+ Log (INFO, true , " Un-patching partner disconnect event..." );
510536 Memory::ReplacePattern (" server" , " 51 50 90 90 83 C4 10 E8" , " 51 50 FF D2 83 C4 10 E8" );
511537 Memory::ReplacePattern (" server" , " EB 28 3B 75 FC" , " 74 28 3B 75 FC" );
512538
513539 // Max players -> 2
540+ Log (INFO, true , " Un-patching max players..." );
514541 Memory::ReplacePattern (" server" , " 83 C0 20 89 01" , " 83 C0 02 89 01" );
515542 Memory::ReplacePattern (" engine" , " 31 C0 04 21 8B 17" , " 85 C0 78 13 8B 17" );
516543 *reinterpret_cast <int *>(reinterpret_cast <uintptr_t >(this ->sv ) + 0x228 ) = 2 ;
517544
518545 // Disconnect by "STEAM validation rejected"
546+ Log (INFO, true , R"( Un-patching "STEAM validation rejected" disconnection...)" );
519547 Memory::ReplacePattern (" engine" , " 01 EB 7D 8B" , " 01 74 7D 8B" );
520548
521549 // sv_password
550+ Log (INFO, true , " Unfixing sv_password..." );
522551 Memory::ReplacePattern (" engine" , " 03 C9 90 51 8D 4D E8" , " 0F 95 C1 51 8D 4D E8" );
523552
524553 // runtime max 0.05 -> 0.03
554+ Log (INFO, true , " Un-patching max runtime for VScript..." );
525555 Memory::ReplacePattern (" vscript" , " 00 00 00 00 00 00 E0 3F" , " 00 00 00 E0 51 B8 9E 3F" );
526556
527557 Log (INFO, true , " Disconnecting hooked functions and initializing MinHook..." );
@@ -530,7 +560,9 @@ void CP2MMServerPlugin::Unload(void)
530560 }
531561 catch (const std::exception& ex)
532562 {
533- Log (INFO, false , " Encountered error when unload plugin! Skipping other patches... :( Exception: \" %s\" " , ex.what ());
563+ assert (0 && " Failed to fully unload!" );
564+ Log (INFO, false , R"( Encountered error when unload plugin! :( Exception: "%s")" , ex.what ());
565+ Log (ERRORR, false , " P2:MM failed to unload!\n Game has to be shutdown as possibly some other patches/hooks are still connected which can cause issues!" );
534566 }
535567
536568 if (p2mm_discord_rpc.GetBool () && CDiscordIntegration::DiscordRPCRunning ())
0 commit comments