Lance_Delmago Posted August 16, 2023 Share Posted August 16, 2023 Good time of day. I am developing a bus system and have run into several problems: 1) I can't make a bus stop informant: I can't make the informant be heard by other players on the server and, in addition, I can't make the reminder trigger timer reset when exiting the bus. The code for triggering the memo every 2 minutes: Spoiler client: setTimer(function() if isPedInVehicle (localPlayer) then randomin={"pamgaz.wav","pam_nez_vesj.wav","pammesta.wav","pamoplaty.wav","pampok.wav","pamporuch.wav","pampriobr.wav","pampriv.wav","pamprovod.wav","pirotehpam.wav"} randInSound = playSound3D("randominform/"..randomin[math.random(1,10)],0.0,0.0,0.0, false) setSoundMaxDistance( randInSound,150 ) attachElements ( randInSound, thevehiclei, 0, 0, 0 ) else stopSound(randInSound) end end, 120000, 0) 2) I can't fully make the texture on the bus route board change (for some reason there are no changes on old devices, but they are applied on the server), that is, the texture changes on the server, but the texture does not change for those players who have just connected to the server. Plate Texture replacement code: Spoiler client: function changeRouteTexture(theVehicle, id) if (theVehicle and id) then local textureName = tostring(id) .. ".png" triggerServerEvent("onClientRouteTextureChanged", resourceRoot, theVehicle, id, textureName) end end addEvent("onServerRouteTextureChanged", true) addEventHandler("onServerRouteTextureChanged", resourceRoot, function(theVehicle, id, textureName) applyTextureShader(theVehicle, id, textureName) end) function applyTextureShader(theVehicle, id, textureName) local texture = dxCreateTexture(textureName) local shader = dxCreateShader("texture_replace.fx") local trailer = getVehicleTowedByVehicle (theVehicle) engineApplyShaderToWorldTexture(shader, "tablavtobus", theVehicle, true) engineApplyShaderToWorldTexture(shader, "tablavtobus", trailer, true) dxSetShaderValue(shader, "gTexture", texture) end changeRouteTexture(thevehiclei, id) server: function changeRouteTexture (pl) triggerClientEvent ("changeRouteTexture", pl) end local shaders = {} addEvent("onClientRouteTextureChanged", true) addEventHandler("onClientRouteTextureChanged", resourceRoot, function(theVehicle, id, textureName) -- Сохраняем информацию об изменении текстуры и применяем изменения на всех клиентах if not shaders[theVehicle] then shaders[theVehicle] = {} end shaders[theVehicle].id = id shaders[theVehicle].textureName = textureName triggerClientEvent("onServerRouteTextureChanged", resourceRoot, theVehicle, id, textureName) outputChatBox("Транспортное средство с ID: " .. tostring(getElementID(theVehicle)) .. " изменило текстуру маршрута на: " .. tostring(id)) end) function sendTexturesToPlayer(player) for theVehicle, shaderTable in pairs(shaders) do triggerClientEvent(player, "onServerRouteTextureChanged", resourceRoot, theVehicle, shaderTable.id, shaderTable.textureName) end end addEventHandler("onPlayerJoin", root, sendTexturesToPlayer) In addition to the classic 1-section buses, I will also use two-section articulated vehicles (tractor + trailer in the original game) Link to comment
DiSaMe Posted August 26, 2023 Share Posted August 26, 2023 1) To make the sound play for other players, you should make all the controlling code server-side, and use triggerClientEvent on nearby players to trigger a client-side event which would call playSound3D. To reset the timer when the player exits the bus: instead of having a timer run all the time, call setTimer in onPlayerVehicleEnter to start the timer and killTimer in onPlayerVehicleExit to stop the timer. 2) You have a variable player for the first parameter in sendTexturesToPlayer, but onPlayerJoin has no parameters and uses source for the player who joined - so you need to pass source instead of player to triggerClientEvent. But even then, there's another problem: when the player joins, the resource hasn't loaded on the client side yet so it hasn't had time to call addEvent yet, which will cause triggerClientEvent to fail. Instead, you need to use onPlayerResourceStart for this. Because this event will be triggered on each resource start, you also need to check if its first parameter (loadedResource in the wiki) equals the return value of getThisResource. Link to comment
Lance_Delmago Posted August 26, 2023 Author Share Posted August 26, 2023 (edited) 2 hours ago, DiSaMe said: 1) To make the sound play for other players, you should make all the controlling code server-side, and use triggerClientEvent on nearby players to trigger a client-side event which would call playSound3D. To reset the timer when the player exits the bus: instead of having a timer run all the time, call setTimer in onPlayerVehicleEnter to start the timer and killTimer in onPlayerVehicleExit to stop the timer. 2) You have a variable player for the first parameter in sendTexturesToPlayer, but onPlayerJoin has no parameters and uses source for the player who joined - so you need to pass source instead of player to triggerClientEvent. But even then, there's another problem: when the player joins, the resource hasn't loaded on the client side yet so it hasn't had time to call addEvent yet, which will cause triggerClientEvent to fail. Instead, you need to use onPlayerResourceStart for this. Because this event will be triggered on each resource start, you also need to check if its first parameter (loadedResource in the wiki) equals the return value of getThisResource. I had to wait a long time for help, but thanks for the answer I managed to make the sound audible on the server, can you help with the implementation of the so-called reset timer? That is, when boarding a car, a memo is triggered every 2 minutes, and when exiting the car, the timer needs to be reset and stop counting, and when re-boarding in the car, it only works after 2 minutes. Here is my code: Client: Spoiler function createRoute (id, name) -- A function that creates a route, and is triggered accordingly when I sit in the driver's seat on the bus thevehiclei = getPedOccupiedVehicle(localPlayer) randomPamtimer=setTimer(ranfominform,120000, 0) routeSet = getRouteFromName (name) replaceTexture(id) if routeSet[markerIndex][4] then....... function ranfominform() local vehicle = getPedOccupiedVehicle(localPlayer) if (getVehicleController(vehicle) == localPlayer) then spam = getTickCount() randomin={"pamgaz.wav","pam_nez_vesj.wav","pammesta.wav","pamoplaty.wav","pampok.wav","pamporuch.wav","pampriobr.wav","pampriv.wav","pamprovod.wav","pirotehpam.wav"} randinInd=randomin[math.random(1,10)] local x, y, z = getElementPosition(vehicle) triggerServerEvent("onSyncRandi", localPlayer,randinInd) end end function syncedranfominform(vehicle, x, y, z,randinSoundInd) if randInSound then stopSound(randInSound) end randInSound = playSound3D(randinSoundInd,x,y,z, false) setSoundMaxDistance( randInSound,150 ) attachElements ( randInSound, vehicle, 0, 0, 0 ) end addEvent("onPlaySyncedRandInform", true) addEventHandler("onPlaySyncedRandInform", root, syncedranfominform) Server: Spoiler function syncRandi(randinInd) local vehicle = getPedOccupiedVehicle(client) if getVehicleController(vehicle) == client then if spam[client] and getTickCount() - spam[client] < 5000 then return end local x, y, z = getElementPosition(client) local nearbyPlayers = getElementsWithinRange(x, y, z, 150, "player") spam[client] = getTickCount() randinSoundInd="randominform/"..randinInd triggerClientEvent(nearbyPlayers, "onPlaySyncedRandInform", client, vehicle, x, y, z,randinSoundInd) end end addEvent("onSyncRandi", true) addEventHandler("onSyncRandi", root, syncRandi) I'm a beginner and just getting to know Lua Edited August 26, 2023 by Lance_Delmago Link to comment
DiSaMe Posted August 26, 2023 Share Posted August 26, 2023 My point was that you shouldn't do that much work on the client. The client-side code should only be used for playing the sound. Which in this case is the part with syncedranfominform function and onPlaySyncedRandInform event. Everything else should be done on the server. You should call setTimer from onPlayerVehicleEnter event to start the timer and call killTimer from onPlayerVehicleExit event to stop it - so every time you enter a vehicle, a timer will be created to execute every 2 minutes, with first execution occurring 2 minutes after entering. And when you exit the vehicle, that timer will be destroyed so it will no longer execute. An example: local timers = {} function startTimerOnEnter(vehicle, seat, jacked) if seat == 0 then -- only call it if entered the driver seat local timer = setTimer(whateverFunctionYouNeedToCall, 120000, 0) -- create a timer timers[source] = timer -- store the timer in the table under source, which is the player end end function stopTimerOnExit(vehicle, seat, jacker, forcedByScript) local timer = timers[source] -- retrieve the timer from the table if timer then -- if, for whatever reason, the timer wasn't previously created, we need to check it killTimer(timer) -- destroy the timer timers[source] = nil -- clear the field from the table since the timer no longer exists end end addEventHandler("onPlayerVehicleEnter", root, startTimerOnEnter) addEventHandler("onPlayerVehicleExit", root, stopTimerOnExit) There are going to be some additional cases where you need to clean up, like destroying the timer if the player quits while in the vehicle, as onPlayerVehicleExit won't be triggered. This is just the main part to show what it should look like. Link to comment
Lance_Delmago Posted August 26, 2023 Author Share Posted August 26, 2023 2 hours ago, DiSaMe said: local timers = {} function startTimerOnEnter(vehicle, seat, jacked) if seat == 0 then -- only call it if entered the driver seat local timer = setTimer(whateverFunctionYouNeedToCall, 120000, 0) -- create a timer timers[source] = timer -- store the timer in the table under source, which is the player end end function stopTimerOnExit(vehicle, seat, jacker, forcedByScript) local timer = timers[source] -- retrieve the timer from the table if timer then -- if, for whatever reason, the timer wasn't previously created, we need to check it killTimer(timer) -- destroy the timer timers[source] = nil -- clear the field from the table since the timer no longer exists end end addEventHandler("onPlayerVehicleEnter", root, startTimerOnEnter) addEventHandler("onPlayerVehicleExit", root, stopTimerOnExit) Thanks, everything works :). Only I decided to do it on the client side because most of the script (sound, gui and route markers) are tied to the client. Everything is related to this topic, but I will need help with things like .dat files (the topic is in the scripting section), adding seats, spawn cars in the interior, "gluing" the trailer to the truck tightly (for articulated buses), etc., but the most basic ".dat" files and turning the rear wheels of the trailer relative to truck (as on ikarus 280) Link to comment
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now