Skip to content

Commit

Permalink
FEAT(positional-audio): plugin for Grounded
Browse files Browse the repository at this point in the history
Positional audio support for the Steam release of Grounded 1.4.3.4578.
  • Loading branch information
sqwishy committed Jul 6, 2024
1 parent 4b20771 commit b4b3122
Show file tree
Hide file tree
Showing 8 changed files with 230 additions and 1 deletion.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2020-2023 The Mumble Developers. All rights reserved.
# Copyright 2024 The Mumble Developers. All rights reserved.
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file at the root of the
# Mumble source tree or at <https://www.mumble.info/LICENSE>.
Expand Down
1 change: 1 addition & 0 deletions plugins/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ if(WIN32 OR (UNIX AND CMAKE_SYSTEM_NAME STREQUAL "Linux"))
"ffxiv"
"ffxiv_x64"
"gmod"
"grounded"
"gtaiv"
"gtasa"
"gtav"
Expand Down
4 changes: 4 additions & 0 deletions plugins/HostWindows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ HostWindows::~HostWindows() {
}
}

HostWindows::HostWindows(HostWindows &&other) noexcept
: m_pid(other.m_pid), m_handle(std::exchange(other.m_handle, nullptr)) {
}

bool HostWindows::peek(const procptr_t address, void *dst, const size_t size) const {
SIZE_T read;
const auto ok = ReadProcessMemory(m_handle, reinterpret_cast< void * >(address), dst, size, &read);
Expand Down
2 changes: 2 additions & 0 deletions plugins/HostWindows.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ class HostWindows {
Modules modules() const;

HostWindows(const procid_t pid);
HostWindows(const HostWindows &) = delete;
HostWindows(HostWindows &&other) noexcept;
virtual ~HostWindows();
};

Expand Down
1 change: 1 addition & 0 deletions plugins/ProcessBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ class ProcessBase : public Host {
static procid_t find(const std::string &name, const std::multimap< std::wstring, unsigned long long int > &pids);

ProcessBase(const procid_t id, const std::string &name);
ProcessBase(ProcessBase &&other) = default;
virtual ~ProcessBase();
};

Expand Down
1 change: 1 addition & 0 deletions plugins/ProcessWindows.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class ProcessWindows : public ProcessBase {
procptr_t exportedSymbol(const std::string &symbol, const procptr_t module) const override;

ProcessWindows(const procid_t id, const std::string &name);
ProcessWindows(ProcessWindows &&other) = default;
virtual ~ProcessWindows();
};

Expand Down
18 changes: 18 additions & 0 deletions plugins/grounded/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@

# Copyright 2020-2023 The Mumble Developers. All rights reserved.
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file at the root of the
# Mumble source tree or at <https://www.mumble.info/LICENSE>.

add_library(grounded SHARED
"grounded.cpp"

"../Module.cpp"
"../ProcessBase.cpp"
"../ProcessWindows.cpp")

if(WIN32)
target_sources(grounded PRIVATE "../HostWindows.cpp")
else()
target_sources(grounded PRIVATE "../HostLinux.cpp")
endif()
202 changes: 202 additions & 0 deletions plugins/grounded/grounded.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
// Copyright 2024 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.

#include "ProcessWindows.h"
#include "MumblePlugin.h"

#include "mumble_positional_audio_utils.h"

#include <cassert>
#include <cstring>

using GroundedHandle = std::tuple< ProcessWindows, procptr_t >;

static std::unique_ptr< GroundedHandle > handle;

/* the indexes of these float[3] from the game are
* 0: south low, north high
* 1: west low, east high
* 2: altitude, high toward sky, goes up when you jump */
struct GroundedCam {
/* 940 */ float top[3];
std::uint8_t _unused1[4];
/* 950 */ float front[3];
std::uint8_t _unused2[4 * 40];
/* 9fc */ float pos[3];
};

static_assert(sizeof(struct GroundedCam) == 200, "GroundedCam struct has unexpected size");

constexpr float unreal_to_mumble_units(float unreal) {
return unreal / 100.0f;
}

float float3_magnitude(float f[3]) {
return sqrtf(f[0] * f[0] + f[1] * f[1] + f[2] * f[2]);
}

bool float3_is_unit(float f[3]) {
const float err = 0.001f;
const float mag = float3_magnitude(f);
return mag > (1.0f - err) && mag < (1.0f + err);
}


mumble_error_t mumble_init(uint32_t) {
return MUMBLE_STATUS_OK;
}

void mumble_shutdown() {
}

MumbleStringWrapper mumble_getName() {
static const char name[] = "Grounded";

MumbleStringWrapper wrapper;
wrapper.data = name;
wrapper.size = strlen(name);
wrapper.needsReleasing = false;

return wrapper;
}

MumbleStringWrapper mumble_getDescription() {
static const char description[] = "Positional audio support for Grounded. Steam release version 1.4.3.4578.";

MumbleStringWrapper wrapper;
wrapper.data = description;
wrapper.size = strlen(description);
wrapper.needsReleasing = false;

return wrapper;
}

MumbleStringWrapper mumble_getAuthor() {
static const char author[] = "MumbleDevelopers";

MumbleStringWrapper wrapper;
wrapper.data = author;
wrapper.size = strlen(author);
wrapper.needsReleasing = false;

return wrapper;
}

mumble_version_t mumble_getAPIVersion() {
return MUMBLE_PLUGIN_API_VERSION;
}

void mumble_registerAPIFunctions(void *) {
}

void mumble_releaseResource(const void *) {
}

mumble_version_t mumble_getVersion() {
return { 1, 0, 0 };
}

uint32_t mumble_getFeatures() {
return MUMBLE_FEATURE_POSITIONAL;
}

uint8_t mumble_initPositionalData(const char *const *programNames, const uint64_t *programPIDs, size_t programCount) {
const std::string exename = "Maine-Win64-Shipping.exe";

for (size_t i = 0; i < programCount; ++i) {
if (programNames[i] != exename) {
continue;
}

ProcessWindows proc(programPIDs[i], programNames[i]);

if (!proc.isOk()) {
continue;
}

const Modules &modules = proc.modules();
const auto iter = modules.find(exename);

if (iter == modules.cend()) {
continue;
}

/* Look up camera positional data through pointer chain */

procptr_t p = iter->second.baseAddress();

if (!(p = proc.peekPtr(p + 0x0612cb38))) {
continue;
}

if (!(p = proc.peekPtr(p + 0x0))) {
continue;
}

if (!(p = proc.peekPtr(p + 0x8))) {
continue;
}

p += 0x8c0;

GroundedCam _cam;

if (!(proc.peek(p, _cam))) {
continue;
}

handle = std::make_unique< GroundedHandle >(std::move(proc), p);

return MUMBLE_PDEC_OK;
}

return MUMBLE_PDEC_ERROR_TEMP;
}

void mumble_shutdownPositionalData() {
handle.reset();
}

bool mumble_fetchPositionalData(float *avatarPos, float *avatarDir, float *avatarAxis, float *cameraPos,
float *cameraDir, float *cameraAxis, const char **contextPtr,
const char **identityPtr) {
*contextPtr = "";
*identityPtr = "";

ProcessWindows &proc = std::get< 0 >(*handle);
procptr_t camAddr = std::get< 1 >(*handle);

GroundedCam cam;

if (!proc.peek< GroundedCam >(camAddr, cam)) {
std::fill_n(avatarPos, 3, 0.f);
std::fill_n(avatarDir, 3, 0.f);
std::fill_n(avatarAxis, 3, 0.f);

std::fill_n(cameraPos, 3, 0.f);
std::fill_n(cameraDir, 3, 0.f);
std::fill_n(cameraAxis, 3, 0.f);

return false;
}

/* We expect top and front to be unit vectors in the game. */
assert(float3_is_unit(cam.top));
assert(float3_is_unit(cam.front));

avatarAxis[0] = cameraAxis[0] = -cam.top[0];
avatarAxis[1] = cameraAxis[1] = cam.top[2];
avatarAxis[2] = cameraAxis[2] = -cam.top[1];

avatarDir[0] = cameraDir[0] = -cam.front[0];
avatarDir[1] = cameraDir[1] = cam.front[2];
avatarDir[2] = cameraDir[2] = -cam.front[1];

avatarPos[0] = cameraPos[0] = unreal_to_mumble_units(cam.pos[0]);
avatarPos[1] = cameraPos[1] = unreal_to_mumble_units(cam.pos[2]);
avatarPos[2] = cameraPos[2] = unreal_to_mumble_units(cam.pos[1]);

return true;
}

0 comments on commit b4b3122

Please sign in to comment.