Skip to content

Attach events & rotation fix #3353

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 26 commits into from
Jul 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
d358a4a
Events for server-side
Nico8340 Mar 30, 2024
91ad6d1
Events for client-side
Nico8340 Mar 30, 2024
c5d9a9c
Modify returns
Nico8340 Apr 3, 2024
463a385
Modify BitStream version
Nico8340 Apr 3, 2024
1daa79e
Merge branch 'master' into attach
Nico8340 Apr 3, 2024
1b85d92
Format & early returns
Nico8340 Apr 3, 2024
1a562d3
Merge branch 'attach' of https://github.com/Nico8340/mtasa-blue into …
Nico8340 Apr 3, 2024
0a94a1b
Merge branch 'master' into attach
Dutchman101 Apr 5, 2024
842dbdd
Merge branch 'master' into attach
Nico8340 Jun 1, 2024
75e6439
Merge branch 'master' into attach
Nico8340 Jun 2, 2024
3895d00
Merge branch 'master' into attach
Nico8340 Jun 5, 2024
2fddd18
Merge branch 'multitheftauto:master' into attach
Nico8340 Jun 6, 2024
4047184
Merge branch 'master' into attach
Nico8340 Jul 15, 2024
95280d6
Merge branch 'master' into attach
Nico8340 Aug 20, 2024
307d6ca
Merge branch 'master' into attach
Nico8340 Nov 21, 2024
26496f2
Merge branch 'master' into attach
Nico8340 Jan 6, 2025
cfdede2
Merge branch 'multitheftauto:master' into attach
Nico8340 Jan 16, 2025
0936201
Merge branch 'master' into attach
Nico8340 Feb 9, 2025
e5c06fd
Merge branch 'master' into attach
Nico8340 May 6, 2025
e254ad9
Merge branch 'master' into attach
Nico8340 May 8, 2025
e3c84aa
Merge branch 'master' into attach
Nico8340 May 31, 2025
09d6d3c
Merge branch 'master' into attach
Nico8340 Jun 4, 2025
f166f04
Merge branch 'master' into attach
Nico8340 Jul 15, 2025
ffef640
Merge branch 'master' into attach
Nico8340 Jul 28, 2025
9bfd7dc
Fix source code
botder Jul 31, 2025
3fe05ed
Merge branch 'master' into attach
botder Jul 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Client/mods/deathmatch/logic/CClientGame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2630,6 +2630,8 @@ void CClientGame::AddBuiltInEvents()
m_Events.AddEvent("onClientElementModelChange", "oldModel, newModel", nullptr, false);
m_Events.AddEvent("onClientElementDimensionChange", "oldDimension, newDimension", nullptr, false);
m_Events.AddEvent("onClientElementInteriorChange", "oldInterior, newInterior", nullptr, false);
m_Events.AddEvent("onClientElementAttach", "attachSource, attachOffsetX, attachOffsetY, attachOffsetZ, attachOffsetRX, attachOffsetRY, attachOffsetRZ", nullptr, false);
m_Events.AddEvent("onClientElementDetach", "detachSource, detachWorldX, detachWorldY, detachWorldZ, detachWorldRX, detachWorldRY, detachWorldRZ", nullptr, false);

// Player events
m_Events.AddEvent("onClientPlayerJoin", "", NULL, false);
Expand Down
59 changes: 44 additions & 15 deletions Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1371,35 +1371,64 @@ bool CStaticFunctionDefinitions::AttachElements(CClientEntity& Entity, CClientEn
RUN_CHILDREN(AttachElements(**iter, AttachedToEntity, vecPosition, vecRotation))

// Can these elements be attached?
if (Entity.IsAttachToable() && AttachedToEntity.IsAttachable() && !AttachedToEntity.IsAttachedToElement(&Entity) &&
Entity.GetDimension() == AttachedToEntity.GetDimension())
if (!Entity.IsAttachToable() || !AttachedToEntity.IsAttachable() || AttachedToEntity.IsAttachedToElement(&Entity) ||
Entity.GetDimension() != AttachedToEntity.GetDimension())
{
ConvertDegreesToRadians(vecRotation);
return false;
}

Entity.SetAttachedOffsets(vecPosition, vecRotation);
Entity.AttachTo(&AttachedToEntity);
CLuaArguments Arguments;
Arguments.PushElement(&AttachedToEntity);
Arguments.PushNumber(vecPosition.fX);
Arguments.PushNumber(vecPosition.fY);
Arguments.PushNumber(vecPosition.fZ);
Arguments.PushNumber(vecRotation.fX);
Arguments.PushNumber(vecRotation.fY);
Arguments.PushNumber(vecRotation.fZ);

if (!Entity.CallEvent("onClientElementAttach", Arguments, true))
return false;

return true;
}
ConvertDegreesToRadians(vecRotation);

return false;
Entity.SetAttachedOffsets(vecPosition, vecRotation);
Entity.AttachTo(&AttachedToEntity);

return true;
}

bool CStaticFunctionDefinitions::DetachElements(CClientEntity& Entity, CClientEntity* pAttachedToEntity)
{
RUN_CHILDREN(DetachElements(**iter, pAttachedToEntity))

CClientEntity* pActualAttachedToEntity = Entity.GetAttachedTo();
if (pActualAttachedToEntity)
if (!pActualAttachedToEntity || (pAttachedToEntity && pActualAttachedToEntity != pAttachedToEntity))
{
if (pAttachedToEntity == NULL || pActualAttachedToEntity == pAttachedToEntity)
{
Entity.AttachTo(NULL);
return true;
}
return false;
}

return false;
CVector vecPosition;
CVector vecRotation;

Entity.GetPosition(vecPosition);
Entity.GetRotationDegrees(vecRotation);

CLuaArguments Arguments;
Arguments.PushElement(pActualAttachedToEntity);
Arguments.PushNumber(vecPosition.fX);
Arguments.PushNumber(vecPosition.fY);
Arguments.PushNumber(vecPosition.fZ);
Arguments.PushNumber(vecRotation.fX);
Arguments.PushNumber(vecRotation.fY);
Arguments.PushNumber(vecRotation.fZ);

if (!Entity.CallEvent("onClientElementDetach", Arguments, true))
{
return false;
}

Entity.AttachTo(NULL);
return true;
}

bool CStaticFunctionDefinitions::SetElementAttachedOffsets(CClientEntity& Entity, CVector& vecPosition, CVector& vecRotation)
Expand Down
92 changes: 75 additions & 17 deletions Client/mods/deathmatch/logic/rpc/CElementRPCs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,32 +313,90 @@ void CElementRPCs::SetElementDimension(CClientEntity* pSource, NetBitStreamInter
void CElementRPCs::AttachElements(CClientEntity* pSource, NetBitStreamInterface& bitStream)
{
ElementID usAttachedToID;
CVector vecPosition, vecRotation;
if (bitStream.Read(usAttachedToID) && bitStream.Read(vecPosition.fX) && bitStream.Read(vecPosition.fY) && bitStream.Read(vecPosition.fZ) &&
bitStream.Read(vecRotation.fX) && bitStream.Read(vecRotation.fY) && bitStream.Read(vecRotation.fZ))

CVector vecPosition;
CVector vecRotation;

if (!(bitStream.Read(usAttachedToID) && bitStream.Read(vecPosition.fX) && bitStream.Read(vecPosition.fY) && bitStream.Read(vecPosition.fZ) &&
bitStream.Read(vecRotation.fX) && bitStream.Read(vecRotation.fY) && bitStream.Read(vecRotation.fZ)))
{
CClientEntity* pAttachedToEntity = CElementIDs::GetElement(usAttachedToID);
if (pAttachedToEntity)
{
pSource->SetAttachedOffsets(vecPosition, vecRotation);
pSource->AttachTo(pAttachedToEntity);
}
return;
}

CClientEntity* pAttachedToEntity = CElementIDs::GetElement(usAttachedToID);
if (!pAttachedToEntity)
{
return;
}

ConvertRadiansToDegrees(vecRotation);

CLuaArguments Arguments;
Arguments.PushElement(pAttachedToEntity);
Arguments.PushNumber(vecPosition.fX);
Arguments.PushNumber(vecPosition.fY);
Arguments.PushNumber(vecPosition.fZ);
Arguments.PushNumber(vecRotation.fX);
Arguments.PushNumber(vecRotation.fY);
Arguments.PushNumber(vecRotation.fZ);

if (!pSource->CallEvent("onClientElementAttach", Arguments, true))
{
return;
}

ConvertDegreesToRadians(vecRotation);

pSource->SetAttachedOffsets(vecPosition, vecRotation);
pSource->AttachTo(pAttachedToEntity);
}

void CElementRPCs::DetachElements(CClientEntity* pSource, NetBitStreamInterface& bitStream)
{
unsigned char ucTimeContext;
if (bitStream.Read(ucTimeContext))
if (!bitStream.Read(ucTimeContext))
{
pSource->SetSyncTimeContext(ucTimeContext);
pSource->AttachTo(NULL);
return;
}

CVector vecPosition;
if (bitStream.Read(vecPosition.fX) && bitStream.Read(vecPosition.fY) && bitStream.Read(vecPosition.fZ))
{
pSource->SetPosition(vecPosition);
}
ElementID usAttachedToID;
CClientEntity* pAttachedToEntity = CElementIDs::GetElement(usAttachedToID);

CVector vecPosition;
CVector vecRotation;

bitStream.Read(vecPosition.fX);
bitStream.Read(vecPosition.fY);
bitStream.Read(vecPosition.fZ);
bitStream.Read(vecRotation.fX);
bitStream.Read(vecRotation.fY);
bitStream.Read(vecRotation.fZ);

CLuaArguments Arguments;
Arguments.PushElement(pAttachedToEntity);
Arguments.PushNumber(vecPosition.fX);
Arguments.PushNumber(vecPosition.fY);
Arguments.PushNumber(vecPosition.fZ);
Arguments.PushNumber(vecRotation.fX);
Arguments.PushNumber(vecRotation.fY);
Arguments.PushNumber(vecRotation.fZ);

if (!pSource->CallEvent("onClientElementDetach", Arguments, true))
{
return;
}

pSource->SetSyncTimeContext(ucTimeContext);
pSource->AttachTo(NULL);

if (vecPosition.fX != 0.0f || vecPosition.fY != 0.0f || vecPosition.fZ != 0.0f)
{
pSource->SetPosition(vecPosition);
}

if (vecRotation.fX != 0.0f || vecRotation.fY != 0.0f || vecRotation.fZ != 0.0f)
{
pSource->SetRotationDegrees(vecRotation);
}
}

Expand Down
2 changes: 2 additions & 0 deletions Server/mods/deathmatch/logic/CGame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1668,6 +1668,8 @@ void CGame::AddBuiltInEvents()
m_Events.AddEvent("onElementModelChange", "oldModel, newModel", NULL, false);
m_Events.AddEvent("onElementDimensionChange", "oldDimension, newDimension", nullptr, false);
m_Events.AddEvent("onElementInteriorChange", "oldInterior, newInterior", nullptr, false);
m_Events.AddEvent("onElementAttach", "attachSource, attachOffsetX, attachOffsetY, attachOffsetZ, attachOffsetRX, attachOffsetRY, attachOffsetRZ", nullptr, false);
m_Events.AddEvent("onElementDetach", "detachSource, detachWorldX, detachWorldY, detachWorldZ, detachWorldRX, detachWorldRY, detachWorldRZ", nullptr, false);

// Radar area events

Expand Down
100 changes: 67 additions & 33 deletions Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1598,56 +1598,90 @@ bool CStaticFunctionDefinitions::AttachElements(CElement* pElement, CElement* pA
assert(pElement);
assert(pAttachedToElement);

if (pElement->IsAttachToable() && pAttachedToElement->IsAttachable() && !pAttachedToElement->IsAttachedToElement(pElement) &&
pElement->GetDimension() == pAttachedToElement->GetDimension())
if (!pElement->IsAttachToable() || !pAttachedToElement->IsAttachable() || pAttachedToElement->IsAttachedToElement(pElement) ||
pElement->GetDimension() != pAttachedToElement->GetDimension())
{
pElement->SetAttachedOffsets(vecPosition, vecRotation);
ConvertDegreesToRadians(vecRotation);
pElement->AttachTo(pAttachedToElement);
return false;
}

CBitStream BitStream;
BitStream.pBitStream->Write(pAttachedToElement->GetID());
BitStream.pBitStream->Write(vecPosition.fX);
BitStream.pBitStream->Write(vecPosition.fY);
BitStream.pBitStream->Write(vecPosition.fZ);
BitStream.pBitStream->Write(vecRotation.fX);
BitStream.pBitStream->Write(vecRotation.fY);
BitStream.pBitStream->Write(vecRotation.fZ);
m_pPlayerManager->BroadcastOnlyJoined(CElementRPCPacket(pElement, ATTACH_ELEMENTS, *BitStream.pBitStream));
CLuaArguments Arguments;
Arguments.PushElement(pAttachedToElement);
Arguments.PushNumber(vecPosition.fX);
Arguments.PushNumber(vecPosition.fY);
Arguments.PushNumber(vecPosition.fZ);
Arguments.PushNumber(vecRotation.fX);
Arguments.PushNumber(vecRotation.fY);
Arguments.PushNumber(vecRotation.fZ);

return true;
if (!pElement->CallEvent("onElementAttach", Arguments))
{
return false;
}

return false;
ConvertDegreesToRadians(vecRotation);

pElement->SetAttachedOffsets(vecPosition, vecRotation);
pElement->AttachTo(pAttachedToElement);

CBitStream BitStream;
BitStream.pBitStream->Write(pAttachedToElement->GetID());
BitStream.pBitStream->Write(vecPosition.fX);
BitStream.pBitStream->Write(vecPosition.fY);
BitStream.pBitStream->Write(vecPosition.fZ);
BitStream.pBitStream->Write(vecRotation.fX);
BitStream.pBitStream->Write(vecRotation.fY);
BitStream.pBitStream->Write(vecRotation.fZ);
m_pPlayerManager->BroadcastOnlyJoined(CElementRPCPacket(pElement, ATTACH_ELEMENTS, *BitStream.pBitStream));

return true;
}

bool CStaticFunctionDefinitions::DetachElements(CElement* pElement, CElement* pAttachedToElement)
{
assert(pElement);

CElement* pActualAttachedToElement = pElement->GetAttachedToElement();
if (pActualAttachedToElement)
if (!pActualAttachedToElement || (pAttachedToElement && pActualAttachedToElement != pAttachedToElement))
{
if (pAttachedToElement == NULL || pActualAttachedToElement == pAttachedToElement)
{
// Detach it. Also generate a new time context to prevent sync screwup from
// old packes arriving.
CVector vecPosition = pElement->GetPosition();
pElement->AttachTo(NULL);
pElement->GenerateSyncTimeContext();
return false;
}

CBitStream BitStream;
BitStream.pBitStream->Write(pElement->GetSyncTimeContext());
BitStream.pBitStream->Write(vecPosition.fX);
BitStream.pBitStream->Write(vecPosition.fY);
BitStream.pBitStream->Write(vecPosition.fZ);
m_pPlayerManager->BroadcastOnlyJoined(CElementRPCPacket(pElement, DETACH_ELEMENTS, *BitStream.pBitStream));
CVector vecPosition = pElement->GetPosition();
CVector vecRotation;

return true;
}
pElement->GetRotation(vecRotation);
ConvertRadiansToDegrees(vecRotation);

CLuaArguments Arguments;
Arguments.PushElement(pActualAttachedToElement);
Arguments.PushNumber(vecPosition.fX);
Arguments.PushNumber(vecPosition.fY);
Arguments.PushNumber(vecPosition.fZ);
Arguments.PushNumber(vecRotation.fX);
Arguments.PushNumber(vecRotation.fY);
Arguments.PushNumber(vecRotation.fZ);

if (!pElement->CallEvent("onElementDetach", Arguments))
{
return false;
}

return false;
// Detach it. Also generate a new time context to prevent sync screwup from
// old packets arriving.
pElement->AttachTo(NULL);
pElement->GenerateSyncTimeContext();

CBitStream BitStream;
BitStream.pBitStream->Write(pElement->GetSyncTimeContext());
BitStream.pBitStream->Write(vecPosition.fX);
BitStream.pBitStream->Write(vecPosition.fY);
BitStream.pBitStream->Write(vecPosition.fZ);
BitStream.pBitStream->Write(vecRotation.fX);
BitStream.pBitStream->Write(vecRotation.fY);
BitStream.pBitStream->Write(vecRotation.fZ);
m_pPlayerManager->BroadcastOnlyJoined(CElementRPCPacket(pElement, DETACH_ELEMENTS, *BitStream.pBitStream));

return true;
}

bool CStaticFunctionDefinitions::SetElementAlpha(CElement* pElement, unsigned char ucAlpha)
Expand Down
Loading