-
Posts
6,058 -
Joined
-
Last visited
-
Days Won
208
Everything posted by IIYAMA
-
That really depends on your user-case. When requesting the browser, you will be starting a web browser application inside of your game. This cost more performance than just rendering a rectangle with dx. But rendering 1000 elements, yes the browser will be more optimised to render multiple elements better/faster. The browser can actually do have influence on the FPS, if the website is not optimised or when there are too many browser windows created. The question you actually want to ask is: "Which is better for me?" And you are the only one able to answer that question. So a few of my recommendations: Use dx: When displaying just a few elements at a location When you do not want to spend a lot of time on a project. Setting up and maintaining a browser requires more code. For optimised textures. Use the browser: When rendering tons of elements. When using a lot of (CSS) animating. When you understand CSS and HTML (required). When handling UI/UX browser events based (Javascript required). Other things: Do not create too many browsers windows. Stop the browser from rendering, when not used: https://wiki.multitheftauto.com/wiki/SetBrowserRenderingPaused A browser renders content like this:
-
Because the players/clients haven't loaded their scripts yet. The server is always one step a head in time.
-
That is not possible.
-
Yes. To be honest, I still do not understand your question completely, so I am trying to gamble a bit.
-
You can do that with local functions. Those functions can only be used within the file local name = function () end local function name () -- this one is able call itself,in compare to the previous one: name() end local name -- variable scope starts here function name () end Another solution would a table with methods.
-
-- -- -- -- -- -- This block cannot be frozen! -- -- -- -- -- co[id] = coroutine.create(function() -- This block can be frozen!!!!!!!!!!!!!!!!!!!!!! local id = querydb("SELECT * FROM `kayitlar` WHERE `KullaniciAdi`='mahlukat'") print("querydb: "..tostring(id)) local result = getQueryResult(id) print("queryresult: "..tostring(result)) end) -- -- -- -- -- function querydb () -- This block can be frozen!!!!!!!!!!!!!!!!!!!!!! coroutine.yield() end function getQueryResult () -- This block can be frozen!!!!!!!!!!!!!!!!!!!!!! coroutine.yield() end That way.
-
@XiVirtue Every step of the query process have to be done inside of the coroutine function. And you cannot use two coroutines for one execution process. Tip: Functions blocks that are outside of the coroutine, but called from within the coroutine function block, are considered to be part of the coroutine. It sound complicated, but it means that you can yield a coroutine from a different function, as long as it is part of the coroutine process.
-
@Sorata_Kanda The event 'onPlayerJoin' triggers faster than a client has loaded his client resources. onClientResourceStart > triggerServerEvent > races > triggerClientEvent This also works for clients that are already in the server.
-
Keep in mind that a table should not be a part of a race element. Because tables become a new object when they are saved inside of elementData. But a race element can be a part of a table. There is a function called isElement after all. Another way to reference from a raceElement to a table is by using another table. They should be both in the same environment. reference = {} table = {} element = [[...]] reference[element] = table The event system is indeed async.
-
Yes, elementData should be considered as something similar to attributes. <race title="example" /> It defines the specifications of elements. Before you continue, rendering based on elements is not the method with the most performance. So keep that in mind. But! The benefits: There is less (validation- and maintenance)code required. If an element is deleted, then you do not have to clean it from a table. 100% control serverside. Client elements can be set as children of server elements. So these can be auto cleaned as well. The tables from the queries are formatted as arrays, so looping through them doesn't require much time.
-
See the first example of this page: https://wiki.multitheftauto.com/wiki/GetElementMatrix Maybe this: https://wiki.multitheftauto.com/wiki/GetDistanceBetweenPointAndSegment2D (might need a 3D version of it) And this: function findClosestPointOf2Lines3D (line1X,line1Y,line1Z,line1VectorX,line1VectorY,line1VectorZ,line2X,line2Y,line2Z,line2VectorX,line2VectorY,line2VectorZ) local Vec1 = Vector3 (line1VectorX,line1VectorY,line1VectorZ) local Vec2 = Vector3 (line2VectorX,line2VectorY,line2VectorZ) local line1 = Vector3 (line1X,line1Y,line1Z) local line2 = Vector3 (line2X,line2Y,line2Z) local a = Vec1:dot(Vec1) local b = Vec1:dot(Vec2) local e = Vec2:dot(Vec2) local d = a*e - b*b if tostring(d) ~= "0.0f" then local r = line1 - line2 local c = Vec1:dot(r) local f = Vec2:dot(r) local s = (b*f - c*e) / d local t = (a*f - c*b) / d local closestPointLine1 = line1 + Vec1 * s local x,y,z = vectorUnpack(closestPointLine1) return x,y,z end return false,false,false end function vectorUnpack(v) return v.x, v.y, v.z end
-
You can also use the onClientRender event to load the textures one by one. To keep up the frame- rate, you can use getTickCount() function to delay the process even further. https://wiki.multitheftauto.com/wiki/OnClientRender https://wiki.multitheftauto.com/wiki/GetTickCount Have you ever considered using a map file? Loading map files is damn xxxxxxx fast in compare to create every single element with createObject. Take it or leave it. (of course this means that you will lose the ability to send specific maps to each client) local file = xmlCreateFile("saved.map", "map") if file then local mapRoot = createElement("map") setElementParent(createObject([[...]]), mapRoot) -- all your objects saveMapData ( file, mapRoot) xmlSaveFile ( file ) xmlUnloadFile ( file ) end https://wiki.multitheftauto.com/wiki/SaveMapData
-
That would me sense. But the way you are using it now is very heavy work. Searching through all elements in the whole server. Would this not make more sense? (limiting to the resource only) for i, race in ipairs(getElementsByType('race', resourceRoot)) do -- do stuff here end This is even faster and has a better structure: -- server local raceContainer = createElement("raceContainer", "raceContainer") for i=1, 10 do setElementParent(createElement("race"), raceContainer) end (find one and access the rest) -- client local raceContainer = getElementByID("raceContainer") local raceElements = getElementsByType("race", raceContainer) -- search also through sub-elements -- or local raceElements = getElementChildren(raceContainer, "race") -- just the direct children (faster) for i, race in ipairs(raceElements) do -- do stuff here end Why bother making a race element? - You can let sub-elements hang on it. They will be deleted when you delete the parent. - Attach addEventHandlers to the parents of sub-elements. (which limits the event scope) - Limit the scope of element queries. (like: getElementsByType) - The benefit of having access to scoped propagation / inherits. -- server local raceContainer = createElement("raceContainer", "raceContainer") for i=1, 10 do setElementParent(createElement("race"), raceContainer) end setElementDimension(raceContainer, 50) (propagation / inherits is by default enabled: https://wiki.multitheftauto.com/wiki/SetElementCallPropagationEnabled)
-
I am only using elementdata to share information globally or between resources(with sync disabled). If I want to get the title for within the resource, then I will get it from a variable. If I want to set the title within the resource, then I will save it in a variable. + If I want to show the title of the map on a client his screen, yes I will use elementdata as second method.
-
-- server Race = {} Race.__index = Race addEventHandler("onResourceStart", resourceRoot, function () attachRaceClasses(Race) -- initial end) addEvent("testRaceClasses", true) addEventHandler("testRaceClasses", resourceRoot, function (raceElement) attachRaceClasses(raceElement) outputChatBox(raceElement:getTitle()) end, false) -- client Race = {} Race.__index = Race addEventHandler("onClientResourceStart", resourceRoot, function () attachRaceClasses(Race) -- initial local raceElement = Race.new() raceElement:setTitle("Sorata_Kanda") triggerServerEvent("testRaceClasses", resourceRoot, raceElement) end) -- shared function attachRaceClasses (race) function race.new() local self = setmetatable({}, race) self.title = 'Great 8-Track' self.laps = 10 self.element = Element('race', 'Race 1') self.checkpoint = Marker(...) self.checkpoint:setParent(self.element) self.element:setData('sourceobj', self) return self end function race:setTitle(string) self.title = string end function race:getTitle() return self.title end function race:getCheckpoint() return self.checkpoint end end Like this. Nothing special.
-
A coroutine is a function block which can be frozen with: coroutine.yield() This function has to be called during the execution of the block. It doesn't have to be in the same block, but within the code that is executed in the block. The resume function can be called from where ever you want. It can be used to start the executing the coroutine function. But also to resume a frozen(yield) coroutine function. coroutine.resume(co) When a coroutine function has been executed till the end, the status of the coroutine function is considered dead. It can't be resumed any more.
-
You can do that, but the coroutine has to be placed around this: -- couroutine function local id = querydb("SOME DB FUNCS") local result = getQueryResult(id) -- function something () local co = coroutine.create(function () local id = querydb(co, "query") local result = querydb(co, "query") end) coroutine.resume(co) -- start the coroutine end function querydb (co, query) -- ... local callBackFunction = function () coroutine.resume(co) -- resume! end -- execute the query here! coroutine.yield() -- freeze! return results end Something like that.
-
This is not how you use coroutines. Databases and coroutines are two very different things. But for what kind of reason do you want to use a coroutines? dbQuery is already providing you with a callback option. https://wiki.multitheftauto.com/wiki/DbQuery Optional Arguments callbackFunction: An optional function to be called when a result is ready. The function will only be called if the result has not already been read with dbPoll. The function is called with the query handle as the first argument. (Notice: Do not use a function with a local prefix) If you want to improve your database performance, then write better queries with limiters.
-
Nope, not 100%, a new instance of the table is already happening behind the scenes. A new instance will be created when: (there might be more) When the table leaves the resource (export or event system) When the table gets transferred from clientside <> serverside (event system) When a table is send as parameter with timer (< not many people are aware of this one, but for timers there isn't a feature that is suppose to keep the table out of the garbage collector. So they let the timer make a deep-copy of the table.) It might contain the same content, but it is not the same table. Creating the instance is done already, but re-attaching the classes to give it the full functionality back is the remaining work.
-
Not being able to send functions is more than logic. Functions are bound to the blocks around it. But you could try to create a shared file with all classes in it. When sending a table over to the otherside the only thing left to do is putting the classes back in to the table.
-
probably. But can't you just make exports? function Race:setTitle(string) self.title = string end -- export function function raceSetTitle (string) return Race:setTitle(string) end
-
We are doing more or less the same. The main difference is that I am building a higher object tree. Technically tables in tables. The one of the race resource is just one layer. Example. clown = { animation = { sleep = function () end, dance = function () end }, movement = { run = function () end, walk = function () end, fly = function () end }, title = { set = function () end, get = function () end, remove = function () end } } A clown can do animations, movements and have a title. This example is used for single clown, without using the hidden variable self.
-
Nope, I write it a bit different. I am still experimenting with it to be honest and I haven't found my style yet. See the client file of this resource: It is looks like JavaScripts with a few Immediate Function Invocation hacks...
-
Yes that would indeed happen. There is no predefined variable, because each loaded map in a single resource has it's own mapRoot. See image: (there are two maps on one resourceRoot) Function to get it: https://wiki.multitheftauto.com/wiki/GetResourceMapRootElement You might also be able to get it with: https://wiki.multitheftauto.com/wiki/GetElementChildren Which only takes the direct children of an element. This will give you the root of all elements created by scripting: (No pre-defined variable for some unknown reason) https://wiki.multitheftauto.com/wiki/GetResourceDynamicElementRoot