Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 26/03/20 in all areas

  1. Dear MTA community, I have been spending my last 8 weeks on mathematical problems. One of them is the 3D Frustum-Plane intersection that is used by GPUs to draw triangles onto your screen. If you want to learn more about this please consider reading this thread. Promotional Video: https://www.youtube.com/watch?v=RQy3Q4Xe110 Prerequisites This tutorial is aimed at people who are capable of scientific thinking and are willing to playfully learn with Lua code. To execute steps in this tutorial minimal knowledge of Linear Algebra and Lua is required. Required MTA Resource: https://github.com/quiret/mta_lua_3d_math Description of the math Imagine that we have got a frustum and a plane in a 3D room described by coordinates plus their boundaries. By intersecting both you obtain all coordinates on a screen along with their depth values. Now think about how your vision works. You see distant objects smaller than closer ones. You rotate your eyes to angles of vision. If we were to put this concept into terms of math we could say: the plane of vision is bigger in the distance than in close proximity. The frustum is a seamless row of vision planes starting from the pyramid tip to the bottom. How to use the MTA Resource Just download the GitHub repository into a folder of your MTA Resources, name it "math_3d_nonlin" and start it. You can execute the following commands for quick testing: send_bbuf: draws a simple depth test draw_model: draws the DFF file "gfriend.dff" Now we have got the basics out of the way. Time to start coding. Please create a new "_math_test.Lua" script file in the resource and include it server-side at the bottom of meta.xml. Tutorial: software rendering a plane on screen Open your _math_test.Lua and include the following code: local viewFrustum = createViewFrustum( createVector(0, 0, 0), -- position createVector(10, 0, 0), -- right createVector(0, 0, 10), -- up createVector(0, 20, 0) -- front ); local plane = createPlane( createVector(-3, 10, -3), createVector(6, 0, 0), createVector(0, 0, 6) ); local function task_draw_scene(thread) local bbuf = create_backbuffer(640, 480, 255, 255, 0, 50); local dbuf = createDepthBuffer(640, 480, 1); local time_start = getTickCount(); do local gotToDraw, numDrawn, numSkipped = draw_plane_on_bbuf(viewFrustum, bbuf, dbuf, plane, true); if ( gotToDraw ) then outputDebugString( "drawn " .. numDrawn .. " pixels (skipped " .. numSkipped .. ")" ); end end local time_end = getTickCount(); local ms_diff = ( time_end - time_start ); outputDebugString( "render time: " .. ms_diff .. "ms" ); taskUpdate( 1, "creating backbuffer color composition string" ); local bbuf_width_ushort = num_to_ushort_bytes( bbuf.width ); local bbuf_height_ushort = num_to_ushort_bytes( bbuf.height ); local pixels_str = table.concat(bbuf.items); local bbuf_string = pixels_str .. ( bbuf_width_ushort .. bbuf_height_ushort ); taskUpdate( false, "sending backbuffer to clients (render time: " .. ms_diff .. "ms)" ); local players = getElementsByType("player"); for m,n in ipairs(players) do triggerClientEvent(n, "onServerTransmitImage", root, bbuf_string); end outputDebugString("sent backbuffer to clients"); end addCommandHandler( "testdraw", function(player) spawnTask(task_draw_scene); end ); Result: Try executing the "testdraw" command. At the top of file you see the definition of our frustum cone as well as a plane. By calling the function "draw_plane_on_bbuf" we put color information into bbuf for exactly the pixels that make up the rectangle. If you change the plane definition to... local plane = createPlane( createVector(-2, 10, -4), createVector(6, 0, 3), createVector(-2, 0, 6) ); you instead get this image: Try changing around the coordinates of frustum and plane to obtain different pictures! Tutorial: software rendering a triangle on screen Take the same code as in the tutorial above but change line 19 to: local gotToDraw, numDrawn, numSkipped = draw_plane_on_bbuf(viewFrustum, bbuf, dbuf, plane, true, "tri"); This way we have changed the primitive type to triangle (rectangle is the default). Try executing the "testdraw" command again to inspect the new result! Tutorial: drawing a DFF file onto screen Instead of writing triangle definitions by hand we can take them from a DFF file instead. DFF files are storage of triangle and vertex information along with 3D rotation and translation information. By extacting the triangles from the DFF file we can put them into our algorithm to software-render them! Here is a related excerpt from math_server.Lua: local modelToDraw = false; do local modelFile = fileOpen("gfriend.dff"); if (modelFile) then modelToDraw = rwReadClump(modelFile); fileClose(modelFile); end end local function task_draw_model(thread) local bbuf = create_backbuffer(640, 480, 255, 255, 0, 50); local dbuf = createDepthBuffer(640, 480, 1); local time_start = getTickCount(); local num_triangles_drawn = 0; if (modelToDraw) then -- Setup the camera. local geom = modelToDraw.geomlist[1]; local mt = geom.morphTargets[1]; local centerSphere = mt.sphere; local camPos = viewFrustum.getPos(); camPos.setX(centerSphere.x); camPos.setY(centerSphere.y - 3.8); camPos.setZ(centerSphere.z); local camFront = viewFrustum.getFront(); camFront.setX(0); camFront.setY(5 + centerSphere.r * 2); camFront.setZ(0); local camRight = viewFrustum.getRight(); camRight.setX(centerSphere.r * 2); camRight.setY(0); camRight.getZ(0); local camUp = viewFrustum.getUp(); camUp.setX(0); camUp.setY(0); camUp.setZ(centerSphere.r * 2); local triPlane = createPlane( createVector(0, 0, 0), createVector(0, 0, 0), createVector(0, 0, 0) ); local vertices = modelToDraw.geomlist[1].morphTargets[1].vertices; local triangles = modelToDraw.geomlist[1].triangles; local tpos = triPlane.getPos(); local tu = triPlane.getU(); local tv = triPlane.getV(); for m,n in ipairs(triangles) do taskUpdate( m / #triangles, "drawing triangle #" .. m ); local vert1 = vertices[n.vertex1 + 1]; local vert2 = vertices[n.vertex2 + 1]; local vert3 = vertices[n.vertex3 + 1]; tpos.setX(vert1.x); tpos.setY(vert1.y); tpos.setZ(vert1.z); tu.setX(vert2.x - vert1.x); tu.setY(vert2.y - vert1.y); tu.setZ(vert2.z - vert1.z); tv.setX(vert3.x - vert1.x); tv.setY(vert3.y - vert1.y); tv.setZ(vert3.z - vert1.z); local gotToDraw, numDrawn, numSkipped = draw_plane_on_bbuf(viewFrustum, bbuf, dbuf, triPlane, false, "tri"); if (gotToDraw) and (numDrawn >= 1) then num_triangles_drawn = num_triangles_drawn + 1; end end end local time_end = getTickCount(); local ms_diff = ( time_end - time_start ); (...) end The code first loads a DFF file called "gfriend.dff" and stores it inside the "modelToDraw" variable. Once you execute the "draw_model" command the code looks up the first geometry in the DFF file and fetches all triangles associated with it. The rendering camera is set up to point at the middle of the model. Then all triangles are drawn one-by-one. https://twitter.com/rplgn/status/1230650912345067520 Try swapping the DFF file for another one, like biker.dff, and examine the results! Maybe extract a different DFF file from GTA:SA and replace gfriend.dff with that one. External references: math calculation on paper example: https://imgur.com/gallery/rLvln3X German thread on mta-sa.org: https://www.mta-sa.org/thread/38693-3d-frustum-ebene-schneidung-in-Lua/ Do you have any questions related to the math or the implementation? Do not shy away from asking! I want to provide you with as much insight as I can.
    1 point
  2. Em vez de você utilizar Command Handlers para as funções, pode usar Event Handlers. Os eventos que podem ser úteis no seu caso, é: onPlayerLogin e onPlayerQuit
    1 point
  3. Caused by a corrupt custom car model Ask the server owner to check all custom car models.
    1 point
  4. Easy mistake. You're applying the wanted level to the wrong element (to the account instead of the player) Line 13 should be setTimer (setPlayerWantedLevel,500,1,source,wantedLevel)
    1 point
  5. Some tutorial: https://www.youtube.com/watch?v=0S0k9ny3d4M (Check the whole channel) https://forum.multitheftauto.com/topic/121619-Lua-for-absolute-beginners https://forum.multitheftauto.com/topic/95654-tut-debugging/ https://forum.multitheftauto.com/topic/114541-tut-events/
    1 point
  6. Hi! You need to use dbConnect to connect databases. (both MySQL / SQLite) For the GUI, you need: guiCreateWindow - background window guiCreateLabel - texts guiCreateEdit - inputs guiCreateButton - buttons guiGetText - get input's text onClientGUIClick - detect when client push to button (event) triggerServerEvent - send datas to server side You can use default login/register functions addAccount - add new account (register) getAccount - get the account from username and password logIn - login player the the account Or do your own account system, with database.
    1 point
  7. Since there is no serverside physics simulation you really should do the hit detection on the clientside. You have to take physics depending on player framerate into account which is impossible to do on the server. Thus the client has to trigger a server event to tell the server about a projectile hit. I hope you see that anything involving game physics is doomed from a security point of view. But that is why we have anti-cheat detection systems built into the MTA system so do not worry. ?
    1 point
  8. Hello redditing, please look at my discussion about general inventory system design with iwalidza: It does cover the creation of any inventory system and does give recommendations for functions you should use.
    1 point
  9. Fiz algo básico para você, quando o veiculo for danificado, e quando estiver com life abaixo de 255.5, será redefinido o life do veiculo, e o motor desligará. addEventHandler("onVehicleDamage", getRootElement(), function ( ) --/> Evento Para Quando o Veiculo for Danificado. if isElement(source) and getElementType(source) == "vehicle" and getElementHealth(source) <= 255.5 then setElementHealth(source, 255.5) --/> Setará a LIFE do Veiculo, Para não explodir. setVehicleEngineState(source, false) --/> Desligará o Motor. end end) --/> OBS : Fiz por evento quando da dano ao veiculo, mas, você pode fazer, disparando um timer. --/> Próximo Evento, Para Quando o Jogador Entrar no Veiculo, o Veiculo Desligar caso, a life do veiculo for igual ou abaixo de 255.5. addEventHandler ( "onPlayerVehicleEnter", getRootElement(), function ( veiculo, seat ) if seat == 0 and getElementHealth(veiculo) <= 255.5 then --/> Ao entrar P1, e se o Veiculo tiver com LIFE igual ou abaixo de 255.5, então : setVehicleEngineState(veiculo, false) --/> Desligar o Motor. end end)
    1 point
  10. Hello, I present to you a simple monitoring script for your server written in Python 3. This script will be useful for your site, for example, if you are developing it using Django / AIOHTTP / Flask or for other purposes. This script provides simple server information: game (mta) port - server main port (UDP) ase_port - server All Seeing Eye port (main MTA:SA port + 123) name - server name gamemode - server mode map - server map version - mta:sa server version players - number of players on the server right now maxplayers - the maximum number of players that can join Usage: from mta.monitoring import Server # pass server address and port s = Server('46.243.253.51', 22003) # get current server online and max players print('{}/{}'.format(s.players, s.maxplayers)) Download & Source code: github
    1 point
  11. شكرا ولله انك ما قصرت
    1 point
  12. Dear Hazardinho, here is an extended (and bugfixed, sorry about that!) version that supports getting screen coordinates as well as the border coordinates in one function. local function get_screen_coordinates(wx, wy, wz) local camMatArray = getElementMatrix(getCamera()); local camMat_right = camMatArray[1]; local camMat_forward = camMatArray[2]; local camMat_up = camMatArray[3]; local camMat_pos = camMatArray[4]; local camMat = Matrix(); local sW, sH = guiGetScreenSize(); local s_ratio = sH / sW; camMat:setForward(Vector3(camMat_forward[1], camMat_forward[2], camMat_forward[3])); camMat:setRight(Vector3(camMat_right[1], camMat_right[2], camMat_right[3])); camMat:setUp(Vector3(camMat_up[1] * s_ratio, camMat_up[2] * s_ratio, camMat_up[3] * s_ratio)); camMat:setPosition(Vector3(camMat_pos[1], camMat_pos[2], camMat_pos[3])); local invCamMat = camMat:inverse(); local invVec = invCamMat:transformPosition(wx, wy, wz); local function to_real_coord(val) return ( val / 2 ) + 1/2; end local ratWidth, depthDist, ratHeight = invVec.x, invVec.y, invVec.z; if (depthDist > 0) then ratWidth = ratWidth / depthDist; ratHeight = ratHeight / depthDist; if (math.abs(ratWidth) <= 1) and (math.abs(ratHeight) <= 1) then return to_real_coord(ratWidth), to_real_coord(-ratHeight), true; end end if (ratWidth == 0) and (ratHeight == 0) then return 1/2, 1/2; elseif (ratWidth == 0) then return 1/2, to_real_coord(1 / ratHeight); elseif (ratHeight == 0) then return to_real_coord(1 / ratWidth), 1/2; end local dist_to_width = math.abs(1 / ratWidth); local dist_to_height = math.abs(1 / ratHeight); local scale_dist = math.min(dist_to_width, dist_to_height); ratWidth = ratWidth * scale_dist; ratHeight = ratHeight * scale_dist; return to_real_coord(ratWidth), to_real_coord(-ratHeight), false; end addEventHandler("onClientRender", root, function() local wx, wy, wz = 0, 0, 0; local screenRelX, screenRelY, isOnScreen = get_screen_coordinates(wx, wy, wz); dxDrawText( "relX: " .. screenRelX .. ", relY: " .. screenRelY, 100, 300 ); dxDrawText( "is on screen: " .. tostring(isOnScreen), 100, 320 ); local screenWidth, screenHeight = guiGetScreenSize(); local screenX, screenY = screenRelX * screenWidth, screenRelY * screenHeight; dxDrawRectangle( screenX - 25, screenY - 25, 50, 50, 0xFFFFFFFF ); end ); In order to detect if an object is on the screen, simply use the third return value.
    1 point
  13. U still here? Lol. Hi man. I'm The Kid Have you checked IDE List?
    1 point
  14. 0 points
×
×
  • Create New...