-
Posts
6,097 -
Joined
-
Last visited
-
Days Won
218
Everything posted by IIYAMA
-
I have heard of this issue, but never ever had encounter it while killing a ped. How to reproduce this issue? And are you sure this isn't caused by a resource or your version of GTA?
-
function teleprotect (>>> thePlayer <<<) local vehicle = getPedOccupiedVehicle(playerSource) if vehicle then setElementVelocity(vehicle,0,0,0) setElementPosition (vehicle, 4131.3872070313, -1759.1988525391, 3) else setElementPosition (playerSource, 4131.3872070313, -1759.1988525391, 3) end outputChatBox ("You Have Been Teleported To The Highway!!", playerSource, 0, 255, 0) end local accName = getAccountName(getPlayerAccount(thePlayer)) if isObjectInACLGroup("user."..accName, aclGetGroup("Admin")) then outputChatBox ( "Server: You are not an owner!", thePlayer, 0, 255, 0 ) setElementPosition (thePlayer, 4131.3872070313, -1759.1988525391, 3) else outputChatBox (getPlayerName(thePlayer) .. ' #BEBEBEASf ! ', source, 255,255,255,true) end addCommandHandler ("highway", teleprotect) You can't just imagine variable names. Consistency matters. function healPlayer(>>> player <<<, cmd, name, price) if not name or not price then outputChatBox("/heal [Player_Name] [Price]", player, 255, 255, 255, true) else end end local gang = getPlayerAccount(thePlayer) if (gang) then if getAccountData(gang, "keks.fraktion") == 3 then outputChatBox("hp <name> <price>", thePlayer) else outputChatBox("You are not a member of Paramedic!", thePlayer, 255, 0, 0) end end local target = getPlayerFromName(name) if target then if getPlayerMoney(target)>=tonumber(price) then takePlayerMoney(target, tonumber(price)) givePlayerMoney(player, tonumber(price)) setElementHealth(target, 100) outputChatBox(getPlayerName(player) .. " healed you!", player, 255, 255, 255, true) outputChatBox("You healed " .. getPlayerName(target), player, 255, 255, 255, true) else outputChatBox("Can't pay the healing", player, 255, 255, 255, true) end else outputChatBox("I can't find the target!", player, 255, 255, 255, true) end addCommandHandler("heal", healPlayer)
-
Best practice to synchronize server/client caches
IIYAMA replied to Sorata_Kanda's topic in Scripting
You can also keep track of people that are allowed to edit the data. And only open a UI for 1 person at the time, per house. + only let that person push updates on serverside. -
Best practice to synchronize server/client caches
IIYAMA replied to Sorata_Kanda's topic in Scripting
@Sorata_Kanda while (blocked_exec["lockHouse"]) do end This will kill your server. ? The code will not stop at the current server/client frame, but freeze all frames that come after it and keep doing endlessly looping as fast as it can. Luckily Lua is smart enough to abort it after a few milliseconds. If we translate this to a possible working version. (I AM NOT saying that it is a good method, AS IT IS NOT, uses a lot of CPU as you are literally rendering on serverside) local function waitWithLocking (pickupElement) if blocked_exec["lockHouse"] then callNextFrame(waitWithLocking, pickupElement) else blocked_exec["lockHouse"] = true -- Block execution until finished (possible concurrency problem/race condition?) local houseObject = houses[pickupElement] houseObject:setLocked(not houseObject:isLocked()) blocked_exec["lockHouse"] = false end end addEventHandler('lockHouse', resourceRoot, function(pickupElement) callNextFrame(waitWithLocking, pickupElement) -- In case this event is currently handled by someone else, keep in loop until finished end) callNextFrame The thing you better can do, is sending a message back to clientside and reset the change. + WARNING. Or a just as risky, keep a table ready with all updates. When the user releases it's edit, update all changes at once. The release of the edit should also be triggered or when the player leaves. And it might also be handy to release it when the resource is going to stop. And the most enchanted method, update all clients that are editing as well instead of blocking! -
According this topic: http://www.computercraft.info/forums2/index.php?/topic/11043-invalid-key-to-next/ It says that the table has been changed while the process has been yield. Not sure is that is true or not. If we would reproduce that: We have for example this table: local thisTable = {[element] = ped, [element] = ped, [element] = ped, [element] = ped, [element] = ped,[element] = ped } We start looping: local thisTable = { [element] = ped, [element] = ped, [element] = ped, -- yield [element] = ped, [element] = ped, [element] = ped } Now a different part of the code removes: local thisTable = { [element] = ped, [element] = ped, [element] = ped, -- yield [element] = ped, -- < deleted [element] = ped, [element] = ped } And we resume. That is when it is suppose to be happening according to this information. Solution without changing the table structure? pcall might be to catch the error and if there is an error, recreate the coroutine. local status, err = pcall(coroutine.resume, clearing_nonexisting_peds) if not status then clearing_nonexisting_peds = coroutine.create(forgetNonExistingPeds) end
-
Yes! ?
-
There is no limit to local variables, as long as they are used in different file or function scopes. -- file scope 200 local's function name () -- function scope 200 local's end
-
@TorNix~|nR That is not how this works. A table is a thing, it is something even if it is empty. if {} then outputChatBox("Always true") end local players = getElementsByType("player") for index,thisPlayer in pairs(#players > 0 and players or getElementsByType("ped")) do Note, this does not merge the tables. Just uses peds when there are no players.
-
getElementsByType("gui-staticimage", resourceRoot) Maybe you get other resource elements as well?
-
@Xwad Master this loop and all possibility will open up to you. local theTable = {[0] = 0, 1,2,3,4,5,6,7} local index = 1 for i=0, #theTable, 2 do print("position: ", index * 10) index = index + 1 print("index: ", theTable[i]) print("index: ", theTable[i + 1]) print("---") end
-
Instead of true save the gui element you entered. Then you can compare it to the destroyed element later.
-
Yes, tables (and functions) are not saved in the variables. They are objects/things that are saved at a different place in the memory. (Not that far, they are neighbours...) The only thing that is saved in those variables are a kind of references to the thing itself. Because it is not saved in to those variables directly, we are able to do this: a = {} b = a a[1] = "I love it" print(b[1]) -- I love it This should really make clear that a table is not just a value, but a thing that can pretend that it exist at multiple places at the same time. `a` and `b` share the same reference to the same table. When both reference are delete, the table becomes unreachable* and the garbage collector will automatically deal with it: http://lua-users.org/wiki/GarbageCollectionTutorial
-
Not sure, Doesn't blob help you out? But it shouldn't be an issue. At the end they both represents NO in most lua conditions. This method is in most scenarios just asking for trouble: if a == nil then This one works just 99% of the time: if not a then
-
A (local) table would probably not faster than a global variable. Because instead of doing 1 thing, you are actually doing 2 things. Requesting the local variable. Indexing in the table with a string. That is also the reason why OOP is not very fast. But as I said many times before, read-ability is also performance. If you want performance then please consider to only apply it selective at places in the code which are used a lot. (by for example a loop or onClientRender) If we look for example at the function callNextFrame: (shared: client/server) It is very well optimised. But not 100%. What would you want to improve of this code to optimise it to a 100%? local tableRemove = table.remove local serverSide = triggerClientEvent and true or false --[[ -- callNextFrame function ]] do local nextFrameCalls = {} local serverSideTimer local processing = false local function process () --[[ Do an empty check at the beginning of the function, this will make sure to make an extra run in case of heavy work load. If the timer is killed or the addEventHandler is removed, then this has to be re-attached again every frame. This is not very healthy... ]] if #nextFrameCalls == 0 then if serverSide then if serverSideTimer then if isTimer(serverSideTimer) then killTimer(serverSideTimer) end serverSideTimer = nil end else removeEventHandler("onClientRender", root, process) end processing = false return end -- In case of calling the function callNextFrame within the process, the loop type `repeat until` is required. repeat local item = nextFrameCalls[1] item.callback(unpack(item.content)) tableRemove(nextFrameCalls, 1) until #nextFrameCalls == 0 end function callNextFrame (callback, ...) if type(callback) == "function" then local newIndex = #nextFrameCalls + 1 nextFrameCalls[newIndex] = {callback = callback, content = {...}} if not processing then if serverSide then serverSideTimer = setTimer(process, 50, 0) else addEventHandler("onClientRender", root, process) end processing = true end return true end return false end end This code does: Moving a function call to the next possible frame. Example: callNextFrame(outputChatBox, "Hey next frame, I love you!")
-
Best practice to synchronize server/client caches
IIYAMA replied to Sorata_Kanda's topic in Scripting
1. Yea, this will also prioritise the request over the network. 2. The entity you will be using to update the main data is a table. MTA objects/elements are secondary. Ofcourse this doesn't mean you can't use an object to fake the updates before they are actually applied. (Data reduction) 3. A boolean or a custom function in between. The default MTA functions do not have such a feature without creating errors. -
If something doesn't exist anymore, then there is nothing to leave from. In fact it will only cause more problems for the onClientMouseLeave event. An event can't just trigger without it's source.
-
A file counts also as a function.
-
No your can't use that function as it blocked. This is more or less how a require_once module works. So you can also make your own. (NOTE: it is not exactly the same as require, just the logic of it) Untested, if it works or not is irrelevant for now. modules = {["module1"] = {loaded = false}} function requireThis (name) local thisModule = modules[name] if thisModule then if thisModule.loaded then return thisModule.container else local fileName = name .. ".lua" if fileExists ( fileName ) then local theFile = fileOpen(fileName, true) if theFile then local count = fileGetSize(theFile) local data = fileRead(theFile, count) thisModule.container = loadstring(data)() thisModule.loaded = true end fileClose(theFile) return true end end end return false end requireThis("module1") File: module1.lua local thisModule = { collection = {} } function thisModule:add (...) local data = {...} if data[1] then local collection = self.collection collection[#collection + 1] = data return true end return false end return thisModule
-
Best practice to synchronize server/client caches
IIYAMA replied to Sorata_Kanda's topic in Scripting
Server should be in control at all times. So yes caches on serverside to reduce impact on the database. But keep in mind that if a query fails, it is important that the data is reset. In case of more users are editing the same data. > No caches recommended on clientside. (until the instructions from clientside are perfect) While there are changes made, it is recommended that the client his GUI is disabled until the server is finished. Else the data might not be mirrored correctly, that being said it is not impossible. You can use caches clientside, but it is important that the identifiers remain unique at all cost. The server is in control of the identifiers. Else there is a VERY HIGH risk of data corruption. Clientside should only send retrace able instructions of the modifications and not the modified data. Else there is a risk of VERSION corruption. Instructions also allows you to mirror without freezing the GUI. Each instruction should be validated on both serverside as well as clientside. In case of a failed data-update/query clientside should be restored to it's previous data-structure. It is VERY important to block new instructions and freeze the GUI until both sides are mirrored again. It is not that easy after all And use or build a tool like this: https://gitlab.com/IIYAMA12/mta-communication-enchantment/tree/master/ -
nvm that is probably not going to work.
-
local posX, posY, posZ = getElementPosition(hitElement) local offsetX, offsetY, offsetZ = getOffsetFromXYZ(getElementMatrix(hitElement), posX - hitX, posY - hitY, posZ - hitZ) The matrix is already containing the position of the vehicle. Untested and not even sure if this is the right approach. @Xwad P.s this function can return the surface position:https://wiki.multitheftauto.com/wiki/ProcessLineOfSight normalX, normalY, normalZ
-
Command with space characters!!! Help with team names!
IIYAMA replied to Razor70538's topic in Scripting
function functionName (player, cmd, ...) local name = table.concat({...}, " ") end @Razor70538 -
@Overkillz dxSetRenderTarget( myRenderTarget, true ) Syntax: bool dxSetRenderTarget ( [ element renderTarget, bool clear = false ] ) The stuff you have drawn before on the paper, will not just clear itself. A render target is like a piece of paper of the REAL WORLD. Once you have drawn on it, you need an eraser to clean it. There are two things you can do. Clear the render target Or paint it black again with a rectangle. If it is just text on it, clearing the render target will do the job. But if you have multiple components on it, which you do not want to re-draw very frame on the render-target, then it might be handy to paint selected area's black. See also blend mode: overwrite : The source textures are overwritten. This can be useful for clearing render targets https://wiki.multitheftauto.com/wiki/DxSetBlendMode (Haven't used it before.) Also keep in minder that you can also use two render targets. One you can update when the text changes and one to move the frame.
- 1 reply
-
- 1
-
-
Or you can use this function: https://wiki.multitheftauto.com/wiki/IsElementVisibleTo Within the donegobeach function. It is a little bit dirty, but it should do it's job.
-
Ah yea true, my bad. But afaik that doesn't work for new joined players. Experimental. local normaliseVisibility = createElement("normaliseVisibility") addEventHandler("onPlayerJoin", root, function () setElementVisibleTo(normaliseVisibility, source, false) end) markergobeach = createMarker ( 2945.4387207031, -2053.7338867188, 2.8984375, "cylinder", 2, 255, 0, 0, 50, thePlayer ) BlipDiver = createBlipAttachedTo ( markergobeach , 41, 2, 255, 0, 0, 255, 0, 99999.0, thePlayer ) setElementParent(markergobeach, normaliseVisibility) setElementParent(BlipDiver, normaliseVisibility)
