Skip to content

Commit 29cf87b

Browse files
committed
Added bone_attach, bone mappings, handle invalid objects in CreateObject, PlayAudioStreamForPlayer, StopAudioStreamForPlayer, general fixes for TogglePlayerSpectating, added SetPlayerAttachedObject, RemovePlayerAttachedObject, AttachCameraToObject.
1 parent f4a588c commit 29cf87b

File tree

9 files changed

+509
-14
lines changed

9 files changed

+509
-14
lines changed

amx/client/bone_attach_c.lua

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
function sendReadyMessage()
2+
triggerServerEvent("boneAttach_requestAttachmentData",root)
3+
end
4+
addEventHandler("onClientResourceStart",resourceRoot,sendReadyMessage)
5+
6+
function getAttachmentData(ped,bone,x,y,z,rx,ry,rz)
7+
for element,att_ped in pairs(ped) do
8+
setElementCollisionsEnabled(element,false)
9+
attached_ped[element] = att_ped
10+
attached_bone[element] = bone[element]
11+
attached_x[element] = x[element]
12+
attached_y[element] = y[element]
13+
attached_z[element] = z[element]
14+
attached_rx[element] = rx[element]
15+
attached_ry[element] = ry[element]
16+
attached_rz[element] = rz[element]
17+
end
18+
end
19+
addEvent("boneAttach_sendAttachmentData",true)
20+
addEventHandler("boneAttach_sendAttachmentData",root,getAttachmentData)
21+
22+
function initAttach()
23+
addEvent("boneAttach_attach",true)
24+
addEvent("boneAttach_detach",true)
25+
addEventHandler("boneAttach_attach",root,attachElementToBone)
26+
addEventHandler("boneAttach_detach",root,detachElementFromBone)
27+
end
28+
addEventHandler("onClientResourceStart",resourceRoot,initAttach)
29+
30+
bone_0,bone_t,bone_f = {},{},{}
31+
bone_0[1],bone_t[1],bone_f[1] = 5,nil,6 --head
32+
bone_0[2],bone_t[2],bone_f[2] = 4,5,8 --neck
33+
bone_0[3],bone_t[3],bone_f[3] = 3,nil,31 --spine
34+
bone_0[4],bone_t[4],bone_f[4] = 1,2,3 --pelvis
35+
bone_0[5],bone_t[5],bone_f[5] = 4,32,5 --left clavicle
36+
bone_0[6],bone_t[6],bone_f[6] = 4,22,5 --right clavicle
37+
bone_0[7],bone_t[7],bone_f[7] = 32,33,34 --left shoulder
38+
bone_0[8],bone_t[8],bone_f[8] = 22,23,24 --right shoulder
39+
bone_0[9],bone_t[9],bone_f[9] = 33,34,32 --left elbow
40+
bone_0[10],bone_t[10],bone_f[10] = 23,24,22 --right elbow
41+
bone_0[11],bone_t[11],bone_f[11] = 34,35,36 --left hand
42+
bone_0[12],bone_t[12],bone_f[12] = 24,25,26 --right hand
43+
bone_0[13],bone_t[13],bone_f[13] = 41,42,43 --left hip
44+
bone_0[14],bone_t[14],bone_f[14] = 51,52,53 --right hip
45+
bone_0[15],bone_t[15],bone_f[15] = 42,43,44 --left knee
46+
bone_0[16],bone_t[16],bone_f[16] = 52,53,54 --right knee
47+
bone_0[17],bone_t[17],bone_f[17] = 43,42,44 --left ankle
48+
bone_0[18],bone_t[18],bone_f[18] = 53,52,54 --right angle
49+
bone_0[19],bone_t[19],bone_f[19] = 44,43,42 --left foot
50+
bone_0[20],bone_t[20],bone_f[20] = 54,53,52 --right foot
51+
52+
function putAttachedElementsOnBones()
53+
for element,ped in pairs(attached_ped) do
54+
if not isElement(element) then
55+
clearAttachmentData(element)
56+
elseif isElementStreamedIn(ped) then
57+
local bone = attached_bone[element]
58+
local x,y,z = getPedBonePosition(ped,bone_0[bone])
59+
local xx,xy,xz,yx,yy,yz,zx,zy,zz = getBoneMatrix(ped,bone)
60+
local offx,offy,offz = attached_x[element],attached_y[element],attached_z[element]
61+
local offrx,offry,offrz = attached_rx[element],attached_ry[element],attached_rz[element]
62+
local objx = x+offx*xx+offy*yx+offz*zx
63+
local objy = y+offx*xy+offy*yy+offz*zy
64+
local objz = z+offx*xz+offy*yz+offz*zz
65+
local rxx,rxy,rxz,ryx,ryy,ryz,rzx,rzy,rzz = getMatrixFromEulerAngles(offrx,offry,offrz)
66+
67+
local txx = rxx*xx+rxy*yx+rxz*zx
68+
local txy = rxx*xy+rxy*yy+rxz*zy
69+
local txz = rxx*xz+rxy*yz+rxz*zz
70+
local tyx = ryx*xx+ryy*yx+ryz*zx
71+
local tyy = ryx*xy+ryy*yy+ryz*zy
72+
local tyz = ryx*xz+ryy*yz+ryz*zz
73+
local tzx = rzx*xx+rzy*yx+rzz*zx
74+
local tzy = rzx*xy+rzy*yy+rzz*zy
75+
local tzz = rzx*xz+rzy*yz+rzz*zz
76+
offrx,offry,offrz = getEulerAnglesFromMatrix(txx,txy,txz,tyx,tyy,tyz,tzx,tzy,tzz)
77+
if (string.find(objx..objy..objz, "a")) then
78+
setElementPosition(element, x, y, z)
79+
else
80+
setElementPosition(element, objx, objy, objz)
81+
end
82+
if (not string.find(offrx..offry..offrz, "a")) then
83+
setElementRotation(element, offrx, offry, offrz, "ZXY")
84+
else
85+
setElementPosition(element,getElementPosition(ped))
86+
end
87+
end
88+
end
89+
end
90+
addEventHandler("onClientPreRender",root,putAttachedElementsOnBones)

amx/client/bone_pos_rot.lua

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
sx,sy,sz = 0,0,3
2+
tx,ty,tz = 0,0,4
3+
fx,fy,fz = 0,1,3
4+
5+
function getMatrixFromPoints(x,y,z,x3,y3,z3,x2,y2,z2)
6+
x3 = x3-x
7+
y3 = y3-y
8+
z3 = z3-z
9+
x2 = x2-x
10+
y2 = y2-y
11+
z2 = z2-z
12+
local x1 = y2*z3-z2*y3
13+
local y1 = z2*x3-x2*z3
14+
local z1 = x2*y3-y2*x3
15+
x2 = y3*z1-z3*y1
16+
y2 = z3*x1-x3*z1
17+
z2 = x3*y1-y3*x1
18+
local len1 = 1/math.sqrt(x1*x1+y1*y1+z1*z1)
19+
local len2 = 1/math.sqrt(x2*x2+y2*y2+z2*z2)
20+
local len3 = 1/math.sqrt(x3*x3+y3*y3+z3*z3)
21+
x1 = x1*len1 y1 = y1*len1 z1 = z1*len1
22+
x2 = x2*len2 y2 = y2*len2 z2 = z2*len2
23+
x3 = x3*len3 y3 = y3*len3 z3 = z3*len3
24+
return x1,y1,z1,x2,y2,z2,x3,y3,z3
25+
end
26+
27+
function getEulerAnglesFromMatrix(x1,y1,z1,x2,y2,z2,x3,y3,z3)
28+
local nz1,nz2,nz3
29+
nz3 = math.sqrt(x2*x2+y2*y2)
30+
nz1 = -x2*z2/nz3
31+
nz2 = -y2*z2/nz3
32+
local vx = nz1*x1+nz2*y1+nz3*z1
33+
local vz = nz1*x3+nz2*y3+nz3*z3
34+
return math.deg(math.asin(z2)),-math.deg(math.atan2(vx,vz)),-math.deg(math.atan2(x2,y2))
35+
end
36+
37+
function getMatrixFromEulerAngles(x,y,z)
38+
x,y,z = math.rad(x),math.rad(y),math.rad(z)
39+
local sinx,cosx,siny,cosy,sinz,cosz = math.sin(x),math.cos(x),math.sin(y),math.cos(y),math.sin(z),math.cos(z)
40+
return
41+
cosy*cosz-siny*sinx*sinz,cosy*sinz+siny*sinx*cosz,-siny*cosx,
42+
-cosx*sinz,cosx*cosz,sinx,
43+
siny*cosz+cosy*sinx*sinz,siny*sinz-cosy*sinx*cosz,cosy*cosx
44+
end
45+
46+
if not script_serverside then
47+
function getBoneMatrix(ped,bone)
48+
local x,y,z,tx,ty,tz,fx,fy,fz
49+
x,y,z = getPedBonePosition(ped,bone_0[bone])
50+
if bone == 1 then
51+
local x6,y6,z6 = getPedBonePosition(ped,6)
52+
local x7,y7,z7 = getPedBonePosition(ped,7)
53+
tx,ty,tz = (x6+x7)*0.5,(y6+y7)*0.5,(z6+z7)*0.5
54+
elseif bone == 3 then
55+
local x21,y21,z21 = getPedBonePosition(ped,21)
56+
local x31,y31,z31 = getPedBonePosition(ped,31)
57+
tx,ty,tz = (x21+x31)*0.5,(y21+y31)*0.5,(z21+z31)*0.5
58+
else
59+
tx,ty,tz = getPedBonePosition(ped,bone_t[bone])
60+
end
61+
fx,fy,fz = getPedBonePosition(ped,bone_f[bone])
62+
local xx,xy,xz,yx,yy,yz,zx,zy,zz = getMatrixFromPoints(x,y,z,tx,ty,tz,fx,fy,fz)
63+
if bone == 1 or bone == 3 then xx,xy,xz,yx,yy,yz = -yx,-yy,-yz,xx,xy,xz end
64+
return xx,xy,xz,yx,yy,yz,zx,zy,zz
65+
end
66+
end

amx/client/client.lua

Lines changed: 116 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -262,15 +262,96 @@ function showIntroScene()
262262
end
263263

264264
-----------------------------
265+
-- Camera related
266+
function removeCamHandlers()
267+
removeInterpCamHandler()
268+
removeCamAttachHandler()
269+
end
270+
271+
-- Camera attachments
272+
--Based on https://forum.mtasa.com/topic/36692-move-camera-by-mouse-like-normal/?do=findComment&comment=368670
273+
local ca = {}
274+
ca.active = 0
275+
ca.objCamPos = nil
276+
ca.dist = 0.025
277+
ca.speed = 5
278+
ca.x = math.rad(60)
279+
ca.y = math.rad(60)
280+
ca.z = math.rad(15)
281+
ca.maxZ = math.rad(89)
282+
ca.minZ = math.rad(-45)
283+
284+
function removeCamAttachHandler()
285+
outputConsole('removeCamAttachHandler was called')
286+
if(ca.active == 1) then
287+
outputConsole('Destroying cam attach handler...')
288+
ca.active = 0
289+
end
290+
end
291+
292+
function camAttachRender()
293+
if (ca.active == 1) then
294+
local x1,y1,z1 = 0.0, 0.0, 0.0
295+
if ca.objCamPos ~= nil then
296+
x1,y1,z1 = getElementPosition(ca.objCamPos)
297+
end
298+
local camDist = ca.dist
299+
local cosZ = math.cos(ca.z)
300+
local camX = x1 + math.cos(ca.x)*camDist*cosZ
301+
local camY = y1 + math.sin(ca.y)*camDist*cosZ
302+
local camZ = z1 + math.sin(ca.z)*camDist
303+
setCameraMatrix(camX, camY, camZ, x1, y1, z1)
304+
305+
--If aiming, set the target (does nothing, todo fix)
306+
if getPedTask(localPlayer, "secondary", 0) == "TASK_SIMPLE_USE_GUN" or isPedDoingGangDriveby(localPlayer) then
307+
setPedAimTarget ( localPlayer, camX, camY, camZ )
308+
setPlayerHudComponentVisible ( localPlayer, "crosshair", true )
309+
outputConsole('ped is aiming')
310+
end
311+
312+
--outputConsole(string.format("camAttachRender - Camera Matrix is: CamPos: %f %f %f CamLookAt: %f %f %f", camX, camY, camZ, x1,y1,z1))
313+
else
314+
removeEventHandler("onClientPreRender", root, camAttachRender)
315+
end
316+
end
317+
318+
function cursorMouseMoveHandler(curX, curY, absX, absY)
319+
if (ca.active == 1) then
320+
local diffX = curX - 0.5
321+
local diffY = curY - 0.5
322+
local camX = ca.x - diffX*ca.speed
323+
local camY = ca.y - diffX*ca.speed
324+
local camZ = ca.z + (diffY*ca.speed)/math.pi
325+
if(camZ > ca.maxZ) then
326+
camZ = ca.maxZ
327+
end
328+
if(camZ < ca.minZ) then
329+
camZ = ca.minZ
330+
end
331+
ca.x = camX
332+
ca.y = camY
333+
ca.z = camZ
334+
else
335+
removeEventHandler("onClientCursorMove", root, cursorMouseMoveHandler)
336+
end
337+
end
338+
339+
function AttachCameraToObject(camObj)
340+
outputConsole('AttachCameraToObject was called')
341+
ca.active = 1
342+
ca.objCamPos = camObj
343+
addEventHandler("onClientPreRender", root, camAttachRender)
344+
addEventHandler("onClientCursorMove", root, cursorMouseMoveHandler)
345+
end
346+
265347
-- Camera Interpolation
266348
--Originally from https://wiki.multitheftauto.com/wiki/SmoothMoveCamera
267-
268349
local sm = {}
269350
sm.moov = 0
270351
sm.objCamPos,sm.objLookAt = nil,nil
271352

272-
function removeCamHandler()
273-
outputConsole('removeCamHandler was called')
353+
function removeInterpCamHandler()
354+
outputConsole('removeInterpCamHandler was called')
274355
if(sm.moov == 1) then
275356
outputConsole('Destroying cam handler...')
276357
sm.moov = 0
@@ -300,7 +381,7 @@ function setupCameraObject(camObj, FromX, FromY, FromZ, ToX, ToY, ToZ, time, cut
300381
setElementAlpha(camObj, 0)
301382
setObjectScale(camObj, 0.01)
302383
moveObject(camObj, time, ToX, ToY, ToZ, ToX, ToY, ToZ, "InOutQuad")
303-
setTimer(removeCamHandler,time,1)
384+
setTimer(removeInterpCamHandler,time,1)
304385
setTimer(destroyElement,time,1,camObj)
305386
return camObj
306387
end
@@ -320,7 +401,14 @@ end
320401
-----------------------------
321402
-- Player objects
322403
function RemoveBuildingForPlayer(model, x, y, z, radius)
404+
if model == -1 then
405+
for i=550,20000 do --Remove all world models if they sent -1
406+
removeWorldModel(i,20000,0,0,0)
407+
end
408+
return true --Don't run the rest of the code
409+
end
323410
removeWorldModel(model, radius, x, y, z)
411+
return true
324412
end
325413

326414
function AttachPlayerObjectToPlayer(amxName, objID, attachPlayer, offsetX, offsetY, offsetZ, rX, rY, rZ)
@@ -377,7 +465,30 @@ function StopPlayerObject(amxName, objID)
377465
stopObject(obj)
378466
end
379467

380-
468+
--- Audio
469+
local pAudioStreamSound = nil --samp can only do one stream at a time anyway
470+
function PlayAudioStreamForPlayer(url, posX, posY, posZ, distance, usepos)
471+
--outputConsole(string.format("PlayAudioStreamForPlayer called with args %s %f %f %f %f %d", url, posX, posY, posZ, distance, usepos))
472+
if pAudioStreamSound ~= nil then --If there's one already playing, stop it
473+
--outputConsole("PlayAudioStreamForPlayer is stopping an audio stream")
474+
StopAudioStreamForPlayer()
475+
end
476+
if usepos == nil or usepos == 0 then
477+
--outputConsole(string.format("PlayAudioStreamForPlayer now playing non-3d sound %s", url))
478+
pAudioStreamSound = playSound(url)
479+
else
480+
--outputConsole(string.format("PlayAudioStreamForPlayer now playing 3d sound %s with max dist %d", url, distance))
481+
pAudioStreamSound = playSound3D(url, posX, posY, posZ)
482+
setSoundMaxDistance(pAudioStreamSound, distance)
483+
end
484+
if pAudioStreamSound ~= nil then
485+
setSoundVolume(pAudioStreamSound, 1.0)
486+
end
487+
return true
488+
end
489+
function StopAudioStreamForPlayer()
490+
stopSound(pAudioStreamSound)
491+
end
381492
-----------------------------
382493
-- Checkpoints
383494

amx/meta.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,17 @@
1818
<script src="client/bars.lua" type="client" />
1919
<script src="client/garages.lua" type="client" />
2020

21+
<!--
22+
Bone_attach: Credit to Devan_LT (also known as CrystalMV)
23+
https://forum.mtasa.com/profile/1985-crystalmv/
24+
https://wiki.multitheftauto.com/wiki/Resource:Bone_attach
25+
-->
26+
<script src="shared/bone_attach.lua" />
27+
<script src="client/bone_attach_c.lua" type="client" />
28+
<script src="shared/attach_func.lua" />
29+
<script src="shared/attach_func.lua" type="client" />
30+
<script src="client/bone_pos_rot.lua" type="client" />
31+
2132
<file src="client/logo_small.png" />
2233
<file src="client/closebtn.png" />
2334
<file src="client/closebtn_hover.png" />

amx/server/defines.lua

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,34 @@ g_PoliceVehicles = {
135135
[601] = true
136136
}
137137

138+
--Left is SAMP, right is MTA
139+
g_BoneMapping = setmetatable({
140+
[2] = 1, -- Head
141+
[17] = 2, -- Neck
142+
[1] = 3, -- Spine
143+
[15] = 5, -- Left Clavicle (Shoulder)
144+
[16] = 6, -- Right Clavicle (Shoulder)
145+
[3] = 9, -- Left Upper Arm
146+
[4] = 10, -- Right Upper Arm
147+
[5] = 11, -- Left Hand
148+
[6] = 12, -- Right Hand
149+
[7] = 13, -- Left thigh (Samp doesn't really have hips)
150+
[8] = 14, -- Right thigh
151+
[12] = 15, -- Left calf
152+
[11] = 16, -- Right Calf
153+
[9] = 19, -- Left Foot
154+
[10] = 20 -- Right Foot
155+
}, {
156+
__index = function(t, k)
157+
if k == 18 then --Since 18 is jaw in SAMP
158+
k = 2 --Default to head
159+
end
160+
if k >= 1 and k <= 17 then
161+
return k
162+
end
163+
end
164+
})
165+
138166
PLAYER_STATE_NONE = 0
139167
PLAYER_STATE_ONFOOT = 1
140168
PLAYER_STATE_DRIVER = 2
@@ -172,5 +200,6 @@ PLAYER_VARTYPE_STRING = 2
172200
PLAYER_VARTYPE_FLOAT = 3
173201

174202
INVALID_ACTOR_ID = 0xFFFF
203+
INVALID_OBJECT_ID = 0xFFFF
175204

176205
ManualVehEngineAndLights = false

amx/server/events.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ function gameModeInit(player)
2525
g_Players[playerID].streamedActors = {}
2626
g_Players[playerID].streamedVehicles = {}
2727
g_Players[playerID].streamedPlayers = {}
28+
g_Players[playerID].attachedObjects = {}
2829
if g_PlayerClasses[0] then
2930
g_Players[playerID].viewingintro = true
3031
fadeCamera(player, true)

0 commit comments

Comments
 (0)