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 34 results

  1. 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
  2. Ahoj. Vydávam ďalší návod. Nezabudni ma podporiť Srdiečkom alebo upvotom! Odkaz na video :
  3. Ahoj. Vydávam ďalší návod. Nezabudni ma podporiť Srdiečkom alebo upvotom! Odkaz na video :
  4. 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.
  5. 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
  6. 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
  7. 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
  8. 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())
  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. 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
  11. 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 :)
  12. 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
  13. 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
  14. 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
  15. 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
  16. 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.
  17. 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
  18. 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 :)
  19. 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
  20. V tomto návodu si ukážeme jak udělat custom blip. Co je potřeba ? - OpenIV (https://openiv.com/) - Texture Toolkit (https://www.gta5-mods.com/tools/texture-toolkit) - Kterýkoliv program který podporuje úpravu .dds souboru. Například Paint (https://www.getpaint.net/) Otevřete si OpenIV. V pravém horním rohu je vyhledávací okénko. Do něj zadejte minimap.ytd. Potom co toto zadáte tak dejte "Search "minimap.ytd" in all archives". Potom vám vyskočí okénko s 3 soubory. Na druhý soubor("minimap.ytd") dvakrát klikneme a následně se objeví kde je soubor uložen. A přetáhneme minimap.ytd na plochu či složky . Potom otevřeme Texture Toolkit. V záložce "File" klikneme na "Load" a vybereme "minimap.ytd". Následně si označíme blips_texturesheet_ng.dds nebo blips_texturesheet_ng_2.dds (Záleží jaký blip chcete upravit) . Následně v záložce "Edit" dáme "Export". Soubor .dds se vám stáhne do složky kde máte Texture Toolkit. Potom tento soubor otevřeme v Paintu (nebo nějaký jiný program k tomu určený). Následně můžete upravovat blipy. Každý blip má velikost 64x64. Potom co jsme dokončily úpravy tak si soubor uložíme. Následně otevřeme Texture Toolkit a v záložce "Edit" dáme "Import". Vybereme soubor .dds který jsme si upravily. Potom když klikneme na soubor , který jsme si upravovali, v Texture Toolkit. Tak by tam měla být textura kterou jsme upravily. Následně v záložce "File" klikneme na "Save". Potom už stačí vytvořit složku (např.: blip) a do ní vytvoříme soubor "__resource.lua". Tento soubor může být prázdný. Potom ještě do naší složky vytvořit další složku s názvem "stream" a to téhle složky vložíme minimap.ytd. Pak už jenom stačí dát naší složku(blip) do serveru a dát 'start blip' do server.cfg . Obrázek jak to může vypadat: https://imgur.com/PKagm2d
  21. teb

    ShapeTest

    ShapeTest (raycast) slouží k detekci "něčeho ve světě." se na určitém místě něco nachází (auto/ped) jestli se něco nachází mezi bodem A a bodem B Může být užitečné pro Spawnování aut (checknutí jestli je parkovací místo zabrané) Radar (vyhledání auta před/za autem hráče) Systém židlí (podívám se, jestli v ruzých směrech kolem peda je židle - rychlejší než GetClosestObjectOfType Užitečné jen když chcete vypsat help text. Pokud máte sednutí jen na tlačítko, pak 1 zavolání GetClosestObjectOfType dostačuje Zjištění, jestli mezi bodem A a bodem B je přímka, která není nijak blokovaná (ekvivalent HasEntityClearLosToEntity, netestoval jsem, co je rychlejší) Mnou testované ShapeTest funkce v GTA StartShapeTestRay StartShapeTestBox StartShapeTestCapsule Pro získání výsledku pak funkce GetShapeTestResult GetShapeTestResultIncludingMaterial Zbytek jsem nezkoušel a zatím jsem pro ně neměl potřebu. Příklad jednoduchého shapetestu, který najde auto před našim autem a zobrazí NumberPlate (R.Z.) Citizen.CreateThread(function() while true do Wait(0) local ped = PlayerPedId() local veh = GetVehiclePedIsIn(ped, false) if veh > 0 then local vehCoord = GetEntityCoords(veh) local fwdVector = GetEntityForwardVector(veh) local rayEnd = vehCoord + fwdVector * 8 -- debug line -- pro debug nevypisuju individualne x,y,z, nechavam CFX -- aby to spravne interpretoval. Neni doporuceno pro -- produkcni kod, nebot se to muze kdykoli zmenit -- a podpora muze zmizet DrawLine(vehCoord, rayEnd, 0, 0, 255, 255) -- nadefinujeme shapetest local ray = StartShapeTestRay( vehCoord.x, vehCoord.y, vehCoord.z, -- začátek shapetestu rayEnd.x, rayEnd.y, rayEnd.z, -- konec shapetestu 2, -- flag => auta veh, -- entita, kterou chceme ignorovat => naše auto 4 -- neznámý argument ) -- získáme výsledek raycastu local _, hit, endCoords, _, entityHit = GetShapeTestResult(ray) if hit > 0 and entityHit > 0 then -- nemusime zjišťovat, jeslti entityHit je auto -- protože jsme ray omezili flagem local license = GetVehicleNumberPlateText(entityHit) Draw3DText(endCoords.x, endCoords.y, endCoords.z, license) end end end end) function Draw3DText(x, y, z, text) local onScreen,_x,_y=World3dToScreen2d(x,y,z) if onScreen then SetTextScale(0.6, 0.6) SetTextFont(0) SetTextColour(255, 255, 255, 255) SetTextDropshadow(0, 0, 0, 0, 255) SetTextDropShadow() SetTextOutline() SetTextEntry("STRING") SetTextCentre(1) AddTextComponentString(text) DrawText(_x,_y) end end Příklad složitějšího shapetestu pro zjištění, jestli je parkovací místo zabrané. Citizen.CreateThread(function() -- checknuti 1 pozice trva na mojem PC neco málo přes 0.01ms local centers = { vector3(228.35, -786.49, 29.69), vector3(229.26, -783.89, 29.7), vector3(230.3, -781.41, 29.7), vector3(231.22, -778.95, 29.71), vector3(233.05, -773.91, 29.73), vector3(234.09, -771.28, 29.75) } local heading = 68.5 -- směr parkovacího boxu -- velikost parkovacího boxu local width = 2.3 local length = 4.5 local height = 2.0 while true do Wait(0) for _, center in pairs(centers) do local occluded = IsParkingSpotOccluded(center, heading, width, length, height) ShapeBoxDraw(center, heading, width, length, height, occluded) end end end) function IsParkingSpotOccluded(center, heading, width, length, height) -- 2 -> auta -- 4 -> peds -- 16 -> objekty -- 256 -> rostliny local flags = 2 + 4 + 16 + 256 local ray = StartShapeTestBox( -- vytvoříme ShapeTest center.x, center.y, center.z, -- center boxu width, length, height, -- velikost boxu 0.0, 0.0, heading, 2, -- https://en.wikipedia.org/wiki/Euler_angles, `2` - pořadí rotací flags, -- flagy, co raycast chyta - https://runtime.fivem.net/doc/natives/?_0x377906D8A31E5586 0, -- entita, kterou má raycast ignorovat (např. PlayerPedId() pokud chceme ignorovat sveho peda) 4 -- neznamy parametr ) -- 1. vystup je neznámá proměnná -- hit - 0 pokud nic nebylo nalezeno, 1 pokud bylo -- endCoords - kde raycast něco trefil -- surfaceNormal - https://cs.wikipedia.org/wiki/Norm%C3%A1la -- entityHit - jakou entitu ray trefil local _, hit, endCoords, surfaceNormal, entityHit = GetShapeTestResult(ray) -- zjistíme výsledek ShapeTestu -- pokud vás zajímá i materiál, pak funkce https://runtime.fivem.net/doc/natives/?_0x65287525D951F6BE return hit > 0 end -- Funkce na debug StartShapeTestBox, není vysvětleno jak funguje, neboť není předmětem návodu -- ale je to jen jednoduchá trigonometrie -- vykreslení debug boxu trvá ~0.01ms function ShapeBoxDraw(center, heading, width, length, height, occluded) local diagonal = math.sqrt((width/2)^2 + (length/2)^2) local fullDiagonal = math.sqrt(width^2 + length^2) local boxHeight = vector3(0.0, 0.0, height) local newAngle = math.deg(math.asin(length/fullDiagonal)) local topRight = GetAngledPosition(center, diagonal, heading + newAngle, 1) local bottomRight = GetAngledPosition(center, diagonal, heading - newAngle, 1) local bottomLeft = GetAngledPosition(center, diagonal, heading + newAngle, -1) local topLeft = GetAngledPosition(center, diagonal, heading - newAngle, -1) local off = vector3(0.0, 0.0, 5.0) local boxColor = {0, 255, 0} if occluded then boxColor = {255, 0, 0} end DrawLine(topRight-off, topRight+off, 0, 255,0,255) DrawLine(bottomRight-off, bottomRight+off, 255, 0 ,0,255) DrawLine(bottomLeft-off, bottomLeft+off, 0, 0,255,255) DrawLine(topLeft-off, topLeft+off, 255, 255,255,255) DrawPoly(topRight, topLeft, topLeft + boxHeight, boxColor[1], boxColor[2], boxColor[3], 100) DrawPoly(topRight, topLeft + boxHeight, topRight + boxHeight, boxColor[1], boxColor[2], boxColor[3], 100) DrawPoly(bottomLeft, bottomRight, bottomRight + boxHeight, boxColor[1], boxColor[2], boxColor[3], 100) DrawPoly(bottomLeft, bottomRight + boxHeight, bottomLeft + boxHeight, boxColor[1], boxColor[2], boxColor[3], 100) DrawPoly(topLeft, bottomLeft, bottomLeft + boxHeight, boxColor[1], boxColor[2], boxColor[3], 100) DrawPoly(topLeft, bottomLeft + boxHeight, topLeft + boxHeight, boxColor[1], boxColor[2], boxColor[3], 100) DrawPoly(bottomRight, topRight, topRight + boxHeight, boxColor[1], boxColor[2], boxColor[3], 100) DrawPoly(bottomRight, topRight + boxHeight, bottomRight + boxHeight, boxColor[1], boxColor[2], boxColor[3], 100) DrawPoly(bottomRight + boxHeight, topRight + boxHeight, topLeft + boxHeight, boxColor[1], boxColor[2], boxColor[3], 100) DrawPoly(topLeft + boxHeight, bottomLeft + boxHeight, bottomRight + boxHeight, boxColor[1], boxColor[2], boxColor[3], 100) end function GetAngledPosition(center, dist, angle, mod) local angRad = math.rad(angle) return center + mod * dist * vector3( math.cos(angRad), math.sin(angRad), 0.0 ) end
  22. Smysl tohoto návodu je nasměrovat vás správným směrem co se porozumění flagů týče, nikoli je kompletně vysvětlit a objasnit. Některé nativky používají tzv. flagy, tenhle návod je pokud o to vysvetlit, jak s nimi pracovat. Flag není nic jiného, než jednoduchá reprezentace složité konfigurace pomoci nastavení bitu v integeru. Ukažme si, jak pracovat s flagy v nativce TaskPlayAnim. Z dokumentace: enum eAnimationFlags { ANIM_FLAG_NORMAL = 0, ANIM_FLAG_REPEAT = 1, ANIM_FLAG_STOP_LAST_FRAME = 2, ANIM_FLAG_UPPERBODY = 16, ANIM_FLAG_ENABLE_PLAYER_CONTROL = 32, ANIM_FLAG_CANCELABLE = 120, -- tohle je divna flaga, nebot zabira bity 4-7 }; Flagy jsou reprezentovány integerem, ale reálne se pracuje s bity daného integeru. Každý integer v desítkové soustavě (kterou používáme), lze reprezentovat v binární soustavě. Tedy: 0 => 0000 1 => 0001 2 => 0010 3 => 0011 => tedy součet 0001 a 0010 4 => 0100 5 => 0101 6 => 0110 7 => 0111 => tedy součet 0001 a 0010 a 0100 8 => 1000 Pro větší dvojkové binární soustavy si vyhledejte relevaltní článek binární soustavy. Čistě s těmito znalostmi bychom měli začít vidět, jak pouzívat jednotlivé flagy animace. Pokud například chceme animaci, aby se opakovala, umožnila pohyb hráče a platila jen na vrchní část těla, pak použijeme // 1 - repeat // 16 - upper body // 32 - controllable 1 + 16 + 32 (nebo dohromady 49, ale je lepší to nechat rozdělené pro budoucí porozumění flagů) Pro animaci na celé tělo, která se má zastavit na konci animace, použijeme flag 2 (neboť celé tělo je by default)
  23. Zdravíčko, připravil jsem si pro vás jednoduchý návod, pro který budete potřebovat trošku něco vědět o tom, jak funguje lua, protože se tu nebudeme zabývat základy. Tímto bych Vám chtěl jsem dát jednoduchý kód pro vytvoření blipu s pár vysvětleními a odkazy na všechny blipy, barvy a podobně. Kód pro blip se spouští pouze jednou a na straně klienta, takže žádný while prostě jen jednou v threadu. Citizen.CreateThread(function() for k, v in pairs(Config.Blips) do Blips[k] = AddBlipForCoord(v.pos.x, v.pos.y, v.pos.z) SetBlipSprite(Blips[k], v.blip) SetBlipDisplay(Blips[k], v.type) SetBlipScale(Blips[k], v.scale) SetBlipColour(Blips[k], v.color) SetBlipAsShortRange(Blips[k], v.shortRange) BeginTextCommandSetBlipName("STRING") AddTextComponentString(v.name) EndTextCommandSetBlipName(Blips[k]) end end) Teď k nějakému většímu vysvětlení funkcí: AddBlipForCoord (https://runtime.fivem.net/doc/natives/#_0x5A039BB0BCA604B6) - vytvoří blip na daných coordinátech SetBlipSprite (https://runtime.fivem.net/doc/natives/#_0xDF735600A4696DAF) - určuje jak bude blip vypadat - https://wiki.gtanet.work/index.php?title=Blips SetBlipDisplay (https://runtime.fivem.net/doc/natives/#_0x9029B2F3DA924928) - určuje, jakým způsobem se bude blip zobrazovat - 0 nebude se zobrazovat nikde - 1 nebude se též zobrazovat nikde - 2 zobrazí se na hlavní mapě i na minimapě - 3 zobrazí se jenom na hlavní mapě - 4 zobrazí se jen na hlavní mapě - 5 zobrazí se jen na minimapě - 6 zobrazí se na minimapě a na hlavní mapě - 7 nezobrazí se vůbec - 8 zobrazí se na minimapě na hlavní mapě ale ne na vybíratelné mapě SetBlipScale (https://runtime.fivem.net/doc/natives/#_0xD38744167B2FA257) - nastaví velikost blipu - 1 je základní velikost a výš je násobením 2 je dvojnásobek normální hodnoty aspoň se tak zdá SetBlipColour (https://runtime.fivem.net/doc/natives/#_0x03D7FB09E75D6B7E) - nastaví jednu z barev, kterou naleznete zde - https://wiki.gtanet.work/index.php?title=Blips SetBlipAsShortRange (https://runtime.fivem.net/doc/natives/#_0xBE8BE4FE60E27B72) - nastavuje či má blip být viděn jen v blízkosti pedu u pozice nebo pořád BeginTextCommandSetBlipName (https://runtime.fivem.net/doc/natives/#_0xF9113A30DE5C6670) - začne přidávat text k blipu, něco jako transakce má několik variant místo STRING můžete vložit přímo text entry te hry - pěkný příklad v nativní dokumentaci AddTextComponent (https://runtime.fivem.net/doc/natives/#_0x6C188BE134E074AA) - změna názvu v nativní dokumentaci na AddtextComponentSubstringPlayerName, KeyboardDisplay, Website netuším, proč to udělali ale nějaký důvod mít budou každopádně starý dobrý název funguje a vypadá to,že bude fungovat pořád. - nastaví název blipu, který se zobrazuje na mapě pokud máte správný display type EndTextCommandSetBlipName (https://runtime.fivem.net/doc/natives/#_0xBC38B49BCB83BC9B) - ukončí nastavování názvu blipu - používá se jako ukončující příkaz pro BeginTextCommandSetBlipName Pro jakékoliv dotazy se nebojte zeptat. Kód je vzaný z scriptu: https://github.com/Isigar/relisoft_blips
  24. Na přidání vozidel budeme potřebovat aplikaci OPENIV a __resource který je v popisku tohoto návodu. 1) Na ploše vytvoříme složku (Je jedno jaký název, jelikož název bude potom změněn - Řekněme že se složka jmenuje 2015polstang) 2) Půjdeme do složky kam vložíme soubor __resource.lua. Ve složce 2015polstang uděláme ještě jednu složku s názvem Stream. 3) Máme-li stažené Add-On vozidlo otevřeme OpenIV. Do OpenIV vložíme soubor dlc.rpf 4) Jakmile máme otevřený dlc.rpf v OpenIV tak si rozklikneme dlc.rpf kde najdeme složku data a x64 5) Rozklikneme si složku data. Ze složky data vezmeme soubory které přesuneme do složky 2015polstang. 6) Rozklikneme si složku x64 kde najdeme vehicles.rpf a u některých vozidel i vehiclemods. 7) Rozklikneme si složku vehicles.rpf a všechny soubory přesuneme do složky stream která se nachází ve složce 2015polstang. 8) Pokud byste měli zájem o vehiclemods stačí soubory přesunout do složky stream POZOR!!! Složka se musí jmenovat stejně jako jméno souboru ve vehicle.rpf bez koncovek .yft, _hi.yft, .ytd, _hi.ytd 9) celou složku vložíme do Resources. 10) Půjdeme do hry a napíšeme /car 2015polstang __resource.lua
  25. Zdravím, připravil jsem si pro Vás malý návod. Obtížnost tutoriálu: 1/5 List funkcí/věcí které použijeme dnes: Attributes EventHandlers["eventjmeno"] new Action<...>() TriggerEvent TriggerServerEvent Event je událost kterou lze volat jen u daného hráče nebo všem hráčům na serveru.. Takovéto eventy se dají využít i na server side čistě.. Bez dalších řečí pojďme se podívat jak registrovat a volat eventy.. Ukážu zde zase více příkladů jak registrovat eventy. Takto se tvoří jak serverové tak klientské eventy. //Vytvoříme funkci kterou pak budeme volat skrze TriggerEvent public void fullArmour() { API.SetPedArmour(API.PlayerPedId(), 100); } //Vytvoříme funkci s paramterama kde budeme hračovi přidávat armour, a budeme volat skrze TriggerEvent. public void giveArmour(int armour) { int playerPed = API.PlayerPedId(); API.SetPedArmour(playerPed, API.GetPedArmour(playerPed) + armour); } //[EventHandler("...")] je attribute který předává "vlastnosti" //dané funkci která půjde volat srkze event, veškeré parametry co zde jsou //tak půjdou volat skrze TriggerEvent. [EventHandler("giveWeapon")] public void giveWeapon(string weapon,int ammo) { API.GiveWeaponToPed(API.PlayerPedId(), (uint)API.GetHashKey(weapon), ammo, false, true); } public MainClass() { //Action nám zapouzdruje metodu kterou lze zapouzdrovat i pomocí //annonymních funkcích, lze přidávat parametry do action které si //ukážeme dóle, tento event nám doplní věškeré HP a lze volat pomocí TriggerEvent EventHandlers["fullHeal"] += new Action(() => { API.SetEntityHealth(API.PlayerPedId(), 250); }); //jak padlo nahoře, tento event bude příjmat datový typ INT //jak už naznačuje annonymní funkce i název eventu, tento event //nám bude léčit hráče ve hře. Lze vyvolat tento event pomocí TriggerEvent. EventHandlers["giveHeal"] += new Action<int>((health) => { int playerPed = API.PlayerPedId(); API.SetEntityHealth(playerPed, API.GetEntityHealth(playerPed) + health); }); //Zapouzdří nám funkci "fullArmour" lze volat pomocí TriggerEvent EventHandlers["fullArmour"] += new Action(fullArmour); //Zapouzdří nám funkci "giveArmour" lze volat pomocí TriggerEvent EventHandlers["giveArmour"] += new Action<int>(giveArmour); } a jak vyvolám takový event ? úplně jednoduše. Pomocí funkce "TriggerEvent" který má parametry takové String eventName params object[] parametry Ale pozor! Jestli chcete volat eventy které jsou čistě client side, musíte použít funkci "TriggerEvent" ale jestli chcete volat event který je na serveru tak musíte použít "TriggerServerEvent" [Command("healme")] void heal() { //Vyvolá event který jsme si registrovali nahoře. //v našem případě nás to vyléčí. TriggerEvent("fullHeal"); } [Command("weapon")] void giveWeapon() { //Vyvolá event který jsme si registrovali nahoře. //v našem případě nám toto dá zbraň pistol a 250 nábojů. TriggerEvent("giveWeapon","WEAPON_PISTOL",250); } a jak můžu "přenášet" proměnné z funkce ? [EventHandler("testValue")] void passValue(dynamic testValue) { //Typovost musí být vždy dynamic, protože jí lze deklarovat //jako dynamickou metodu.. a volá se jako normální funkce. //lze dávat více argumentů do této dynamické funkce. testValue("joujoujou cum na to"); } [EventHandler("testMoreValue")] void passMoreValue(dynamic testValue) { //příklad více parametrů. testValue("string",true,0.1f); } [Command("event")] void cmd() { //Zde musíme "zaobalit" tu dynamickou funkci kterou jsme si //deklarovali v eventu "testValue" jelikož vracíme string //tak budeme deklarovat new Action se stringem. TriggerEvent("testValue", new Action<string>((value) => { //Vypíšeme do konzole jaká je hodnota z dynamické funkce, //respektivě jeho parametry. Debug.WriteLine("string" + value); })); //Jen mezera do konzole ať lépe rozeznáme který text je který. Debug.WriteLine(" "); Debug.WriteLine(" "); TriggerEvent("testMoreValue", new Action<string,bool,float>((value,boolean,floatik) => { //to samé jako nahoře, akorát máme více parametrů. Debug.WriteLine($"{value}"); Debug.WriteLine($"{boolean}"); Debug.WriteLine($"{floatik}"); })); } Jelikož tento návod je pouze o eventech a jen jak NAČÍST esx. tak tady ukážu jen jak načíst esx jak client, tak server side. Jestli vás zajímá jaké funkce má ESX tak zde je jejich dokumentace: https://esx-org.github.io/es_extended/ client //Napíšeme si statickou dynamickou proměnnu //kterou budeme deklarovat hned jak se resource spustí. public static dynamic esx; public ClientMain() { //while je smyčka která se bude opakovat do té doby //dokud esx nebude mít null hodnotu. //proč chceme smyčku vůbec ? Protože se může stát že omylem //se náš script načte dřív jak ESX a nezapíše nic do "dynamic esx" while (esx == null) { //je lepší vždy dávat delay nad všechny funkce, jestli jedna //z funkci bude mít nějakou chybu tak se "Delay" nikdy nevyvolá //a crashne hra.. //Co vlastně tato funkce dělá ? //Vytváří úlohu která bude pozastavena po určitém čase, v našem případě //za 10 milisekund, ano čas se udává v milisekundách 1000 ms = 1 sekunda Delay(10); //Vyvoláme event který nám bude vracet dynamické metody //a ty zapíšeme do proměnné "esx" TriggerEvent("esx:getSharedObject", new Action<dynamic>(esxObj => { esx = esxObj; })); } } server //Napíšeme si statickou dynamickou proměnnu //kterou budeme deklarovat hned jak se resource spustí. public static dynamic esx; public main() { //Vyvoláme event který nám bude vracet dynamické metody //a ty zapíšeme do proměnné "esx" TriggerEvent("esx:getSharedObject", new Action<dynamic>(esxObj => { esx = esxObj; })); } Ještě se pojďme podívat na server side eventy, protože budete chtít někdy v budoucnu zjištovat jaký hráč trigroval event atd, tak pojďme si rovnou ukázat jak na to! //[FromSource] player, fivem handluje docela trošku zvláštně toto.. tento parametr //"Player" nemusíte vůbec nikde dávat do eventu aby tam byl. Kdykoliv vyvoláte //funkci "TriggerServerEvent" tak tento parametr se tam sám přenese. [EventHandler("sourcePlayerTest")] public void giveWeapon([FromSource] Player player,string text) { Debug.WriteLine(player.Name + " string value: " + text); } public serverClass() { //Bylo vysvětleno nahoře, zde jestli chcete zjištovat kdo event vyvolal, tak musíte //dát do parametrů Action "Player" jelikož to není funkce ale annonymní funkce tak //zde musíte dávat jenom datový typ Player a ne Attribute [FromSource] EventHandlers["AnotherTestSourcePlayer"] += new Action<Player, string>((player, text) => { //Vypíše do konzole jméno hráče a string z parametru "text" Debug.WriteLine(player.Name + " string value: " + text); }); } Jak takový event vyvolám ? Ale pozor! Jestli chcete volat eventy které jsou čistě server side, musíte použít funkci "TriggerEvent" ale jak vyvolám eventy ze serveru pro hráče ? Máme tady 2 funkce které budeme volat pro hráče... player.TriggerEvent("eventName") toto nám vyvolá jen u daného hráče event. TriggerClientEvent("eventName") Tato funkce vyvolá daný event úplně u všech lidí na serveru... Ale pozor, jestli ovládáte luU tak víte že musíte vyplnít "-1" aby se to vyvolalo u všech lidí na serveru, zde nemusíte specifikovat hráče protože to dělá funkce co jsme si ukazovali nad náma. Příklad client side: [Command("serverevent")] void playerCommand() { //Vyvolá event na serveru se jménem "AnotherTestSourcePlayer" TriggerServerEvent("AnotherTestSourcePlayer","textik lulik"); } //registrujeme příkaz "healplayer" a musíme kontrolovat i parametry //logicky když to chceme vyvolávat u určitého hráče tak musíme //řešit jeho ID... stím nám pomůže "string[] args" který nám bude //vracet co vlastně za parametry zadal do příkazu //musíte zadat /healplayer <ID> [Command("healplayer")] void addGroup(string[] args) { //Jelikož c# začíná s číslem 0 a ne 1 jako lua tak zadáme 0. //Jelikož c# řeší typovost, tak musíme ze stringu udělat int //a stím nám pomůže funkce Parse. Která nám ze stringu udělá int TriggerServerEvent("HealPlayerFromId", Int64.Parse(args[0])); } Příklad server side: [EventHandler("AnotherTestSourcePlayer")] void testEvent() { //vyvolá u všech lidí na serveru event "fullHeal" TriggerClientEvent("fullHeal"); } //Logicky budeme potřebovat ID hráče takže si napíšeme parametr "ID" //který pak budeme volat skrze client/server odkud chcete. [EventHandler("HealPlayerFromId")] void fromId(int id) { //toto nám vratí instanci daného hráče z ID. Player player = new PlayerList()[id]; player.TriggerEvent("fullHeal"); } Výsledek: Client event "fullHeal" event "testValue" a "testMoreValue" event "giveWeapon" server Jedná se o event "sourcePlayerTest" Další návody na c#

Our partners

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