Skip to content

A modern C++ header-only library for interacting with VotV.

Notifications You must be signed in to change notification settings

modestimpala/libvotv

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

16 Commits
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

libvotv

C++17 CMake 3.18+ VotV pa0081_0008 UE4SS Header Only

A modern C++ header-only library for interacting with Voices of the Void game state, providing type-safe access to game objects, player state, and environment variables.

Features

  • ๐ŸŽฎ Type-safe game state access through a single header
  • ๐Ÿ”’ Memory-safe field manipulation
  • ๐ŸŽฏ Direct access to core game systems
  • ๐Ÿงฐ Modern C++ wrapper around UE4/UE4SS objects
  • ๐Ÿ“ก Object lifetime tracking utilities
  • ๐Ÿ”ง Struct manipulation macros for clean field access of custom fields

Todo

  • Map VotV specific functions with same method

Table of Contents

Prerequisites

Installation

The library consists of three headers:

  • game.hpp - Main game state and objects
  • ObjectLifetimeTracker.hpp - UObject lifetime management
  • StructUtil.hpp - Field access macros and utilities

As a CMake Subproject

  1. Add the repository as a submodule:
git submodule add https://github.com/modestimpala/libvotv.git extern/libvotv
  1. Add to your CMakeLists.txt:
add_subdirectory(extern/libvotv)
target_link_libraries(your_project PRIVATE libvotv)

Manual Installation / IDE Setup

Since the library is header-only:

  1. Copy the three headers to your project
  2. Add their location to your include path
  3. Ensure UE4SS headers are available

Usage

Basic Setup

#include <votv/game.hpp>  // Single header for all game functionality
#include <votv/ObjectLifetimeTracker.hpp>

using namespace votv::game;

// Get existing game mode from UE4SS
GameMode* gameMode = /* get from UE4SS */;

// Validate object is still alive
auto& tracker = ObjectLifetimeTracker::Get();
if (!tracker.IsActorAlive(gameMode)) return;

// Access player
MainPlayer* player = gameMode->mainPlayer;
if (!tracker.IsActorAlive(player)) return;

// Check player state
if (player->inWater && player->air < 50.0f) {
    // Handle low air situation
}

Utility Classes

ObjectLifetimeTracker

The ObjectLifetimeTracker provides safe UObject lifetime tracking.

Initialize the ObjectLifetimeTracker as early as possible in your mod lifecycle:

auto on_unreal_init() -> void override
    auto& tracker = ObjectLifetimeTracker::Get(); // Get instance early
    // Rest of initialization...
}

Early initialization ensures no objects created during startup are missed by the tracking system.

Example:

#include <ObjectLifetimeTracker.hpp>

// Get singleton instance
auto& tracker = ObjectLifetimeTracker::Get();

// Track specific types
tracker.RegisterTrackedType(Car::StaticClass());
tracker.RegisterTrackedName(L"specialDoor");

// Check if objects are still valid
if (tracker.IsActorAlive(someActor)) {
    // Safe to use
}

Features:

  • Default tracking of GameMode and MainPlayer objects
  • Registering custom types/names to track
  • Thread-safe operation
  • RAII-based resource management
  • Protection against use-after-free

StructUtil Macros

StructUtil.hpp provides type-safe field access macros:

// Regular field access
FIELD(0x0600, MainPlayer*, mainPlayer);  // Generates getters/setters

// Vector field with component access
VECTOR_INT_FIELD(0x02F8, timeZ);  // Adds _x, _y, _z component access

// Enum field with type safety
ENUM_FIELD(0x01E1, GameModes::Type, gamemodeType);

// Bit field for flags
BIT_FIELD(0x0480, 0x01, someFlag);

// Array field access
ARRAY_FIELD(0x0208, RC::Unreal::TArray<float>, scores);

Features:

  • Automatic getter/setter generation
  • Type-safe field access
  • Support for vectors, enums, arrays and bit fields
  • Property syntax support through __declspec
  • All methods marked noexcept where appropriate
  • Proper reference handling (lvalue/rvalue)

API Reference

Core Game Classes (game.hpp)

All game functionality is contained in a single header under the votv::game namespace.

namespace votv::game {
    class GameMode;
    class MainPlayer;
    class DayNightCycle;
    class Car;
    class Door;
    class KerfurOmega;
    class GameInst;
    class SaveSlot;
}

PowerInfo GetPowerInfo() const;  // Get complete power system state
TimeInfo GetTimeInfo() const; // Get complete time info
WeatherInfo GetWeatherInfo() const; // Get complete weather info

// Game Instance
class GameInst : public RC::Unreal::UObject {
    SaveSlot* save;             // Active save
    GameModes::Type gamemodeType; // Game mode Type (Sandbox, Story, etc)
    bool opened;                // Instance opened
    int32_t startDay;           // Starting day
    ...
};

// Save slot
class SaveSlot : public RC::Unreal::UObject {
    float food;                 // Food level
    float sleep;                // Sleep level
    int32_t Points;             // Money
    float health;               // Current health
    ...
};

See header file for complete API.

Examples

Safe Object Access Pattern

#include <votv/game.hpp>
#include <votv/ObjectLifetimeTracker.hpp>

void SafeGameObjectAccess(votv::game::GameMode* gameMode) {
    auto& tracker = ObjectLifetimeTracker::Get();
    
    // Validate game mode
    if (!tracker.IsActorAlive(gameMode)) return;

    // Access and validate player
    auto* player = gameMode->mainPlayer;
    if (!tracker.IsActorAlive(player)) return;

    // Safe to use objects
    auto state = player->GetState();
    auto power = gameMode->GetPowerInfo();

    if (state.inWater && power.ratio < 0.2f) {
        // Handle dangerous situation
    }
}

Custom Object Tracking

#include <votv/game.hpp>
#include <votv/ObjectLifetimeTracker.hpp>

void SetupTracking() {
    auto& tracker = ObjectLifetimeTracker::Get();

    // Track all cars
    tracker.RegisterTrackedType(Car::StaticClass());

    // Track special objects
    tracker.RegisterTrackedName(L"prop_important");

    // Later cleanup if needed
    tracker.UnregisterTrackedType(Car::StaticClass());
    tracker.UnregisterTrackedName(L"prop_important");
}

Time and Weather Management

#include <votv/game.hpp>

void HandleTimeChange(DayNightCycle* dnc) {
    // Get complete time state
    auto timeInfo = dnc->GetTimeInfo();
    auto weather = dnc->GetWeatherInfo();
    

    // Access raw day counter
    int32_t currentDay = dnc->current_day();
    
    // Modify time
    dnc->set_timeZ(0, 0, currentDay + 1); 
}

Defining Custom Fields from UE4SS Header Dumps

See UE4SS Dumpers

See UE4SS Dumper Converter

Make sure DumpOffsetsAndSizes and LoadAllAssetsBeforeGeneratingCXXHeaders are 1 then dump headers from main menu.

Find specific class, then map offsets:

// Dumped cremator.hpp
class Acremator_C : public Aactor_save_C
{
    ...
    bool IsClosed;                                                                    // 0x0351 (size: 0x1)
    ...
}

#include <votv/game.hpp>
#include <StructUtil.hpp>

// Your custom wrapper class (e.g., extra_game.hpp)
class Cremator : public RC::Unreal::AActor {
public:
    FIELD(0x0351, bool, isClosed);    // Maps to IsClosed from dump
};

And so on for any other custom fields needed.

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/extra-offsets)
  3. Commit your changes (git commit -m 'More offsets')
  4. Push to the branch (git push origin feature/extra-offsets)
  5. Open a Pull Request

Credits

  • MrDrNose for VotV
  • UE4SS and their Discord Community
  • agersant (gbvsr-frame-meter)

About

A modern C++ header-only library for interacting with VotV.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published