├── .github ├── FUNDING.yml └── workflows │ └── main.yml ├── .luacheckrc ├── fxmanifest.lua ├── shared.lua ├── .gitignore ├── LICENSE ├── README.md ├── server.lua └── client.lua /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | patreon: lemonchan 2 | custom: ["https://paypal.me/justalemon"] 3 | -------------------------------------------------------------------------------- /.luacheckrc: -------------------------------------------------------------------------------- 1 | allow_defined = true 2 | files["fivem.lua"] = { 3 | unused = false, 4 | max_line_length = false, 5 | ignore = { 6 | "131" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /fxmanifest.lua: -------------------------------------------------------------------------------- 1 | fx_version "cerulean" 2 | games { "gta5" } 3 | 4 | client_script "client.lua" 5 | client_script "shared.lua" 6 | server_script "server.lua" 7 | server_script "shared.lua" 8 | -------------------------------------------------------------------------------- /shared.lua: -------------------------------------------------------------------------------- 1 | function Debug(message) 2 | if GetConvarInt("simplepassive_debug", 0) == 0 then 3 | return 4 | end 5 | 6 | print(message) 7 | end 8 | 9 | function GetDefaultActivation() 10 | return GetConvarInt("simplepassive_default", 0) ~= 0 11 | end 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | fivem.lua 3 | 4 | # Compiled Lua sources 5 | luac.out 6 | 7 | # luarocks build files 8 | *.src.rock 9 | *.zip 10 | *.tar.gz 11 | 12 | # Object files 13 | *.o 14 | *.os 15 | *.ko 16 | *.obj 17 | *.elf 18 | 19 | # Precompiled Headers 20 | *.gch 21 | *.pch 22 | 23 | # Libraries 24 | *.lib 25 | *.a 26 | *.la 27 | *.lo 28 | *.def 29 | *.exp 30 | 31 | # Shared objects (inc. Windows DLLs) 32 | *.dll 33 | *.so 34 | *.so.* 35 | *.dylib 36 | 37 | # Executables 38 | *.exe 39 | *.out 40 | *.app 41 | *.i*86 42 | *.x86_64 43 | *.hex 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2023 Hannele Ruiz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Compile Lua Mod 2 | on: 3 | release: 4 | types: 5 | - created 6 | push: 7 | pull_request: 8 | 9 | permissions: 10 | contents: write 11 | id-token: write 12 | pages: write 13 | 14 | jobs: 15 | lint-and-compile: 16 | runs-on: ubuntu-22.04 17 | steps: 18 | - uses: actions/checkout@v3 19 | - uses: actions/setup-python@v4.6.0 20 | with: 21 | python-version: "3.10" 22 | - run: pip install https://github.com/justalemon/Collei/archive/master.zip 23 | - run: python -m collei natives cfxlua 24 | - uses: lunarmodules/luacheck@v1.1.0 25 | - run: rm fivem.lua 26 | - run: rm -r dist/simplepassive || true && mkdir -p dist/simplepassive && cp *.lua dist/simplepassive 27 | - uses: actions/upload-artifact@v3 28 | with: 29 | name: ${{ github.event.repository.name }} 30 | path: dist 31 | deploy: 32 | runs-on: ubuntu-22.04 33 | if: ${{ github.event_name == 'release' }} 34 | needs: 35 | - lint-and-compile 36 | steps: 37 | - uses: actions/checkout@v3 38 | - uses: actions/download-artifact@v3 39 | with: 40 | name: ${{ github.event.repository.name }} 41 | path: dist 42 | - run: 7z a ${{ github.event.repository.name }}.zip ${{ github.workspace }}/dist/* 43 | - run: ls -R 44 | working-directory: dist 45 | - uses: ncipollo/release-action@v1.10.0 46 | with: 47 | allowUpdates: true 48 | artifactErrorsFailBuild: true 49 | artifacts: ${{ github.event.repository.name }}.zip 50 | omitBodyDuringUpdate: true 51 | omitDraftDuringUpdate: true 52 | omitNameDuringUpdate: true 53 | omitPrereleaseDuringUpdate: true 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SimplePassive
[![GitHub Actions][actions-img]][actions-url] [![Patreon][patreon-img]][patreon-url] [![PayPal][paypal-img]][paypal-url] [![Discord][discord-img]][discord-url] 2 | 3 | SimplePassive is a resource for FiveM that allows you to use a Passive Mode like feature just like in GTA Online. 4 | 5 | It has multiple configurable features that you can configure and use, like: 6 | 7 | * Authorizing specific players via ACL permissions (for example: only staff members can use passive) 8 | * Forcing passive mode onto players (to prevent harassment or ramming with vehicles) 9 | * Disable combat between players (for the true passive mode experience) 10 | 11 | ## Download 12 | 13 | * [GitHub Releases](https://github.com/justalemon/SimplePassive/releases) 14 | * [GitHub Actions](https://github.com/justalemon/SimplePassive/actions) (experimental versions) 15 | 16 | ## Installation 17 | 18 | Copy the folder from the compressed file to your **resources** directory. 19 | 20 | ## Usage 21 | 22 | By default, SimplePassive does not allows users to enable or disable passive mode. You need to authorize it via the `simplepassive.changeself` ACL permission (you can allow everyone with `add_ace builtin.everyone simplepassive.changeself allow`). Then, passive mode can be toggled via the /passivetoggle command. 23 | 24 | Feel free to check out the [wiki](https://github.com/justalemon/SimplePassive/wiki) for a list of Commands, Convars and Exports. 25 | 26 | [actions-img]: https://img.shields.io/github/actions/workflow/status/justalemon/SimplePassive/main.yml?branch=master&label=actions 27 | [actions-url]: https://github.com/justalemon/SimplePassive/actions 28 | [patreon-img]: https://img.shields.io/badge/support-patreon-FF424D.svg 29 | [patreon-url]: https://www.patreon.com/lemonchan 30 | [paypal-img]: https://img.shields.io/badge/support-paypal-0079C1.svg 31 | [paypal-url]: https://paypal.me/justalemon 32 | [discord-img]: https://img.shields.io/badge/discord-join-7289DA.svg 33 | [discord-url]: https://discord.gg/Cf6sspj 34 | -------------------------------------------------------------------------------- /server.lua: -------------------------------------------------------------------------------- 1 | -- The activation of passive mode for specific players. 2 | Activations = {} 3 | -- The activations that override the dictionary above. 4 | Overrides = {} 5 | -- The last time the player changed it's own activation. 6 | LastChange = {} 7 | 8 | function GetPlayer(playerSrc) 9 | -- do this as it might be passed as an int from C# 10 | local handle = tonumber(playerSrc) 11 | -- Best option I could find 12 | -- Returns nil when the playerSrc is not valid, and a number when valid 13 | local guid = GetPlayerGuid(handle) 14 | 15 | if guid then 16 | return handle 17 | else 18 | return nil 19 | end 20 | end 21 | 22 | function IsInCooldown(player) 23 | local lastChange = LastChange[player] 24 | return lastChange ~= nil and lastChange + GetConvarInt("simplepassive_cooldown", 0) > GetGameTimer() 25 | end 26 | 27 | function GetPlayerActivation(playerSrc) 28 | local player = GetPlayer(playerSrc) 29 | 30 | if player == nil then 31 | return false 32 | end 33 | 34 | local override = Overrides[player] 35 | if override ~= nil then 36 | return override 37 | end 38 | 39 | local activation = Activations[player] 40 | if activation ~= nil then 41 | return activation 42 | end 43 | 44 | return GetDefaultActivation() 45 | end 46 | 47 | function SetPlayerActivation(playerSrc, activation) 48 | local player = GetPlayer(playerSrc) 49 | -- TODO: Add proper boolean checks 50 | 51 | if player == nil then 52 | return false 53 | end 54 | 55 | Activations[player] = activation 56 | TriggerClientEvent("simplepassive:activationChanged", -1, player, activation) 57 | Debug("Passive Activation of " .. GetPlayerName(player) .. " (" .. player .. ") is now " .. activation) 58 | return true 59 | end 60 | 61 | function IsPlayerOverridden(playerSrc) 62 | local player = GetPlayer(playerSrc) 63 | return player ~= nil and Overrides[player] ~= nil 64 | end 65 | 66 | function SetPlayerOverride(playerSrc, override) 67 | local player = GetPlayer(playerSrc) 68 | -- TODO: Add proper boolean checks 69 | 70 | if player == nil then 71 | return false 72 | end 73 | 74 | Overrides[player] = override 75 | TriggerClientEvent("simplepassive:activationChanged", -1, tonumber(player), override) 76 | Debug("Passive Activation of " .. GetPlayerName(player) .. " (" .. player .. ") is overriden to " .. override) 77 | return true 78 | end 79 | 80 | function ClearPlayerOverride(playerSrc) 81 | local player = GetPlayer(playerSrc) 82 | 83 | if player == nil then 84 | return false 85 | end 86 | 87 | if Overrides[player] == nil then 88 | return false 89 | end 90 | 91 | Overrides[player] = nil 92 | Debug("Passive Override of " .. GetPlayerName(player) .. " (" .. player .. ") was removed") 93 | return true 94 | end 95 | 96 | function OnPlayerDropped() 97 | local player = tonumber(source) 98 | 99 | TriggerClientEvent("simplepassive:doCleanup", -1, player) 100 | Overrides[player] = nil 101 | Activations[player] = nil 102 | end 103 | 104 | function OnPlayerInitialized() 105 | local player = GetPlayer(source) 106 | 107 | if player == nil then 108 | return false 109 | end 110 | 111 | Activations[player] = GetDefaultActivation() 112 | 113 | for _, otherPlayerSrc in ipairs(GetPlayers()) do 114 | local otherPlayer = GetPlayer(otherPlayerSrc) 115 | 116 | if otherPlayer ~= nil then 117 | TriggerClientEvent("simplepassive:activationChanged", player, otherPlayer, GetPlayerActivation(otherPlayer)) 118 | end 119 | end 120 | 121 | Debug("Player " .. GetPlayerName(player) .. " (" .. player .. ") received all passive activations") 122 | end 123 | 124 | function SetPassiveSelf(activation) 125 | local player = GetPlayer(source) 126 | -- TODO: Add proper boolean checks 127 | 128 | if player == nil then 129 | return false 130 | end 131 | 132 | if not IsPlayerAceAllowed(player, "simplepassive.changeself") or IsInCooldown() then 133 | return 134 | end 135 | 136 | if Overrides[player] ~= nil then 137 | return 138 | end 139 | 140 | Activations[player] = activation 141 | TriggerClientEvent("simplepassive:activationChanged", -1, player, activation) 142 | 143 | Debug("Player " .. GetPlayerName(player) .. " (" .. player .. ") set it's own activation to " .. activation) 144 | end 145 | 146 | function OnOverrideCommand(_, args, _) 147 | if #args < 2 then 148 | print("You need to specify the Player ID and desired Activation!") 149 | return 150 | end 151 | 152 | local player = GetPlayer(args[1]) 153 | 154 | if player == nil then 155 | print("The Player specified it's not valid!") 156 | return 157 | end 158 | 159 | local activation = tonumber(args[2]) 160 | 161 | if activation == nil then 162 | print("The activation needs to be 0 or 1!") 163 | return 164 | end 165 | 166 | SetPlayerOverride(player, activation) 167 | end 168 | 169 | function OnClearCommand(_, args, _) 170 | if args[1] == nil then 171 | Debug("You need to specify the ID of a Player!") 172 | return 173 | end 174 | 175 | local player = GetPlayer(args[1]) 176 | 177 | if player == nil then 178 | Debug("The Player specified is not valid."); 179 | return 180 | end 181 | 182 | if ClearPlayerOverride(player) then 183 | print("The Override of " .. GetPlayerName(player) .. " (" .. player .. ") was cleared!") 184 | else 185 | print("Player " .. GetPlayerName(player) .. " (" .. player .. ") does not has an override set") 186 | end 187 | end 188 | 189 | function OnOverridesCommand(_, _, _) 190 | if #Overrides == 0 then 191 | print("There are no Passive Mode Overrides in place.") 192 | return 193 | end 194 | 195 | for player, activation in pairs(Activations) do 196 | print("\t" .. player .. " set to " .. activation) 197 | end 198 | end 199 | 200 | function OnToggleCommand(source, _, _) 201 | local player = GetPlayer(source) 202 | 203 | if player == nil then 204 | print("This command can only be used by players on the server") 205 | return 206 | end 207 | 208 | if Overrides[player] ~= nil then 209 | print("Your Passive Mode Activation has been overriden, you can't change it") 210 | return 211 | end 212 | 213 | if not IsPlayerAceAllowed(source, "simplepassive.changeself") then 214 | print("You are not allowed to change your passive mode activation") 215 | return 216 | end 217 | 218 | if IsInCooldown(player) then 219 | print("You need to wait a bit before changing your passive mode activation again") 220 | return 221 | end 222 | 223 | local opposite = not GetPlayerActivation(player) 224 | Activations[player] = opposite 225 | TriggerClientEvent("simplepassive:activationChanged", -1, player, opposite) 226 | LastChange[player] = GetGameTimer() 227 | print("Player " .. GetPlayerName(player) .. " (" .. player .. ") set it's activation to " .. tostring(opposite)) 228 | end 229 | 230 | exports("getActivation", GetPlayerActivation) 231 | exports("setActivation", SetPlayerActivation) 232 | exports("isOverriden", IsPlayerOverridden) 233 | exports("setOverride", SetPlayerOverride) 234 | exports("clearOverride", ClearPlayerOverride) 235 | RegisterNetEvent("playerDropped", OnPlayerDropped) 236 | RegisterNetEvent("simplepassive:initialized", OnPlayerInitialized) 237 | RegisterNetEvent("simplepassive:setPassive", SetPassiveSelf) 238 | RegisterCommand("passiveoverride", OnOverrideCommand, true) 239 | RegisterCommand("passiveclear", OnClearCommand, true) 240 | RegisterCommand("passiveoverrides", OnOverridesCommand, true) 241 | RegisterCommand("passivetoggle", OnToggleCommand, false) 242 | -------------------------------------------------------------------------------- /client.lua: -------------------------------------------------------------------------------- 1 | -- The activations sent by the server 2 | Activations = {} 3 | -- Whether the next set of collision changes should be printed on the console 4 | PrintCollisionChanges = false 5 | -- The last known player vehicle 6 | LastVehicle = 0 7 | -- The last known trailer/hooked vehicle 8 | LastHooked = 0 9 | 10 | function GetHookedVehicle(vehicle) 11 | if vehicle == 0 or not IsEntityAVehicle(vehicle) then 12 | return 13 | end 14 | 15 | local _, trailer = GetVehicleTrailerVehicle(vehicle) 16 | if trailer ~= 0 then 17 | return trailer 18 | end 19 | 20 | local towed = GetEntityAttachedToTowTruck(vehicle) 21 | if towed ~= 0 then 22 | return towed 23 | end 24 | 25 | local hooked = GetVehicleAttachedToCargobob(vehicle) 26 | if hooked ~= 0 then 27 | return hooked 28 | end 29 | 30 | return 0 31 | end 32 | 33 | function DrawDebugMarker(entity) 34 | if entity == 0 or not IsEntityOnScreen(entity) then 35 | return 36 | end 37 | 38 | local pos = GetEntityCoords(entity, false) 39 | local _, x, y = GetScreenCoordFromWorldCoord(pos.x, pos.y, pos.z) 40 | BeginTextCommandDisplayText("CELL_EMAIL_BCON") 41 | AddTextComponentSubstringPlayerName(tostring(entity)) 42 | SetTextColour(255, 66, 198, 255) 43 | SetTextJustification(0) 44 | EndTextCommandDisplayText(x, y) 45 | end 46 | 47 | function DisableCollisionsThisFrame(one, two) 48 | if one == 0 or two == 0 then 49 | return 50 | end 51 | 52 | SetEntityNoCollisionEntity(one, two, true) 53 | SetEntityNoCollisionEntity(two, one, true) 54 | 55 | if PrintCollisionChanges then 56 | print("Disabled collisions between " .. one .. " and " .. two .. " ."); 57 | end 58 | end 59 | 60 | function SetAlpha(entity, alpha) 61 | if entity == 0 then 62 | return 63 | end 64 | 65 | if alpha >= 255 then 66 | ResetEntityAlpha(entity) 67 | else 68 | SetEntityAlpha(entity, alpha, 0) 69 | end 70 | end 71 | 72 | function GetLocalPlayerActivation() 73 | local playerId = PlayerId() 74 | local player = GetPlayerServerId(playerId) 75 | return GetPlayerActivation(player) 76 | end 77 | 78 | function GetPlayerActivation(player) 79 | local activation = Activations[player] 80 | 81 | if activation ~= nil then 82 | return activation 83 | else 84 | return GetDefaultActivation() 85 | end 86 | end 87 | 88 | function SetLocalPlayerActivation(activation) 89 | -- TODO: Add proper boolean checks 90 | Debug("Requesting server to change the activation to " .. activation) 91 | TriggerServerEvent("simplepassive:setPassive", activation) 92 | end 93 | 94 | function Initialize() 95 | TriggerServerEvent("simplepassive:initialized") 96 | end 97 | 98 | function HandleCollisions() 99 | while true do 100 | local localPlayer = PlayerId() 101 | local localPed = PlayerPedId() 102 | local localVehicle = GetVehiclePedIsIn(localPed, false) 103 | local localHooked = GetHookedVehicle(localVehicle) 104 | local localActivation = GetLocalPlayerActivation() 105 | 106 | local debug = GetConvarInt("simplepassive_debug", 0) ~= 0 107 | local shadowAlpha = GetConvarInt("simplepassive_alpha", 200) 108 | 109 | local setInvincible = GetConvarInt("simplepassive_makeinvincible", 0) ~= 0 110 | local disableCombat = GetConvarInt("simplepassive_disablecombat", 0) ~= 0 111 | 112 | SetEntityInvincible(localPed, setInvincible and localActivation) 113 | if localVehicle then 114 | SetEntityInvincible(localVehicle, setInvincible and localActivation) 115 | end 116 | if localHooked then 117 | SetEntityInvincible(localHooked, setInvincible and localActivation) 118 | end 119 | 120 | -- this ones will be overridden by the checks above from the other player's client 121 | if setInvincible then 122 | if LastVehicle ~= localVehicle then 123 | SetEntityInvincible(LastVehicle, false) 124 | LastVehicle = localVehicle 125 | end 126 | if LastHooked ~= localHooked then 127 | SetEntityInvincible(LastHooked, false) 128 | LastHooked = localHooked 129 | end 130 | end 131 | 132 | if localActivation and disableCombat then 133 | DisablePlayerFiring(localPlayer, true) 134 | 135 | DisableControlAction(0, 45, true) -- INPUT_RELOAD 136 | DisableControlAction(0, 263, true) -- INPUT_MELEE_ATTACK1 137 | DisableControlAction(0, 264, true) -- INPUT_MELEE_ATTACK2 138 | DisableControlAction(0, 140, true) -- INPUT_MELEE_ATTACK_LIGHT 139 | DisableControlAction(0, 141, true) -- INPUT_MELEE_ATTACK_HEAVY 140 | DisableControlAction(0, 142, true) -- INPUT_MELEE_ATTACK_ALTERNATE 141 | DisableControlAction(0, 143, true) -- INPUT_MELEE_BLOCK 142 | DisableControlAction(0, 24, true) -- INPUT_ATTACK 143 | DisableControlAction(0, 257, true) -- INPUT_ATTACK2 144 | DisableControlAction(0, 69, true) -- INPUT_VEH_ATTACK 145 | DisableControlAction(0, 70, true) -- INPUT_VEH_ATTACK2 146 | DisableControlAction(0, 91, true) -- INPUT_VEH_PASSENGER_AIM 147 | DisableControlAction(0, 92, true) -- INPUT_VEH_PASSENGER_ATTACK 148 | DisableControlAction(0, 114, true) -- INPUT_VEH_FLY_ATTACK 149 | DisableControlAction(0, 331, true) -- INPUT_VEH_FLY_ATTACK2 150 | end 151 | 152 | if debug then 153 | DrawDebugMarker(localPed) 154 | DrawDebugMarker(localVehicle) 155 | DrawDebugMarker(localHooked) 156 | end 157 | 158 | for _, otherPlayer in ipairs(GetActivePlayers()) do 159 | if otherPlayer == localPlayer then 160 | goto continue 161 | end 162 | 163 | local otherPed = GetPlayerPed(otherPlayer) 164 | local otherVehicle = GetVehiclePedIsIn(otherPed, false) 165 | local otherHooked = GetHookedVehicle(otherVehicle) 166 | local otherActivation = GetPlayerActivation(GetPlayerServerId(otherPlayer)) 167 | local shouldDisableCollisions = otherActivation or localActivation 168 | 169 | local alpha = 255 170 | 171 | if shouldDisableCollisions and not GetIsTaskActive(otherPed, 2) and 172 | (otherVehicle == 0 or otherVehicle ~= localVehicle) then 173 | alpha = shadowAlpha 174 | end 175 | 176 | SetAlpha(otherPed, alpha) 177 | SetAlpha(otherVehicle, alpha) 178 | SetAlpha(otherHooked, alpha) 179 | 180 | if debug then 181 | DrawDebugMarker(otherPed) 182 | DrawDebugMarker(otherVehicle) 183 | DrawDebugMarker(otherHooked) 184 | end 185 | 186 | if shouldDisableCollisions then 187 | if otherVehicle and IsPedInVehicle(otherVehicle, localPed, false) and 188 | GetPedInVehicleSeat(otherVehicle, -1) ~= localPed then 189 | goto continue 190 | end 191 | 192 | DisableCollisionsThisFrame(localPed, otherPed) 193 | DisableCollisionsThisFrame(localPed, otherVehicle) 194 | DisableCollisionsThisFrame(localPed, otherHooked) 195 | 196 | DisableCollisionsThisFrame(localVehicle, otherPed) 197 | DisableCollisionsThisFrame(localVehicle, otherVehicle) 198 | DisableCollisionsThisFrame(localVehicle, otherHooked) 199 | 200 | DisableCollisionsThisFrame(localHooked, otherPed) 201 | DisableCollisionsThisFrame(localHooked, otherVehicle) 202 | DisableCollisionsThisFrame(localHooked, otherHooked) 203 | 204 | -- luacheck: ignore 113 205 | DisableCamCollisionForEntity(otherPed) 206 | 207 | if otherVehicle then 208 | -- luacheck: ignore 113 209 | DisableCamCollisionForEntity(otherVehicle) 210 | end 211 | 212 | if otherHooked then 213 | -- luacheck: ignore 113 214 | DisableCamCollisionForEntity(otherHooked) 215 | end 216 | end 217 | 218 | ::continue:: 219 | end 220 | 221 | if debug then 222 | local debugText = "Passive Players: " 223 | 224 | for _, playerId in ipairs(GetActivePlayers()) do 225 | local player = GetPlayerServerId(playerId) 226 | local activation = GetPlayerActivation(player) 227 | 228 | -- fallback for race conditions 229 | if activation == nil then 230 | activation = GetDefaultActivation() 231 | end 232 | 233 | debugText = debugText .. " " .. player .. " " .. tostring(activation) 234 | end 235 | 236 | BeginTextCommandDisplayText("CELL_EMAIL_BCON") 237 | AddTextComponentSubstringPlayerName(debugText) 238 | SetTextScale(1, 0.5) 239 | SetTextColour(255, 255, 255, 255) 240 | EndTextCommandDisplayText(0, 0) 241 | end 242 | 243 | PrintCollisionChanges = false 244 | 245 | Citizen.Wait(0) 246 | end 247 | end 248 | 249 | function OnActivationChanged(playerId, activation) 250 | -- TODO: Add proper boolean checks 251 | 252 | local player = tonumber(playerId) 253 | 254 | if player == nil then 255 | return 256 | end 257 | 258 | Activations[player] = activation 259 | 260 | Debug("Received Passive Activation of " .. player .. " (" .. tostring(activation) .. ")") 261 | 262 | local localPlayer = PlayerId() 263 | 264 | if player == GetPlayerServerId(localPlayer) then 265 | local shouldDisableCombat = GetConvarInt("simplepassive_disablecombat", 0) ~= 0 266 | SetPlayerCanDoDriveBy(localPlayer, (not activation and shouldDisableCombat) or not shouldDisableCombat) 267 | end 268 | end 269 | 270 | function OnDoCleanup(player) 271 | Activations[player] = nil 272 | end 273 | 274 | function OnPrintTickCommand(_, _, _) 275 | if GetConvarInt("simplepassive_debug", 0) ~= 0 then 276 | PrintCollisionChanges = true 277 | end 278 | end 279 | 280 | exports("getActivation", GetLocalPlayerActivation) 281 | exports("setActivation", SetLocalPlayerActivation) 282 | Citizen.CreateThread(Initialize) 283 | Citizen.CreateThread(HandleCollisions) 284 | RegisterNetEvent("simplepassive:activationChanged", OnActivationChanged) 285 | RegisterNetEvent("simplepassive:doCleanup", OnDoCleanup) 286 | RegisterCommand("passiveprinttick", OnPrintTickCommand, true) 287 | --------------------------------------------------------------------------------