Pluginguide
Contents
Introduction
![Icons oxygen 48x48 status task-attention.png](/images/e/ee/Icons_oxygen_48x48_status_task-attention.png)
Game positional audio is a feature of Mumble that many users consider very useful. However, creating the game plugin can sometimes be complicated, and for the average person, daunting. This guide will help you understand how a game plugin works, what it does, and how you can make one.
If you have any questions regarding the process hit us in IRC (#mumble @ freenode) and we will try to help. We also accept new plugins into our codebase as long as you are willing to support them.
This guide is supposed to be a step-by-step tutorial for the general case. For a more abstract view and more methodology take a look at the Hack Positional Audio article.
Prerequisites
Programs needed
Cheating utility
![Icons oxygen 48x48 status task-attention.png](/images/e/ee/Icons_oxygen_48x48_status_task-attention.png)
Note that Mumble does NOT support cheating of any kind. We use these utilities because the interface is easy to use and they fit our purposes; they are simply memory searching tools, required to find the positional addresses in the game.
Windows
- Cheat Engine: Very comfortable, easy to use program to gather addresses. It has everything you need, and more!
- UsaMimi Hurricane: No description
- ArtMoney: No description
Linux
- Cheat Engine server: This server allows you to scan a Linux process through the network using Cheat Engine on Windows. If you don't have a Windows machine, you can use Wine to run Cheat Engine and connect to the server on Linux.
- GameConqueror/scanmem: It's basically the Linux counterpart of Cheat Engine.
- PINCE: It has more advanced features than GameConqueror, but it doesn't scan memory addresses yet.
Tools
C++ IDE and compiler. Read the entire section to know what IDE/Compiler is right for you.
MumblePAHelper. This binary is built with MSVC 2010, it doesn't work with plugins built with other compilers or MSVC versions.
This is a useful tool to quickly see if your plugin is working as it should. Simply place it together with QtCore4.dll and QtGui4.dll (found in the Mumble directory) in your %APPDATA%\Mumble folder and run it while your game is running, and it will show if the plugin is linked, if the positional coordinates are working properly, etc. Note that it will only show the plugins which are present inside %APPDATA%\Mumble\plugins.
Notepad++ (optional). After you install Notepad++, start it, go to Preferences -> New Document/Default Directory, and check "Unix" in the Format box.
Learn a Little C++
Although you do not need to be an expert programmer in order to write a plugin, you do need to understand fundamental data types. Here are a few of the most important:
float: This is the data type that almost all positional audio game addresses use. They are 32 bit, decimal numbers stored in the memory. A float data type is 4 bytes * 8 = 32 bits. An example of a floating point value would be "1234.0123456".
byte: This is the smallest data type in Intel x86-based computing. This type of memory address holds 1 byte of information (1 byte * 8 = 8 bits). From this type of memory address, you can get 0-255 base^10 values, or -127 to 128, depending on whether or not you use a signed byte (it has a + or - on the front of the value), or an unsigned byte (no + or -). An example of a byte value would be "12".
In C++, you must declare a variable before you can use it. If you want to use a float variable, you declare it with
float <variable name>;
If you are pointing to an array, you specify how many addresses are in the array. With a float array, it automatically assumes that each address is 4 bytes away from the other. We can declare a 3 address array using
float <variable name>[3];
declare a byte value using
uint8_t <variable name>;
remember that there is a difference between amount and location. [3] means three addresses, but locations in the memory start from 0. Therefore, the first address in <variable name>[3] is
<variable name>[0]
How a plugin works
Below is a standard template that you can use for your plugin making. The code itself will be explained in the comments that follow.
Template
1 // Copyright 2005-2016 The Mumble Developers. All rights reserved.
2 // Use of this source code is governed by a BSD-style license
3 // that can be found in the LICENSE file at the root of the
4 // Mumble source tree or at <https://www.mumble.info/LICENSE>.
5
6 #include "../mumble_plugin_main.h" // Include standard plugin header.
7
8 static int fetch(float *avatar_pos, float *avatar_front, float *avatar_top, float *camera_pos, float *camera_front, float *camera_top, std::string &context, std::wstring &identity) {
9 for (int i=0;i<3;i++) {
10 avatar_pos[i] = avatar_front[i] = avatar_top[i] = camera_pos[i] = camera_front[i] = camera_top[i] = 0.0f;
11 }
12
13 // Boolean values to check if game addresses retrieval is successful and if the player is in-game
14 bool ok, state;
15 // Create containers to stuff our raw data into, so we can convert it to Mumble's coordinate system
16 float avatar_pos_corrector[3], avatar_front_corrector[3], avatar_top_corrector[3];
17
18 // Peekproc and assign game addresses to our containers, so we can retrieve positional data
19 ok = peekProc(pModule + 0x<offset>, &state, 1) && // Magical state value: 1 when in-game and 0 when in main menu.
20 peekProc(pModule + 0x<offset>, avatar_pos_corrector, 12) && // Avatar Position values (X, Z and Y, respectively).
21 peekProc(pModule + 0x<offset>, avatar_front_corrector, 12) && // Avatar Front Vector values (X, Z and Y, respectively).
22 peekProc(pModule + 0x<offset>, avatar_top_corrector, 12); // Avatar Top Vector values (X, Z and Y, respectively).
23
24 // This prevents the plugin from linking to the game in case something goes wrong during values retrieval from memory addresses.
25 if (! ok) {
26 return false;
27 }
28
29 if (! state) { // If not in-game
30 context.clear(); // Clear context
31 identity.clear(); // Clear identity
32 // Set vectors values to 0.
33 for (int i=0;i<3;i++)
34 avatar_pos[i] = avatar_front[i] = avatar_top[i] = camera_pos[i] = camera_front[i] = camera_top[i] = 0.0f;
35
36 return true; // This tells Mumble to ignore all vectors.
37 }
38
39 /*
40 Mumble | Game
41 X | X
42 Y | Z
43 Z | Y
44 */
45 avatar_pos[0] = avatar_pos_corrector[0];
46 avatar_pos[1] = avatar_pos_corrector[2];
47 avatar_pos[2] = avatar_pos_corrector[1];
48
49 avatar_front[0] = avatar_front_corrector[0];
50 avatar_front[1] = avatar_front_corrector[2];
51 avatar_front[2] = avatar_front_corrector[1];
52
53 avatar_top[0] = avatar_top_corrector[0];
54 avatar_top[1] = avatar_top_corrector[2];
55 avatar_top[2] = avatar_top_corrector[1];
56
57 // Sync camera with avatar
58 for (int i=0;i<3;i++) {
59 avatar_pos[i]/=32.0f; // Scale to meters
60 camera_pos[i] = avatar_pos[i];
61 camera_front[i] = avatar_front[i];
62 camera_top[i] = avatar_top[i];
63 }
64
65 return true;
66 }
67
68 static int trylock(const std::multimap<std::wstring, unsigned long long int> &pids) {
69
70 if (! initialize(pids, L"<executable name>.exe")) { // Retrieve game executable's memory address
71 return false;
72 }
73
74 // Check if we can get meaningful data from it
75 float apos[3], afront[3], atop[3], cpos[3], cfront[3], ctop[3];
76 std::wstring sidentity;
77 std::string scontext;
78
79 if (fetch(apos, afront, atop, cpos, cfront, ctop, scontext, sidentity)) {
80 return true;
81 } else {
82 generic_unlock();
83 return false;
84 }
85 }
86
87 static const std::wstring longdesc() {
88 return std::wstring(L"Supports <game name> version <game version> without context or identity support."); // Plugin long description
89 }
90
91 static std::wstring description(L"<game name> (v<game version>)"); // Plugin short description
92 static std::wstring shortname(L"<game name>"); // Plugin short name
93
94 static int trylock1() {
95 return trylock(std::multimap<std::wstring, unsigned long long int>());
96 }
97
98 static MumblePlugin <game acronym, lowercase>plug = {
99 MUMBLE_PLUGIN_MAGIC,
100 description,
101 shortname,
102 NULL,
103 NULL,
104 trylock1,
105 generic_unlock,
106 longdesc,
107 fetch
108 };
109
110 static MumblePlugin2 <game acronym, lowercase>plug2 = {
111 MUMBLE_PLUGIN_MAGIC_2,
112 MUMBLE_PLUGIN_VERSION,
113 trylock
114 };
115
116 extern "C" MUMBLE_PLUGIN_EXPORT MumblePlugin *getMumblePlugin() {
117 return &<game acronym, lowercase>plug;
118 }
119
120 extern "C" MUMBLE_PLUGIN_EXPORT MumblePlugin2 *getMumblePlugin2() {
121 return &<game acronym, lowercase>plug2;
122 }
Explanation
All that probably looks pretty daunting, right? It isn't really, but even if it does, you actually don't need to understand all of it. You just need to understand the parts that need to be changed in order to make this standard plugin hook to the right game, and fetch the right memory addresses.
First, you need to understand how C++ assignment and functions work. From the code above, let's look at
peekProc(pModule + 0x<offset>, avatar_pos_corrector, 12)
peekProc(pModule + 0x<offset>, avatar_front_corrector, 12)
peekProc(pModule + 0x<offset>, avatar_top_corrector, 12)
You see that avatar_pos_corrector is a three address array. You would point this to the first address in your positional coordinate array in the memory. If you found a static address in the memory for "something.dll + 24acf2", then you would put this line in the code:
procptr_t mod=getModuleAddr(L"something.dll");
And set your peekProc to
peekProc(mod + 0x024acf2, avatar_pos_corrector, 12)
If your game doesn't have static memory addresses from its executable, but only from modules, you could set pModule to the module that has most of the addresses:
if (! initialize(pids, L"game.exe", L"client.dll"))
But, you're still wondering exactly how the plugin uses one address to get several. Well, right here is where the action happens:
ok = peekProc(pModule + 0x<offset>, &state, 1) &&
peekProc(pModule + 0x<offset>, avatar_pos_corrector, 12) &
peekProc(pModule + 0x<offset>, avatar_front_corrector, 12) &&
peekProc(pModule + 0x<offset>, avatar_top_corrector, 12);
You see, in this statement, we pass the three pointers that we assigned to the peekProc function, and then assign the results to the avatar_pos_corrector array. Let's look at this one part:
peekProc(pModule + 0x<offset>, avatar_pos_corrector, 12)
here is what happens: the peekProc function is called and it is instructed to take the first address and add two more. See the "12" at the end? That's the size of the array. Remember that 4 bytes = one float address. 4 * 3 = 12. This means that peekProc sends back three addresses:
avatar_pos_corrector[0] = pModule + 0x<offset>
avatar_pos_corrector[1] = pModule + 0x<offset> + 0x4
avatar_pos_corrector[2] = pModule + 0x<offset> + 0x4 + 0x4
Beginning the Hunt
Introduction
CE = Cheat Engine;
For this game, we will be memory searching the game Alien Arena, an FPS game. If you are trying to create a third-person or camera-based game plugin, you will need to find the avatar positional data and the camera positional data. This is explained further in a few minutes.
Almost all games will have the positional, front, and top coordinates/vectors you need in arrays. This means that the memory addresses will be sequential, one after the other. For instance, 1234ABC0 = X coordinate, 1234ABC4 = Y coordinate, and 1234ABC8 = Z coordinate.
Now it's time for a little Cheat Engine tutorial. Note, again, that Mumble does not support cheating in any way, and this guide does in no way try to teach any cheating methods.
Note that you need to make sure that your server has NO anti-cheat setting enabled, as it might flag Cheat Engine as a hack. NEVER use Cheat Engine on a game that has an anti-cheat method currently engaged, or risk getting banned from that server/game!
If you find a static address, it will either be static from a module, or static from the game executable. If it is static from the game executable, it will be something like
something.exe+123ABC
when you double click on the address.
Explanation of Sound and Coordinate Systems
Mumble, like most sound systems, uses a left handed coordinate system. If you imagine yourself looking over a large empty field; X increases towards your right, Y increases above your head, and Z increases in front of you. In other words, if we place origo in your chest and you strech your arms out to your sides, your right hand will be (1,0,0), your left hand will be (-1,0,0) and your head will be (0,0.2,0). If you then stretch your arms out in front of you instead, they'll become (0,0,1).
We need three vectors. First is the position vector. This should be in meters, but if it isn't, you may need to scale it. If it is not in meters, distance attenuation will be different for each game, meaning users will have a bad experience with positional audio.
These three vectors make what is called a unit vector. Here is an excellent explanation of how a unit vector works. It will help you understand how to convert Azimuth and Heading coordinates into a unit vector that Mumble can use, as well.
The next two vectors are the heading. These should be unit vectors, and should be perpendicular. The first vector is the front vector, which is simply the direction you are looking in. The second is the top vector, which is an imaginary vector pointing straight out the top of your head. If you do not supply a top vector, Mumble will assume you have a "Y-is-up" coordinate system and that the user cannot tilt his head, and then compute the top vector based on that.
Once you have the position, you need to find the heading. Since you now know what is the positive direction of the X axis, position yourself so you are looking straight down it. Your 'front' heading should be (1,0,0), so search for a floating point value between 0.7 and 1.05. Turn 180 degrees and search for a value between -0.7 and -1.05. Repeat for Y and Z.
The top vector is done the exact same way, just look down into the ground when finding X; your head now points along the X axis. Note that some games do not have a top vector; a top vector is only "needed" if the game allows you to tilt your head from side to side.
Hunt
Part 1 - Find the Position Array
- First, start your game. If there is a way to make the game windowed, do so. Usually Googling for "<game name> windowed mode" will get the results you need. If you can start your own server for the game, that is preferred. Now load into a map. The game needs to change as little as possible, so make sure you don't have bots or artificial intelligence players enabled.
- Start Cheat Engine. On the main window, you will see a little computer icon, that is flashing red/green/blue. Click it, find your game executable name on the list, and then double click it. In this case, you would click "crx.exe".
- You are now hooked to the executable. In the main Cheat Engine window, set "Value type" to "Float" and on "Scan type", select "Unknown initial value". Now click "First Scan". Depending on how fast your computer is, this could take from a few seconds to a few minutes.
- Move ingame a little. Move forwards, backwards, whatever.
- Open CE, set "Scan type" to "Changed value", then click "Next Scan".
- Set "Scan type" to "Unchanged value". Wait a little while (10-20 seconds), then click Click "Next Scan" five or six times.
- Go back ingame, move a little, and repeat steps 4 to 6.
- Repeat step 7 a few times.
- Go back ingame, and look around with your mouse. Do NOT press any WASD keys. Repeat step 6.
- At this point, you can begin to analyze the addresses that you see on the left. Try to find any addresses that are green. If you can't, it's still ok. This guide found an address with a value of "802.8125", that kept changing when one moved ingame. Now double click the address, and it will be added to the bottom address box.
So, now you should have a position address. Position addresses are almost always an even number in the memory, in hex, offset by four addresses. So, if you had a memory address of 0x5399010, then click "Add address manually", and in the address field, put 0x5399014. 0x5399010 + 4 hex = 0x5399014. Now add 0x5399018.
The second address should also have a similar looking value, and when you move ingame, it should change accordingly. Depending on how the specific game coordinate system works, the first address might be the X value (east to west), the Y value (up and down), or the Z value (north to south). Jump up and down ingame, and see which value changes the most. That address will be your Y coordinate.
Part 2 - Find the Front Vector
Now it's time to search for the front and top coordinates. These are a little bit tricky, so you will need some patience. First, see if you can figure out which direction "north" is for the map you are on. Although this may not apply to all games, generally the textures on a map are lined up north-south and east-west, perfectly. This means that if you look straight down a wall, you will be looking perfectly in any one of the four cardinal directions.
- front straight north, or straight down a texture, whichever works for you.
- In the main Cheat Engine window, set "Value type" to "Float" and on "Scan type", select "Unknown initial value". Now click "First Scan". Depending on how fast your computer is, this could take from a few seconds to a few minutes.
- Now look a little bit to the left, just move your mouse enough that you can see a change in the pixels.
- Open CE, set "Scan type" to "Changed value", then click "Next Scan".
- Set "Scan type" to "Unchanged value". Wait a little while (10-20 seconds), then click Click "Next Scan" five or six times.
- Go back ingame, move a little, and repeat steps 4 and 5.
- Repeat step 6 two or three times.
- Look straight north or down your wall. Look for a value in the -0.999 or 0.999 range. Move in a circle and see if this decreases or increases, but never gets larger than 0.999, or less than -0.999. By now, the addresses should be narrowed down enough that you should be able to find the right value by just looking through the results list.
Part 3 - Find the Top Vector
In almost any first person game, the top vector will be within 300 hex of your front vector. So, we will set a scan range for CE. Example: front vector pointer is 1234ABC0, so we will make a scan range of 1234A000 to 1234AFFF. In the memory scan options, set your range to these two addresses.
Go ingame and place yourself looking straight forward.
- In the main Cheat Engine window, set "Value type" to "Float" and on "Scan type", select "Unknown initial value". Now click "First Scan".
- Look a little bit down.
- Open CE, set "Scan type" to "Changed value", then click "Next Scan".
- Set "Scan type" to "Unchanged value". Wait a little while (10-20 seconds), then click Click "Next Scan" five or six times.
- Look back up, so your are looking straight at the horizon.
While looking straight toward the horizon, look for a value in the 0.980 to 0.999 range. Now look down at the ground. The value should change to somewhere close to 0 - anywhere between 0.2 and -0.2. Find and add any addresses in that range.
Now add the addresses from the value that you find. Depending on whether or not the coordinate system is left-handed, this could change. In the game that this guide used, the vector component that changed when looking up and down had an address of 05399038, and it was the last address of the vector. So, to get the complete vector, subtract 4 from each address two times, so you would have the following addresses:
05399030
05399034
05399038
Please Note
The Position, Front, and Top vectors are very, very oftentimes right next to each other in memory. If you find the position coordinates, chances are, the rotational ones will be within 100 hex of the former.
Also, note that depending on the game type, all the positional data may be very slightly changing at all times. Therefore, if you cannot find the addresses you are searching for, your game probably falls into this category. If so, you cannot use the "unchanged value" parameter in CE, but must search for relative changes in value.
Part 4 - Find a State Value
This is probably the easiest part. Simple search for a byte value that remains constant, and changes as soon as you load into a map. Assign it using the sample code in Part 6.
Part 5 - Determine the Coordinate System
So, now you should have the three positional components you need:
- The position array
- The front vector array
- The top vector array
But, you will still need to determine how to arrange the coordinates.
In the left handed coordinate system, the X value will increase, as one vector component remains around 0.999. In Alien Arena, the second address in the position array increases as the second address in the front vector array remains at 0.999. So, we know that this is a centered coordinate system. Therefore, if we spawn at (0,0,0), and we front north, and move one meter, our position coordinate system will be (0,1,0). From that, we determine the following: a left-handed coordinate system uses array of type
address[0]
address[1]
address[2]
and a center coordinate system uses the same thing, but offset by 2; it uses
address[0]
address[2]
address[1]
Also, we note that the coordinate system is in Quake units. 1 meter = ~ 32 Quake units, so we will convert it using the following code:
for (int i=0;i<3;i++)
avatar_pos[i]/=32.0f; // Scale to meters
now we will take all this information, and piece together our final plugin code.
Part 6 - Using Pointers
Unfortunately, not all games have static addresses. If yours does not, you will need to perform a pointer scan.
- After you have found your non-static addresses for each of your respective position, front, and top addresses, right click them and click "Pointer scan for this address"; leave the default settings and start the scan.
- After the pointer scan is completed, click Pointer scanner -> Rescan memory and type in the actual memory address you're trying to find a pointer to, then click OK.
- Now it comes down to trial and error. Keep the scan window opened, restart the game and hook Cheat Engine to the process. See if there are pointers that still point to the right address and delete the bad ones by repeating step 2. You can find the updated non-static memory address from a working pointer or by doing a new scan in Cheat Engine. Do this more times to be sure that they are reliable and choose one of them.
After you think you have a reliable pointer, you code it in the fetch() function, above the peekProc part. For example, if I had a pointer of
Level 1 -> Offset CF
Level 2 -> Offset 250
Level 3 -> Offset 230
Level 4 -> something.dll + 242adf
for my avatar_pos, then I would use the following code:
procptr_t avatar_base = peekProcPtr(pModule + 0x0242adf);
if (!avatar_base) return false;
procptr_t avatar_offset_0 = peekProcPtr(avatar_base + 0x230);
if (!avatar_offset_0) return false;
procptr_t avatar_offset_1 = peekProcPtr(avatar_offset_0 + 0x250);
if (!avatar_offset_1) return false;
And then I would change peekProc to this:
peekProc(avatar_offset_1 + 0xCF, avatar_pos_corrector, 12)
Code the Plugin
The comments are marked in the code. Look it over carefully, and pay close attention to the commenting.
1 // Copyright 2005-2016 The Mumble Developers. All rights reserved.
2 // Use of this source code is governed by a BSD-style license
3 // that can be found in the LICENSE file at the root of the
4 // Mumble source tree or at <https://www.mumble.info/LICENSE>.
5
6 #include "../mumble_plugin_main.h" // Include standard plugin header.
7
8 static int fetch(float *avatar_pos, float *avatar_front, float *avatar_top, float *camera_pos, float *camera_front, float *camera_top, std::string &context, std::wstring &identity) {
9 for (int i=0;i<3;i++) {
10 avatar_pos[i] = avatar_front[i] = avatar_top[i] = camera_pos[i] = camera_front[i] = camera_top[i] = 0.0f;
11 }
12
13 // Boolean values to check if game addresses retrieval is successful and if the player is in-game
14 bool ok, state;
15 // Create containers to stuff our raw data into, so we can convert it to Mumble's coordinate system
16 float avatar_pos_corrector[3], avatar_front_corrector[3], avatar_top_corrector[3];
17
18 // Peekproc and assign game addresses to our containers, so we can retrieve positional data
19 ok = peekProc(pModule + 0x5399000, &state, 1) && // Magical state value: 1 when in-game and 0 when in main menu.
20 peekProc(pModule + 0x5399010, avatar_pos_corrector, 12) && // Avatar Position values (X, Z and Y, respectively).
21 peekProc(pModule + 0x5399020, avatar_front_corrector, 12) && // Avatar Front Vector values (X, Z and Y, respectively).
22 peekProc(pModule + 0x5399030, avatar_top_corrector, 12); // Avatar Top Vector values (X, Z and Y, respectively).
23
24 // This prevents the plugin from linking to the game in case something goes wrong during values retrieval from memory addresses.
25 if (! ok) {
26 return false;
27 }
28
29 if (! state) { // If not in-game
30 context.clear(); // Clear context
31 identity.clear(); // Clear identity
32 // Set vectors values to 0.
33 for (int i=0;i<3;i++)
34 avatar_pos[i] = avatar_front[i] = avatar_top[i] = camera_pos[i] = camera_front[i] = camera_top[i] = 0.0f;
35
36 return true; // This tells Mumble to ignore all vectors.
37 }
38
39 /*
40 Mumble | Game
41 X | X
42 Y | Z
43 Z | Y
44 */
45 avatar_pos[0] = avatar_pos_corrector[0];
46 avatar_pos[1] = avatar_pos_corrector[2];
47 avatar_pos[2] = avatar_pos_corrector[1];
48
49 avatar_front[0] = avatar_front_corrector[0];
50 avatar_front[1] = avatar_front_corrector[2];
51 avatar_front[2] = avatar_front_corrector[1];
52
53 avatar_top[0] = avatar_top_corrector[0];
54 avatar_top[1] = avatar_top_corrector[2];
55 avatar_top[2] = avatar_top_corrector[1];
56
57 // Sync camera with avatar
58 for (int i=0;i<3;i++) {
59 avatar_pos[i]/=32.0f; // Scale to meters
60 camera_pos[i] = avatar_pos[i];
61 camera_front[i] = avatar_front[i];
62 camera_top[i] = avatar_top[i];
63 }
64
65 return true;
66 }
67
68 static int trylock(const std::multimap<std::wstring, unsigned long long int> &pids) {
69
70 if (! initialize(pids, L"Game.exe")) { // Retrieve game executable's memory address
71 return false;
72 }
73
74 // Check if we can get meaningful data from it
75 float apos[3], afront[3], atop[3], cpos[3], cfront[3], ctop[3];
76 std::wstring sidentity;
77 std::string scontext;
78
79 if (fetch(apos, afront, atop, cpos, cfront, ctop, scontext, sidentity)) {
80 return true;
81 } else {
82 generic_unlock();
83 return false;
84 }
85 }
86
87 static const std::wstring longdesc() {
88 return std::wstring(L"Supports Game version 1.0 without context or identity support."); // Plugin long description
89 }
90
91 static std::wstring description(L"Game (v1.0)"); // Plugin short description
92 static std::wstring shortname(L"Game"); // Plugin short name
93
94 static int trylock1() {
95 return trylock(std::multimap<std::wstring, unsigned long long int>());
96 }
97
98 static MumblePlugin gameplug = {
99 MUMBLE_PLUGIN_MAGIC,
100 description,
101 shortname,
102 NULL,
103 NULL,
104 trylock1,
105 generic_unlock,
106 longdesc,
107 fetch
108 };
109
110 static MumblePlugin2 gameplug2 = {
111 MUMBLE_PLUGIN_MAGIC_2,
112 MUMBLE_PLUGIN_VERSION,
113 trylock
114 };
115
116 extern "C" MUMBLE_PLUGIN_EXPORT MumblePlugin *getMumblePlugin() {
117 return &gameplug;
118 }
119
120 extern "C" MUMBLE_PLUGIN_EXPORT MumblePlugin2 *getMumblePlugin2() {
121 return &gameplug2;
122 }
Compile the Plugin
You can either build the plugin out of tree, meaning without the rest of the mumble environment around it, or as a part of Mumble. Note that to submit the plugin we prefer a patch against our tree with full integration. However we will do that part for you if you don't want to bother.
Out of tree build (doesn't need a Mumble build environment)
Make a folder for your plugin and then make a subfolder, with your plugin's name. Now download mumble_plugin.h and the right platform header.
You can see the list of available headers here.
Put the files in the first folder and your .cpp game plugin file into the second folder that is inside of the first.
Info on compilers
Mumble 1.3.x is built with MSVC 2015 (Visual Studio 2015 compiler).
Mumble 1.2.x is built with MSVC 2010 (Visual Studio 2010 compiler).
Plugins built with GCC will not work with the version of Mumble distributed from the website.
![Icons oxygen 48x48 status task-attention.png](/images/e/ee/Icons_oxygen_48x48_status_task-attention.png)
Using Qt Creator
Download the right Qt package version from Qt.io. Qt for MSVC 2010 is discontinued, this is the latest version that supports it.
You also have to download Visual C++ 2015 Build Tools (which contains MSVC 2015, for Mumble 1.3.x) or MSBuild 4.0 (MSVC 2010, for Mumble 1.2.x), to install the compiler.
Using Visual Studio
Visual Studio 2015 Community
Visual Studio 2010 Express edition. Default options, except for the SQL server, which you can uncheck.
Start Visual Studio and go to File -> New -> Project. Enter a name, then double click "Win32 Project". Click Next, select "DLL" and check "Empty project". Click Finish. Now open the folder that contains your game's cpp plugin file, and drag that file into the "Source Files" folder on the left. Now click Build -> Batch Build... and check the box in the Build column that corresponds to "Release". Click Build and the plugin will compile. Once it is compiled, go to [My] Documents\Visual Studio 2010\Projects\<project name>\Release. You can take <plugin name>.dll and put it in %AppData%\Mumble\plugins, and when you start Mumble, the plugin will load and you can test it.
In tree build
If you do not have a working build environment yet follow the BuildingWindows or BuildingLinux guide to create one. Once you successfully built Mumble (client suffices) perform the following steps:
- Create a new sub-directory for your plugin in plugins/ named after your plugin (e.g. bf2 for Battlefield 2).
- Name your your primary source file the same as the newly created directory and put it in there.
- Create a <pluginname>.pro file in the new directory. You can use an existing plugin's pro file (e.g. bf2/bf2.pro) as a template.
- Add your plugin sub-directory to the list in plugins/plugins.pro
- Add your plugin to the installer in installer/Plugins.wxs (top and bottom)
- Reconfigure mumble with -recursive and rebuild.
The plugin should now be built as part of mumble.