@@ -517,33 +517,33 @@ DETOUR_B(Server::AirMove) {
517517
518518 return Server::AirMove (thisptr);
519519}
520+
521+ Memory::Patch *g_aircontrolPatch;
522+
520523static void setAircontrol (int val) {
521- if (!server-> aircontrol_fling_speed_addr ) return ;
524+ if (!g_aircontrolPatch-> IsInit () ) return ;
522525 switch (val) {
523526 case 0 :
524- *server-> aircontrol_fling_speed_addr = 300 . 0f * 300 . 0f ;
527+ g_aircontrolPatch-> Restore () ;
525528 break ;
526529 default :
527- *server-> aircontrol_fling_speed_addr = INFINITY ;
530+ g_aircontrolPatch-> Execute () ;
528531 break ;
529532 }
530533}
534+
535+ Memory::Patch *g_portalsThruPortalsPatch;
536+
531537static void setPortalsThruPortals (bool val) {
532- uintptr_t tfp = (uintptr_t )server->TraceFirePortal ;
533- if (!server->TraceFirePortal ) return ;
534- #ifdef _WIN32
535- *(uint8_t *)(tfp + Offsets::portalsThruPortals) = val ? 0x00 : 0x0A ;
536- #else
537- if (sar.game ->Is (SourceGame_EIPRelPIC)) {
538- *(uint8_t *)(tfp + Offsets::portalsThruPortals) = val ? 0x82 : 0x85 ;
539- } else if (sar.game ->Is (SourceGame_PortalReloaded) || sar.game ->Is (SourceGame_PortalStoriesMel)) {
540- *(uint8_t *)(tfp + Offsets::portalsThruPortals) = val ? 0xEB : 0x74 ;
538+ if (!g_portalsThruPortalsPatch->IsInit ()) return ;
539+ if (val) {
540+ g_portalsThruPortalsPatch->Execute ();
541541 } else {
542- *( uint8_t *)(tfp + Offsets::portalsThruPortals) = val ? 0x85 : 0x84 ;
542+ g_portalsThruPortalsPatch-> Restore () ;
543543 }
544- #endif
545544}
546545Variable sar_portals_thru_portals (" sar_portals_thru_portals" , " 0" , " Allow firing portals through portals.\n " );
546+
547547// cvar callbacks dont want to fucking work so we'll just do this bs
548548ON_EVENT (PRE_TICK) {
549549 setAircontrol (server->AllowsMovementChanges () ? sar_aircontrol.GetInt () : 0 );
@@ -817,8 +817,9 @@ float hostTimeWrap() {
817817 return engine->GetHostTime ();
818818}
819819
820- static char g_orig_check_stuck_code[6 ];
821- static void *g_check_stuck_code;
820+ Memory::Patch *g_chatPatch;
821+ Memory::Patch *g_unblockChatPatch;
822+ Memory::Patch *g_checkStuckPatch;
822823
823824bool Server::Init () {
824825 this ->g_GameMovement = Interface::Create (this ->Name (), " GameMovement001" );
@@ -844,9 +845,13 @@ bool Server::Init() {
844845 Memory::Deref<_CheckJumpButton>(baseOffset + Offsets::CheckJumpButton * sizeof (uintptr_t *), &Server::CheckJumpButtonBase);
845846
846847 auto aircontrol_fling_speed_addr = Memory::Scan (this ->Name (), Offsets::aircontrol_fling_speedSig, Offsets::aircontrol_fling_speedOff);
848+ g_aircontrolPatch = new Memory::Patch ();
847849 if (aircontrol_fling_speed_addr) {
848- this ->aircontrol_fling_speed_addr = Memory::Deref<float *>(aircontrol_fling_speed_addr);
849- Memory::UnProtect (this ->aircontrol_fling_speed_addr , 4 );
850+ unsigned char bytes[4 ];
851+ float infinityValue = INFINITY;
852+ std::memcpy (bytes, &infinityValue, sizeof (bytes));
853+ g_aircontrolPatch->Execute (Memory::Deref<uintptr_t >(aircontrol_fling_speed_addr), bytes, 4 );
854+ g_aircontrolPatch->Restore ();
850855 }
851856 }
852857
@@ -889,40 +894,47 @@ bool Server::Init() {
889894
890895 // Remove the limit on how quickly you can use 'say', and also hook it
891896 Command::Hook (" say" , Server::say_callback_hook, Server::say_callback);
897+ g_chatPatch = new Memory::Patch ();
892898 if (say_callback) {
893899 auto insn_addr = (uintptr_t )say_callback + Offsets::say_callback_insn;
894900 // This is the location of an ADDSD instruction which adds 0.66
895901 // to the current time. If we instead *subtract* 0.66, we'll
896902 // always be able to chat again! We can just do this by changing
897903 // the third byte from 0x58 to 0x5C, hence making the full
898904 // opcode start with F2 0F 5C.
899- Memory::UnProtect ((void *)(insn_addr + 2 ), 1 );
900905 if (*(char *)(insn_addr + 2 ) == 0x58 ) {
901- *(char *)(insn_addr + 2 ) = 0x5C ;
906+ unsigned char patchByte = 0x5C ;
907+ g_chatPatch->Execute ((uintptr_t )(insn_addr + 2 ), &patchByte, 1 );
902908 } else {
903- console->DevMsg (" Failed to uncap chat time. insn was %02X\n " , *(char *)(insn_addr + 2 ));
909+ console->Warning (" Failed to uncap chat time. insn was %02X\n " , *(char *)(insn_addr + 2 ));
904910 }
905911 }
906912 auto Host_Say = Memory::Scan (this ->Name (), Offsets::Host_Say);
913+ g_unblockChatPatch = new Memory::Patch ();
907914 if (Host_Say) {
908915 auto insn_addr = Host_Say + Offsets::Host_Say_insn;
909916 // FIXME: This also disables the "ignoremsg" client command
910917 // functionality.
911918 // This is the location of a JZ instruction which jumps if the
912919 // chat sender is dead but recipient is alive, blocking
913920 // messages. We just change it to a JO, which will never jump.
914- Memory::UnProtect ((void *)insn_addr, 1 );
915921 if (*(char *)insn_addr == 0x74 ) {
916- *(char *)insn_addr = 0x70 ;
922+ unsigned char patchByte = 0x70 ;
923+ g_unblockChatPatch->Execute ((uintptr_t )insn_addr, &patchByte, 1 );
917924 } else {
918- console->DevMsg (" Failed to unblock chat when dead . insn was %02X\n " , *(char *)insn_addr);
925+ console->Warning (" Failed to unblock chat. insn was %02X\n " , *(char *)insn_addr);
919926 }
920927 }
921928
922929 // find the TraceFirePortal function
923930 TraceFirePortal = (_TraceFirePortal)Memory::Scan (this ->Name (), Offsets::TraceFirePortal);
931+ g_portalsThruPortalsPatch = new Memory::Patch ();
932+ if (TraceFirePortal && Offsets::portalsThruPortals) {
933+ unsigned char portalsThruPortalsValOn = Offsets::portalsThruPortalsValOn;
934+ g_portalsThruPortalsPatch->Execute ((uintptr_t )TraceFirePortal + Offsets::portalsThruPortals, &portalsThruPortalsValOn, 1 );
935+ g_portalsThruPortalsPatch->Restore ();
936+ }
924937 FindPortal = (_FindPortal)Memory::Scan (this ->Name (), Offsets::FindPortal);
925- if (TraceFirePortal) Memory::UnProtect ((void *)((uintptr_t )TraceFirePortal + Offsets::portalsThruPortals), 1 ); // see setPortalsThruPortals
926938
927939 ViewPunch = (decltype (ViewPunch))Memory::Scan (this ->Name (), Offsets::ViewPunch);
928940
@@ -939,17 +951,19 @@ bool Server::Init() {
939951
940952 // a call to Plat_FloatTime in CGameMovement::CheckStuck
941953 auto code = Memory::Scan (this ->Name (), Offsets::CheckStuck_FloatTime);
954+ g_checkStuckPatch = new Memory::Patch ();
942955 if (code) {
943- Memory::UnProtect ((void *)code, sizeof g_orig_check_stuck_code);
944- memcpy (g_orig_check_stuck_code, (void *)code, sizeof g_orig_check_stuck_code);
945-
946- *(uint8_t *)code = 0xE8 ;
947- *(uint32_t *)(code + 1 ) = (uint32_t )&hostTimeWrap - (code + 5 );
948956#ifdef _WIN32
949- *(uint8_t *)(code + 5 ) = 0x90 ; // nop
957+ unsigned char checkStuckBytes[6 ];
958+ #else
959+ unsigned char checkStuckBytes[5 ];
950960#endif
951-
952- g_check_stuck_code = (void *)code;
961+ checkStuckBytes[0 ] = 0xE8 ; // call
962+ *(uint32_t *)(checkStuckBytes + 1 ) = (uint32_t )&hostTimeWrap - (code + 5 );
963+ #ifdef _WIN32
964+ checkStuckBytes[5 ] = 0x90 ; // nop
965+ #endif
966+ g_checkStuckPatch->Execute ((uintptr_t )code, checkStuckBytes, sizeof checkStuckBytes);
953967 }
954968
955969 if (sar.game ->Is (SourceGame_Portal2 | SourceGame_Portal2_2011)) {
@@ -1028,9 +1042,18 @@ DETOUR_COMMAND(Server::say) {
10281042}
10291043void Server::Shutdown () {
10301044 Command::Unhook (" say" , Server::say_callback);
1031- setAircontrol (0 );
1032- setPortalsThruPortals (false );
1033- if (g_check_stuck_code) memcpy (g_check_stuck_code, g_orig_check_stuck_code, sizeof g_orig_check_stuck_code);
1045+
1046+ g_aircontrolPatch->Restore ();
1047+ SAFE_DELETE (g_aircontrolPatch);
1048+ g_portalsThruPortalsPatch->Restore ();
1049+ SAFE_DELETE (g_portalsThruPortalsPatch);
1050+ g_chatPatch->Restore ();
1051+ SAFE_DELETE (g_chatPatch);
1052+ g_unblockChatPatch->Restore ();
1053+ SAFE_DELETE (g_unblockChatPatch);
1054+ g_checkStuckPatch->Restore ();
1055+ SAFE_DELETE (g_checkStuckPatch);
1056+
10341057 Interface::Delete (this ->gEntList );
10351058 Interface::Delete (this ->g_GameMovement );
10361059 Interface::Delete (this ->g_ServerGameDLL );
0 commit comments