Jump to content
Fivem-DEV.cz

Search the Community

Showing results for tags 'návod'.



More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Informace
    • Pravidla
    • Informace
    • Vyhlášení
  • rcore
    • Release
  • Fivem Dev
    • Pomoc
    • Upravené verze
    • Veřejně dostupné
    • Prezentace
    • Hledám / Nabizím
    • Návody
  • Fivem servery
    • Prezentace serverů
    • Recenze serverů
  • Temná doba
    • Cheateři / Buggeři
    • Podvodník
    • Ostatní

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


About Me

Found 39 results

  1. Zdravíčko, tento návod bude napsaný jednoduše a tak aby ho každý pochopil, nebudu zde vysvětlovat, proč se co dělá jen Vám tu přímo ukáži, jak si vytvořit font,který můžete streamovat pro fivem a tím pádem používat diakritiku v draw 3d textu nebo v notifikacích. Potřebné programy: - swf converter (http://swfmill.org/releases/swfmill-0.3.3-win32.zip) - gfw exporter gfxexport.zip Postup: 1) Vyberte si font U tohoto bodu je to jednoduché skočíme se na jakoukoliv stránku ohledně fontů preferuji google fonts,kde si vybereme font, který se nám libí a můžeme ho používat dle jeho licence, tento font si stáhneme k nám do počítače někam bokem do složky a měl by být ve formátu TTF 2) Vytvoříme si soubor in.xml Tento soubor bude za nás řešit, který font potřebujeme a bude použit při konverzi TTF do SWF pomocí programu swfmill <?xml version="1.0" encoding="iso-8859-1" ?> <movie version="8" width="320" height="240" framerate="12"> <frame> <library> <font id="Fire Sans" import="FiraSans-Regular.ttf" name="Fire Sans"/> </library> </frame> </movie> Jak vydíte soubor má v sobě iframe o který my se starat nebudeme, nám jde o hodnoty v parametru font a to ID, import a name - id = název fontu - import = cesta k fontu (název souboru pokud ho máte ve stejné složce) - name = název fontu 3) Provedeme konverzi TTF na SWF Ve stejné složce tedy máme font.ttf u nás tedy FireSans-Regular.ttf a in.xml, do této složky si vložíme i program swfmill, který můžete stáhnout pomocí odkazu výše. Příkaz pro provedení převodu: swfmill simple in.xml out.swf Použijeme klávesovou zkratku windows + R Do tohoto okýnka napíšeme cmd a zmáčkneme enter Otevře se nám příkazový řádek a v něm bychom se měli dostat do složky ve které se nám nachází font i program, u mě se nachází ve složce se serverem v assetech rcore takže jsem se dopracoval pomocí cd příkazů až do této složky, pokud nevíte co je cd a jak se pohybovat v konzoli prosím najděte si návod na youtube je tam toho hodně. Následně do tohoto příkazového řádku napíšeme příkaz který máte víš a zmáčkneme enter, nemělo by to napsat žádnou chybu a ve složce, kde máte in.xml by se měl vytvořit soubor out.swf 4) Vytvoříme z SWF GFX soubor,který již fivem umí streamovat Do složky přidáme soubor gfxexport.exe který si můžete stáhnout nahoře v tomto článku, následně do stejné příkazové řádky s cestou zadáme příkaz gfxexport.exe out.swf Mělo by se nám objevit něco takového a ve složce by měl být nový soubor out.gfx 4) Přejmenujeme out.gfx na název fontu U nás aktuálně třeba na firesans.gfx abychom byli schopni rozlišit ve složce, o který font se jedná. 5) Registrace fontu a streamování Vytvoříme si jednoduchý script a do něho vložíme tento kód na stranu klienta. Citizen.CreateThread(function() RegisterFontFile('firesans') -- název soubory gfx bez koncovky gfx fontId = RegisterFontId('Fire Sans') -- nazev ktery jsme dávali do in.xml print(string.format('[rcore] setting up font Fire Sans as ID: %s',fontId)) end) 6) Vložíme font.gfx do stream složky V našem resouru vytvoříme složku stream a do ní vložíme náš GFX soubor, mělo by být vše v pořádku. 7) Použití Použití je jednoduché, pro 3D text použijeme nativ nastavení fontu s ID které vytváříme a registrujeme v našem scriptu výše. SetTextFont(getFontId())
  2. Zdravim kdyz se tu delaji nejaky navody tak jsem chtel udelat taky jeden ktery je neskutecne jednoduchy,ale treba nejaky lidi o tom ani nevedi.. Tutiz jak pridat Item napr Kava aby se ve hre dala pit. Prvni co musite najit slozku pod jmenem esx_basicneeds nasledne do slozky server a otevrete si slozku main.lua pote uvidite zakladni 2 itemy chleba a vodu,to znamne aze pokud budu chtit jidlo skopiruji si chleba a pokud nejaky drink nebo cokolive jineho skopiruji si Vodu. Takze skopiruji si napr Vodu coz je toto: ESX.RegisterUsableItem('water', function(source) --TADY PREPISU WATER NA hotova_kava local xPlayer = ESX.GetPlayerFromId(source) --toto necham tak jak je xPlayer.removeInventoryItem('water', 1) --tady znovu prepisu water na hotova_kava TriggerClientEvent('esx_status:add', source, 'thirst', 200000) --kolik vam to prida ho pouziti itemu v hudu TriggerClientEvent('esx_basicneeds:onDrink', source) --toto nechte tak jak je TriggerClientEvent('esx:showNotification', source, _U('used_water')) --tady vam ukaze oznameni,tudiz bych sel napsal misto used_water used_kava. end) Takze budu chtit mit Item kava v mem pripade muj item kavy se jmenuje v Databazi/items hotova_kava takze misto water vsude napisi hotova_kava : ESX.RegisterUsableItem('hotova_kava', function(source) local xPlayer = ESX.GetPlayerFromId(source) xPlayer.removeInventoryItem('hotova_kava', 1) TriggerClientEvent('esx_status:add', source, 'thirst', 200000) TriggerClientEvent('esx_basicneeds:onDrink', source) TriggerClientEvent('esx:showNotification', source, _U('used_kava')) end) Potom kdyby jste si chteli upravit treba kolik to prida jidla/piti do vaseho hudu,tak to udelate tak ze TriggerClientEvent('esx_status:add', source, 'thirst', 200000) -- Zde zmenit 200000 na Mene nebo Vice Zmenite 200000 na mene nebo vice to uz je na vas,cim min tak tim mene se vam piti/jidlo prida,cim vic tak vic se vam jidlo/piti prida. A to je vse snad jsem nekomu pomohl :)
  3. Jak jistě víte jeden z injectorů má i možnost vypínat client side script na své straně což umožnuje danému člověku cheatovat na serveru pokud daný anticheat využívá hlavně detekci na client side jako například výbuchy, spawnování objektů a podobně, včera jsem udělal rozšíření bezpečnostního prvku frameworku rcore, kde můžete pomocí jednoduchého kódu rozšířit vlastní scripty o detekci vypnutí a daného uživatele zablokovat. Budete na to potřebovat poslední verzi rcore z masteru z gitu - https://github.com/isigar/relisoft_core Instalace a podobně je již v jiném návodu zde na foru tady se zaměříme jen na integraci ochrany Do svého scriptu na client side přidejte tento kód, první řádek zaregistruje resource, aby se checkoval či stále jede na straně rcore a ve druhém provádíme cyklus, kde posílám co 2s požadavek na rcore,že stále resource žije. Proč to tak funguje? Daný injector co umí vypínat client side vypíná thready a cykly ale eventy mu pořád fungují, proto my vytvoříme jednoduchý cyklus - fivemock ho vypne a client side nám přestane dávat vědět, že je živý což znamená,že ho někdo vypl mno a když už to víme, tak toho šulinka zabanujeme,že :) Client side TriggerServerEvent('rcore:registerCheck',GetCurrentResourceName()) AddEventHandler('rcore:changePlayer', function() TriggerServerEvent('rcore:checkDone', GetCurrentResourceName(), rcore:getClientKey(GetCurrentResourceName())) end) Citizen.CreateThread(function() while true do Citizen.Wait(2000) TriggerServerEvent('rcore:checkDone', GetCurrentResourceName(), rcore:getClientKey(GetCurrentResourceName())) end end) rcore automaticky takového člověka vyhodí ale před tím zavolá event, pro vaši implementaci banu, jelikož rcore nemá v sobě přímo banovací systém. Server side AddEventHandler('rcore:cheaterDetect',function(playerId, resource) --TODO: Zabanovat uživatele end) Kdyby jste měli jakékoliv dotazy pište sem :)
  4. Zdravíčko! Vítám Vás u jednoduchého a začátečnického počteníčka, jak začít se lua skriptováním v prostředí FiveM. Budu se snažit vysvětlit většinu věcí, co nejvíce do detailu, aby to pochopil doopravdy i jednotlivci. Předtím, než se vrhneme do FiveM by bylo fajn se seznámit s lua jazykem. Lua jako každý jiný jazyk (programovací / skriptovací) má vlastnosti, které můžete i nemusíte znát. Ovšem jsou sdílené napříč skoro všemi jazyky a tím, že budete dělat skripty se můžete začít zajímat i o reálné programování a svět okolo kódování. Pojďme si říct o těch vlastnostech. Proměnné / funkce / tipy Nejvíce základní věci všech jazyků jsou právě proměnné. Proměnné mají mnoho typů a také mají svojí takzvanou "dálku vidění" (scope) v daném kódu. V samotném lua jazyce existuje mnoha funkcí / metod, které jsou velmi užitečné a nemuseli jste je do teď znát. Jdeme si uvést příklady, se kterými se v lua skriptování můžeme potkat. -- Typy proměnných v lue -- Proměnnou si představte něco jako "úložiště" pro data. variable = nil -- Proměnná variable nemá hodnotu. variable = "string" -- Proměnná variable je string. A tento string obsahuje text "string". variable = 0 -- Proměnná variable je integer (v lue se používá number). Hodnotou je 0. -- POZOR!! -- V případě, že nastane případ, kdy proměnná variable vypadá takto: variable = "0" -- Tak se typově už NEJEDNÁ o number, ale o string. Nutno si toto rozlišit. Jak si to převést? variable = "0" alterVariable = tonumber(variable) -- Tato lua funkce nám zajistí, že ve stringu najde tu danou 0 a převede jí na 0. (proměnná se uvede jako number). -- tonumber() funkce se také dá použít jako check zda string obsahuje číslo, pokud ne vrátí Vám hodnotu nil (která se také beré jako false při podmínce) if tonumber("dfdf") then -- string "dfdf" obsahuje číslo (neobsahuje) else -- string "dfdf" neobsahuje číslo (neobsahuje) end -- Tato funkce je dosti používaná při pracování s daty, které jsou ve právě stringu. -- variable = {} -- table / pole, které může mít své vlastnosti. variable = true; variable = false -- boolean / pravda, nepravda. Na tomdle asi není, co víc vysvětlovat. -- Na závěr dodám, že existuje ještě jedna fajn lua funkce a tou je: type(variable) -- Zjistí Vám to typ dané proměnné. (string, number, table, boolean) -- -- Cykly -- Hlavní cykly -> for a while. Uvedeme si příklady použití obou. local locations = {"Praha", "Brno"} -- for ... do for i=1, #locations do -- Lua indexuje od 1. Tímpádem si vytvoříme proměnnou i, která bude mít počáteční hodnotu 1 a cyklus se provede tolikrát, dokud i nebude mít hodnotu #locations. (#locations je v našem případě délka tohoto pole. V tomto případě 2.) print(locations[i]) -- ukaž mi hodnotu v locations na indexu i. end -- while ... do local showingOnScreen = true -- ukazuje se něco na obrazovce? Ano. while showingOnScreen do -- jeden z mnoha příkladů -- VE FIVEM SE MUSÍ VE WHILE CYKLU ČEKAT! Citizen.Wait(počet milisekund) -- operace, která se bude provádět neustále dokud proměnná showingOnScreen nebude nepravda / false. end -- -- Scopes / viditelnost v kódu -- Mezi proměnnými v lua skriptování existují 2 scopy. local / global local variable = nil -- < Toto je lokální proměnná. variable = nil -- < Proměnná bez určení scopu je vždy globální. -- Kdy se s tímdle reálně setkáme ? -- Vytvoříme si nějakou funkci. useDefaultName = true -- Vytvoříme si proměnnou defaultName, která bude globální playerName = getPlayerName() -- Vytvoříme si proměnnou playerName, která bude globální. Tato proměnná zavolá metodu getPlayerName. function getPlayerName() -- Metoda / funkce. V rámci jednoduchosti tomu budeme říkat prostě funkce. local name -- Určíme si lokální proměnnou name. Aktuálně nemá hodnotu (nil). Jde používat pouze v rámci té funkce, kdekoliv jinde Vám bude později vracet nil. Tato proměnná pokaždé při zavolání této funkce nebude mít hodnotu. Nějakou hodnotu jí přidělíme. if useDefaultName then -- Uděláme si podmínku, která by se dala přeložit takto (pokud proměnná useDefaultName je pravda tak proveď) name = "Pavel" -- výše uvedená lokální proměnná name bude mít hodnotu Pavel (string), protože se zde její hodnota upravila za pomocí proměnné, která je "globální". else -- Pokud je podmínka nepravda (false) tak proveď operaci: name = "Franta" -- výše uvedená lokální proměnná name bude mít hodnotu Franta (string). end return name -- Metoda vrátí výše uvedenou proměnnou name. V našem případě vrátí Pavla. end -- Nyní se přesuneme na skriptování ve FiveM, protože tyto znalosti nám aktuálně stačí k tomu si vytvořit jednoduchý skript pro nakupování itemů (postavené na ESX). !! Upozorňuju, že Vás zde nebudu učit, jak vytvořit server / zapnout ho nebo jak dát resource do server.cfg. To snad víte všichni už. !! Vytvoříme si složku se skriptem. Např. strin_example pro moje účely. Do této složky si vytvoříme základní soubory (lua soubory) Můžeme si to uspořádat takhle: Ovšem já mám radši větší pořádek, a tak si to rozdělím pro lepší přehlednost. Do client a server složky si udělám: Tento soubor nám bude v obou případech sloužit jako hlavní skript mezi všemi v těch složkách. Nyní se vrátíme zpět a koukneme se do fxmanifestu. Ten by měl vypadat přibližně takto: fx_version 'cerulean' -- FX verze. resource_manifest_version je "deprecated" (zastaralé), nový výraz je fx_version game 'gta5' -- Hra, na kterou je resource / skript tvořen. (gta5 / rdr3 nebo i oboje -> games {gta5, rdr3}) client_scripts { -- Skripty, které se načtou clientovi. 'client/*.lua', -- Osobně využívám "globbing". Tedy nepíšu furt nové řádky 'client/jméno_skriptu.lua', ale napíšu 'client/*.lua' a to mi načte veškeré soubory ve složce client s příponou .lua 'config.lua' -- Soubor, který bude obsahovat konstanty / Config, bude sdílený pro clienta i server a nebude se měnit. } server_scripts { -- Skripty, které se načtou serveru. 'server/*.lua', -- opět "globbing". 'config.lua' -- opět sdílený soubot. } Nyní, když půjdeme na náš server a do F8 napíšeme refresh by nám mělo FiveM napsat, že soubor byl úspěšně načten. Takže resource máme ready a můžeme se do toho vrhnout. Jako první destinaci si dáme config.lua. Zde si napíšeme data, které chceme, aby používal client i server. Jelikož budeme dělat jako příklad shopy, tak si dáme tento kód. -- Zde si budu psát proměnné caps lockem. Vytvoříme si takové "fake" konstanty (nepřepisovatelné proměnné). -- Jelikož je lua case-sensitive tak nám toto nejvíce zaručí, že si to nepřepíšeme. ONESYNC = true -- Pokud jsme uživatelé onesyncu tak tato proměnná bude pravda. (Onesync je dobrá věc zejména díky server-side zabezpečení -> uvidíte později) ESX_VERSION = 1.1 -- Určení jaké ESX máme 1.1 a níže nebo 1.2 / v1-final. AMOUNT_TO_BUY = 1 -- Kolik si hráč koupí při jedné návštěvě? SHOP_LOCATIONS = { -- proměnná SHOP_LOCATIONS, která je pole a obsahuje vectory. vector3(20.33268737793,-1106.1296386719,29.797008514404), -- vector3 je víceméně table, které má 3 numerické hodnoty x, y, z a používá se ke koordinacím. vector3(25.747142791748,-1344.9035644531,29.497022628784), } SHOP_ITEMS = { -- table / pole SHOP_ITEMS pro itemy {name = 'bread', label = 'Chleba', price = 40}, -- další pole pro jednotlivý item {name = 'beer', label = 'Pivo', price = 60} } Základní data v configu máme a teď s nimi jdeme na client pracovat! :) Otevřeme si client/main.lua, v prohlížeči https://docs.fivem.net/natives/ a začneme. ESX = nil -- globální proměnná ESX Citizen.CreateThread(function() -- "vlákno", které nám načte ESX while ESX == nil do TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end) Citizen.Wait(0) end end) Citizen.CreateThread(function() -- naše hlavní "vlákno" AddTextEntry('OPEN_SHOPS:FIVEMDEV', '~INPUT_CONTEXT~ Otevrit obchod') -- Na začátku vlákna si vytvoříme text entry pro otevření obchodu. while true do -- cyklus while, který poběží vždy dokud pravda bude pravda. (To se chápeme, že vždy) Citizen.Wait(0) -- FiveM čekání lehce řečeno. (Pokud cyklus while nemá čekání tak se Vám FiveM freeze). V našem případě budeme chtít prozatím každý frame. local ped = PlayerPedId() -- Proměnná ped, která nám získa ID peda clienta. local coords = GetEntityCoords(ped) -- Proměnná coords, která získa koordinace entity. (pro nás to bude náš ped) local distanceToShop = 10000.0 -- Proměnná, která nám bude držet nejbližší distanci k jakémukoliv shopu for i=1, #SHOP_LOCATIONS do -- cyklus for local distance = #(coords - SHOP_LOCATIONS[i]) -- length operátor -> #(Naše koordinace - koordinace obchodu) if distance < distanceToShop then distanceToShop = distance end if distance < 50.0 then -- Pokud je vzdálenost menší, než 50 tak proveď DrawMarker( 21, -- typ markeru SHOP_LOCATIONS[i], -- naše koordinace na indexu i z cyklu for 0, -- směr X 0, -- směr Y 0, -- směr Z 0, -- rotace markeru X 0, -- rotace markeru Y 0, -- rotace markeru Z 0.5, -- šírka X 0.5, -- šírka Y 0.5, -- šírka Z 30, -- červená 50, -- modrá 100, -- zelená 140, -- alpha / opacity. 0 až 255 false, -- chceme, aby marker skákal? false, -- chceme, aby se marker otáčel ve směru hráčova vidění? nil, -- nemá vliv true -- chceme, aby se marker točil? ) -- vykresli marker. end if distance < 3.0 then -- Pokud je vzdálenost menší, než 3 tak proveď DisplayHelpTextThisFrame('OPEN_SHOPS:FIVEMDEV') -- Ukaž help text každý frame. if IsControlJustReleased(0, 38) then -- Pokud je zrovna spuštěna klávesa E, tak proveď openShopMenu() -- Zavolej funkci na otevření menu obchodu. end end end if distanceToShop > 60 then -- pokud je distance větší, než 60 tak nám čekej v tomto cyklu sekundu. (Značná optimalizace) Citizen.Wait(1000) end end end) function openShopMenu() -- funkce na otevření menu obchodu local elements = {} -- lokální proměnná elements, která nám bude sloužit jako pole pro elementy itemů -- Tato část je dost o pochopení ESX menu. Doporučuju se kouknout přímo na dokumentaci ESX. for i=1, #SHOP_ITEMS do -- cyklus for, používáme na itemy local item = SHOP_ITEMS[i] -- SHOP_ITEMS na indexu i (určité pole z SHOP_ITEMS) local itemLabel = string.format('%s - $%s / %sks', item.label, item.price * AMOUNT_TO_BUY, AMOUNT_TO_BUY) --[[ využijeme lua funkce string.format a uděláme si pěkný label pro náš item. string.format nahrazuje %s ve stringu námi udanými hodnotami. ]] table.insert(elements, {label = itemLabel, value = i}) --[[ vkládáme do pole elements pole, která má hodnoty label & value label bude mít hodnotu itemLabel a value bude mít hodnotu i (indexu itemu v poli) ]] end ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'shop_menu', { title = 'Obchod', -- Nadpis menu align = 'center', -- Kde se menu bude nacházet elements = elements, -- elementy menu }, function(data, menu) -- on select callback menu.close() -- Zavři menu po zakoupení itemu. TriggerServerEvent('strin_example:buyItem', data.current.value) -- Zavoláme server event na koupení itemu s udáním indexu na daný item. end, function(data, menu) -- on cancel callback menu.close() -- Zavři menu, když ho hráč chce zavřít. end) end Teď, když máme napsaný client se podíváme do server/main.lua. o_o ESX = nil TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end) --[[ opět si načteme esx, ovšem tentokrát na serveru. ]] RegisterNetEvent('strin_example:buyItem') -- Registrace network eventu. (server eventu) AddEventHandler('strin_example:buyItem', function(itemIndex) -- na tento event mi přidej handler s funkcí: local _source = source --[[ uložíme si ID sourcu. (source je vždy server ID clienta, který zavolal tento event) ukládáme si ho, abychom ho neztratili. ]] local xPlayer = ESX.GetPlayerFromId(_source) -- přes ESX si zjistíme hráče skrze ID if isPlayerNearShop(_source) then -- V této podmínce si zavoláme funkci zda je hráč blízko shopu a předáme jí ID hráče. local item = SHOP_ITEMS[itemIndex] -- uvedeme si jaký item si hráč zakoupil. V tomto případě item na indexu itemIndex local price = item.price * AMOUNT_TO_BUY -- cena na kus if canPlayerCarryItem(_source, item.name, AMOUNT_TO_BUY) then -- naše funkce, která nám zkontroluje zda hráč může dostat tolik itemu. if doesPlayerHaveEnoughMoney(_source, price) then -- naše funkce nám zkontroluje zda hráč má dostatek peněz. xPlayer.removeMoney(price) -- odečti cenu z hráčových kapes. xPlayer.addInventoryItem(item.name, AMOUNT_TO_BUY) -- xPlayer funkce na přidaní itemu TriggerClientEvent('esx:showNotification', _source, string.format('Koupil jste %s - %sx za $%s', item.label, AMOUNT_TO_BUY, price)) -- esx notify event end else TriggerClientEvent('esx:showNotification', _source, 'Máš plné bágly brácho') --[[ Jelikož nevím zda používám ESX 1.1 nebo výše, tak si to ujistím eventem, který mají obě verze. O tomto eventu si více můžete zjistit v ESX dokumentaci. ]] end else print('??') end end) function isPlayerNearShop(id) if ONESYNC then -- Uděláme si podmínku na to zda je ONESYNC proměnná v configu uvedená jako pravda. Pokud ano proveď: local ped = GetPlayerPed(id) -- zde používám GetPlayerPed(id) za účelem toho, že musím získat peda daného hráče a na serveru PlayerPedId()... To snad dojde všem, že ne. :D local coords = GetEntityCoords(ped) -- opět získáme koordinace local distanceToShop = 100 for i=1, #SHOP_LOCATIONS do -- opět for cyklus jako na clientovi local distance = #(coords - SHOP_LOCATIONS[i]) -- opět vypočteme vzdálenost if distance < distanceToShop then distanceToShop = distance end if distanceToShop > 10 then -- pokud vzdálenost od jakéhokoli shopu je větší, než 10 (budeme více tolerantní) tak proveď return false -- není blízko obchodu, vracím false end end end return true -- Na konec funkce si zapíšeme, že hráč je blízko shopu a vrátíme true. (v průběhu této funkce nám to může vrátit nějaký return dřív.) end function canPlayerCarryItem(id, item, count) local xPlayer = ESX.GetPlayerFromId(id) -- získáme si opět pomocí ESX hráče skrz ID if ESX_VERSION >= 1.2 then -- pokud je ESX verze nad 1.2 tak proveď: if xPlayer.canCarryItem(item, count) then -- xPlayer funkce to už řeší za nás. return true -- vrať true, hráč může nosit item end else local xPlayerItem = xPlayer.getInventoryItem(item) -- tato xPlayer funkce nám zjistí informace o itemu a stavu o itemu u hráče. if (xPlayerItem.count + count) <= xPlayerItem.limit then -- pokud je nový počet itemu u hráče menší, než limit nebo se rovná limitu tak proveď: return true -- vrať true, hráč můž nosit item end end return false -- vrať false, hráč má plný bágl PepegaClap end function doesPlayerHaveEnoughMoney(id, price) local xPlayer = ESX.GetPlayerFromId(id) -- získáme si opět pomocí ESX hráče skrz ID if (xPlayer.getMoney() - price) < 0 then -- odečti od aktuálních peněz, co má u sebe hráč cenu itemů. Pokud je to menší, než 0 tak nemá prachy. return false -- vrať false, hráč nemá na rohlík end return true -- vrať true, hráč může roztáčet prašule end No a pomocí těchto kroků se dokážete naučit psát jednoduché skripty. Není to hitparáda nějaká, ale tydle malé zkušenosti Vás můžou dovést k velkým věcem. Vždy je to o tom se učit a nechat si radit od zkušenějších. Snad Vám tento "tutoriál" nějak pomohl k sebe rozvoji a ještě si na závěr dodáme in-game ukázku. V blízkosti - 0.02 / 0.03 Idle - 0.01 Ozkoušet si to můžete sami, děkuju za pozornost. :) Pokud jsem na něco zapomněl nebo napsal blbost, tak se omlouvám. Píšu to už 3 hodiny a je 3:30. Dobrou noc. :D
  5. Zdravíčko, tentokráte se podíváme na věc, kterou již pár z vás jistě vyzkoušela, přidáte addon vozidla na server a v garáži nebo někde jinde se místo jeho jména zobrazuji NIL / NULL, jak toto opravit? Je to v celku jednoduché. Pokud používáte esx_advancedgarage tak můžete vytvořit tento script uvnitř této složky ať to máte pohromadě ale jedná se o client script, který lze vložit všude. 1) Vytvoříme si vehicle_names.lua soubor 2) V souboru vytvoříme nové vlákno Citizen.CreateThread(function() end) 3) Přidáváme názvy do tohoto vlákna Citizen.CreateThread(function() --Example 1: AddTextEntry('SPAWN_NAME_HERE', 'VEHICLE_NAME_HERE') AddTextEntry('18performante', 'Lamborghiny Huracan') end) 4) Přidáme do fxmanifest.lua zápis našeho nové resourcu nezapomeňte přidat verzi hry a další potřebné věci client_script { 'vehicle_names.lua' } Návod na fxmanifest.lua Hotovo 🙂
  6. Podíváme se jak na zámky dveří ve FiveM! 1) V první řadě budete potřebovat nějaký ten resource, který umožní dveře uzamknout. Např. https://github.com/esx-community/esx_doorlock/releases/tag/v1.3.0 Některé scripty mohou ubírat dost na ms, takže buďte při výběru scriptu obezřetní. Na trhu v této době můžete sehnat zámky, které umožnují snadné nastavení přímo ze hry. 2) Konfigurace samotných zámků. objHash = GetHashKey('v_ilev_ph_gendoor004'), -- název propu dveří; některé zámky využívají hash objHeading = 90.0, -- rotace dveří objCoords = vector3(449.6, -986.4, 30.6), -- pozice dveří textCoords = vector3(450.1, -986.3, 31.7), -- pozice textu authorizedJobs = {'police'}, -- oprávnění jobu locked = true, -- mají být dveře zamčeny po restartu? true = ano, false = ne maxDistance = 1.25 -- vzdálenost, od které můžete zámky ovládat (menší = lepší) Jak zjistit všechny potřebné informace o dvěřích? Každý využívá nejspíše to, co mu vyhovuje, ale já vám zde ukážu nejčastější řešení. 1) vMenu V development tools si zapnete prop dimensions a entity handles. vMenu vám ukáže hash dveří, který můžete poté vyhledat např.: https://forge.plebmasters.de/objects 2) CodeWalker Slyšíte o tomto programu poprvé? Je to dost šikovný program, který vám někdy může ulehčit práci. Na discordu CodeWalkeru si stáhněte nejnovější verzi programu: https://discord.gg/BxfKHkk Zkušenější "developeři" zde mohou využívat i addon MLO informace. 3) showme (přikládám) Showme rozhodně nespouštějte za provozu v server.cfg. Ukazuje dostatek informací, že může způsobit větší lag, doporučuji zapínat až ve hře a poté zase vypnout. showme 4) Menyoo Pokud někdo staví ymap přes Menyoo, mohou využívat také pravé tlačítko o detaily o propu. Jak zjistit název dveří u addon MLO? Otevřte si soubory v OpenIV a najděte zde dveře, které chcete zamknout. Název dvěří je nepochybně bez ".ydr" A takto mohou poté vypadat uzamknuté dveře.
  7. Zdravím, dnes ukážu nováčkům v DEV jak přepsat v ESX překlad scriptů. (EZ) 1. Najdeme script který chceme přepsat do českého jazyka (já použiji například esx_boat) 2. Otevřeme script a jdeme do config.lua, který si otevřeme 3. Najdeme políčko s názvem: Config.Locale = 'en'. Pro nás je potřebné zjistit v jakém jazyce se momentálně script nachází. Tady jde vidět že je v jazyce EN - angličtina 4. Teď když víme v jakém jazyce je script tak můžeme zavřít config.lua a otevřeme soubor, který se nachází Locales --> en.lua (nebo jazyk ve kterém máte script např de.lua) 5. Přepíšeme překlad podle potřeby 6. uložíme a restartujeme script. HOTOVO Alternativní možnost: Pokud se nachází ve souboru locales překlad cs tak stačí jít do config.lua kde se přepíše z Config.Locale = 'en' na Config.Locale = 'cs' a máte hotovo jelikož překlad tu již byl hotový od tvůrců.
  8. Zdravím, přidám zde návod na to jak ukládat poškození vozidel, funguje to v jakémkoliv scriptu na garáže, uložené poškození zůstane i po restartu serveru. Budeme to nastavovat v es_extended. NÁVOD: Jako první si otevřeme \es_extended\client\functions.lua a najdeme si: modLivery = GetVehicleLivery(vehicle), nezapomene zapsat čárku na konci řádku a přidáme další řádek: health = GetVehicleEngineHealth(vehicle) Jako druhý krok si najdeme též v functions.lua toto: if props.modLivery ~= nil then SetVehicleMod(vehicle, 48, props.modLivery, false) SetVehicleLivery(vehicle, props.modLivery) end a přidáme pod tuto část toto: if props.health ~= nil then SetVehicleEngineHealth(vehicle, props.health+0.00) end Nyní se vám bude ukládat poškození vozidla, funguje to pro jakékoliv garáže a auta zůstanou poškozená i po restartu.
  9. Tento návod ukazuje jednoduchý kód,který se dá použít na server-side straně a funguje proti spawnování objektů a i proti spawnování blacklisted vozidel, tyto vozidla zmizí a ostatní klienti nejsou nasraní, není to anticheat na vše :) Jen na spawnování ale myslím,že je lepší něco než nic :) Např: http://prntscr.com/te8vvb Tato ochrana využívá onesync eventů, bez něho nepojede. PROSÍM NEZAPOMEŇTE SI UPRAVIT BLACKLIST A WHITELIST Blacklisted vozidla - sem patří všechny vozidla, které nechcete aby šli spawnout například hydra Whitelisted objekty - objekty, které jdou spawnou na serveru, najdete je v kódu většinou u CreateObject Server-side kód: SConfig = {} SConfig.WhitelistedObjects = { 'prop_v_cam_01', 'p_ing_microphonel_01', 'apa_mp_apa_yacht_jacuzzi_ripple1', 'xm_prop_x17_l_door_glass_01', 'xm_prop_x17_l_glass_01', 'xm_prop_x17_l_glass_02', 'xm_prop_x17_l_glass_03', 'prop_cs_burger_01', 'prop_ld_flow_bottle', 'prop_tool_pickaxe', 'prop_cs_remote_01', 'prop_cs_hand_radio', 'prop_v_bmike_01', 'hei_p_m_bag_var22_arm_s', 'hei_prop_heist_thermite', 'hei_prop_hst_laptop', 'hei_prop_heist_card_hack_02', 'p_ld_id_card_01', 'hei_prop_heist_cash_pile', 'prop_amb_phone', 'ng_proc_sodabot_01a', 'ng_proc_box_01a', 'ng_proc_food_burg01a', 'ba_prop_battle_glowstick_01', 'ba_prop_battle_hobby_horse', 'p_amb_brolly_01', 'prop_notepad_01', 'prop_pencil_01', 'hei_prop_heist_box', 'prop_single_rose', 'prop_cs_ciggy_01', 'hei_heist_sh_bong_01', 'prop_ld_suitcase_01', 'prop_security_case_01', 'prop_police_id_board', 'p_amb_coffeecup_01', 'prop_drink_whisky', 'prop_amb_beer_bottle', 'prop_plastic_cup_02', 'prop_amb_donut', 'prop_sandwich_01', 'prop_ecola_can', 'prop_choc_ego', 'prop_drink_redwine', 'prop_champ_flute', 'prop_drink_champ', 'prop_cigar_02', 'prop_cigar_01', 'prop_acc_guitar_01', 'prop_el_guitar_01', 'prop_el_guitar_03', 'prop_novel_01', 'prop_snow_flower_02', 'v_ilev_mr_rasberryclean', 'p_michael_backpack_s', 'p_amb_clipboard_01', 'prop_tourist_map_01', 'prop_beggers_sign_03', 'prop_anim_cash_pile_01', 'prop_pap_camera_01', 'ba_prop_battle_champ_open', 'p_cs_joint_02', 'prop_amb_ciggy_01', 'prop_ld_case_01', 'prop_cs_tablet', 'prop_npc_phone_02', 'prop_sponge_01', 269934519, 2007413986, 881130828, 769923921, 2714348429, } SConfig.BlacklistedVehicles = { "vigilante", "hydra", "buzzard", "deluxo", "freight", "avenger", "akula", "apc", "barrage", "caracara", "cargobob", "chernobog", "hunter", "insurgent", "starling", "lazer", "bombushka", "savage", "rhino", "khanjali" } CONST_POPULATION_TYPE_MISSION = 7 CONST_ENTITY_TYPE_OBJECT = 3 CONST_ENTITY_TYPE_VEHICLE = 2 CONST_ENTITY_TYPE_PED = 1 AddEventHandler('entityCreating', function(id) local _source = source local model = GetEntityModel(id) local eType = GetEntityType(id) if eType == CONST_ENTITY_TYPE_OBJECT then --Objects for i, v in pairs(SConfig.WhitelistedObjects) do local v = (type(v) == 'number' and v or GetHashKey(v)) if v == model then return end end print(string.format('Model not whitelisted %s', model)) CancelEvent() elseif eType == CONST_ENTITY_TYPE_VEHICLE then for i, v in pairs(SConfig.BlacklistedVehicles) do local v = (type(v) == 'number' and v or GetHashKey(v)) if v == model then print(string.format('Vehicle not whitelisted %s', model)) CancelEvent() end end local speed = GetEntityVelocity(id) if #(speed-vector3(0,0,0)) > 35.0 then CancelEvent() end end end)
  10. OneSync Infinity a jeho neřesti OneSync Infinity a jeho přednost je, že umožňuje téměř neomezený počet slotů a že si client nenačítá všechny hráče na serveru, ale pouze ty v okolí - hráč má zónu, budeme jí nyní nazývat třeba "render zone". Tato zóna, dle všeho, je velká 400 GTA units, tzn. pokud chcete zjistit hráče na druhé straně mapy, tak ho nezjistíte -> Proto je potřeba zjišťovat hráče (pokud to je nutné), tak serverově. Níže si řekneme asi nejzákladnější problémy, které může a s nějvětší pravděpodobností OneSync Infinity bude způsobovat. 1) Chat Dost lidí, při zapnutí OneSync Infinity přijde na server, začne si sundavat boty (/me sundavá botu z levé nohy) a najednou se na druhé straně mapy zleká, co se děje, proč vidí, že si někdo sundavá boty i když u něho nikdo není. Opravu si ukážeme na následujícím esx_rpchat"u". (https://github.com/esx-framework/esx_rpchat/blob/master/client/main.lua) RegisterNetEvent('esx_rpchat:sendProximityMessage') AddEventHandler('esx_rpchat:sendProximityMessage', function(playerId, title, message, color) local player = PlayerId() local target = GetPlayerFromServerId(playerId) local playerPed = PlayerPedId() local targetPed = GetPlayerPed(target) local playerCoords = GetEntityCoords(playerPed) local targetCoords = GetEntityCoords(targetPed) if target == player or #(playerCoords - targetCoords) < 20 then TriggerEvent('chat:addMessage', {args = {title, message}, color = color}) end end) Takto nějak (jak je ukázáno výše) vypadá normální funkčí client side event na posílání eventu, který všem hráčů v blízkosti ukáže proximity message. No jo, ale proč se ta zpráva na OneSync Infinity ukáže klidně i hráčům přes celou mapu? Je to prostě -> Hráč mimo zónu bude mít "GetPlayerServerFromId" - nebo jeho, -1 a coords budou vector3(0.0, 0.0, 0.0) a když se od sebe odečtou, tak to bude splňovat podmínku, že vzdálenost je menší než 20 GTA units a proto se ukáže zpráva i jemu. Tento problém se dá vyřešit pouhým přidáním 2 řádků (nebo-li podmínky), která bude kontrolovat, zda "target" není -1: RegisterNetEvent('esx_rpchat:sendProximityMessage') AddEventHandler('esx_rpchat:sendProximityMessage', function(playerId, title, message, color) local player = PlayerId() local target = GetPlayerFromServerId(playerId) if target ~= -1 then local playerPed = PlayerPedId() local targetPed = GetPlayerPed(target) local playerCoords = GetEntityCoords(playerPed) local targetCoords = GetEntityCoords(targetPed) if target == player or #(playerCoords - targetCoords) < 20 then TriggerEvent('chat:addMessage', {args = {title, message}, color = color}) end end end) No a takovouto jednoduchou podmínkou se bám opraví problém s chatem, kdy zpráva je viditelná pro všechny hráče na serveru. Jednoduché, ne? Ještě bych rád dodal, že toto mi NIKDO neporadil a tento "fix" jsem našel na fóru https://forum.cfx.re . 2) Neexistující ID entity (špatné ID entit) Při OneSync Infinity (i normální server bez OneSync) mohou mít problémy, kdy si spawnou entitu, vzdálí se od ní a vrátí se k entitě, mají uložené její ID v proměnné, ale už to ID entity není stejné jako to uložené v proměnné a script nefunguje tak, jak má. Je to z důvodu toho, že když se od auta vzdálím z "render zone", tak se smaže a když se vrátím, tak se vytvoří znova. Dá se tím pracovat pomocí NetworkGetEntityFromNetworkId NetworkGetNetworkIdFromEntity Kdy tyto 2 natives zobrazí ID entity, které se nemění při vzdálení se od entity Nutno podotknout, že toto píši po zhlédnutí videa od pana "teb" z LSRP.cz a čerpám z informací, které on řekl, takže pokud se chcete dozvědět více, určitě byste měli zajít se podívat na toto video a celý kanál LSPR.cz : 3) Spawnování entit na vzdálenost Jak je OneSync Infinity známý pro svojí možnost "neomezeného" počtu hráčů, tak asi dá logiku, že kdyby si client načítal a stáhoval stále 1024 hráčů, tak by to nedělalo dobro. To znamená, že pokud budete stát na letišti v Los Santos (LSIA) a budete tam chtít udělat heist, že na tom letišti se vám spawne letadlo a budete mít nějaké drogy, letadlem je převezete do Sandy Shores a tam to rozvezete dodávkou. Pokud budete chtít kolečko u letiště, dát E a spustí se heist, vy si spawnete auto v Sandy, Letadlo na letišti v LSIA, tak bude problém. Problém bude, protože letadlo v Sandy Shores bude s největší pravděpodobností smazáno OneSyncem, protože se nachází mimo render zone. Takže to dané auto musíte spawnout jiném způsobem, letadlo u vás na letišti by nemělo dělat problém. Spustíme si "heist" a potom, třeba každé 2 sekundy si řekneme: "Je hráč 250 units a méně od místa kde chci spawnovat auto"? -> "Ne" - Počkám sekundu a proces zopakuji -> "Ano" - Jdu k dalšímu kroku - "Je auto již spawnuté"? -> "Ano" - Nic nedělám -> "Ne" - Spawnu auto a zapíši si, že je auto již spawnuté, aby se nám každou 1 sekundu nespawnulo 1 auto. Ale abychom byli trochu konkrétnější, tak si ukážeme jeden problém, které jsem před nedávnem řešil a to konkrétně problém s aircraft shopem, kdy se mi letadlo nespawnulo po zakoupení a hráč neměl ani peníze a ani stroj. Pro ukázku si půjčíme tento script: https://github.com/HumanTree92/esx_aircraftshop/blob/master/client/main.lua. No a letadlo se nám nezobrazí, protože ho budeme chtít dělat mimo render zone. To si můžeme zjistit následujícím "výpočtem" print(#(vector3(-965.2, -2983.5, 14.5) - vector3(-1874.7, -3137.5, 14.9))) No a protože je to daleko, tak se spawne, nám zmizí a potom máme smůlu. Dá se tomu předejít tak, že prvně hráče "portnete" na místo, kde se má stroj spawnout a potom až ho spawnete no a to si můžeme udělat nějak takto: ESX.TriggerServerCallback('esx_aircraftshop:buyVehicle', function(success) if success then IsInShopMenu = false menu2.close() menu.close() DeleteDisplayVehicleInsideShop() SetEntityCoords(playerPed, Config.Zones.ShopOutside.Pos) -- Zde si hráče portneme na místo spawnu letadla a letadlo nadále nezmizí ESX.Game.SpawnVehicle(vehicleData.model, Config.Zones.ShopOutside.Pos, Config.Zones.ShopOutside.Heading, function(vehicle) TaskWarpPedIntoVehicle(playerPed, vehicle, -1) SetVehicleNumberPlateText(vehicle, generatedPlate) FreezeEntityPosition(playerPed, false) SetEntityVisible(playerPed, true) end) else ESX.ShowNotification(_U('not_enough_money')) end end, vehicleData.model, generatedPlate) Jenom bych rád, v neposlední řadě, pro rejpaly jako pan J****, B***** a tak dále a tak dále, že neříkám, že toto je tak nějak správně, že je to nejlepší a nejfunkčnější řešení. Jen říkám, jak bych a jak jsem to udělal já, jak to u nás na serveru se 100 hráči denně funguje a jak si myslím, že je to dobře. A pokud proti tomuto máte výhrady, tak k tomu napište prosím napiště konstruktivní a objektivní kritiku a dá se s tím něco dělat, ale jinak ... .
  11. Zdravím, viděl sem že zde má hodně lidí problém s mumblem tak vám tu sepíšu malý tutoriál 1. Stáhneme mumble voip Vložíme do resources 2. Zapíšeme do server.cfg Prosím aby jste tohle zapsali dříve v startu než hardcap start mumble-voip start rp-radio setr voice_use3dAudio true setr voice_useSendingRangeOnly true 3. Smažeme Server Cache 4. Zapneme server NESMÍTE MÍT AKTIVNÍ ŽÁDNÝ DALŠÍ VOICE SYSTÉMY Pro Integraci GcPhone Otevřeme gcphone/client/client.lua Najdeme si řádek 377 následně nahradíme NetworkSetVoiceChannel(infoCall.id + 1) NetworkSetTalkerProximity(0.0) za tohle exports["mumble-voip"]:SetCallChannel(infoCall.id + 1) -- NetworkSetVoiceChannel(infoCall.id + 1) -- NetworkSetTalkerProximity(0.0) Následně zase najdeme řádek 392 zase nahradíme Citizen.InvokeNative(0xE036A705F989E049) NetworkSetTalkerProximity(2.5) za tohle exports["mumble-voip"]:SetCallChannel(0) --Citizen.InvokeNative(0xE036A705F989E049) --NetworkSetTalkerProximity(2.5) Doufám že jsem pomohl jestli ano budu rád když mi tu necháte srdičko .) S Láskou Mr.N0BODY
  12. Je to jednoduché stačí escapovat znaky, přidáme funkci do scoreboardu function escape(str) str = string.gsub( str, '&', '&amp;' ) str = string.gsub( str, '<', '&lt;' ) str = string.gsub( str, '>', '&gt;' ) str = string.gsub( str, '"', '&quot;' ) str = string.gsub( str, "'", '&apos;' ) str = string.gsub( str, "/", '&#47;' ) return str end A upravíme funkci AddPlayerToScoreboard function AddPlayerToScoreboard(xPlayer, update) local playerId = xPlayer.source connectedPlayers[playerId] = {} connectedPlayers[playerId].ping = GetPlayerPing(playerId) connectedPlayers[playerId].id = playerId connectedPlayers[playerId].name = escape(xPlayer.getName()) connectedPlayers[playerId].job = xPlayer.job.name if update then TriggerClientEvent('esx_scoreboard:updateConnectedPlayers', -1, connectedPlayers) end Citizen.CreateThread(function() Citizen.Wait(3000) TriggerClientEvent('esx_scoreboard:toggleID', playerId, true) end) end
  13. Ahoj. Vydávam ďalší návod. Nezabudni ma podporiť Srdiečkom alebo upvotom! Odkaz na video :
  14. Ahoj, pár týdnu zpět jsem dělal stream primárně pro programátory LSRP, kde jsem jim chtěl předat základní znalosti na téma ID entity a komunikace client-server-client. Jeden z nich to šikovně natočil, tak jsem se rozhodl to zveřejnit na LSRP youtube pro všechny. Velká část streamu je dedikovaná porozumění entitám - entity ID a entity network ID, pak také PlayerID a PlayerServerId. Část pak komunikaci client-server-client.
  15. Přidávám sem důležité řádky, jak si zapnout vypisování toho, co Vám lítá na databázi do souboru, velice se to hodí pokud máte nějaký mysql error a nevíte jaký, zde to zjistíte, tyto řádky vložte přímo pod hodnoty pro připojení. set mysql_debug 1 #zapnutí debugu set mysql_debug_output "file" #vypisování do souboru ještě se dá použít hodnota console ale pak to hodně spamuje :) set mysql_slow_query_warning 1 #pokud je nějaká query moc pomalá dá to vědět a můžete s tím něco dělat
  16. Dobrý den, chtěl bych se s vámi podělit o to, jak udělat, aby o krádeži obchodu/banky dostali oznámení i sheriffové. Stačí ve scriptu na vykrádání, který používáte jít do server-side lua a tam vyhledat if xPlayer.job.name == 'police' then Tento text nahradíte za if xPlayer.job.name == 'police' or xPlayer.job.name == '<název Sheriff jobu, například sheriff>' then Tento text musíte nahradit v kódu několikrát. :) No a nyní veškeré notifikace dostanou sheriffové a policisté. 👍🏻 Doufám, že jsem pomohl. - itIsMaku
  17. Cs, přikládám sem podrobný tutorial/návod k zmenšení textur, doufám, že to je vše srozumitelné. K čemu? - menší FPS drop rate, je-li více vozů u sebe - u některých vozů můžou textury bugovat a problikávat, neboť FiveM podporuje velikost .ytd souborů jen do 16 MB Co je potřeba? - OpenIV - program k otevření souborů - XnResize - program k zmenšení textur (lze využít jakýkoliv jiný program, který zvládne uložit texturu v .dds nebo .png) - volná složka 1. Otevřeme soubor vozu v OpenIV a povolíme Edit mode 2. Nalezneme .ytd soubor a otevřeme ho - v mém případě v dlc.rpf\x64\levels\gta5\vehicles.rpf - je zde vidět, že .ytd soubor má lehce více jak 21,7 MB 3. Exportujeme textury přes "Export all textures" a ve formátu DirectDraw Surface (*.dds) do volné složky a počkáme, než se vše exportuje - v mém případě jsem si jí pojmenoval "63lb - textury" - složka by měla vypadat takto: 4. Otevřeme XnResize a posuneme si ho vedle naší složky 5. Označíme všechny .dds soubory, které chceme nechat zmenšit a přesuneme je do XnResize 6. Dáme na horní liště sekci "Akce" - zkontrolujeme, že máme přednastavený režim "Přižpůsobit" - následně vedle nastavení Šířky a výšky nastavíme "procent" - v případě, že nemáme odškrtnuto "zachovat poměr", tak ho zaškrtneme 7. Nastavíme procenta, o kolik chceme naše soubory celkově zmenšit - nastavené je 50%, takže když je textura například 4096x2048, tak se zmenší na 2048x1024 8. Klikneme na horní liště na "Výstup" - rozklikneme u nastavení výstupní složky (output filename) rozklikneme 3 tečky a zvolíme naší složku s texturami "63lb - textury" - v ní si vytvoříme novou složku, aby se nám to nepomíchalo, například "Hotovo" - rozklikneme si nastavení formátu a tam si zvolíme DDS - Direct Draw Surface - poté, co vše vyplníme dáme konvertovat - po konvertování se nám všechny naše konvertované soubory uloží v složce 63lb - textury\Hotovo - můžeme XnResize vypnout, dál ho potřebovat nebudeme 9. Otevřeme si zpátky .ytd soubor v OpenIV (viz bod č. 2) a vlevo nahoře dáme "Import", označíme všechny naše textury a zmáčkneme "Hotovo" - poté stačí dát vpravo dole Save a vyčkáme, než se to vše uloží Po uložení se nám soubor zmenší pod 16MB, což už je pro FiveM použitelné. Porovnání: - vepředu model s 21 MB .ytd, vzadu s 3,5 MB Notes: - zmenšení už malých textur je zbytečné, například textura, která má už 4x4 pixelů - zmenšením textur se taktéž snižuje kvalita - jestli chcete zanechat nějaký textury nepozměněné, stačí je v kroku č. 5 neoznačovat
  18. 1) Najdu si nějakou mapu FREE na gta5-mods.com (Mapa musí být YMAP/ Pokud se značí YMAP ale jsou tam soubory jiné koncovky tak se dají také využít) 2) Stáhnu ji 3) Na ploše vytvořím složku s jakýmkoliv názvem pro mapu (Příklad PolicejniInterier) 4) Stáhnu resource v popisku tohoto návodu. 5) Vložím __resource do složky a ve složce např. PolicejniInterier vytvořím složku stream 6) Soubory ze staženého souboru z gta5-mods vložím do složky stream DOBROVOLNĚ 7) Vytvořím ve WinSCP v resources složku [maps] 8) Vložím PolicejniInterier do složky [maps] 9) Do server.cfg vložím start nazev_slozky (V našem případě PolicejniInterier) 10) Hotovo
  19. Ako RESKINovať Addon Vozidlo Budete potrebovať : - OpenIV - https://openiv.com/ - Nejaký editor fotiek. (MUSI PODPOROVAT FORMAT .DDS INAC VAM TO NEPOJDE!!!!) Alebo si stiahnite .DDS plugin do photoshopu. ČASŤ PRVÁ - Vozidlo a nastavenie OpenIV Stiahnite si hocijaké Addon auto zo stránky gta5mods.com, alebo z lcpdfr.com Otvorte OpenIV a kliknite hore na Tools a potom na ASI Manager Potom už len nainštalujte všetky veci okrem OpenCamera Potom budete musieť otvoriť zložku Gta 5 cez normálny prieskumník, čiže steam/steamapps/common/Grand Theft Auto V/ Skopírujte si priečinky x64 a update a vložte ich do priečinku mods Addon vozidlo si pripravte zatial pomocou tohto návodu - https://fivem-dev.cz/index.php?/topic/47-přidávání-add-on-vozidel/ Súbory typu .yft .ytd vložte do složky mods. MUSÍTE MAT ZAPNUTY EDIT MODE Otvorte .ytd súbor v OpenIV a mali by sa vám ukázať textúry. Vyberte si textúru ktorú chcete upraviť a kliknite na Export selected Vložte vašu exportovanú textúru do Photo Editora. Ja používam GIMP. A potom už len replacnite textúru svojou upravenou textúrou Upravené súbory potom dajte do priečinku stream. Addon auto si možete nainštalovať na svoj server pomocou tohto návodu - https://fivem-dev.cz/index.php?/topic/47-přidávání-add-on-vozidel/ ZÁVER Dúfam že tento tutoriál pomohol, možete to využit pre svoje frakcie :D Ak som zasa niečo dojebal, zasa ma možete opraviť a ja vam dám reputáciu. DISCORD : Bromomento#2778
  20. Návod na vytvorenie mapy YMAP cez CodeWalker Budete potrebovať : Codewalker : https://www.gta5-mods.com/tools/codewalker-gtav-interactive-3d-map A nainštalované GTA 5 ČASŤ PRVÁ - NASTAVENIE CODEWALKERU Krok 1 - Otvorte menu v Codewalker. Pre pepíkov : Musíte kliknúť na tlačítko, ktoré je zakrúžkované na obrázku. Krok 2 - Zapnite si DLC možnosť. Zasa pre pepíkov : Zaškrtnite políčko "Enable DLC" viz. na obrázku. Krok 3 - Otvorte sekciu Selection a tam si zapnite Mouse Select a Mód si nastavte na Entity Pre pepíkov : Záver : Super a teraz ste pripravený pridávať objekty! ČASŤ DRUHÁ - PRIDÁVANIE OBJEKTOV Krok 1 - Stlačte písmeno T a mal by sa vám objaviť tento Tool Bar. Krok 3 - Vytvorte YMAPU a pridajte tam objekt. Kliknite na new file a potom na New ymap file Malo by sa vám otvoriť toto okienko : Premenujte si mapu. Kliknite na políčko Ymap hore a kliknite New Entity. Malo by sa vám vytvoriť entita v podobe vajíčka. S entitou môžete hýbať a otáčať pomocou toolbaru. Entitu môžete zmeniť tu : Nejaké propy môžete nájsť na tomto webe: https://plebmasters.de/?app=objects Ja použijem: prop_palm_med_01b Položte si entitu na nejaké miesto kde chcete. Ja si moju palmu dám na HL. Garáže Entitu môžete duplikovať pomocou klávesy LSHIFT. - Pre pepíkov Ľavý Shift. Ja som si na HL. Garáže pridal palmy. ČASŤ TRETIA - EXPORT Stlačte Calculate all flags a Calculate all extents. Potom už len súbor uložte ako .ymap do hocijakého priečinka. Potom nezabudnite na Manifest! Skopírujte si celý kód manifestu, a dajte ho do textového editora a uložte to ako formát .ymf (Odporúčam Notepad++) (v starších verziach ide rovno stiahnuť súbor _manifest.ymf) Vytvorte si priečinok napr. MojaMapa, tam vytvorte ďalší priečinok s názvom stream a tam presuňte vaš YMAP a YMF súbor. Už len stačí keď interiér nainštalujete pomocou tohto návodu : https://fivem-dev.cz/index.php?/topic/186-jak-přidávat-mapu-na-server-ymap/ ZÁVER Ak by náhodou niečo nefungovalo, alebo som sem niečo napísal zle, nebojte sa mi to povedať :D Som občas krypel a niečo pokazím. Neviem čím sa tu hodnotia príspevky, ale poteším sa za každý like alebo upvote. Za dostatočný počet upvotov urobím aj návod na retextúrovanie budov a interiérov :D Pre nejaké dotazy ma môžete kontaktovať na discorde : Bromomento#2778 Ale prosím nevolajte mi, alebo nepíšte mi o polnoci. Díky <3
  21. Zdravím, koukal sem že je tu dosti nových lidí kteří by chtěli zkusit dělat Car Developera tak tu vydávám menší tutoriál jak na to. Tutoriál obsahuje : 1. Jak streamovat addon auta 2. Jak streamovat X aut v jednom resourců Youtube Link
  22. Tento návod je pro starší verzi ESX, protože s novější už jsem nepracoval, ale měla by se dát v pohodě přenést i na novější verze. Úprava byla dělána pro esx verzi, která používá v inventáři limit místo váhy. Počet řádků tabulky es_extended roste exponencionálně s počtem hráčů a itemů - jelikož u každého hráče vytvoří záznam s předmětem a to i v případě, že jej hráč u sebe nemá (tedy count = 0). Postup: 1. Úprava načítání inventáře V souboru: es_extended/server/main.lua Uvnitř tohoto eventu: AddEventHandler('es:playerLoaded', function(source, _player) Nalezneme část, kde se načítá inventář. Poznáme to dle komentáře: -- Get Inventory Celou část upravíme a přepíšeme následovně: -- Get Inventory table.insert( tasks, function(cb) MySQL.Async.fetchAll( "SELECT * FROM `user_inventory` WHERE `identifier` = @identifier", { ["@identifier"] = player.getIdentifier() }, function(inventory) local tasks2 = {} for i = 1, #inventory do local item = ESX.Items[inventory[i].item] if item then table.insert( userData.inventory, { name = inventory[i].item, count = inventory[i].count, label = item.label, limit = item.limit, usable = ESX.UsableItemsCallbacks[inventory[i].item] ~= nil, rare = item.rare, canRemove = item.canRemove } ) else print(('es_extended: invalid item "%s" ignored!'):format(inventory[i].item)) end end for k, v in pairs(ESX.Items) do local found = false for j = 1, #userData.inventory do if userData.inventory[j].name == k then found = true break end end if not found then table.insert( userData.inventory, { name = k, count = 0, label = ESX.Items[k].label, limit = ESX.Items[k].limit, usable = ESX.UsableItemsCallbacks[k] ~= nil, rare = ESX.Items[k].rare, canRemove = ESX.Items[k].canRemove } ) end end Async.parallelLimit( tasks2, 5, function(results) end ) table.sort( userData.inventory, function(a, b) return a.label < b.label end ) cb() end ) end ) Tím jsme zajistili, že se nám v DB nebudou vytvářet záznamy s count = 0. 2. Ukládání inventáře V souboru: es_extended/server/functions.lua Uvnitř této funkce: ESX.SavePlayer = function(xPlayer, cb) Nalezneme část, kde se ukládá inventář postavy. Poznáme to dle komentáře: -- Inventory items Celou část upravíme a přepíšeme následovně: -- Inventory items for i = 1, #xPlayer.inventory, 1 do if ESX.LastPlayerData[xPlayer.source].items[xPlayer.inventory[i].name] ~= xPlayer.inventory[i].count then table.insert( asyncTasks, function(cb) MySQL.Async.execute( "UPDATE user_inventory SET `count` = @count WHERE identifier = @identifier and item = @item", { ["@count"] = xPlayer.inventory[i].count, ["@identifier"] = xPlayer.identifier, ["@item"] = xPlayer.inventory[i].name }, function(rowsChanged) if rowsChanged == 0 then MySQL.Async.execute( "INSERT INTO `user_inventory` (count, identifier, item) VALUES (@count, @identifier, @item)", { ["@count"] = xPlayer.inventory[i].count, ["@identifier"] = xPlayer.identifier, ["@item"] = xPlayer.inventory[i].name }, function(rowsChanged) if cb ~= nil then cb() end end ) else cb() end end ) end ) ESX.LastPlayerData[xPlayer.source].items[xPlayer.inventory[i].name] = xPlayer.inventory[i].count end end Tím zařídíme, že pokud hráč u sebe předmět již měl, jenom se upraví počet. Pokud neměl, vytvoří se nový záznam. 3. Mazání záznamů s count = 0 Poslední krok. Mazání záznamů s count = 0 můžete dělat kdekoliv a jakkoliv. Ideálně při startu es_extended v souboru: es_extended/server/common.lua Stačí do události AddEventHandler('onMySQLReady', function () přidat následující dotaz: MySQL.Async.execute("DELETE FROM user_inventory WHERE `count` = 0", {}) A tadááá, to je celé kouzlo. Velikost databáze se vám tak klidně může zmenšit z 500 000 záznamů třeba na 5 000, čímž dotazy do této tabulky značně urychlíte.
  23. Ahoj, podělím se o velmi jednoduchý "návod" jak "opravit" problém s databází při používání anticheatu chocohax. Většina serverů má problém, že jim server s chocohaxem bootuje moc dlouho a timeoutne db, tudíž stačí zvětšit čas. Pro připojení databáze k serveru použijte tento formát (pouze doplňte svoje údaje): SERVER.CFG set mysql_connection_string "mysql://uzivatel:heslo@host/jmenodb?connectTimeout=60000&acquireTimeout=60000&timeout=60000&charset=utf8mb4" uzivatel = uživatelské jméno (příklad: kFxDaKing) heslo = heslo (př.íklad: kFx12345) host = hostitel (příklad: 51.77.42.13) jmenodb = jméno databáze (příklad: server) Tuším, že tento formát funguje jen s novější verzí mysql-async - https://github.com/brouznouf/fivem-mysql-async
  24. Návod na opravu gcphone pro novou verzi es_extended v1-final Sám jsem potřeboval tento fix, když už jsem ho našel a dal dohromady tak jsem se rozhodl zveřejnit ho i pro ostatní aby jste nemuseli hledat tak dlouho jako já :) Toto je oprava pokud máte místo tel. čísla XXX-XXXX gcphone/server/server.lua Najděte si AddEventHandler('es:playerLoaded',function(source) local sourcePlayer = tonumber(source) local identifier = getPlayerID(source) getOrGeneratePhoneNumber(sourcePlayer, identifier, function (myPhoneNumber) TriggerClientEvent("gcPhone:myPhoneNumber", sourcePlayer, myPhoneNumber) TriggerClientEvent("gcPhone:contactList", sourcePlayer, getContacts(identifier)) TriggerClientEvent("gcPhone:allMessage", sourcePlayer, getMessages(identifier)) end) end) A nahraďte za AddEventHandler('esx:playerLoaded', function(playerId, xPlayer) local sourcePlayer = tonumber(xPlayer.source) local identifier = xPlayer.identifier getOrGeneratePhoneNumber(sourcePlayer, identifier, function (myPhoneNumber) TriggerClientEvent("gcPhone:myPhoneNumber", sourcePlayer, myPhoneNumber) TriggerClientEvent("gcPhone:contactList", sourcePlayer, getContacts(identifier)) TriggerClientEvent("gcPhone:allMessage", sourcePlayer, getMessages(identifier)) end) end) To by mělo opravit telefonní číslo A ted jak by se měl opravit tento error [error] [mysql] [gcphone] an error happens on mysql for query "insert into phone_messages (`transmitter`, `receiver`,`message`, `isread`,`owner`) values('444', @receiver, 'ahoj', 1, 1);": er_bad_null_error: column 'receiver' cannot be null Zde návod: Opět v gcphone/server/server.lua Úplně na horu vložte local ESX = nil TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end) Pak najděte function getPlayerID(source) local identifiers = GetPlayerIdentifiers(source) local player = getIdentifiant(identifiers) return player end A nahraďte za function getPlayerID(source) local xplayer = ESX.GetPlayerFromId(source) local player = xplayer.identifier return player end Pak najděte function getSourceFromIdentifier(identifier, cb) TriggerEvent("esx:getPlayers", function(users) for k , user in pairs(users) do if (user.getIdentifier ~= nil and user.getIdentifier() == identifier) or (user.identifier == identifier) then cb(k) return end end end) cb(nil) end Nahraďte za function getSourceFromIdentifier(identifier, cb) local users = ESX.GetPlayers() for k , user in pairs(users) do local xplayer = ESX.GetPlayerFromId(user) if (xplayer.getIdentifier ~= nil and xplayer.getIdentifier() == identifier) or (xplayer.identifier == identifier) then cb(k) return end end --cb(nil) end A hotovo snad jsem vám pomohl :)
  25. weed.webm V tomto tutoriálu bych vám chtěl ukázat, jak na LSRP.cz navrhuji scripty tak, aby snadno fungovaly ve více hráčích, stav byl konzistentní napříč hráči a zároveň tento způsob programování naprosto znemožňuje, aby hacker mohl jakkoli benefitovat. Projdeme si, jak bych řešil script pro pěstování marihuany, připadně čehokoli jiného na podobný způsob. Výsledek neposkytuje nijak zábavný gameplay a smysl tohoto scriptu je pouze, aby jste se naučili, jak problémy podobného typu řešit správně, nikoli aby jste to použili na svém serveru. Je pak na vás, jak to dochutíte a uděláte to zábavné pro hráče. Nebudu vše vysvětlovat detailně, tuprtoriál je určen pro ogramátory, ne "fivem developery." Pokud ale něco nebude jasné, klidně se ptejte. Na LSRP.cz tak budeme řešit právě pěstování trávy, řešíme tak synchronizaci krabic, které hráči nosí jako součást jobu a některé mechaniky používáme pro jízdu na a vození nosítek a wheelchairu, nošení hráčů a NPC přes rameno, atd.. Hlavní koncept je, že server si udržuje stav, spravuje změnu stavu a distribuuje stav hráčům. To znamená, že když hráč chce zasadit květinu, pošle na server pouze event "chci zasadit květinu." Server pak zjistí, jestli může zasadit květinu (má v inventáři semínka? - neřeším v tutoriálu), kde se hráč nachází, vypočítá pozici kytky, nastaví počáteční stav kytky a pošle všem hráčům nový stav. Mohl by také kontrolovat, jestli na dané pozici či blízko už není jiná kytka (mimo scope tutoriálu) Dále server hlídá, kdy kytka vyroste a jde sebrat, řeší když hráč chce sebrat kytku (je kytka vyrostlá? je hráč dostatečně blízko?) a o těchto změnách stavu pak informuje hráče. Hacker při použítí tohoto stylu programování nemá žádnou výhodu. Nemůže zasadit kytku když nemá semínka, nemůže sebrat kytku když není vyrostlá a nemůže ukrást cizí kytky, aniž by u nich stál. Samozřejmě hacker může pomocí noclipu/fly hacku zasadit kytku mimo mapu, ve vzduchu, pod zemí atd., ale to už není problém tohoto scriptu, to by měl anticheat system. Na straně klienta pak pouze sledujeme stav, pokud je hráč blížko kytce tak vytvoříme OFFLINE objekt (je dobré omezit počet networked objektů), pokud se hráč vzdáli tak objekt smažeme, pokud se změní stage tak objekt smažeme a vytvoříme nový. Pokud je hráč blízko kytce co má stage který umožňuje kytku sklidit, zobrazíme hint a reagujeme na tlačítko. To je zhruba vše, co je potřeba. Detailněji to můžete vidět v následujícím anotovaném kódu. OneSync Server kód -- Zde si budeme udržovat kompletní přehled o trávě WeedState = {} -- vždy zvyšující se číslo, aby každá kytka měla unikátní ID WeedIndex = 1 -- jak dlouho trvá než kytka vyroste -- dvojnásobek pak trvá než kytka uhyne a zmizí TIME_TO_GROW = 10 * 1000 -- užitečný console příkaz pro vypsání stavu scriptu -- hodí se při debugování, když se ptáte "je chyba v syncu?" "za jak dlouho vyroste?" "kolik je kytek?" RegisterCommand('showweed', function(source) if source == 0 then tprint(WeedState) end end) -- příkaz pro zasazení trávy -- úmyslně zjednodušený, nic se nekontroluje, všichni můžou sázet všude -- ideálně by se melo zkontrolvoat jestli hráč má semínku a to pak sebrat z inventáře RegisterCommand('weed', function(source) local Source = source local ped = GetPlayerPed(Source) -- využijeme onesyncu, abychom bezpečně vypočítali, kam kytku zasadit -- díky tomu předejteme možnosti, že by si hacker mohl kytky sázet na místa, kde se nenachází local coords = GetEntityCoords(ped) local heading = GetEntityHeading(ped) -- kytku dáme před hráče. +90 proto, že EntityHeading směřuje o 90 stupnů doprava -- když přičteme 90 stupňů, bude heading směřovat před hráče local weedOffset = vector3( math.cos(math.rad(heading + 90.0)), math.sin(math.rad(heading + 90.0)), -1.0 ) AddPlant(coords + weedOffset) end, false) -- Jednoduchá funkce která přidá novou kytku do WeedState a synchronizuje stav -- nechceme nechávat tuto logiku zbytečne v command handleru -- kód se pak líp čte function AddPlant(pos) local idx = WeedIndex WeedIndex = WeedIndex + 1 WeedState[idx] = { pos = pos, stage = 0, plantedAt = GetGameTimer(), } SyncPlants(-1) end -- jen wrapper okolo eventu, nic zvláštního function SyncPlants(target) TriggerClientEvent('state_weed:sync', target, WeedState) end -- nesmíme zapomenout poslat stav komukoli, kdo se napojí na server -- když bychom to neudělali, tak hráči uvidí jen kytky, které byly zasazené během doby, co jsou online -- (nebo, s tím, jak je tento script napsaný, tak by dostali celý stav jakmile by někdo zasadil kytku) RegisterNetEvent('playerSpawned') AddEventHandler('playerSpawned', function() SyncPlants(source) end) -- tento thread slouží k tomu, že periodicky kontrolujeme, -- jestli nějaká kytka nevyrostla a pokud ano, posuneme jí stage -- případně ji smažeme, pokud zahynula Citizen.CreateThread(function() while true do Wait(1000) -- užitečný způsob, jak zjistit, jestli se tento tick něco změnilo -- pokud ano, tak synchronizovat stav -- pokud ne, tak zbytečně neposíláme data local anythingChanged = false for id, plant in pairs(WeedState) do if plant.stage == 0 and (GetGameTimer() - plant.plantedAt) > TIME_TO_GROW then plant.stage = 1 anythingChanged = true elseif plant.stage == 1 and (GetGameTimer() - plant.plantedAt) > (TIME_TO_GROW * 2) then WeedState[id] = nil anythingChanged = true end end if anythingChanged then SyncPlants(-1) end end end) -- když hráč chce sebrat kytku, pošle event na server -- jelikož nechceme, aby hackeři mohli jen tak sbírat kytky, -- ještě na serveru ověříme, jestli je tento event legit RegisterNetEvent('state_weed:pickup') AddEventHandler('state_weed:pickup', function(id) local Source = source local ped = GetPlayerPed(Source) local coords = GetEntityCoords(ped) local plant = WeedState[id] -- zkontrolujeme, že hráč sbírá kytku co existuje if plant then -- zkontrolujeme, že hráč je dostatečně blížko kytce if #(plant.pos - coords) < 3.0 then -- zkontrolujeme, že kytka je sbíratelná (stage 1) if plant.stage == 1 then WeedState[id] = nil -- tady bychom ještě hráče měli odměnit za sebrání kytky TriggerClientEvent('state_weed:info', Source, '~g~Tráva byla úspesne sklizena') SyncPlants(-1) else TriggerClientEvent('state_weed:info', Source, '~g~Tráva jeste nevyrostla') end else TriggerClientEvent('state_weed:info', Source, 'Tráva je moc daleko') end else TriggerClientEvent('state_weed:info', Source, 'Trávu se nepodarilo sklidit') end end) -- DEBUG FN -- jen debug funkce co vypíše obsah LUA tabulky function tprint (tbl, indent) if not indent then indent = 0 end if type(tbl) == 'table' then for k, v in pairs(tbl) do formatting = string.rep(" ", indent) .. k .. ": " if type(v) == "table" then print(formatting) tprint(v, indent+1) elseif type(v) == 'boolean' then print(formatting .. tostring(v)) else print(formatting .. v) end end else print(tbl) end end Client kód -- klientský stav scriptu WeedState = {} -- jednoduchý způsob, jak zjistit, jestli objekt/auto/ped je NETWORKED, je použít constantu -- pak se nedívám na `false, true, false)` a nemusím se ptát "je networked?" -- neboť to vidím - `NOT_NETWORKED, true, false)` - samozřejmě když popletu poředí argumentu, tak mi tohle nijak nepomůže NOT_NETWORKED = false -- na jakou vzdálenost chceme vytvořit objekt? -- pokud hráč bude dál, než tato vzdálenost, tak objekt vůbec nebude -- existovat ve hře. Já často používám 100 - 150, ale na testování 5 RENDER_DISTANCE = 5.0 -- Pokud už objekt existuje, tak ho despawneme, až když bude o toleranci dál, než v render distance -- Díky tomu pokud budu stát na hranici render distance tak mi objekt nebude přeblikávat pokaždé, když se přiblížím a oddálím -- Dobrá tolerance je třeba 20 jednotek RENDER_DISTANCE_TOLERANCE = 2.0 -- Jaké objekty použijeme, pro jakou stage STAGE_OBJECTS = { [0] = 'prop_weed_02', [1] = 'prop_weed_01', } RegisterNetEvent('state_weed:sync') AddEventHandler('state_weed:sync', function(w) local receivedIds = {} local ped = PlayerPedId() local coords = GetEntityCoords(ped) for id, plant in pairs(w) do -- receivedIds tabulku použijeme pro to, -- abychom poznali, jaké ID kytek už nejsou na serveru -- tzn. pokud v lokálním WeedState bude některé ID, co není v -- receivedIds, pak už server smazal danou kytku a klient musí taky receivedIds[id] = true -- pokud jde o novou kytku, tak ji jen přidáme do stavu a vytvoříme objekt if not WeedState[id] then WeedState[id] = plant ProcessPlantObject(coords, WeedState[id]) else -- pokud již na clientu kytka existuje -- musíme myslet na to, že klient už jí mohl vytvořit entitu -- a ten musíme zachovat. Nesmíme na něj ztratit referenci. -- zároveň zkontrolujeme, jestli se nezměnila stage a pokud ano, refreshneme objekt local oldPlantStage = WeedState[id].stage local entity = WeedState[id].entity WeedState[id] = plant WeedState[id].entity = entity if oldPlantStage ~= WeedState[id].stage then ProcessPlantObject(coords, WeedState[id]) end end end -- nakonec, jak jsem psal na začátku funkce -- smažeme kytky, které už nejsou evidované na serveru for id, plant in pairs(WeedState) do if not receivedIds[id] then DeleteWeedObject(plant) WeedState[id] = nil end end end) -- jen funkce na zobrazení notifikace. Ideálně použijte to, co používáte napříč projektem RegisterNetEvent('state_weed:info') AddEventHandler('state_weed:info', function(text) SetNotificationTextEntry('STRING') AddTextComponentSubstringPlayerName(text) DrawNotification(true, true) end) -- samostatný thread checkuje, jestli je hráč blízko nějaké kytce -- a pokud ano a kytka je vyrostlá, zobrazíme hint a reagujeme na tlačítko Citizen.CreateThread(function() while true do Wait(0) local ped = PlayerPedId() local coords = GetEntityCoords(ped) for id, plant in pairs(WeedState) do if plant.stage == 1 and #(coords - plant.pos) < 1.5 then RenderPickupText(plant.pos) if IsControlJustPressed(0, 38) then TriggerServerEvent('state_weed:pickup', id) end end end end end) -- samostatný thread checkuje stav entit -- pokud se hráč přiblíží, vytvoříme entitu -- pokud se vzdáli, smažeme entitu -- pokud nesedí model entity, refreshneme entitu Citizen.CreateThread(function() while true do Wait(1000) local ped = PlayerPedId() local coords = GetEntityCoords(ped) for _, plant in pairs(WeedState) do ProcessPlantObject(coords, plant) end end end) -- funkce která dělá to, co je popsané nad předchozím theadem ^^ function ProcessPlantObject(playerCoords, plant) if not plant.entity and #(plant.pos - playerCoords) < RENDER_DISTANCE then plant.entity = CreateWeedObject(plant.pos, plant.stage) elseif plant.entity and #(plant.pos - playerCoords) > (RENDER_DISTANCE + RENDER_DISTANCE_TOLERANCE) then DeleteWeedObject(plant) elseif plant.entity and GetEntityModel(plant.entity) ~= GetHashKey(STAGE_OBJECTS[plant.stage]) then DeleteWeedObject(plant) plant.entity = CreateWeedObject(plant.pos, plant.stage) end end -- Wrapper funkce na vytvoření objektu -- Ideálně by to chtělo do `while not HasModelLoaded(hash) do` -- přidat backpressure, že pokud se do např. 500 framu (nebo určitého času) nenačte model, tak -- to přestane čekat a vyfailuje -- to je ale mimo scope tohoto tutoriálu function CreateWeedObject(pos, stage) local hash = GetHashKey(STAGE_OBJECTS[stage]) if IsModelInCdimage(hash) then -- IsModelInCdimage checkuje, jestli model je ve hře. Na vzdory názvu nemá nic dočinení s CDčkama :) RequestModel(hash) while not HasModelLoaded(hash) do Wait(0) end local entity = CreateObject(hash, pos.x, pos.y, pos.z, NOT_NETWORKED, false, false) if entity == 0 then print("ERROR: Could not create object", hash) return nil end FreezeEntityPosition(entity, true) SetEntityAsMissionEntity(entity, true, true) return entity else print("ERROR: Model hash not in game ", hash) end end -- jednoduchy wrapper na smazani entity function DeleteWeedObject(plant) if plant.entity then DeleteObject(plant.entity) plant.entity = nil end end -- wrapper na 3d text function RenderPickupText(pos) local visible, x, y = GetScreenCoordFromWorldCoord(pos.x, pos.y, pos.z) SetTextFont(0) SetTextScale(0.0, 0.5) SetTextColour(255, 255, 255, 255) SetTextOutline() SetTextCentre(true) SetTextEntry("STRING") AddTextComponentString("~y~[E]~s~ Sklidit") DrawText(x, y) end

Our partners

rcore.cz
K4mb1
SLTH
×
×
  • Create New...