diff --git a/plugins/l4d2/l4d2.cpp b/plugins/l4d2/l4d2.cpp index b05a399ca..1a2748226 100644 --- a/plugins/l4d2/l4d2.cpp +++ b/plugins/l4d2/l4d2.cpp @@ -1,3 +1,8 @@ +// Copyright 2005-2016 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 . + /* Copyright (C) 2005-2012, Thorvald Natvig Copyright (C) 2012, dark_skeleton (d-rez) @@ -31,48 +36,29 @@ #include "../mumble_plugin_win32.h" +/* DESCRIPTION ADDRESS TYPE VALUE + + position tuple: client.dll+0x774B40 float (x, y, z location in inches) + front tuple: client.dll+0x774BA0 float (x, y, z as unit vector in direction you are facing) + top tuple: client.dll+0x774BD0 float (x, y, z as unit vector pointing out top of head) + state: client.dll+0x772ACC byte (0 in menu; non-zero in game) + context: client.dll+0x772ACC str (see context support below for its possible values) +*/ + static BYTE *posptr; -static BYTE *rotptr; +static BYTE *frontptr; +static BYTE *topptr; static BYTE *stateptr; static BYTE *contextptr; -static bool calcout(float *pos, float *rot, float *opos, float *front, float *top) { - float h = rot[0]; - float v = rot[1]; - - if ((v < -180.0f) || (v > 180.0f) || (h < -180.0f) || (h > 180.0f)) - return false; - - h *= static_cast(M_PI / 180.0f); - v *= static_cast(M_PI / 180.0f); - - // Seems L4D is in inches. INCHES?!? - opos[0] = pos[0] / 39.37f; - opos[1] = pos[2] / 39.37f; - opos[2] = pos[1] / 39.37f; - - front[0] = cos(v) * cos(h); - front[1] = -sin(h); - front[2] = sin(v) * cos(h); - - h -= static_cast(M_PI / 2.0f); - - top[0] = cos(v) * cos(h); - top[1] = -sin(h); - top[2] = sin(v) * cos(h); - /* - printf("Poll\n"); - printf("%f %f %f : %f %f\n",pos[0],pos[1],pos[2], rot[0], rot[1]); - printf("%f %f %f :: %.2f %.2f %.2f :: %.2f %.2f %.2f\n", opos[0], opos[1], opos[2], front[0], front[1], front[2], top[0], top[1], top[2]); - */ - return true; -} +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*/); static int trylock(const std::multimap &pids) { - posptr = rotptr = stateptr = contextptr = NULL; + posptr = frontptr = topptr = stateptr = contextptr = NULL; if (! initialize(pids, L"left4dead2.exe", L"client.dll")) return false; + /* Some hints to make things easier next time valve updates this game: use Cheat Engine (non-network single player or non VAC-secured servers to be safe) @@ -82,32 +68,24 @@ static int trylock(const std::multimap &pi speed things up by limiting the scan range to 40000000 to 90000000 (hex number) you need addresses relative to client.dll. You can get address by double clicking on the address. - pos: float likely in a range of 0 to 10000 (changes if you move. constant if you view around) - rot: float in range of -180 to 180. If you look up the value is -89.0 . If you look down it is 89.0 (changes if you viewaround. constant if you only move) - state: single player: search for loopback. Go back to menu. There is likely only one instance which has the string when having a game running and empty when not running a game. - context: same as state appearantly + pos: float likely in a range of 0 to 10000 (changes if you move. constant if you view around.) + front: float in range of -1 to 1. (changes if you move your camera. constant if you do not.) + top: float in range of -1 to 1. (changes if you move your camera. constant if you do not.) + state: single player -> search for "loopback:0" + public game -> search for server ip "xxx.xxx.xxx.xxx:yyyyy" + menu -> empty string "" + context: same as state (they are used differently) */ - posptr = pModule + 0x8217D0; - rotptr = pModule + 0x762E04; - stateptr = pModule + 0x81CB4C; - contextptr = pModule + 0x81CB4C; + float apos[3], afront[3], atop[3]; + float cpos[3], cfront[3], ctop[3]; + std::string context; + std::wstring identity; - float pos[3]; - float rot[3]; - char state, _context[21]; - bool ok = peekProc(posptr, pos, 12) && - peekProc(rotptr, rot, 12) && - peekProc(stateptr, &state, 1) && - peekProc(contextptr, _context); - - if (ok) { - float opos[3], top[3], front[3]; - return calcout(pos, rot, opos, top, front); - } + if (fetch(apos, afront, atop, cpos, cfront, ctop, context, identity)) + return true; generic_unlock(); - return false; } @@ -115,60 +93,85 @@ static int fetch(float *avatar_pos, float *avatar_front, float *avatar_top, floa for (int i=0;i<3;i++) avatar_pos[i] = avatar_front[i] = avatar_top[i] = camera_pos[i] = camera_front[i] = camera_top[i] = 0.0f; - float ipos[3], rot[3]; + float pos[3], front[3], top[3]; bool ok; char state; char _context[21]; + + // when valve updates the game and breaks the plugin, these following 5 addresses will need changed + // nothing else should need to be modified + posptr = pModule + 0x774B40; + frontptr = pModule + 0x774BA0; + topptr = pModule + 0x774BD0; + stateptr = pModule + 0x772ACC; + contextptr = pModule + 0x772ACC; - // stateptr returns byte values: 0 when map is not loaded; first character in hostname when map is loaded - ok = peekProc(posptr, ipos, 12) && - peekProc(rotptr, rot, 12) && + ok = peekProc(posptr, pos, 12) && + peekProc(frontptr, front, 12) && + peekProc(topptr, top, 12) && peekProc(stateptr, &state, 1) && peekProc(contextptr, _context); + // in menu -> disable plugin if (state == 0) { context = std::string(""); // clear context - return true; // This results in all vectors beeing zero which tells Mumble to ignore them. + return true; // This results in all vectors being zero which tells Mumble to ignore them. } + + if(!ok) + return false; + + // convert all vectors from right handed coordinate system to left handed coordinate system + // L4D2 is in inches so convert to meters + avatar_pos[0] = pos[0] / 39.37f; + avatar_pos[1] = pos[2] / 39.37f; + avatar_pos[2] = pos[1] / 39.37f; + + avatar_front[0] = front[0]; + avatar_front[1] = front[2]; + avatar_front[2] = front[1]; + + avatar_top[0] = top[0]; + avatar_top[1] = top[2]; + avatar_top[2] = top[1]; + + for (int i=0;i<3;++i) { + camera_pos[i] = avatar_pos[i]; + camera_front[i] = avatar_front[i]; + camera_top[i] = avatar_top[i]; - if (ok) { - int res = calcout(ipos, rot, avatar_pos, avatar_front, avatar_top); - if (res) { - for (int i=0;i<3;++i) { - camera_pos[i] = avatar_pos[i]; - camera_front[i] = avatar_front[i]; - camera_top[i] = avatar_top[i]; - - // Example only -- only set these when you have sane values, and make sure they're pretty constant (every change causes a sever message). - //context = std::string("server/map/blah"); - //identity = std::wstring(L"STEAM_1:2:3456789"); - } - - _context[sizeof(_context) - 1] = '\0'; - std::string sHost(_context); - // This string can be either "xxx.xxx.xxx.xxx:yyyyy" (or shorter), "loopback:0" or "" (empty) when in menus. Hence 21 size for char. - if (!sHost.empty()) - { - if (sHost.find("loopback") == std::string::npos) - { - std::ostringstream newcontext; - newcontext << "{\"ipport\": \"" << sHost << "\"}"; - context = newcontext.str(); - } - - } - return res; + // Example only -- only set these when you have sane values, and make sure they're pretty constant (every change causes a sever message). + //context = std::string("server/map/blah"); + //identity = std::wstring(L"STEAM_1:2:3456789"); + } + + // context support + // used to disable positional audio when people are on different servers + _context[sizeof(_context) - 1] = '\0'; + std::string sHost(_context); + // this string will change depending on your context: + // if in public game then server ip -> "xxx.xxx.xxx.xxx:yyyyy" + // if in single player then loopback -> "loopback:0" + // if in menu then empty -> "" + if (!sHost.empty()) + { + if (sHost.find("loopback") == std::string::npos) + { + std::ostringstream newcontext; + newcontext << "{\"ipport\": \"" << sHost << "\"}"; + context = newcontext.str(); } + } - return false; + return true; } static const std::wstring longdesc() { - return std::wstring(L"Supports L4D2 version 2.1.4.4 with context support. No identity support yet."); + return std::wstring(L"Supports L4D2 version 2.1.4.5 with context support. No identity support yet."); } -static std::wstring description(L"Left 4 Dead 2 (version 2.1.4.4)"); +static std::wstring description(L"Left 4 Dead 2 (version 2.1.4.5)"); static std::wstring shortname(L"Left 4 Dead 2"); static int trylock1() {