Jump to content

IIYAMA

Moderators
  • Posts

    6,062
  • Joined

  • Last visited

  • Days Won

    208

Everything posted by IIYAMA

  1. By nesting them, so that you know which table belongs to which gate. local gates = { { openPosition = {x = 1023.599609375, y = -367.7001953125, z = 74.099998474121}, closePosition = {cx = 1029.3000488281, cy = -367.7001953125, cz = 74.099998474121}, colshapes = { {colX = 1021,colY = -371.5,colWidth = 5,colHeight = 8}, -- {colX = 1021,colY = -371.5,colWidth = 5,colHeight = 8} 2 colshapes? }, state = "closed", gateElement = nil }, --[[{ another gate }]] } --[[ While creating the elements, make the link between element and table. When you have access to the element, you have direct access to the data that belongs to the gate. ]] local dataByColshapes = {} local gateElement = createObject(...) local colshapeElement = createColRectangle(...) local gate = gates[i] gate.gateElement = gateElement -- save the gate element also inside of this table -- Make the link dataByColshapes[colshapeElement] = gate -- hit colshape?: local gate = dataByColshapes[source] if gate then local gateElement = gate.gateElement -- move gate! gate.openPosition, gate.closePosition end
  2. Then you will need xml functions. If you added the file as a config file in the meta.xml, then you can get the file like this: https://wiki.multitheftauto.com/wiki/GetResourceConfig Else you will need this function https://wiki.multitheftauto.com/wiki/XmlLoadFile All of them -> https://wiki.multitheftauto.com/wiki/Xmlnode
  3. I don't think it can be a simple example, but here you go. local bone_attach = {} local bone_attach_render = {} local queue = {} local queueProcessStatus = false local queueNextCycleTime = 0 local tableRemove = table.remove function prepareQueue () queueProcessStatus = true for i=1, #bone_attach do local item = bone_attach[i] if not item.rendered then queue[#queue + 1] = item end end end function processQueue () for i=#queue, math.max(#queue - 50, 1), -1 do local item = queue[i] local element = item.element if isElement(element) and isElementStreamedIn(element) then item.rendered = true bone_attach_render[#bone_attach_render + 1] = item end tableRemove(queue, i) end if #queue == 0 then queueProcessStatus = false end end addEventHandler("onClientRender", root, function () for i=#bone_attach_render, 1, -1 do local item = bone_attach_render[i] local element = item.element if isElement(element) and isElementStreamedIn(element) then else item.rendered = false tableRemove(bone_attach_render, i) end end -- cycle management local timeNow = getTickCount() if not queueProcessStatus then if timeNow > queueNextCycleTime then prepareQueue() queueNextCycleTime = timeNow + 3000 end else processQueue () end end)
  4. IIYAMA

    Uptime

    getTickCount returns the up time of the system. https://wiki.multitheftauto.com/wiki/GetTickCount
  5. I see you have optimised the loop cycles to the bone. But there is something you haven't tried yet, which can improve performance of 100 objects to a % of that, depending on the context. In your current code, you are making full cycles, which changes the usage of the resource by the amount of objects. But what if you could only make the necessary cycles? Prepare render cycle | | \/ bone_attach \ / Add each item to the queue, except for the once that are already in the render table, based on a state. QUEUE \ / Loop through 50 items each frame QUEUE [50 elements] \ / Is element streamed in? If YES, then add the item to the render table. If YES or NO, then table.remove. Give the item a state that it is already in the render table. bone_attach_render | | \/ Re-do the cycle after X ms This concept allows you to reduce big looping cycles. Which also allows you to even render 1000 objects, as long as the peds/players are not inside of the same area. These are not all the steps, there are some more which are related to 'destroyed' and 'streamed-out' elements.
  6. See this tutorial. Or attach the addEventHandler on to the resourceRoot. This will trigger the eventHandler only for elements created by the same resource.
  7. Because in the first example, login_box is not defined. So: gui_elements = {} gui_elements["login_box"] = guiCreateWindow(0.39, 0.29, 0.21, 0.43, "", true) gui_elements["user_input"] = guiCreateMemo(0.16, 0.15, 0.66, 0.13, "", true, gui_elements["login_box"]) gui_elements["password_input"] = guiCreateMemo(0.16, 0.30, 0.66, 0.13, "", true, gui_elements["login_box"]) gui_elements["big_button"] = guiCreateButton(0.17, 0.47, 0.43, 0.11, "", true, gui_elements["login_box"]) gui_elements["small_button"] = guiCreateButton(0.68, 0.47, 0.15, 0.12, "", true, gui_elements["login_box"])
  8. Even after all those optimisations, it is still pretty high ? What is the usage of the initial version compared to the current version? Also, I might be able to squeeze even more out of it, if you want that.
  9. You can't retrieve async data with a blocking method. Blocking/sync function _Query( ... ) if connection then local queryHandle = dbQuery( connection, ...) return dbPoll(queryHandle, -1) else outputServerLog("DB: Tried to fetch query but failed.") return false end end Non-blocking/Async function _Query(callBackFunctionName ... ) local sourceResource_ = sourceResource if connection then dbQuery( function (queryHandle) local results = dbPoll(queryHandle, 0) call ( sourceResource_, callBackFunctionName, results ) end, connection, ... ) return true else outputServerLog("DB: Tried to fetch query but failed.") return false end end
  10. Nope, but shaders can hold other textures, and renderTargets can capture unexpected different parts of images. Combine those and it can cause exactly that problem. If there are no rendertargets in the rest of the code, then it is also a mystery for me. ?
  11. Did you END the render target capture scope? (which is excluded in this code)
  12. IIYAMA

    [Doubts] IPB

    If the average total is higher than 30%, you might have a problem over time. If your server fps is much lower than the client fps, you might have a problem. If the regular operations on client/server from scripts take longer than 10/16 ms, you got a big problem.
  13. Little example: local gameModeState = "initial" function setGameModeState (newState) gameModeState = newState end function getGameModeState () return gameModeState end addEventHandler("onResourceStart", resourceRoot, function () setGameModeState ("started") setTimer(function () setGameModeState ("lobby") end, 1000, 1) end, false) addEventHandler("onPlayerJoin", root, function () if getGameModeState () == "lobby" then -- do something end end)
  14. The management of initiated/loaded players. Design different gamemode states. (loading/lobby/started) Making a list of resources you might need, instead of building every component from scratch. You do not have all the time of the world and you will be demotivated after a while, so make sure you will be able to finish it, else it is a waste of time. (99% of the people will be demotivated after a while...)
  15. Using: https://wiki.multitheftauto.com/wiki/Resource:Dynamic_lighting#setLightPosition + https://wiki.multitheftauto.com/wiki/OnClientPreRender
  16. That is probably related with the mathematics behind the colshape. For example a cube requires some basic mathematics, while a rotated cube requires some advanced mathematics.
  17. bindKey getElementMatrix getDistanceBetweenPoints3D findRotation3D --https://wiki.multitheftauto.com/wiki/FindRotation3D getTickCount createProjectile "onClientRender" "onClientPreRender" --(timeSlice benefit) function getPositionFromElementOffset(element,offX,offY,offZ) local m = getElementMatrix ( element ) -- Get the matrix local x = offX * m[1][1] + offY * m[2][1] + offZ * m[3][1] + m[4][1] -- Apply transform local y = offX * m[1][2] + offY * m[2][2] + offZ * m[3][2] + m[4][2] local z = offX * m[1][3] + offY * m[2][3] + offZ * m[3][3] + m[4][3] return x, y, z -- Return the transformed point end Just one of the concepts you can use: This function allows you to calculate the distance between a line and a point. This can be very powerful, when you combine that with getPositionFromElementOffset, because that function allows you create offset points from the vehicle. These offset points can be used to create a line in front of you, which you can use to compare the distance between all vehicles. Now you will able to exclude most of the vehicles behind you. Be creative, there a lot of options out there to do the same based on other mathematics calculations like rotation. (which you can also include as another layer) local getDistanceBetweenPointAndSegment3D = function (pointX, pointY, pointZ, x1, y1, z1, x2, y2, z2) -- vector1 -- local A = pointX - x1 local B = pointY - y1 local C = pointZ - z1 -- -- vector2 -- local D = x2 - x1 local E = y2 - y1 local F = z2 - z1 -- local point = A * D + B * E + C * F local lenSquare = D * D + E * E + F * F local parameter = point / lenSquare local shortestX local shortestY local shortestZ if parameter < 0 then shortestX = x1 shortestY = y1 shortestZ = z1 elseif parameter > 1 then shortestX = x2 shortestY = y2 shortestZ = z2 else shortestX = x1 + parameter * D shortestY = y1 + parameter * E shortestZ = z1 + parameter * F end local distance = getDistanceBetweenPoints3D(pointX, pointY,pointZ, shortestX, shortestY,shortestZ) return distance end Another concept: You can just simple use getDistanceBetweenPoints3D on a point in front of you. If you make the detection size 300 units and you do it 300 units in front of you. You will be able to capture all vehicles in front of you inside of a giant circle. > From that segment you can use getDistanceBetweenPoints3D again to compare the vehicle distance from the hydra and all other vehicles and this time you use a detection size of 150 units.
  18. Nope, unless you make the lock system yourself. I can give you a list of functions and events for that, if you so desire. But it is not a project for beginners.
  19. Locked This is a scripting request, which may not look like one, but this user has already made 2 scripting requests in this section and doesn't know Lua. And he is exceedingly bumping on all of his topics.
  20. Not a bug: https://wiki.multitheftauto.com/wiki/SetPedStat Serverside: addCommandHandler("setMaxHealth", function (player) setPedStat(player, 24, 650) end) Also according to this formula: (not sure if this is valid) stat = 650 print(100 + (stat - 569) / 4.31) -- 118.79350348028 max health Source: https://wiki.multitheftauto.com/wiki/GetPedMaxHealth
  21. Maybe, but you do not really need a lot of work to make that to work. addCommandHandler("callclient", function (player) -- An addCommandHandler is needed, because the client hasn't loaded it's scripts yet. callClient(player, "hello", function (value) iprint(value) end) end, false, false) function hello () return exports. -- ... end That is not possible, as the table reference can't be transferred to the other side. When you export tables from 1 resource to another, it deep copies the table. And functions can't be transferred at all. If you really want that. You need to transfer the method as a string. local methods = { { key = "test1", value = [[ function (self, something) return somthing * 2 end ]] }, { key = "test2", value = [[ function (self, something) return somthing * 2 end ]] } }
  22. Because the table is not an array format. That is why I split up the formats in to register and list. if not self.vehicles.register[vehicle] then self.vehicles.list[#self.vehicles.list + 1] = vehicleData self.vehicles.register[vehicle] = vehicleData else return false end #self.vehicles.list -- item count #self.vehicles.register -- always 0 In your case you can do 4 things. Recount local count = 0 for _,_ in pairs(vehicleCreator.vehicles) do count = count + 1 end Manually keep track of the count: self.vehicleCount = self.vehicleCount + 1 -- when you add a vehicle self.vehicleCount = self.vehicleCount - 1 -- when you remove a vehicle Or use an array format. --- at the cost of more search work with loops Or use 2 formats: array and custom indexes (vehicle = key) -- at the cost of more clean work I can answer that with an easy answer, but I do not think that would match your case, since that would kill some people their network. It is very important to write down the synchronization rules and pay a lot of attention to data reduction. Give it a 20 min brainstorm. Do you have to receive data when you are inside of a vehicle? Or when you are close by? Do you send the same value X when the user already know that the value is X? -- easy answer triggerClientEvent(players, "sync-vehicle-fuel", resourceRoot, { vehicleData1, vehicleData2, vehicleData3 }) addEvent("sync-vehicle-fuel", true) addEventHandler("sync-vehicle-fuel", resourceRoot, function (data) end, false) Exports do not work across clientside and serverside. Could work, but you can't reduce data. Element data maybe be smaller than triggerServerEvents, but you no control. But I do recommend to test both, so that you can get an idea, which one works better for you. To make the fuel system feel smoother, instead of only regular updates, you can also consider adding something that predicts what the fuel will be on clientside. So for example the server sends every 5 second an update. The updates from serverside: 100 > 95 > 90 While on clientside you make an future prediction and do: 100 > 99 > 98 > 97 > 96 > 95 > 94 > 93 > 92> 91 > 90
  23. That is not so simple. Especially if you set a value from both sides at the same time. If there is a 'large' connection delay between the client and server. Client says the vehicle has 70 fuel. When that message is still underway, serverside says the vehicle has been filled up to 100 fuel. 1. Client set 70 2. Server sets 100 3. Client sets 100 4. Server sets 70 Now it is desynchronized, so the first step is to set the rules. For example: The server is only allowed to set the fuel value. You also need to make an collection of all vehicles, else you can't synchronize. vehicleCreator = {totalSavedVehicles = 0, totalTemporaryVehicles = 0, vehicles = {list={}, register={}}} The list is optional, it can be used to increase processing time for loops, since it is an array. if not self.vehicles.register[vehicle] then self.vehicles.list[#self.vehicles.list + 1] = vehicleData self.vehicles.register[vehicle] = vehicleData else return false end You can also turn these operations in to functions, but this is just basics. If you have a register, you have already have access to those data. The vehicle is the key of course. local data = vehicleCreator.vehicles.register[source] if data then -- magic end -- or function vehicleCreator:getVehicleData (vehicle) return self.vehicles.register[vehicle] end -- or vehicleCreator.getVehicleData = function (self, vehicle) return self.vehicles.register[vehicle] end Did you know that the JS libraries jquery and D3 are working very similar to that? They just put their own layer on top of it. jquery var element = $( "#id" ); d3 var element = d3.select("#id") Lua ??? local vehicleData = vehicleCreator:getVehicleData(vehicle) I know you want to work cleanly but you have to keep in mind that in order to do that, you have to start wrapping a lot of things. > Even if you did save these information into the class, you will lose that as soon as the element is destroyed. Which is another thing to keep in mind.
  24. local consumeFuel = function() local vehicle = vehicleData.element local distance = getDistanceBetweenPoints2D(vehicle.position.x, vehicle.position.y, newPosition.x, newPosition.y) local engineConsumption = 0 if vehicle:getEngineState() then engineConsumption = 0.7 end if vehicleData.fuel >= 1 then vehicleData.fuel = vehicleData.fuel - (VEHICLE_FUEL_CONSUMPTION*(distance+engineConsumption)) newPosition.x, newPosition.y = vehicle.position.x, vehicle.position.y print(vehicleData.fuel) end if vehicleData.fuel < 1 then vehicleData.fuel = 0 vehicle:setEngineState(false) end end You do not have to create another function, you can just use 1 function instead. Every new function you create within a block, will keep the block alive. addEventHandler("onVehicleEnter", vehicleData.element, function(_, seat) if seat == 0 then local fuelTimer = setTimer(function(vehicle) consumeFuel() vehicle:setData("vehicle.datatable", vehicleData) end, 1000, 0, source) addEventHandler("onVehicleExit", source, function(_, seat) if seat == 0 then if isTimer(fuelTimer) then killTimer(fuelTimer) fuelTimer = nil end end end) end end) This code can cause a memory leak, since the code is merged with addEventHandler's that leave the Lua environment. Also here make use of 2 already existing function. If I want to have OOP tables (not meta table) shared between client/server. I have to split up the methods and re-attach them when they are available on the other side. > [1 file] Client only methods > [1 file] Server only methods > [1 file] Shared methods I do not know the best practice for this, but re-attaching them seems to work fine. Maybe you can use rawset: (not sure if that is allowed, I do not use MTA OOP, only regular) http://www.Lua.org/manual/5.1/manual.html#pdf-rawset And if you can't edit those classes, you can just put another meta layer on top of it, to make it work. I am not a pro,so I am pretty sure there are smarter people around here to give you the best answers.
  25. For melee hits, there is 1, which only works for break-able objects. If you want other elements as well, you need to make the event yourself: https://wiki.multitheftauto.com/wiki/ProcessLineOfSight https://wiki.multitheftauto.com/wiki/BindKey For bullets: https://wiki.multitheftauto.com/wiki/OnClientPlayerWeaponFire
×
×
  • Create New...