Jump to content

Kayl

Members
  • Posts

    70
  • Joined

  • Last visited

Everything posted by Kayl

  1. I think it's pretty well coded, as it would let you have both a modded object and don't mess the GTA world with the same object ID You can't really say that you are left with the freedom to have both a modded object and an untouched GTA world object because the moment your MTA object is streamed in, the GTA world object changes as well. When you replace an "ID", you expect all instances to be replaced. If it was that well coded, it would either replace also GTA world objects without the need for a hack, or provide us with an option to say if we want only MTA objects affected. Right now we have absolutely no control over when the GTA object is replaced (since it depends on the MTA objects as we discussed). To have a real freedom to leave GTA objects untouched, it all goes down to the problem of having only access to "replacement" functions. If we could create new IDs and load new models without having to replace GTA ones, that would also be great. There are lots of improvements to be done on those engine functions (no control over the real replacement of GTA objects, no way to create new models, collision model failing on streamin > need scripting hack to maintain the col in a working state, random texture fail). I wouldn't really say it's "well coded". It's a preview of what we could expect but it's left in a weird state.
  2. That's indeed the technique used for this DKR sign. A ghost (alpha = 0) MTA object is created at the same location as the GTA object to guarantee the streaming in of the MTA object will force the GTA object to be "updated" accordingly. I wish this was not necessary.
  3. <script src="..." type="client" />
  4. Thank you very much for sending me your file. Thanks to it, I was able to spot the problem. It was a QtToLua bug introduced when the export of scroll bar was created. Scrollbar of scrollareas where also exported as standalone scrollbars when they shouldn't be. I have therefore released version 0.1.7 of QtToLua http://dkrclan.com/qttolua_data/download/QtToLua.zip which fixes the aforementioned bug. I have tested it with your file and it works fine now. You are free to use layouts or not, the problem was not coming from that. Thank you for your feedback which helped me fix this issue.
  5. From what I see you don't use layouts which might explain a mismatch when going from Qt to MTA, also when you create a new window, choose widget or dialog, mainwindow is useless since menus are not part of MTA. Apart from the layout suggestion, I don't see what the problem could be, could you send me your UI file so I can have a look?
  6. Vice > The example resource shows how to show/hide the window with a command. In your code for your own window, simply use https://wiki.multitheftauto.com/wiki/BindKey to bind F5 to your command/function showing the GUI. dukenukem > No. Qt with C++, hence "Qt to Lua".
  7. As far as I know, the very definition of dimension is that all elements in other dimensions than the current local player's dimension aren't streamed in² for the local player, they are merely element information that will only be transposed to GTA world "objects" if the player is in the right dimension and the surrounding of it. The GTA clientside version of the car is "gone" not "hidden" for the client so there is no way his GTA physic engine could continue syncing it correctly so I fairly doubt MTA would let him be the syncer of it. So for me, forget about the car issue since I think it's a non issue, moving (clientside) all the map objects to the current player's dimension each time it changes seems for me the right solution to get map elements in all dimensions. ²OnClientElementStreamIn : "When this event is triggered, that element is guaranteed to be physically created as a GTA object."
  8. That's because of euler rotation order. Cf: viewtopic.php?p=326214#p326214 Objects in MTA are ZXY whereas vehicles are ZYX, meaning (for objects) rotation about world Z, then rotation about resulting X and then rotation about resulting Y (for objects). So the result is different depending on the order. Most people use moveObject to rotate about one axis at a time and on objects that have 0 rotation on X or Y so the problem is not seen for those. The editor uses a patch, similar to the lua code you will find in the topic post above, to make objects rotate with ZYX and not ZXY. It has now been integrated in MTA 1.1 directly via an extra parameter for https://wiki.multitheftauto.com/wiki/SetElementRotation which, as far as I know, hasn't been backported to 1.0.4. However moveObject isn't affected by it yet, and I intend to fix that, hopefully it will be backported. For now, if you do the moveObject clientside, you can work around the issue by doing the moveObject yourself onClientRender and using the lua patch above. If you do it serverside, you have to wait for it to be implemented and backported. Edit: actually now that I think about how moveObject is done (since I'm already working on it for something else) I can tell you that even if it gets implemented, it will create some rotation artefacts on the non updated clients. I will implement it though, but I don't think this part should be backported.
  9. Kayl

    Compiling LUA

    Even if you do use an external webserver it shall be configured so as to give access to the resource-cache folder (not the resource one) which only consists of the latest versions of all required clientside files. Only if the webserver was poorly configured would it give access to mta serverside files.
  10. XX3 > Indeed the end goal is to be able to attach object like hats or other items to a ped. Both problems need to be resolved to be able to do that correctly (for the orientation one, the hack I currently do in the head only works for some skins, providing the orientation of any bone would allow me to make it work for all). benxamix2 > I don't want to attach the object to the root bone of the ped but to a specific bone which, during animations, changes offset and orientation. But as I mentioned, this topic is more about the positioning than the rotation (which can be hacked for most skins when it comes to the head). I didn't put my rotation hack in the example code since I want to focus on the position issue first.
  11. Hi there, I'm trying to play a bit with bones. I'm trying to "attach" an object relatively to a bone. The first problem concerns the position of the bone (here, a bone in the head). It appears that, in order to have the object following the bone smoothly, the getBonePosition + setElementPosition (on the object) must be done onClientPreRender. However, when walking on steep slopes, it seems GTA changes the bone position between onClientPreRender and onClientRender, I guess it's a result of inverse kinematics being performed to make the ped's feet touch the ground and adapt the current animation accordingly. In this case then the valid position is the position given onClientRender but if I set the position of the object onClientRender, the position is fine, but the object is flickering. Whereas if I set it onClientPreRender, the object doesn't flicker but isn't in the right position when it comes to peds walking on non flat ground. Illustration code: addCommandHandler("bone", function() local objectPreRender = createObject(2054, 0, 0, 0) local objectRender = createObject(2054, 0, 0, 0) local objectRender2 = createObject(2054, 0, 0, 0) local bx, by, bz = nil, nil, nil addEventHandler("onClientPreRender", getRootElement(), function() bx, by, bz = objectToBone(objectPreRender, 0, tocolor(255, 0, 0, 255)) end) addEventHandler("onClientRender", getRootElement(), function() objectToBone(objectRender, 0.1, tocolor(0, 255, 0, 255), objectRender2, 0.2, tocolor(0, 0, 255, 255), bx, by, bz) end) end) function objectToBone(object1, offset1, color1, object2, offset2, color2, bx, by, bz) local newbx, newby, newbz = getPedBonePosition(getLocalPlayer(), 5) setElementPosition(object1, newbx, newby, newbz + offset1) _FDP({newbx, newby, newbz + offset1}, color1) if object2 and bx and by and bz then setElementPosition(object2, bx, by, bz + offset2) _FDP({bx, by, bz + offset2}, color2) end return newbx, newby, newbz end function _FDL(sx, sy, sz, ex, ey, ez, color) local realColor = color or tocolor(255, 0, 0, 255) local ssx, ssy = getScreenFromWorldPosition(sx, sy, sz) local esx, esy = getScreenFromWorldPosition(ex, ey, ez) if ssx and ssy and esx and esy then dxDrawLine(ssx, ssy, esx, esy, realColor, 2) end end function _FDP(pos, color) local delta = 0.1 local x, y, z = unpack(pos) _FDL(x +delta, y, z, x-delta, y, z, color) _FDL(x, y+delta, z, x, y-delta, z, color) _FDL(x, y, z+delta, x, y, z-delta, color) end And the result (Z offset is on purpose to differentiate techniques): Is there any way to solve this dilemma? The second issue I have is different and not as important for now and is more a feature request. It's about the orientation of a bone. Looking at MTA's code, it seems there isn't yet the ability to extract (from GTA) the absolute orientation of a bone (only its position). Hence it becomes quite tricky to attach an object to a bone without it. However, luckily for me, the head has several bones that barely move with respect to one another (I guess only for "facial" animation). So I'm able to derive an estimate of the bone orientation I want. If by any chance, at some point in the future, one dude responsible for finding available functions via Reverse Engineering had some time to look at that and provide us with a getPedBoneMatrix() that would be epic (But don't worry I'm aware there are more important things to work on at the moment).
  12. Kayl

    Element Rotation

    Ok, I have posted the new patch that contains also serverside changes: http://dkrclan.com/qttolua_data/eulerPatchFull.patch It was a bit simpler since serverside peds only use Z and don't have this -Z(set) +Z(get) problem. Here is the serverside test code that goes with it. addCommandHandler("stest", function () local spacing = 20 local x, y, z = -1375.1043701172, -25.0885887146, (14.1484375 + 5) local modes = { "default", "ZXY", "ZYX" } local elementsConf = { [70] = {createPed, 2}, [519] = {createVehicle, 0}, [1681] = {createObject, 0}, } local elements = {} for model, elementConf in pairs(elementsConf) do local createElementFcn, offsetZ = unpack(elementConf) for itMode, mode in ipairs(modes) do local offsetX = (itMode-1)*spacing local element1 = createElementFcn(model, x, y, z) setElementCollisionsEnabled(element1, false) setElementAlpha(element1, 150) local element2 = createElementFcn(model, x, y, z) setElementCollisionsEnabled(element2, false) setElementAlpha(element2, 150) table.insert(elements, {element1, element2, offsetX, offsetZ, mode}) end end local rx, ry, rz = 0, 0, 0 local totalTime = 0 local rotationTime = 5 local oldTick = nil setTimer( function(deltaT) local now = getTickCount() if not oldTick then oldTick = now return end local deltaT = now - oldTick oldTick = now totalTime = totalTime + deltaT if totalTime > 5*rotationTime*1000 then totalTime = 0 rx, ry, rz = 0, 0, 0 elseif totalTime > 4*rotationTime*1000 then rx = rx + 360/rotationTime*deltaT/1000 ry = ry + 360/rotationTime*deltaT/1000 rz = rz + 360/rotationTime*deltaT/1000 elseif totalTime > 3*rotationTime*1000 then rz = rz + 360/rotationTime*deltaT/1000 rx, ry = 0, 0 elseif totalTime > 2*rotationTime*1000 then ry = ry + 360/rotationTime*deltaT/1000 rx, rz = 0, 0 elseif totalTime > 1*rotationTime*1000 then rx = rx + 360/rotationTime*deltaT/1000 ry, rz = 0, 0 end local angles = {rx, ry, rz} for i=1,3 do if angles[i] < 0 then angles[i] = angles[i] + 360 elseif angles[i] >= 360 then angles[i] = angles[i] - 360 end end rx, ry, rz = unpack(angles) local text = string.format("desired %f %f %f ", rx, ry, rz) for _, elementData in ipairs(elements) do local element1, element2, offsetX, offsetZ, rotationMode = unpack(elementData) local erx, ery, erz = getElementRotation(element1, rotationMode) setElementPosition(element1, x - offsetX, y, z + offsetZ) setElementRotation(element1, rx, ry, rz, rotationMode) setElementVelocity(element1, 0, 0, 0) setElementPosition(element2, x - offsetX, y, z + offsetZ) setElementRotation(element2, erx, ery, erz, rotationMode) setElementVelocity(element2, 0, 0, 0) end end , 50, 0) end )
  13. Kayl

    Element Rotation

    Thx to our PM discussion, I was able to compile MTA. Here is a first version of the patch: http://dkrclan.com/qttolua_data/eulerPatch.patch I would have liked to upload it on the bug report but I'm getting access denied. The test code for it: addCommandHandler("test", function () local spacing = 20 local x, y, z = -1375.1043701172, -25.0885887146, (14.1484375 + 5) local modes = { "default", "ZXY", "ZYX" } local elementsConf = { [70] = {createPed, 2}, [519] = {createVehicle, 0}, [1681] = {createObject, 0}, } local elements = {} for model, elementConf in pairs(elementsConf) do local createElementFcn, offsetZ = unpack(elementConf) for itMode, mode in ipairs(modes) do local offsetX = (itMode-1)*spacing local element1 = createElementFcn(model, x, y, z) setElementCollisionsEnabled(element1, false) setElementAlpha(element1, 150) local element2 = createElementFcn(model, x, y, z) setElementCollisionsEnabled(element2, false) setElementAlpha(element2, 150) table.insert(elements, {element1, element2, offsetX, offsetZ, mode}) end end local rx, ry, rz = 0, 0, 0 local totalTime = 0 local rotationTime = 5 addEventHandler("onClientPreRender", getRootElement(), function(deltaT) if not getKeyState("space") then totalTime = totalTime + deltaT if totalTime > 5*rotationTime*1000 then totalTime = 0 rx, ry, rz = 0, 0, 0 elseif totalTime > 4*rotationTime*1000 then rx = rx + 360/rotationTime*deltaT/1000 ry = ry + 360/rotationTime*deltaT/1000 rz = rz + 360/rotationTime*deltaT/1000 elseif totalTime > 3*rotationTime*1000 then rz = rz + 360/rotationTime*deltaT/1000 rx, ry = 0, 0 elseif totalTime > 2*rotationTime*1000 then ry = ry + 360/rotationTime*deltaT/1000 rx, rz = 0, 0 elseif totalTime > 1*rotationTime*1000 then rx = rx + 360/rotationTime*deltaT/1000 ry, rz = 0, 0 end end local angles = {rx, ry, rz} for i=1,3 do if angles[i] < 0 then angles[i] = angles[i] + 360 elseif angles[i] >= 360 then angles[i] = angles[i] - 360 end end rx, ry, rz = unpack(angles) local text = string.format("desired %f %f %f ", rx, ry, rz) for _, elementData in ipairs(elements) do local element1, element2, offsetX, offsetZ, rotationMode = unpack(elementData) local erx, ery, erz = getElementRotation(element1, rotationMode) setElementPosition(element1, x - offsetX, y, z + offsetZ) setElementRotation(element1, rx, ry, rz, rotationMode) setElementVelocity(element1, 0, 0, 0) setElementPosition(element2, x - offsetX, y, z + offsetZ) setElementRotation(element2, erx, ery, erz, rotationMode) setElementVelocity(element2, 0, 0, 0) end local width, height = guiGetScreenSize() local nbLines = #(text:split("\n")) dxDrawRectangle(0, 0, width, 10+nbLines*dxGetFontHeight(1.5, "clear"), tocolor(0, 0, 0, 128)) dxDrawText(text, 0, 0, width, height, tocolor(255, 255, 255, 255), 1.5, "clear", "center", "top") end ) end ) function string.split(str, delim) local startPos = 1 local endPos = string.find(str, delim, 1, true) local result = {} while endPos do table.insert(result, string.sub(str, startPos, endPos-1)) startPos = endPos + 1 endPos = string.find(str, delim, startPos, true) end table.insert(result, string.sub(str, startPos)) return result end setElementRotation and getElementRotation now take an extra optional string parameter that can be "default", "ZXY" or "ZYX" (cf example code) I have only changed the clientside version. Do you want this also on the serverside? If so, can you tell me if I should do the exact thing on the server side or if by any chance some of the files I modified are shared (didn't look like it when compiling).
  14. Kayl

    Element Rotation

    In order not to brake compatibility, an extra parameter to get and set could be used to specify the rotation order. By default, this order would be what it is now depending on the element type. setElementRotation(object, rx, ry, rz) would be same as setElementRotation(object, rx, ry, rz, "ZXY") getElementRotation(object) would be same as getElementRotation(object, "ZXY") same goes for vehicle and ped/player with their respective current rotation order. Like that, old scripts keep working, but at least those desiring to use unified versions could do so by passing the same order to all their set/gets. (Only a subset could be implemented, no need to go through all http://en.wikipedia.org/wiki/Euler_angl ... _rotations) However it's just a thought, because I'm not sure the standard MTA scripter cares that much or knows really what "euler" and "rotation order" mean
  15. Kayl

    Element Rotation

    I know I'm answering to myself, however if I were to continue on the same post it would start to be way too long. So, since yesterday I have figured out what was wrong, or actually, why the code provided worked when it shouldn't have. The "patch" I based my fix on labeled the rotations wrongly. After intensive testing and headache, I can make the following statement with confidence: 'When calling setElementRotation(rx, ry, rz), MTA applies the rotations in the following order : - for objects: ZXY - for vehicles: ZYX - for peds: -Z-Y-X When doing getElementRotation, peds are bugged and return coordinates in Z-Y-X instead of -Z-Y-X (cf video)". I have changed the test case to illustrate several things: - I show the difference between default MTA setElementRotation/getElementRotation and euler based set/get both with ZXY and ZYX meaning - I create 2 instances of each element, to set the rotation of the 2nd of each, I get the rotation of the first and set it to the second (it's used to show if both function work properly). As the video shows, it help me notice that MTA getElementRotation is bugged for peds. - Now the object is also a plane and is placed at the same location/orientation as the vehicle. It helps seeing the differences (which only happen in default MTA functions). The code for the fix, with math details in the comments: Euler conversion functions -- RX(theta) -- | 1 0 0 | -- | 0 c(theta) -s(theta) | -- | 0 s(theta) c(theta) | -- RY(theta) -- | c(theta) 0 s(theta) | -- | 0 1 0 | -- | -s(theta) 0 c(theta) | -- RZ(theta) -- | c(theta) -s(theta) 0 | -- | s(theta) c(theta) 0 | -- | 0 0 1 | -- ZXY = RZ(z).RX(x).RY(y) -- | c(y)*c(z)-s(x)*s(y)*s(z) -c(x)*s(z) s(x)*c(y)*s(z)+s(y)*c(z) | -- | c(y)*s(z)+s(x)*s(y)*c(z) c(x)*c(z) s(y)*s(z)-s(x)*c(y)*c(z) | -- | -c(x)*s(y) s(x) c(x)*c(y) | -- ZYX = RZ(z).RY(y).RX(x) -- | c(y)*c(z) s(x)*s(y)*c(z)-c(x)*s(z) s(x)*s(z)+c(x)*s(y)*c(z) | -- | c(y)*s(z) s(x)*s(y)*s(z)+c(x)*c(z) c(x)*s(y)*s(z)-s(x)*c(z) | -- | -s(y) s(x)*c(y) c(x)*c(y) | function euler_ZXY_to_ZYX(ZXY_x, ZXY_y, ZXY_z) ZXY_x = math.rad(ZXY_x) ZXY_y = math.rad(ZXY_y) ZXY_z = math.rad(ZXY_z) local cx = math.cos(ZXY_x) local sx = math.sin(ZXY_x) local cy = math.cos(ZXY_y) local sy = math.sin(ZXY_y) local cz = math.cos(ZXY_z) local sz = math.sin(ZXY_z) --ZYX (unknown) => A = s(x)*c(y) / c(x)*c(y) = t(x) --ZXY (known) => A = s(x) / c(x)*c(y) local ZYX_x = math.atan2(sx, cx*cy) --ZYX (unknown) => B = c(y)*s(z) / c(y)*c(z) = t(z) --ZXY (known) => B = c(y)*s(z)+s(x)*s(y)*c(z) / c(y)*c(z)-s(x)*s(y)*s(z) local ZYX_z = math.atan2(cy*sz+sx*sy*cz, cy*cz-sx*sy*sz) --ZYX (unknown) => C = -s(y) --ZXY (known) => C = -c(x)*s(y) --Isn't asin not as good as atan2 ? solution tried with atan2 doesn't work that well though local ZYX_y = math.asin(cx*sy) return math.deg(ZYX_x), math.deg(ZYX_y), math.deg(ZYX_z) end function euler_ZYX_to_ZXY(ZYX_x, ZYX_y, ZYX_z) ZYX_x = math.rad(ZYX_x) ZYX_y = math.rad(ZYX_y) ZYX_z = math.rad(ZYX_z) local cx = math.cos(ZYX_x) local sx = math.sin(ZYX_x) local cy = math.cos(ZYX_y) local sy = math.sin(ZYX_y) local cz = math.cos(ZYX_z) local sz = math.sin(ZYX_z) --ZXY (unknown) => A = -c(x)*s(z) / c(x)*c(z) => t(z) = -A --ZYX (known) => A = s(x)*s(y)*c(z)-c(x)*s(z) / s(x)*s(y)*s(z)+c(x)*c(z) local ZXY_z = math.atan2(-(sx*sy*cz-cx*sz), sx*sy*sz+cx*cz) --ZXY (unknown) => B = -c(x)*s(y) / c(x)*c(y) => t(y) = -B --ZYX (known) => B = -s(y) / c(x)*c(y) local ZXY_y = math.atan2(sy, cx*cy) --ZXY (unknown) => C = s(x) --ZYX (known) => C = s(x)*c(y) --Isn't asin not as good as atan2 ? solution tried with atan2 doesn't work that well though local ZXY_x = math.asin(sx*cy) return math.deg(ZXY_x), math.deg(ZXY_y), math.deg(ZXY_z) end New setElementRotation_Euler??? and getElementRotation_Euler??? (both for ZXY and ZYX) function setElementRotation_EulerZXY(element, rx, ry, rz, bZeroOnZisEast) if not element or not isElement(element) then return false end if bZeroOnZisEast then rz = rz - 90 rx, ry = -ry, rx end local mta_rx, mta_ry, mta_rz = rx, ry, rz local eType = getElementType(element) if eType == "ped" or eType == "player" then mta_rx, mta_ry, mta_rz = euler_ZXY_to_ZYX(rx, ry, rz) mta_rx, mta_ry, mta_rz = -mta_rx, -mta_ry, -mta_rz --In set, ped is -Z-Y-X elseif eType == "vehicle" then mta_rx, mta_ry, mta_rz = euler_ZXY_to_ZYX(rx, ry, rz) end return setElementRotation(element, mta_rx, mta_ry, mta_rz) end function setElementRotation_EulerZYX(element, rx, ry, rz, bZeroOnZisEast) if not element or not isElement(element) then return false end if bZeroOnZisEast then rz = rz - 90 rx, ry = -ry, rx end local mta_rx, mta_ry, mta_rz = rx, ry, rz local eType = getElementType(element) if eType == "ped" or eType == "player" then mta_rx, mta_ry, mta_rz = -mta_rx, -mta_ry, -mta_rz --In set, ped is -Z-Y-X elseif eType == "object" then mta_rx, mta_ry, mta_rz = euler_ZYX_to_ZXY(rx, ry, rz) end return setElementRotation(element, mta_rx, mta_ry, mta_rz) end function getElementRotation_EulerZXY(element, bZeroOnZisEast) if not element or not isElement(element) then return false end local rx, ry, rz = getElementRotation(element) local eType = getElementType(element) if eType == "ped" or eType == "player" then rx, ry, rz = -rx, -ry, rz --In get, ped is Z-Y-X rx, ry, rz = euler_ZYX_to_ZXY(rx, ry, rz) elseif eType == "vehicle" then rx, ry, rz = euler_ZYX_to_ZXY(rx, ry, rz) end if bZeroOnZisEast then rz = rz + 90 rx, ry = ry, -rx end return rx, ry, rz end function getElementRotation_EulerZYX(element, bZeroOnZisEast) if not element or not isElement(element) then return false end local rx, ry, rz = getElementRotation(element) local eType = getElementType(element) if eType == "ped" or eType == "player" then rx, ry, rz = -rx, -ry, rz --In get, ped is Z-Y-X elseif eType == "object" then rx, ry, rz = euler_ZXY_to_ZYX(rx, ry, rz) end if bZeroOnZisEast then rz = rz + 90 rx, ry = ry, -rx end return rx, ry, rz end And the updated test case addCommandHandler("test", function () local spacing = 20 local x, y, z = -1375.1043701172, -25.0885887146, (14.1484375 + 5) local modes = { {setElementRotation, getElementRotation}, {setElementRotation_EulerZXY, getElementRotation_EulerZXY}, {setElementRotation_EulerZYX, getElementRotation_EulerZYX} } local elementsConf = { [70] = {createPed, 2}, [519] = {createVehicle, 0}, [1681] = {createObject, 0}, } local elements = {} for model, elementConf in pairs(elementsConf) do local createElementFcn, offsetZ = unpack(elementConf) for itMode, mode in ipairs(modes) do local offsetX = (itMode-1)*spacing local element1 = createElementFcn(model, x, y, z) setElementCollisionsEnabled(element1, false) setElementAlpha(element1, 150) local element2 = createElementFcn(model, x, y, z) setElementCollisionsEnabled(element2, false) setElementAlpha(element2, 150) table.insert(elements, {element1, element2, offsetX, offsetZ, mode}) end end local bZeroOnZIsEast = false local rx, ry, rz = 0, 0, 0 local totalTime = 0 local rotationTime = 5 addEventHandler("onClientPreRender", getRootElement(), function(deltaT) if not getKeyState("space") then totalTime = totalTime + deltaT if totalTime > 5*rotationTime*1000 then totalTime = 0 bZeroOnZIsEast = not bZeroOnZIsEast rx, ry, rz = 0, 0, 0 elseif totalTime > 4*rotationTime*1000 then rx = rx + 360/rotationTime*deltaT/1000 ry = ry + 360/rotationTime*deltaT/1000 rz = rz + 360/rotationTime*deltaT/1000 elseif totalTime > 3*rotationTime*1000 then rz = rz + 360/rotationTime*deltaT/1000 rx, ry = 0, 0 elseif totalTime > 2*rotationTime*1000 then ry = ry + 360/rotationTime*deltaT/1000 rx, rz = 0, 0 elseif totalTime > 1*rotationTime*1000 then rx = rx + 360/rotationTime*deltaT/1000 ry, rz = 0, 0 end end local angles = {rx, ry, rz} for i=1,3 do if angles[i] < 0 then angles[i] = angles[i] + 360 elseif angles[i] >= 360 then angles[i] = angles[i] - 360 end end rx, ry, rz = unpack(angles) local text = nil text = string.format("bZeroOnZIsEast: %s\ndesired %f %f %f ", tostring(bZeroOnZIsEast), rx, ry, rz) for _, elementData in ipairs(elements) do local element1, element2, offsetX, offsetZ, mode = unpack(elementData) local setRotationFcn, getRotationFcn = unpack(mode) local erx, ery, erz = getRotationFcn(element1, bZeroOnZIsEast) setElementPosition(element1, x - offsetX, y, z + offsetZ) setRotationFcn(element1, rx, ry, rz, bZeroOnZIsEast) setElementVelocity(element1, 0, 0, 0) setElementPosition(element2, x - offsetX, y, z + offsetZ) setRotationFcn(element2, erx, ery, erz, bZeroOnZIsEast) setElementVelocity(element2, 0, 0, 0) end local width, height = guiGetScreenSize() local nbLines = #(text:split("\n")) dxDrawRectangle(0, 0, width, 10+nbLines*dxGetFontHeight(1.5, "clear"), tocolor(0, 0, 0, 128)) dxDrawText(text, 0, 0, width, height, tocolor(255, 255, 255, 255), 1.5, "clear", "center", "top") end ) end ) I hope the countless hours I spent figuring out the underlying problem and the real rotation orders will be of some use to some of you.
  16. Hi there, I have filled a bug report regarding the inconsistency of result when calling setElementRotation on different element types (vehicle, ped, object): http://bugs.mtasa.com/view.php?id=5631 An illustrated example can be found below: In the current state, I find it a bit useless to have unified functions like setElementRotation and getElementRotation if semantically the outcome of each is different. Even if a fix was released in any coming nightly, I would still need my script to work for older versions. So, I create this topic not that much to complain about the whole issue, but to seek explanations from people that have experience with it (either from scripting or from within MTA dev team). A reason I see, that could explain the differences observed, would be different rotation sequences when interpreting the Euler angles. When doing getElementRotation and getElementMatrix and then converting the matrix to XYZ euler angles, it seems to work fine for vehicles, so it seems vehicles use XYZ. From a video I found on youtube (http://www.youtube.com/watch?v=MuMImJuoeIQ) it seems objects might use YXZ. Can it be confirmed/explained by some MTA folks? And what is the rotation sequence for peds? --------------------------------------------------------- Edit 15:06 UTC+1 Ok so, looking at the other video with the YXZ patch and its bug report, http://bugs.mtasa.com/view.php?id=4609, I managed to find a workaround. With this workaround, setElementRotation and getElementRotation use unified Euler angle meaning (XYZ that is). So calling any of those on a ped, an object, or a vehicle ends up giving the same result. First of all, video time: Since I was in the process of using fixed functions, I introduced an extra parameter to setElementRotation and getElementRotation which allows the user to use angles that make mathematical sense, hence putting angles so that a rotation of 0 on Z means element facing +X (East). So it's now: setElementRotation(element, rx, ry, rz, bZeroOnZIsEast) getElementRotation(element, bZeroOnZIsEast) The video shows the test sequence in both cases (normal case of 0 = North, and logical case of 0 = East). I didn't try to fix any other type as the 3 illustrated in the video. The fix code (to be put before any of your code using setElementRotation or getElementRotation (for instance in a file declared before the others in meta.xml)): --Adapted from [url=http://bugs.mtasa.com/view.php?id=4609]http://bugs.mtasa.com/view.php?id=4609[/url] function Euler_XYZ_to_YXZ(rx, ry, rz) rx = math.rad(rx) ry = math.rad(ry) rz = math.rad(rz) local sinX = math.sin(rx) local cosX = math.cos(rx) local sinY = math.sin(ry) local cosY = math.cos(ry) local sinZ = math.sin(rz) local cosZ = math.cos(rz) local newRx = math.asin(cosY * sinX) local newRy = math.atan2(sinY, cosX * cosY) local newRz = math.atan2(cosX * sinZ - cosZ * sinX * sinY, cosX * cosZ + sinX * sinY * sinZ) return math.deg(newRx), math.deg(newRy), math.deg(newRz) end -- Adapted and fixed from [url=http://bugs.mtasa.com/view.php?id=4609]http://bugs.mtasa.com/view.php?id=4609[/url] function Euler_YXZ_to_XYZ(rx, ry, rz) rx = math.rad(rx) ry = math.rad(ry) rz = math.rad(rz) local sinX = math.sin(rx) local cosX = math.cos(rx) local sinY = math.sin(ry) local cosY = math.cos(ry) local sinZ = math.sin(rz) local cosZ = math.cos(rz) local newRx = math.atan2(sinX, cosX * cosY) local newRy = math.asin(cosX * sinY) local newRz = math.atan2(cosZ * sinX * sinY + cosY * sinZ, cosY * cosZ - sinX * sinY * sinZ) return math.deg(newRx), math.deg(newRy), math.deg(newRz) end local _setElementRotation = setElementRotation function setElementRotation(element, rx, ry, rz, bZeroOnZIsEast) if not element or not isElement(element) then return false end if bZeroOnZIsEast then rz = rz - 90 rx, ry = -ry, rx end local eType = getElementType(element) if eType == "ped" or eType == "player" then return _setElementRotation(element, -rx, -ry, -rz) elseif eType == "object" then return _setElementRotation(element, Euler_XYZ_to_YXZ(rx, ry, rz)) else return _setElementRotation(element, rx, ry, rz) end end local _getElementRotation = getElementRotation function getElementRotation(element, bZeroOnZIsEast) if not element or not isElement(element) then return false end local eType = getElementType(element) local rx, ry, rz = _getElementRotation(element) if bZeroOnZIsEast then rz = rz + 90 rx, ry = ry, -rx end if eType == "ped" or eType == "player" then rx, ry = -rx, -ry elseif eType == "object" then for i=1,3 do rx, ry, rz = Euler_YXZ_to_XYZ(rx, ry, rz) end end local angles = {rx, ry, rz} for i=1,3 do if angles[i] < 0 then angles[i] = angles[i] + 360 elseif angles[i] >= 360 then angles[i] = angles[i] - 360 end end return unpack(angles) end And the new test code: addCommandHandler("test", function () local x, y, z = -1375.1043701172, -25.0885887146, (14.1484375 + 5) local elements = {} elements[1] = {createPed(0, x, y, z ), 0} elements[2] = {createVehicle(520, x, y, z), 10} elements[3] = {createObject(1632, x, y, z), -10} for i=1,3 do setElementCollisionsEnabled(elements[i][1], false) end local bZeroOnZIsEast = false local rx, ry, rz = 0, 0, 0 local totalTime = 0 local rotationTime = 5 local keyPositions = { {0, 0, 0}, {45, 0, 0}, {-45, 0, 0}, {0, 45, 0}, {0, -45, 0}, {0, 0, 45}, {0, 0, -45} } local currentKey = 1 addEventHandler("onClientPreRender", getRootElement(), function(deltaT) if not getKeyState("space") then totalTime = totalTime + deltaT if currentKey <= #keyPositions and totalTime > rotationTime*1000 then currentKey = currentKey + 1 rx, ry, rz = 0, 0, 0 totalTime = 0 end if currentKey <= #keyPositions then rx, ry, rz = unpack(keyPositions[currentKey]) else if totalTime > 5*rotationTime*1000 then totalTime = 0 bZeroOnZIsEast = not bZeroOnZIsEast currentKey = 1 rx, ry, rz = 0, 0, 0 elseif totalTime > 4*rotationTime*1000 then rx = rx + 360/rotationTime*deltaT/1000 ry = ry + 360/rotationTime*deltaT/1000 rz = rz + 360/rotationTime*deltaT/1000 elseif totalTime > 3*rotationTime*1000 then rz = rz + 360/rotationTime*deltaT/1000 rx, ry = 0, 0 elseif totalTime > 2*rotationTime*1000 then ry = ry + 360/rotationTime*deltaT/1000 rx, rz = 0, 0 elseif totalTime > 1*rotationTime*1000 then rx = rx + 360/rotationTime*deltaT/1000 ry, rz = 0, 0 end end end local angles = {rx, ry, rz} for i=1,3 do if angles[i] < 0 then angles[i] = angles[i] + 360 elseif angles[i] >= 360 then angles[i] = angles[i] - 360 end end rx, ry, rz = unpack(angles) local text = nil text = string.format("bZeroOnZIsEast: %s\ndesired %f %f %f ", tostring(bZeroOnZIsEast), rx, ry, rz) for _, data in ipairs(elements) do local element = data[1] local erx, ery, erz = getElementRotation(element, bZeroOnZIsEast) text = text.."\n"..string.format("%s %f %f %f ", getElementType(element), erx, ery, erz) local deltaX = data[2] local rotMult = data[3] setElementPosition(element, x+deltaX, y, z) setElementRotation(element, rx, ry, rz, bZeroOnZIsEast) setElementVelocity(element, 0, 0, 0) end local width, height = guiGetScreenSize() local nbLines = #(text:split("\n")) dxDrawRectangle(0, 0, width, 10+nbLines*dxGetFontHeight(1.5, "clear"), tocolor(0, 0, 0, 128)) dxDrawText(text, 0, 0, width, height, tocolor(255, 255, 255, 255), 1.5, "clear", "center", "top") end ) end ) Edit: 21:13 UTC+1 the getElementRotation in the case of objects is still not perfect, needs fixing. I'll post fix when I have it -> Indeed, playing with only 2 angles at a time, it turns out in fact objects are XYZ and vehicles are YXZ and peds are -Y-X-Z. Besides, the conversions provided use asin which is not as mathematically as smooth as atan2, so I'll provide clearer functions as soon as I'm sure they work well.
  17. Sorry I didn't visit this forum for a while. Ok I will add quickly: - Text Color for QLabels - Scroll bars (independent from scrollArea) I'll edit this post or post a new one (if there is an answer until then) when it's available. Edit: QtToLua 1.0.6 available. Adds: - Color of QLabels - QScrollBar support Help page updated: http://dkrclan.com/?p=qttolua&large Example resource (MTA 1.1 due to combobox code) updated: http://dkrclan.com/qttolua_data/download/guitest.zip QtToLua 1.0.6: http://dkrclan.com/qttolua_data/download/QtToLua.zip
  18. addEventHandler ( "onResourceStart", getRootElement(), resource_starts ) the "resource_starts" function doesn't exist yet at this point when the addEventHandler is called. Move this whole line below the "end" of the function (resource_starts that is) code.
  19. Version 1.0.5 available: http://dkrclan.com/qttolua_data/download/QtToLua.zip Added support (for MTA 1.1) of comboboxes: guitest resource updated with combobox examples: http://dkrclan.com/qttolua_data/download/guitest.zip Read help page for details: http://dkrclan.com/?p=qttolua&large
  20. It was our host having issues. Don't worry it's back now. If the current download location were to be down for too long, I would provide a mirror indeed.
  21. https://wiki.multitheftauto.com/wiki/Res ... or/Plugins Once you created your objects, they are children of your resource root element, hence calling the "import" exported function of the editor on your root element should make your objects visible/editable in the editor.
  22. He means he played on a server, grabbed the clientside version of a script and would like us to recreate the serverside part in order to recreate (may I dare say steal) the complete feature.
  23. Indeed, col mesh replacement for gta world objects is a bit buggy. How I diagnosed the problem: Since you can't get the bounding box of a gta object (to debug its col mesh), I tried to create a ghost MTA version of the object and display its bounding box to see when the problem occurs. Right after the col replacement, the bbox is fine. If you move away from your ghost/gta original object it's still ok. But when you come back, I guess right at the time the object switches between LOD version and real version, the bbox returns to the original gta state, showing the col mesh has been reset. And indeed even if your gta object is still visually "replaced", it collides as the original. The workaround I have found so far : (requires preparation to get the desired bbox right) + Load & replace txd/dff/col + Create a ghost object at the same position & rotation as the original gta object (get the coords using MEd) (you need to inverse rotation found in MEd). + Ghost should be non collidable & invisible + When a ghost is streamed in, use onClientRender to check its bounding box every frame + When the bounding box suddenly turns out to be wrong (hence the preparation required), reload and re-replace the col mesh (and don't do bbox check for some seconds)
  24. Kayl

    setElementSyncer

    Fair enough that might be a logical reason for it. Thank you for explaining the sync policy with regards to unoccupied vehicles. I have updated the test resource: http://www.megaupload.com/?d=J3PGQD1B Now there is a ped driving the vehicle. I haven't modified it so as to make the ped really use inputs and actually drive. I'm only interested in the actual position/rotation/velocity in order to sync vehicles that don't obey normal GTA driving laws. And I'm saddened to say that this didn't change anything. I'll report this as a bug as you suggested even though I have already 3 tickets on mantis that are fairly ignored so I have doubts about this new request being considered at all.
  25. Kayl

    setElementSyncer

    I know bumping our own topic is not regarded as a good thing. However I have spent time creating a test resource JUST to show the problem I have (or anyone using setElementSyncer would have) and also took some time making a video about it. I would appreciate some feedback from MTA team about the status of the sync of non occupied vehicles.
×
×
  • Create New...