Files
GTASource/game/pickups/PickupPlacement.cpp

958 lines
25 KiB
C++
Raw Permalink Normal View History

2025-02-23 17:40:52 +08:00
// File header
#include "event/EventGroup.h"
#include "event/EventNetwork.h"
#include "frontend/MiniMap.h"
#include "Network/Objects/Entities/NetObjPickupPlacement.h"
#include "fwnet/NetGameObjectBase.h"
#include "network/Events/NetworkEventTypes.h"
#include "Network/Objects/Entities/NetObjGame.h"
#include "Network/Objects/NetworkObjectMgr.h"
#include "peds/PlayerInfo.h"
#include "peds/Ped.h"
#include "pickups/Data/PickupDataManager.h"
#include "pickups/Pickup.h"
#include "pickups/PickupManager.h"
#include "pickups/PickupPlacement.h"
#include "script/script.h"
#include "script/script_channel.h"
#include "script/Handlers/GameScriptHandlerNetwork.h"
WEAPON_OPTIMISATIONS()
NETWORK_OPTIMISATIONS()
float CPickupPlacement::ms_customBlipScale = 0.0f;
int CPickupPlacement::ms_customBlipDisplay = 0;
int CPickupPlacement::ms_customBlipPriority = 0;
int CPickupPlacement::ms_customBlipSprite = 0;
int CPickupPlacement::ms_customBlipColour = 0;
float CPickupPlacement::ms_generationRangeMultiplier = 1.f;
FW_INSTANTIATE_CLASS_POOL(CPickupPlacement, CONFIGURED_FROM_FILE, atHashString("CPickupPlacement",0xef501806));
FW_INSTANTIATE_CLASS_POOL(CPickupPlacement::CPickupPlacementCustomScriptData, CONFIGURED_FROM_FILE, atHashString("CPickupPlacementCustomScriptData",0xb1786625));
const float CPickupPlacement::DEFAULT_GLOW_OFFSET = 0.5f;
CPickupPlacement::CPickupPlacement(u32 pickupHash, Vector3& position, Vector3& orientation, PlacementFlags flags, u32 customModelIndex)
: m_pickupPosition(position)
, m_pickupOrientation(orientation)
, m_roomHashkey(0)
, m_pPickup(NULL)
, m_pPickupData(CPickupDataManager::GetPickupData(pickupHash))
, m_pHandler(NULL)
, m_pCustomScriptData(NULL)
, m_flags(flags)
, m_customRegenTime(0)
, m_amount(0)
, m_amountCollected(0)
, m_customWeaponHash(0)
{
Assertf(!(GetHasComplexBlip() && GetHasSimpleBlip()), "Trying to create a placement with simple & complex blip!");
// create a blip if necessary (the collected flag can be set if this is being created as a clone)
if (!(flags & PLACEMENT_INTERNAL_FLAG_COLLECTED))
{
CreateBlip();
}
// map pickups must always be fixed
if (m_flags & PLACEMENT_CREATION_FLAG_MAP)
{
m_flags |= PLACEMENT_CREATION_FLAG_FIXED;
}
if (customModelIndex != fwModelId::MI_INVALID && GetOrCreateCustomScriptData())
{
m_pCustomScriptData->m_customModelIndex = customModelIndex;
}
}
CPickupPlacement::~CPickupPlacement()
{
Assert(!GetNetworkObject());
if (m_pPickup)
{
m_pPickup->SetCreatedBlip(false);
// can't destroy cloned pickups, they will be removed by the owner
if (!m_pPickup->IsNetworkClone())
{
DestroyPickup();
}
else
{
m_pPickup->SetPlacement(NULL);
m_pPickup = NULL;
}
}
RemoveBlip();
if (m_pCustomScriptData)
{
delete m_pCustomScriptData;
m_pCustomScriptData = NULL;
}
}
u32 CPickupPlacement::GetPickupHash() const
{
Assert(m_pPickupData);
return m_pPickupData ? m_pPickupData->GetHash() : 0;
}
void CPickupPlacement::SetPickup(CPickup* pPickup)
{
Assert(!m_pPickup || !pPickup);
m_pPickup = pPickup;
}
float CPickupPlacement::GetGenerationRange() const
{
return m_pPickupData->GetGenerationRange() * ms_generationRangeMultiplier;
}
void CPickupPlacement::SetAmount(u16 amount)
{
m_amount = amount;
if (GetPickup())
GetPickup()->SetAmount(amount);
}
void CPickupPlacement::SetPickupHasBeenDestroyed(bool bLocallyDestroyed)
{
if (!GetHasPickupBeenDestroyed())
{
m_flags |= PLACEMENT_INTERNAL_FLAG_PICKUP_DESTROYED;
CPickupManager::RegisterPickupDestruction(this);
if (NetworkInterface::IsGameInProgress())
{
netObject* pNetObj = GetNetworkObject();
if (pNetObj && !pNetObj->IsClone() && !pNetObj->IsPendingOwnerChange())
{
// force an immediate send of the game state data so that any explosions are triggered a.s.a.p
pNetObj->GetSyncTree()->Update(pNetObj, pNetObj->GetActivationFlags(), netInterface::GetSynchronisationTime());
pNetObj->GetSyncTree()->ForceSendOfNodeData(SERIALISEMODE_FORCE_SEND_OF_DIRTY, pNetObj->GetActivationFlags(), pNetObj, *SafeCast(CPickupPlacementSyncTree, pNetObj->GetSyncTree())->GetStateNode());
}
else
{
// send an event informing other machines the pickup is destroyed
if (bLocallyDestroyed && !GetLocalOnly())
{
CPickupDestroyedEvent::Trigger(*this);
}
}
if (m_pPickup && !bLocallyDestroyed)
{
m_pPickup->AddExplosion();
if (m_pPickup)
{
DestroyPickup();
}
}
}
}
}
void CPickupPlacement::SetUncollectable(bool b)
{
if (b)
{
m_flags |= PLACEMENT_INTERNAL_FLAG_UNCOLLECTABLE;
}
else
{
m_flags &= ~PLACEMENT_INTERNAL_FLAG_UNCOLLECTABLE;
}
if (m_pPickup)
{
m_pPickup->SetProhibitLocalCollection(b);
}
}
void CPickupPlacement::SetTransparentWhenUncollectable(bool b)
{
if (b)
{
m_flags |= PLACEMENT_INTERNAL_FLAG_FADE_WHEN_UNCOLLECTABLE;
}
else
{
m_flags &= ~PLACEMENT_INTERNAL_FLAG_FADE_WHEN_UNCOLLECTABLE;
}
if (m_pPickup)
{
m_pPickup->SetTransparentWhenUncollectable(b);
}
}
void CPickupPlacement::SetHiddenWhenUncollectable(bool b)
{
if (b)
{
m_flags |= PLACEMENT_INTERNAL_FLAG_HIDE_WHEN_UNCOLLECTABLE;
if (m_pPickup && !CanCollectScript())
{
DestroyPickup();
}
}
else
{
m_flags &= ~PLACEMENT_INTERNAL_FLAG_HIDE_WHEN_UNCOLLECTABLE;
if (GetInScope() && !GetIsCollected())
{
CreatePickup();
}
}
}
u32 CPickupPlacement::GetCustomModelHash() const
{
u32 modelHash = 0;
if (m_pCustomScriptData && m_pCustomScriptData->m_customModelIndex != fwModelId::MI_INVALID)
{
CBaseModelInfo * pModelInfo = CModelInfo::GetBaseModelInfo(fwModelId(m_pCustomScriptData->m_customModelIndex));
if (AssertVerify(pModelInfo))
{
modelHash = pModelInfo->GetModelNameHash();
}
}
return modelHash;
}
void CPickupPlacement::SetRegenerationTime(u32 regenTime)
{
m_customRegenTime = (u16)(regenTime/1000); // store as seconds
m_flags |= PLACEMENT_CREATION_FLAG_REGENERATES;
}
u32 CPickupPlacement::GetRegenerationTime()
{
u32 regenTime = 0;
Assert(GetRegenerates());
if (m_pCustomScriptData && m_customRegenTime != 0)
{
regenTime = static_cast<u32>(m_customRegenTime)*1000; // return time in millisecs
}
else
{
const CPickupData* pPickupData = CPickupDataManager::GetPickupData(GetPickupHash());
if (AssertVerify(pPickupData))
{
regenTime = static_cast<u32>(pPickupData->GetRegenerationTime()) * 1000; // return time in millisecs
}
}
return regenTime;
}
void CPickupPlacement::SetTeamPermits(TeamFlags teams)
{
if (m_pCustomScriptData || teams != 0)
{
if (GetOrCreateCustomScriptData())
{
m_pCustomScriptData->m_teamPermits = teams;
if (m_pPickup)
{
m_pPickup->SetTeamPermits(m_pCustomScriptData->m_teamPermits);
}
}
}
}
void CPickupPlacement::AddTeamPermit(u8 team)
{
if (GetOrCreateCustomScriptData())
{
m_pCustomScriptData->m_teamPermits |= (1<<team);
if (m_pPickup)
{
m_pPickup->SetTeamPermits(m_pCustomScriptData->m_teamPermits);
}
}
}
bool CPickupPlacement::GeneratesNetworkedPickups() const
{
/*
// no point in networking fixed pickups as they can't move
if (GetNetworkObject() && !(GetFlags() & PLACEMENT_CREATION_FLAG_FIXED))
{
Assert (!(GetFlags() & PLACEMENT_CREATION_FLAG_LOCAL_ONLY));
return true;
}*/
return false;
}
void CPickupPlacement::SetPickupGlowOffset(float f)
{
if (m_pCustomScriptData || f != DEFAULT_GLOW_OFFSET)
{
if (GetOrCreateCustomScriptData())
{
m_pCustomScriptData->m_pickupGlowOffset = f;
}
}
}
/*
void CPickupPlacement::SetPlayersAvailability(PlayerFlags players)
{
if (AssertVerify(GetIsMapPlacement()) && GetOrCreateCustomScriptData())
{
m_pCustomScriptData->m_CloneToPlayersList = players;
if (GetNetworkObject())
{
SafeCast(CNetObjPickupPlacement, GetNetworkObject())->SetPlayersAvailability(players);
}
}
}
*/
void CPickupPlacement::Update()
{
// unregister map placements that have regenerated and synced with all other players in scope
if (GetNetworkObject() &&
GetIsMapPlacement() &&
!GetIsCollected() &&
!GetNetworkObject()->IsClone() &&
!GetNetworkObject()->IsPendingOwnerChange())
{
if (GetNetworkObject()->IsSyncedWithAllPlayers())
{
NetworkInterface::GetObjectManager().UnregisterNetworkObject(GetNetworkObject(), netObjectMgrBase::GAME_UNREGISTRATION);
}
}
// if the pickup has fallen through the map destroy and recreate it fixed
if (GetPickup())
{
Vector3 pickupPos = VEC3V_TO_VECTOR3(GetPickup()->GetTransform().GetPosition());
if (pickupPos.z < m_pickupPosition.z - 1000.0f)
{
#if ENABLE_NETWORK_LOGGING
netLoggingInterface *log = &NetworkInterface::GetObjectManager().GetLog();
if (log && GetNetworkObject())
{
NetworkLogUtils::WriteLogEvent(*log, "RECREATING FALLEN PICKUP", "%s", GetNetworkObject()->GetLogName());
if (GetPickup()->GetNetworkObject())
{
log->WriteDataValue("Old pickup", "%s", GetPickup()->GetNetworkObject()->GetLogName());
}
}
#endif // ENABLE_NETWORK_LOGGING
DestroyPickup();
m_flags |= PLACEMENT_CREATION_FLAG_FIXED;
CreatePickup();
#if ENABLE_NETWORK_LOGGING
if (log && GetNetworkObject() && GetPickup())
{
log->WriteDataValue("New pickup", "%s", GetPickup()->GetNetworkObject()->GetLogName());
}
#endif // ENABLE_NETWORK_LOGGING
}
}
}
bool CPickupPlacement::GetInScope(CPed* pPlayerPed) const
{
float generationRange = GetGenerationRange();
Assertf(generationRange > 0.0f, "Generation range is not set for pickup of type %s - the pickups will not appear", m_pPickupData->GetName());
if (pPlayerPed)
{
return GetInScope(*pPlayerPed, m_pickupPosition, generationRange);
}
// networked pickups are always in scope
if (GetNetworkObject() && GeneratesNetworkedPickups())
{
return true;
}
if (FindPlayerPed())
{
// use static GetInScope()
return GetInScope(*FindPlayerPed(), m_pickupPosition, generationRange);
}
return false;
}
CPickup* CPickupPlacement::CreatePickup(CNetObjPickup* pNetObj)
{
CPickup* pPickup = NULL;
bool bRegisterAsNetworkObject = GeneratesNetworkedPickups();
if (GetHiddenWhenUncollectable())
{
if (!CanCollectScript())
{
return NULL;
}
}
if (AssertVerify(!GetPickup()) && AssertVerify(!GetIsCollected()) && AssertVerify(pNetObj || !GetNetworkObject() || !bRegisterAsNetworkObject || !GetNetworkObject()->IsClone()))
{
Matrix34 placementM;
placementM.FromEulersXYZ(m_pickupOrientation);
placementM.d = m_pickupPosition;
pPickup = CPickupManager::CreatePickup(GetPickupHash(), placementM, pNetObj, bRegisterAsNetworkObject, m_pCustomScriptData ? m_pCustomScriptData->m_customModelIndex.Get() : fwModelId::MI_INVALID);
if (pPickup)
{
// Should we attempt to snap this to the ground?
if( GetShouldSnapToGround() )
{
pPickup->SetPlaceOnGround(GetShouldOrientToGround(), GetShouldBeUpright());
}
// placements are always generated by script commands, so the pickups are mission objects
pPickup->SetOwnedBy( ENTITY_OWNEDBY_SCRIPT );
SetPickup(pPickup);
pPickup->SetPlacement(this);
if (m_pCustomScriptData)
{
if (m_pCustomScriptData->m_teamPermits != 0)
{
pPickup->SetTeamPermits(m_pCustomScriptData->m_teamPermits);
}
if (m_pCustomScriptData->m_pickupGlowOffset != 0.0f || !( GetShouldSnapToGround() || GetShouldOrientToGround() ))
{
pPickup->SetGlowOffset(m_pCustomScriptData->m_pickupGlowOffset);
pPickup->SetOffsetGlow(true);
}
}
if(m_customWeaponHash != 0)
{
pPickup->SetWeaponHash(m_customWeaponHash);
}
if (m_amount > 0)
{
pPickup->SetAmount(m_amount);
}
if ((m_flags & PLACEMENT_CREATION_FLAG_HIDE_IN_PHOTOS) != 0)
{
pPickup->SetFlag(CPickup::PF_HideInPhotos);
}
if ((m_flags & PLACEMENT_CREATION_FLAG_ON_OBJECT) != 0)
{
pPickup->SetLyingOnFixedObject();
}
if ((m_flags & PLACEMENT_CREATION_FLAG_COLLECTABLE_IN_VEHICLE) != 0)
{
pPickup->SetFlag(CPickup::PF_AllowCollectionInVehicle);
}
if (GetGlowWhenInSameTeam())
{
pPickup->SetFlag(CPickup::PF_GlowInSameTeam);
}
if (GetTransparentWhenUncollectable())
{
pPickup->SetTransparentWhenUncollectable(true);
}
if (GetUncollectable())
{
pPickup->SetProhibitLocalCollection(true);
}
if ((m_flags & PLACEMENT_CREATION_FLAG_AUTO_EQUIP) != 0)
{
pPickup->SetFlag(CPickup::PF_AutoEquipOnCollect);
}
if (bRegisterAsNetworkObject)
{
// if this is a map placement, register it as a network object when it first creates a pickup.
if (NetworkInterface::IsGameInProgress())
{
Assert(pPickup->GetNetworkObject());
if (!GetNetworkObject())
{
// only map placements should have no network object at this point
Assertf(GetIsMapPlacement(), "The pickup placement at %f, %f, %f has no network object!", m_pickupPosition.x, m_pickupPosition.y, m_pickupPosition.z);
// placements are always created by scripts so they automatically become script network objects
NetworkInterface::GetObjectManager().RegisterGameObject(this, 0, CNetObjGame::GLOBALFLAG_SCRIPTOBJECT|CNetObjGame::GLOBALFLAG_SCRIPT_MIGRATION|CNetObjGame::GLOBALFLAG_CLONEONLY_SCRIPT);
Assert(GetNetworkObject());
}
else if (pPickup->GetNetworkObject())
{
Assert(pPickup->GetNetworkObject()->GetPlayerOwner() == GetNetworkObject()->GetPlayerOwner());
}
}
else
{
Assert(!NetworkInterface::IsNetworkOpen());
}
}
}
}
return pPickup;
}
void CPickupPlacement::Collect(CPed* pPedWhoGotIt)
{
if (AssertVerify(!GetIsCollected()))
{
if (GetIsMapPlacement() && !GetNetworkObject() && NetworkInterface::IsGameInProgress() && (m_flags & PLACEMENT_CREATION_FLAG_LOCAL_ONLY)==0)
{
// register the placement once collected
NetworkInterface::GetObjectManager().RegisterGameObject(this, 0, CNetObjGame::GLOBALFLAG_SCRIPTOBJECT|CNetObjGame::GLOBALFLAG_SCRIPT_MIGRATION|CNetObjGame::GLOBALFLAG_CLONEONLY_SCRIPT);
}
m_flags |= PLACEMENT_INTERNAL_FLAG_COLLECTED;
Assert(GetPickup() || (GetNetworkObject() && GetNetworkObject()->IsClone()));
if (GetPickup())
{
GetPickup()->SetCreatedBlip(false);
if (GetPickup()->GetNetworkObject() && IsNetworkClone())
{
GetPickup()->SetCollected();
}
else
{
DestroyPickup();
}
}
RemoveBlip();
// inform network object about who collected it (to save having to search collection history every time)
if (GetNetworkObject() && pPedWhoGotIt)
{
static_cast<CNetObjPickupPlacement*>(GetNetworkObject())->SetCollector(pPedWhoGotIt);
}
}
}
bool CPickupPlacement::Regenerate()
{
if (AssertVerify(GetIsCollected() || GetHasPickupBeenDestroyed()) && Verifyf(!GetPickup(), "Regenerating placement %s at %0.2f, %0.2f, %0.2f already has a pickup", GetNetworkObject() ? GetNetworkObject()->GetLogName() : "??", m_pickupPosition.x, m_pickupPosition.y, m_pickupPosition.z))
{
netObject* pNetObj = GetNetworkObject();
// migrating placements can't regenerate
if (pNetObj && pNetObj->IsPendingOwnerChange())
{
return false;
}
// clear collected flag to prevent assert in CreatePickup()
m_flags &= ~PLACEMENT_INTERNAL_FLAG_COLLECTED;
m_flags &= ~PLACEMENT_INTERNAL_FLAG_PICKUP_DESTROYED;
if (GetInScope() && (!GeneratesNetworkedPickups() || !(GetNetworkObject() && GetNetworkObject()->IsClone())) && !CreatePickup())
{
// the placement can fail to regenerate a pickup if the model for the pickup is not streamed in yet
m_flags |= PLACEMENT_INTERNAL_FLAG_COLLECTED;
return false;
}
CreateBlip();
// inform network object to clear the collector
if (GetNetworkObject())
{
static_cast<CNetObjPickupPlacement*>(GetNetworkObject())->SetCollector(NULL);
if (GetIsMapPlacement() && !GetNetworkObject()->IsClone())
{
// dirty the state node here so that it will definitely be sent out before the network object is removed for the pickup
CPickupPlacementSyncTree* pPlacementTree = static_cast<CPickupPlacementSyncTree*>(GetNetworkObject()->GetSyncTree());
pPlacementTree->DirtyNode(GetNetworkObject(), *pPlacementTree->GetStateNode());
}
}
if (GetScriptInfo() && GetPickup())
{
u32 modelHash = 0;
CBaseModelInfo *modelInfo = GetPickup()->GetBaseModelInfo();
if(AssertVerify(modelInfo))
{
modelHash = modelInfo->GetHashKey();
}
CEventNetworkPickupRespawned pickupEvent(GetScriptInfo()->GetObjectId(), GetPickupHash(), modelHash);
GetEventScriptNetworkGroup()->Add(pickupEvent);
}
CPickupManager::RemovePickupPlacementFromCollectionHistory(this);
}
return true;
}
void CPickupPlacement::DestroyPickup()
{
if (AssertVerify(m_pPickup))
{
m_pPickup->Destroy();
m_pPickup = NULL;
}
}
s32 CPickupPlacement::CreateBlip()
{
if ((GetHasComplexBlip() || GetHasSimpleBlip()) &&
AssertVerify(!m_pCustomScriptData || m_pCustomScriptData->m_radarBlip == INVALID_BLIP_ID) &&
Verifyf(!(m_flags & PLACEMENT_INTERNAL_FLAG_COLLECTED), "Trying to create a blip for a collected pickup") &&
GetOrCreateCustomScriptData())
{
if (GetHasComplexBlip())
{
CEntityPoolIndexForBlip poolIndexForPlacement(this);
#if __DEV
m_pCustomScriptData->m_radarBlip = CMiniMap::CreateBlip(true, BLIP_TYPE_PICKUP, poolIndexForPlacement, BLIP_DISPLAY_BOTH, CTheScripts::GetCurrentScriptName());
#else
m_pCustomScriptData->m_radarBlip = CMiniMap::CreateBlip(true, BLIP_TYPE_PICKUP, poolIndexForPlacement, BLIP_DISPLAY_BOTH, NULL);
#endif
if (ms_customBlipSprite != 0)
CMiniMap::SetBlipParameter(BLIP_CHANGE_SPRITE, m_pCustomScriptData->m_radarBlip, ms_customBlipSprite);
if (ms_customBlipScale > 0.0f)
CMiniMap::SetBlipParameter(BLIP_CHANGE_SCALE, m_pCustomScriptData->m_radarBlip, ms_customBlipScale);
if (ms_customBlipDisplay != 0)
CMiniMap::SetBlipParameter(BLIP_CHANGE_DISPLAY, m_pCustomScriptData->m_radarBlip, ms_customBlipDisplay);
if (ms_customBlipColour != 0)
CMiniMap::SetBlipParameter(BLIP_CHANGE_COLOUR, m_pCustomScriptData->m_radarBlip, ms_customBlipColour);
if (ms_customBlipPriority != 0)
CMiniMap::SetBlipParameter(BLIP_CHANGE_PRIORITY, m_pCustomScriptData->m_radarBlip, ms_customBlipPriority);
}
else if (GetHasSimpleBlip())
{
#if __DEV
m_pCustomScriptData->m_radarBlip = CMiniMap::CreateSimpleBlip(GetPickupPosition(), "SimplePickup");
#else
m_pCustomScriptData->m_radarBlip = CMiniMap::CreateSimpleBlip(GetPickupPosition(), NULL);
#endif
}
return m_pCustomScriptData->m_radarBlip;
}
return INVALID_BLIP_ID;
}
void CPickupPlacement::RemoveBlip()
{
if (m_pCustomScriptData && m_pCustomScriptData->m_radarBlip != INVALID_BLIP_ID)
{
CMiniMapBlip *pBlip = CMiniMap::GetBlip(m_pCustomScriptData->m_radarBlip);
if (pBlip)
{
CMiniMap::RemoveBlip(pBlip);
}
m_pCustomScriptData->m_radarBlip = INVALID_BLIP_ID;
}
}
bool CPickupPlacement::CanCollectScript() const
{
if (GetUncollectable())
{
return false;
}
CNetGamePlayer* pLocalPlayer = NetworkInterface::GetLocalPlayer();
if (pLocalPlayer)
{
if (m_pCustomScriptData && m_pCustomScriptData->m_teamPermits != 0)
{
if (pLocalPlayer->GetTeam() == INVALID_TEAM || !(m_pCustomScriptData->m_teamPermits & (1<<pLocalPlayer->GetTeam())))
{
return false;
}
}
// not sure if these checks are needed, disable for now
/*
// certain players can be prohibited from collecting certain types of pickup in MP
PhysicalPlayerIndex playerIndex = pLocalPlayer->GetPhysicalPlayerIndex();
if (playerIndex != INVALID_PLAYER_INDEX && CPickupManager::IsCollectionProhibited(GetPickupHash(), playerIndex))
{
return false;
}
const CPickupData* pPickupData = CPickupDataManager::GetPickupData(GetPickupHash());
if (pPickupData)
{
if (CPickupManager::IsPickupModelCollectionProhibited(pPickupData->GetModelHash()))
{
return false;
}
}
*/
}
return true;
}
// scriptHandlerObject methods:
void CPickupPlacement::CreateScriptInfo(const scriptIdBase& scrId, const ScriptObjectId& objectId, const HostToken hostToken)
{
m_ScriptInfo = CGameScriptObjInfo(scrId, objectId, hostToken);
Assert(m_ScriptInfo.IsValid());
}
void CPickupPlacement::SetScriptInfo(const scriptObjInfoBase& info)
{
m_ScriptInfo = info;
Assert(m_ScriptInfo.IsValid());
}
scriptObjInfoBase* CPickupPlacement::GetScriptInfo()
{
if (m_ScriptInfo.IsValid())
return static_cast<scriptObjInfoBase*>(&m_ScriptInfo);
return NULL;
}
const scriptObjInfoBase* CPickupPlacement::GetScriptInfo() const
{
if (m_ScriptInfo.IsValid())
return static_cast<const scriptObjInfoBase*>(&m_ScriptInfo);
return NULL;
}
void CPickupPlacement::SetScriptHandler(scriptHandler* handler)
{
Assert(!handler || handler->GetScriptId() == m_ScriptInfo.GetScriptId());
m_pHandler = handler;
}
void CPickupPlacement::OnRegistration(bool LOGGING_ONLY(newObject), bool LOGGING_ONLY(hostObject) )
{
#if ENABLE_NETWORK_LOGGING
if (m_pHandler)
{
#if __BANK
scriptDisplayf("%s : Register %s script pickup %s", m_pHandler->GetLogName(), newObject ? "new" : "existing", m_pPickupData->GetName());
#endif // __BANK
if (newObject && GetNetworkObject())
{
Assertf(m_pHandler->GetNetworkComponent(), "Script %s is not networked but is creating networked pickups. This is not permitted.", m_pHandler->GetScriptId().GetLogName());
}
}
if (NetworkInterface::IsGameInProgress())
{
netLoggingInterface *log = CTheScripts::GetScriptHandlerMgr().GetLog();
if(log)
{
char logName[30];
char header[50];
m_ScriptInfo.GetLogName(logName, 30);
formatf(header, 50, "REGISTER_%s_%s_PICKUP", newObject ? "NEW" : "EXISTING", hostObject ? "HOST" : "LOCAL");
NetworkLogUtils::WriteLogEvent(*log, header, "%s %s", m_ScriptInfo.GetScriptId().GetLogName(), logName);
log->WriteDataValue("Script id", "%d", m_ScriptInfo.GetObjectId());
netObject* netObj = GetNetworkObject();
if (netObj)
{
log->WriteDataValue("Net Object", "%s", netObj->GetLogName());
}
}
}
#endif // ENABLE_NETWORK_LOGGING
}
void CPickupPlacement::OnUnregistration()
{
#if __BANK
scriptDisplayf("%s : Unregister script pickup %s", m_ScriptInfo.GetScriptId().GetLogName(), m_pPickupData ? m_pPickupData->GetName() : "?");
#endif // !__FINAL
netLoggingInterface *log = CTheScripts::GetScriptHandlerMgr().GetLog();
char logName[30];
m_ScriptInfo.GetLogName(logName, 30);
if (log)
{
NetworkLogUtils::WriteLogEvent(*log, "UNREGISTER_PICKUP", "%s %s", m_ScriptInfo.GetScriptId().GetLogName(), logName);
log->WriteDataValue("Script id", "%d", m_ScriptInfo.GetObjectId());
if (GetNetworkObject())
{
log->WriteDataValue("Net Object", "%s", GetNetworkObject()->GetLogName());
}
}
}
// Determine whether the object needs to be cleaned up properly. This is not done if the object is still required to persist as a script object
// for the remaining participants, who may still be running the script normally.
bool CPickupPlacement::IsCleanupRequired() const
{
netLoggingInterface* log = CTheScripts::GetScriptHandlerMgr().GetLog();
char logName[30];
logName[0] = 0;
if (gnetVerify(GetScriptInfo()))
{
GetScriptInfo()->GetLogName(logName, 30);
}
if (GetIsBeingDestroyed())
{
if (log)
{
NetworkLogUtils::WriteLogEvent(*log, "DETACH_PICKUP_PLACEMENT", "%s %s", GetScriptInfo()->GetScriptId().GetLogName(), logName);
log->WriteDataValue("Net Object", "%s", GetNetworkObject() ? GetNetworkObject()->GetLogName() : "?");
log->WriteDataValue("Being destroyed", "true");
}
return false;
}
return CGameScriptHandlerObject::IsCleanupRequired();
}
void CPickupPlacement::Cleanup()
{
netLoggingInterface* log = CTheScripts::GetScriptHandlerMgr().GetLog();
if (log)
{
char logName[30];
logName[0] = 0;
if (gnetVerify(GetScriptInfo()))
{
GetScriptInfo()->GetLogName(logName, 30);
}
NetworkLogUtils::WriteLogEvent(*log, "CLEANUP_PICKUP_PLACEMENT", "%s %s", GetScriptInfo()->GetScriptId().GetLogName(), logName);
log->WriteDataValue("Net Object", "%s", GetNetworkObject() ? GetNetworkObject()->GetLogName() : "?");
}
m_ScriptInfo.Invalidate();
CPickupManager::RemovePickupPlacement(this);
}
#if __BANK
void CPickupPlacement::SpewDebugInfo(const char* scriptName) const
{
if (scriptName)
{
Displayf("%s: %s (%f, %f, %f) %s\n",
scriptName,
m_pPickupData->GetName(),
m_pickupPosition.x, m_pickupPosition.y, m_pickupPosition.z,
GetNetworkObject() ? GetNetworkObject()->GetLogName() : "");
}
else
{
Displayf("%s (%f, %f, %f) %s\n",
m_pPickupData->GetName(),
m_pickupPosition.x, m_pickupPosition.y, m_pickupPosition.z,
GetNetworkObject() ? GetNetworkObject()->GetLogName() : "");
}
}
#endif // __BANK
CPickupPlacement::CPickupPlacementCustomScriptData* CPickupPlacement::GetOrCreateCustomScriptData()
{
if (!m_pCustomScriptData && CPickupPlacementCustomScriptData::GetPool()->GetNoOfFreeSpaces() > 0)
{
m_pCustomScriptData = rage_new CPickupPlacementCustomScriptData();
}
Assertf(m_pCustomScriptData, "Ran out of CPickupPlacement::CCustomScriptDatas");
return m_pCustomScriptData;
}
// static functions:
bool CPickupPlacement::GetInScope(const CPed& playerPed, const Vector3& placementPos, float range)
{
Vector3 playerPos = VEC3V_TO_VECTOR3(playerPed.GetTransform().GetPosition());
// if the local player is spectating, use his camera position or spectated player position instead
if (playerPed.IsLocalPlayer() && NetworkInterface::IsGameInProgress())
{
CNetGamePlayer* localPlayer = NetworkInterface::GetLocalPlayer();
if (localPlayer)
{
playerPos = NetworkInterface::GetPlayerFocusPosition(*localPlayer);
}
}
Vector3 playerDist = playerPos - placementPos;
float scope = static_cast<float>(range*range);
return (playerDist.Mag2() < scope);
}