Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
64 changes: 58 additions & 6 deletions code/components/extra-natives-five/src/PoolTraversalNatives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,32 @@ struct PickupPoolTraits
}
};

#ifdef IS_RDR3
struct BlipPoolTraits
{
using PoolType = atPoolBase;

static PoolType* GetPool()
{
return rage::GetPoolBase("fwuiBlip");
}

static uint32_t getScriptGuid(void* entry, int index)
{
auto pool = GetPool();
if (!pool)
return 0;

// Blips use flag value 2
// The handle format is: (index << 8) | flag
uint32_t handle = (index << 8) | 2;

return handle;
}
};
#endif


template<typename TTraits, bool NetworkOnly = false>
static void SerializePool(fx::ScriptContext& context)
{
Expand All @@ -156,10 +182,10 @@ static void SerializePool(fx::ScriptContext& context)
{
if (!entry->GetNetObject())
{
continue;
}
}
continue;
}
}

uint32_t guid = TTraits::getScriptGuid(entry);
if (guid != 0)
{
Expand All @@ -171,6 +197,28 @@ static void SerializePool(fx::ScriptContext& context)
context.SetResult(fx::SerializeObject(guids));
}

template<typename TTraits>
static void SerializePoolBase(fx::ScriptContext& context)
{
std::vector<uint32_t> guids;

auto pool = static_cast<atPoolBase*>(TTraits::GetPool());
for (int i = 0; i < pool->GetCountDirect(); ++i)
{
auto entry = pool->GetAt<void>(i);
if (entry)
{
uint32_t guid = TTraits::getScriptGuid(entry, i);
if (guid != 0)
{
guids.push_back(guid);
}
}
}

context.SetResult(fx::SerializeObject(guids));
}

struct FindHandle
{
void* pool;
Expand Down Expand Up @@ -290,12 +338,16 @@ static InitFunction initFunction([]()
SerializePool<PedPoolTraits>(context);
else if (pool.compare("CObject") == 0)
SerializePool<ObjectPoolTraits>(context);
else if (pool.compare("CNetObject") == 0)
SerializePool<ObjectPoolTraits, true>(context);
else if (pool.compare("CNetObject") == 0)
SerializePool<ObjectPoolTraits, true>(context);
else if (pool.compare("CPickup") == 0)
SerializePool<PickupPoolTraits>(context);
else if (pool.compare("CVehicle") == 0)
SerializePool<VehiclePoolTraits>(context);
#ifdef IS_RDR3
else if (pool.compare("CBlip") == 0)
SerializePoolBase<BlipPoolTraits>(context);
#endif
else
{
throw std::runtime_error(va("Invalid pool: %s", pool));
Expand Down
100 changes: 100 additions & 0 deletions code/components/extra-natives-rdr3/src/BlipNatives.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#include "StdInc.h"

#include <Hooking.h>
#include <ScriptEngine.h>
#include <ScriptSerialization.h>

#include <atArray.h>
#include <Pool.h>

#include <GameInit.h>
#include <Local.h>

struct BlipData
{
char pad1[32]; // 0x0000-0x001F (32 bytes)
float x; // 0x0020 (4 bytes)
float y; // 0x0024 (4 bytes)
float z; // 0x0028 (4 bytes)
char vpad[4]; // 0x002C-0x002F (4 bytes)
uint16_t rotation; // 0x0030 (2 bytes)
char pad2[542]; // 0x0032-0x024F (542 bytes)
atArray<uint32_t> modifiers; // 0x0250-0x025F (16 bytes)
char pad3[92]; // 0x0260-0x02BB (92 bytes)
uint32_t blipSprite; // 0x02BC (4 bytes)
char pad4[15]; // 0x02C0-0x02CE (15 bytes)
uint8_t blipFlags; // 0x02CF - bitfield containing blip type/flags
char pad5[16]; // 0x02D0-0x02DF (16 bytes)
void* vtable; // 0x02F0 (8 bytes)
void* unk; // 0x02F8 (8 bytes)
};

static auto GetBlipPool()
{
static auto pool = rage::GetPoolBase("fwuiBlip");
return pool;
}

static BlipData* GetBlipData(uint32_t blipHandle)
{
if (blipHandle == 0)
return nullptr;

auto pool = GetBlipPool();
if (!pool)
return nullptr;

auto blip = pool->GetAtHandle<BlipData>(blipHandle);
return blip;
}

static InitFunction initFunction([]()
{
fx::ScriptEngine::RegisterNativeHandler("GET_BLIP_SPRITE", [](fx::ScriptContext& context)
{
uint32_t blipHandle = context.GetArgument<uint32_t>(0);

auto blip = GetBlipData(blipHandle);
if (blip)
{
context.SetResult(blip->blipSprite);
}
else
{
context.SetResult(0);
}
});

fx::ScriptEngine::RegisterNativeHandler("GET_BLIP_ROTATION", [](fx::ScriptContext& context)
{
uint32_t blipHandle = context.GetArgument<uint32_t>(0);

auto blip = GetBlipData(blipHandle);
if (blip)
{
float rotation = static_cast<float>(blip->rotation) * (360.0f / 65535.0f);
context.SetResult(rotation);
}
else
{
context.SetResult(0.0f);
}
});

fx::ScriptEngine::RegisterNativeHandler("GET_BLIP_MODIFIERS", [](fx::ScriptContext& context)
{
uint32_t blipHandle = context.GetArgument<uint32_t>(0);

std::vector<uint32_t> modifiers;
auto blip = GetBlipData(blipHandle);
if (blip)
{
for (int i = 0; i < blip->modifiers.GetCount(); ++i)
{
modifiers.push_back(blip->modifiers[i]);
}
}
context.SetResult(fx::SerializeObject(modifiers));
});

});
39 changes: 39 additions & 0 deletions ext/native-decls/GetBlipModifiers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
ns: CFX
apiset: client
game: rdr3
---
## GET_BLIP_MODIFIERS

```c
object GET_BLIP_MODIFIERS(int blipHandle);
```

Gets the modifiers array of a blip from its handle.

## Parameters
* **blipHandle**: The blip handle obtained from GET_GAME_POOL("CBlip")

## Return value
An array of uint32_t modifiers. Returns an empty array if the blip doesn't exist.

## Examples
```lua
local blips = GetGamePool("CBlip")
for _, blipHandle in ipairs(blips) do
local modifiers = GetBlipModifiers(blipHandle)
if #modifiers > 0 and modifiers[1] == 0x9D6AB6CB then -- BLIP_STYLE_POI
print("Found POI style blip with handle:", blipHandle)
end
end
```

```js
const blips = GetGamePool("CBlip");
blips.forEach(blipHandle => {
const modifiers = GetBlipModifiers(blipHandle);
if (modifiers.length > 0 && modifiers[0] === 0x9D6AB6CB) { // BLIP_STYLE_POI
console.log(`Found POI style blip with handle: ${blipHandle}`);
}
});
```
35 changes: 35 additions & 0 deletions ext/native-decls/GetBlipRotation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
ns: CFX
apiset: client
game: rdr3
---
## GET_BLIP_ROTATION

```c
float GET_BLIP_ROTATION(int blipHandle);
```

Gets the rotation of a blip from its handle.

## Parameters
* **blipHandle**: The blip handle obtained from GET_GAME_POOL("CBlip")

## Return value
The blip rotation in degrees as a float value (0.0 to 360.0). Returns 0.0 if the blip doesn't exist.

## Examples
```lua
local blips = GetGamePool("CBlip")
for _, blipHandle in ipairs(blips) do
local rotation = GetBlipRotation(blipHandle)
print(string.format("Blip %d rotation: %.2f degrees", blipHandle, rotation))
end
```

```js
const blips = GetGamePool("CBlip");
blips.forEach(blipHandle => {
const rotation = GetBlipRotation(blipHandle);
console.log(`Blip ${blipHandle} rotation: ${rotation.toFixed(2)} degrees`);
});
```
39 changes: 39 additions & 0 deletions ext/native-decls/GetBlipSprite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
ns: CFX
apiset: client
game: rdr3
---
## GET_BLIP_SPRITE

```c
Hash GET_BLIP_SPRITE(int blipHandle);
```

Gets the sprite/hash of a blip from its handle.

## Parameters
* **blipHandle**: The blip handle obtained from GET_GAME_POOL("CBlip")

## Return value
The blip sprite hash. Returns 0 if the blip doesn't exist.

## Examples
```lua
local blips = GetGamePool("CBlip")
for _, blipHandle in ipairs(blips) do
local sprite = GetBlipSprite(blipHandle)
if sprite == 0x866B73BE then -- BLIP_POI
print("Found POI blip with handle:", blipHandle)
end
end
```

```js
const blips = GetGamePool("CBlip");
blips.forEach(blipHandle => {
const sprite = GetBlipSprite(blipHandle);
if (sprite === 0x866B73BE) { // BLIP_POI
console.log(`Found POI blip with handle: ${blipHandle}`);
}
});
```
10 changes: 10 additions & 0 deletions ext/native-decls/GetGamePool.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ follows:
* `CNetObject`: Networked objects
* `CVehicle`: Vehicles.
* `CPickup`: Pickups.
* `CBlip`: Blips (RDR3 only).

## Examples
```lua
Expand All @@ -30,6 +31,15 @@ for i = 1, #vehiclePool do -- loop through each vehicle (entity)
DeleteEntity(vehiclePool[i]) -- Delete vehicles (entities) that don't have a driver
end
end

-- RDR3 only: Get all blips
local blipPool = GetGamePool('CBlip')
for i = 1, #blipPool do
local sprite = GetBlipSprite(blipPool[i])
local rotation = GetBlipRotation(blipPool[i])
print(string.format("Blip %d: sprite=0x%X, rotation=%d",
blipPool[i], sprite, rotation))
end
```

## Parameters
Expand Down
Loading