├── .gitignore ├── button_states.md ├── cs2_cvar_renamer.idc ├── cs2_movement_reverse_engineering.cpp ├── cs2_vtable_dump.idc ├── make_source2sdk_headers_importable_in_ida.py └── scripts └── vscripts ├── kz.lua └── raytracing.lua /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ -------------------------------------------------------------------------------- /button_states.md: -------------------------------------------------------------------------------- 1 | 8 possible button states instead of 2, defined by IN_BUTTON_STATE_COUNT 2 | 3 | => Require 3 bits to represent all possible states 4 | 5 | | | buttonstate1 | buttonstate2 | buttonstate3 | Note | 6 | |:--------------------------|:------------:|:------------:|:------------:|:----------------------------------------------------------------------| 7 | | IN_BUTTON_UP | 0 | 0 | 0 | Default state | 8 | | IN_BUTTON_DOWN | 1 | 0 | 0 | State for holding a key | 9 | | IN_BUTTON_DOWN_UP | 0 | 1 | 0 | Release a key being held last tick | 10 | | IN_BUTTON_UP_DOWN | 1 | 1 | 0 | Key is newly pressed this tick. State sent by normal keypress. | 11 | | IN_BUTTON_UP_DOWN_UP | 0 | 0 | 1 | Press and release within the same tick. State sent by scroll inputs. | 12 | | IN_BUTTON_DOWN_UP_DOWN | 1 | 0 | 1 | Previously held then release and repress within the same tick | 13 | | IN_BUTTON_DOWN_UP_DOWN_UP | 0 | 1 | 1 | Previously held, release, repress and re-release within the same tick | 14 | | IN_BUTTON_UP_DOWN_UP_DOWN | 1 | 1 | 1 | Press, release, then repress within the same tick. | 15 | 16 | - Ladderhopping only checks for buttonstate1 value, so scrolling will not work if player wants be boosted off the ladder. 17 | - Scroll inputs going through subtick pipeline (IN_BUTTON_UP_DOWN_UP) will not register, as the engine will consider the player as if they never pressed the key in the first place. 18 | - Scroll input subtick moves look like this (IN_JUMP = 2): 19 | ``` 20 | CSGOUserCmdPB 21 | { 22 | base { 23 | command_number: 63188 24 | tick_count: 63346 25 | buttons_pb { 26 | buttonstate1: 0 27 | buttonstate2: 0 28 | buttonstate3: 2 29 | } 30 | viewangles { 31 | x: 19.0926456 32 | y: 100.950325 33 | z: 0 34 | } 35 | forwardmove: 0 36 | leftmove: 0 37 | upmove: 0 38 | random_seed: 1990122587 39 | mousedx: 0 40 | mousedy: 0 41 | pawn_entity_handle: 14582260 42 | subtick_moves { 43 | button: 2 44 | pressed: true 45 | when: 0 46 | } 47 | subtick_moves { 48 | button: 2 49 | pressed: false 50 | when: 0 51 | } 52 | move_crc: "\032\006\010\000\020\000\030\002\"\017\r\275\275\230A\025\221\346\311B\035\000\000\000\000" 53 | fixangle_tick: 9709 54 | } 55 | ``` -------------------------------------------------------------------------------- /cs2_cvar_renamer.idc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // rename cvars and commands to their appropriate names automatically. 4 | 5 | // converted from a python script to idc for us plebs. 6 | // stolen from a game hacking website 7 | 8 | // cvar signature 9 | // 48 8D ? ? ? ? ? 48 8D ? ? ? ? ? E8 ? ? ? ? 48 8D ? ? ? ? ? 48 81 C4 88 00 00 00 E9 ? ? ? ? 10 | // command signature 11 | // 48 8D ? ? ? ? ? 66 0F 7F 44 24 40 48 8D ? ? ? ? ? 0F 11 4C 24 30 E8 ? ? ? ? 48 8D ? ? ? ? ? 12 | static main() 13 | { 14 | auto current = get_imagebase() + 1024; 15 | auto max = 0; 16 | 17 | auto pattern = "48 8D ? ? ? ? ? 48 8D ? ? ? ? ? E8 ? ? ? ? 48 8D ? ? ? ? ? E8 ? ? ? ? 48 8D ? ? ? ? ? E8 ? ? ? ?"; 18 | 19 | auto uniqueCount = 0; 20 | // this attempts to rename cvars made by RegisterCvar. 21 | // the pattern is a bit too broad and found a "cvar" named %s::%s in server.dll 22 | /* 23 | while (1) 24 | { 25 | // search for convar creation byte sequence 26 | current = find_binary(current, SEARCH_DOWN | SEARCH_NEXT, pattern); 27 | if (current == BADADDR) 28 | { 29 | break; 30 | } 31 | 32 | // should be at .text:000000018065B60C 48 8D 15 AD 59 8D 00 lea rdx, aHostTimescale ; "host_timescale" 33 | auto cvarNameAddress = GetOperandValue(current, 1); 34 | auto cvarName = GetString(cvarNameAddress, -1, ASCSTR_C); 35 | if (strlen(cvarName) == 0) 36 | { 37 | continue; 38 | } 39 | print(cvarName); 40 | 41 | // now go down to an LEA (48 8D) instruction to get to the actual convar operand 42 | auto last = current; 43 | current = current + 7; 44 | auto cvarAddress = GetOperandValue(current, 1); 45 | auto lastName = get_name(cvarAddress, GN_DEMANGLED); 46 | if (get_name_ea_simple(cvarName) == BADADDR || strstr(cvarName, lastName, 0) != -1) 47 | { 48 | set_name(cvarAddress, cvarName); 49 | } 50 | else 51 | { 52 | set_name(cvarAddress, sprintf("%s__%d", cvarName, uniqueCount)); 53 | uniqueCount = uniqueCount + 1; 54 | msg("Duplicate cvar %s\n", cvarName); 55 | } 56 | 57 | current = current + 1; 58 | // return current; 59 | // break; 60 | } 61 | current = get_imagebase() + 1024; 62 | */ 63 | // cvars 64 | while (1) 65 | { 66 | current = SetNextCvarName(current, "48 8D ? ? ? ? ? 48 8D ? ? ? ? ? E8 ? ? ? ? 48 8D ? ? ? ? ? 48 81 C4 88 00 00 00 E9 ? ? ? ?"); 67 | if (current == 0) 68 | { 69 | break; 70 | } 71 | current = current + 1; 72 | } 73 | // commands 74 | current = get_imagebase() + 1024; 75 | while (1) 76 | { 77 | current = SetNextCvarName(current, "48 8D ? ? ? ? ? 66 0F 7F 44 24 40 48 8D ? ? ? ? ? 0F 11 4C 24 30 E8 ? ? ? ? 48 8D ? ? ? ? ? 48 83 C4 58"); 78 | if (current == 0) 79 | { 80 | break; 81 | } 82 | current = current + 1; 83 | } 84 | } 85 | 86 | static SetNextCvarName(base, pattern) 87 | { 88 | // search for convar creation byte sequence 89 | auto current = find_binary(base, SEARCH_DOWN | SEARCH_NEXT, pattern); 90 | if (current == BADADDR) 91 | { 92 | return 0; 93 | } 94 | 95 | // should be at .text:00000001800A587A 48 8D 15 E7 AC E8 00 lea rdx, aSvAutobunnyhop ; "sv_autobunnyhopping" 96 | auto cvarNameAddress = GetOperandValue(current, 1); 97 | auto cvarName = GetString(cvarNameAddress, -1, ASCSTR_C); 98 | if (strlen(cvarName) == 0) 99 | { 100 | msg("Encountered empty cvar name at %x", cvarNameAddress); 101 | return 0; 102 | } 103 | // print(cvarName); 104 | 105 | // now search down for an LEA (48 8D) instruction to get to the actual convar operand 106 | auto last = current; 107 | current = FindBinary(current, SEARCH_DOWN, "48 8D 0D ? ? ? ?"); 108 | if (current - last > 20) 109 | { 110 | msg("Couldn't find operand for cvar \"%s\".", cvarName); 111 | return 0; 112 | } 113 | set_name(GetOperandValue(current, 1), cvarName); 114 | return current; 115 | } 116 | -------------------------------------------------------------------------------- /cs2_vtable_dump.idc: -------------------------------------------------------------------------------- 1 | 2 | // ***************************************************************************** 3 | // - IDA Pro script - 4 | // Name: ida_vtables.idc 5 | // Desc: Recreates the methods of a class from a vtable 6 | // 7 | // Ver: 1.0b - July 20, 2006 - By Sirmabus 8 | // Ver: 2.0 - July 7, 2006 by BAILOPAN 9 | // �������������������������������������������������������������������������-��- 10 | // 11 | // ----------------------------------------------------------------------------- 12 | 13 | #include 14 | 15 | static main() 16 | { 17 | auto pAddress, iIndex; 18 | auto szFilePath, hFile; 19 | auto skipAmt; 20 | 21 | SetStatus(IDA_STATUS_WORK); 22 | 23 | // User selected vtable block 24 | pAddress = ScreenEA(); 25 | 26 | if (pAddress == BADADDR) 27 | { 28 | Message("** No vtable selected! Aborted **"); 29 | Warning("No vtable selected!\nSelect vtable block first."); 30 | SetStatus(IDA_STATUS_READY); 31 | return; 32 | } 33 | 34 | skipAmt = AskLong(0, "Number of vtable entries to ignore for indexing:"); 35 | auto dumpasVirtualFuncs = AskYN(0, "Format as C++ virtual method definitions."); 36 | 37 | // Request output header file 38 | SetStatus(IDA_STATUS_WAITING); 39 | if ((szFilePath = AskFile(1, "*.txt", "Select output dump file:")) == 0) 40 | { 41 | Message("Aborted."); 42 | SetStatus(IDA_STATUS_READY); 43 | return; 44 | } 45 | 46 | // And create it.. 47 | if ((hFile = fopen(szFilePath, "wb")) != 0) 48 | { 49 | auto szFuncName, szFullName, BadHits; 50 | 51 | BadHits = 0; 52 | 53 | // Create the header 54 | fprintf(hFile, "// Auto reconstructed from vtable block @ 0x%08X\n// from \"%s\", by ida_vtables.idc\n", pAddress, GetInputFile()); 55 | 56 | /* For linux, skip the first entry */ 57 | if (Qword(pAddress) == 0) 58 | { 59 | pAddress = pAddress + 16; 60 | } 61 | 62 | pAddress = pAddress + (skipAmt * 8); 63 | 64 | // Loop through the vtable block 65 | while (pAddress != BADADDR) 66 | { 67 | auto real_addr; 68 | real_addr = Qword(pAddress); 69 | szFuncName = GetFunctionName(real_addr); 70 | Message("%x\n", real_addr); 71 | if (szFuncName == 0 || strlen(szFuncName) == 0) 72 | { 73 | break; 74 | } 75 | szFullName = Demangle(szFuncName, INF_LONG_DN); 76 | if (szFullName == "") 77 | { 78 | szFullName = szFuncName; 79 | } 80 | if (strstr(szFullName, "_ZN") != -1) 81 | { 82 | fclose(hFile); 83 | Warning("You must toggle GCC v3.x demangled names!\n"); 84 | break; 85 | } 86 | if (!dumpasVirtualFuncs) 87 | { 88 | fprintf(hFile, "%d\t%s\n", iIndex, szFullName); 89 | } 90 | else 91 | { 92 | if (strstr(szFullName, "sub_") != -1) 93 | { 94 | fprintf(hFile, "virtual void Unk_%d(); // %d %s\n", iIndex, iIndex, szFullName); 95 | } 96 | else 97 | { 98 | fprintf(hFile, "virtual void %s(); // %d\n", szFullName, iIndex); 99 | } 100 | } 101 | 102 | pAddress = pAddress + 8; 103 | iIndex++; 104 | }; 105 | 106 | fclose(hFile); 107 | Message("Successfully wrote %d vtable entries.\n", iIndex); 108 | } 109 | else 110 | { 111 | Message("** Error opening \"%s\"! Aborted **\n", szFilePath); 112 | Warning("Error creating \"%s\"!\n", szFilePath); 113 | } 114 | 115 | Message("\nDone.\n\n"); 116 | SetStatus(IDA_STATUS_READY); 117 | } 118 | -------------------------------------------------------------------------------- /make_source2sdk_headers_importable_in_ida.py: -------------------------------------------------------------------------------- 1 | 2 | import glob 3 | import os 4 | 5 | # put this script in sdk/include 6 | # put source2gen.hpp in sdk/include/source2sdk 7 | # run this script at your own risk 8 | # in ida: File > Load File > Parse C Header File and select source2sdk_supermegaheader.h 9 | # as of time of writing 16 classes fail to load due to missing types. 10 | 11 | with open("source2sdk_supermegaheader.h", 'w') as list_file: 12 | list_file.write("#include \n") 13 | list_file.write("\n") 14 | for root, subdirs, files in os.walk("."): 15 | for filename in files: 16 | file_path = os.path.join(root, filename) 17 | if file_path.endswith(".hpp"): 18 | # delete all static_asserts from file 19 | lines = [] 20 | with open(file_path, "r+") as header: 21 | lines = header.readlines() 22 | header.truncate(0) 23 | header.seek(0) 24 | for line in lines: 25 | if "static_assert(" not in line: 26 | header.write(line) 27 | 28 | file_path = file_path.replace("\\", "/").replace("./", "") 29 | print(file_path) 30 | 31 | list_file.write("#include \"" + file_path + "\"\n") 32 | -------------------------------------------------------------------------------- /scripts/vscripts/kz.lua: -------------------------------------------------------------------------------- 1 | 2 | -- 0 = kztimer, 1 = vnl 3 | local mode = 0 4 | local cpSound = "sounds/buttons/blip1.vsnd" 5 | local g_worldent = nil 6 | 7 | if Kreedz == nil then 8 | Kreedz = class({}) 9 | end 10 | 11 | function CvarsKztimer() 12 | mode = 0 13 | SendToServerConsole("sv_accelerate 6.5") 14 | SendToServerConsole("sv_accelerate_use_weapon_speed 0") 15 | SendToServerConsole("sv_airaccelerate 100.0") 16 | SendToServerConsole("sv_air_max_wishspeed 30.0") 17 | SendToServerConsole("sv_enablebunnyhopping 1") 18 | SendToServerConsole("sv_friction 5.0") 19 | SendToServerConsole("sv_gravity 800.0") 20 | SendToServerConsole("sv_jump_impulse 301.993377") 21 | SendToServerConsole("sv_ladder_scale_speed 1.0") 22 | SendToServerConsole("sv_ledge_mantle_helper 0.0") 23 | SendToServerConsole("sv_maxspeed 320.0") 24 | SendToServerConsole("sv_maxvelocity 2000.0") 25 | SendToServerConsole("sv_staminajumpcost 0.0") 26 | SendToServerConsole("sv_staminalandcost 0.0") 27 | SendToServerConsole("sv_staminamax 0.0") 28 | SendToServerConsole("sv_staminarecoveryrate 0.0") 29 | SendToServerConsole("sv_standable_normal 0.7") 30 | SendToServerConsole("sv_timebetweenducks 0.0") 31 | SendToServerConsole("sv_walkable_normal 0.7") 32 | SendToServerConsole("sv_wateraccelerate 10.0") 33 | SendToServerConsole("sv_water_movespeed_multiplier 0.8") 34 | SendToServerConsole("sv_water_swim_mode 0.0") 35 | SendToServerConsole("sv_weapon_encumbrance_per_item 0.0") 36 | SendToServerConsole("sv_weapon_encumbrance_scale 0.0") 37 | end 38 | 39 | function CvarsVanilla() 40 | mode = 1 41 | SendToServerConsole("sv_accelerate 5.5") 42 | SendToServerConsole("sv_accelerate_use_weapon_speed 1") 43 | SendToServerConsole("sv_airaccelerate 12.0") 44 | SendToServerConsole("sv_air_max_wishspeed 30.0") 45 | SendToServerConsole("sv_enablebunnyhopping 1") 46 | SendToServerConsole("sv_friction 5.2") 47 | SendToServerConsole("sv_gravity 800.0") 48 | SendToServerConsole("sv_jump_impulse 301.993377") 49 | SendToServerConsole("sv_ladder_scale_speed 0.78") 50 | SendToServerConsole("sv_ledge_mantle_helper 0.0") 51 | SendToServerConsole("sv_maxspeed 320.0") 52 | SendToServerConsole("sv_maxvelocity 3500.0") 53 | SendToServerConsole("sv_staminajumpcost 0.08") 54 | SendToServerConsole("sv_staminalandcost 0.05") 55 | SendToServerConsole("sv_staminamax 80.0") 56 | SendToServerConsole("sv_staminarecoveryrate 60.0") 57 | SendToServerConsole("sv_standable_normal 0.7") 58 | SendToServerConsole("sv_timebetweenducks 0.4") 59 | SendToServerConsole("sv_walkable_normal 0.7") 60 | SendToServerConsole("sv_wateraccelerate 10.0") 61 | SendToServerConsole("sv_water_movespeed_multiplier 0.8") 62 | SendToServerConsole("sv_water_swim_mode 0.0") 63 | SendToServerConsole("sv_weapon_encumbrance_per_item 0.85") 64 | SendToServerConsole("sv_weapon_encumbrance_scale 0.0") 65 | end 66 | 67 | function locals() 68 | local i = 1 69 | repeat 70 | local k, v = debug.getlocal(1, i) 71 | if k then 72 | print(k, v) 73 | i = i + 1 74 | end 75 | until nil == k 76 | end 77 | 78 | function PlayCpSound(player) 79 | -- HACK, can't get EmitSoundOnClient to work :( 80 | SendToConsole("play " .. cpSound) 81 | end 82 | 83 | Convars:RegisterCommand("kz_cp", function() 84 | local player = Convars:GetCommandClient() 85 | if player.onGround then 86 | player.cpSaved = true 87 | player.cpOrigin = player:GetAbsOrigin() 88 | player.cpAngles = player:EyeAngles() 89 | PlayCpSound(player) 90 | end 91 | 92 | end, nil, 0) 93 | 94 | Convars:RegisterCommand("kz_tp", function() 95 | local player = Convars:GetCommandClient() 96 | if player.cpSaved then 97 | player:SetAbsOrigin(player.cpOrigin) 98 | player:SetAngles(player.cpAngles.x, player.cpAngles.y, player.cpAngles.z) 99 | player:SetVelocity(Vector(0, 0, 0)) 100 | PlayCpSound(player) 101 | print(player) 102 | end 103 | end, nil, 0) 104 | 105 | Convars:RegisterCommand("kz_kztimer", function() 106 | CvarsKztimer() 107 | end, nil, 0) 108 | 109 | Convars:RegisterCommand("kz_vanilla", function() 110 | CvarsVanilla() 111 | end, nil, 0) 112 | 113 | Convars:RegisterCommand("kz_testcommand", function() 114 | local player = Convars:GetCommandClient() 115 | ScriptPrintMessageChatAll(tostring(player:GetAbsOrigin())) 116 | -- print(player:QueryFloat("m_flFriction", 420.69)) 117 | end, nil, 0) 118 | 119 | function UserIdPawnToPlayerPawn(useridPawn) 120 | return EntIndexToHScript(bit.band(useridPawn, 16383)) 121 | end 122 | 123 | ListenToGameEvent("player_jump", function (event) 124 | local player = UserIdPawnToPlayerPawn(event.userid_pawn) 125 | 126 | player.userid = event.userid 127 | -- NOTE: 2 jump events get fired on the same tick for some reason... 128 | if player.lastJumpEventFrame ~= GetFrameCount() then 129 | player.jumped = true 130 | player.jumpOrigin = player:GetAbsOrigin() 131 | ScriptPrintMessageChatAll("FOG: " .. tostring(player.lastFramesOnGround)) 132 | player.lastJumpEventFrame = GetFrameCount() 133 | end 134 | end, nil) 135 | 136 | function InitialiseVars(player) 137 | player.varsInitialised = true 138 | player.framesOnGround = 0 139 | player.onGround = false 140 | player.lastOnGround = false 141 | player.lastOrigin = player:GetAbsOrigin() 142 | player.lastVelocity = player:GetVelocity() 143 | player.jumpOrigin = Vector(0, 0, 0) 144 | player.jumpVelocity = Vector(0, 0, 0) 145 | player.jumped = false 146 | player.lastFramesOnGround = 0 147 | end 148 | 149 | function PlayerTick(player) 150 | local velocity = player:GetVelocity() 151 | local speed = velocity:Length2D() 152 | ScriptPrintMessageCenterAll(string.format("%.3f", speed)) 153 | -- DebugScreenTextPretty(900, 900, 0, "Test!", 255, 255, 255, 255, 5, "Tahoma", 48, false) 154 | --[[ 155 | local startVector = player:GetAbsOrigin() 156 | local traceTable = 157 | { 158 | startpos = startVector; 159 | endpos = startVector - Vector(0, 0, 2); 160 | ignore = player; 161 | mask = 33636363; -- TRACE_MASK_PLAYER_SOLID from L4D2 script API, may not be correct for Source 2. 162 | min = player:GetBoundingMins(); 163 | max = player:GetBoundingMaxs() 164 | } 165 | 166 | TraceHull(traceTable) 167 | --]] 168 | 169 | if player.varsInitialised == nil then 170 | InitialiseVars(player) 171 | end 172 | 173 | if player.lastJumpEventFrame == GetFrameCount() - 2 then 174 | local speed = velocity:Length2D() 175 | -- TODO: kinda broken 176 | if mode == 0 then 177 | if speed > 380.0 then 178 | local mult = 380.0 / speed 179 | velocity.x = velocity.x * mult 180 | velocity.y = velocity.y * mult 181 | player:SetVelocity(velocity) 182 | end 183 | end 184 | player.jumpVelocity = velocity 185 | end 186 | 187 | player.onGround = player:GetGraphParameter("Is On Ground") 188 | if player.onGround then 189 | player.framesOnGround = player.framesOnGround + 1 190 | else 191 | player.framesOnGround = 0 192 | end 193 | 194 | if player.framesOnGround == 1 then 195 | if player.jumped then 196 | local jumpVec = player.jumpOrigin - player:GetOrigin() 197 | local distance = jumpVec:Length2D() 198 | local pre = math.sqrt(player.jumpVelocity.x * player.jumpVelocity.x + player.jumpVelocity.y * player.jumpVelocity.y) 199 | ScriptPrintMessageChatAll("[GC] LJ: " .. tostring(distance + 32.0) .. " [Pre: " .. tostring(pre) .. "]") 200 | player.jumped = false 201 | end 202 | end 203 | 204 | if player.framesOnGround == 2 then 205 | -- only for taming movement unlocker 206 | if speed > 250.0 then 207 | local mult = 250.0 / speed 208 | velocity.x = velocity.x * mult 209 | velocity.y = velocity.y * mult 210 | player:SetVelocity(velocity) 211 | end 212 | end 213 | 214 | player:SetGraphParameterFloat("flLandWeight", 1.0) 215 | player:SetGraphParameterFloat("stand", 1.0) 216 | 217 | player.lastOnGround = player.onGround 218 | player.lastOrigin = player:GetAbsOrigin() 219 | player.lastVelocity = player:GetVelocity() 220 | player.lastFramesOnGround = player.framesOnGround 221 | end 222 | 223 | function Tick() 224 | local players = Entities:FindAllByClassname("player") 225 | for i, player in ipairs(players) 226 | do 227 | PlayerTick(players[i]) 228 | end 229 | return FrameTime() 230 | end 231 | 232 | function UpdateOnRemove() 233 | StopListeningToAllGameEvents(Kreedz) 234 | end 235 | 236 | function Activate() 237 | SendToServerConsole("mp_ct_default_secondary weapon_usp_silencer") 238 | SendToServerConsole("mp_t_default_secondary weapon_usp_silencer") 239 | 240 | SendToServerConsole("sv_holiday_mode 0") 241 | SendToServerConsole("sv_party_mode 0") 242 | 243 | SendToServerConsole("sv_clamp_unsafe_velocities 0") 244 | SendToServerConsole("mp_respawn_on_death_ct 1") 245 | SendToServerConsole("mp_respawn_on_death_t 1") 246 | SendToServerConsole("mp_respawn_immunitytime -1") 247 | SendToServerConsole("sv_spec_post_death_additional_time 1") 248 | 249 | -- Hide money 250 | SendToServerConsole("mp_playercashawards 0") 251 | SendToServerConsole("mp_teamcashawards 0") 252 | 253 | -- Stop dropping guns 254 | SendToServerConsole("mp_death_drop_c4 0") 255 | SendToServerConsole("mp_death_drop_defuser 0") 256 | SendToServerConsole("mp_death_drop_grenade 0") 257 | SendToServerConsole("mp_death_drop_gun 1") 258 | SendToServerConsole("mp_drop_knife_enable 1") 259 | SendToServerConsole("mp_weapons_allow_map_placed 1") 260 | SendToServerConsole("mp_disconnect_kills_players 0") 261 | 262 | -- No limits on joining teams 263 | SendToServerConsole("mp_autoteambalance 0") 264 | SendToServerConsole("mp_limitteams 0") 265 | SendToServerConsole("mp_spectators_max 64") 266 | 267 | -- Performance 268 | SendToServerConsole("sv_occlude_players 0") 269 | 270 | -- General 271 | SendToServerConsole("sv_pure 0") 272 | -- SendToServerConsole("bot_quota 0") 273 | SendToServerConsole("sv_allow_votes 0") 274 | SendToServerConsole("sv_infinite_ammo 2") 275 | SendToServerConsole("mp_free_armor 2") 276 | SendToServerConsole("mp_buytime 0") 277 | SendToServerConsole("mp_freezetime 0") 278 | SendToServerConsole("mp_team_intro_time 0") 279 | SendToServerConsole("mp_do_warmup_period 0") 280 | SendToServerConsole("mp_ignore_round_win_conditions 1") 281 | SendToServerConsole("mp_match_end_changelevel 1") 282 | SendToServerConsole("sv_ignoregrenaderadio 1") 283 | SendToServerConsole("sv_disable_radar 1") 284 | SendToServerConsole("mp_footsteps_serverside 1") 285 | SendToServerConsole("sv_mincmdrate 128") 286 | SendToServerConsole("sv_minupdaterate 128") 287 | SendToServerConsole("mp_warmuptime_all_players_connected 0") 288 | -- Fix bots not spawning 289 | SendToServerConsole("mp_randomspawn 1") 290 | 291 | -- Team picking 292 | SendToServerConsole("mp_force_pick_time 60") 293 | 294 | -- End to falldamage 295 | SendToServerConsole("sv_falldamage_scale 0") 296 | 297 | -- Restart round to ensure settings (e.g. mp_weapons_allow_map_placed) are applied 298 | -- SendToServerConsole("mp_restartgame 1") 299 | 300 | CvarsKztimer() 301 | 302 | g_worldent = Entities:FindByClassname(nil, "worldent") 303 | g_worldent:SetContextThink(nil, Tick, 0) 304 | end 305 | -------------------------------------------------------------------------------- /scripts/vscripts/raytracing.lua: -------------------------------------------------------------------------------- 1 | -- how to use: 2 | -- 1. put this file in csgo/scripts/vscripts/ 3 | -- 2. type script_reload_code raytracing.lua in console 4 | -- 3. type gc_raytrace in console, or bind it to a key. 5 | 6 | local FCVAR_GAMEDLL = 0x4 7 | local FCVAR_CLIENTDLL = 0x8 8 | local FCVAR_RELEASE = 0x80000 9 | local cvarFlags = bit.bor(FCVAR_GAMEDLL, FCVAR_CLIENTDLL, FCVAR_NOTIFY, FCVAR_REPLICATED, FCVAR_RELEASE) 10 | 11 | Convars:RegisterConvar("gc_raytrace_fov", "90.0", nil, cvarFlags) 12 | Convars:RegisterConvar("gc_raytrace_width", "192.0", nil, cvarFlags) 13 | Convars:RegisterConvar("gc_raytrace_height", "108.0", nil, cvarFlags) 14 | 15 | local CONTENTS = { 16 | EMPTY = 0; -- No contents. 17 | SOLID = 0x1; -- an eye is never valid in a solid . 18 | HITBOX = 0x2; -- From reversing IDA + elimination, yet to hit in testing 19 | PLAYERCLIP = 0x10; 20 | MONSTERCLIP = 0x20; 21 | UNKNOWN0 = 0x40; -- hits world and weapons 22 | OPAQUE = 0x80; -- things that cannot be seen through (may be non-solid though). 23 | LADDER = 0x100; 24 | UNKNOWN1 = 0x200; -- hits weapons 25 | UNKNOWN2 = 0x400; -- hits world 26 | WINDOW = 0x1000; -- translucent, but not watery (glass). 27 | GRATE = 0x2000; -- alpha-tested "grate" textures. Bullets/sight pass through, but solids don't. 28 | WATER = 0x8000; 29 | SLIME = 0x10000; 30 | UNKNOWN3 = 0x20000; -- hits football in dust2 and players 31 | MOVEABLE = 0x40000; -- hits entities which are MOVETYPE_PUSH (doors, plats, etc) 32 | MONSTER = 0x80000; -- should never be on a brush, only in game. 33 | DEBRIS = 0x100000; 34 | UNKNOWN4 = 0x200000; -- hits football 35 | UNKNOWN5 = 0x8000000; -- hits football 36 | UNKNOWN6 = 0x40000000; -- hits world 37 | } 38 | 39 | local MASK = { 40 | ALL = (0xFFFFFFFF); 41 | SOLID = bit.bor(CONTENTS.SOLID, CONTENTS.MOVEABLE, CONTENTS.WINDOW, CONTENTS.MONSTER, CONTENTS.GRATE); -- everything that is normally solid 42 | PLAYERSOLID = bit.bor(CONTENTS.SOLID, CONTENTS.MOVEABLE, CONTENTS.PLAYERCLIP, CONTENTS.WINDOW, CONTENTS.MONSTER, CONTENTS.GRATE); -- everything that blocks player movement 43 | NPCSOLID = bit.bor(CONTENTS.SOLID, CONTENTS.MOVEABLE, CONTENTS.MONSTERCLIP, CONTENTS.WINDOW, CONTENTS.MONSTER, CONTENTS.GRATE); -- blocks npc movement 44 | WATER = bit.bor(CONTENTS.WATER, CONTENTS.MOVEABLE, CONTENTS.SLIME); -- water physics in these contents 45 | OPAQUE = bit.bor(CONTENTS.SOLID, CONTENTS.MOVEABLE, CONTENTS.OPAQUE); -- everything that blocks line of sight for AI, lighting, etc 46 | OPAQUE_AND_NPCS = bit.bor(CONTENTS.SOLID, CONTENTS.MOVEABLE, CONTENTS.OPAQUE, CONTENTS.MONSTER); -- everything that blocks line of sight for AI, lighting, etc, but with monsters added. 47 | VISIBLE = bit.bor(CONTENTS.SOLID, CONTENTS.MOVEABLE, CONTENTS.OPAQUE); -- everything that blocks line of sight for players 48 | VISIBLE_AND_NPCS = bit.bor(CONTENTS.SOLID, CONTENTS.MOVEABLE, CONTENTS.OPAQUE, CONTENTS.MONSTER); -- everything that blocks line of sight for players, but with monsters added. 49 | SHOT = bit.bor(CONTENTS.SOLID, CONTENTS.MOVEABLE, CONTENTS.MONSTER, CONTENTS.WINDOW, CONTENTS.DEBRIS, CONTENTS.HITBOX); -- bullets see these as solid 50 | SHOT_HULL = bit.bor(CONTENTS.SOLID, CONTENTS.MOVEABLE, CONTENTS.MONSTER, CONTENTS.WINDOW, CONTENTS.DEBRIS, CONTENTS.GRATE); -- non-raycasted weapons see this as solid (includes grates) 51 | SHOT_PORTAL = bit.bor(CONTENTS.SOLID, CONTENTS.MOVEABLE, CONTENTS.WINDOW); -- hits solids (not grates) and passes through everything else 52 | SOLID_BRUSHONLY = bit.bor(CONTENTS.SOLID, CONTENTS.MOVEABLE, CONTENTS.WINDOW, CONTENTS.GRATE); -- everything normally solid, except monsters (world+brush only) 53 | PLAYERSOLID_BRUSHONLY = bit.bor(CONTENTS.SOLID, CONTENTS.MOVEABLE, CONTENTS.WINDOW, CONTENTS.PLAYERCLIP, CONTENTS.GRATE); -- everything normally solid for player movement, except monsters (world+brush only) 54 | NPCSOLID_BRUSHONLY = bit.bor(CONTENTS.SOLID, CONTENTS.MOVEABLE, CONTENTS.WINDOW, CONTENTS.MONSTERCLIP, CONTENTS.GRATE); -- everything normally solid for npc movement, except monsters (world+brush only) 55 | NPCWORLDSTATIC = bit.bor(CONTENTS.SOLID, CONTENTS.WINDOW, CONTENTS.MONSTERCLIP, CONTENTS.GRATE); -- just the world, used for route rebuilding 56 | SPLITAREAPORTAL = bit.bor(CONTENTS.WATER, CONTENTS.SLIME); -- These are things that can split areaportals 57 | } 58 | 59 | 60 | local MAX_PIC_WIDTH = 3840 61 | local MAX_PIC_HEIGHT = 2160 62 | 63 | 64 | local RAYTRACE_POSITION_USAGE = "Usage: sm_raytrace_position [mask_flags; default: \"MASK_PLAYERSOLID\"]" 65 | local RAYTRACE_USAGE = "Usage: sm_raytrace [mask_flags; default: \"MASK_PLAYERSOLID\"]" 66 | 67 | local TRACETYPE_RAY = 0 68 | local TRACETYPE_HULL = 1 69 | 70 | local g_raytraceOverlay = false 71 | 72 | function CvarGetFloatChecked(cvar, min, max, default) 73 | local cvarValue = Convars:GetFloat(cvar) 74 | if cvarValue == nil then 75 | Convars:SetFloat(cvar, default) 76 | return default 77 | end 78 | if cvarValue < min then 79 | Convars:SetFloat(cvar, min) 80 | return min 81 | end 82 | if cvarValue > max then 83 | Convars:SetFloat(cvar, max) 84 | return max 85 | end 86 | return cvarValue 87 | end 88 | 89 | function PictureWidth() 90 | return CvarGetFloatChecked("gc_raytrace_width", 2.0, MAX_PIC_WIDTH, 1280.0) 91 | end 92 | 93 | function PictureHeight() 94 | return CvarGetFloatChecked("gc_raytrace_height", 2.0, MAX_PIC_HEIGHT, 720.0) 95 | end 96 | 97 | function PictureFov() 98 | return CvarGetFloatChecked("gc_raytrace_fov", 0.001, 179.0, 90.0) 99 | end 100 | 101 | function VectorDot(a, b) 102 | local temp = a * b 103 | return temp.x + temp.y + temp.z 104 | end 105 | 106 | -- v: a vector in 3D space 107 | -- k: a unit vector describing the axis of rotation 108 | -- theta: the angle (in radians) that v rotates around k 109 | function RotateVector(v, k, theta) 110 | local cos_theta = math.cos(theta); 111 | local sin_theta = math.sin(theta); 112 | 113 | local cross = CrossVectors(k, v); 114 | local dot = VectorDot(k, v); 115 | 116 | return (v * cos_theta) + (cross * sin_theta) + (k * dot) * (1.0 - cos_theta); 117 | end 118 | 119 | function ConvertFov(fovDegrees) 120 | return math.deg(2.0 * math.atan(math.tan(math.rad(fovDegrees) * 0.5) * (4.0 / 3.0))); 121 | end 122 | 123 | function TraceRayPixel(ignoreEntity, position, pos2, pixel, maskFlags) 124 | local trace = { 125 | startpos = position; 126 | endpos = pos2; 127 | ignore = ignoreEntity; 128 | mask = maskFlags; 129 | } 130 | TraceLine(trace) 131 | return trace 132 | end 133 | 134 | function TraceHullPixel(ignoreEntity, position, pos2, pixel, maskFlags) 135 | local trace = { 136 | startpos = position; 137 | endpos = pos2; 138 | ignore = ignoreEntity; 139 | mask = maskFlags; 140 | min = Vector(-16, -16, 0); 141 | max = Vector(16, 16, 72); 142 | } 143 | TraceHull(trace) 144 | return trace 145 | end 146 | 147 | function ScreenToTraceEndPos(x, y, invWidth, invHeight, angle, aspectRatio, angles) 148 | local xx = (2.0 * (x * invWidth) - 1.0) * angle; 149 | local yy = (1.0 - 2.0 * (y * invHeight)) * angle / aspectRatio; 150 | 151 | local result = Vector(xx, yy, -1.0); 152 | --NormalizeVector(result, result); 153 | 154 | -- x axis aka pitch 155 | result = RotateVector(result, Vector(1.0, 0.0, 0.0), math.rad(90.0 - angles.x)); 156 | 157 | -- z axis aka yaw 158 | result = RotateVector(result, Vector(0.0, 0.0, 1.0), math.rad(angles.y - 90.0)); 159 | -- result = RotatePosition(Vector(0, 0, 0), angles, result) 160 | return result; 161 | end 162 | 163 | function Quad(v1, v2, v3, v4, r, g, b, a, time) 164 | --[[ 165 | quad vertex layout: 166 | 1---2 167 | | /| 168 | | / | 169 | |/ | 170 | 3---4 171 | 172 | ]]-- 173 | debugoverlay:Triangle(v1, v2, v3, r, g, b, a, false, time) 174 | debugoverlay:Triangle(v3, v2, v4, r, g, b, a, false, time) 175 | end 176 | 177 | function TwoDto1D(x, y, maxX) 178 | return ((x - 1) + (y - 1) * maxX) + 1; 179 | end 180 | 181 | function Length(vec) 182 | return math.sqrt(vec.x * vec.x + vec.y * vec.y + vec.z * vec.z) 183 | end 184 | 185 | Convars:RegisterCommand("gc_raytrace", function(command, inTraceType, inTraceMask) 186 | local player = Convars:GetCommandClient() 187 | 188 | traceMask = MASK.PLAYERSOLID 189 | if inTraceMask ~= nil and MASK[inTraceMask] ~= nil then 190 | traceMask = MASK[inTraceMask] 191 | end 192 | -- print("trace mask:", traceMask) 193 | 194 | traceType = TRACETYPE_RAY 195 | if inTraceType ~= nil then 196 | traceType = tonumber(inTraceType) 197 | if traceType ~= TRACETYPE_RAY and traceType ~= TRACETYPE_HULL then 198 | traceType = TRACETYPE_RAY 199 | end 200 | end 201 | 202 | local position = player:EyePosition() 203 | local angles = player:EyeAngles() 204 | local width = PictureWidth() 205 | local height = PictureHeight() 206 | -- rgb colours: [r, g, b] * n 207 | local picture = {} 208 | for i = 0, (width * height) do 209 | picture[i + 1] = { 210 | pos = Vector(0, 0, 0); 211 | normal = Vector(0, 0, 0); 212 | } 213 | end 214 | -- picture index 215 | local pixel = 1; 216 | 217 | local invWidth = 1.0 / width 218 | local invHeight = 1.0 / height 219 | 220 | -- angle diff 221 | local fov = ConvertFov(PictureFov()); 222 | 223 | local angle = math.tan(3.1415926535 * 0.5 * fov / 180.0); 224 | local aspectRatio = width / height / (4.0 / 3.0); 225 | 226 | print("Tracing. width:", width, "height:", height, "traceType:", traceType, "traceMask:", traceMask, "position:", position, "angles:", angles, "fov:", fov) 227 | -- y is for yaw 228 | for y = 0, (height - 1) do 229 | -- x is for pitch 230 | for x = 0, (width - 1) do 231 | pos2 = ScreenToTraceEndPos(x, y, invWidth, invHeight, angle, aspectRatio, angles) 232 | pos2 = pos2 * 10000.0; 233 | pos2 = pos2 + position 234 | 235 | local trace = {} 236 | if traceType == TRACETYPE_RAY then 237 | trace = TraceRayPixel(player, position, pos2, pixel, traceMask) 238 | else 239 | trace = TraceHullPixel(player, position, pos2, pixel, traceMask) 240 | end 241 | picture[pixel].pos = trace.pos 242 | picture[pixel].normal = trace.normal 243 | pixel = pixel + 1 244 | end 245 | end 246 | 247 | debugoverlay:PushAndClearDebugOverlayScope("gc_raytracing") 248 | for y = 1, (height - 1) do 249 | for x = 1, (width - 1) do 250 | local n1 = picture[TwoDto1D(x, y, width)].normal 251 | local n2 = picture[TwoDto1D(x + 1, y, width)].normal 252 | local n3 = picture[TwoDto1D(x, y + 1, width)].normal 253 | local n4 = picture[TwoDto1D(x + 1, y + 1, width)].normal 254 | 255 | local v1 = picture[TwoDto1D(x, y, width)].pos + n1 * 0.1 256 | local v2 = picture[TwoDto1D(x + 1, y, width)].pos + n2 * 0.1 257 | local v3 = picture[TwoDto1D(x, y + 1, width)].pos + n3 * 0.1 258 | local v4 = picture[TwoDto1D(x + 1, y + 1, width)].pos + n4 * 0.1 259 | 260 | local d1 = Length(v2 - v1) 261 | local d2 = Length(v3 - v1) 262 | local d3 = Length(v4 - v1) 263 | 264 | local tolerance = 32.0 265 | if d1 < tolerance and d2 < tolerance and d3 < tolerance then 266 | local colour = (n1 + n2 + n3 + n4) * 0.25 267 | colour.x = math.abs(colour.x) * 255.0 268 | colour.y = math.abs(colour.y) * 255.0 269 | colour.z = math.abs(colour.z) * 255.0 270 | local frac = (math.floor(v1.x / 32.0) + math.floor(v1.y / 32.0) + math.floor(v1.z / 32.0)) * 0.5 271 | frac = frac - math.floor(frac) 272 | colour = colour * (frac * 0.75 + 0.25) 273 | Quad(v1, v2, v3, v4, colour.x, colour.y, colour.z, 200, -1.0) 274 | end 275 | end 276 | end 277 | debugoverlay:PopDebugOverlayScope() 278 | print("Tracing done.") 279 | end, nil, 0) 280 | --------------------------------------------------------------------------------