Skip to content

Instantly share code, notes, and snippets.

@Hiradur
Created December 16, 2015 10:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Hiradur/94bb7414a40043b2a628 to your computer and use it in GitHub Desktop.
Save Hiradur/94bb7414a40043b2a628 to your computer and use it in GitHub Desktop.
diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt
index 4a714e1..a113685 100644
--- a/builtin/settingtypes.txt
+++ b/builtin/settingtypes.txt
@@ -571,6 +571,8 @@ enable_sound (Sound) bool true
sound_volume (Volume) float 0.7 0.0 1.0
+enable_mumble (Mumble positional audio) bool false
+
[*Advanced]
# Timeout for client to remove unused map data from memory.
diff --git a/minetest.conf.example b/minetest.conf.example
index 34d618f..e693d0e 100644
--- a/minetest.conf.example
+++ b/minetest.conf.example
@@ -674,6 +674,9 @@
# type: float min: 0 max: 1
# sound_volume = 0.7
+# type: bool
+# enable_mumble = false
+
## Advanced
# Timeout for client to remove unused map data from memory.
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 6256a85..7a6e955 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -79,6 +79,14 @@ endif()
option(ENABLE_SOUND "Enable sound" TRUE)
set(USE_SOUND FALSE)
+OPTION(ENABLE_MUMBLE "Enable Mumble positional audio" FALSE)
+set(USE_MUMBLE FALSE)
+
+if(ENABLE_MUMBLE)
+ set(USE_MUMBLE TRUE)
+ message(STATUS "Mumble positional audio enabled.")
+endif(ENABLE_MUMBLE)
+
if(BUILD_CLIENT AND ENABLE_SOUND)
# Sound libraries
find_package(OpenAL)
@@ -204,7 +212,6 @@ if(ENABLE_LEVELDB)
endif()
endif(ENABLE_LEVELDB)
-
OPTION(ENABLE_REDIS "Enable Redis backend" TRUE)
set(USE_REDIS FALSE)
diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt
index a1ec37f..b7f5fb6 100644
--- a/src/client/CMakeLists.txt
+++ b/src/client/CMakeLists.txt
@@ -1,5 +1,6 @@
set(client_SRCS
- ${CMAKE_CURRENT_SOURCE_DIR}/clientlauncher.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/clientlauncher.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/mumbleintegration.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tile.cpp
PARENT_SCOPE
)
diff --git a/src/client/mumbleintegration.cpp b/src/client/mumbleintegration.cpp
new file mode 100644
index 0000000..98774c6
--- /dev/null
+++ b/src/client/mumbleintegration.cpp
@@ -0,0 +1,173 @@
+/*
+Minetest
+Copyright (C) 2010-2015 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+// required for USE_MUMBLE
+#include "../cmake_config.h"
+
+#if USE_MUMBLE
+
+#include "mumbleintegration.h"
+
+#include <cstring>
+#include <sstream>
+#ifdef WIN32
+ #include <windows.h>
+#else
+ #include <sys/mman.h>
+ #include <fcntl.h> /* For O_* constants */
+ #include <unistd.h>
+#endif // WIN32
+
+
+
+MumbleIntegration::MumbleIntegration() : lm(NULL)
+{
+ initMumble();
+}
+
+MumbleIntegration::~MumbleIntegration()
+{
+ #ifdef WIN32
+ if (map_object != NULL) {
+ CloseHandle(hMapObject);
+ map_object = NULL;
+ }
+ #else
+ if (shmfd > 0) {
+ close(shmfd);
+ shmfd = 0;
+ }
+ #endif
+}
+
+void MumbleIntegration::initMumble()
+{
+#ifdef WIN32
+ map_object = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, L"MumbleLink");
+ if (map_object == NULL)
+ return;
+
+ lm = (LinkedMem *) MapViewOfFile(hMapObject, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(LinkedMem));
+ if (lm == NULL) {
+ CloseHandle(map_object);
+ map_object = NULL;
+ return;
+ }
+#else
+ char memname[256];
+ int size = sizeof(struct LinkedMem);
+ snprintf(memname, 256, "/MumbleLink.%d", getuid());
+
+ shmfd = shm_open(memname, O_RDWR, S_IRUSR | S_IWUSR);
+
+ if (shmfd < 0) {
+ perror("shm_open in MumbleIntegration");
+ return;
+ }
+
+ ftruncate(shmfd, size);
+ lm = (LinkedMem *)(mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0));
+
+ if (lm == (void *)(-1)) {
+ lm = NULL;
+ return;
+ }
+#endif // WIN32
+}
+
+void MumbleIntegration::updateContext(std::string *address, u16 port, std::string playername)
+{
+ if (! lm)
+ return;
+ // Context is equal for players on the same server
+ //TODO allow mods to append something to allow for teams
+ std::stringstream contextstringstream;
+ contextstringstream << (*address) << ":" << port;
+ std::string context = contextstringstream.str();
+ memcpy(lm->context, context.c_str(), context.length());
+ lm->context_len = context.length();
+
+ // Identifier which uniquely identifies the player on the server (nicknames are unique per server)
+ std::wstring wplayername;
+ wplayername.assign(playername.begin(), playername.end());
+ wcsncpy(lm->identity, wplayername.c_str(), 256);
+}
+
+void MumbleIntegration::updatePosition(v3f avatar_pos, v3f avatar_dir, v3f avatar_up, v3f camera_pos, v3f camera_dir, v3f camera_up)
+{
+ if (! lm)
+ return;
+
+ if (lm->version != 2) {
+ wcsncpy(lm->name, L"Minetest", 256);
+ wcsncpy(lm->description, L"Links Minetest to Mumble for positional audio", 2048);
+ lm->version = 2;
+ }
+ lm->tick++;
+
+ // Left handed coordinate system.
+ // X positive towards "right".
+ // Y positive towards "up".
+ // Z positive towards "front".
+ //
+ // 1 unit = 1 meter
+
+ // unit vectors are required
+ avatar_dir = avatar_dir.normalize();
+ avatar_up = avatar_up.normalize();
+ camera_dir = camera_dir.normalize();
+ camera_up = camera_up.normalize();
+
+ // Position of the avatar
+ lm->avatar_position[0] = avatar_pos.X;
+ lm->avatar_position[1] = avatar_pos.Y;
+ lm->avatar_position[2] = avatar_pos.Z;
+
+ // Unit vector pointing out of the avatars eyes
+ lm->avatar_front[0] = avatar_dir.X;
+ lm->avatar_front[1] = avatar_dir.Y;
+ lm->avatar_front[2] = avatar_dir.Z;
+
+ // Unit vector pointing out of the top of the avatars head
+ lm->avatar_top[0] = avatar_up.X;
+ lm->avatar_top[1] = avatar_up.Y;
+ lm->avatar_top[2] = avatar_up.Z;
+
+ // Same as avatar but for the camera.
+ lm->camera_position[0] = camera_pos.X;
+ lm->camera_position[1] = camera_pos.Y;
+ lm->camera_position[2] = camera_pos.Z;
+
+ lm->camera_front[0] = camera_dir.X;
+ lm->camera_front[1] = camera_dir.Y;
+ lm->camera_front[2] = camera_dir.Z;
+
+ lm->camera_top[0] = camera_up.X;
+ lm->camera_top[1] = camera_up.Y;
+ lm->camera_top[2] = camera_up.Z;
+}
+
+void MumbleIntegration::reset()
+{
+ v3f vz = v3f(0,0,0);
+ // set Mumble to non-positional audio
+ updatePosition(vz, vz, vz, vz, vz, vz);
+}
+
+#endif // USE_MUMBLE
diff --git a/src/client/mumbleintegration.h b/src/client/mumbleintegration.h
new file mode 100644
index 0000000..2ed9205
--- /dev/null
+++ b/src/client/mumbleintegration.h
@@ -0,0 +1,102 @@
+/*
+Minetest
+Copyright (C) 2010-2015 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "../cmake_config.h"
+
+#if USE_MUMBLE
+#pragma once
+
+#include "../irrlichttypes_bloated.h"
+
+#include <string>
+
+/*
+ Class which establishes a link to the VOIP software Mumble to
+ transmit positional data to other Mumble clients so voices
+ are heard from their relative ingame position.
+ There should be only one instance of this class at runtime.
+*/
+class MumbleIntegration
+{
+public:
+ MumbleIntegration();
+ ~MumbleIntegration();
+
+ void updatePosition(v3f avatar_pos, v3f avatar_dir, v3f avatar_up, v3f camera_pos, v3f camera_dir, v3f camera_up);
+ void updateContext(std::string *address, u16 port, std::string playername);
+ void reset();
+
+private:
+ void initMumble();
+
+ struct LinkedMem
+ {
+
+ u32 version;
+ u32 tick;
+ float avatar_position[3];
+ float avatar_front[3];
+ float avatar_top[3];
+ wchar_t name[256];
+ float camera_position[3];
+ float camera_front[3];
+ float camera_top[3];
+ wchar_t identity[256];
+ u32 context_len;
+ unsigned char context[256];
+ wchar_t description[2048];
+ /* TODO: remove this if tests with above struct succeed
+ #ifdef WIN32
+ UINT32 version;
+ DWORD tick;
+ #else
+ uint32_t version;
+ uint32_t tick;
+ #endif
+
+ float avatar_position[3];
+ float avatar_front[3];
+ float avatar_top[3];
+ wchar_t name[256];
+ float camera_position[3];
+ float camera_front[3];
+ float camera_top[3];
+ wchar_t identity[256];
+
+ #ifdef WIN32
+ UINT32 context_len;
+ #else
+ uint32_t context_len;
+ #endif
+
+ unsigned char context[256];
+ wchar_t description[2048];
+ */
+ };
+
+ LinkedMem *lm;
+
+ #ifdef WIN32
+ HANDLE map_object;
+ #else
+ int shmfd;
+ #endif
+};
+
+#endif //USE_MUMBLE
diff --git a/src/cmake_config.h.in b/src/cmake_config.h.in
index 018532d..64dce08 100644
--- a/src/cmake_config.h.in
+++ b/src/cmake_config.h.in
@@ -18,6 +18,7 @@
#cmakedefine01 USE_GETTEXT
#cmakedefine01 USE_CURL
#cmakedefine01 USE_SOUND
+#cmakedefine01 USE_MUMBLE
#cmakedefine01 USE_FREETYPE
#cmakedefine01 USE_CURSES
#cmakedefine01 USE_LEVELDB
diff --git a/src/game.cpp b/src/game.cpp
index 5e4f4ca..8283b6b 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -64,6 +64,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "sound_openal.h"
#endif
+#if USE_MUMBLE
+ #include "client/mumbleintegration.h"
+#endif
+
#ifdef HAVE_TOUCHSCREENGUI
#include "touchscreengui.h"
#endif
@@ -1569,6 +1573,9 @@ class Game {
ISoundManager *sound;
bool sound_is_dummy;
SoundMaker *soundmaker;
+ #if USE_MUMBLE
+ MumbleIntegration *mumble_link;
+ #endif
ChatBackend *chat_backend;
@@ -1653,6 +1660,9 @@ Game::Game() :
sound(NULL),
sound_is_dummy(false),
soundmaker(NULL),
+ #if USE_MUMBLE
+ mumble_link(NULL),
+ #endif
chat_backend(NULL),
current_formspec(NULL),
eventmgr(NULL),
@@ -1701,6 +1711,9 @@ Game::~Game()
delete soundmaker;
if (!sound_is_dummy)
delete sound;
+ #if USE_MUMBLE
+ delete mumble_link;
+ #endif
delete server; // deleted first to stop all server threads
@@ -1769,6 +1782,17 @@ bool Game::startup(bool *kill,
if (!createClient(playername, password, address, port))
return false;
+ #if USE_MUMBLE
+ /* Mumble Link
+ */
+ if (g_settings->getBool("enable_mumble")) {
+ if (mumble_link == NULL)
+ mumble_link = new MumbleIntegration();
+
+ mumble_link->updateContext(address, port, client->getEnv().getLocalPlayer()->getName());
+ }
+ #endif
+
return true;
}
@@ -1860,6 +1884,23 @@ void Game::run()
flags.show_hud, flags.show_debug);
updateFrame(highlight_boxes, &graph, &stats, &runData, dtime,
flags, cam_view);
+ #if USE_MUMBLE
+ if(g_settings->getBool("enable_mumble"))
+ if(mumble_link != NULL) {
+ LocalPlayer *avatar = client->getEnv().getLocalPlayer();
+ v3f avatar_pos = avatar->getEyePosition();
+ // TODO: calculate from pitch and yaw
+ v3f avatar_dir = camera->getDirection();
+ v3f avatar_up = camera->getCameraNode()->getUpVector();
+
+ v3f camera_pos = camera->getPosition();
+ v3f camera_dir = camera->getDirection();
+ v3f camera_up = camera->getCameraNode()->getUpVector();
+
+ mumble_link->updatePosition(avatar_pos, avatar_dir, avatar_up,
+ camera_pos, camera_dir, camera_up);
+ }
+ #endif
updateProfilerGraphs(&graph);
// Update if minimap has been disabled by the server
@@ -1881,6 +1922,12 @@ void Game::shutdown()
if (sky)
sky->drop();
+ #if USE_MUMBLE
+ if(g_settings->getBool("enable_mumble"))
+ if(mumble_link != NULL)
+ mumble_link->reset();
+ #endif
+
/* cleanup menus */
while (g_menumgr.menuCount() > 0) {
g_menumgr.m_stack.front()->setVisible(false);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment