diff --git a/server-data/resources/[bpt_addons]/bpt_crafting/bpt_crafting.sql b/server-data/resources/[bpt_addons]/bpt_crafting/bpt_crafting.sql index c308d77e8..5b3375368 100644 --- a/server-data/resources/[bpt_addons]/bpt_crafting/bpt_crafting.sql +++ b/server-data/resources/[bpt_addons]/bpt_crafting/bpt_crafting.sql @@ -55,5 +55,6 @@ INSERT INTO `bpt_items` (`name`, `label`) VALUES ('cannabis', 'Cannabis'), ('diamond_tip', 'Diamond tip'), ('diamond', 'Diamond'), - ('marijuana_extract', 'Marijuana extract') + ('marijuana_extract', 'Marijuana extract'), + ('medikit', 'Medikit') ; \ No newline at end of file diff --git a/server-data/resources/[bpt_addons]/bpt_crafting/config.lua b/server-data/resources/[bpt_addons]/bpt_crafting/config.lua index 67e182a52..e1978638b 100644 --- a/server-data/resources/[bpt_addons]/bpt_crafting/config.lua +++ b/server-data/resources/[bpt_addons]/bpt_crafting/config.lua @@ -5,14 +5,19 @@ Config = { HideWhenCantCraft = false, -- Instead of lowering the opacity it hides the item that is not craftable due to low level or wrong job Categories = { - ["medical"] = { - Label = "Ospedale", - Image = "bandage", - Jobs = { "ambulance" }, + ["tools"] = { + Label = "Utensili", + Image = "tools", + Jobs = { "import" }, + }, + ["recycled"] = { + Label = "Riciclo", + Image = "recycled", + Jobs = { "import" }, }, - ["import"] = { - Label = "Import", - Image = "Import", + ["manufacturing"] = { + Label = "Fabbricazione", + Image = "manufacturing", Jobs = { "import" }, }, ["mechanic"] = { @@ -20,8 +25,18 @@ Config = { Image = "Mechanic", Jobs = { "mechanic" }, }, + ["med_equip"] = { + Label = "Med Equip", + Image = "bandage", + Jobs = { "ambulance" }, + }, + ["drugs"] = { + Label = "Droghe", + Image = "drugs", + Jobs = { "ambulance" }, + }, ["ammu"] = { - Label = "Armeria", + Label = "Armi", Image = "ammu", Jobs = { "ammu" }, }, @@ -45,6 +60,11 @@ Config = { Image = "fisherman", Jobs = { "fisherman" }, }, + ["ammunation"] = { + Label = "Munizioni", + Image = "ammu", + Jobs = { "ammu" }, + }, }, PermanentItems = { -- Items that dont get removed when crafting @@ -54,7 +74,7 @@ Config = { Recipes = { -- Enter Item name and then the speed value! The higher the value the more torque ["bandage"] = { Level = 0, - Category = "medical", + Category = "med_equip", isGun = false, Jobs = { "ambulance" }, JobGrades = {}, @@ -67,9 +87,27 @@ Config = { }, }, + ["medikit"] = { + Level = 0, + Category = "med_equip", + isGun = false, + Jobs = { "ambulance" }, + JobGrades = {}, + Amount = 1, + SuccessRate = 100, + requireBlueprint = false, + Time = 30, + Ingredients = { + ["recycled_plastic"] = 2, + ["marijuana"] = 5, + ["bandage"] = 1, + ["cottonforbandages"] = 2, + }, + }, + ["marijuana_extract"] = { Level = 0, - Category = "medical", + Category = "drugs", isGun = false, Jobs = { "ambulance" }, JobGrades = {}, @@ -86,7 +124,7 @@ Config = { ["marijuana"] = { Level = 0, - Category = "medical", + Category = "drugs", isGun = false, Jobs = { "ambulance" }, JobGrades = {}, @@ -101,23 +139,23 @@ Config = { }, ["cottonforbandages"] = { - Level = 0, -- From what level this item will be craftable - Category = "import", -- The category item will be put in - isGun = false, -- Specify if this is a gun so it will be added to the loadout - Jobs = { "import" }, -- What jobs can craft this item, leaving {} allows any job - JobGrades = {}, -- What job grades can craft this item, leaving {} allows any grade - Amount = 1, -- The amount that will be crafted - SuccessRate = 100, -- 100% you will recieve the item - requireBlueprint = false, -- Requires a blueprint whitch you need to add in the database yourself TEMPLATE: itemname_blueprint EXAMPLE: bandage_blueprint - Time = 20, -- Time in seconds it takes to craft this item - Ingredients = { -- Ingredients needed to craft this item - ["cotton"] = 4, -- item name and count, adding items that dont exist in database will crash the script + Level = 0, + Category = "manufacturing", + isGun = false, + Jobs = { "import" }, + JobGrades = {}, + Amount = 1, + SuccessRate = 100, + requireBlueprint = false, + Time = 20, + Ingredients = { + ["cotton"] = 4, }, }, ["ironsheet"] = { Level = 0, - Category = "import", + Category = "manufacturing", isGun = false, Jobs = { "import" }, JobGrades = {}, @@ -133,7 +171,7 @@ Config = { ["diamond_tip"] = { Level = 0, - Category = "import", + Category = "tools", isGun = false, Jobs = { "import" }, JobGrades = {}, @@ -150,7 +188,7 @@ Config = { ["recycled_paper"] = { Level = 0, - Category = "import", + Category = "recycled", isGun = false, Jobs = { "import" }, JobGrades = {}, @@ -165,7 +203,7 @@ Config = { ["paper"] = { Level = 0, - Category = "import", + Category = "manufacturing", isGun = false, Jobs = { "import" }, JobGrades = {}, @@ -181,7 +219,7 @@ Config = { ["hammer"] = { Level = 0, - Category = "import", + Category = "tools", isGun = false, Jobs = { "import" }, JobGrades = {}, @@ -246,7 +284,7 @@ Config = { ["iron"] = { Level = 0, - Category = "import", + Category = "manufacturing", isGun = false, Jobs = { "import" }, JobGrades = {}, @@ -314,7 +352,7 @@ Config = { }, ["ammo-sniper"] = { Level = 10, - Category = "ammu", + Category = "ammunation", isGun = false, Jobs = { "ammu" }, JobGrades = {}, @@ -333,7 +371,7 @@ Config = { ["ammo-9"] = { Level = 10, - Category = "ammu", + Category = "ammunation", isGun = false, Jobs = { "ammu" }, JobGrades = {}, @@ -465,7 +503,7 @@ Config = { ["recycled_plastic"] = { Level = 0, - Category = "import", + Category = "recycled", isGun = false, Jobs = { "import" }, JobGrades = {}, @@ -500,7 +538,7 @@ Config = { coords = vector3(311.314301, -565.213196, 43.282104), jobs = { "ambulance" }, blip = false, - recipes = { "bandage", "marijuana", "marijuana_extract" }, + recipes = { "bandage", "marijuana", "marijuana_extract", "medikit" }, radius = 1.0, }, { diff --git a/server-data/resources/[bpt_addons]/bpt_crafting/fxmanifest.lua b/server-data/resources/[bpt_addons]/bpt_crafting/fxmanifest.lua index b32873c2c..6975e722d 100644 --- a/server-data/resources/[bpt_addons]/bpt_crafting/fxmanifest.lua +++ b/server-data/resources/[bpt_addons]/bpt_crafting/fxmanifest.lua @@ -1,5 +1,5 @@ fx_version("adamant") -version("1.0.1") +version("1.0.2") game("gta5") shared_script("@es_extended/imports.lua") diff --git a/server-data/resources/[bpt_addons]/bpt_crafting/html/img/drugs.png b/server-data/resources/[bpt_addons]/bpt_crafting/html/img/drugs.png new file mode 100644 index 000000000..227008058 Binary files /dev/null and b/server-data/resources/[bpt_addons]/bpt_crafting/html/img/drugs.png differ diff --git a/server-data/resources/[bpt_addons]/bpt_crafting/html/img/fixkit.png b/server-data/resources/[bpt_addons]/bpt_crafting/html/img/fixkit.png index 5a2584ac9..fe07db048 100644 Binary files a/server-data/resources/[bpt_addons]/bpt_crafting/html/img/fixkit.png and b/server-data/resources/[bpt_addons]/bpt_crafting/html/img/fixkit.png differ diff --git a/server-data/resources/[bpt_addons]/bpt_crafting/html/img/manufacturing.png b/server-data/resources/[bpt_addons]/bpt_crafting/html/img/manufacturing.png new file mode 100644 index 000000000..b3f83c29a Binary files /dev/null and b/server-data/resources/[bpt_addons]/bpt_crafting/html/img/manufacturing.png differ diff --git a/server-data/resources/[bpt_addons]/bpt_crafting/html/img/medikit.png b/server-data/resources/[bpt_addons]/bpt_crafting/html/img/medikit.png new file mode 100644 index 000000000..f8aec9cc1 Binary files /dev/null and b/server-data/resources/[bpt_addons]/bpt_crafting/html/img/medikit.png differ diff --git a/server-data/resources/[bpt_addons]/bpt_crafting/html/img/recycled.png b/server-data/resources/[bpt_addons]/bpt_crafting/html/img/recycled.png new file mode 100644 index 000000000..49213ae9e Binary files /dev/null and b/server-data/resources/[bpt_addons]/bpt_crafting/html/img/recycled.png differ diff --git a/server-data/resources/[bpt_addons]/bpt_crafting/html/img/tools.png b/server-data/resources/[bpt_addons]/bpt_crafting/html/img/tools.png new file mode 100644 index 000000000..dd7a83cd2 Binary files /dev/null and b/server-data/resources/[bpt_addons]/bpt_crafting/html/img/tools.png differ diff --git a/server-data/resources/[bpt_addons]/bpt_crafting/localization/bpt_crafting_it.sql b/server-data/resources/[bpt_addons]/bpt_crafting/localization/bpt_crafting_it.sql index cc6f2e1f5..0f0a2d466 100644 --- a/server-data/resources/[bpt_addons]/bpt_crafting/localization/bpt_crafting_it.sql +++ b/server-data/resources/[bpt_addons]/bpt_crafting/localization/bpt_crafting_it.sql @@ -55,5 +55,6 @@ INSERT INTO `bpt_items` (`name`, `label`) VALUES ('cannabis', 'Cannabis'), ('diamond_tip', 'Punta di diamante'), ('diamond', 'Diamond'), - ('marijuana_extract', 'Estratto di marijuana') + ('marijuana_extract', 'Estratto di marijuana'), + ('medikit', 'Medikit') ; \ No newline at end of file diff --git a/server-data/resources/[bpt_addons]/bpt_pointsell/config.lua b/server-data/resources/[bpt_addons]/bpt_pointsell/config.lua index d0b346e65..06c24efb3 100644 --- a/server-data/resources/[bpt_addons]/bpt_pointsell/config.lua +++ b/server-data/resources/[bpt_addons]/bpt_pointsell/config.lua @@ -3,8 +3,8 @@ Config = {} Config.Locale = GetConvar("esx:locale", "it") Config.DealerItems = { - emerald = 200, - diamond = 820, + emerald = 50, + diamond = 150, } Config.GiveBlack = true -- give black money? if disabled it'll give regular cash. diff --git a/server-data/resources/[esx]/es_extended/client/main.lua b/server-data/resources/[esx]/es_extended/client/main.lua index bbfde96c0..32fd0c1a1 100644 --- a/server-data/resources/[esx]/es_extended/client/main.lua +++ b/server-data/resources/[esx]/es_extended/client/main.lua @@ -140,6 +140,7 @@ AddEventHandler("esx:playerLoaded", function(xPlayer, _, skin) for i = 1, 15 do EnableDispatchService(i, false) end + SetAudioFlag('PoliceScannerDisabled', true) end -- Disable Scenarios diff --git a/server-data/resources/[esx]/es_extended/client/modules/actions.lua b/server-data/resources/[esx]/es_extended/client/modules/actions.lua index f762e0c84..ec0f06d31 100644 --- a/server-data/resources/[esx]/es_extended/client/modules/actions.lua +++ b/server-data/resources/[esx]/es_extended/client/modules/actions.lua @@ -91,7 +91,7 @@ CreateThread(function() ToggleVehicleStatus(current.vehicle, current.seat) end elseif isInVehicle then - if not IsPedInAnyVehicle(playerPed, false) or IsPlayerDead(PlayerId()) then + if (current.vehicle ~= GetVehiclePedIsUsing(playerPed)) or IsPlayerDead(PlayerId()) then -- bye, vehicle TriggerEvent("esx:exitedVehicle", current.vehicle, current.plate, current.seat, current.displayName, current.netId) TriggerServerEvent("esx:exitedVehicle", current.plate, current.seat, current.displayName, current.netId) diff --git a/server-data/resources/[esx]/esx_context/index.html b/server-data/resources/[esx]/esx_context/index.html index bb47d5a19..2d0e576f9 100644 --- a/server-data/resources/[esx]/esx_context/index.html +++ b/server-data/resources/[esx]/esx_context/index.html @@ -370,14 +370,20 @@ }); } + const api = { + Open, + Closed, + Close + }; + window.addEventListener("message", (e) => { let data = e.data; - if (!data.func || !window[data.func]) { + if (!data.func || !api.hasOwnProperty(data.func)) { return; } - window[data.func](...data.args); + api[data.func](...data.args); }); window.addEventListener("keydown", (e) => { diff --git a/server-data/resources/[esx_addons]/esx_garage/nui/js/app.js b/server-data/resources/[esx_addons]/esx_garage/nui/js/app.js index 65656e83b..e08b3348f 100644 --- a/server-data/resources/[esx_addons]/esx_garage/nui/js/app.js +++ b/server-data/resources/[esx_addons]/esx_garage/nui/js/app.js @@ -51,17 +51,6 @@ $(window).ready(function() { $('.impounded_content .vehicle-list').empty(); } - // Locales - - // needs a rework - // $(".content h2").html(function (i, text) { - // return text.replace("No vehicle in this garage.", data.locales.no_veh_parking); - // }); - - // $(".impounded_content h2").html(function (i, text) { - // return text.replace("No vehicle impounded.", data.locales.no_veh_impounded); - // }); - $('.vehicle-listing').html(function(_i, text) { return text.replace('Model', data.locales.veh_model); }); @@ -232,4 +221,4 @@ $(window).ready(function() { $('li[data-page="impounded"]').removeClass('selected'); }, ); -}); +}); \ No newline at end of file diff --git a/server-data/resources/[esx_addons]/esx_lumberjack/client/main.lua b/server-data/resources/[esx_addons]/esx_lumberjack/client/main.lua index c2b18e990..9bf061524 100644 --- a/server-data/resources/[esx_addons]/esx_lumberjack/client/main.lua +++ b/server-data/resources/[esx_addons]/esx_lumberjack/client/main.lua @@ -117,11 +117,7 @@ RegisterCommand("cutatree", function() FreezeEntityPosition(PlayerPedId(), true) Citizen.Wait(3000) - lib.callback("map_lumberjack:makeDamage", false, function(data) - if data then - --print('You made damage') - end - end, closest) + lib.callback("map_lumberjack:makeDamage", false, function(data) end, closest) FreezeEntityPosition(PlayerPedId(), false) DeleteObject(axe) diff --git a/server-data/resources/[esx_addons]/esx_lumberjack/server/main.lua b/server-data/resources/[esx_addons]/esx_lumberjack/server/main.lua index eb5190d6d..31e990be8 100644 --- a/server-data/resources/[esx_addons]/esx_lumberjack/server/main.lua +++ b/server-data/resources/[esx_addons]/esx_lumberjack/server/main.lua @@ -18,7 +18,7 @@ lib.callback.register("map_lumberjack:duty", function(source) end) Citizen.CreateThread(function() - for k, v in pairs(Config.Trees) do + for _, v in pairs(Config.Trees) do table.insert(trees, { coords = v, health = 100, diff --git a/server-data/resources/[esx_addons]/esx_property/client/cctv.lua b/server-data/resources/[esx_addons]/esx_property/client/cctv.lua index 1680de982..222c01ade 100644 --- a/server-data/resources/[esx_addons]/esx_property/client/cctv.lua +++ b/server-data/resources/[esx_addons]/esx_property/client/cctv.lua @@ -99,8 +99,8 @@ function CCTV(PropertyID) RenderScriptCams(true, false, 1, true, false) Wait(1000) DoScreenFadeIn(500) - RequestAmbientAudioBank("Phone_Soundset_Franklin", 0, 0) - RequestAmbientAudioBank("HintCamSounds", 0, 0) + RequestAmbientAudioBank("Phone_Soundset_Franklin", false) + RequestAmbientAudioBank("HintCamSounds", false) while IsCamActive(cctvcam) do Wait(5) DisableAllControlActions(0) @@ -209,7 +209,7 @@ function CCTV(PropertyID) if CamTakePic then ShowButtons = false Wait(1) - PlaySoundFrontend(-1, "Camera_Shoot", "Phone_Soundset_Franklin", 1) + PlaySoundFrontend(-1, "Camera_Shoot", "Phone_Soundset_Franklin", true) ESX.TriggerServerCallback("esx_property:GetWebhook", function(hook) if hook then exports["screenshot-basic"]:requestScreenshotUpload(hook, "files[]", function(data) diff --git a/server-data/resources/[esx_addons]/esx_property/client/furniture.lua b/server-data/resources/[esx_addons]/esx_property/client/furniture.lua index fa3e9baf4..477187717 100644 --- a/server-data/resources/[esx_addons]/esx_property/client/furniture.lua +++ b/server-data/resources/[esx_addons]/esx_property/client/furniture.lua @@ -43,7 +43,7 @@ if Config.Furniture.Enabled then local inFurniture = false local CurrentlyEditing = nil - function TempFurniturePlacement(PropertyId, PropName, PropIndex, PropCatagory, PropPrice, Existing, Pos, Heading) + function TempFurniturePlacement(_, PropName, PropIndex, PropCatagory, _, Existing, Pos, Heading) ESX.CloseContext() if CurrentlyEditing then DeleteEntity(CurrentlyEditing) diff --git a/server-data/resources/[esx_addons]/esx_property/config.lua b/server-data/resources/[esx_addons]/esx_property/config.lua index 7327158b1..0506fa6ed 100644 --- a/server-data/resources/[esx_addons]/esx_property/config.lua +++ b/server-data/resources/[esx_addons]/esx_property/config.lua @@ -138,10 +138,10 @@ Config.WardrobeInteraction = function(PropertyId, Interaction) TriggerEvent("skinchanger:getSkin", function(skin) ESX.TriggerServerCallback("esx_property:getPlayerOutfit", function(clothes) TriggerEvent("skinchanger:loadClothes", skin, clothes) - TriggerEvent("esx_skin:setLastSkin", skin) + TriggerEvent("fivem-appearance:setLastSkin", skin) TriggerEvent("skinchanger:getSkin", function(skin) - TriggerServerEvent("esx_skin:save", skin) + TriggerServerEvent("fivem-appearance:save", skin) end) end, element.value) end) diff --git a/server-data/resources/[esx_addons]/esx_property/locales/it.lua b/server-data/resources/[esx_addons]/esx_property/locales/it.lua index 6194ca88d..98cd7a6b5 100644 --- a/server-data/resources/[esx_addons]/esx_property/locales/it.lua +++ b/server-data/resources/[esx_addons]/esx_property/locales/it.lua @@ -109,7 +109,7 @@ Locales["it"] = { ["wardrobe_desc"] = "Cambia posizione del guardaroba della proprietà.", ["furniture_title"] = "Mobili", ["furniture_desc"] = "Cambia posizione dell'arredamento della proprietà.", - ["enter_title"] = "Invio", + ["enter_title"] = "Entra", ["knock_title"] = "Bussa alla porta", ["buy_title"] = "Acquista", ["buy_desc"] = "Compra questa proprietà per $%s", @@ -141,7 +141,7 @@ Locales["it"] = { ["enabled"] = "Abilitato", ["disabled"] = "Disabilitato", ["exiting"] = "Esci dalla proprietà...", - ["entering"] = "Inserimento proprietà...", + ["entering"] = "Entrando nella proprietà...", ["shell_disabled"] = "Questo interno utilizza uno shell, che è disabilitato!", ["access_textui"] = "Premi ~b~[E]~s~ per accedere a ~b~%s", ["raid_notify_error"] = "Hai bisogno di ~b~ %sx %s~s~ per poter invadere la casa!", diff --git a/server-data/resources/[esx_addons]/esx_property/server/main.lua b/server-data/resources/[esx_addons]/esx_property/server/main.lua index db13ab73b..a38cddda0 100644 --- a/server-data/resources/[esx_addons]/esx_property/server/main.lua +++ b/server-data/resources/[esx_addons]/esx_property/server/main.lua @@ -1,12 +1,23 @@ local function Log(title, color, fields, Level) if Level <= Config.Logs.LogLevel then local webHook = Config.Logs.Webhook - local embedData = {{['title'] = title, ['color'] = color, ['footer'] = {['text'] = "ESX-Property | " .. os.date(), - ['icon_url'] = 'https://cdn.discordapp.com/attachments/944789399852417096/1004915039414788116/imageedit_1_2564956129.png'}, - ['fields'] = fields, ['description'] = "", ['author'] = {['name'] = "ESX-Framework | Log Level " .. Level, - ['icon_url'] = 'https://cdn.discordapp.com/emojis/939245183621558362.webp?size=128&quality=lossless'}}} + local embedData = { { + ['title'] = title, + ['color'] = color, + ['footer'] = { + ['text'] = "ESX-Property | " .. os.date(), + ['icon_url'] = + 'https://cdn.discordapp.com/attachments/944789399852417096/1004915039414788116/imageedit_1_2564956129.png' + }, + ['fields'] = fields, + ['description'] = "", + ['author'] = { + ['name'] = "ESX-Framework | Log Level " .. Level, + ['icon_url'] = 'https://cdn.discordapp.com/emojis/939245183621558362.webp?size=128&quality=lossless' + } + } } PerformHttpRequest(webHook, function(err, text, headers) - end, 'POST', json.encode({username = 'ESX-Framework', embeds = embedData}), {['Content-Type'] = 'application/json'}) + end, 'POST', json.encode({ username = 'ESX-Framework', embeds = embedData }), { ['Content-Type'] = 'application/json' }) end end @@ -24,10 +35,10 @@ function PropertiesRefresh() Properties[i].furniture = {} end if not Properties[i].cctv then - Properties[i].cctv = {enabled = false} + Properties[i].cctv = { enabled = false } end if not Properties[i].garage then - Properties[i].garage = {enabled = false} + Properties[i].garage = { enabled = false } end if not Properties[i].garage.StoredVehicles then Properties[i].garage.StoredVehicles = {} @@ -49,8 +60,8 @@ function PropertiesRefresh() end end local Players = ESX.GetExtendedPlayers() - Log("ESX-Property Loaded", 11141375, {{name = "Property Count", value = #Properties, inline = true}, - {name = "OX Inventory", value = Config.OxInventory and "Enabled" or "Disabled", inline = true}}, 1) + Log("ESX-Property Loaded", 11141375, { { name = "Property Count", value = #Properties, inline = true }, + { name = "OX Inventory", value = Config.OxInventory and "Enabled" or "Disabled", inline = true } }, 1) for _, xPlayer in pairs(Players) do TriggerClientEvent("esx_property:syncProperties", xPlayer.source, Properties, xPlayer.get("lastProperty")) end @@ -79,66 +90,72 @@ function IsPlayerAdmin(player, action) end CreateThread(function() - Wait(3000) - PropertiesRefresh() - - MySQL.query("ALTER TABLE `users` ADD COLUMN IF NOT EXISTS `last_property` LONGTEXT NULL", function(result) - if result?.affectedRows > 0 then - print("[^2INFO^7] Added ^5last_property^7 column to users table") - end - end) - - -- Check if datastore table exists before to insert values. - if MySQL.scalar.await("SELECT EXISTS (SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_TYPE LIKE 'BASE TABLE' AND TABLE_NAME = 'datastore')") > 0 then - MySQL.insert("INSERT IGNORE INTO `datastore` (name, label, shared) VALUES ('property', 'Property' , 1)", function(affectedRows) - if affectedRows > 0 then - print("[^2INFO^7] Added ^5Property^7 into ^5datastore^7 table") - end - end) - MySQL.insert("INSERT IGNORE INTO `datastore_data` (name, owner, data) VALUES ('property', NULL, '{}')", function(affectedRows) - if affectedRows > 0 then - print("[^2INFO^7] Added ^5Property^7 into ^5datastore_data^7 table") - end - end) - end - - if PM.Enabled then - if MySQL.scalar.await("SELECT EXISTS (SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_TYPE LIKE 'BASE TABLE' AND TABLE_NAME = 'datastore')") > 0 then - MySQL.insert("INSERT IGNORE INTO `addon_account` (name, label, shared) VALUES (?, ? , 1)", {PM.society, PM.joblabel}, function(affectedRows) - if affectedRows > 0 then - print("[^2INFO^7] Added ^5" .. PM.society .. " - " .. PM.joblabel .. "^7 into ^5addon_account^7 table") - end - end) - end - if not ESX.DoesJobExist(PM.job, 0) then - MySQL.insert("INSERT INTO `jobs` SET name = ?, label = ?, whitelisted = 1", {PM.job, PM.joblabel}, function(affectedRows) - if affectedRows > 0 then - print("[^2INFO^7] Inserted ^5" .. PM.job .. " - " .. PM.joblabel .. "^7 into ^5jobs^7 table") - end - end) - end - - local QUERIES = {} - for i = 1, #PM.jobRanks do - if not ESX.DoesJobExist(PM.job, PM.jobRanks[i].grade) then - QUERIES[i] = { - query = "INSERT INTO `job_grades` SET job_name = ?, grade = ?, name = ?, label = ?, salary = ?, skin_male = '{}', skin_female = '{}'", - parameters = { PM.job, PM.jobRanks[i].grade, PM.jobRanks[i].name, PM.jobRanks[i].label, PM.jobRanks[i].salary } - } - end - end - MySQL.transaction(QUERIES) - - Wait(10) - ESX.RefreshJobs() - exports["bpt_society"]:registerSociety('realestateagent', 'realestateagent', 'society_realestateagent', 'society_realestateagent', 'society_realestateagent', {type = 'private'}) - end + Wait(3000) + PropertiesRefresh() + + MySQL.query("ALTER TABLE `users` ADD COLUMN IF NOT EXISTS `last_property` LONGTEXT NULL", function(result) + if result?.affectedRows > 0 then + print("[^2INFO^7] Added ^5last_property^7 column to users table") + end + end) + + -- Check if datastore table exists before to insert values. + if MySQL.scalar.await("SELECT EXISTS (SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_TYPE LIKE 'BASE TABLE' AND TABLE_NAME = 'datastore')") > 0 then + MySQL.insert("INSERT IGNORE INTO `datastore` (name, label, shared) VALUES ('property', 'Property' , 1)", + function(affectedRows) + if affectedRows > 0 then + print("[^2INFO^7] Added ^5Property^7 into ^5datastore^7 table") + end + end) + MySQL.insert("INSERT IGNORE INTO `datastore_data` (name, owner, data) VALUES ('property', NULL, '{}')", + function(affectedRows) + if affectedRows > 0 then + print("[^2INFO^7] Added ^5Property^7 into ^5datastore_data^7 table") + end + end) + end + + if PM.Enabled then + if MySQL.scalar.await("SELECT EXISTS (SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_TYPE LIKE 'BASE TABLE' AND TABLE_NAME = 'datastore')") > 0 then + MySQL.insert("INSERT IGNORE INTO `addon_account` (name, label, shared) VALUES (?, ? , 1)", + { PM.society, PM.joblabel }, function(affectedRows) + if affectedRows > 0 then + print("[^2INFO^7] Added ^5" .. PM.society .. " - " .. PM.joblabel .. "^7 into ^5addon_account^7 table") + end + end) + end + if not ESX.DoesJobExist(PM.job, 0) then + MySQL.insert("INSERT INTO `jobs` SET name = ?, label = ?, whitelisted = 1", { PM.job, PM.joblabel }, + function(affectedRows) + if affectedRows > 0 then + print("[^2INFO^7] Inserted ^5" .. PM.job .. " - " .. PM.joblabel .. "^7 into ^5jobs^7 table") + end + end) + end + + local QUERIES = {} + for i = 1, #PM.jobRanks do + if not ESX.DoesJobExist(PM.job, PM.jobRanks[i].grade) then + QUERIES[i] = { + query = + "INSERT INTO `job_grades` SET job_name = ?, grade = ?, name = ?, label = ?, salary = ?, skin_male = '{}', skin_female = '{}'", + parameters = { PM.job, PM.jobRanks[i].grade, PM.jobRanks[i].name, PM.jobRanks[i].label, PM.jobRanks[i].salary } + } + end + end + MySQL.transaction(QUERIES) + + Wait(10) + ESX.RefreshJobs() + exports["bpt_society"]:registerSociety('realestateagent', 'realestateagent', 'society_realestateagent', + 'society_realestateagent', 'society_realestateagent', { type = 'private' }) + end end) AddEventHandler("esx:playerLoaded", function(playerId, xPlayer) Wait(1000) local lastProperty = nil - MySQL.query("SELECT last_property FROM users WHERE identifier = ?", {xPlayer.identifier}, function(result) + MySQL.query("SELECT last_property FROM users WHERE identifier = ?", { xPlayer.identifier }, function(result) if result then if result[1].last_property then local Data = json.decode(result[1].last_property) @@ -153,17 +170,17 @@ end) --- Commands ESX.RegisterCommand(_("refresh_name"), Config.AllowedGroups, function(xPlayer) PropertiesRefresh() -end, false, {help = TranslateCap("refresh_desc")}) +end, false, { help = TranslateCap("refresh_desc") }) ESX.RegisterCommand(_("create_name"), "user", function(xPlayer) if IsPlayerAdmin(xPlayer.source) or (PM.Enabled and xPlayer.job.name == PM.job) then xPlayer.triggerEvent("esx_property:CreateProperty") end -end, false,{help = TranslateCap("create_desc")}) +end, false, { help = TranslateCap("create_desc") }) ESX.RegisterCommand(_("admin_name"), Config.AllowedGroups, function(xPlayer) xPlayer.triggerEvent("esx_property:AdminMenu") -end, false,{help = TranslateCap("admin_desc")}) +end, false, { help = TranslateCap("admin_desc") }) -- Buy Property ESX.RegisterServerCallback("esx_property:buyProperty", function(source, cb, PropertyId) @@ -174,12 +191,13 @@ ESX.RegisterServerCallback("esx_property:buyProperty", function(source, cb, Prop Properties[PropertyId].Owner = xPlayer.identifier Properties[PropertyId].OwnerName = xPlayer.getName() Properties[PropertyId].Owned = true - Log("Property Bought", 65280, {{name = "**Property Name**", value = Properties[PropertyId].Name, inline = true}, - {name = "**Price**", value = ESX.Math.GroupDigits(Price), inline = true}, - {name = "**Player**", value = xPlayer.getName(), inline = true}}, 1) + Log("Property Bought", 65280, { { name = "**Property Name**", value = Properties[PropertyId].Name, inline = true }, + { name = "**Price**", value = ESX.Math.GroupDigits(Price), inline = true }, + { name = "**Player**", value = xPlayer.getName(), inline = true } }, 1) TriggerClientEvent("esx_property:syncProperties", -1, Properties) if Config.OxInventory then - exports.ox_inventory:RegisterStash("property-" .. PropertyId, Properties[PropertyId].Name, 15, 100000, xPlayer.identifier) + exports.ox_inventory:RegisterStash("property-" .. PropertyId, Properties[PropertyId].Name, 15, 100000, + xPlayer.identifier) end end cb(xPlayer.getAccount("bank").money >= Price) @@ -194,13 +212,15 @@ ESX.RegisterServerCallback("esx_property:attemptSellToPlayer", function(source, Properties[PropertyId].Owner = xTarget.identifier Properties[PropertyId].OwnerName = xTarget.getName() Properties[PropertyId].Owned = true - Log("Property Sold To Player", 65280, {{name = "**Property Name**", value = Properties[PropertyId].Name, inline = true}, - {name = "**Price**", value = ESX.Math.GroupDigits(Price), inline = true}, - {name = "**Player**", value = xTarget.getName(), inline = true}, - {name = "**Agent**", value = xPlayer.getName(), inline = true}}, 1) + Log("Property Sold To Player", 65280, + { { name = "**Property Name**", value = Properties[PropertyId].Name, inline = true }, + { name = "**Price**", value = ESX.Math.GroupDigits(Price), inline = true }, + { name = "**Player**", value = xTarget.getName(), inline = true }, + { name = "**Agent**", value = xPlayer.getName(), inline = true } }, 1) TriggerClientEvent("esx_property:syncProperties", -1, Properties) if Config.OxInventory then - exports.ox_inventory:RegisterStash("property-" .. PropertyId, Properties[PropertyId].Name, 15, 100000, xTarget.identifier) + exports.ox_inventory:RegisterStash("property-" .. PropertyId, Properties[PropertyId].Name, 15, 100000, + xTarget.identifier) end if PM.Enabled then local PlayerPrice = Price * PM.SalePercentage @@ -215,38 +235,47 @@ ESX.RegisterServerCallback("esx_property:attemptSellToPlayer", function(source, end) -- Buy Property -ESX.RegisterServerCallback("esx_property:buyFurniture", function(source, cb, PropertyId, PropName, PropIndex, PropCatagory, pos, heading) - local xPlayer = ESX.GetPlayerFromId(source) - local Owner = Properties[PropertyId].Owner - if xPlayer.identifier == Owner or IsPlayerAdmin(source) or (Properties[PropertyId].Keys and Properties[PropertyId].Keys[xPlayer.identifier]) then - local Price = Config.FurnitureCatagories[PropCatagory][PropIndex].price - if xPlayer.getAccount("bank").money >= Price then - xPlayer.removeAccountMoney("bank", Price, "Furniture") - cb(true) - local furniture = {Name = PropName, Index = PropIndex, Catagory = PropCatagory, Pos = pos, Heading = heading, Price = Price} - table.insert(Properties[PropertyId].furniture, furniture) - for i = 1, #Properties[PropertyId].plysinside do - TriggerClientEvent("esx_property:placeFurniture", Properties[PropertyId].plysinside[i], PropertyId, furniture, - #Properties[PropertyId].furniture) +ESX.RegisterServerCallback("esx_property:buyFurniture", + function(source, cb, PropertyId, PropName, PropIndex, PropCatagory, pos, heading) + local xPlayer = ESX.GetPlayerFromId(source) + local Owner = Properties[PropertyId].Owner + if xPlayer.identifier == Owner or IsPlayerAdmin(source) or (Properties[PropertyId].Keys and Properties[PropertyId].Keys[xPlayer.identifier]) then + local Price = Config.FurnitureCatagories[PropCatagory][PropIndex].price + if xPlayer.getAccount("bank").money >= Price then + xPlayer.removeAccountMoney("bank", Price, "Furniture") + cb(true) + local furniture = { Name = PropName, Index = PropIndex, Catagory = PropCatagory, Pos = pos, Heading = heading, Price = + Price } + table.insert(Properties[PropertyId].furniture, furniture) + for i = 1, #Properties[PropertyId].plysinside do + TriggerClientEvent("esx_property:placeFurniture", Properties[PropertyId].plysinside[i], PropertyId, furniture, + #Properties[PropertyId].furniture) + end + TriggerClientEvent("esx_property:syncFurniture", -1, PropertyId, Properties[PropertyId].furniture) + else + cb(false) + ESX.ShowNotification(TranslateCap("furni_cannot_afford")) end - TriggerClientEvent("esx_property:syncFurniture", -1, PropertyId, Properties[PropertyId].furniture) else cb(false) - ESX.ShowNotification(TranslateCap("furni_cannot_afford")) end - else - cb(false) - end - Log("Furniture Bought", 3640511, - {{name = "**Property Name**", value = Properties[PropertyId].Name, inline = true}, - {name = "**Player**", value = xPlayer.getName(), inline = true}, {name = "**Has Access**", - value = (xPlayer.identifier == Owner or IsPlayerAdmin(source) or - (Properties[PropertyId].Keys and Properties[PropertyId].Keys[xPlayer.identifier])) and "Yes" or "No", inline = true}, - {name = "**Prop Name**", value = Config.FurnitureCatagories[PropCatagory][PropIndex].title, inline = true}, - {name = "**Price**", value = tostring(Config.FurnitureCatagories[PropCatagory][PropIndex].price), inline = true}, - {name = "**Can Afford**", - value = xPlayer.getAccount("bank").money >= Config.FurnitureCatagories[PropCatagory][PropIndex].price and "Yes" or "No", inline = true}}, 1) -end) + Log("Furniture Bought", 3640511, + { { name = "**Property Name**", value = Properties[PropertyId].Name, inline = true }, + { name = "**Player**", value = xPlayer.getName(), inline = true }, { + name = "**Has Access**", + value = (xPlayer.identifier == Owner or IsPlayerAdmin(source) or + (Properties[PropertyId].Keys and Properties[PropertyId].Keys[xPlayer.identifier])) and "Yes" or "No", + inline = true + }, + { name = "**Prop Name**", value = Config.FurnitureCatagories[PropCatagory][PropIndex].title, inline = true }, + { name = "**Price**", value = tostring(Config.FurnitureCatagories[PropCatagory][PropIndex].price), inline = true }, + { + name = "**Can Afford**", + value = xPlayer.getAccount("bank").money >= Config.FurnitureCatagories[PropCatagory][PropIndex].price and "Yes" or + "No", + inline = true + } }, 1) + end) -- Selling Property @@ -269,11 +298,12 @@ ESX.RegisterServerCallback("esx_property:sellProperty", function(source, cb, Pro Properties[PropertyId].setName = "" end Properties[PropertyId].plysinside = {} - Log("Property Sold", 16711680, {{name = "**Property Name**", value = Properties[PropertyId].Name, inline = true}, - {name = "**Price**", value = ESX.Math.GroupDigits(Price), inline = true}, - {name = "**Owner**", value = xPlayer.getName(), inline = true}, - {name = "**Furniture Count**", value = tostring(furn), inline = true}, - {name = "**Vehicle Count**", value = tostring(Properties[PropertyId].garage.StoredVehicles and #Properties[PropertyId].garage.StoredVehicles or "N/A"), inline = true}}, 1) + Log("Property Sold", 16711680, { { name = "**Property Name**", value = Properties[PropertyId].Name, inline = true }, + { name = "**Price**", value = ESX.Math.GroupDigits(Price), inline = true }, + { name = "**Owner**", value = xPlayer.getName(), inline = true }, + { name = "**Furniture Count**", value = tostring(furn), inline = true }, + { name = "**Vehicle Count**", value = tostring(Properties[PropertyId].garage.StoredVehicles and #Properties[PropertyId].garage.StoredVehicles or "N/A"), inline = true } }, + 1) if Properties[PropertyId].garage.StoredVehicles then Properties[PropertyId].garage.StoredVehicles = {} end @@ -291,16 +321,16 @@ ESX.RegisterServerCallback("esx_property:toggleLock", function(source, cb, Prope local xPlayer = ESX.GetPlayerFromId(source) local Owner = Properties[PropertyId].Owner if xPlayer.identifier == Owner or IsPlayerAdmin(source, "ToggleLock") or - (Properties[PropertyId].Keys and Properties[PropertyId].Keys[xPlayer.identifier]) then + (Properties[PropertyId].Keys and Properties[PropertyId].Keys[xPlayer.identifier]) then Properties[PropertyId].Locked = not Properties[PropertyId].Locked TriggerClientEvent("esx_property:syncProperties", -1, Properties) end - Log("Lock Toggled", 3640511, {{name = "**Property Name**", value = Properties[PropertyId].Name, inline = true}, - {name = "**Owner**", value = Properties[PropertyId].OwnerName, inline = true}, - {name = "**Executing User**", value = xPlayer.getName(), inline = true}, - {name = "**Status**", value = Properties[PropertyId].Locked and "Locked" or "Unlocked", inline = true}}, 3) + Log("Lock Toggled", 3640511, { { name = "**Property Name**", value = Properties[PropertyId].Name, inline = true }, + { name = "**Owner**", value = Properties[PropertyId].OwnerName, inline = true }, + { name = "**Executing User**", value = xPlayer.getName(), inline = true }, + { name = "**Status**", value = Properties[PropertyId].Locked and "Locked" or "Unlocked", inline = true } }, 3) cb(xPlayer.identifier == Owner or IsPlayerAdmin(source, "ToggleLock") or - (Properties[PropertyId].Keys and Properties[PropertyId].Keys[xPlayer.identifier])) + (Properties[PropertyId].Keys and Properties[PropertyId].Keys[xPlayer.identifier])) end) ESX.RegisterServerCallback("esx_property:toggleGarage", function(source, cb, PropertyId) @@ -308,11 +338,15 @@ ESX.RegisterServerCallback("esx_property:toggleGarage", function(source, cb, Pro if IsPlayerAdmin(source, "ToggleGarage") then Properties[PropertyId].garage.enabled = not Properties[PropertyId].garage.enabled TriggerClientEvent("esx_property:syncProperties", -1, Properties) - Log("Property Garage Toggled", 3640511, {{name = "**Property Name**", value = Properties[PropertyId].Name, inline = true}, - {name = "**Owner**", value = Properties[PropertyId].OwnerName, inline = true}, - {name = "**Admin**", value = xPlayer.getName(), inline = true}, - {name = "**Status**", value = Properties[PropertyId].garage.enabled and "Enabled" or "Disabled", - inline = true}}, 2) + Log("Property Garage Toggled", 3640511, + { { name = "**Property Name**", value = Properties[PropertyId].Name, inline = true }, + { name = "**Owner**", value = Properties[PropertyId].OwnerName, inline = true }, + { name = "**Admin**", value = xPlayer.getName(), inline = true }, + { + name = "**Status**", + value = Properties[PropertyId].garage.enabled and "Enabled" or "Disabled", + inline = true + } }, 2) cb(true, Properties[PropertyId].garage.enabled) else cb(false) @@ -325,11 +359,15 @@ ESX.RegisterServerCallback("esx_property:toggleCCTV", function(source, cb, Prope Properties[PropertyId].cctv.enabled = not Properties[PropertyId].cctv.enabled TriggerClientEvent("esx_property:syncProperties", -1, Properties) cb(true, Properties[PropertyId].cctv.enabled) - Log("Property CCTV Toggled", 3640511, {{name = "**Property Name**", value = Properties[PropertyId].Name, inline = true}, - {name = "**Owner**", value = Properties[PropertyId].OwnerName, inline = true}, - {name = "**Admin**", value = xPlayer.getName(), inline = true}, - {name = "**Status**", value = Properties[PropertyId].cctv.enabled and "Enabled" or "Disabled", - inline = true}}, 2) + Log("Property CCTV Toggled", 3640511, + { { name = "**Property Name**", value = Properties[PropertyId].Name, inline = true }, + { name = "**Owner**", value = Properties[PropertyId].OwnerName, inline = true }, + { name = "**Admin**", value = xPlayer.getName(), inline = true }, + { + name = "**Status**", + value = Properties[PropertyId].cctv.enabled and "Enabled" or "Disabled", + inline = true + } }, 2) else cb(false) end @@ -341,15 +379,18 @@ ESX.RegisterServerCallback("esx_property:SetGaragePos", function(source, cb, Pro local PlayerPed = GetPlayerPed(source) local PlayerPos = GetEntityCoords(PlayerPed) local Property = Properties[PropertyId] - local Original = Properties[PropertyId].garage.pos and Properties[PropertyId].garage.pos.x .. ", " .. Properties[PropertyId].garage.pos.y .. ", " .. Properties[PropertyId].garage.pos.z or "N/A" + local Original = Properties[PropertyId].garage.pos and + Properties[PropertyId].garage.pos.x .. + ", " .. Properties[PropertyId].garage.pos.y .. ", " .. Properties[PropertyId].garage.pos.z or "N/A" Properties[PropertyId].garage.pos = PlayerPos Properties[PropertyId].garage.Heading = heading TriggerClientEvent("esx_property:syncProperties", -1, Properties) - Log("Property Garage Location Changed", 3640511, {{name = "**Property Name**", value = Properties[PropertyId].Name, inline = true}, - {name = "**Owner**", value = Properties[PropertyId].OwnerName, inline = true}, - {name = "**Admin**", value = xPlayer.getName(), inline = true}, - {name = "**Original Position**", value = tostring(Original), inline = true}, - {name = "**New Position**", value = tostring(PlayerPos), inline = true}}, 2) + Log("Property Garage Location Changed", 3640511, + { { name = "**Property Name**", value = Properties[PropertyId].Name, inline = true }, + { name = "**Owner**", value = Properties[PropertyId].OwnerName, inline = true }, + { name = "**Admin**", value = xPlayer.getName(), inline = true }, + { name = "**Original Position**", value = tostring(Original), inline = true }, + { name = "**New Position**", value = tostring(PlayerPos), inline = true } }, 2) cb(true) else cb(false) @@ -365,9 +406,10 @@ ESX.RegisterServerCallback("esx_property:SetCCTVangle", function(source, cb, Pro Properties[PropertyId].cctv.maxright = angles.maxright TriggerClientEvent("esx_property:syncProperties", -1, Properties) cb(true) - Log("Property CCTV Angle Changed", 3640511, {{name = "**Property Name**", value = Properties[PropertyId].Name, inline = true}, - {name = "**Owner**", value = Properties[PropertyId].OwnerName, inline = true}, - {name = "**Admin**", value = xPlayer.getName(), inline = true}}, 2) + Log("Property CCTV Angle Changed", 3640511, + { { name = "**Property Name**", value = Properties[PropertyId].Name, inline = true }, + { name = "**Owner**", value = Properties[PropertyId].OwnerName, inline = true }, + { name = "**Admin**", value = xPlayer.getName(), inline = true } }, 2) else cb(false) end @@ -381,9 +423,10 @@ ESX.RegisterServerCallback("esx_property:CCTV", function(source, cb, PropertyId) SetEntityCoords(GetPlayerPed(source), vector3(Property.Entrance.x, Property.Entrance.y, Property.Entrance.z + 5.0)) SetPlayerRoutingBucket(source, 0) end - Log("Player Entered CCTV", 3640511, {{name = "**Property Name**", value = Properties[PropertyId].Name, inline = true}, - {name = "**Player**", value = xPlayer.getName(), inline = true}}, 3) - cb(xPlayer.identifier == Owner or IsPlayerAdmin(source) or (Properties[PropertyId].Keys and Properties[PropertyId].Keys[xPlayer.identifier])) + Log("Player Entered CCTV", 3640511, { { name = "**Property Name**", value = Properties[PropertyId].Name, inline = true }, + { name = "**Player**", value = xPlayer.getName(), inline = true } }, 3) + cb(xPlayer.identifier == Owner or IsPlayerAdmin(source) or + (Properties[PropertyId].Keys and Properties[PropertyId].Keys[xPlayer.identifier])) end) ESX.RegisterServerCallback("esx_property:ExitCCTV", function(source, cb, PropertyId) @@ -399,9 +442,10 @@ ESX.RegisterServerCallback("esx_property:ExitCCTV", function(source, cb, Propert end SetPlayerRoutingBucket(source, PropertyId + 1) end - Log("Player Exited CCTV", 3640511, {{name = "**Property Name**", value = Properties[PropertyId].Name, inline = true}, - {name = "**Player**", value = xPlayer.getName(), inline = true}}, 3) - cb(xPlayer.identifier == Owner or IsPlayerAdmin(source) or (Properties[PropertyId].Keys and Properties[PropertyId].Keys[xPlayer.identifier])) + Log("Player Exited CCTV", 3640511, { { name = "**Property Name**", value = Properties[PropertyId].Name, inline = true }, + { name = "**Player**", value = xPlayer.getName(), inline = true } }, 3) + cb(xPlayer.identifier == Owner or IsPlayerAdmin(source) or + (Properties[PropertyId].Keys and Properties[PropertyId].Keys[xPlayer.identifier])) end) ESX.RegisterServerCallback("esx_property:SetPropertyName", function(source, cb, PropertyId, name) @@ -413,11 +457,13 @@ ESX.RegisterServerCallback("esx_property:SetPropertyName", function(source, cb, Properties[PropertyId].setName = name TriggerClientEvent("esx_property:syncProperties", -1, Properties) Log("Property Name Changed", 3640511, - {{name = "**Property Name**", value = Properties[PropertyId].Name, inline = true}, - {name = "**Player**", value = xPlayer.getName(), inline = true}, {name = "**New Name**", value = name, inline = true}}, 2) + { { name = "**Property Name**", value = Properties[PropertyId].Name, inline = true }, + { name = "**Player**", value = xPlayer.getName(), inline = true }, { name = "**New Name**", value = name, inline = true } }, + 2) end end - cb((xPlayer.identifier == Owner or IsPlayerAdmin(source, "SetPropertyName")) and name and #name <= Config.MaxNameLength) + cb((xPlayer.identifier == Owner or IsPlayerAdmin(source, "SetPropertyName")) and name and #name <= Config + .MaxNameLength) end) ESX.RegisterServerCallback("esx_property:KnockOnDoor", function(source, cb, PropertyId, name) @@ -429,9 +475,10 @@ ESX.RegisterServerCallback("esx_property:KnockOnDoor", function(source, cb, Prop if Property.plysinside[i] == Owner.source then Owner.showNotification(TranslateCap("knocking"), "info") cb(true) - Log("Player Knocked On Door", 3640511, {{name = "**Property Name**", value = Properties[PropertyId].Name, inline = true}, - {name = "**Owner**", value = Properties[PropertyId].OwnerName, inline = true}, - {name = "**Player**", value = xPlayer.getName(), inline = true}}, 3) + Log("Player Knocked On Door", 3640511, + { { name = "**Property Name**", value = Properties[PropertyId].Name, inline = true }, + { name = "**Owner**", value = Properties[PropertyId].OwnerName, inline = true }, + { name = "**Player**", value = xPlayer.getName(), inline = true } }, 3) end end cb(false) @@ -447,10 +494,11 @@ ESX.RegisterServerCallback("esx_property:RemoveCustomName", function(source, cb, local n = Properties[PropertyId].setName Properties[PropertyId].setName = "" TriggerClientEvent("esx_property:syncProperties", -1, Properties) - Log("Property Name Reset", 3640511, {{name = "**Property Name**", value = Properties[PropertyId].Name, inline = true}, - {name = "**Owner**", value = Properties[PropertyId].OwnerName, inline = true}, - {name = "**Admin**", value = xPlayer.getName(), inline = true}, - {name = "**Removed Name**", value = n, inline = true}}, 3) + Log("Property Name Reset", 3640511, + { { name = "**Property Name**", value = Properties[PropertyId].Name, inline = true }, + { name = "**Owner**", value = Properties[PropertyId].OwnerName, inline = true }, + { name = "**Admin**", value = xPlayer.getName(), inline = true }, + { name = "**Removed Name**", value = n, inline = true } }, 3) cb(true) else cb(false) @@ -461,11 +509,12 @@ ESX.RegisterServerCallback("esx_property:deleteProperty", function(source, cb, P local xPlayer = ESX.GetPlayerFromId(source) if IsPlayerAdmin(source, "DeleteProperty") then Log("Property Deleted", 16711680, - {{name = "**Property Name**", value = Properties[PropertyId].Name, inline = true}, - {name = "**Admin**", value = xPlayer.getName(), inline = true}, - {name = "**Owner**", value = Properties[PropertyId].OwnerName ~= "" and Properties[PropertyId].OwnerName or "N/A", inline = true}, - {name = "**Furniture Count**", value = #(Properties[PropertyId].furniture), inline = true}, - {name = "**Vehicle Count**", value = Properties[PropertyId].garage.StoredVehicles and #(Properties[PropertyId].garage.StoredVehicles) or "N/A", inline = true}}, 1) + { { name = "**Property Name**", value = Properties[PropertyId].Name, inline = true }, + { name = "**Admin**", value = xPlayer.getName(), inline = true }, + { name = "**Owner**", value = Properties[PropertyId].OwnerName ~= "" and Properties[PropertyId].OwnerName or "N/A", inline = true }, + { name = "**Furniture Count**", value = #(Properties[PropertyId].furniture), inline = true }, + { name = "**Vehicle Count**", value = Properties[PropertyId].garage.StoredVehicles and #(Properties[PropertyId].garage.StoredVehicles) or "N/A", inline = true } }, + 1) table.remove(Properties, PropertyId) TriggerClientEvent("esx_property:syncProperties", -1, Properties) if Config.OxInventory then @@ -482,9 +531,9 @@ ESX.RegisterServerCallback("esx_property:ChangePrice", function(source, cb, Prop Properties[PropertyId].Price = NewPrice TriggerClientEvent("esx_property:syncProperties", -1, Properties) Log("Property Price Changed", 3640511, - {{name = "**Property Name**", value = Properties[PropertyId].Name, inline = true}, - {name = "**Admin**", value = xPlayer.getName(), inline = true}, {name = "**Original Price**", value = tostring(Original), inline = true}, - {name = "**New Price**", value = tostring(NewPrice), inline = true}}, 2) + { { name = "**Property Name**", value = Properties[PropertyId].Name, inline = true }, + { name = "**Admin**", value = xPlayer.getName(), inline = true }, { name = "**Original Price**", value = tostring(Original), inline = true }, + { name = "**New Price**", value = tostring(NewPrice), inline = true } }, 2) end cb(IsPlayerAdmin(source, "SetPropertyPrice")) end) @@ -501,9 +550,10 @@ ESX.RegisterServerCallback("esx_property:ChangeInterior", function(source, cb, P end TriggerClientEvent("esx_property:syncProperties", -1, Properties) Log("Property Interior Changed", 3640511, - {{name = "**Property Name**", value = Properties[PropertyId].Name, inline = true}, - {name = "**Admin**", value = xPlayer.getName(), inline = true}, {name = "**Original**", value = tostring(Original), inline = true}, - {name = "**New Interior**", value = GetInteriorValues(Properties[PropertyId].Interior).label, inline = true}}, 2) + { { name = "**Property Name**", value = Properties[PropertyId].Name, inline = true }, + { name = "**Admin**", value = xPlayer.getName(), inline = true }, { name = "**Original**", value = tostring(Original), inline = true }, + { name = "**New Interior**", value = GetInteriorValues(Properties[PropertyId].Interior).label, inline = true } }, + 2) end cb(IsPlayerAdmin(source, "ChangeInterior")) end) @@ -512,7 +562,7 @@ ESX.RegisterServerCallback("esx_property:RemoveAllfurniture", function(source, c local xPlayer = ESX.GetPlayerFromId(source) local Owner = Properties[PropertyId].Owner if xPlayer.identifier == Owner or IsPlayerAdmin(source, "ResetFurniture") or - (Properties[PropertyId].Keys and Properties[PropertyId].Keys[xPlayer.identifier]) then + (Properties[PropertyId].Keys and Properties[PropertyId].Keys[xPlayer.identifier]) then for i = 1, #Properties[PropertyId].plysinside do for furniture = 1, #Properties[PropertyId].furniture do TriggerClientEvent("esx_property:removeFurniture", Properties[PropertyId].plysinside[i], PropertyId, furniture) @@ -521,10 +571,11 @@ ESX.RegisterServerCallback("esx_property:RemoveAllfurniture", function(source, c Properties[PropertyId].furniture = {} TriggerClientEvent("esx_property:syncFurniture", -1, PropertyId, Properties[PropertyId].furniture) end - Log("Property Furniture Reset", 16711680, {{name = "**Property Name**", value = Properties[PropertyId].Name, inline = true}, - {name = "**Admin**", value = xPlayer.getName(), inline = true}}, 1) + Log("Property Furniture Reset", 16711680, + { { name = "**Property Name**", value = Properties[PropertyId].Name, inline = true }, + { name = "**Admin**", value = xPlayer.getName(), inline = true } }, 1) cb(xPlayer.identifier == Owner or IsPlayerAdmin(source, "ResetFurniture") or - (Properties[PropertyId].Keys and Properties[PropertyId].Keys[xPlayer.identifier])) + (Properties[PropertyId].Keys and Properties[PropertyId].Keys[xPlayer.identifier])) end) ESX.RegisterServerCallback("esx_property:deleteFurniture", function(source, cb, PropertyId, furnitureIndex) @@ -540,9 +591,10 @@ ESX.RegisterServerCallback("esx_property:deleteFurniture", function(source, cb, end end Log("Property Furniture Deleted", 16711680, - {{name = "**Property Name**", value = Properties[PropertyId].Name, inline = true}, {name = "**Admin**", value = xPlayer.getName(), inline = true}, - {name = "**Furniture Name**", value = xPlayer.getName(), inline = true}}, 3) - cb(xPlayer.identifier == Owner or IsPlayerAdmin(source) or (Properties[PropertyId].Keys and Properties[PropertyId].Keys[xPlayer.identifier])) + { { name = "**Property Name**", value = Properties[PropertyId].Name, inline = true }, { name = "**Admin**", value = xPlayer.getName(), inline = true }, + { name = "**Furniture Name**", value = xPlayer.getName(), inline = true } }, 3) + cb(xPlayer.identifier == Owner or IsPlayerAdmin(source) or + (Properties[PropertyId].Keys and Properties[PropertyId].Keys[xPlayer.identifier])) end) ESX.RegisterServerCallback("esx_property:editFurniture", function(source, cb, PropertyId, furnitureIndex, Pos, Heading) @@ -554,11 +606,13 @@ ESX.RegisterServerCallback("esx_property:editFurniture", function(source, cb, Pr Properties[PropertyId].furniture[furnitureIndex].Heading = Heading TriggerClientEvent("esx_property:syncFurniture", -1, PropertyId, Properties[PropertyId].furniture) for i = 1, #Properties[PropertyId].plysinside do - TriggerClientEvent("esx_property:editFurniture", Properties[PropertyId].plysinside[i], PropertyId, furnitureIndex, Pos, Heading) + TriggerClientEvent("esx_property:editFurniture", Properties[PropertyId].plysinside[i], PropertyId, furnitureIndex, + Pos, Heading) end end end - cb(xPlayer.identifier == Owner or IsPlayerAdmin(source) or (Properties[PropertyId].Keys and Properties[PropertyId].Keys[xPlayer.identifier])) + cb(xPlayer.identifier == Owner or IsPlayerAdmin(source) or + (Properties[PropertyId].Keys and Properties[PropertyId].Keys[xPlayer.identifier])) end) ESX.RegisterServerCallback("esx_property:evictOwner", function(source, cb, PropertyId, Interior) @@ -587,9 +641,9 @@ ESX.RegisterServerCallback("esx_property:evictOwner", function(source, cb, Prope exports.ox_inventory:ClearInventory("property-" .. PropertyId) end Log("Property Owner Evicted", 3640511, - {{name = "**Property Name**", value = Properties[PropertyId].Name, inline = true}, {name = "**Owner**", value = pName, inline = true}, - {name = "**Admin**", value = xPlayer.getName(), inline = true}, - {name = "**Has Access**", value = IsPlayerAdmin(source, "EvictOwner") and "Yes" or "No", inline = true}}, 1) + { { name = "**Property Name**", value = Properties[PropertyId].Name, inline = true }, { name = "**Owner**", value = pName, inline = true }, + { name = "**Admin**", value = xPlayer.getName(), inline = true }, + { name = "**Has Access**", value = IsPlayerAdmin(source, "EvictOwner") and "Yes" or "No", inline = true } }, 1) end cb(IsPlayerAdmin(source, "EvictOwner")) end) @@ -607,7 +661,9 @@ ESX.RegisterServerCallback("esx_property:CanRaid", function(source, cb, Property end Can = true else - xPlayer.showNotification(TranslateCap("raid_notify_error", Config.Raiding.ItemRequired.ItemCount, Config.Raiding.ItemRequired.name), "error") + xPlayer.showNotification( + TranslateCap("raid_notify_error", Config.Raiding.ItemRequired.ItemCount, Config.Raiding.ItemRequired.name), + "error") end else Can = true @@ -629,17 +685,26 @@ end) ESX.RegisterServerCallback("esx_property:ChangeEntrance", function(source, cb, PropertyId, Coords) local xPlayer = ESX.GetPlayerFromId(source) if IsPlayerAdmin(source, "ChangeEntrance") then - local Origonal = Properties[PropertyId].Entrance.x .. "," .. Properties[PropertyId].Entrance.y .. "," .. Properties[PropertyId].Entrance.z - Properties[PropertyId].Entrance = {x = ESX.Math.Round(Coords.x, 2), y = ESX.Math.Round(Coords.y, 2), z = ESX.Math.Round(Coords.z, 2) - 0.8} + local Origonal = Properties[PropertyId].Entrance.x .. + "," .. Properties[PropertyId].Entrance.y .. "," .. Properties[PropertyId].Entrance.z + Properties[PropertyId].Entrance = { x = ESX.Math.Round(Coords.x, 2), y = ESX.Math.Round(Coords.y, 2), z = ESX.Math + .Round(Coords.z, 2) - 0.8 } TriggerClientEvent("esx_property:syncProperties", -1, Properties) - Log("Property Entrance Changed", 3640511, {{name = "**Property Name**", value = Properties[PropertyId].Name, inline = true}, - {name = "**Owner**", value = Properties[PropertyId].OwnerName, inline = true}, - {name = "**Admin**", value = xPlayer.getName(), inline = true}, - {name = "**Has Access**", value = IsPlayerAdmin(source, "ChangeEntrance") and "Yes" or "No", - inline = true}, {name = "**Original**", value = Origonal, inline = true}, - {name = "**New**", - value = Properties[PropertyId].Entrance.x .. "," .. Properties[PropertyId].Entrance.y .. "," .. - Properties[PropertyId].Entrance.z, inline = true}}, 1) + Log("Property Entrance Changed", 3640511, + { { name = "**Property Name**", value = Properties[PropertyId].Name, inline = true }, + { name = "**Owner**", value = Properties[PropertyId].OwnerName, inline = true }, + { name = "**Admin**", value = xPlayer.getName(), inline = true }, + { + name = "**Has Access**", + value = IsPlayerAdmin(source, "ChangeEntrance") and "Yes" or "No", + inline = true + }, { name = "**Original**", value = Origonal, inline = true }, + { + name = "**New**", + value = Properties[PropertyId].Entrance.x .. "," .. Properties[PropertyId].Entrance.y .. "," .. + Properties[PropertyId].Entrance.z, + inline = true + } }, 1) end cb(IsPlayerAdmin(source, "ChangeEntrance")) end) @@ -651,24 +716,32 @@ ESX.RegisterServerCallback("esx_property:SetInventoryPosition", function(source, if IsPlayerAdmin(source, "EditInteriorPositions") or (Property.Owner == xPlayer.identifier or Properties[PropertyId].Keys[xPlayer.identifier]) then local Interior = GetInteriorValues(Property.Interior) if Reset then - Properties[PropertyId].positions.Storage = {x = ESX.Math.Round(Coords.x, 2), y = ESX.Math.Round(Coords.y, 2), z = ESX.Math.Round(Coords.z, 2)} + Properties[PropertyId].positions.Storage = { x = ESX.Math.Round(Coords.x, 2), y = ESX.Math.Round(Coords.y, 2), z = + ESX.Math.Round(Coords.z, 2) } else if Interior.type == "ipl" then - Properties[PropertyId].positions.Storage = {x = ESX.Math.Round(Coords.x, 2), y = ESX.Math.Round(Coords.y, 2), - z = ESX.Math.Round(Coords.z, 2)} + Properties[PropertyId].positions.Storage = { + x = ESX.Math.Round(Coords.x, 2), + y = ESX.Math.Round(Coords.y, 2), + z = ESX.Math.Round(Coords.z, 2) + } else Properties[PropertyId].positions.Storage = vector3(Property.Entrance.x, Property.Entrance.y, 2000) - Coords end end Log("Property Storage Location Set", 3640511, - {{name = "**Property Name**", value = Property.Name, inline = true}, {name = "**Owner**", value = Property.OwnerName, inline = true}, - {name = "**Player**", value = xPlayer.getName(), inline = true}, {name = "**Has Access**", - value = (IsPlayerAdmin(source, "EditInteriorPositions") or - (Property.Owner == xPlayer.identifier or Properties[PropertyId].Keys[xPlayer.identifier])) and "Yes" or "No", inline = true}, - {name = "**Reset?**", value = Reset and "Yes" or "No", inline = true}}, 1) + { { name = "**Property Name**", value = Property.Name, inline = true }, { name = "**Owner**", value = Property.OwnerName, inline = true }, + { name = "**Player**", value = xPlayer.getName(), inline = true }, { + name = "**Has Access**", + value = (IsPlayerAdmin(source, "EditInteriorPositions") or + (Property.Owner == xPlayer.identifier or Properties[PropertyId].Keys[xPlayer.identifier])) and "Yes" or "No", + inline = true + }, + { name = "**Reset?**", value = Reset and "Yes" or "No", inline = true } }, 1) TriggerClientEvent("esx_property:syncProperties", -1, Properties) end - cb(IsPlayerAdmin(source, "EditInteriorPositions") or (Property.Owner == xPlayer.identifier or Properties[PropertyId].Keys[xPlayer.identifier])) + cb(IsPlayerAdmin(source, "EditInteriorPositions") or + (Property.Owner == xPlayer.identifier or Properties[PropertyId].Keys[xPlayer.identifier])) else cb(false) end @@ -684,20 +757,24 @@ ESX.RegisterServerCallback("esx_property:SetWardrobePosition", function(source, else if Interior.type == "ipl" then Properties[PropertyId].positions.Wardrobe = - {x = ESX.Math.Round(Coords.x, 2), y = ESX.Math.Round(Coords.y, 2), z = ESX.Math.Round(Coords.z, 2)} + { x = ESX.Math.Round(Coords.x, 2), y = ESX.Math.Round(Coords.y, 2), z = ESX.Math.Round(Coords.z, 2) } else Properties[PropertyId].positions.Wardrobe = vector3(Property.Entrance.x, Property.Entrance.y, 1999.8) - Coords end Log("Property Wardrobe Location Set", 3640511, - {{name = "**Property Name**", value = Property.Name, inline = true}, {name = "**Owner**", value = Property.OwnerName, inline = true}, - {name = "**Player**", value = xPlayer.getName(), inline = true}, {name = "**Has Access**", - value = (IsPlayerAdmin(source, "EditInteriorPositions") or - (Property.Owner == xPlayer.identifier or Properties[PropertyId].Keys[xPlayer.identifier])) and "Yes" or "No", inline = true}, - {name = "**Reset?**", value = Reset and "Yes" or "No", inline = true}}, 1) + { { name = "**Property Name**", value = Property.Name, inline = true }, { name = "**Owner**", value = Property.OwnerName, inline = true }, + { name = "**Player**", value = xPlayer.getName(), inline = true }, { + name = "**Has Access**", + value = (IsPlayerAdmin(source, "EditInteriorPositions") or + (Property.Owner == xPlayer.identifier or Properties[PropertyId].Keys[xPlayer.identifier])) and "Yes" or "No", + inline = true + }, + { name = "**Reset?**", value = Reset and "Yes" or "No", inline = true } }, 1) end TriggerClientEvent("esx_property:syncProperties", -1, Properties) end - cb(IsPlayerAdmin(source, "EditInteriorPositions") or (Property.Owner == xPlayer.identifier or Properties[PropertyId].Keys[xPlayer.identifier])) + cb(IsPlayerAdmin(source, "EditInteriorPositions") or + (Property.Owner == xPlayer.identifier or Properties[PropertyId].Keys[xPlayer.identifier])) end) ESX.RegisterServerCallback('esx_property:getPlayerDressing', function(source, cb) @@ -728,7 +805,7 @@ ESX.RegisterServerCallback('esx_property:GetInsidePlayers', function(source, cb, Properties[property].Keys = {} end if xPlayer.identifier ~= Property.Owner and not Properties[property].Keys[xPlayer.identifier] then - Players[#Players + 1] = {Name = xPlayer.getName(), Id = xPlayer.source} + Players[#Players + 1] = { Name = xPlayer.getName(), Id = xPlayer.source } end end cb(Players) @@ -738,15 +815,16 @@ ESX.RegisterServerCallback('esx_property:GetNearbyPlayers', function(source, cb, local Property = Properties[property] local Players = {} local xPlayer = ESX.GetPlayerFromId(source) - local NearbyPlayers = ESX.OneSync.GetPlayersInArea(vector3(Property.Entrance.x, Property.Entrance.y, Property.Entrance.z), 5.0) + local NearbyPlayers = ESX.OneSync.GetPlayersInArea( + vector3(Property.Entrance.x, Property.Entrance.y, Property.Entrance.z), 5.0) Wait(100) - for k, v in pairs(NearbyPlayers) do - local xTarget = ESX.GetPlayerFromId(v.id) - if xPlayer.identifier ~= xTarget.identifier then - Players[#Players + 1] = {name = xTarget.getName(), source = xTarget.source} - end + for k, v in pairs(NearbyPlayers) do + local xTarget = ESX.GetPlayerFromId(v.id) + if xPlayer.identifier ~= xTarget.identifier then + Players[#Players + 1] = { name = xTarget.getName(), source = xTarget.source } end - cb(Players) + end + cb(Players) end) ESX.RegisterServerCallback('esx_property:GetPlayersWithKeys', function(source, cb, property) @@ -769,8 +847,8 @@ end) ESX.RegisterServerCallback('esx_property:RemoveLastProperty', function(source, cb, property) local xPlayer = ESX.GetPlayerFromId(source) - MySQL.query("UPDATE `users` SET `last_property` = NULL WHERE `identifier` = ?", {xPlayer.identifier}) -- Remove Saved Data - SetPlayerRoutingBucket(source, 0) -- Reset Routing Bucket + MySQL.query("UPDATE `users` SET `last_property` = NULL WHERE `identifier` = ?", { xPlayer.identifier }) -- Remove Saved Data + SetPlayerRoutingBucket(source, 0) -- Reset Routing Bucket xPlayer.set("lastProperty", nil) cb() end) @@ -787,7 +865,7 @@ ESX.RegisterServerCallback('esx_property:GiveKey', function(source, cb, property local id = xTarget.identifier if not Properties[property].Keys[id] then - Property.Keys[id] = {name = xTarget.getName(), identifier = id} + Property.Keys[id] = { name = xTarget.getName(), identifier = id } xTarget.showNotification(TranslateCap("you_granted", Property.Name), 'success') xTarget.triggerEvent("esx_property:giveKeyAccess") cb(true) @@ -800,9 +878,9 @@ ESX.RegisterServerCallback('esx_property:GiveKey', function(source, cb, property cb(false) end Log("Property Key Given", 3640511, - {{name = "**Property Name**", value = Property.Name, inline = true}, {name = "**Owner**", value = Property.OwnerName, inline = true}, - {name = "**Player**", value = xPlayer.getName(), inline = true}, - {name = "**Has Access**", value = Property.Owner == xPlayer.identifier and "Yes" or "No", inline = true}}, 1) + { { name = "**Property Name**", value = Property.Name, inline = true }, { name = "**Owner**", value = Property.OwnerName, inline = true }, + { name = "**Player**", value = xPlayer.getName(), inline = true }, + { name = "**Has Access**", value = Property.Owner == xPlayer.identifier and "Yes" or "No", inline = true } }, 1) end) ESX.RegisterServerCallback('esx_property:StoreVehicle', function(source, cb, PropertyId, VehicleProperties) @@ -812,29 +890,36 @@ ESX.RegisterServerCallback('esx_property:StoreVehicle', function(source, cb, Pro if Property.Owner == xPlayer.identifier or Properties[PropertyId].Keys[xPlayer.identifier] then if Property.garage.enabled then if Config.Garage.OwnedVehiclesOnly then - MySQL.scalar("SELECT `owner` FROM `owned_vehicles` WHERE `plate` = ?", {VehicleProperties.plate}, function(result) - if result then - if result == xPlayer.identifier then - Properties[PropertyId].garage.StoredVehicles[#Properties[PropertyId].garage.StoredVehicles + 1] = {owner = xPlayer.identifier, - vehicle = VehicleProperties} - cb(true) - elseif (Properties[PropertyId].Keys[result] or Property.Owner == result) then - Properties[PropertyId].garage.StoredVehicles[#Properties[PropertyId].garage.StoredVehicles + 1] = {owner = xPlayer.identifier, - vehicle = VehicleProperties} - cb(true) + MySQL.scalar("SELECT `owner` FROM `owned_vehicles` WHERE `plate` = ?", { VehicleProperties.plate }, + function(result) + if result then + if result == xPlayer.identifier then + Properties[PropertyId].garage.StoredVehicles[#Properties[PropertyId].garage.StoredVehicles + 1] = { + owner = xPlayer.identifier, + vehicle = VehicleProperties + } + cb(true) + elseif (Properties[PropertyId].Keys[result] or Property.Owner == result) then + Properties[PropertyId].garage.StoredVehicles[#Properties[PropertyId].garage.StoredVehicles + 1] = { + owner = xPlayer.identifier, + vehicle = VehicleProperties + } + cb(true) + else + cb(false) + end else cb(false) end - else - cb(false) - end - end) + end) else - Properties[PropertyId].garage.StoredVehicles[#Properties[PropertyId].garage.StoredVehicles + 1] = {owner = xPlayer.identifier, - vehicle = VehicleProperties} + Properties[PropertyId].garage.StoredVehicles[#Properties[PropertyId].garage.StoredVehicles + 1] = { + owner = xPlayer.identifier, + vehicle = VehicleProperties + } cb(true) end - MySQL.query(Config.Garage.MySQLquery, {1, VehicleProperties.plate}) -- Set vehicle as stored in MySQL + MySQL.query(Config.Garage.MySQLquery, { 1, VehicleProperties.plate }) -- Set vehicle as stored in MySQL else xPlayer.showNotification(TranslateCap("garage_not_enabled"), 'error') cb(false) @@ -844,11 +929,15 @@ ESX.RegisterServerCallback('esx_property:StoreVehicle', function(source, cb, Pro cb(false) end Log("User Attempted To Store Vehicle", 3640511, - {{name = "**Property Name**", value = Property.Name, inline = true}, {name = "**Owner**", value = Property.OwnerName, inline = true}, - {name = "**Player**", value = xPlayer.getName(), inline = true}, - {name = "**Has Access**", value = (Property.Owner == xPlayer.identifier or Properties[PropertyId].Keys[xPlayer.identifier]) and "Yes" or "No", - inline = true}, {name = "**Garage Status**", value = Property.garage.enabled and "Enabled" or "Disabled", inline = true}, - {name = "**Vehicle Name**", value = VehicleProperties.DisplayName, inline = true}}, 2) + { { name = "**Property Name**", value = Property.Name, inline = true }, { name = "**Owner**", value = Property.OwnerName, inline = true }, + { name = "**Player**", value = xPlayer.getName(), inline = true }, + { + name = "**Has Access**", + value = (Property.Owner == xPlayer.identifier or Properties[PropertyId].Keys[xPlayer.identifier]) and "Yes" or + "No", + inline = true + }, { name = "**Garage Status**", value = Property.garage.enabled and "Enabled" or "Disabled", inline = true }, + { name = "**Vehicle Name**", value = VehicleProperties.DisplayName, inline = true } }, 2) end) ESX.RegisterServerCallback('esx_property:AccessGarage', function(source, cb, PropertyId, VehicleProperties) @@ -868,9 +957,9 @@ ESX.RegisterServerCallback('esx_property:AccessGarage', function(source, cb, Pro end Log("User Opened Garage Menu", 3640511, - {{name = "**Property Name**", value = Property.Name, inline = true}, {name = "**Owner**", value = Property.OwnerName, inline = true}, - {name = "**Player**", value = xPlayer.getName(), inline = true}, - {name = "**Garage Status**", value = Property.garage.enabled and "Enabled" or "Disabled", inline = true}}, 2) + { { name = "**Property Name**", value = Property.Name, inline = true }, { name = "**Owner**", value = Property.OwnerName, inline = true }, + { name = "**Player**", value = xPlayer.getName(), inline = true }, + { name = "**Garage Status**", value = Property.garage.enabled and "Enabled" or "Disabled", inline = true } }, 2) end) ESX.RegisterServerCallback('esx_property:RemoveKey', function(source, cb, property, player) @@ -882,8 +971,8 @@ ESX.RegisterServerCallback('esx_property:RemoveKey', function(source, cb, proper if Property.Keys then if Properties[property].Keys[player] then Log("Property Key Revoked", 3640511, - {{name = "**Property Name**", value = Property.Name, inline = true}, {name = "**Owner**", value = xPlayer.getName(), inline = true}, - {name = "**Removed From**", value = tostring(Properties[property].Keys[player].name), inline = true}}, 3) + { { name = "**Property Name**", value = Property.Name, inline = true }, { name = "**Owner**", value = xPlayer.getName(), inline = true }, + { name = "**Removed From**", value = tostring(Properties[property].Keys[player].name), inline = true } }, 3) Properties[property].Keys[player] = nil xTarget.showNotification(TranslateCap("key_revoked", Property.Name), 'error') xTarget.triggerEvent("esx_property:RemoveKeyAccess", property) @@ -958,8 +1047,9 @@ RegisterNetEvent('esx_property:enter', function(PropertyId) end table.insert(Properties[PropertyId].plysinside, player) - local PropertyData = {id = PropertyId, coords = Property.Entrance} -- Save the property data to the table - MySQL.query("UPDATE `users` SET `last_property` = ? WHERE `identifier` = ?", {json.encode(PropertyData), xPlayer.identifier}) -- Save the property data to the database + local PropertyData = { id = PropertyId, coords = Property.Entrance } -- Save the property data to the table + MySQL.query("UPDATE `users` SET `last_property` = ? WHERE `identifier` = ?", + { json.encode(PropertyData), xPlayer.identifier }) -- Save the property data to the database xPlayer.set("lastProperty", PropertyData) if Interior.type == "shell" then SetEntityCoords(PlayerPed, vector3(Property.Entrance.x, Property.Entrance.y, 2001)) @@ -969,16 +1059,16 @@ RegisterNetEvent('esx_property:enter', function(PropertyId) end SetPlayerRoutingBucket(player, PropertyId + 1) Log("Player Entered Property", 3640511, - {{name = "**Property Name**", value = Properties[PropertyId].Name, inline = true}, - {name = "**Player**", value = xPlayer.getName(), inline = true}, - {name = "**Property Player Count**", value = tostring(#(Properties[PropertyId].plysinside)), inline = true}}, 3) + { { name = "**Property Name**", value = Properties[PropertyId].Name, inline = true }, + { name = "**Player**", value = xPlayer.getName(), inline = true }, + { name = "**Property Player Count**", value = tostring(#(Properties[PropertyId].plysinside)), inline = true } }, 3) end) RegisterNetEvent('esx_property:leave', function(PropertyId) local player = source local Property = Properties[PropertyId] local xPlayer = ESX.GetPlayerFromId(player) - MySQL.query("UPDATE `users` SET `last_property` = NULL WHERE `identifier` = ?", {xPlayer.identifier}) -- Remove Saved Data + MySQL.query("UPDATE `users` SET `last_property` = NULL WHERE `identifier` = ?", { xPlayer.identifier }) -- Remove Saved Data xPlayer.set("lastProperty", nil) SetEntityCoords(player, vector3(Property.Entrance.x, Property.Entrance.y, Property.Entrance.z)) SetEntityHeading(player, 0.0) @@ -990,16 +1080,16 @@ RegisterNetEvent('esx_property:leave', function(PropertyId) end end Log("Player Left Property", 3640511, - {{name = "**Property Name**", value = Properties[PropertyId].Name, inline = true}, - {name = "**Player**", value = xPlayer.getName(), inline = true}, - {name = "**Property Player Count**", value = tostring(#(Properties[PropertyId].plysinside)), inline = true}}, 3) + { { name = "**Property Name**", value = Properties[PropertyId].Name, inline = true }, + { name = "**Player**", value = xPlayer.getName(), inline = true }, + { name = "**Property Player Count**", value = tostring(#(Properties[PropertyId].plysinside)), inline = true } }, 3) end) RegisterNetEvent('esx_property:SetVehicleOut', function(PropertyId, VehIndex) local VehicleData = Properties[PropertyId].garage.StoredVehicles[VehIndex] local plate = VehicleData.vehicle.plate table.remove(Properties[PropertyId].garage.StoredVehicles, VehIndex) - MySQL.query(Config.Garage.MySQLquery, {0, plate}) -- Set vehicle as no longer stored + MySQL.query(Config.Garage.MySQLquery, { 0, plate }) -- Set vehicle as no longer stored end) @@ -1034,7 +1124,8 @@ end) ESX.RegisterServerCallback('esx_property:CanAccessRealEstateMenu', function(source, cb) local xPlayer = ESX.GetPlayerFromId(source) - local Re = (Config.PlayerManagement.Enabled and xPlayer.job.name == Config.PlayerManagement.job and xPlayer.job.grade >= Config.PlayerManagement.Permissions.ManagePropertiesFromQuickActions) and true or false + local Re = (Config.PlayerManagement.Enabled and xPlayer.job.name == Config.PlayerManagement.job and xPlayer.job.grade >= Config.PlayerManagement.Permissions.ManagePropertiesFromQuickActions) and + true or false cb(Re) end) @@ -1043,21 +1134,36 @@ RegisterNetEvent('esx_property:server:createProperty', function(Property) local xPlayer = ESX.GetPlayerFromId(source) local Interior = GetInteriorValues(Property.interior) local garageData = - Property.garage.enabled and {enabled = true, pos = Property.garage.pos, Heading = Property.garage.heading, StoredVehicles = {}} or - {enabled = false} + Property.garage.enabled and + { enabled = true, pos = Property.garage.pos, Heading = Property.garage.heading, StoredVehicles = {} } or + { enabled = false } if IsPlayerAdmin(source, "CreateProperty") then - local ActualProperty = {Name = Property.name, setName = "", Price = Property.price, furniture = {}, plysinside = {}, Interior = Property.interior, - Entrance = Property.entrance, Owner = "", Keys = {}, positions = Interior.positions, cctv = Property.cctv, - garage = garageData, Owned = false, Locked = false} + local ActualProperty = { + Name = Property.name, + setName = "", + Price = Property.price, + furniture = {}, + plysinside = {}, + Interior = Property.interior, + Entrance = Property.entrance, + Owner = "", + Keys = {}, + positions = Interior.positions, + cctv = Property.cctv, + garage = garageData, + Owned = false, + Locked = false + } Properties[#Properties + 1] = ActualProperty end Log("Property Created", 65280, - {{name = "**Admin**", value = xPlayer.getName(), inline = true}, {name = "**Name**", value = Property.name, inline = true}, - {name = "**Price**", value = ESX.Math.GroupDigits(Property.price), inline = true}, - {name = "**Interior**", value = Interior.label, inline = true}, - {name = "**Garage Status**", value = Property.garage.enabled and "Enabled" or "Disabled", inline = true}, - {name = "**CCTV Status**", value = Property.cctv.enabled and "Enabled" or "Disabled", inline = true}, - {name = "**Entrance**", value = tostring(Property.entrance.x .. ", " .. Property.entrance.y .. ", " .. Property.entrance.z), inline = true}}, 1) + { { name = "**Admin**", value = xPlayer.getName(), inline = true }, { name = "**Name**", value = Property.name, inline = true }, + { name = "**Price**", value = ESX.Math.GroupDigits(Property.price), inline = true }, + { name = "**Interior**", value = Interior.label, inline = true }, + { name = "**Garage Status**", value = Property.garage.enabled and "Enabled" or "Disabled", inline = true }, + { name = "**CCTV Status**", value = Property.cctv.enabled and "Enabled" or "Disabled", inline = true }, + { name = "**Entrance**", value = tostring(Property.entrance.x .. ", " .. Property.entrance.y .. ", " .. Property.entrance.z), inline = true } }, + 1) TriggerClientEvent("esx_property:syncProperties", -1, Properties) end) @@ -1070,8 +1176,8 @@ AddEventHandler('txAdmin:events:scheduledRestart', function(eventData) Wait(50000) if Properties and #Properties > 0 then SaveResourceFile(GetCurrentResourceName(), 'properties.json', json.encode(Properties)) - Log("Properties Saving", 11141375, {{name = "**Reason**", value = "Scheduled Server Restart", inline = true}, - {name = "**Property Count**", value = tostring(#Properties), inline = true}}, 1) + Log("Properties Saving", 11141375, { { name = "**Reason**", value = "Scheduled Server Restart", inline = true }, + { name = "**Property Count**", value = tostring(#Properties), inline = true } }, 1) end end) end @@ -1081,7 +1187,8 @@ function PropertySave(Reason) if Properties and #Properties > 0 then SaveResourceFile(GetCurrentResourceName(), 'properties.json', json.encode(Properties)) Log("Properties Saving", 11141375, - {{name = "**Reason**", value = Reason, inline = true}, {name = "**Property Count**", value = tostring(#Properties), inline = true}}, 1) + { { name = "**Reason**", value = Reason, inline = true }, { name = "**Property Count**", value = tostring(#Properties), inline = true } }, + 1) end end @@ -1091,7 +1198,6 @@ AddEventHandler('txAdmin:events:serverShuttingDown', function() end) --- Save Properties On Resource Stop/Restart - AddEventHandler('onResourceStop', function(ResourceName) if ResourceName == GetCurrentResourceName() then PropertySave(TranslateCap("resource_stop")) @@ -1104,8 +1210,7 @@ AddEventHandler('onServerResourceStop', function(ResourceName) end end) --- Save Properties every x Minutes - +-- Save Properties every x Minutes CreateThread(function() while true do Wait(60000 * Config.SaveInterval) @@ -1113,19 +1218,18 @@ CreateThread(function() end end) -ESX.RegisterCommand(_("save_name"), Config.AllowedGroups, function(xPlayer) +ESX.RegisterCommand(TranslateCap("save_name"), Config.AllowedGroups, function(xPlayer) PropertySave(TranslateCap("manual_save", GetPlayerName(xPlayer.source))) -end, false,{help = TranslateCap("save_desc")}) +end, false, { help = TranslateCap("save_desc") }) ----- Exports ----- - exports("GetProperties", function() return Properties end) exports("GetOwnedProperties", function() local OwnedProperties = {} - for i=1, #Properties do + for i = 1, #Properties do if Properties[i].Owned then OwnedProperties[#OwnedProperties + 1] = Properties[i] end @@ -1135,7 +1239,7 @@ end) exports("GetNonOwnedProperties", function() local NonOwnedProperties = {} - for i=1, #Properties do + for i = 1, #Properties do if not Properties[i].Owned then NonOwnedProperties[#NonOwnedProperties + 1] = Properties[i] end @@ -1145,7 +1249,7 @@ end) exports("GetPlayerProperties", function(identifier) local PlayerProperties = {} - for i=1, #Properties do + for i = 1, #Properties do if Properties[i].Owned and Properties[i].Owner == identifier then PlayerProperties[#PlayerProperties + 1] = Properties[i] end diff --git a/server-data/resources/[esx_addons]/esx_scoreboard/html/listener.js b/server-data/resources/[esx_addons]/esx_scoreboard/html/listener.js index 0f5876162..7174b4dad 100644 --- a/server-data/resources/[esx_addons]/esx_scoreboard/html/listener.js +++ b/server-data/resources/[esx_addons]/esx_scoreboard/html/listener.js @@ -50,7 +50,8 @@ $(function() { break; case 'updateServerInfo': if (event.data.maxPlayers) { - $('#max_players').html(event.data.maxPlayers); + const sanitizedMaxPlayers = DOMPurify.sanitize(event.data.maxPlayers); + $('#max_players').html(sanitizedMaxPlayers); } break; default: diff --git a/server-data/resources/[esx_addons]/esx_vehicleshop/client/main.lua b/server-data/resources/[esx_addons]/esx_vehicleshop/client/main.lua index a5ba64e9b..6d280a0f6 100644 --- a/server-data/resources/[esx_addons]/esx_vehicleshop/client/main.lua +++ b/server-data/resources/[esx_addons]/esx_vehicleshop/client/main.lua @@ -476,7 +476,7 @@ function OpenRentedVehiclesMenu() local elements = {} for _, v in ipairs(vehicles) do - local vehicleLabel = GetVehicleFromModel(v.name).label + local vehicleLabel = GetVehicleFromModel(v.name).name table.insert(elements, { label = ('%s: %s - %s'):format(v.playerName, vehicleLabel, v.plate), diff --git a/server-data/resources/[esx_addons]/generic_texture_renderer_gfx/fxmanifest.lua b/server-data/resources/[esx_addons]/generic_texture_renderer_gfx/fxmanifest.lua new file mode 100644 index 000000000..242789006 --- /dev/null +++ b/server-data/resources/[esx_addons]/generic_texture_renderer_gfx/fxmanifest.lua @@ -0,0 +1,4 @@ +fx_version "cerulean" +game "gta5" +lua54 'yes' +version "1.0.2" \ No newline at end of file diff --git a/server-data/resources/[esx_addons]/generic_texture_renderer_gfx/stream/generic_texture_renderer.gfx b/server-data/resources/[esx_addons]/generic_texture_renderer_gfx/stream/generic_texture_renderer.gfx new file mode 100644 index 000000000..8151eff54 Binary files /dev/null and b/server-data/resources/[esx_addons]/generic_texture_renderer_gfx/stream/generic_texture_renderer.gfx differ diff --git a/server-data/resources/[esx_addons]/generic_texture_renderer_gfx/stream/generic_texture_renderer_2.gfx b/server-data/resources/[esx_addons]/generic_texture_renderer_gfx/stream/generic_texture_renderer_2.gfx new file mode 100644 index 000000000..8151eff54 Binary files /dev/null and b/server-data/resources/[esx_addons]/generic_texture_renderer_gfx/stream/generic_texture_renderer_2.gfx differ diff --git a/server-data/resources/[esx_addons]/ptelevision/README.md b/server-data/resources/[esx_addons]/ptelevision/README.md new file mode 100644 index 000000000..fd3ded86b --- /dev/null +++ b/server-data/resources/[esx_addons]/ptelevision/README.md @@ -0,0 +1,27 @@ +
+ + +## What is this? + +Basically, this serves as a free resource for servers that need a television script. + +With this resource, you will be able to do the following: + +- Watch Youtube & Twitch Videos / Streams. +- Broadcast your Youtube / Twitch Stream as a server-wide channel. +- Display & Browse the Web. +- Display Images and Videos (via direct link in the browser). + +## What do I need? + +You will need the following for this script to work. + +- [Ox Lib](https://github.com/overextended/ox_lib/releases) (works with any framework) + +- [Renderer](https://forum.cfx.re/t/release-generic-dui-2d-3d-renderer/131208) (works with any framework) + +If you want to make a fork, please obtain permission with a valid reason. + +## Need Support? + +Click here! diff --git a/server-data/resources/[esx_addons]/ptelevision/client/cursor.lua b/server-data/resources/[esx_addons]/ptelevision/client/cursor.lua new file mode 100644 index 000000000..cdf51cf3b --- /dev/null +++ b/server-data/resources/[esx_addons]/ptelevision/client/cursor.lua @@ -0,0 +1,88 @@ +local scale = 1.5 +local screenWidth = math.floor(1920 / scale) +local screenHeight = math.floor(1080 / scale) +shouldDraw = false + +function SetInteractScreen(bool) + if not shouldDraw and bool then + shouldDraw = bool + Citizen.CreateThread(function() + -- Create screen + local nX = 0 + local nY = 0 + + local w, h = screenWidth, screenHeight + + local minX, maxX = ((w - (w / 2)) / 2), (w - (w / 4)) + local totalX = minX - maxX + + local minY, maxY = ((h - (h / 2)) / 2), (h - (h / 4)) + local totalY = minY - maxY + + RequestTextureDictionary("fib_pc") + + -- Update controls while active + while shouldDraw do + nX = GetControlNormal(0, 239) * screenWidth + nY = GetControlNormal(0, 240) * screenHeight + DisableControlAction(0, 1, true) -- Disable looking horizontally + DisableControlAction(0, 2, true) -- Disable looking vertically + DisablePlayerFiring(PlayerPedId(), true) -- Disable weapon firing + DisableControlAction(0, 142, true) -- Disable aiming + DisableControlAction(0, 106, true) -- Disable in-game mouse controls + -- Update mouse position when changed + DrawSprite("ptelevision_b_dict", "ptelevision_b_txd", 0.5, 0.5, 0.5, 0.5, 0.0, 255, 255, 255, 255) + if nX ~= mX or nY ~= mY then + mX = nX + mY = nY + local duiX = -screenWidth * ((mX - minX) / totalX) + local duiY = -screenHeight * ((mY - minY) / totalY) + BlockWeaponWheelThisFrame() + if not (mX > 325) then + mX = 325 + end + if not (mX < 965) then + mX = 965 + end + if not (mY > 185) then + mY = 185 + end + if not (mY < 545) then + mY = 545 + end + SendDuiMouseMove(duiObj, math.floor(duiX), math.floor(duiY)) + end + DrawSprite("fib_pc", "arrow", mX / screenWidth, mY / screenHeight, 0.005, 0.01, 0.0, 255, 255, 255, 255) + + -- Send scroll and click events to dui + + if IsControlPressed(0, 177) then + SetInteractScreen(false) + OpenTVMenu() + end -- scroll up + if IsControlPressed(0, 172) then + SendDuiMouseWheel(duiObj, 10, 0) + end -- scroll up + if IsControlPressed(0, 173) then + SendDuiMouseWheel(duiObj, -10, 0) + end -- scroll down + + if IsDisabledControlJustPressed(0, 24) then + SendDuiMouseDown(duiObj, "left") + elseif IsDisabledControlJustReleased(0, 24) then + SendDuiMouseUp(duiObj, "left") + SendDuiMouseUp(duiObj, "right") + end + if IsDisabledControlJustPressed(0, 25) then + SendDuiMouseDown(duiObj, "right") + elseif IsDisabledControlJustReleased(0, 24) then + SendDuiMouseUp(duiObj, "right") + end + + Wait(0) + end + end) + else + shouldDraw = bool + end +end diff --git a/server-data/resources/[esx_addons]/ptelevision/client/dui.lua b/server-data/resources/[esx_addons]/ptelevision/client/dui.lua new file mode 100644 index 000000000..8a5dab7d7 --- /dev/null +++ b/server-data/resources/[esx_addons]/ptelevision/client/dui.lua @@ -0,0 +1,44 @@ +function CreateNamedRenderTargetForModel(name, model) + local handle = 0 + if not IsNamedRendertargetRegistered(name) then + RegisterNamedRendertarget(name, 0) + end + if not IsNamedRendertargetLinked(model) then + LinkNamedRendertarget(model) + end + if IsNamedRendertargetRegistered(name) then + handle = GetNamedRendertargetRenderId(name) + end + return handle +end + +function RequestTextureDictionary(dict) + RequestStreamedTextureDict(dict) + while not HasStreamedTextureDictLoaded(dict) do + Wait(0) + end + return dict +end + +function LoadModel(model) + if not IsModelInCdimage(model) then + return + end + RequestModel(model) + while not HasModelLoaded(model) do + Wait(0) + end + return model +end + +function RenderScaleformTV(renderTarget, scaleform, entity) + SetTextRenderId(renderTarget) -- set render target + Set_2dLayer(4) + SetScriptGfxDrawBehindPausemenu(1) + --DrawRect(0.5, 0.5, 1.0, 0.5, 255, 0, 0, 255); -- WOAH! + local coords = GetEntityCoords(entity) + local rot = GetEntityRotation(entity) + DrawSprite("ptelevision_b_dict", "ptelevision_b_txd", 0.5, 0.5, 1.0, 1.0, 0.0, 255, 255, 255, 255) + SetTextRenderId(GetDefaultScriptRendertargetRenderId()) -- reset + SetScriptGfxDrawBehindPausemenu(0) +end diff --git a/server-data/resources/[esx_addons]/ptelevision/client/main.lua b/server-data/resources/[esx_addons]/ptelevision/client/main.lua new file mode 100644 index 000000000..1ac16c578 --- /dev/null +++ b/server-data/resources/[esx_addons]/ptelevision/client/main.lua @@ -0,0 +1,242 @@ +DEFAULT_URL = "https://cfx-nui-ptelevision/html/index.html" +duiUrl = DEFAULT_URL +duiObj = nil +tvObj = nil +volume = 0.5 +CURRENT_SCREEN = nil + +local Locations = Config.Locations + +function getDuiURL() + return duiUrl +end + +function SetVolume(coords, num) + volume = num + SetTelevisionLocal(coords, "volume", num) +end + +function GetVolume(dist, range) + if not volume then + return 0 + end + local rem = (dist / range) + rem = rem > volume and volume or rem + local _vol = math.floor((volume - rem) * 100) + return _vol +end + +function setDuiURL(url) + duiUrl = url + SetDuiUrl(duiObj, duiUrl) +end + +local sfName = "generic_texture_renderer" + +local width = 1280 +local height = 720 + +local sfHandle = nil +local txdHasBeenSet = false + +function loadScaleform(scaleform) + local scaleformHandle = RequestScaleformMovie(scaleform) + + while not HasScaleformMovieLoaded(scaleformHandle) do + scaleformHandle = RequestScaleformMovie(scaleform) + Citizen.Wait(0) + end + return scaleformHandle +end + +function ShowScreen(data) + CURRENT_SCREEN = data + sfHandle = loadScaleform(sfName) + runtimeTxd = "ptelevision_b_dict" + + local txd = CreateRuntimeTxd("ptelevision_b_dict") + duiObj = CreateDui(duiUrl, width, height) + local dui = GetDuiHandle(duiObj) + local tx = CreateRuntimeTextureFromDuiHandle(txd, "ptelevision_b_txd", dui) + + Citizen.Wait(10) + + PushScaleformMovieFunction(sfHandle, "SET_TEXTURE") + + PushScaleformMovieMethodParameterString("ptelevision_b_dict") + PushScaleformMovieMethodParameterString("ptelevision_b_txd") + + PushScaleformMovieFunctionParameterInt(0) + PushScaleformMovieFunctionParameterInt(0) + PushScaleformMovieFunctionParameterInt(width) + PushScaleformMovieFunctionParameterInt(height) + + PopScaleformMovieFunctionVoid() + Citizen.CreateThread(function() + TriggerServerEvent("ptelevision:requestSync", data.coords) + local tvObj = data.entity + local screenModel = Config.Models[data.model] + while duiObj do + if tvObj and sfHandle ~= nil and HasScaleformMovieLoaded(sfHandle) then + local pos = GetEntityCoords(tvObj) + local scale = screenModel.Scale + local offset = GetOffsetFromEntityInWorldCoords( + tvObj, + screenModel.Offset.x, + screenModel.Offset.y, + screenModel.Offset.z + ) + if screenModel.Target then + local id = CreateNamedRenderTargetForModel(screenModel.Target, data.model) + if id ~= -1 then + RenderScaleformTV(id, sfHandle, tvObj) + end + else + local hz = GetEntityHeading(tvObj) + DrawScaleformMovie_3dSolid( + sfHandle, + offset, + 0.0, + 0.0, + -hz, + 2.0, + 2.0, + 2.0, + scale * 1, + scale * (9 / 16), + 2 + ) + end + end + Citizen.Wait(0) + end + end) + Citizen.CreateThread(function() + local screen = CURRENT_SCREEN + local modelData = Config.Models[screen.model] + local coords = screen.coords + local range = modelData.Range + local _, lstatus = GetTelevisionLocal(coords) + if lstatus and lstatus.volume then + SetVolume(coords, lstatus.volume) + else + SetVolume(coords, modelData.DefaultVolume) + end + while duiObj do + local pcoords = GetEntityCoords(PlayerPedId()) + local dist = #(coords - pcoords) + SendDuiMessage( + duiObj, + json.encode({ + setVolume = true, + data = GetVolume(dist, range, volume), + }) + ) + Citizen.Wait(100) + end + end) +end + +function HideScreen() + CURRENT_SCREEN = nil + if duiObj then + DestroyDui(duiObj) + SetScaleformMovieAsNoLongerNeeded(sfHandle) + duiObj = nil + sfHandle = nil + end +end + +function GetClosestScreen() + local objPool = GetGamePool("CObject") + local closest = { dist = -1 } + local pcoords = GetEntityCoords(PlayerPedId()) + for i = 1, #objPool do + local entity = objPool[i] + local model = GetEntityModel(entity) + local data = Config.Models[model] + if data then + local coords = GetEntityCoords(entity) + local dist = #(pcoords - coords) + if (dist < closest.dist or closest.dist < 0) and dist < data.Range then + closest = { dist = dist, coords = coords, model = model, entity = entity } + end + end + end + return (closest.entity and closest or nil) +end + +Citizen.CreateThread(function() + Citizen.Wait(2000) + TriggerServerEvent("ptelevision:requestUpdate") + while true do + local wait = 2500 + local data = GetClosestScreen() + if data and not duiObj then + ShowScreen(data) + elseif (not data or #(v3(CURRENT_SCREEN.coords) - v3(data.coords)) > 0.01) and duiObj then + HideScreen() + end + Citizen.Wait(wait) + end +end) + +Citizen.CreateThread(function() + while true do + local wait = 2500 + for i = 1, #Locations do + local data = Locations[i] + local dist = #(GetEntityCoords(PlayerPedId()) - v3(data.Position)) + if not Locations[i].obj and dist < 20.0 then + LoadModel(data.Model) + Locations[i].obj = CreateObject(data.Model, data.Position.x, data.Position.y, data.Position.z) + SetEntityHeading(Locations[i].obj, data.Position.w) + FreezeEntityPosition(Locations[i].obj, true) + elseif Locations[i].obj and dist > 20.0 then + DeleteEntity(Locations[i].obj) + Locations[i].obj = nil + end + end + Citizen.Wait(wait) + end +end) + +RegisterNetEvent("ptelevision:requestUpdate", function(data) + Televisions = data.Televisions + Channels = data.Channels +end) + +RegisterNetEvent("ptelevision:requestSync", function(coords, data) + local tvObj = data.entity + + local _, status = GetTelevision(coords) + local screenModel = Config.Models[data.model] + if status and status["ptv_status"] then + local update_time = status.update_time + local status = status["ptv_status"] + Citizen.Wait(1000) + if status.type == "play" then + if status.channel and Channels[status.channel] then + PlayVideo({ url = Channels[status.channel].url, channel = status.channel }) + elseif status.url then + local time = math.floor(data.current_time - update_time) + PlayVideo({ url = status.url, time = time }) + end + elseif status.type == "browser" then + PlayBrowser({ url = status.url }) + end + end +end) + +RegisterNUICallback("pageLoaded", function(cb) + WaitForLoad = false +end) + +AddEventHandler("onResourceStop", function(name) + if name == GetCurrentResourceName() then + HideScreen() + for i = 1, #Locations do + DeleteEntity(Locations[i].obj) + end + end +end) diff --git a/server-data/resources/[esx_addons]/ptelevision/client/tv.lua b/server-data/resources/[esx_addons]/ptelevision/client/tv.lua new file mode 100644 index 000000000..0a52c02df --- /dev/null +++ b/server-data/resources/[esx_addons]/ptelevision/client/tv.lua @@ -0,0 +1,240 @@ +TelevisionsLocal = {} + +function SetChannel(index) + TriggerServerEvent("ptelevision:event", CURRENT_SCREEN, "ptv_status", { + type = "play", + channel = index, + }) +end + +function GetChannelList() + if not Channels then + return {} + end + local channel_list = {} + local menu_list = {} + local current = 1 + local screen = CURRENT_SCREEN + local ent = screen.entity + local _, status = GetTelevision(screen.coords) + local channel = nil + if status then + channel = status.channel + end + for index, value in pairs(Channels) do + table.insert(channel_list, { index = index, url = value.url }) + table.insert(menu_list, "Channel #" .. index .. " (" .. value.name .. ")") + if channel ~= nil and channel == index then + current = #channel_list + end + end + return { list = channel_list, display = menu_list, current = current } +end + +function BroadcastMenu() + local _source = GetPlayerServerId(PlayerId()) + for k, v in pairs(Channels) do + if v.source == _source then + TriggerServerEvent("ptelevision:broadcast", nil) + return + end + end + local input = lib.inputDialog("Live Broadcast", { "Channel Name:", "Broadcast URL:" }) + if input[1] and input[2] then + TriggerServerEvent("ptelevision:broadcast", { name = input[1], url = input[2] }) + end +end + +function WebBrowserMenu() + lib.hideMenu() + local input = lib.inputDialog("Web Browser", { "URL:" }) + + if input then + TriggerServerEvent("ptelevision:event", CURRENT_SCREEN, "ptv_status", { + type = "browser", + url = input[1], + }) + end + Citizen.Wait(300) + OpenTVMenu() +end + +function VideoMenu() + lib.hideMenu() + local input = lib.inputDialog("Video Player", { "URL:" }) + if input then + TriggerServerEvent("ptelevision:event", CURRENT_SCREEN, "ptv_status", { + type = "play", + url = input[1], + }) + end + Citizen.Wait(300) + OpenTVMenu() +end + +function VolumeMenu() + lib.hideMenu() + local input = lib.inputDialog("Volume", { "Set Volume (0-100):" }) + if tonumber(input[1]) then + local coords = CURRENT_SCREEN.coords + SetVolume(coords, tonumber(input[1]) / 100) + end + Citizen.Wait(300) + OpenTVMenu() +end + +function OpenTVMenu() + local screen = CURRENT_SCREEN + if not screen then + return + end + lib.hideMenu() + local ChannelList = GetChannelList() + lib.registerMenu({ + id = "ptelevision-menu", + title = "Television", + position = "top-right", + onSideScroll = function(selected, scrollIndex, args) + if selected == 3 then + SetChannel(ChannelList.list[scrollIndex].index) + end + end, + onSelected = function(selected, scrollIndex, args) end, + onClose = function(keyPressed) end, + options = { + { label = "Videos", description = "Play a video or stream on the screen." }, + { label = "Web Browser", description = "Access the web via your TV." }, + { label = "TV Channels", values = ChannelList.display, description = "Live TV Channels in San Andreas!", defaultIndex = ChannelList.current }, + { label = "Interact With Screen", description = "Allows you to control on-screen elements." }, + { label = "Set Volume", description = "Sets your TV's volume (For yourself)." }, + { label = "Close Menu", close = true }, + }, + }, function(selected, scrollIndex, args) + if selected == 1 then + VideoMenu() + elseif selected == 2 then + WebBrowserMenu() + elseif selected == 3 then + SetChannel(ChannelList.list[scrollIndex].index) + OpenTVMenu() + elseif selected == 4 then + SetInteractScreen(true) + elseif selected == 5 then + VolumeMenu() + end + end) + lib.showMenu("ptelevision-menu") +end + +function PlayBrowser(data) + while not IsDuiAvailable(duiObj) do + Wait(10) + end + setDuiURL(data.url) +end + +function PlayVideo(data) + while not IsDuiAvailable(duiObj) do + Wait(10) + end + if getDuiURL() ~= DEFAULT_URL then + waitForLoad = true + setDuiURL(DEFAULT_URL) + while waitForLoad do + Wait(10) + end + end + SendDuiMessage( + duiObj, + json.encode({ + setVideo = true, + data = data, + }) + ) +end + +function ResetDisplay() + setDuiURL(DEFAULT_URL) +end + +function GetTelevisionLocal(coords) + for k, v in pairs(TelevisionsLocal) do + if #(v3(v.coords) - v3(coords)) < 0.01 then + return k, v + end + end +end + +function SetTelevisionLocal(coords, key, value) + local index, data = GetTelevisionLocal(coords) + if index ~= nil then + if TelevisionsLocal[index] == nil then + TelevisionsLocal[index] = {} + end + TelevisionsLocal[index][key] = value + else + index = GetGameTimer() + while TelevisionsLocal[index] do + index = index + 1 + Citizen.Wait(0) + end + if TelevisionsLocal[index] == nil then + TelevisionsLocal[index] = {} + end + TelevisionsLocal[index][key] = value + end + TelevisionsLocal[index].coords = coords + return index +end + +RegisterNetEvent("ptelevision:event", function(data, index, key, value) + Televisions = data + local data = Televisions[index] + local screen = CURRENT_SCREEN + if screen and #(v3(screen.coords) - v3(data.coords)) < 0.001 then + local index, data = GetTelevision(screen.coords) + if index then + local event = value + if event.type == "play" then + local data = { url = event.url } + if event.channel then + data = Channels[event.channel] + data.channel = event.channel + end + PlayVideo(data) + elseif event.type == "browser" then + PlayBrowser({ url = event.url }) + end + end + end + SetTelevisionLocal(Televisions[index].coords, "start_time", GetGameTimer()) +end) + +RegisterNetEvent("ptelevision:broadcast", function(data, index) + Channels = data + if getDuiURL() == DEFAULT_URL then + local screen = CURRENT_SCREEN + local tvObj = screen.entity + local _, status = GetTelevision(screen.coords) + if status and status.channel == index and data[index] == nil then + ResetDisplay() + Citizen.Wait(10) + end + SendDuiMessage( + duiObj, + json.encode({ + showNotification = true, + channel = index, + data = data[index], + }) + ) + end +end) + +RegisterCommand("tv", function() + OpenTVMenu() +end) + +RegisterCommand("broadcast", function(source, args, raw) + BroadcastMenu() +end) diff --git a/server-data/resources/[esx_addons]/ptelevision/config.lua b/server-data/resources/[esx_addons]/ptelevision/config.lua new file mode 100644 index 000000000..97c36a96f --- /dev/null +++ b/server-data/resources/[esx_addons]/ptelevision/config.lua @@ -0,0 +1,154 @@ +Config = {} + +Config.Models = { -- Any TV Models used on the map or in locations must be defined here. + [`des_tvsmash_start`] = { + DefaultVolume = 0.5, + Range = 20.0, + Target = "tvscreen", -- Only use if prop has render-target name. + Scale = 0.085, + Offset = vector3(-1.02, -0.055, 1.04), + }, + [`prop_flatscreen_overlay`] = { + DefaultVolume = 0.5, + Range = 20.0, + Target = "tvscreen", -- Only use if prop has render-target name. + Scale = 0.085, + Offset = vector3(-1.02, -0.055, 1.04), + }, + [`prop_laptop_lester2`] = { + DefaultVolume = 0.5, + Range = 20.0, + Target = "tvscreen", -- Only use if prop has render-target name. + Scale = 0.085, + Offset = vector3(-1.02, -0.055, 1.04), + }, + [`prop_monitor_02`] = { + DefaultVolume = 0.5, + Range = 20.0, + Target = "tvscreen", -- Only use if prop has render-target name. + Scale = 0.085, + Offset = vector3(-1.02, -0.055, 1.04), + }, + [`prop_trev_tv_01`] = { + DefaultVolume = 0.5, + Range = 20.0, + Target = "tvscreen", -- Only use if prop has render-target name. + Scale = 0.085, + Offset = vector3(-1.02, -0.055, 1.04), + }, + [`prop_tv_02`] = { + DefaultVolume = 0.5, + Range = 20.0, + Target = "tvscreen", -- Only use if prop has render-target name. + Scale = 0.085, + Offset = vector3(-1.02, -0.055, 1.04), + }, + [`prop_tv_03_overlay`] = { + DefaultVolume = 0.5, + Range = 20.0, + Target = "tvscreen", -- Only use if prop has render-target name. + Scale = 0.085, + Offset = vector3(-1.02, -0.055, 1.04), + }, + [`prop_tv_06`] = { + DefaultVolume = 0.5, + Range = 20.0, + Target = "tvscreen", -- Only use if prop has render-target name. + Scale = 0.085, + Offset = vector3(-1.02, -0.055, 1.04), + }, + [`prop_tv_flat_01`] = { + DefaultVolume = 0.5, + Range = 20.0, + Target = "tvscreen", -- Only use if prop has render-target name. + Scale = 0.085, + Offset = vector3(-1.02, -0.055, 1.04), + }, + [`prop_tv_flat_01_screen`] = { + DefaultVolume = 0.5, + Range = 20.0, + Target = "tvscreen", -- Only use if prop has render-target name. + Scale = 0.085, + Offset = vector3(-1.02, -0.055, 1.04), + }, + [`prop_tv_flat_02b`] = { + DefaultVolume = 0.5, + Range = 20.0, + Target = "tvscreen", -- Only use if prop has render-target name. + Scale = 0.085, + Offset = vector3(-1.02, -0.055, 1.04), + }, + [`prop_tv_flat_03`] = { + DefaultVolume = 0.5, + Range = 20.0, + Target = "tvscreen", -- Only use if prop has render-target name. + Scale = 0.085, + Offset = vector3(-1.02, -0.055, 1.04), + }, + [`prop_tv_flat_03b`] = { + DefaultVolume = 0.5, + Range = 20.0, + Target = "tvscreen", -- Only use if prop has render-target name. + Scale = 0.085, + Offset = vector3(-1.02, -0.055, 1.04), + }, + [`prop_tv_flat_michael`] = { + DefaultVolume = 0.5, + Range = 20.0, + Target = "tvscreen", -- Only use if prop has render-target name. + Scale = 0.085, + Offset = vector3(-1.02, -0.055, 1.04), + }, + [`prop_monitor_w_large`] = { + DefaultVolume = 0.5, + Range = 20.0, + Target = "tvscreen", -- Only use if prop has render-target name. + Scale = 0.085, + Offset = vector3(-1.02, -0.055, 1.04), + }, + [`prop_tv_03`] = { + DefaultVolume = 0.5, + Range = 20.0, + Target = "tvscreen", -- Only use if prop has render-target name. + Scale = 0.085, + Offset = vector3(-1.02, -0.055, 1.04), + }, + [`prop_tv_flat_02`] = { + DefaultVolume = 0.5, + Range = 20.0, + Target = "tvscreen", -- Only use if prop has render-target name. + Scale = 0.085, + Offset = vector3(-1.02, -0.055, 1.04), + }, +} + +Config.Locations = { -- REMOVE ALL IF NOT USING ONESYNC, OR IT SHALL BREAK. + { + Model = `prop_tv_flat_01`, + Position = vector4(144.3038, -1037.4647, 29.4173, 70.81), + }, +} + +Config.Channels = { -- These channels are default channels and cannot be overriden. + { name = "Twitch", url = "twitch.tv/twitch" }, +} + +Config.BannedWords = { + "google", +} + +Config.Events = { -- Events for approving broadcasts / interactions (due to popular demand). + ScreenInteract = function(source, data, key, value, cb) -- cb() to approve. + if value.url then + for i = 1, #Config.BannedWords do + if string.find(value.url, Config.BannedWords[i]) then + return + end + end + end + cb() + end, + Broadcast = function(source, data, cb) -- cb() to approve. + cb() + end, +} diff --git a/server-data/resources/[esx_addons]/ptelevision/fxmanifest.lua b/server-data/resources/[esx_addons]/ptelevision/fxmanifest.lua new file mode 100644 index 000000000..8bfc3d884 --- /dev/null +++ b/server-data/resources/[esx_addons]/ptelevision/fxmanifest.lua @@ -0,0 +1,32 @@ +fx_version("cerulean") +game("gta5") +author("Pickle Mods#0001") +version("v1.2.5") +ui_page("html/blank.html") + +files({ + "html/blank.html", + "html/index.html", + "html/style.css", + "html/main.js", + "html/VCR_OSD_MONO_1.001.ttf", +}) + +shared_scripts({ + "@ox_lib/init.lua", + "config.lua", + "shared/*.lua", +}) + +client_scripts({ + "client/cursor.lua", + "client/tv.lua", + "client/dui.lua", + "client/main.lua", +}) + +server_scripts({ + "server/*.lua", +}) + +lua54("yes") diff --git a/server-data/resources/[esx_addons]/ptelevision/html/VCR_OSD_MONO_1.001.ttf b/server-data/resources/[esx_addons]/ptelevision/html/VCR_OSD_MONO_1.001.ttf new file mode 100644 index 000000000..dcca687a4 Binary files /dev/null and b/server-data/resources/[esx_addons]/ptelevision/html/VCR_OSD_MONO_1.001.ttf differ diff --git a/server-data/resources/[esx_addons]/ptelevision/html/blank.html b/server-data/resources/[esx_addons]/ptelevision/html/blank.html new file mode 100644 index 000000000..4f830fa74 --- /dev/null +++ b/server-data/resources/[esx_addons]/ptelevision/html/blank.html @@ -0,0 +1,12 @@ + + + + + + +