mirror of
https://github.com/alliedmodders/amxmodx.git
synced 2024-12-25 06:15:37 +03:00
Removing files for a r3wr1t3
This commit is contained in:
parent
5309189602
commit
46bd9127fb
@ -1,413 +0,0 @@
|
|||||||
/* AMX Mod X
|
|
||||||
*
|
|
||||||
* by the AMX Mod X Development Team
|
|
||||||
* originally developed by OLO
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by the
|
|
||||||
* Free Software Foundation; either version 2 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
|
|
||||||
* General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
* In addition, as a special exception, the author gives permission to
|
|
||||||
* link the code of this program with the Half-Life Game Engine ("HL
|
|
||||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
|
||||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
|
||||||
* respects for all of the code used other than the HL Engine and MODs
|
|
||||||
* from Valve. If you modify this file, you may extend this exception
|
|
||||||
* to your version of the file, but you are not obligated to do so. If
|
|
||||||
* you do not wish to do so, delete this exception statement from your
|
|
||||||
* version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _INCLUDE_CSTRING_H
|
|
||||||
#define _INCLUDE_CSTRING_H
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
//by David "BAILOPAN" Anderson
|
|
||||||
class String
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
String()
|
|
||||||
{
|
|
||||||
v = NULL;
|
|
||||||
a_size = 0;
|
|
||||||
//assign("");
|
|
||||||
}
|
|
||||||
|
|
||||||
~String()
|
|
||||||
{
|
|
||||||
if (v)
|
|
||||||
delete [] v;
|
|
||||||
}
|
|
||||||
|
|
||||||
String(const char *src)
|
|
||||||
{
|
|
||||||
v = NULL;
|
|
||||||
a_size = 0;
|
|
||||||
assign(src);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char * _fread(FILE *fp)
|
|
||||||
{
|
|
||||||
Grow(512, false);
|
|
||||||
char *ret = fgets(v, 511, fp);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
String(const String &src)
|
|
||||||
{
|
|
||||||
v = NULL;
|
|
||||||
a_size = 0;
|
|
||||||
assign(src.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *c_str() { return v?v:""; }
|
|
||||||
|
|
||||||
const char *c_str() const { return v?v:""; }
|
|
||||||
|
|
||||||
void append(const char *t)
|
|
||||||
{
|
|
||||||
Grow(size() + strlen(t) + 1);
|
|
||||||
strcat(v, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
void append(const char c)
|
|
||||||
{
|
|
||||||
size_t len = size();
|
|
||||||
Grow(len + 2);
|
|
||||||
v[len] = c;
|
|
||||||
v[len + 1] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
void append(String &d)
|
|
||||||
{
|
|
||||||
append(d.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void assign(const String &src)
|
|
||||||
{
|
|
||||||
assign(src.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void assign(const char *d)
|
|
||||||
{
|
|
||||||
if (!d)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
} else {
|
|
||||||
size_t len = strlen(d);
|
|
||||||
Grow(len + 1, false);
|
|
||||||
memcpy(v, d, len);
|
|
||||||
v[len] = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
if (v)
|
|
||||||
v[0] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
int compare (const char *d) const
|
|
||||||
{
|
|
||||||
if (!v)
|
|
||||||
return strcmp("", d);
|
|
||||||
else
|
|
||||||
return strcmp(v, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Added this for amxx inclusion
|
|
||||||
bool empty() const
|
|
||||||
{
|
|
||||||
if (!v)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (v[0] == '\0')
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t size() const
|
|
||||||
{
|
|
||||||
if (v)
|
|
||||||
return strlen(v);
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int find(const char c, int index = 0)
|
|
||||||
{
|
|
||||||
int len = static_cast<int>(size());
|
|
||||||
if (len < 1)
|
|
||||||
return npos;
|
|
||||||
if (index >= len || index < 0)
|
|
||||||
return npos;
|
|
||||||
int i = 0;
|
|
||||||
for (i=index; i<len; i++)
|
|
||||||
{
|
|
||||||
if (v[i] == c)
|
|
||||||
{
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return npos;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_space(int c)
|
|
||||||
{
|
|
||||||
if (c == '\f' || c == '\n' ||
|
|
||||||
c == '\t' || c == '\r' ||
|
|
||||||
c == '\v' || c == ' ')
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reparse_newlines()
|
|
||||||
{
|
|
||||||
size_t len = size();
|
|
||||||
int offs = 0;
|
|
||||||
char c;
|
|
||||||
if (!len)
|
|
||||||
return;
|
|
||||||
for (size_t i=0; i<len; i++)
|
|
||||||
{
|
|
||||||
c = v[i];
|
|
||||||
if (c == '^' && (i != len-1))
|
|
||||||
{
|
|
||||||
c = v[++i];
|
|
||||||
if (c == 'n')
|
|
||||||
c = '\n';
|
|
||||||
else if (c == 't')
|
|
||||||
c = '\t';
|
|
||||||
offs++;
|
|
||||||
}
|
|
||||||
v[i-offs] = c;
|
|
||||||
}
|
|
||||||
v[len-offs] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
void trim()
|
|
||||||
{
|
|
||||||
if (!v)
|
|
||||||
return;
|
|
||||||
|
|
||||||
unsigned int i = 0;
|
|
||||||
unsigned int j = 0;
|
|
||||||
size_t len = strlen(v);
|
|
||||||
|
|
||||||
if (len == 1)
|
|
||||||
{
|
|
||||||
if (is_space(v[i]))
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char c0 = v[0];
|
|
||||||
|
|
||||||
if (is_space(c0))
|
|
||||||
{
|
|
||||||
for (i=0; i<len; i++)
|
|
||||||
{
|
|
||||||
if (!is_space(v[i]) || (is_space(v[i]) && ((unsigned char)i==len-1)))
|
|
||||||
{
|
|
||||||
erase(0, i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
len = strlen(v);
|
|
||||||
|
|
||||||
if (len < 1)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_space(v[len-1]))
|
|
||||||
{
|
|
||||||
for (i=len-1; i>=0; i--)
|
|
||||||
{
|
|
||||||
if (!is_space(v[i])
|
|
||||||
|| (is_space(v[i]) && i==0))
|
|
||||||
{
|
|
||||||
erase(i+1, j);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len == 1)
|
|
||||||
{
|
|
||||||
if (is_space(v[0]))
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void erase(unsigned int start, int num = npos)
|
|
||||||
{
|
|
||||||
if (!v)
|
|
||||||
return;
|
|
||||||
unsigned int i = 0;
|
|
||||||
size_t len = size();
|
|
||||||
//check for bounds
|
|
||||||
if (num == npos || start+num > len-start)
|
|
||||||
num = len - start;
|
|
||||||
//do the erasing
|
|
||||||
bool copyflag = false;
|
|
||||||
for (i=0; i<len; i++)
|
|
||||||
{
|
|
||||||
if (i>=start && i<start+num)
|
|
||||||
{
|
|
||||||
if (i+num < len)
|
|
||||||
{
|
|
||||||
v[i] = v[i+num];
|
|
||||||
} else {
|
|
||||||
v[i] = 0;
|
|
||||||
}
|
|
||||||
copyflag = true;
|
|
||||||
} else if (copyflag) {
|
|
||||||
if (i+num < len)
|
|
||||||
{
|
|
||||||
v[i] = v[i+num];
|
|
||||||
} else {
|
|
||||||
v[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
len -= num;
|
|
||||||
v[len] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
String substr(unsigned int index, int num = npos)
|
|
||||||
{
|
|
||||||
if (!v)
|
|
||||||
{
|
|
||||||
String b("");
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
String ns;
|
|
||||||
|
|
||||||
size_t len = size();
|
|
||||||
|
|
||||||
if (index >= len || !v)
|
|
||||||
return ns;
|
|
||||||
|
|
||||||
if (num == npos)
|
|
||||||
{
|
|
||||||
num = len - index;
|
|
||||||
} else if (index+num >= len) {
|
|
||||||
num = len - index;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int i = 0;
|
|
||||||
unsigned int nslen = num + 2;
|
|
||||||
|
|
||||||
ns.Grow(nslen);
|
|
||||||
|
|
||||||
for (i=index; i<index+num; i++)
|
|
||||||
ns.append(v[i]);
|
|
||||||
|
|
||||||
return ns;
|
|
||||||
}
|
|
||||||
|
|
||||||
void toLower()
|
|
||||||
{
|
|
||||||
if (!v)
|
|
||||||
return;
|
|
||||||
unsigned int i = 0;
|
|
||||||
size_t len = strlen(v);
|
|
||||||
for (i=0; i<len; i++)
|
|
||||||
{
|
|
||||||
if (v[i] >= 65 && v[i] <= 90)
|
|
||||||
v[i] &= ~(1<<5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String & operator = (const String &src)
|
|
||||||
{
|
|
||||||
assign(src);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
String & operator = (const char *src)
|
|
||||||
{
|
|
||||||
assign(src);
|
|
||||||
return *this;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
char operator [] (unsigned int index)
|
|
||||||
{
|
|
||||||
if (index > size() || !v)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
return v[index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int at(int a)
|
|
||||||
{
|
|
||||||
if (a < 0 || a >= (int)size() || !v)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return v[a];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool at(int at, char c)
|
|
||||||
{
|
|
||||||
if (at < 0 || at >= (int)size() || !v)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
v[at] = c;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void Grow(unsigned int d, bool copy=true)
|
|
||||||
{
|
|
||||||
if (d <= a_size)
|
|
||||||
return;
|
|
||||||
char *n = new char[d + 1];
|
|
||||||
if (copy && v)
|
|
||||||
strcpy(n, v);
|
|
||||||
if (v)
|
|
||||||
delete [] v;
|
|
||||||
else
|
|
||||||
strcpy(n, "");
|
|
||||||
v = n;
|
|
||||||
a_size = d + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *v;
|
|
||||||
unsigned int a_size;
|
|
||||||
public:
|
|
||||||
static const int npos = -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //_INCLUDE_CSTRING_H
|
|
@ -1,491 +0,0 @@
|
|||||||
/* AMX Mod X
|
|
||||||
*
|
|
||||||
* by the AMX Mod X Development Team
|
|
||||||
* originally developed by OLO
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by the
|
|
||||||
* Free Software Foundation; either version 2 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
|
|
||||||
* General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
* In addition, as a special exception, the author gives permission to
|
|
||||||
* link the code of this program with the Half-Life Game Engine ("HL
|
|
||||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
|
||||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
|
||||||
* respects for all of the code used other than the HL Engine and MODs
|
|
||||||
* from Valve. If you modify this file, you may extend this exception
|
|
||||||
* to your version of the file, but you are not obligated to do so. If
|
|
||||||
* you do not wish to do so, delete this exception statement from your
|
|
||||||
* version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __CVECTOR_H__
|
|
||||||
#define __CVECTOR_H__
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
// Vector
|
|
||||||
template <class T> class CVector
|
|
||||||
{
|
|
||||||
bool Grow()
|
|
||||||
{
|
|
||||||
// automatic grow
|
|
||||||
size_t newSize = m_Size * 2;
|
|
||||||
if (newSize == 0)
|
|
||||||
newSize = 8; // a good init value
|
|
||||||
T *newData = new T[newSize];
|
|
||||||
if (!newData)
|
|
||||||
return false;
|
|
||||||
if (m_Data)
|
|
||||||
{
|
|
||||||
for (size_t i=0; i<m_CurrentUsedSize; i++)
|
|
||||||
newData[i] = m_Data[i];
|
|
||||||
delete [] m_Data;
|
|
||||||
}
|
|
||||||
m_Data = newData;
|
|
||||||
m_Size = newSize;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GrowIfNeeded()
|
|
||||||
{
|
|
||||||
if (m_CurrentUsedSize >= m_Size)
|
|
||||||
return Grow();
|
|
||||||
else
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ChangeSize(size_t size)
|
|
||||||
{
|
|
||||||
// change size
|
|
||||||
if (size == m_Size)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (!size)
|
|
||||||
{
|
|
||||||
if (m_Data)
|
|
||||||
{
|
|
||||||
delete [] m_Data;
|
|
||||||
m_Data = NULL;
|
|
||||||
m_Size = 0;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
T *newData = new T[size];
|
|
||||||
if (!newData)
|
|
||||||
return false;
|
|
||||||
if (m_Data)
|
|
||||||
{
|
|
||||||
size_t end = (m_CurrentUsedSize < size) ? (m_CurrentUsedSize) : size;
|
|
||||||
for (size_t i=0; i<end; i++)
|
|
||||||
newData[i] = m_Data[i];
|
|
||||||
delete [] m_Data;
|
|
||||||
}
|
|
||||||
m_Data = newData;
|
|
||||||
m_Size = size;
|
|
||||||
if (m_CurrentUsedSize > m_Size)
|
|
||||||
m_CurrentUsedSize = m_Size;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FreeMemIfPossible()
|
|
||||||
{
|
|
||||||
if (!m_Data)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!m_CurrentUsedSize)
|
|
||||||
{
|
|
||||||
ChangeSize(0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t newSize = m_Size;
|
|
||||||
while (m_CurrentUsedSize <= newSize / 2)
|
|
||||||
newSize /= 2;
|
|
||||||
|
|
||||||
if (newSize != m_Size)
|
|
||||||
ChangeSize(newSize);
|
|
||||||
}
|
|
||||||
protected:
|
|
||||||
T *m_Data;
|
|
||||||
size_t m_Size;
|
|
||||||
size_t m_CurrentUsedSize;
|
|
||||||
public:
|
|
||||||
class iterator
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
T *m_Ptr;
|
|
||||||
public:
|
|
||||||
// constructors / destructors
|
|
||||||
iterator()
|
|
||||||
{
|
|
||||||
m_Ptr = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator(T * ptr)
|
|
||||||
{
|
|
||||||
m_Ptr = ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// member functions
|
|
||||||
T * base()
|
|
||||||
{
|
|
||||||
return m_Ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const T * base() const
|
|
||||||
{
|
|
||||||
return m_Ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// operators
|
|
||||||
T & operator*()
|
|
||||||
{
|
|
||||||
return *m_Ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
T * operator->()
|
|
||||||
{
|
|
||||||
return m_Ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator & operator++() // preincrement
|
|
||||||
{
|
|
||||||
++m_Ptr;
|
|
||||||
return (*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator operator++(int) // postincrement
|
|
||||||
{
|
|
||||||
iterator tmp = *this;
|
|
||||||
++m_Ptr;
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator & operator--() // predecrement
|
|
||||||
{
|
|
||||||
--m_Ptr;
|
|
||||||
return (*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator operator--(int) // postdecrememnt
|
|
||||||
{
|
|
||||||
iterator tmp = *this;
|
|
||||||
--m_Ptr;
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(T * right) const
|
|
||||||
{
|
|
||||||
return (m_Ptr == right);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const iterator & right) const
|
|
||||||
{
|
|
||||||
return (m_Ptr == right.m_Ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(T * right) const
|
|
||||||
{
|
|
||||||
return (m_Ptr != right);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(const iterator & right) const
|
|
||||||
{
|
|
||||||
return (m_Ptr != right.m_Ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator & operator+=(size_t offset)
|
|
||||||
{
|
|
||||||
m_Ptr += offset;
|
|
||||||
return (*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator & operator-=(size_t offset)
|
|
||||||
{
|
|
||||||
m_Ptr -= offset;
|
|
||||||
return (*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator operator+(size_t offset) const
|
|
||||||
{
|
|
||||||
iterator tmp(*this);
|
|
||||||
tmp.m_Ptr += offset;
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator operator-(size_t offset) const
|
|
||||||
{
|
|
||||||
iterator tmp(*this);
|
|
||||||
tmp.m_Ptr -= offset;
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
T & operator[](size_t offset)
|
|
||||||
{
|
|
||||||
return (*(*this + offset));
|
|
||||||
}
|
|
||||||
|
|
||||||
const T & operator[](size_t offset) const
|
|
||||||
{
|
|
||||||
return (*(*this + offset));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator<(const iterator & right) const
|
|
||||||
{
|
|
||||||
return m_Ptr < right.m_Ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator>(const iterator & right) const
|
|
||||||
{
|
|
||||||
return m_Ptr > right.m_Ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator<=(const iterator & right) const
|
|
||||||
{
|
|
||||||
return m_Ptr <= right.m_Ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator>=(const iterator & right) const
|
|
||||||
{
|
|
||||||
return m_Ptr >= right.m_Ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t operator-(const iterator & right) const
|
|
||||||
{
|
|
||||||
return m_Ptr - right.m_Ptr;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// constructors / destructors
|
|
||||||
CVector<T>()
|
|
||||||
{
|
|
||||||
m_Size = 0;
|
|
||||||
m_CurrentUsedSize = 0;
|
|
||||||
m_Data = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
CVector<T>(const CVector<T> & other)
|
|
||||||
{
|
|
||||||
// copy data
|
|
||||||
m_Data = new T [other.m_CurrentUsedSize];
|
|
||||||
m_Size = other.m_CurrentUsedSize;
|
|
||||||
m_CurrentUsedSize = other.m_CurrentUsedSize;
|
|
||||||
for (size_t i=0; i<other.m_CurrentUsedSize; i++)
|
|
||||||
m_Data[i] = other.m_Data[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
~CVector<T>()
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// interface
|
|
||||||
size_t size() const
|
|
||||||
{
|
|
||||||
return m_CurrentUsedSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t capacity() const
|
|
||||||
{
|
|
||||||
return m_Size;
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator begin() const
|
|
||||||
{
|
|
||||||
return iterator(m_Data);
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator end() const
|
|
||||||
{
|
|
||||||
return iterator(m_Data + m_CurrentUsedSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator iterAt(size_t pos)
|
|
||||||
{
|
|
||||||
if (pos > m_CurrentUsedSize)
|
|
||||||
assert(0);
|
|
||||||
return iterator(m_Data + pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool reserve(size_t newSize)
|
|
||||||
{
|
|
||||||
if (newSize > m_Size)
|
|
||||||
return ChangeSize(newSize);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool push_back(const T & elem)
|
|
||||||
{
|
|
||||||
++m_CurrentUsedSize;
|
|
||||||
if (!GrowIfNeeded())
|
|
||||||
{
|
|
||||||
--m_CurrentUsedSize;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Data[m_CurrentUsedSize - 1] = elem;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pop_back()
|
|
||||||
{
|
|
||||||
--m_CurrentUsedSize;
|
|
||||||
if (m_CurrentUsedSize < 0)
|
|
||||||
m_CurrentUsedSize = 0;
|
|
||||||
|
|
||||||
FreeMemIfPossible();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool resize(size_t newSize)
|
|
||||||
{
|
|
||||||
if (!ChangeSize(newSize))
|
|
||||||
return false;
|
|
||||||
m_CurrentUsedSize = newSize;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool empty() const
|
|
||||||
{
|
|
||||||
return (m_CurrentUsedSize == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
T & at(size_t pos)
|
|
||||||
{
|
|
||||||
if (pos > m_CurrentUsedSize)
|
|
||||||
{
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
return m_Data[pos];
|
|
||||||
}
|
|
||||||
|
|
||||||
const T & at(size_t pos) const
|
|
||||||
{
|
|
||||||
if (pos > m_CurrentUsedSize)
|
|
||||||
{
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
return m_Data[pos];
|
|
||||||
}
|
|
||||||
|
|
||||||
T & operator[](size_t pos)
|
|
||||||
{
|
|
||||||
return at(pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
const T & operator[](size_t pos) const
|
|
||||||
{
|
|
||||||
return at(pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
T & front()
|
|
||||||
{
|
|
||||||
if (m_CurrentUsedSize < 1)
|
|
||||||
{
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
return m_Data[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
const T & front() const
|
|
||||||
{
|
|
||||||
if (m_CurrentUsedSize < 1)
|
|
||||||
{
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
return m_Data[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
T & back()
|
|
||||||
{
|
|
||||||
if (m_CurrentUsedSize < 1)
|
|
||||||
{
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
return m_Data[m_CurrentUsedSize - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
const T & back() const
|
|
||||||
{
|
|
||||||
if (m_CurrentUsedSize < 1)
|
|
||||||
{
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
return m_Data[m_CurrentUsedSize - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator insert(iterator where, const T & value)
|
|
||||||
{
|
|
||||||
// validate iter
|
|
||||||
if (where < m_Data || where > (m_Data + m_CurrentUsedSize))
|
|
||||||
return iterator(0);
|
|
||||||
|
|
||||||
size_t ofs = where - begin();
|
|
||||||
|
|
||||||
++m_CurrentUsedSize;
|
|
||||||
if (!GrowIfNeeded())
|
|
||||||
{
|
|
||||||
--m_CurrentUsedSize;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
where = begin() + ofs;
|
|
||||||
|
|
||||||
// Move subsequent entries
|
|
||||||
for (T *ptr = m_Data + m_CurrentUsedSize - 2; ptr >= where.base(); --ptr)
|
|
||||||
*(ptr + 1) = *ptr;
|
|
||||||
|
|
||||||
*where.base() = value;
|
|
||||||
|
|
||||||
return where;
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator erase(iterator where)
|
|
||||||
{
|
|
||||||
// validate iter
|
|
||||||
if (where < m_Data || where >= (m_Data + m_CurrentUsedSize))
|
|
||||||
return iterator(0);
|
|
||||||
|
|
||||||
size_t ofs = where - begin();
|
|
||||||
|
|
||||||
if (m_CurrentUsedSize > 1)
|
|
||||||
{
|
|
||||||
// move
|
|
||||||
T *theend = m_Data + m_CurrentUsedSize;
|
|
||||||
for (T *ptr = where.base() + 1; ptr < theend; ++ptr)
|
|
||||||
*(ptr - 1) = *ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
--m_CurrentUsedSize;
|
|
||||||
|
|
||||||
FreeMemIfPossible();
|
|
||||||
|
|
||||||
return begin() + ofs;
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
m_Size = 0;
|
|
||||||
m_CurrentUsedSize = 0;
|
|
||||||
if (m_Data)
|
|
||||||
{
|
|
||||||
delete [] m_Data;
|
|
||||||
m_Data = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // __CVECTOR_H__
|
|
||||||
|
|
@ -1,161 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "FileParser.h"
|
|
||||||
|
|
||||||
#define FP_MAX_LENGTH 2048
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a string, this will remove whitespace at the beginning and end, and remove comments.
|
|
||||||
*
|
|
||||||
* @param data The string to format. It changes this data directly.
|
|
||||||
* @return Returns a pointer to the end of the newly formated string.
|
|
||||||
*/
|
|
||||||
static char *FP_FormatLine(char *data)
|
|
||||||
{
|
|
||||||
char *End; /**< Pointer to the end of the string. */
|
|
||||||
char *Start; /**< Pointer to the start of the string. */
|
|
||||||
char *Temp; /**< Temporary pointer for parsing. */
|
|
||||||
|
|
||||||
Start=data;
|
|
||||||
|
|
||||||
// Strip beginning whitespace
|
|
||||||
while (*Start==' ' || *Start=='\t') Start++;
|
|
||||||
|
|
||||||
// if the beginning non-whitespace character is a ';', then it's a comment
|
|
||||||
// ignore the rest of the file
|
|
||||||
if (*Start==';')
|
|
||||||
{
|
|
||||||
// just set data[0] to \0 and return out of here.
|
|
||||||
*data='\0';
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
// now strip comments from the end of a line
|
|
||||||
Temp=Start;
|
|
||||||
|
|
||||||
End=Start+(strlen(Start)-1);
|
|
||||||
|
|
||||||
|
|
||||||
while (Temp<=End)
|
|
||||||
{
|
|
||||||
if (*Temp==';')
|
|
||||||
{
|
|
||||||
*Temp='\0';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++Temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// now go to the end of the line, and remove whitespace
|
|
||||||
|
|
||||||
while ( (*End=='\n' ||
|
|
||||||
*End=='\r' ||
|
|
||||||
*End==' ' ||
|
|
||||||
*End=='\t') &&
|
|
||||||
End>=Start)
|
|
||||||
{
|
|
||||||
End--;
|
|
||||||
}
|
|
||||||
++End;
|
|
||||||
*End='\0';
|
|
||||||
|
|
||||||
// if Start==data, we're done
|
|
||||||
if (Start==data)
|
|
||||||
{
|
|
||||||
return End;
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise, copy from Start to data
|
|
||||||
|
|
||||||
while ((*data++=*Start++)!='\0')/*do nothing*/;
|
|
||||||
|
|
||||||
return End;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char* get_localinfo( const char* name , const char* def = 0 )
|
|
||||||
{
|
|
||||||
const char* b = LOCALINFO( (char*)name );
|
|
||||||
if (((b==0)||(*b==0)) && def )
|
|
||||||
SET_LOCALINFO((char*)name,(char*)(b = def) );
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Reads the config file and parses keys.
|
|
||||||
*
|
|
||||||
* @param Category The category (prefix) to look for. Eg.: "cs_linux_", "dod_windows_"
|
|
||||||
* @param Feedback The function to call when a match is made.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void FP_SetupOffsets(const char *Category, FP_ptrFeedback Feedback)
|
|
||||||
{
|
|
||||||
char FileName[512];
|
|
||||||
|
|
||||||
size_t CatLen=strlen(Category);
|
|
||||||
|
|
||||||
MF_BuildPathnameR(FileName,sizeof(FileName)-1,"%s",get_localinfo("amxx_configsdir","addons/amxmodx/configs"));
|
|
||||||
|
|
||||||
strncat(FileName,"/hamdata.ini",sizeof(FileName)-1);
|
|
||||||
|
|
||||||
FILE *fp=fopen(FileName,"r");
|
|
||||||
|
|
||||||
if (!fp)
|
|
||||||
{
|
|
||||||
MF_Log("Unable to open \"%s\" for reading",FileName);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char Data[FP_MAX_LENGTH + 1];
|
|
||||||
|
|
||||||
|
|
||||||
while (!feof(fp))
|
|
||||||
{
|
|
||||||
|
|
||||||
Data[0]='\0';
|
|
||||||
|
|
||||||
fgets(Data,FP_MAX_LENGTH,fp);
|
|
||||||
|
|
||||||
FP_FormatLine(Data);
|
|
||||||
|
|
||||||
if (strncmp(Data,Category,CatLen)==0)
|
|
||||||
{
|
|
||||||
// Find the first space, set it to NULL
|
|
||||||
char *Param=&Data[0];
|
|
||||||
|
|
||||||
while (*Param!=' ' && *Param!='\t' && *Param!='\0')
|
|
||||||
{
|
|
||||||
++Param;
|
|
||||||
}
|
|
||||||
if (*Param=='\0')
|
|
||||||
{
|
|
||||||
// special instance; if this is NULL get out of here
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NULL this space, and then find the first non whitespace character and
|
|
||||||
// use that as the parameter field in the callback
|
|
||||||
*Param++='\0';
|
|
||||||
while (*Param==' ' || *Param=='\t')
|
|
||||||
{
|
|
||||||
++Param;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*Param=='\0')
|
|
||||||
{
|
|
||||||
// special instance; if this is NULL get out of here
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Feedback(&Data[0],Param);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
#ifndef FILEPARSER_H
|
|
||||||
#define FILEPARSER_H
|
|
||||||
|
|
||||||
typedef bool (*FP_ptrFeedback)(const char *key, const char *value);
|
|
||||||
|
|
||||||
#endif // FILEPARSER_H
|
|
@ -1,116 +0,0 @@
|
|||||||
#(C)2004-2005 AMX Mod X Development Team
|
|
||||||
# Makefile written by David "BAILOPAN" Anderson
|
|
||||||
|
|
||||||
HLSDK = ../../../hlsdk
|
|
||||||
MM_ROOT = ../../metamod/metamod
|
|
||||||
|
|
||||||
### EDIT BELOW FOR OTHER PROJECTS ###
|
|
||||||
|
|
||||||
|
|
||||||
CRAZY_OPT_FLAGS = -DCRAZY_OPTS -O3 -funroll-loops -ffast-math -s -pipe -fomit-frame-pointer -fno-strict-aliasing -DNDEBUG -fmerge-all-constants -fmodulo-sched -fgcse-sm -fgcse-las -fgcse-after-reload -floop-optimize2 -funsafe-loop-optimizations -ftree-loop-linear -ftree-loop-im -ftree-loop-ivcanon -fivopts -ftree-vectorize -fvariable-expansion-in-unroller -funsafe-math-optimizations -ffinite-math-only -fpeel-loops -funswitch-loops -fvisibility=hidden -fvisibility-inlines-hidden -fPIC -Wall -Wno-unknown-pragmas -Wno-deprecated -fno-exceptions -DHAVE_STDINT_H -static-libgcc -fno-rtti -Wpointer-arith -Wcast-qual -Wcast-align -Wconversion -Wsign-compare -Wmissing-noreturn -Winline -Wlong-long -Wunsafe-loop-optimizations -Wctor-dtor-privacy -Wno-non-virtual-dtor -Wreorder -Woverloaded-virtual -Wsign-promo -Wsynth -shared
|
|
||||||
|
|
||||||
CRAZY_LINK_FLAGS = -fwhole-program
|
|
||||||
#-fwhole-program -combine
|
|
||||||
|
|
||||||
SANE_OPT_FLAGS = -O3 -funroll-loops -s -pipe -fomit-frame-pointer -fno-strict-aliasing -DNDEBUG
|
|
||||||
|
|
||||||
OPT_FLAGS =
|
|
||||||
|
|
||||||
DEBUG_FLAGS = -g -ggdb3
|
|
||||||
CPP = gcc-4.1
|
|
||||||
#CPP = gcc-2.95
|
|
||||||
NAME = hamsandwich
|
|
||||||
|
|
||||||
BIN_SUFFIX = amxx_i386.so
|
|
||||||
|
|
||||||
OBJECTS = sdk/amxxmodule.cpp FileParser.cpp amxxapi.cpp hooks.cpp \
|
|
||||||
tableentries/VTableManager.cpp tableentries/TakeDamage.cpp tableentries/Use.cpp \
|
|
||||||
tableentries/Blocked.cpp tableentries/Killed.cpp tableentries/Respawn.cpp \
|
|
||||||
tableentries/Restart.cpp tableentries/AddPoints.cpp tableentries/AddPointsToTeam.cpp \
|
|
||||||
tableentries/AddPlayerItem.cpp tableentries/RemovePlayerItem.cpp tableentries/IsPlayer.cpp \
|
|
||||||
tableentries/BloodColor.cpp tableentries/ObjectCaps.cpp tableentries/Classify.cpp \
|
|
||||||
tableentries/IsInWorld.cpp tableentries/IsNetClient.cpp tableentries/IsSneaking.cpp \
|
|
||||||
tableentries/IsMoving.cpp tableentries/IsBSPModel.cpp tableentries/IsAlive.cpp \
|
|
||||||
tableentries/GetToggleState.cpp tableentries/Think.cpp tableentries/Touch.cpp
|
|
||||||
|
|
||||||
|
|
||||||
#natives.cpp vtable.cpp
|
|
||||||
|
|
||||||
#tableentries/VTableUse.cpp tableentries/VTableTakedamage.cpp
|
|
||||||
|
|
||||||
|
|
||||||
#natives/cs.cpp natives/dod.cpp natives/tfc.cpp \
|
|
||||||
#natives/ns.cpp natives/ts.cpp natives/sven.cpp \
|
|
||||||
#FileParser.cpp
|
|
||||||
|
|
||||||
LINK =
|
|
||||||
|
|
||||||
INCLUDE = -I. -I$(HLSDK) -I$(HLSDK)/dlls -I$(HLSDK)/engine -I$(HLSDK)/game_shared -I$(HLSDK)/game_shared \
|
|
||||||
-I$(MM_ROOT) -I$(HLSDK)/common -I$(HLSDK)/pm_shared -I./tableentries
|
|
||||||
|
|
||||||
GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1)
|
|
||||||
|
|
||||||
ifeq "$(DEBUG)" "true"
|
|
||||||
BIN_DIR = Debug
|
|
||||||
CFLAGS = $(DEBUG_FLAGS)
|
|
||||||
else
|
|
||||||
ifeq "$(CRAZY)" "true"
|
|
||||||
BIN_DIR = Optimized
|
|
||||||
OPT_FLAGS = $(CRAZY_OPT_FLAGS)
|
|
||||||
LINK = $(CRAZY_LINK_FLAGS)
|
|
||||||
else
|
|
||||||
BIN_DIR = Release
|
|
||||||
OPT_FLAGS = $(SANE_OPT_FLAGS)
|
|
||||||
endif
|
|
||||||
ifeq "$(GCC_VERSION)" "4"
|
|
||||||
OPT_FLAGS += -fvisibility=hidden -fvisibility-inlines-hidden
|
|
||||||
endif
|
|
||||||
CFLAGS = $(OPT_FLAGS)
|
|
||||||
endif
|
|
||||||
|
|
||||||
CFLAGS += -fPIC -Wall -Wno-non-virtual-dtor -fno-exceptions -DHAVE_STDINT_H -fno-rtti
|
|
||||||
|
|
||||||
BINARY = $(NAME)_$(BIN_SUFFIX)
|
|
||||||
CFLAGS += -DPAWN_CELL_SIZE=32 -DJIT -DASM32
|
|
||||||
OPT_FLAGS += -march=i586
|
|
||||||
|
|
||||||
OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o)
|
|
||||||
|
|
||||||
$(BIN_DIR)/%.o: %.cpp
|
|
||||||
$(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $<
|
|
||||||
|
|
||||||
all:
|
|
||||||
mkdir -p $(BIN_DIR)
|
|
||||||
mkdir -p $(BIN_DIR)/sdk
|
|
||||||
mkdir -p $(BIN_DIR)/natives
|
|
||||||
mkdir -p $(BIN_DIR)/tableentries
|
|
||||||
$(MAKE) hamsandwich
|
|
||||||
|
|
||||||
hamsandwich: $(OBJ_LINUX)
|
|
||||||
$(CPP) $(INCLUDE) $(CFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY)
|
|
||||||
|
|
||||||
debug:
|
|
||||||
$(MAKE) all DEBUG=true
|
|
||||||
|
|
||||||
default: all
|
|
||||||
|
|
||||||
crazy:
|
|
||||||
$(MAKE) all CRAZY=true
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf Release/*.o
|
|
||||||
rm -rf Release/sdk/*.o
|
|
||||||
rm -rf Release/natives/*.o
|
|
||||||
rm -rf Release/tableentries/*.o
|
|
||||||
rm -rf Release/$(NAME)_$(BIN_SUFFIX)
|
|
||||||
rm -rf Debug/*.o
|
|
||||||
rm -rf Debug/sdk/*.o
|
|
||||||
rm -rf Debug/natives/*.o
|
|
||||||
rm -rf Debug/tableentries/*.o
|
|
||||||
rm -rf Debug/$(NAME)_$(BIN_SUFFIX)
|
|
||||||
rm -rf Optimized/*.o
|
|
||||||
rm -rf Optimized/sdk/*.o
|
|
||||||
rm -rf Optimized/natives/*.o
|
|
||||||
rm -rf Optimized/tableentries/*.o
|
|
||||||
rm -rf Optimized/$(NAME)_$(BIN_SUFFIX)
|
|
||||||
|
|
@ -1,90 +0,0 @@
|
|||||||
/* Ham Sandwich
|
|
||||||
*
|
|
||||||
* by sawce
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by the
|
|
||||||
* Free Software Foundation; either version 2 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
|
|
||||||
* General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
* In addition, as a special exception, the author gives permission to
|
|
||||||
* link the code of this program with the Half-Life Game Engine ("HL
|
|
||||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
|
||||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
|
||||||
* respects for all of the code used other than the HL Engine and MODs
|
|
||||||
* from Valve. If you modify this file, you may extend this exception
|
|
||||||
* to your version of the file, but you are not obligated to do so. If
|
|
||||||
* you do not wish to do so, delete this exception statement from your
|
|
||||||
* version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Inlined replacements for INDEXENT/ENTINDEX
|
|
||||||
* It only really removes the overhead of the push/jump
|
|
||||||
* but since INDEXENT/ENTINDEX are used a lot with amxx
|
|
||||||
* it might be beneficial to include.
|
|
||||||
* NOTE: Bad stuff will happen if you call these before
|
|
||||||
* NEW_Initialize()
|
|
||||||
* NOTE: No bounds checking is done because natives
|
|
||||||
* should use their own bounds checking!
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef NEW_UTIL_H
|
|
||||||
#define NEW_UTIL_H
|
|
||||||
|
|
||||||
|
|
||||||
extern edict_t *NEW_FirstEdict;
|
|
||||||
extern bool NEW_Initialized;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is called on the first Spawn() ever hooked. This would be worldspawn (index 0)
|
|
||||||
*/
|
|
||||||
inline void NEW_Initialize(edict_t *Entity)
|
|
||||||
{
|
|
||||||
// This is not worldspawn?
|
|
||||||
// compensate
|
|
||||||
NEW_FirstEdict=Entity;
|
|
||||||
NEW_Initialized=true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts an integer index into an edict pointer
|
|
||||||
*/
|
|
||||||
inline edict_t *INDEXENT_NEW(const int Index)
|
|
||||||
{
|
|
||||||
return (edict_t *)(NEW_FirstEdict + Index);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts an edict pointer into an integer index
|
|
||||||
*/
|
|
||||||
inline int ENTINDEX_NEW(const edict_t *Ent)
|
|
||||||
{
|
|
||||||
return (int)(Ent - NEW_FirstEdict);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Inlined replacement of MF_GetAmxAddr
|
|
||||||
|
|
||||||
|
|
||||||
inline REAL amx_ctof2(cell x)
|
|
||||||
{
|
|
||||||
return *(REAL*)&x;
|
|
||||||
}
|
|
||||||
inline cell amx_ftoc2(REAL x)
|
|
||||||
{
|
|
||||||
return *(cell*)&x;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif // NEW_UTIL_H
|
|
||||||
|
|
@ -1,632 +0,0 @@
|
|||||||
/* Trampolines
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by the
|
|
||||||
* Free Software Foundation; either version 2 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
|
|
||||||
* General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
* In addition, as a special exception, the author gives permission to
|
|
||||||
* link the code of this program with the Half-Life Game Engine ("HL
|
|
||||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
|
||||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
|
||||||
* respects for all of the code used other than the HL Engine and MODs
|
|
||||||
* from Valve. If you modify this file, you may extend this exception
|
|
||||||
* to your version of the file, but you are not obligated to do so. If
|
|
||||||
* you do not wish to do so, delete this exception statement from your
|
|
||||||
* version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef TRAMPOLINES_H
|
|
||||||
#define TRAMPOLINES_H
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
#define TPRINT(msg) printf msg
|
|
||||||
#else
|
|
||||||
#define TPRINT(msg) /* nothing */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined _WIN32
|
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#endif // WIN32_LEAN_AND_MEAN
|
|
||||||
#if _MSC_VER >= 1400
|
|
||||||
#ifdef offsetof
|
|
||||||
#undef offsetof
|
|
||||||
#endif // offsetof
|
|
||||||
#endif // _MSC_VER >= 1400
|
|
||||||
#include <windows.h>
|
|
||||||
#elif defined __linux__
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#endif
|
|
||||||
#include <stddef.h> // size_t
|
|
||||||
#include <string.h> // memcpy
|
|
||||||
|
|
||||||
|
|
||||||
namespace Trampolines
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of x86 bytecodes for creating
|
|
||||||
* basic trampolines at runtime.
|
|
||||||
* -
|
|
||||||
* These are defined here so that, should
|
|
||||||
* the need ever arise, this can be ported
|
|
||||||
* to other architectures fairly painlessly
|
|
||||||
*/
|
|
||||||
namespace Bytecode
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Prologue for a void function
|
|
||||||
* Clobbers EBX and EAX
|
|
||||||
*/
|
|
||||||
const unsigned char codeVoidPrologue[] = {
|
|
||||||
0x55, // push ebp
|
|
||||||
0x89, 0xE5, // mov ebp, esp
|
|
||||||
0x50, // push eax
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prologue for a function that returns
|
|
||||||
* Clobbers EBX, EAX too but not after call
|
|
||||||
*/
|
|
||||||
const unsigned char codeReturnPrologue[] = {
|
|
||||||
0x55, // push ebp
|
|
||||||
0x89, 0xE5, // mov ebp, esp
|
|
||||||
};
|
|
||||||
const unsigned char codeThisReturnPrologue[] = {
|
|
||||||
0x55, // push ebp
|
|
||||||
0x89, 0xE5, // mov ebp, esp
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Takes a paramter from the trampoline's stack
|
|
||||||
* and pushes it onto the target's stack.
|
|
||||||
*/
|
|
||||||
const unsigned char codePushParam[] = {
|
|
||||||
0xFF, 0x75, 0xFF // pushl [ebp+0xFF]
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Offset of codePushParam to modify at runtime
|
|
||||||
* that contains the stack offset
|
|
||||||
*/
|
|
||||||
const unsigned int codePushParamReplace = 2;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Takes the "this" pointer from the trampoline and
|
|
||||||
* pushes it onto the target's stack.
|
|
||||||
*/
|
|
||||||
const unsigned char codePushThis[] = {
|
|
||||||
#if defined _WIN32
|
|
||||||
0x51 // push ecx
|
|
||||||
#elif defined __linux__
|
|
||||||
0xFF, 0x75, 0x04 // pushl [ebp+0x08h]
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined __linux__
|
|
||||||
const int codePushThisReplace = 2;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pushes a raw number onto the target's stack
|
|
||||||
*/
|
|
||||||
const unsigned char codePushID[] = {
|
|
||||||
0x68, 0xDE, 0xFA, 0xAD, 0xDE // push DEADFADEh
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Offset of codePushID to modify at runtime
|
|
||||||
* to contain the number to push
|
|
||||||
*/
|
|
||||||
const unsigned int codePushIDReplace = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call our procedure
|
|
||||||
*/
|
|
||||||
const unsigned char codeCall[] = {
|
|
||||||
0xB8, 0xDE, 0xFA, 0xAD, 0xDE,// mov eax, DEADFADEh
|
|
||||||
0xFF, 0xD0 // call eax
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Offset of codeCall to modify at runtime
|
|
||||||
* to contain the pointer to the function
|
|
||||||
*/
|
|
||||||
const unsigned int codeCallReplace = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds to ESP, freeing up stack space
|
|
||||||
*/
|
|
||||||
const unsigned char codeFreeStack[] = {
|
|
||||||
0x81, 0xC4, 0xFF, 0xFF, 0xFF, 0xFF// add esp REPLACEME
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Offset of codeFreeStack to modify at runtime
|
|
||||||
* to contain how much data to free
|
|
||||||
*/
|
|
||||||
const unsigned int codeFreeStackReplace = 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Epilogue of a simple return function
|
|
||||||
*/
|
|
||||||
const unsigned char codeReturnEpilogue[] = {
|
|
||||||
0x5D, // pop ebp
|
|
||||||
0xC3 // ret
|
|
||||||
};
|
|
||||||
const unsigned char codeReturnEpilogueN[] = {
|
|
||||||
0x5D, // pop ebp
|
|
||||||
0xC2, 0xCD, 0xAB // retn 0xABCD
|
|
||||||
};
|
|
||||||
const int codeReturnEpilogueNReplace = 2;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Epilogue of a void return function
|
|
||||||
*/
|
|
||||||
const unsigned char codeVoidEpilogue[] = {
|
|
||||||
0x58, // pop eax
|
|
||||||
0x5D, // pop ebp
|
|
||||||
0xC3 // ret
|
|
||||||
};
|
|
||||||
|
|
||||||
const unsigned char codeVoidEpilogueN[] = {
|
|
||||||
0x58, // pop eax
|
|
||||||
0x5D, // pop ebp
|
|
||||||
0xC2, 0xCD, 0xAB // retn 0xABCD
|
|
||||||
};
|
|
||||||
const int codeVoidEpilogueNReplace = 3;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const unsigned char codeBreakpoint[] = {
|
|
||||||
0xCC // int 3
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Our actual maker of the trampolines!!@$
|
|
||||||
* I've no idea why I made this a class and not a namespace
|
|
||||||
* Oh well!
|
|
||||||
*/
|
|
||||||
|
|
||||||
class TrampolineMaker
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
unsigned char *m_buffer; // the actual buffer containing the code
|
|
||||||
int m_size; // size of the buffer
|
|
||||||
int m_mystack; // stack for the trampoline itself
|
|
||||||
int m_calledstack; // stack for the target function
|
|
||||||
int m_paramstart;
|
|
||||||
int m_thiscall;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds data to the buffer
|
|
||||||
* data must be pre-formatted before hand!
|
|
||||||
*/
|
|
||||||
void Append(const unsigned char *src, size_t size)
|
|
||||||
{
|
|
||||||
int orig=m_size;
|
|
||||||
m_size+=size;
|
|
||||||
|
|
||||||
if (m_buffer==NULL)
|
|
||||||
{
|
|
||||||
m_buffer=(unsigned char *)malloc(m_size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_buffer=(unsigned char *)realloc(m_buffer,m_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char *dat=m_buffer+orig; // point dat to the end of the prewritten
|
|
||||||
|
|
||||||
while (orig<m_size)
|
|
||||||
{
|
|
||||||
*dat++=*src++;
|
|
||||||
|
|
||||||
orig++;
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
public:
|
|
||||||
TrampolineMaker()
|
|
||||||
{
|
|
||||||
m_buffer=NULL;
|
|
||||||
m_size=0;
|
|
||||||
m_mystack=0;
|
|
||||||
m_calledstack=0;
|
|
||||||
m_paramstart=0;
|
|
||||||
m_thiscall=0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts a breakpoint (int 3) into the trampoline.
|
|
||||||
*/
|
|
||||||
void Breakpoint()
|
|
||||||
{
|
|
||||||
Append(&::Trampolines::Bytecode::codeBreakpoint[0],sizeof(::Trampolines::Bytecode::codeBreakpoint));
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the "return prologue", pushes registers and prepares stack
|
|
||||||
*/
|
|
||||||
void ReturnPrologue()
|
|
||||||
{
|
|
||||||
Append(&::Trampolines::Bytecode::codeReturnPrologue[0],sizeof(::Trampolines::Bytecode::codeReturnPrologue));
|
|
||||||
m_paramstart=0;
|
|
||||||
m_thiscall=0;
|
|
||||||
};
|
|
||||||
void ThisReturnPrologue()
|
|
||||||
{
|
|
||||||
this->ReturnPrologue();
|
|
||||||
m_thiscall=1;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the void prologue pushes registers, prepares the stack
|
|
||||||
*/
|
|
||||||
void VoidPrologue()
|
|
||||||
{
|
|
||||||
Append(&::Trampolines::Bytecode::codeVoidPrologue[0],sizeof(::Trampolines::Bytecode::codeVoidPrologue));
|
|
||||||
m_paramstart=0;
|
|
||||||
m_thiscall=0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flags this trampoline as a thiscall trampoline, and prepares the void prologue.
|
|
||||||
*/
|
|
||||||
void ThisVoidPrologue()
|
|
||||||
{
|
|
||||||
this->VoidPrologue();
|
|
||||||
m_thiscall=1;
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Epilogue for a returning function pops registers but does not free any more of the stack!
|
|
||||||
*/
|
|
||||||
void ReturnEpilogue()
|
|
||||||
{
|
|
||||||
Append(&::Trampolines::Bytecode::codeReturnEpilogue[0],sizeof(::Trampolines::Bytecode::codeReturnEpilogue));
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Epilogue that also frees it's estimated stack usage. Useful for stdcall/thiscall/fastcall.
|
|
||||||
*/
|
|
||||||
void ReturnEpilogueAndFree()
|
|
||||||
{
|
|
||||||
printf("Freeing %d bytes\n",m_mystack);
|
|
||||||
this->ReturnEpilogue(m_mystack);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return epilogue. Pops registers, and frees given amount of data from the stack.
|
|
||||||
*
|
|
||||||
* @param howmuch How many bytes to free from the stack.
|
|
||||||
*/
|
|
||||||
void ReturnEpilogue(int howmuch)
|
|
||||||
{
|
|
||||||
|
|
||||||
unsigned char code[sizeof(::Trampolines::Bytecode::codeReturnEpilogueN)];
|
|
||||||
|
|
||||||
memcpy(&code[0],&::Trampolines::Bytecode::codeReturnEpilogueN[0],sizeof(::Trampolines::Bytecode::codeReturnEpilogueN));
|
|
||||||
|
|
||||||
|
|
||||||
unsigned char *c=&code[0];
|
|
||||||
|
|
||||||
union
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
unsigned char b[4];
|
|
||||||
} bi;
|
|
||||||
|
|
||||||
bi.i=howmuch;
|
|
||||||
|
|
||||||
c+=::Trampolines::Bytecode::codeReturnEpilogueNReplace;
|
|
||||||
*c++=bi.b[0];
|
|
||||||
*c++=bi.b[1];
|
|
||||||
|
|
||||||
Append(&code[0],sizeof(::Trampolines::Bytecode::codeReturnEpilogueN));
|
|
||||||
//Append(&::Trampolines::Bytecode::codeReturnEpilogueN[0],sizeof(::Trampolines::Bytecode::codeReturnEpilogueN));
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Void epilogue, pops registers and frees the estimated stack usage of the trampoline.
|
|
||||||
*/
|
|
||||||
void VoidEpilogueAndFree()
|
|
||||||
{
|
|
||||||
printf("Freeing %d bytes\n",m_mystack);
|
|
||||||
this->VoidEpilogue(m_mystack);
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Void epilogue, pops registers, nothing else done with stack.
|
|
||||||
*/
|
|
||||||
void VoidEpilogue()
|
|
||||||
{
|
|
||||||
Append(&::Trampolines::Bytecode::codeVoidEpilogue[0],sizeof(::Trampolines::Bytecode::codeVoidEpilogue));
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Void epilogue, pops registers, frees given amount of data off of the stack.
|
|
||||||
*
|
|
||||||
* @param howmuch How many bytes to free from the stack.
|
|
||||||
*/
|
|
||||||
void VoidEpilogue(int howmuch)
|
|
||||||
{
|
|
||||||
|
|
||||||
unsigned char code[sizeof(::Trampolines::Bytecode::codeVoidEpilogueN)];
|
|
||||||
|
|
||||||
memcpy(&code[0],&::Trampolines::Bytecode::codeVoidEpilogueN[0],sizeof(::Trampolines::Bytecode::codeVoidEpilogueN));
|
|
||||||
|
|
||||||
|
|
||||||
unsigned char *c=&code[0];
|
|
||||||
|
|
||||||
union
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
unsigned char b[4];
|
|
||||||
} bi;
|
|
||||||
|
|
||||||
bi.i=howmuch;
|
|
||||||
|
|
||||||
c+=::Trampolines::Bytecode::codeVoidEpilogueNReplace;
|
|
||||||
*c++=bi.b[0];
|
|
||||||
*c++=bi.b[1];
|
|
||||||
|
|
||||||
Append(&code[0],sizeof(::Trampolines::Bytecode::codeVoidEpilogueN));
|
|
||||||
Append(&::Trampolines::Bytecode::codeVoidEpilogueN[0],sizeof(::Trampolines::Bytecode::codeVoidEpilogueN));
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pushes the "this" pointer onto the callee stack. Pushes ECX for MSVC, and param0 on GCC.
|
|
||||||
*/
|
|
||||||
void PushThis()
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!m_thiscall)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char code[sizeof(::Trampolines::Bytecode::codePushThis)];
|
|
||||||
|
|
||||||
memcpy(&code[0],&::Trampolines::Bytecode::codePushThis[0],sizeof(::Trampolines::Bytecode::codePushThis));
|
|
||||||
|
|
||||||
|
|
||||||
#if defined __linux__
|
|
||||||
unsigned char *c=&code[0];
|
|
||||||
|
|
||||||
union
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
unsigned char b[4];
|
|
||||||
} bi;
|
|
||||||
|
|
||||||
bi.i=m_paramstart+8;
|
|
||||||
|
|
||||||
c+=::Trampolines::Bytecode::codePushThisReplace;
|
|
||||||
*c++=bi.b[0];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Append(&code[0],sizeof(::Trampolines::Bytecode::codePushThis));
|
|
||||||
|
|
||||||
#if defined __linux__
|
|
||||||
TPRINT(("mystack=%d+4\n",m_mystack));
|
|
||||||
m_mystack+=4;
|
|
||||||
#endif
|
|
||||||
TPRINT(("calledstack=%d+4\n",m_calledstack));
|
|
||||||
m_calledstack+=4;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Frees what is estimated as the stack usage of the trampoline.
|
|
||||||
*/
|
|
||||||
void FreeMyStack(void)
|
|
||||||
{
|
|
||||||
|
|
||||||
TPRINT(("freeing mystack=%d+4\n",m_mystack));
|
|
||||||
this->FreeStack(m_mystack);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Frees the estimated stack usage of the callee.
|
|
||||||
*/
|
|
||||||
void FreeTargetStack(void)
|
|
||||||
{
|
|
||||||
TPRINT(("freeing calledstack=%d+4\n",m_calledstack));
|
|
||||||
this->FreeStack(m_calledstack);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Frees the estimated stack usage of the callee and the trampoline.
|
|
||||||
*/
|
|
||||||
void FreeBothStacks(void)
|
|
||||||
{
|
|
||||||
TPRINT(("freeing mystack=%d+4\n",m_mystack));
|
|
||||||
TPRINT(("freeing calledstack=%d+4\n",m_calledstack));
|
|
||||||
this->FreeStack(m_calledstack + m_mystack);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Frees a given amount of bytes from the stack.
|
|
||||||
*
|
|
||||||
* @param howmuch How many bytes to free.
|
|
||||||
*/
|
|
||||||
void FreeStack(int howmuch)
|
|
||||||
{
|
|
||||||
unsigned char code[sizeof(::Trampolines::Bytecode::codeFreeStack)];
|
|
||||||
|
|
||||||
memcpy(&code[0],&::Trampolines::Bytecode::codeFreeStack[0],sizeof(::Trampolines::Bytecode::codeFreeStack));
|
|
||||||
|
|
||||||
unsigned char *c=&code[0];
|
|
||||||
|
|
||||||
union
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
unsigned char b[4];
|
|
||||||
} bi;
|
|
||||||
|
|
||||||
bi.i=howmuch;
|
|
||||||
|
|
||||||
c+=::Trampolines::Bytecode::codeFreeStackReplace;
|
|
||||||
*c++=bi.b[0];
|
|
||||||
*c++=bi.b[1];
|
|
||||||
*c++=bi.b[2];
|
|
||||||
*c++=bi.b[3];
|
|
||||||
|
|
||||||
Append(&code[0],sizeof(::Trampolines::Bytecode::codeFreeStack));
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pushes a raw number onto the callee stack.
|
|
||||||
*
|
|
||||||
* @param Number The number to push onto the callee stack.
|
|
||||||
*/
|
|
||||||
void PushNum(int Number)
|
|
||||||
{
|
|
||||||
unsigned char code[sizeof(::Trampolines::Bytecode::codePushID)];
|
|
||||||
|
|
||||||
memcpy(&code[0],&::Trampolines::Bytecode::codePushID[0],sizeof(::Trampolines::Bytecode::codePushID));
|
|
||||||
|
|
||||||
unsigned char *c=&code[0];
|
|
||||||
|
|
||||||
union
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
unsigned char b[4];
|
|
||||||
} bi;
|
|
||||||
|
|
||||||
bi.i=Number;
|
|
||||||
|
|
||||||
c+=::Trampolines::Bytecode::codePushIDReplace;
|
|
||||||
*c++=bi.b[0];
|
|
||||||
*c++=bi.b[1];
|
|
||||||
*c++=bi.b[2];
|
|
||||||
*c++=bi.b[3];
|
|
||||||
|
|
||||||
Append(&code[0],sizeof(::Trampolines::Bytecode::codePushID));
|
|
||||||
|
|
||||||
TPRINT(("calledstack=%d+4\n",m_calledstack));
|
|
||||||
m_calledstack+=4; // increase auto detected stack size
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Takes a parameter passed on the trampoline's stack and inserts it into the callee's stack.
|
|
||||||
*
|
|
||||||
* @param which The parameter number to push. 1-based. "thiscall" trampolines automatically compensate for the off-number on GCC.
|
|
||||||
*/
|
|
||||||
void PushParam(int which)
|
|
||||||
{
|
|
||||||
#if defined __linux__
|
|
||||||
if (m_thiscall)
|
|
||||||
{
|
|
||||||
which++;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
which=which*4;
|
|
||||||
which+=m_paramstart+4;
|
|
||||||
|
|
||||||
unsigned char value=which;
|
|
||||||
|
|
||||||
unsigned char code[sizeof(::Trampolines::Bytecode::codePushParam)];
|
|
||||||
|
|
||||||
memcpy(&code[0],&::Trampolines::Bytecode::codePushParam[0],sizeof(::Trampolines::Bytecode::codePushParam));
|
|
||||||
|
|
||||||
unsigned char *c=&code[0];
|
|
||||||
|
|
||||||
|
|
||||||
c+=::Trampolines::Bytecode::codePushParamReplace;
|
|
||||||
|
|
||||||
*c=value;
|
|
||||||
|
|
||||||
Append(&code[0],sizeof(::Trampolines::Bytecode::codePushParam));
|
|
||||||
|
|
||||||
TPRINT(("calledstack=%d+4\n",m_calledstack));
|
|
||||||
m_calledstack+=4; // increase auto detected stack size
|
|
||||||
TPRINT(("mystack=%d+4\n",m_mystack));
|
|
||||||
m_mystack+=4;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert a function to call into the trampoline.
|
|
||||||
*
|
|
||||||
* @param ptr The function to call, cast to void*.
|
|
||||||
*/
|
|
||||||
void Call(void *ptr)
|
|
||||||
{
|
|
||||||
unsigned char code[sizeof(::Trampolines::Bytecode::codeCall)];
|
|
||||||
|
|
||||||
memcpy(&code[0],&::Trampolines::Bytecode::codeCall[0],sizeof(::Trampolines::Bytecode::codeCall));
|
|
||||||
|
|
||||||
unsigned char *c=&code[0];
|
|
||||||
|
|
||||||
union
|
|
||||||
{
|
|
||||||
void *p;
|
|
||||||
unsigned char b[4];
|
|
||||||
} bp;
|
|
||||||
|
|
||||||
bp.p=ptr;
|
|
||||||
|
|
||||||
c+=::Trampolines::Bytecode::codeCallReplace;
|
|
||||||
|
|
||||||
*c++=bp.b[0];
|
|
||||||
*c++=bp.b[1];
|
|
||||||
*c++=bp.b[2];
|
|
||||||
*c++=bp.b[3];
|
|
||||||
Append(&code[0],sizeof(::Trampolines::Bytecode::codeCall));
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finalizes the trampoline. Do not try to modify it after this.
|
|
||||||
*
|
|
||||||
* @param size A pointer to retrieve the size of the trampoline. Ignored if set to NULL.
|
|
||||||
* @return The trampoline pointer, cast to void*.
|
|
||||||
*/
|
|
||||||
void *Finish(int *size)
|
|
||||||
{
|
|
||||||
void *ret=(void *)m_buffer;
|
|
||||||
|
|
||||||
if (size)
|
|
||||||
{
|
|
||||||
*size=m_size;
|
|
||||||
}
|
|
||||||
#if defined _WIN32
|
|
||||||
DWORD OldFlags;
|
|
||||||
VirtualProtect(ret,m_size,PAGE_EXECUTE_READWRITE,&OldFlags);
|
|
||||||
#elif defined __linux__
|
|
||||||
mprotect(ret,m_size,PROT_READ|PROT_WRITE|PROT_EXEC);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
m_size=0;
|
|
||||||
m_buffer=NULL; // so we don't accidentally rewrite!
|
|
||||||
m_mystack=0;
|
|
||||||
m_calledstack=0;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif // TRAMPOLINEMANAGER_H
|
|
@ -1,267 +0,0 @@
|
|||||||
/* AMX Mod X
|
|
||||||
*
|
|
||||||
* by the AMX Mod X Development Team
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by the
|
|
||||||
* Free Software Foundation; either version 2 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
|
|
||||||
* General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
* In addition, as a special exception, the author gives permission to
|
|
||||||
* link the code of this program with the Half-Life Game Engine ("HL
|
|
||||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
|
||||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
|
||||||
* respects for all of the code used other than the HL Engine and MODs
|
|
||||||
* from Valve. If you modify this file, you may extend this exception
|
|
||||||
* to your version of the file, but you are not obligated to do so. If
|
|
||||||
* you do not wish to do so, delete this exception statement from your
|
|
||||||
* version.
|
|
||||||
*
|
|
||||||
* Description: AMX Mod X Module Interface hooks
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "CVector.h"
|
|
||||||
#include "CString.h"
|
|
||||||
|
|
||||||
#include "FileParser.h"
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
#include "VTableManager.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
CVector<String *> SuffixNames; /**< List of names being searched for in the config file. */
|
|
||||||
CVector<void (*)(const char *, const char *)> SuffixFunctions; /**< Callback functions for when we find a hunted keyvalue. */
|
|
||||||
CVector<void (*)(void)> ConfigDoneCallbacks; /**< Callbacks when our config file is done being parsed. */
|
|
||||||
|
|
||||||
edict_t *NEW_FirstEdict=NULL; /**< Used for the NEW_Utils INDEXENT/ENTINDEX replacements. */
|
|
||||||
bool NEW_Initialized=false; /**< Whether NEW_Utils has been initialized yet. */
|
|
||||||
|
|
||||||
void FP_SetupOffsets(const char *name, FP_ptrFeedback feedback);
|
|
||||||
|
|
||||||
|
|
||||||
unsigned int HAM_pev=0; /**< Offset of pev from the this pointer. */
|
|
||||||
unsigned int HAM_pevset=0; /**< Whether or not the pev offset has been set. */
|
|
||||||
unsigned int HAM_classbase=0; /**< Offset of the vtable from the this pointer. */
|
|
||||||
unsigned int HAM_classbaseset=0; /**< Whether or not the classbase offset has been set. */
|
|
||||||
|
|
||||||
char ModKey[256]; /**< Temporary buffer for holding the <modname>_<os> prefix. */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a callback to the config parser for this config suffix.
|
|
||||||
*
|
|
||||||
* @param suffix The suffix to add, eg "takedamage" would be called for "cs_linux_takedamage"
|
|
||||||
* @param callback The function to call when this key is found.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void RegisterKeySuffix(const char *suffix, void (*callback)(const char *,const char *))
|
|
||||||
{
|
|
||||||
String *Suffix=new String(suffix);
|
|
||||||
|
|
||||||
|
|
||||||
SuffixNames.push_back(Suffix);
|
|
||||||
|
|
||||||
SuffixFunctions.push_back(callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds this entry to the configdone callback.
|
|
||||||
*
|
|
||||||
* @param callback Function to call when the config file is done being parsed.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void RegisterConfigCallback(void (*callback)(void))
|
|
||||||
{
|
|
||||||
ConfigDoneCallbacks.push_back(callback);
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Starts each vtable entry. This needs to be edited for every additional hook.
|
|
||||||
*
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void HAM_CallInitialization(void)
|
|
||||||
{
|
|
||||||
#define VTINIT(TableName) VTable##TableName::Initialize(&HAM_pev,&HAM_pevset,&HAM_classbase,&HAM_classbaseset)
|
|
||||||
|
|
||||||
VTINIT(TakeDamage);
|
|
||||||
VTINIT(Use);
|
|
||||||
VTINIT(Killed);
|
|
||||||
VTINIT(Blocked);
|
|
||||||
VTINIT(Respawn);
|
|
||||||
VTINIT(Restart);
|
|
||||||
VTINIT(AddPoints);
|
|
||||||
VTINIT(AddPointsToTeam);
|
|
||||||
VTINIT(AddPlayerItem);
|
|
||||||
VTINIT(RemovePlayerItem);
|
|
||||||
VTINIT(BloodColor);
|
|
||||||
VTINIT(Classify);
|
|
||||||
VTINIT(GetToggleState);
|
|
||||||
VTINIT(IsAlive);
|
|
||||||
VTINIT(IsBSPModel);
|
|
||||||
VTINIT(IsInWorld);
|
|
||||||
VTINIT(IsMoving);
|
|
||||||
VTINIT(IsNetClient);
|
|
||||||
VTINIT(IsPlayer);
|
|
||||||
VTINIT(IsSneaking);
|
|
||||||
VTINIT(ObjectCaps);
|
|
||||||
VTINIT(Think);
|
|
||||||
VTINIT(Touch);
|
|
||||||
|
|
||||||
|
|
||||||
#undef VTINIT
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells all the table entries that the config file is done being parsed. Register their natives now.
|
|
||||||
*
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void HAM_CallConfigDone(void)
|
|
||||||
{
|
|
||||||
int i=0; /**< Iterator. */
|
|
||||||
int end=ConfigDoneCallbacks.size(); /**< How many to parse. */
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
ConfigDoneCallbacks[i]();
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// done with this, free up the vector
|
|
||||||
ConfigDoneCallbacks.clear();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple wrapper to uniform string to number conversion. I don't just use -1 on strtol base because I don't want octal conversion.
|
|
||||||
*
|
|
||||||
* @param input The input string.
|
|
||||||
* @return The input string converted to an unsigned integer.
|
|
||||||
*/
|
|
||||||
int HAM_StrToNum(const char *input)
|
|
||||||
{
|
|
||||||
char *end; /**< Temporary pointer, needed for strtoul(). */
|
|
||||||
|
|
||||||
// if begins with 0x or 0X it's to be interpretted as hex
|
|
||||||
if (*input=='0' &&
|
|
||||||
(*(input+1)=='x' || *(input+1)=='X'))
|
|
||||||
{
|
|
||||||
return strtoul(input,&end,16);
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise it's to be interpretted as base 10
|
|
||||||
return strtoul(input,&end,10);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This is called every time a key with the <mod>_<os>_ prefix is found.
|
|
||||||
*
|
|
||||||
* @param key The full key (eg: cs_windows_takedamage)
|
|
||||||
* @param data The corresponding data.
|
|
||||||
* @return true when key is used, false otherwise
|
|
||||||
*/
|
|
||||||
bool HAM_GetKey(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
char TempKey[512]; /**< Temporary buffer. */
|
|
||||||
int i=0; /**< Iterator. */
|
|
||||||
int end=SuffixNames.size(); /**< How many suffixes to check. */
|
|
||||||
bool found=false; /**< Whether this key has been used or not. */
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
snprintf(TempKey,sizeof(TempKey)-1,"%s_%s",ModKey,SuffixNames[i]->c_str());
|
|
||||||
if (strcmp(TempKey,key)==0)
|
|
||||||
{
|
|
||||||
SuffixFunctions[i](SuffixNames[i]->c_str(),data);
|
|
||||||
found=true;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Simple function to set the "pev" field that is used by all forwards.
|
|
||||||
*
|
|
||||||
* @param key The key suffix being forwarded.
|
|
||||||
* @param data The data corresponding to the key.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void HAM_SetPev(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
HAM_pev=HAM_StrToNum(data);
|
|
||||||
HAM_pevset=1;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Simple function to set the "classbase" field that is used by all natives when built with GCC.
|
|
||||||
*
|
|
||||||
* @param key The key suffix being forwarded.
|
|
||||||
* @param data The data corresponding to the key.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
#if defined __linux__
|
|
||||||
void HAM_SetClassBase(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
HAM_classbase=HAM_StrToNum(data);
|
|
||||||
HAM_classbaseset=1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void OnAmxxAttach()
|
|
||||||
{
|
|
||||||
HAM_CallInitialization();
|
|
||||||
#ifdef __linux__
|
|
||||||
snprintf(ModKey,sizeof(ModKey)-1,"%s_linux",MF_GetModname());
|
|
||||||
#else
|
|
||||||
snprintf(ModKey,sizeof(ModKey)-1,"%s_windows",MF_GetModname());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
RegisterKeySuffix("pev",HAM_SetPev);
|
|
||||||
|
|
||||||
// this is only needed for Linux
|
|
||||||
#if defined __linux__
|
|
||||||
RegisterKeySuffix("classbase",HAM_SetClassBase);
|
|
||||||
#else // Emulate it being set on Windows, since it's not needed
|
|
||||||
HAM_classbase=0;
|
|
||||||
HAM_classbaseset=1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
RegisterRegisterNatives();
|
|
||||||
|
|
||||||
FP_SetupOffsets(ModKey,HAM_GetKey);
|
|
||||||
|
|
||||||
HAM_CallConfigDone();
|
|
||||||
|
|
||||||
/* TODO: Cbase natives
|
|
||||||
if (HAM_Set & HAM_GOT_PEV)
|
|
||||||
{
|
|
||||||
HAM_RegisterCbaseFast();
|
|
||||||
}
|
|
||||||
HAM_RegisterCbaseSafe();
|
|
||||||
|
|
||||||
VTH_Natives();
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnPluginsLoaded()
|
|
||||||
{
|
|
||||||
NEW_Initialize(INDEXENT(0));
|
|
||||||
|
|
||||||
};
|
|
||||||
void OnPluginsUnloaded()
|
|
||||||
{
|
|
||||||
VTMan.Cleanup();
|
|
||||||
};
|
|
@ -1,120 +0,0 @@
|
|||||||
; Ham Sandwich module config file
|
|
||||||
; -
|
|
||||||
; Do not modify this file unless you know exactly what you're doing!
|
|
||||||
; -
|
|
||||||
; entry syntax is as follows:
|
|
||||||
; [modname]_[os]_key
|
|
||||||
; Example: the "use" key on TS running Linux would be "ts_linux_use"
|
|
||||||
; "modname" is the game directory, NOT the game description!
|
|
||||||
; eg: "ts", not "The Specialists"
|
|
||||||
; -
|
|
||||||
; Keys support either hexadecimal (MUST prefix with 0x) or base 10
|
|
||||||
; -
|
|
||||||
; Key types:
|
|
||||||
; * takedamage: this is the vtable index of the takedamage routine
|
|
||||||
; * use: this is the vtable index of the use routine
|
|
||||||
; * pev: this is the offset in bytes of the location of pev in the cbaseentity
|
|
||||||
; * classbase: this is the size in bytes of the cbaseentity base class LINUX ONLY
|
|
||||||
; NOTE: If the mod is compiled with GCC 3.3+ (NS is the only one
|
|
||||||
; I know of), then the classbase will always be 0x0
|
|
||||||
; -
|
|
||||||
; NOTE: If a mod is missing keys for a certain native, that particular native
|
|
||||||
; will not be loaded! Example: Say CS is missing the "takedamage" index
|
|
||||||
; but has the use and pev indexes. The hs_use and hs_pdata_cbase natives
|
|
||||||
; will be registered, but the hs_takedamage native will not be registered.
|
|
||||||
|
|
||||||
; Data dated: 2007-02-23
|
|
||||||
; Version tested: 1.6 Steam (legitimate)
|
|
||||||
cstrike_windows_takedamage 12
|
|
||||||
cstrike_windows_killed 14 ;estimated
|
|
||||||
cstrike_windows_addpoints 23 ;estimated
|
|
||||||
cstrike_windows_addpointstoteam 24 ;estimated
|
|
||||||
cstrike_windows_use 46
|
|
||||||
cstrike_windows_blocked 47 ;estimated
|
|
||||||
cstrike_windows_respawn 48 ;estimated
|
|
||||||
cstrike_windows_pev 4
|
|
||||||
cstrike_linux_restart 4 ;estimated
|
|
||||||
cstrike_linux_takedamage 14
|
|
||||||
cstrike_windows_addpoints 25 ;estimated
|
|
||||||
cstrike_windows_addpointstoteam 26 ;estimated
|
|
||||||
cstrike_linux_killed 16 ;estimated
|
|
||||||
cstrike_linux_use 48
|
|
||||||
cstrike_linux_blocked 49 ;estimated
|
|
||||||
cstrike_linux_respawn 50 ;estimated
|
|
||||||
cstrike_linux_pev 0
|
|
||||||
cstrike_linux_classbase 0x94
|
|
||||||
|
|
||||||
; Data dated: 2007-02-23
|
|
||||||
; Version tested: 1.6 Steam (legitimate)
|
|
||||||
czero_windows_takedamage 12
|
|
||||||
czero_windows_use 46
|
|
||||||
czero_windows_pev 4
|
|
||||||
czero_linux_takedamage 14
|
|
||||||
czero_linux_use 48
|
|
||||||
czero_linux_pev 0
|
|
||||||
czero_linux_classbase 0x94
|
|
||||||
|
|
||||||
; Data dated: 2007-02-23
|
|
||||||
; Version tested: 3.1
|
|
||||||
ns_windows_takedamage 10
|
|
||||||
ns_windows_use 49
|
|
||||||
ns_windows_pev 4
|
|
||||||
ns_linux_takedamage 11
|
|
||||||
ns_linux_use 50
|
|
||||||
ns_linux_pev 4
|
|
||||||
ns_linux_classbase 0x0
|
|
||||||
|
|
||||||
; Data dated: 2007-02-23
|
|
||||||
; Version tested: 3.2 beta 2
|
|
||||||
nsp_windows_takedamage 10
|
|
||||||
nsp_windows_use 49
|
|
||||||
nsp_windows_pev 4
|
|
||||||
nsp_linux_takedamage 11
|
|
||||||
nsp_linux_use 50
|
|
||||||
nsp_linux_pev 4
|
|
||||||
nsp_linux_classbase 0x0
|
|
||||||
|
|
||||||
; Data dated: 2007-02-23
|
|
||||||
; Version tested: 1.3 (?) Steam (legitimate)
|
|
||||||
dod_windows_takedamage 18
|
|
||||||
dod_windows_use 51
|
|
||||||
dod_windows_pev 4
|
|
||||||
dod_linux_takedamage 20
|
|
||||||
dod_linux_use 51
|
|
||||||
dod linux_pev 0
|
|
||||||
dod_linux_classbase 0x154
|
|
||||||
|
|
||||||
; Data dated: 2007-02-23
|
|
||||||
; Version tested: 2.1
|
|
||||||
ts_windows_takedamage 12
|
|
||||||
ts_windows_use 44
|
|
||||||
ts_windows_pev 4
|
|
||||||
ts_linux_takedamage 14
|
|
||||||
ts_linux_use 46
|
|
||||||
ts_linux_pev 0
|
|
||||||
ts_linux_classbase 0x470
|
|
||||||
|
|
||||||
; Data dated: 2007-02-23
|
|
||||||
; Version tested: 1.5 Steam (legitimate)
|
|
||||||
tfc_windows_takedamage 14
|
|
||||||
tfc_windows_use 48
|
|
||||||
tfc_windows_pev 4
|
|
||||||
tfc_linux_takedamage 16
|
|
||||||
tfc_linux_use 50
|
|
||||||
tfc_linux_pev 0
|
|
||||||
tfc_linux_classbase 0x60
|
|
||||||
|
|
||||||
; Data dated: 2007-02-23
|
|
||||||
; Version tested: 3.0
|
|
||||||
; Sven-Coop does not have a Linux build
|
|
||||||
svencoop_windows_takedamage 11
|
|
||||||
svencoop_windows_use 46
|
|
||||||
svencoop_windows_pev 4
|
|
||||||
|
|
||||||
; Data dated: 2007-02-26
|
|
||||||
; Version tested: 2.18.07
|
|
||||||
; Earth's Special Forces (I can't find the non beta version, but it should still work!)
|
|
||||||
; ESF does not have a Linux binary!
|
|
||||||
esf_openbeta_windows_takedamage 12
|
|
||||||
esf_openbeta_windows_use 46
|
|
||||||
esf_openbeta_windows_pev 4
|
|
@ -1,162 +0,0 @@
|
|||||||
/* Ham Sandwich
|
|
||||||
*
|
|
||||||
* by sawce
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by the
|
|
||||||
* Free Software Foundation; either version 2 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
|
|
||||||
* General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
* In addition, as a special exception, the author gives permission to
|
|
||||||
* link the code of this program with the Half-Life Game Engine ("HL
|
|
||||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
|
||||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
|
||||||
* respects for all of the code used other than the HL Engine and MODs
|
|
||||||
* from Valve. If you modify this file, you may extend this exception
|
|
||||||
* to your version of the file, but you are not obligated to do so. If
|
|
||||||
* you do not wish to do so, delete this exception statement from your
|
|
||||||
* version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef HAMSANDWICH_H
|
|
||||||
#define HAMSANDWICH_H
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
extern unsigned int HAM_pev;
|
|
||||||
extern unsigned int HAM_classbase;
|
|
||||||
|
|
||||||
enum HAMHooks
|
|
||||||
{
|
|
||||||
HAM_TakeDamage,
|
|
||||||
HAM_Use,
|
|
||||||
HAM_AddPoints,
|
|
||||||
HAM_AddPointsToTeam,
|
|
||||||
HAM_Blocked,
|
|
||||||
HAM_Killed,
|
|
||||||
HAM_Respawn,
|
|
||||||
HAM_Restart,
|
|
||||||
HAM_TakeHealth,
|
|
||||||
HAM_AddPlayerItem,
|
|
||||||
HAM_RemovePlayerItem,
|
|
||||||
HAM_BloodColor,
|
|
||||||
HAM_Classify,
|
|
||||||
HAM_GetToggleState,
|
|
||||||
HAM_IsAlive,
|
|
||||||
HAM_IsBSPModel,
|
|
||||||
HAM_IsInWorld,
|
|
||||||
HAM_IsMoving,
|
|
||||||
HAM_IsNetClient,
|
|
||||||
HAM_IsPlayer,
|
|
||||||
HAM_IsSneaking,
|
|
||||||
HAM_ObjectCaps,
|
|
||||||
HAM_Think,
|
|
||||||
HAM_Touch,
|
|
||||||
|
|
||||||
|
|
||||||
HAM_END_DONT_USE_ME
|
|
||||||
};
|
|
||||||
|
|
||||||
inline edict_t *PrivateToEdict(const void *pdata)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!pdata)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *ptr=(char*)pdata + HAM_pev;
|
|
||||||
entvars_t *pev=(entvars_t *)ptr;
|
|
||||||
|
|
||||||
if (!pev)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return pev->pContainingEntity;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline int PrivateToIndex(const void *pdata)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (pdata==NULL)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
char *ptr=(char*)pdata;
|
|
||||||
|
|
||||||
ptr+=HAM_pev;
|
|
||||||
|
|
||||||
entvars_t *pev=*(entvars_t **)ptr;
|
|
||||||
|
|
||||||
|
|
||||||
if (pev==NULL)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pev->pContainingEntity==NULL)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ENTINDEX_NEW(pev->pContainingEntity);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline int EntvarToIndex(entvars_t *pev)
|
|
||||||
{
|
|
||||||
if (pev==NULL)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pev->pContainingEntity==NULL)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ENTINDEX_NEW(pev->pContainingEntity);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline edict_t *EntvarToEdict(entvars_t *pev)
|
|
||||||
{
|
|
||||||
if (pev==NULL)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pev->pContainingEntity;
|
|
||||||
};
|
|
||||||
inline void **EdictToVTable(edict_t *ent)
|
|
||||||
{
|
|
||||||
char *btbl=(char *)ent->pvPrivateData;
|
|
||||||
btbl+=HAM_classbase;
|
|
||||||
return *((void ***)btbl);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void RegisterKeySuffix(const char *suffix, void (*callback)(const char *,const char *));
|
|
||||||
void RegisterConfigCallback(void (*callback)(void));
|
|
||||||
void HAM_CallConfigDone(void);
|
|
||||||
void HAM_CallInitialization(void);
|
|
||||||
int HAM_StrToNum(const char *input);
|
|
||||||
bool HAM_GetKey(const char *key, const char *data);
|
|
||||||
void HAM_SetPev(const char *key, const char *data);
|
|
||||||
#ifdef __linux__
|
|
||||||
void HAM_SetClassBase(const char *key, const char *data);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif //HAMSANDWICH_H
|
|
@ -1,137 +0,0 @@
|
|||||||
#if defined _hamsandwich_included
|
|
||||||
#endinput
|
|
||||||
#endif
|
|
||||||
#define _hamsandwich_included
|
|
||||||
|
|
||||||
#if AMXX_VERSION_NUM >= 175
|
|
||||||
#pragma reqlib hamsandwich
|
|
||||||
#if !defined AMXMODX_NOAUTOLOAD
|
|
||||||
#pragma loadlib hamsandwich
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#pragma library hamsandwich
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined _amxmodx_included
|
|
||||||
#include <amxmodx>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
native ham_addplayeritem(idPlayer,idItem);
|
|
||||||
native ham_eaddplayeritem(idPlayer,idItem);
|
|
||||||
|
|
||||||
native ham_addpoints(idEntity,points,bool:allownegative);
|
|
||||||
native ham_eaddpoints(idEntity,points,bool:allownegative);
|
|
||||||
|
|
||||||
native ham_addpointstoteam(idEntity,points,bool:allownegative);
|
|
||||||
native ham_eaddpointstoteam(idEntity,points,bool:allownegative);
|
|
||||||
|
|
||||||
native ham_blocked(idEntity,idOther);
|
|
||||||
native ham_eblocked(idEntity,idOther);
|
|
||||||
|
|
||||||
native ham_bloodcolor(idEntity);
|
|
||||||
native ham_ebloodcolor(idEntity);
|
|
||||||
|
|
||||||
native ham_classify(idEntity);
|
|
||||||
native ham_eclassify(idEntity);
|
|
||||||
|
|
||||||
native ham_gettogglestate(idEntity);
|
|
||||||
native ham_egettogglestate(idEntity);
|
|
||||||
|
|
||||||
native ham_isalive(idEntity);
|
|
||||||
native ham_eisalive(idEntity);
|
|
||||||
|
|
||||||
native ham_isbspmodel(idEntity);
|
|
||||||
native ham_eisbspmodel(idEntity);
|
|
||||||
|
|
||||||
native ham_isinworld(idEntity);
|
|
||||||
native ham_eisinworld(idEntity);
|
|
||||||
|
|
||||||
native ham_isnetclient(idEntity);
|
|
||||||
native ham_eisnetclient(idEntity);
|
|
||||||
|
|
||||||
native ham_isplayer(idEntity);
|
|
||||||
native ham_eisplayer(idEntity);
|
|
||||||
|
|
||||||
native ham_issneaking(idEntity);
|
|
||||||
native ham_eissneaking(idEntity);
|
|
||||||
|
|
||||||
native ham_killed(idEntity,idAttacker,iGib);
|
|
||||||
native ham_ekilled(idEntity,idAttacker,iGib);
|
|
||||||
|
|
||||||
native ham_objectcaps(idEntity);
|
|
||||||
native ham_eobjectcaps(idEntity);
|
|
||||||
|
|
||||||
native ham_removeplayeritem(idEntity,idItem);
|
|
||||||
native ham_eremoveplayeritem(idEntity,idItem);
|
|
||||||
|
|
||||||
native ham_respawn(idEntity);
|
|
||||||
native ham_erespawn(idEntity);
|
|
||||||
|
|
||||||
native ham_restart(idEntity);
|
|
||||||
native ham_erestart(idEntity);
|
|
||||||
|
|
||||||
native ham_takedamage(idEntity,idInflictor,idAttacker,Float:damage,dmgtype);
|
|
||||||
native ham_etakedamage(idEntity,idInflictor,idAttacker,Float:damage,dmgtype);
|
|
||||||
|
|
||||||
native ham_takehealth(idEntity,Float:health,dmgtype);
|
|
||||||
native ham_etakehealth(idEntity,Float:health,dmgtype);
|
|
||||||
|
|
||||||
native ham_think(idEntity);
|
|
||||||
native ham_ethink(idEntity);
|
|
||||||
|
|
||||||
native ham_touch(idEntity,idOther);
|
|
||||||
native ham_etouch(idEntity,idOther);
|
|
||||||
|
|
||||||
native ham_use(idEntity,idActivator,idCaller,use_type,Float:value);
|
|
||||||
native ham_euse(idEntity,idActivator,idCaller,use_type,Float:value);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
HAM_UNSET = 0,
|
|
||||||
HAM_IGNORED,
|
|
||||||
HAM_HANDLED,
|
|
||||||
HAM_OVERRIDE,
|
|
||||||
HAM_SUPERCEDE
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
enum HAMHooks
|
|
||||||
{
|
|
||||||
HAM_TakeDamage,
|
|
||||||
HAM_Use,
|
|
||||||
HAM_AddPoints,
|
|
||||||
HAM_AddPointsToTeam,
|
|
||||||
HAM_Blocked,
|
|
||||||
HAM_Killed,
|
|
||||||
HAM_Respawn,
|
|
||||||
HAM_Restart,
|
|
||||||
HAM_TakeHealth,
|
|
||||||
HAM_AddPlayerItem,
|
|
||||||
HAM_RemovePlayerItem,
|
|
||||||
HAM_BloodColor,
|
|
||||||
HAM_Classify,
|
|
||||||
HAM_GetToggleState,
|
|
||||||
HAM_IsAlive,
|
|
||||||
HAM_IsBSPModel,
|
|
||||||
HAM_IsInWorld,
|
|
||||||
HAM_IsMoving,
|
|
||||||
HAM_IsNetClient,
|
|
||||||
HAM_IsPlayer,
|
|
||||||
HAM_IsSneaking,
|
|
||||||
HAM_ObjectCaps,
|
|
||||||
HAM_Think,
|
|
||||||
HAM_Touch,
|
|
||||||
|
|
||||||
|
|
||||||
HAM_END_DONT_USE_ME
|
|
||||||
};
|
|
||||||
|
|
||||||
native ham_register(HAMHooks:hook, const classname[], const function[], post=0);
|
|
||||||
|
|
||||||
public __fatal_ham_error(const reason[])
|
|
||||||
{
|
|
||||||
set_fail_state(reason);
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 9.00
|
|
||||||
# Visual C++ Express 2005
|
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ham sandwich", "hs.vcproj", "{5B5DEFD0-28ED-4D0E-A1B0-50F9304A65DF}"
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug|Win32 = Debug|Win32
|
|
||||||
Release|Win32 = Release|Win32
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{5B5DEFD0-28ED-4D0E-A1B0-50F9304A65DF}.Debug|Win32.ActiveCfg = Debug|Win32
|
|
||||||
{5B5DEFD0-28ED-4D0E-A1B0-50F9304A65DF}.Debug|Win32.Build.0 = Debug|Win32
|
|
||||||
{5B5DEFD0-28ED-4D0E-A1B0-50F9304A65DF}.Release|Win32.ActiveCfg = Release|Win32
|
|
||||||
{5B5DEFD0-28ED-4D0E-A1B0-50F9304A65DF}.Release|Win32.Build.0 = Release|Win32
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
@ -1,364 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="Windows-1252"?>
|
|
||||||
<VisualStudioProject
|
|
||||||
ProjectType="Visual C++"
|
|
||||||
Version="8.00"
|
|
||||||
Name="ham sandwich"
|
|
||||||
ProjectGUID="{5B5DEFD0-28ED-4D0E-A1B0-50F9304A65DF}"
|
|
||||||
RootNamespace="hamsandwich"
|
|
||||||
>
|
|
||||||
<Platforms>
|
|
||||||
<Platform
|
|
||||||
Name="Win32"
|
|
||||||
/>
|
|
||||||
</Platforms>
|
|
||||||
<ToolFiles>
|
|
||||||
</ToolFiles>
|
|
||||||
<Configurations>
|
|
||||||
<Configuration
|
|
||||||
Name="Release|Win32"
|
|
||||||
OutputDirectory=".\Release"
|
|
||||||
IntermediateDirectory=".\Release"
|
|
||||||
ConfigurationType="2"
|
|
||||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
|
||||||
UseOfMFC="0"
|
|
||||||
ATLMinimizesCRunTimeLibraryUsage="false"
|
|
||||||
CharacterSet="2"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="2"
|
|
||||||
InlineFunctionExpansion="1"
|
|
||||||
AdditionalIncludeDirectories="z:\metamod\metamod;z:\hlsdk\common;z:\hlsdk\engine;z:\hlsdk\dlls;z:\hlsdk\pm_shared;..;..\tableentries"
|
|
||||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;ns_amxx_EXPORTS"
|
|
||||||
StringPooling="true"
|
|
||||||
RuntimeLibrary="0"
|
|
||||||
EnableFunctionLevelLinking="true"
|
|
||||||
RuntimeTypeInfo="false"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
AssemblerListingLocation=".\Release/"
|
|
||||||
ObjectFile=".\Release/"
|
|
||||||
ProgramDataBaseFileName=".\Release/"
|
|
||||||
WarningLevel="3"
|
|
||||||
SuppressStartupBanner="true"
|
|
||||||
CompileAs="0"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
PreprocessorDefinitions="NDEBUG"
|
|
||||||
Culture="1033"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
OutputFile="$(OutDir)\hamsandwich_amxx.dll"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCALinkTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManifestTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXDCMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCBscMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCFxCopTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCAppVerifierTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebDeploymentTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPostBuildEventTool"
|
|
||||||
/>
|
|
||||||
</Configuration>
|
|
||||||
<Configuration
|
|
||||||
Name="Debug|Win32"
|
|
||||||
OutputDirectory=".\Debug"
|
|
||||||
IntermediateDirectory=".\Debug"
|
|
||||||
ConfigurationType="2"
|
|
||||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
|
||||||
UseOfMFC="0"
|
|
||||||
ATLMinimizesCRunTimeLibraryUsage="false"
|
|
||||||
CharacterSet="2"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
CommandLine="del c:\HLServer\tfc\addons\amxmodx\modules
copy $(TargetDir)$(TargetFileName) c:\HLServer\tfc\addons\amxmodx\modules
"
|
|
||||||
Outputs=""echo lol"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"
|
|
||||||
PreprocessorDefinitions="_DEBUG"
|
|
||||||
MkTypLibCompatible="true"
|
|
||||||
SuppressStartupBanner="true"
|
|
||||||
TargetEnvironment="1"
|
|
||||||
TypeLibraryName=".\Debug/ns_amxx.tlb"
|
|
||||||
HeaderFileName=""
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="0"
|
|
||||||
AdditionalIncludeDirectories="z:\metamod\metamod;z:\hlsdk\common;z:\hlsdk\engine;z:\hlsdk\dlls;z:\hlsdk\pm_shared;..;..\tableentries"
|
|
||||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;ns_amxx_EXPORTS"
|
|
||||||
BasicRuntimeChecks="3"
|
|
||||||
RuntimeLibrary="3"
|
|
||||||
RuntimeTypeInfo="false"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
PrecompiledHeaderFile=".\Debug/ns_amxx.pch"
|
|
||||||
AssemblerListingLocation=".\Debug/"
|
|
||||||
ObjectFile=".\Debug/"
|
|
||||||
ProgramDataBaseFileName=".\Debug/"
|
|
||||||
WarningLevel="3"
|
|
||||||
SuppressStartupBanner="true"
|
|
||||||
DebugInformationFormat="3"
|
|
||||||
CompileAs="0"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
PreprocessorDefinitions="_DEBUG"
|
|
||||||
Culture="1033"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
OutputFile=".\Debug/hamsandwich_amxx.dll"
|
|
||||||
LinkIncremental="1"
|
|
||||||
SuppressStartupBanner="true"
|
|
||||||
GenerateDebugInformation="true"
|
|
||||||
ProgramDatabaseFile=".\Debug/ns_amxx.pdb"
|
|
||||||
ImportLibrary=".\Debug/ns_amxx.lib"
|
|
||||||
TargetMachine="1"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCALinkTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManifestTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXDCMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCBscMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCFxCopTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCAppVerifierTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebDeploymentTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPostBuildEventTool"
|
|
||||||
/>
|
|
||||||
</Configuration>
|
|
||||||
</Configurations>
|
|
||||||
<References>
|
|
||||||
</References>
|
|
||||||
<Files>
|
|
||||||
<Filter
|
|
||||||
Name="sdk"
|
|
||||||
>
|
|
||||||
<File
|
|
||||||
RelativePath="..\sdk\amxxmodule.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\sdk\amxxmodule.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\sdk\moduleconfig.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
<Filter
|
|
||||||
Name="Entries"
|
|
||||||
>
|
|
||||||
<File
|
|
||||||
RelativePath="..\tableentries\AddPlayerItem.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\tableentries\AddPoints.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\tableentries\AddPointsToTeam.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\tableentries\Blocked.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\tableentries\BloodColor.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\tableentries\Classify.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\tableentries\GetToggleState.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\tableentries\IsAlive.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\tableentries\IsBSPModel.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\tableentries\IsInWorld.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\tableentries\IsMoving.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\tableentries\IsNetClient.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\tableentries\IsPlayer.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\tableentries\IsSneaking.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\tableentries\Killed.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\tableentries\ObjectCaps.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\tableentries\RemovePlayerItem.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\tableentries\Respawn.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\tableentries\Restart.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\tableentries\TakeDamage.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\tableentries\Think.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\tableentries\Touch.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\tableentries\Use.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\tableentries\VTableEntries.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
<File
|
|
||||||
RelativePath="..\amxxapi.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\FileParser.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\FileParser.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\hamsandwich.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\Makefile"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\NEW_Util.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\Trampolines.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\vfunc_gcc295.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\vfunc_msvc.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\tableentries\VTableManager.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\tableentries\VTableManager.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Files>
|
|
||||||
<Globals>
|
|
||||||
</Globals>
|
|
||||||
</VisualStudioProject>
|
|
@ -1,185 +0,0 @@
|
|||||||
|
|
||||||
/* Ham Sandwich
|
|
||||||
*
|
|
||||||
* by sawce
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by the
|
|
||||||
* Free Software Foundation; either version 2 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
|
|
||||||
* General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
* In addition, as a special exception, the author gives permission to
|
|
||||||
* link the code of this program with the Half-Life Game Engine ("HL
|
|
||||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
|
||||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
|
||||||
* respects for all of the code used other than the HL Engine and MODs
|
|
||||||
* from Valve. If you modify this file, you may extend this exception
|
|
||||||
* to your version of the file, but you are not obligated to do so. If
|
|
||||||
* you do not wish to do so, delete this exception statement from your
|
|
||||||
* version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
#include "vfunc_msvc.h"
|
|
||||||
#include "vfunc_gcc295.h"
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL hs_takedamage(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
return VCall4<int>(
|
|
||||||
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
|
|
||||||
HAM_Takedamage, /*vtable entry*/
|
|
||||||
HAM_Classbase, /*size of class*/
|
|
||||||
&(INDEXENT_NEW(params[2])->v), /*inflictor*/
|
|
||||||
&(INDEXENT_NEW(params[3])->v), /*attacker*/
|
|
||||||
amx_ctof2(params[4]), /*damage*/
|
|
||||||
(int)params[5]); /*dmgtype*/
|
|
||||||
};
|
|
||||||
static cell AMX_NATIVE_CALL hs_use(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
VoidVCall4(
|
|
||||||
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
|
|
||||||
HAM_Use, /*vtable entry*/
|
|
||||||
HAM_Classbase, /*size of class*/
|
|
||||||
INDEXENT_NEW(params[2])->pvPrivateData, /*activator*/
|
|
||||||
INDEXENT_NEW(params[3])->pvPrivateData, /*caller*/
|
|
||||||
params[4], /*use type*/
|
|
||||||
amx_ctof2(params[5])); /*value*/
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Very fast, but potentially unsafe (if you use the wrong index/offset)
|
|
||||||
* method of converting a CBaseEntity pointer into a usable entity index
|
|
||||||
*/
|
|
||||||
static cell AMX_NATIVE_CALL hs_pdata_cbase(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// Get the offset of the private data
|
|
||||||
int Offset=params[2];
|
|
||||||
|
|
||||||
// If this is a linux server increase the offset
|
|
||||||
#ifdef __linux__
|
|
||||||
Offset+=params[3];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Get the CBase pointer
|
|
||||||
int *ent=*((int **)INDEXENT_NEW(params[1])->pvPrivateData + Offset);
|
|
||||||
|
|
||||||
// Null pointer; get out
|
|
||||||
if (ent==NULL)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now move up HAM_Pev bytes
|
|
||||||
char *bent=*(char**)&ent;
|
|
||||||
|
|
||||||
bent+=HAM_Pev;
|
|
||||||
|
|
||||||
entvars_t *pev=*(entvars_t **)&bent;
|
|
||||||
|
|
||||||
// Null pointer, get out
|
|
||||||
if (pev==NULL)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ENTINDEX_NEW(pev->pContainingEntity);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Slow, but very safe replacement for hs_pdata_cbase
|
|
||||||
* -
|
|
||||||
* This will scan through all entities to check their private
|
|
||||||
* data against the requested offset's data.
|
|
||||||
* It will never reference the requested PData, so unless
|
|
||||||
* the plugin author is way off with the offset it should
|
|
||||||
* never crash.
|
|
||||||
* -
|
|
||||||
* This should only be used for offset searching; NEVER
|
|
||||||
* in a release quality script.
|
|
||||||
*/
|
|
||||||
static cell AMX_NATIVE_CALL hs_pdata_cbase_safe(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// Get the offset of the private data
|
|
||||||
int Offset=params[2];
|
|
||||||
|
|
||||||
// If this is a linux server increase the offset
|
|
||||||
#ifdef __linux__
|
|
||||||
Offset+=params[3];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Get the CBase pointer
|
|
||||||
int *data=*((int **)INDEXENT_NEW(params[1])->pvPrivateData + Offset);
|
|
||||||
|
|
||||||
// Get the first entity
|
|
||||||
edict_t *Entity=INDEXENT_NEW(0);
|
|
||||||
|
|
||||||
// Get the last entity
|
|
||||||
edict_t *Last=INDEXENT_NEW(gpGlobals->maxEntities);
|
|
||||||
|
|
||||||
// Scan through all of the entities (excluding 0, because no other module allows for worldspawn)
|
|
||||||
while (Entity++<Last)
|
|
||||||
{
|
|
||||||
// If this entity's private data matches the CBase pointer requested, return
|
|
||||||
if (((int *)Entity->pvPrivateData)==data)
|
|
||||||
{
|
|
||||||
return ENTINDEX_NEW(Entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not found
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO reg_takedamage[] = {
|
|
||||||
{ "hs_takedamage", hs_takedamage },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
static AMX_NATIVE_INFO reg_use[] = {
|
|
||||||
{ "hs_use", hs_use },
|
|
||||||
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
static AMX_NATIVE_INFO reg_cbase_fast[] = {
|
|
||||||
{ "hs_pdata_cbase", hs_pdata_cbase },
|
|
||||||
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
static AMX_NATIVE_INFO reg_cbase_safe[] = {
|
|
||||||
{ "hs_pdata_cbase_safe", hs_pdata_cbase_safe },
|
|
||||||
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
void HAM_RegisterTakeDamage()
|
|
||||||
{
|
|
||||||
MF_AddNatives(reg_takedamage);
|
|
||||||
}
|
|
||||||
void HAM_RegisterUse()
|
|
||||||
{
|
|
||||||
MF_AddNatives(reg_use);
|
|
||||||
}
|
|
||||||
void HAM_RegisterCbaseFast()
|
|
||||||
{
|
|
||||||
MF_AddNatives(reg_cbase_fast);
|
|
||||||
}
|
|
||||||
void HAM_RegisterCbaseSafe()
|
|
||||||
{
|
|
||||||
MF_AddNatives(reg_cbase_safe);
|
|
||||||
}
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,491 +0,0 @@
|
|||||||
// Configuration
|
|
||||||
|
|
||||||
#ifndef __MODULECONFIG_H__
|
|
||||||
#define __MODULECONFIG_H__
|
|
||||||
|
|
||||||
// Module info
|
|
||||||
#define MODULE_NAME "Ham Sandwich"
|
|
||||||
#define MODULE_VERSION "1.77"
|
|
||||||
#define MODULE_AUTHOR "AMX Mod X Dev Team"
|
|
||||||
#define MODULE_URL "http://www.amxmodx.org"
|
|
||||||
#define MODULE_LOGTAG "HAM"
|
|
||||||
#define MODULE_LIBRARY "hamsandwich"
|
|
||||||
#define MODULE_LIBCLASS ""
|
|
||||||
// If you want the module not to be reloaded on mapchange, remove / comment out the next line
|
|
||||||
// #define MODULE_RELOAD_ON_MAPCHANGE
|
|
||||||
|
|
||||||
#ifdef __DATE__
|
|
||||||
#define MODULE_DATE __DATE__
|
|
||||||
#else // __DATE__
|
|
||||||
#define MODULE_DATE "Unknown"
|
|
||||||
#endif // __DATE__
|
|
||||||
|
|
||||||
// metamod plugin?
|
|
||||||
#define USE_METAMOD
|
|
||||||
|
|
||||||
// use memory manager/tester?
|
|
||||||
// note that if you use this, you cannot construct/allocate
|
|
||||||
// anything before the module attached (OnAmxxAttach).
|
|
||||||
// be careful of default constructors using new/malloc!
|
|
||||||
// #define MEMORY_TEST
|
|
||||||
|
|
||||||
// Unless you use STL or exceptions, keep this commented.
|
|
||||||
// It allows you to compile without libstdc++.so as a dependency
|
|
||||||
// #define NO_ALLOC_OVERRIDES
|
|
||||||
|
|
||||||
// Uncomment this if you are using MSVC8 or greater and want to fix some of the compatibility issues yourself
|
|
||||||
// #define NO_MSVC8_AUTO_COMPAT
|
|
||||||
|
|
||||||
/**
|
|
||||||
* AMXX Init functions
|
|
||||||
* Also consider using FN_META_*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** AMXX query */
|
|
||||||
//#define FN_AMXX_QUERY OnAmxxQuery
|
|
||||||
|
|
||||||
/** AMXX attach
|
|
||||||
* Do native functions init here (MF_AddNatives)
|
|
||||||
*/
|
|
||||||
#define FN_AMXX_ATTACH OnAmxxAttach
|
|
||||||
|
|
||||||
/** AMXX Detach (unload) */
|
|
||||||
//#define FN_AMXX_DETACH OnAmxxDetach
|
|
||||||
|
|
||||||
/** All plugins loaded
|
|
||||||
* Do forward functions init here (MF_RegisterForward)
|
|
||||||
*/
|
|
||||||
#define FN_AMXX_PLUGINSLOADED OnPluginsLoaded
|
|
||||||
|
|
||||||
/** All plugins are about to be unloaded */
|
|
||||||
//#define FN_AMXX_PLUGINSUNLOADING OnPluginsUnloading
|
|
||||||
|
|
||||||
/** All plugins are now unloaded */
|
|
||||||
#define FN_AMXX_PLUGINSUNLOADED OnPluginsUnloaded
|
|
||||||
|
|
||||||
/**** METAMOD ****/
|
|
||||||
// If your module doesn't use metamod, you may close the file now :)
|
|
||||||
#ifdef USE_METAMOD
|
|
||||||
// ----
|
|
||||||
// Hook Functions
|
|
||||||
// Uncomment these to be called
|
|
||||||
// You can also change the function name
|
|
||||||
|
|
||||||
// - Metamod init functions
|
|
||||||
// Also consider using FN_AMXX_*
|
|
||||||
// Meta query
|
|
||||||
//#define FN_META_QUERY OnMetaQuery
|
|
||||||
// Meta attach
|
|
||||||
//#define FN_META_ATTACH OnMetaAttach
|
|
||||||
// Meta detach
|
|
||||||
//#define FN_META_DETACH OnMetaDetach
|
|
||||||
|
|
||||||
// (wd) are Will Day's notes
|
|
||||||
// - GetEntityAPI2 functions
|
|
||||||
// #define FN_GameDLLInit GameDLLInit /* pfnGameInit() */
|
|
||||||
//#define FN_DispatchSpawn DispatchSpawn /* pfnSpawn() */
|
|
||||||
// #define FN_DispatchThink DispatchThink /* pfnThink() */
|
|
||||||
// #define FN_DispatchUse DispatchUse /* pfnUse() */
|
|
||||||
// #define FN_DispatchTouch DispatchTouch /* pfnTouch() */
|
|
||||||
// #define FN_DispatchBlocked DispatchBlocked /* pfnBlocked() */
|
|
||||||
//#define FN_DispatchKeyValue DispatchKeyValue /* pfnKeyValue() */
|
|
||||||
// #define FN_DispatchSave DispatchSave /* pfnSave() */
|
|
||||||
// #define FN_DispatchRestore DispatchRestore /* pfnRestore() */
|
|
||||||
// #define FN_DispatchObjectCollsionBox DispatchObjectCollsionBox /* pfnSetAbsBox() */
|
|
||||||
// #define FN_SaveWriteFields SaveWriteFields /* pfnSaveWriteFields() */
|
|
||||||
// #define FN_SaveReadFields SaveReadFields /* pfnSaveReadFields() */
|
|
||||||
// #define FN_SaveGlobalState SaveGlobalState /* pfnSaveGlobalState() */
|
|
||||||
// #define FN_RestoreGlobalState RestoreGlobalState /* pfnRestoreGlobalState() */
|
|
||||||
// #define FN_ResetGlobalState ResetGlobalState /* pfnResetGlobalState() */
|
|
||||||
//#define FN_ClientConnect ClientConnect /* pfnClientConnect() (wd) Client has connected */
|
|
||||||
//#define FN_ClientDisconnect ClientDisconnect /* pfnClientDisconnect() (wd) Player has left the game */
|
|
||||||
// #define FN_ClientKill ClientKill /* pfnClientKill() (wd) Player has typed "kill" */
|
|
||||||
// #define FN_ClientPutInServer ClientPutInServer /* pfnClientPutInServer() (wd) Client is entering the game */
|
|
||||||
// #define FN_ClientCommand ClientCommand /* pfnClientCommand() (wd) Player has sent a command (typed or from a bind) */
|
|
||||||
// #define FN_ClientUserInfoChanged ClientUserInfoChanged /* pfnClientUserInfoChanged() (wd) Client has updated their setinfo structure */
|
|
||||||
//#define FN_ServerActivate ServerActivate /* pfnServerActivate() (wd) Server is starting a new map */
|
|
||||||
//#define FN_ServerDeactivate ServerDeactivate /* pfnServerDeactivate() (wd) Server is leaving the map (shutdown or changelevel); SDK2 */
|
|
||||||
// #define FN_PlayerPreThink PlayerPreThink /* pfnPlayerPreThink() */
|
|
||||||
// #define FN_PlayerPostThink PlayerPostThink /* pfnPlayerPostThink() */
|
|
||||||
// #define FN_StartFrame StartFrame /* pfnStartFrame() */
|
|
||||||
// #define FN_ParmsNewLevel ParmsNewLevel /* pfnParmsNewLevel() */
|
|
||||||
// #define FN_ParmsChangeLevel ParmsChangeLevel /* pfnParmsChangeLevel() */
|
|
||||||
// #define FN_GetGameDescription GetGameDescription /* pfnGetGameDescription() Returns string describing current .dll. E.g. "TeamFotrress 2" "Half-Life" */
|
|
||||||
// #define FN_PlayerCustomization PlayerCustomization /* pfnPlayerCustomization() Notifies .dll of new customization for player. */
|
|
||||||
// #define FN_SpectatorConnect SpectatorConnect /* pfnSpectatorConnect() Called when spectator joins server */
|
|
||||||
// #define FN_SpectatorDisconnect SpectatorDisconnect /* pfnSpectatorDisconnect() Called when spectator leaves the server */
|
|
||||||
// #define FN_SpectatorThink SpectatorThink /* pfnSpectatorThink() Called when spectator sends a command packet (usercmd_t) */
|
|
||||||
// #define FN_Sys_Error Sys_Error /* pfnSys_Error() Notify game .dll that engine is going to shut down. Allows mod authors to set a breakpoint. SDK2 */
|
|
||||||
// #define FN_PM_Move PM_Move /* pfnPM_Move() (wd) SDK2 */
|
|
||||||
// #define FN_PM_Init PM_Init /* pfnPM_Init() Server version of player movement initialization; (wd) SDK2 */
|
|
||||||
// #define FN_PM_FindTextureType PM_FindTextureType /* pfnPM_FindTextureType() (wd) SDK2 */
|
|
||||||
// #define FN_SetupVisibility SetupVisibility /* pfnSetupVisibility() Set up PVS and PAS for networking for this client; (wd) SDK2 */
|
|
||||||
// #define FN_UpdateClientData UpdateClientData /* pfnUpdateClientData() Set up data sent only to specific client; (wd) SDK2 */
|
|
||||||
// #define FN_AddToFullPack AddToFullPack /* pfnAddToFullPack() (wd) SDK2 */
|
|
||||||
// #define FN_CreateBaseline CreateBaseline /* pfnCreateBaseline() Tweak entity baseline for network encoding allows setup of player baselines too.; (wd) SDK2 */
|
|
||||||
// #define FN_RegisterEncoders RegisterEncoders /* pfnRegisterEncoders() Callbacks for network encoding; (wd) SDK2 */
|
|
||||||
// #define FN_GetWeaponData GetWeaponData /* pfnGetWeaponData() (wd) SDK2 */
|
|
||||||
// #define FN_CmdStart CmdStart /* pfnCmdStart() (wd) SDK2 */
|
|
||||||
// #define FN_CmdEnd CmdEnd /* pfnCmdEnd() (wd) SDK2 */
|
|
||||||
// #define FN_ConnectionlessPacket ConnectionlessPacket /* pfnConnectionlessPacket() (wd) SDK2 */
|
|
||||||
// #define FN_GetHullBounds GetHullBounds /* pfnGetHullBounds() (wd) SDK2 */
|
|
||||||
// #define FN_CreateInstancedBaselines CreateInstancedBaselines /* pfnCreateInstancedBaselines() (wd) SDK2 */
|
|
||||||
// #define FN_InconsistentFile InconsistentFile /* pfnInconsistentFile() (wd) SDK2 */
|
|
||||||
// #define FN_AllowLagCompensation AllowLagCompensation /* pfnAllowLagCompensation() (wd) SDK2 */
|
|
||||||
|
|
||||||
// - GetEntityAPI2_Post functions
|
|
||||||
// #define FN_GameDLLInit_Post GameDLLInit_Post
|
|
||||||
// #define FN_DispatchSpawn_Post DispatchSpawn_Post
|
|
||||||
// #define FN_DispatchThink_Post DispatchThink_Post
|
|
||||||
// #define FN_DispatchUse_Post DispatchUse_Post
|
|
||||||
// #define FN_DispatchTouch_Post DispatchTouch_Post
|
|
||||||
// #define FN_DispatchBlocked_Post DispatchBlocked_Post
|
|
||||||
// #define FN_DispatchKeyValue_Post DispatchKeyValue_Post
|
|
||||||
// #define FN_DispatchSave_Post DispatchSave_Post
|
|
||||||
// #define FN_DispatchRestore_Post DispatchRestore_Post
|
|
||||||
// #define FN_DispatchObjectCollsionBox_Post DispatchObjectCollsionBox_Post
|
|
||||||
// #define FN_SaveWriteFields_Post SaveWriteFields_Post
|
|
||||||
// #define FN_SaveReadFields_Post SaveReadFields_Post
|
|
||||||
// #define FN_SaveGlobalState_Post SaveGlobalState_Post
|
|
||||||
// #define FN_RestoreGlobalState_Post RestoreGlobalState_Post
|
|
||||||
// #define FN_ResetGlobalState_Post ResetGlobalState_Post
|
|
||||||
// #define FN_ClientConnect_Post ClientConnect_Post
|
|
||||||
// #define FN_ClientDisconnect_Post ClientDisconnect_Post
|
|
||||||
// #define FN_ClientKill_Post ClientKill_Post
|
|
||||||
// #define FN_ClientPutInServer_Post ClientPutInServer_Post
|
|
||||||
// #define FN_ClientCommand_Post ClientCommand_Post
|
|
||||||
// #define FN_ClientUserInfoChanged_Post ClientUserInfoChanged_Post
|
|
||||||
//#define FN_ServerActivate_Post ServerActivate_Post
|
|
||||||
// #define FN_ServerDeactivate_Post ServerDeactivate_Post
|
|
||||||
// #define FN_PlayerPreThink_Post PlayerPreThink_Post
|
|
||||||
// #define FN_PlayerPostThink_Post PlayerPostThink_Post
|
|
||||||
// #define FN_StartFrame_Post StartFrame_Post
|
|
||||||
// #define FN_ParmsNewLevel_Post ParmsNewLevel_Post
|
|
||||||
// #define FN_ParmsChangeLevel_Post ParmsChangeLevel_Post
|
|
||||||
// #define FN_GetGameDescription_Post GetGameDescription_Post
|
|
||||||
// #define FN_PlayerCustomization_Post PlayerCustomization_Post
|
|
||||||
// #define FN_SpectatorConnect_Post SpectatorConnect_Post
|
|
||||||
// #define FN_SpectatorDisconnect_Post SpectatorDisconnect_Post
|
|
||||||
// #define FN_SpectatorThink_Post SpectatorThink_Post
|
|
||||||
// #define FN_Sys_Error_Post Sys_Error_Post
|
|
||||||
// #define FN_PM_Move_Post PM_Move_Post
|
|
||||||
// #define FN_PM_Init_Post PM_Init_Post
|
|
||||||
// #define FN_PM_FindTextureType_Post PM_FindTextureType_Post
|
|
||||||
// #define FN_SetupVisibility_Post SetupVisibility_Post
|
|
||||||
// #define FN_UpdateClientData_Post UpdateClientData_Post
|
|
||||||
// #define FN_AddToFullPack_Post AddToFullPack_Post
|
|
||||||
// #define FN_CreateBaseline_Post CreateBaseline_Post
|
|
||||||
// #define FN_RegisterEncoders_Post RegisterEncoders_Post
|
|
||||||
// #define FN_GetWeaponData_Post GetWeaponData_Post
|
|
||||||
// #define FN_CmdStart_Post CmdStart_Post
|
|
||||||
// #define FN_CmdEnd_Post CmdEnd_Post
|
|
||||||
// #define FN_ConnectionlessPacket_Post ConnectionlessPacket_Post
|
|
||||||
// #define FN_GetHullBounds_Post GetHullBounds_Post
|
|
||||||
// #define FN_CreateInstancedBaselines_Post CreateInstancedBaselines_Post
|
|
||||||
// #define FN_InconsistentFile_Post InconsistentFile_Post
|
|
||||||
// #define FN_AllowLagCompensation_Post AllowLagCompensation_Post
|
|
||||||
|
|
||||||
// - GetEngineAPI functions
|
|
||||||
// #define FN_PrecacheModel PrecacheModel
|
|
||||||
// #define FN_PrecacheSound PrecacheSound
|
|
||||||
// #define FN_SetModel SetModel
|
|
||||||
// #define FN_ModelIndex ModelIndex
|
|
||||||
// #define FN_ModelFrames ModelFrames
|
|
||||||
// #define FN_SetSize SetSize
|
|
||||||
// #define FN_ChangeLevel ChangeLevel
|
|
||||||
// #define FN_GetSpawnParms GetSpawnParms
|
|
||||||
// #define FN_SaveSpawnParms SaveSpawnParms
|
|
||||||
// #define FN_VecToYaw VecToYaw
|
|
||||||
// #define FN_VecToAngles VecToAngles
|
|
||||||
// #define FN_MoveToOrigin MoveToOrigin
|
|
||||||
// #define FN_ChangeYaw ChangeYaw
|
|
||||||
// #define FN_ChangePitch ChangePitch
|
|
||||||
// #define FN_FindEntityByString FindEntityByString
|
|
||||||
// #define FN_GetEntityIllum GetEntityIllum
|
|
||||||
// #define FN_FindEntityInSphere FindEntityInSphere
|
|
||||||
// #define FN_FindClientInPVS FindClientInPVS
|
|
||||||
// #define FN_EntitiesInPVS EntitiesInPVS
|
|
||||||
// #define FN_MakeVectors MakeVectors
|
|
||||||
// #define FN_AngleVectors AngleVectors
|
|
||||||
// #define FN_CreateEntity CreateEntity
|
|
||||||
// #define FN_RemoveEntity RemoveEntity
|
|
||||||
// #define FN_CreateNamedEntity CreateNamedEntity
|
|
||||||
// #define FN_MakeStatic MakeStatic
|
|
||||||
// #define FN_EntIsOnFloor EntIsOnFloor
|
|
||||||
// #define FN_DropToFloor DropToFloor
|
|
||||||
// #define FN_WalkMove WalkMove
|
|
||||||
// #define FN_SetOrigin SetOrigin
|
|
||||||
// #define FN_EmitSound EmitSound
|
|
||||||
// #define FN_EmitAmbientSound EmitAmbientSound
|
|
||||||
// #define FN_TraceLine TraceLine
|
|
||||||
// #define FN_TraceToss TraceToss
|
|
||||||
// #define FN_TraceMonsterHull TraceMonsterHull
|
|
||||||
// #define FN_TraceHull TraceHull
|
|
||||||
// #define FN_TraceModel TraceModel
|
|
||||||
// #define FN_TraceTexture TraceTexture
|
|
||||||
// #define FN_TraceSphere TraceSphere
|
|
||||||
// #define FN_GetAimVector GetAimVector
|
|
||||||
// #define FN_ServerCommand ServerCommand
|
|
||||||
// #define FN_ServerExecute ServerExecute
|
|
||||||
// #define FN_engClientCommand engClientCommand
|
|
||||||
// #define FN_ParticleEffect ParticleEffect
|
|
||||||
// #define FN_LightStyle LightStyle
|
|
||||||
// #define FN_DecalIndex DecalIndex
|
|
||||||
// #define FN_PointContents PointContents
|
|
||||||
// #define FN_MessageBegin MessageBegin
|
|
||||||
// #define FN_MessageEnd MessageEnd
|
|
||||||
// #define FN_WriteByte WriteByte
|
|
||||||
// #define FN_WriteChar WriteChar
|
|
||||||
// #define FN_WriteShort WriteShort
|
|
||||||
// #define FN_WriteLong WriteLong
|
|
||||||
// #define FN_WriteAngle WriteAngle
|
|
||||||
// #define FN_WriteCoord WriteCoord
|
|
||||||
// #define FN_WriteString WriteString
|
|
||||||
// #define FN_WriteEntity WriteEntity
|
|
||||||
// #define FN_CVarRegister CVarRegister
|
|
||||||
// #define FN_CVarGetFloat CVarGetFloat
|
|
||||||
// #define FN_CVarGetString CVarGetString
|
|
||||||
// #define FN_CVarSetFloat CVarSetFloat
|
|
||||||
// #define FN_CVarSetString CVarSetString
|
|
||||||
// #define FN_AlertMessage AlertMessage
|
|
||||||
// #define FN_EngineFprintf EngineFprintf
|
|
||||||
// #define FN_PvAllocEntPrivateData PvAllocEntPrivateData
|
|
||||||
// #define FN_PvEntPrivateData PvEntPrivateData
|
|
||||||
// #define FN_FreeEntPrivateData FreeEntPrivateData
|
|
||||||
// #define FN_SzFromIndex SzFromIndex
|
|
||||||
// #define FN_AllocString AllocString
|
|
||||||
// #define FN_GetVarsOfEnt GetVarsOfEnt
|
|
||||||
// #define FN_PEntityOfEntOffset PEntityOfEntOffset
|
|
||||||
// #define FN_EntOffsetOfPEntity EntOffsetOfPEntity
|
|
||||||
// #define FN_IndexOfEdict IndexOfEdict
|
|
||||||
// #define FN_PEntityOfEntIndex PEntityOfEntIndex
|
|
||||||
// #define FN_FindEntityByVars FindEntityByVars
|
|
||||||
// #define FN_GetModelPtr GetModelPtr
|
|
||||||
// #define FN_RegUserMsg RegUserMsg
|
|
||||||
// #define FN_AnimationAutomove AnimationAutomove
|
|
||||||
// #define FN_GetBonePosition GetBonePosition
|
|
||||||
// #define FN_FunctionFromName FunctionFromName
|
|
||||||
// #define FN_NameForFunction NameForFunction
|
|
||||||
// #define FN_ClientPrintf ClientPrintf
|
|
||||||
// #define FN_ServerPrint ServerPrint
|
|
||||||
// #define FN_Cmd_Args Cmd_Args
|
|
||||||
// #define FN_Cmd_Argv Cmd_Argv
|
|
||||||
// #define FN_Cmd_Argc Cmd_Argc
|
|
||||||
// #define FN_GetAttachment GetAttachment
|
|
||||||
// #define FN_CRC32_Init CRC32_Init
|
|
||||||
// #define FN_CRC32_ProcessBuffer CRC32_ProcessBuffer
|
|
||||||
// #define FN_CRC32_ProcessByte CRC32_ProcessByte
|
|
||||||
// #define FN_CRC32_Final CRC32_Final
|
|
||||||
// #define FN_RandomLong RandomLong
|
|
||||||
// #define FN_RandomFloat RandomFloat
|
|
||||||
// #define FN_SetView SetView
|
|
||||||
// #define FN_Time Time
|
|
||||||
// #define FN_CrosshairAngle CrosshairAngle
|
|
||||||
// #define FN_LoadFileForMe LoadFileForMe
|
|
||||||
// #define FN_FreeFile FreeFile
|
|
||||||
// #define FN_EndSection EndSection
|
|
||||||
// #define FN_CompareFileTime CompareFileTime
|
|
||||||
// #define FN_GetGameDir GetGameDir
|
|
||||||
// #define FN_Cvar_RegisterVariable Cvar_RegisterVariable
|
|
||||||
// #define FN_FadeClientVolume FadeClientVolume
|
|
||||||
// #define FN_SetClientMaxspeed SetClientMaxspeed
|
|
||||||
// #define FN_CreateFakeClient CreateFakeClient
|
|
||||||
// #define FN_RunPlayerMove RunPlayerMove
|
|
||||||
// #define FN_NumberOfEntities NumberOfEntities
|
|
||||||
// #define FN_GetInfoKeyBuffer GetInfoKeyBuffer
|
|
||||||
// #define FN_InfoKeyValue InfoKeyValue
|
|
||||||
// #define FN_SetKeyValue SetKeyValue
|
|
||||||
// #define FN_SetClientKeyValue SetClientKeyValue
|
|
||||||
// #define FN_IsMapValid IsMapValid
|
|
||||||
// #define FN_StaticDecal StaticDecal
|
|
||||||
// #define FN_PrecacheGeneric PrecacheGeneric
|
|
||||||
// #define FN_GetPlayerUserId GetPlayerUserId
|
|
||||||
// #define FN_BuildSoundMsg BuildSoundMsg
|
|
||||||
// #define FN_IsDedicatedServer IsDedicatedServer
|
|
||||||
// #define FN_CVarGetPointer CVarGetPointer
|
|
||||||
// #define FN_GetPlayerWONId GetPlayerWONId
|
|
||||||
// #define FN_Info_RemoveKey Info_RemoveKey
|
|
||||||
// #define FN_GetPhysicsKeyValue GetPhysicsKeyValue
|
|
||||||
// #define FN_SetPhysicsKeyValue SetPhysicsKeyValue
|
|
||||||
// #define FN_GetPhysicsInfoString GetPhysicsInfoString
|
|
||||||
// #define FN_PrecacheEvent PrecacheEvent
|
|
||||||
// #define FN_PlaybackEvent PlaybackEvent
|
|
||||||
// #define FN_SetFatPVS SetFatPVS
|
|
||||||
// #define FN_SetFatPAS SetFatPAS
|
|
||||||
// #define FN_CheckVisibility CheckVisibility
|
|
||||||
// #define FN_DeltaSetField DeltaSetField
|
|
||||||
// #define FN_DeltaUnsetField DeltaUnsetField
|
|
||||||
// #define FN_DeltaAddEncoder DeltaAddEncoder
|
|
||||||
// #define FN_GetCurrentPlayer GetCurrentPlayer
|
|
||||||
// #define FN_CanSkipPlayer CanSkipPlayer
|
|
||||||
// #define FN_DeltaFindField DeltaFindField
|
|
||||||
// #define FN_DeltaSetFieldByIndex DeltaSetFieldByIndex
|
|
||||||
// #define FN_DeltaUnsetFieldByIndex DeltaUnsetFieldByIndex
|
|
||||||
// #define FN_SetGroupMask SetGroupMask
|
|
||||||
// #define FN_engCreateInstancedBaseline engCreateInstancedBaseline
|
|
||||||
// #define FN_Cvar_DirectSet Cvar_DirectSet
|
|
||||||
// #define FN_ForceUnmodified ForceUnmodified
|
|
||||||
// #define FN_GetPlayerStats GetPlayerStats
|
|
||||||
// #define FN_AddServerCommand AddServerCommand
|
|
||||||
// #define FN_Voice_GetClientListening Voice_GetClientListening
|
|
||||||
// #define FN_Voice_SetClientListening Voice_SetClientListening
|
|
||||||
// #define FN_GetPlayerAuthId GetPlayerAuthId
|
|
||||||
|
|
||||||
// - GetEngineAPI_Post functions
|
|
||||||
// #define FN_PrecacheModel_Post PrecacheModel_Post
|
|
||||||
// #define FN_PrecacheSound_Post PrecacheSound_Post
|
|
||||||
// #define FN_SetModel_Post SetModel_Post
|
|
||||||
// #define FN_ModelIndex_Post ModelIndex_Post
|
|
||||||
// #define FN_ModelFrames_Post ModelFrames_Post
|
|
||||||
// #define FN_SetSize_Post SetSize_Post
|
|
||||||
// #define FN_ChangeLevel_Post ChangeLevel_Post
|
|
||||||
// #define FN_GetSpawnParms_Post GetSpawnParms_Post
|
|
||||||
// #define FN_SaveSpawnParms_Post SaveSpawnParms_Post
|
|
||||||
// #define FN_VecToYaw_Post VecToYaw_Post
|
|
||||||
// #define FN_VecToAngles_Post VecToAngles_Post
|
|
||||||
// #define FN_MoveToOrigin_Post MoveToOrigin_Post
|
|
||||||
// #define FN_ChangeYaw_Post ChangeYaw_Post
|
|
||||||
// #define FN_ChangePitch_Post ChangePitch_Post
|
|
||||||
// #define FN_FindEntityByString_Post FindEntityByString_Post
|
|
||||||
// #define FN_GetEntityIllum_Post GetEntityIllum_Post
|
|
||||||
// #define FN_FindEntityInSphere_Post FindEntityInSphere_Post
|
|
||||||
// #define FN_FindClientInPVS_Post FindClientInPVS_Post
|
|
||||||
// #define FN_EntitiesInPVS_Post EntitiesInPVS_Post
|
|
||||||
// #define FN_MakeVectors_Post MakeVectors_Post
|
|
||||||
// #define FN_AngleVectors_Post AngleVectors_Post
|
|
||||||
// #define FN_CreateEntity_Post CreateEntity_Post
|
|
||||||
// #define FN_RemoveEntity_Post RemoveEntity_Post
|
|
||||||
// #define FN_CreateNamedEntity_Post CreateNamedEntity_Post
|
|
||||||
// #define FN_MakeStatic_Post MakeStatic_Post
|
|
||||||
// #define FN_EntIsOnFloor_Post EntIsOnFloor_Post
|
|
||||||
// #define FN_DropToFloor_Post DropToFloor_Post
|
|
||||||
// #define FN_WalkMove_Post WalkMove_Post
|
|
||||||
// #define FN_SetOrigin_Post SetOrigin_Post
|
|
||||||
// #define FN_EmitSound_Post EmitSound_Post
|
|
||||||
// #define FN_EmitAmbientSound_Post EmitAmbientSound_Post
|
|
||||||
// #define FN_TraceLine_Post TraceLine_Post
|
|
||||||
// #define FN_TraceToss_Post TraceToss_Post
|
|
||||||
// #define FN_TraceMonsterHull_Post TraceMonsterHull_Post
|
|
||||||
// #define FN_TraceHull_Post TraceHull_Post
|
|
||||||
// #define FN_TraceModel_Post TraceModel_Post
|
|
||||||
// #define FN_TraceTexture_Post TraceTexture_Post
|
|
||||||
// #define FN_TraceSphere_Post TraceSphere_Post
|
|
||||||
// #define FN_GetAimVector_Post GetAimVector_Post
|
|
||||||
// #define FN_ServerCommand_Post ServerCommand_Post
|
|
||||||
// #define FN_ServerExecute_Post ServerExecute_Post
|
|
||||||
// #define FN_engClientCommand_Post engClientCommand_Post
|
|
||||||
// #define FN_ParticleEffect_Post ParticleEffect_Post
|
|
||||||
// #define FN_LightStyle_Post LightStyle_Post
|
|
||||||
// #define FN_DecalIndex_Post DecalIndex_Post
|
|
||||||
// #define FN_PointContents_Post PointContents_Post
|
|
||||||
// #define FN_MessageBegin_Post MessageBegin_Post
|
|
||||||
// #define FN_MessageEnd_Post MessageEnd_Post
|
|
||||||
// #define FN_WriteByte_Post WriteByte_Post
|
|
||||||
// #define FN_WriteChar_Post WriteChar_Post
|
|
||||||
// #define FN_WriteShort_Post WriteShort_Post
|
|
||||||
// #define FN_WriteLong_Post WriteLong_Post
|
|
||||||
// #define FN_WriteAngle_Post WriteAngle_Post
|
|
||||||
// #define FN_WriteCoord_Post WriteCoord_Post
|
|
||||||
// #define FN_WriteString_Post WriteString_Post
|
|
||||||
// #define FN_WriteEntity_Post WriteEntity_Post
|
|
||||||
// #define FN_CVarRegister_Post CVarRegister_Post
|
|
||||||
// #define FN_CVarGetFloat_Post CVarGetFloat_Post
|
|
||||||
// #define FN_CVarGetString_Post CVarGetString_Post
|
|
||||||
// #define FN_CVarSetFloat_Post CVarSetFloat_Post
|
|
||||||
// #define FN_CVarSetString_Post CVarSetString_Post
|
|
||||||
// #define FN_AlertMessage_Post AlertMessage_Post
|
|
||||||
// #define FN_EngineFprintf_Post EngineFprintf_Post
|
|
||||||
// #define FN_PvAllocEntPrivateData_Post PvAllocEntPrivateData_Post
|
|
||||||
// #define FN_PvEntPrivateData_Post PvEntPrivateData_Post
|
|
||||||
// #define FN_FreeEntPrivateData_Post FreeEntPrivateData_Post
|
|
||||||
// #define FN_SzFromIndex_Post SzFromIndex_Post
|
|
||||||
// #define FN_AllocString_Post AllocString_Post
|
|
||||||
// #define FN_GetVarsOfEnt_Post GetVarsOfEnt_Post
|
|
||||||
// #define FN_PEntityOfEntOffset_Post PEntityOfEntOffset_Post
|
|
||||||
// #define FN_EntOffsetOfPEntity_Post EntOffsetOfPEntity_Post
|
|
||||||
// #define FN_IndexOfEdict_Post IndexOfEdict_Post
|
|
||||||
// #define FN_PEntityOfEntIndex_Post PEntityOfEntIndex_Post
|
|
||||||
// #define FN_FindEntityByVars_Post FindEntityByVars_Post
|
|
||||||
// #define FN_GetModelPtr_Post GetModelPtr_Post
|
|
||||||
// #define FN_RegUserMsg_Post RegUserMsg_Post
|
|
||||||
// #define FN_AnimationAutomove_Post AnimationAutomove_Post
|
|
||||||
// #define FN_GetBonePosition_Post GetBonePosition_Post
|
|
||||||
// #define FN_FunctionFromName_Post FunctionFromName_Post
|
|
||||||
// #define FN_NameForFunction_Post NameForFunction_Post
|
|
||||||
// #define FN_ClientPrintf_Post ClientPrintf_Post
|
|
||||||
// #define FN_ServerPrint_Post ServerPrint_Post
|
|
||||||
// #define FN_Cmd_Args_Post Cmd_Args_Post
|
|
||||||
// #define FN_Cmd_Argv_Post Cmd_Argv_Post
|
|
||||||
// #define FN_Cmd_Argc_Post Cmd_Argc_Post
|
|
||||||
// #define FN_GetAttachment_Post GetAttachment_Post
|
|
||||||
// #define FN_CRC32_Init_Post CRC32_Init_Post
|
|
||||||
// #define FN_CRC32_ProcessBuffer_Post CRC32_ProcessBuffer_Post
|
|
||||||
// #define FN_CRC32_ProcessByte_Post CRC32_ProcessByte_Post
|
|
||||||
// #define FN_CRC32_Final_Post CRC32_Final_Post
|
|
||||||
// #define FN_RandomLong_Post RandomLong_Post
|
|
||||||
// #define FN_RandomFloat_Post RandomFloat_Post
|
|
||||||
// #define FN_SetView_Post SetView_Post
|
|
||||||
// #define FN_Time_Post Time_Post
|
|
||||||
// #define FN_CrosshairAngle_Post CrosshairAngle_Post
|
|
||||||
// #define FN_LoadFileForMe_Post LoadFileForMe_Post
|
|
||||||
// #define FN_FreeFile_Post FreeFile_Post
|
|
||||||
// #define FN_EndSection_Post EndSection_Post
|
|
||||||
// #define FN_CompareFileTime_Post CompareFileTime_Post
|
|
||||||
// #define FN_GetGameDir_Post GetGameDir_Post
|
|
||||||
// #define FN_Cvar_RegisterVariable_Post Cvar_RegisterVariable_Post
|
|
||||||
// #define FN_FadeClientVolume_Post FadeClientVolume_Post
|
|
||||||
// #define FN_SetClientMaxspeed_Post SetClientMaxspeed_Post
|
|
||||||
// #define FN_CreateFakeClient_Post CreateFakeClient_Post
|
|
||||||
// #define FN_RunPlayerMove_Post RunPlayerMove_Post
|
|
||||||
// #define FN_NumberOfEntities_Post NumberOfEntities_Post
|
|
||||||
// #define FN_GetInfoKeyBuffer_Post GetInfoKeyBuffer_Post
|
|
||||||
// #define FN_InfoKeyValue_Post InfoKeyValue_Post
|
|
||||||
// #define FN_SetKeyValue_Post SetKeyValue_Post
|
|
||||||
// #define FN_SetClientKeyValue_Post SetClientKeyValue_Post
|
|
||||||
// #define FN_IsMapValid_Post IsMapValid_Post
|
|
||||||
// #define FN_StaticDecal_Post StaticDecal_Post
|
|
||||||
// #define FN_PrecacheGeneric_Post PrecacheGeneric_Post
|
|
||||||
// #define FN_GetPlayerUserId_Post GetPlayerUserId_Post
|
|
||||||
// #define FN_BuildSoundMsg_Post BuildSoundMsg_Post
|
|
||||||
// #define FN_IsDedicatedServer_Post IsDedicatedServer_Post
|
|
||||||
// #define FN_CVarGetPointer_Post CVarGetPointer_Post
|
|
||||||
// #define FN_GetPlayerWONId_Post GetPlayerWONId_Post
|
|
||||||
// #define FN_Info_RemoveKey_Post Info_RemoveKey_Post
|
|
||||||
// #define FN_GetPhysicsKeyValue_Post GetPhysicsKeyValue_Post
|
|
||||||
// #define FN_SetPhysicsKeyValue_Post SetPhysicsKeyValue_Post
|
|
||||||
// #define FN_GetPhysicsInfoString_Post GetPhysicsInfoString_Post
|
|
||||||
//#define FN_PrecacheEvent_Post PrecacheEvent_Post
|
|
||||||
// #define FN_PlaybackEvent_Post PlaybackEvent_Post
|
|
||||||
// #define FN_SetFatPVS_Post SetFatPVS_Post
|
|
||||||
// #define FN_SetFatPAS_Post SetFatPAS_Post
|
|
||||||
// #define FN_CheckVisibility_Post CheckVisibility_Post
|
|
||||||
// #define FN_DeltaSetField_Post DeltaSetField_Post
|
|
||||||
// #define FN_DeltaUnsetField_Post DeltaUnsetField_Post
|
|
||||||
// #define FN_DeltaAddEncoder_Post DeltaAddEncoder_Post
|
|
||||||
// #define FN_GetCurrentPlayer_Post GetCurrentPlayer_Post
|
|
||||||
// #define FN_CanSkipPlayer_Post CanSkipPlayer_Post
|
|
||||||
// #define FN_DeltaFindField_Post DeltaFindField_Post
|
|
||||||
// #define FN_DeltaSetFieldByIndex_Post DeltaSetFieldByIndex_Post
|
|
||||||
// #define FN_DeltaUnsetFieldByIndex_Post DeltaUnsetFieldByIndex_Post
|
|
||||||
// #define FN_SetGroupMask_Post SetGroupMask_Post
|
|
||||||
// #define FN_engCreateInstancedBaseline_Post engCreateInstancedBaseline_Post
|
|
||||||
// #define FN_Cvar_DirectSet_Post Cvar_DirectSet_Post
|
|
||||||
// #define FN_ForceUnmodified_Post ForceUnmodified_Post
|
|
||||||
// #define FN_GetPlayerStats_Post GetPlayerStats_Post
|
|
||||||
// #define FN_AddServerCommand_Post AddServerCommand_Post
|
|
||||||
// #define FN_Voice_GetClientListening_Post Voice_GetClientListening_Post
|
|
||||||
// #define FN_Voice_SetClientListening_Post Voice_SetClientListening_Post
|
|
||||||
// #define FN_GetPlayerAuthId_Post GetPlayerAuthId_Post
|
|
||||||
|
|
||||||
// #define FN_OnFreeEntPrivateData OnFreeEntPrivateData
|
|
||||||
// #define FN_GameShutdown GameShutdown
|
|
||||||
// #define FN_ShouldCollide ShouldCollide
|
|
||||||
|
|
||||||
// #define FN_OnFreeEntPrivateData_Post OnFreeEntPrivateData_Post
|
|
||||||
// #define FN_GameShutdown_Post GameShutdown_Post
|
|
||||||
// #define FN_ShouldCollide_Post ShouldCollide_Post
|
|
||||||
|
|
||||||
|
|
||||||
#endif // USE_METAMOD
|
|
||||||
|
|
||||||
#endif // __MODULECONFIG_H__
|
|
@ -1,371 +0,0 @@
|
|||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "VTableManager.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
#include "vfunc_gcc295.h"
|
|
||||||
#include "vfunc_msvc.h"
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
|
|
||||||
#define ThisVTable VTableAddPlayerItem
|
|
||||||
#define ThisEntries AddPlayerItemEntries
|
|
||||||
|
|
||||||
#define ThisKey "addplayeritem"
|
|
||||||
#define ThisNative "ham_addplayeritem"
|
|
||||||
#define ThisENative "ham_eaddplayeritem"
|
|
||||||
#define ThisRegisterID HAM_AddPlayerItem
|
|
||||||
#define ThisParamCount 1
|
|
||||||
#define ThisVoidCall 0
|
|
||||||
|
|
||||||
unsigned int *ThisVTable::pevoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::pevset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseset=0;
|
|
||||||
unsigned int ThisVTable::index=0;
|
|
||||||
unsigned int ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO callnatives[] = {
|
|
||||||
{ ThisNative, ThisVTable::NativeCall },
|
|
||||||
{ ThisENative, ThisVTable::ENativeCall },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
|
|
||||||
*
|
|
||||||
* @param poffset Pointer to an integer that stores the pev offset for this mod.
|
|
||||||
* @param pset Pointer to an integer that tells whether pev offset was set or not.
|
|
||||||
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
|
|
||||||
* @param baseset Pointer to an integer that tells whether class base offset has been set.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
|
|
||||||
{
|
|
||||||
ThisVTable::pevoffset=poffset;
|
|
||||||
ThisVTable::pevset=pset;
|
|
||||||
|
|
||||||
ThisVTable::baseoffset=baseoffs;
|
|
||||||
ThisVTable::baseset=baseset;
|
|
||||||
|
|
||||||
ThisVTable::index=0;
|
|
||||||
ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
RegisterConfigCallback(ThisVTable::ConfigDone);
|
|
||||||
|
|
||||||
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
|
|
||||||
|
|
||||||
RegisterThisRegisterName(ThisRegisterID,ThisKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when one of this table entry's keyvalues is caught in a config file.
|
|
||||||
*
|
|
||||||
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
|
|
||||||
* @param data The data this keyvalue is set to.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::KeyValue(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
if (strcmp(key,ThisKey)==0)
|
|
||||||
{
|
|
||||||
ThisVTable::index=HAM_StrToNum(data);
|
|
||||||
ThisVTable::indexset=1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called immediately after the config file is done being parsed. Register our natives here.
|
|
||||||
*
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::ConfigDone(void)
|
|
||||||
{
|
|
||||||
if (ThisVTable::indexset && *(ThisVTable::baseset))
|
|
||||||
{
|
|
||||||
MF_AddNatives(callnatives);
|
|
||||||
|
|
||||||
if (*(ThisVTable::pevset))
|
|
||||||
{
|
|
||||||
//MF_AddNatives(registernatives);
|
|
||||||
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// Get the classname
|
|
||||||
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
|
|
||||||
|
|
||||||
// create an entity, assign it the gamedll's class, hook it and destroy it
|
|
||||||
edict_t *Entity=CREATE_ENTITY();
|
|
||||||
|
|
||||||
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
// Simulate a call to hs_register_id_takedamage
|
|
||||||
cell tempparams[4];
|
|
||||||
memcpy(tempparams,params,sizeof(cell)*4);
|
|
||||||
tempparams[1]=ENTINDEX_NEW(Entity);
|
|
||||||
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int funcid;
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
|
|
||||||
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
edict_t *Entity=INDEXENT_NEW(params[1]);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::NativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// scan to see if this virtual function is a trampoline
|
|
||||||
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
|
|
||||||
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=VTMan.ThisEntries.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (VTMan.ThisEntries[i]->IsTrampoline(func))
|
|
||||||
{
|
|
||||||
// this function is a trampoline
|
|
||||||
// use the original function instead
|
|
||||||
func=VTMan.ThisEntries[i]->GetOriginalFunction();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// TODO: Inline ASM this
|
|
||||||
#ifdef _WIN32
|
|
||||||
return reinterpret_cast<int (__fastcall *)(void *,int,void *)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
0, /*fastcall buffer*/
|
|
||||||
INDEXENT_NEW(params[2])->pvPrivateData /*item*/
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
return reinterpret_cast<int (*)(void *,void *)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
INDEXENT_NEW(params[2])->pvPrivateData /*item*/
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
return VCall1<int>(
|
|
||||||
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
|
|
||||||
ThisVTable::index, /*vtable entry*/
|
|
||||||
*(ThisVTable::baseoffset), /*size of class*/
|
|
||||||
INDEXENT_NEW(params[3])->pvPrivateData /*item*/
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param outtrampoline The trampoline that was created.
|
|
||||||
* @param origfunc The original function that was hooked.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
|
|
||||||
{
|
|
||||||
|
|
||||||
VTableEntryBase::CreateGenericTrampoline(manager,
|
|
||||||
vtable,
|
|
||||||
ThisVTable::index,
|
|
||||||
id,
|
|
||||||
outtrampoline,
|
|
||||||
origfunc,
|
|
||||||
reinterpret_cast<void *>(ThisVTable::EntryPoint),
|
|
||||||
ThisParamCount, // param count
|
|
||||||
ThisVoidCall, // voidcall
|
|
||||||
1); // thiscall
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param plugin The plugin that's requesting this.
|
|
||||||
* @param funcid The function id of the callback.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
|
|
||||||
{
|
|
||||||
void *ptr=vtable[ThisVTable::index];
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=manager->ThisEntries.size();
|
|
||||||
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_CELL/*item*/,FP_DONE);
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (manager->ThisEntries[i]->IsTrampoline(ptr))
|
|
||||||
{
|
|
||||||
// this function is already hooked!
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// this function is NOT hooked
|
|
||||||
void *tramp;
|
|
||||||
void *func;
|
|
||||||
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
|
|
||||||
ThisVTable *entry=new ThisVTable;
|
|
||||||
|
|
||||||
entry->Setup(&vtable[ThisVTable::index],tramp,func);
|
|
||||||
|
|
||||||
manager->ThisEntries.push_back(entry);
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
entry->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the command. This is called directly from our global hook function.
|
|
||||||
*
|
|
||||||
* @param pthis The "this" pointer, cast to a void. The victim.
|
|
||||||
* @param inflictor Damage inflictor.
|
|
||||||
* @param attacker The attacker who caused the inflictor to damage the victim.
|
|
||||||
* @param damage How much damage was caused.
|
|
||||||
* @param type Damage type (usually in bitmask form).
|
|
||||||
* @return Unsure. Does not appear to be used.
|
|
||||||
*/
|
|
||||||
int ThisVTable::Execute(void *pthis, void *item)
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
|
|
||||||
int end=Forwards.size();
|
|
||||||
|
|
||||||
int result=HAM_UNSET;
|
|
||||||
int thisresult=HAM_UNSET;
|
|
||||||
|
|
||||||
int iThis=PrivateToIndex(pthis);
|
|
||||||
int iItem=PrivateToIndex(item);
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
thisresult=MF_ExecuteForward(Forwards[i++],iThis,item);
|
|
||||||
|
|
||||||
if (thisresult>result)
|
|
||||||
{
|
|
||||||
result=thisresult;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
int ireturn=0;
|
|
||||||
|
|
||||||
if (result<HAM_SUPERCEDE)
|
|
||||||
{
|
|
||||||
#if defined _WIN32
|
|
||||||
ireturn=reinterpret_cast<int (__fastcall *)(void *,int,void *)>(function)(pthis,0,item);
|
|
||||||
#elif defined __linux__
|
|
||||||
ireturn=reinterpret_cast<int (*)(void *,void *)>(function)(pthis,item);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
i=0;
|
|
||||||
|
|
||||||
end=PostForwards.size();
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
MF_ExecuteForward(PostForwards[i++],iThis,iItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (result!=HAM_OVERRIDE)
|
|
||||||
return ireturn;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
int HAM_CDECL ThisVTable::EntryPoint(int id,void *pthis,void *item)
|
|
||||||
{
|
|
||||||
return VTMan.ThisEntries[id]->Execute(pthis,item);
|
|
||||||
}
|
|
@ -1,363 +0,0 @@
|
|||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "VTableManager.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
#include "vfunc_gcc295.h"
|
|
||||||
#include "vfunc_msvc.h"
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
|
|
||||||
#define ThisVTable VTableAddPoints
|
|
||||||
#define ThisEntries AddPointsEntries
|
|
||||||
#define ThisKey "addpoints"
|
|
||||||
#define ThisNative "ham_addpoints"
|
|
||||||
#define ThisENative "ham_eaddpoints"
|
|
||||||
#define ThisRegisterID HAM_AddPoints
|
|
||||||
#define ThisParamCount 0
|
|
||||||
#define ThisVoidCall 1
|
|
||||||
|
|
||||||
unsigned int *ThisVTable::pevoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::pevset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseset=0;
|
|
||||||
unsigned int ThisVTable::index=0;
|
|
||||||
unsigned int ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO callnatives[] = {
|
|
||||||
{ ThisNative, ThisVTable::NativeCall },
|
|
||||||
{ ThisENative, ThisVTable::ENativeCall },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
|
|
||||||
*
|
|
||||||
* @param poffset Pointer to an integer that stores the pev offset for this mod.
|
|
||||||
* @param pset Pointer to an integer that tells whether pev offset was set or not.
|
|
||||||
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
|
|
||||||
* @param baseset Pointer to an integer that tells whether class base offset has been set.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
|
|
||||||
{
|
|
||||||
ThisVTable::pevoffset=poffset;
|
|
||||||
ThisVTable::pevset=pset;
|
|
||||||
|
|
||||||
ThisVTable::baseoffset=baseoffs;
|
|
||||||
ThisVTable::baseset=baseset;
|
|
||||||
|
|
||||||
ThisVTable::index=0;
|
|
||||||
ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
RegisterConfigCallback(ThisVTable::ConfigDone);
|
|
||||||
|
|
||||||
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
|
|
||||||
|
|
||||||
RegisterThisRegisterName(ThisRegisterID,ThisKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when one of this table entry's keyvalues is caught in a config file.
|
|
||||||
*
|
|
||||||
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
|
|
||||||
* @param data The data this keyvalue is set to.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::KeyValue(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
if (strcmp(key,ThisKey)==0)
|
|
||||||
{
|
|
||||||
ThisVTable::index=HAM_StrToNum(data);
|
|
||||||
ThisVTable::indexset=1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called immediately after the config file is done being parsed. Register our natives here.
|
|
||||||
*
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::ConfigDone(void)
|
|
||||||
{
|
|
||||||
if (ThisVTable::indexset && *(ThisVTable::baseset))
|
|
||||||
{
|
|
||||||
MF_AddNatives(callnatives);
|
|
||||||
|
|
||||||
if (*(ThisVTable::pevset))
|
|
||||||
{
|
|
||||||
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// Get the classname
|
|
||||||
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
|
|
||||||
|
|
||||||
// create an entity, assign it the gamedll's class, hook it and destroy it
|
|
||||||
edict_t *Entity=CREATE_ENTITY();
|
|
||||||
|
|
||||||
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
// Simulate a call to hs_register_id_takedamage
|
|
||||||
cell tempparams[4];
|
|
||||||
memcpy(tempparams,params,sizeof(cell)*4);
|
|
||||||
tempparams[1]=ENTINDEX_NEW(Entity);
|
|
||||||
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int funcid;
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
|
|
||||||
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
edict_t *Entity=INDEXENT_NEW(params[1]);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::NativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// scan to see if this virtual function is a trampoline
|
|
||||||
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
|
|
||||||
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=VTMan.ThisEntries.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (VTMan.ThisEntries[i]->IsTrampoline(func))
|
|
||||||
{
|
|
||||||
// this function is a trampoline
|
|
||||||
// use the original function instead
|
|
||||||
func=VTMan.ThisEntries[i]->GetOriginalFunction();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// TODO: Inline ASM this
|
|
||||||
#ifdef _WIN32
|
|
||||||
reinterpret_cast<void (__fastcall *)(void *,int,int,int)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
0, /*fastcall buffer*/
|
|
||||||
params[2],
|
|
||||||
params[3]
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
reinterpret_cast<void (*)(void *,int,int)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
params[2],
|
|
||||||
params[3]
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
VoidVCall2(
|
|
||||||
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
|
|
||||||
ThisVTable::index, /*vtable entry*/
|
|
||||||
*(ThisVTable::baseoffset), /*size of class*/
|
|
||||||
params[2],
|
|
||||||
params[3]
|
|
||||||
);
|
|
||||||
return 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param outtrampoline The trampoline that was created.
|
|
||||||
* @param origfunc The original function that was hooked.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
|
|
||||||
{
|
|
||||||
|
|
||||||
VTableEntryBase::CreateGenericTrampoline(manager,
|
|
||||||
vtable,
|
|
||||||
ThisVTable::index,
|
|
||||||
id,
|
|
||||||
outtrampoline,
|
|
||||||
origfunc,
|
|
||||||
reinterpret_cast<void *>(ThisVTable::EntryPoint),
|
|
||||||
ThisParamCount, // param count
|
|
||||||
ThisVoidCall, // voidcall
|
|
||||||
1); // thiscall
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param plugin The plugin that's requesting this.
|
|
||||||
* @param funcid The function id of the callback.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
|
|
||||||
{
|
|
||||||
void *ptr=vtable[ThisVTable::index];
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=manager->ThisEntries.size();
|
|
||||||
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_CELL,FP_CELL,FP_DONE);
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (manager->ThisEntries[i]->IsTrampoline(ptr))
|
|
||||||
{
|
|
||||||
// this function is already hooked!
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// this function is NOT hooked
|
|
||||||
void *tramp;
|
|
||||||
void *func;
|
|
||||||
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
|
|
||||||
ThisVTable *entry=new ThisVTable;
|
|
||||||
|
|
||||||
entry->Setup(&vtable[ThisVTable::index],tramp,func);
|
|
||||||
|
|
||||||
manager->ThisEntries.push_back(entry);
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
entry->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the command. This is called directly from our global hook function.
|
|
||||||
*
|
|
||||||
* @param pthis The "this" pointer, cast to a void. The victim.
|
|
||||||
* @return Unsure. Does not appear to be used.
|
|
||||||
*/
|
|
||||||
void ThisVTable::Execute(void *pthis,int points, int allownegative)
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
|
|
||||||
int end=Forwards.size();
|
|
||||||
|
|
||||||
int result=HAM_UNSET;
|
|
||||||
int thisresult=HAM_UNSET;
|
|
||||||
|
|
||||||
int iThis=PrivateToIndex(pthis);
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
thisresult=MF_ExecuteForward(Forwards[i++],iThis,points,allownegative);
|
|
||||||
|
|
||||||
if (thisresult>result)
|
|
||||||
{
|
|
||||||
result=thisresult;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (result<HAM_SUPERCEDE)
|
|
||||||
{
|
|
||||||
#if defined _WIN32
|
|
||||||
reinterpret_cast<void (__fastcall *)(void *,int,int,int)>(function)(pthis,0,points,allownegative);
|
|
||||||
#elif defined __linux__
|
|
||||||
reinterpret_cast<void (*)(void *,int,int)>(function)(pthis,points,allownegative);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
i=0;
|
|
||||||
end=PostForwards.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
MF_ExecuteForward(PostForwards[i++],iThis,points,allownegative);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
void HAM_CDECL ThisVTable::EntryPoint(int id,void *pthis,int points,int allownegative)
|
|
||||||
{
|
|
||||||
VTMan.ThisEntries[id]->Execute(pthis,points,allownegative);
|
|
||||||
}
|
|
@ -1,362 +0,0 @@
|
|||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "VTableManager.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
#include "vfunc_gcc295.h"
|
|
||||||
#include "vfunc_msvc.h"
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
|
|
||||||
#define ThisVTable VTableAddPointsToTeam
|
|
||||||
#define ThisEntries AddPointsToTeamEntries
|
|
||||||
#define ThisKey "addpointstoteam"
|
|
||||||
#define ThisNative "ham_addpointstoteam"
|
|
||||||
#define ThisENative "ham_eaddpointstoteam"
|
|
||||||
#define ThisRegisterID HAM_AddPointsToTeam
|
|
||||||
#define ThisParamCount 2
|
|
||||||
#define ThisVoidCall 1
|
|
||||||
|
|
||||||
unsigned int *ThisVTable::pevoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::pevset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseset=0;
|
|
||||||
unsigned int ThisVTable::index=0;
|
|
||||||
unsigned int ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO callnatives[] = {
|
|
||||||
{ ThisNative, ThisVTable::NativeCall },
|
|
||||||
{ ThisENative, ThisVTable::ENativeCall },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
|
|
||||||
*
|
|
||||||
* @param poffset Pointer to an integer that stores the pev offset for this mod.
|
|
||||||
* @param pset Pointer to an integer that tells whether pev offset was set or not.
|
|
||||||
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
|
|
||||||
* @param baseset Pointer to an integer that tells whether class base offset has been set.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
|
|
||||||
{
|
|
||||||
ThisVTable::pevoffset=poffset;
|
|
||||||
ThisVTable::pevset=pset;
|
|
||||||
|
|
||||||
ThisVTable::baseoffset=baseoffs;
|
|
||||||
ThisVTable::baseset=baseset;
|
|
||||||
|
|
||||||
ThisVTable::index=0;
|
|
||||||
ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
RegisterConfigCallback(ThisVTable::ConfigDone);
|
|
||||||
|
|
||||||
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
|
|
||||||
|
|
||||||
RegisterThisRegisterName(ThisRegisterID,ThisKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when one of this table entry's keyvalues is caught in a config file.
|
|
||||||
*
|
|
||||||
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
|
|
||||||
* @param data The data this keyvalue is set to.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::KeyValue(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
if (strcmp(key,ThisKey)==0)
|
|
||||||
{
|
|
||||||
ThisVTable::index=HAM_StrToNum(data);
|
|
||||||
ThisVTable::indexset=1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called immediately after the config file is done being parsed. Register our natives here.
|
|
||||||
*
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::ConfigDone(void)
|
|
||||||
{
|
|
||||||
if (ThisVTable::indexset && *(ThisVTable::baseset))
|
|
||||||
{
|
|
||||||
MF_AddNatives(callnatives);
|
|
||||||
|
|
||||||
if (*(ThisVTable::pevset))
|
|
||||||
{
|
|
||||||
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// Get the classname
|
|
||||||
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
|
|
||||||
|
|
||||||
// create an entity, assign it the gamedll's class, hook it and destroy it
|
|
||||||
edict_t *Entity=CREATE_ENTITY();
|
|
||||||
|
|
||||||
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
// Simulate a call to hs_register_id_takedamage
|
|
||||||
cell tempparams[4];
|
|
||||||
memcpy(tempparams,params,sizeof(cell)*4);
|
|
||||||
tempparams[1]=ENTINDEX_NEW(Entity);
|
|
||||||
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int funcid;
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
|
|
||||||
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
edict_t *Entity=INDEXENT_NEW(params[1]);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::NativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// scan to see if this virtual function is a trampoline
|
|
||||||
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
|
|
||||||
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=VTMan.ThisEntries.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (VTMan.ThisEntries[i]->IsTrampoline(func))
|
|
||||||
{
|
|
||||||
// this function is a trampoline
|
|
||||||
// use the original function instead
|
|
||||||
func=VTMan.ThisEntries[i]->GetOriginalFunction();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// TODO: Inline ASM this
|
|
||||||
#ifdef _WIN32
|
|
||||||
reinterpret_cast<void (__fastcall *)(void *,int,int,int)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
0, /*fastcall buffer*/
|
|
||||||
params[2],
|
|
||||||
params[3]
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
reinterpret_cast<void (*)(void *,int,int)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
params[2],
|
|
||||||
params[3]
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
VoidVCall2(
|
|
||||||
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
|
|
||||||
ThisVTable::index, /*vtable entry*/
|
|
||||||
*(ThisVTable::baseoffset), /*size of class*/
|
|
||||||
params[2],
|
|
||||||
params[3]
|
|
||||||
);
|
|
||||||
return 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param outtrampoline The trampoline that was created.
|
|
||||||
* @param origfunc The original function that was hooked.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
|
|
||||||
{
|
|
||||||
|
|
||||||
VTableEntryBase::CreateGenericTrampoline(manager,
|
|
||||||
vtable,
|
|
||||||
ThisVTable::index,
|
|
||||||
id,
|
|
||||||
outtrampoline,
|
|
||||||
origfunc,
|
|
||||||
reinterpret_cast<void *>(ThisVTable::EntryPoint),
|
|
||||||
ThisParamCount, // param count
|
|
||||||
ThisVoidCall, // voidcall
|
|
||||||
1); // thiscall
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param plugin The plugin that's requesting this.
|
|
||||||
* @param funcid The function id of the callback.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
|
|
||||||
{
|
|
||||||
void *ptr=vtable[ThisVTable::index];
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=manager->ThisEntries.size();
|
|
||||||
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_CELL,FP_CELL,FP_DONE);
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (manager->ThisEntries[i]->IsTrampoline(ptr))
|
|
||||||
{
|
|
||||||
// this function is already hooked!
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// this function is NOT hooked
|
|
||||||
void *tramp;
|
|
||||||
void *func;
|
|
||||||
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
|
|
||||||
ThisVTable *entry=new ThisVTable;
|
|
||||||
|
|
||||||
entry->Setup(&vtable[ThisVTable::index],tramp,func);
|
|
||||||
|
|
||||||
manager->ThisEntries.push_back(entry);
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
entry->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the command. This is called directly from our global hook function.
|
|
||||||
*
|
|
||||||
* @param pthis The "this" pointer, cast to a void. The victim.
|
|
||||||
* @return Unsure. Does not appear to be used.
|
|
||||||
*/
|
|
||||||
void ThisVTable::Execute(void *pthis,int points, int allownegative)
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
|
|
||||||
int end=Forwards.size();
|
|
||||||
|
|
||||||
int result=HAM_UNSET;
|
|
||||||
int thisresult=HAM_UNSET;
|
|
||||||
|
|
||||||
int iThis=PrivateToIndex(pthis);
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
thisresult=MF_ExecuteForward(Forwards[i++],iThis,points,allownegative);
|
|
||||||
|
|
||||||
if (thisresult>result)
|
|
||||||
{
|
|
||||||
result=thisresult;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (result<HAM_SUPERCEDE)
|
|
||||||
{
|
|
||||||
#if defined _WIN32
|
|
||||||
reinterpret_cast<void (__fastcall *)(void *,int,int,int)>(function)(pthis,0,points,allownegative);
|
|
||||||
#elif defined __linux__
|
|
||||||
reinterpret_cast<void (*)(void *,int,int)>(function)(pthis,points,allownegative);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
i=0;
|
|
||||||
end=PostForwards.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
MF_ExecuteForward(PostForwards[i++],iThis,points,allownegative);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
void HAM_CDECL ThisVTable::EntryPoint(int id,void *pthis,int points,int allownegative)
|
|
||||||
{
|
|
||||||
VTMan.ThisEntries[id]->Execute(pthis,points,allownegative);
|
|
||||||
}
|
|
@ -1,366 +0,0 @@
|
|||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "VTableManager.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
#include "vfunc_gcc295.h"
|
|
||||||
#include "vfunc_msvc.h"
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
|
|
||||||
#define ThisVTable VTableBlocked
|
|
||||||
#define ThisEntries BlockedEntries
|
|
||||||
|
|
||||||
#define ThisKey "blocked"
|
|
||||||
#define ThisNative "ham_blocked"
|
|
||||||
#define ThisENative "ham_eblocked"
|
|
||||||
#define ThisRegisterID HAM_Blocked
|
|
||||||
#define ThisParamCount 1
|
|
||||||
#define ThisVoidCall 1
|
|
||||||
|
|
||||||
|
|
||||||
unsigned int *ThisVTable::pevoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::pevset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseset=0;
|
|
||||||
unsigned int ThisVTable::index=0;
|
|
||||||
unsigned int ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO callnatives[] = {
|
|
||||||
{ ThisNative, ThisVTable::NativeCall },
|
|
||||||
{ ThisENative, ThisVTable::ENativeCall },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
|
|
||||||
*
|
|
||||||
* @param poffset Pointer to an integer that stores the pev offset for this mod.
|
|
||||||
* @param pset Pointer to an integer that tells whether pev offset was set or not.
|
|
||||||
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
|
|
||||||
* @param baseset Pointer to an integer that tells whether class base offset has been set.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
|
|
||||||
{
|
|
||||||
ThisVTable::pevoffset=poffset;
|
|
||||||
ThisVTable::pevset=pset;
|
|
||||||
|
|
||||||
ThisVTable::baseoffset=baseoffs;
|
|
||||||
ThisVTable::baseset=baseset;
|
|
||||||
|
|
||||||
ThisVTable::index=0;
|
|
||||||
ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
RegisterConfigCallback(ThisVTable::ConfigDone);
|
|
||||||
|
|
||||||
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
|
|
||||||
|
|
||||||
RegisterThisRegisterName(ThisRegisterID,ThisKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when one of this table entry's keyvalues is caught in a config file.
|
|
||||||
*
|
|
||||||
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
|
|
||||||
* @param data The data this keyvalue is set to.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::KeyValue(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
if (strcmp(key,ThisKey)==0)
|
|
||||||
{
|
|
||||||
ThisVTable::index=HAM_StrToNum(data);
|
|
||||||
ThisVTable::indexset=1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called immediately after the config file is done being parsed. Register our natives here.
|
|
||||||
*
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::ConfigDone(void)
|
|
||||||
{
|
|
||||||
if (ThisVTable::indexset && *(ThisVTable::baseset))
|
|
||||||
{
|
|
||||||
MF_AddNatives(callnatives);
|
|
||||||
|
|
||||||
if (*(ThisVTable::pevset))
|
|
||||||
{
|
|
||||||
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// Get the classname
|
|
||||||
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
|
|
||||||
|
|
||||||
// create an entity, assign it the gamedll's class, hook it and destroy it
|
|
||||||
edict_t *Entity=CREATE_ENTITY();
|
|
||||||
|
|
||||||
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
// Simulate a call to hs_register_id_takedamage
|
|
||||||
cell tempparams[4];
|
|
||||||
memcpy(tempparams,params,sizeof(cell)*4);
|
|
||||||
tempparams[1]=ENTINDEX_NEW(Entity);
|
|
||||||
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int funcid;
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
|
|
||||||
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
edict_t *Entity=INDEXENT_NEW(params[1]);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::NativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// scan to see if this virtual function is a trampoline
|
|
||||||
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
|
|
||||||
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=VTMan.ThisEntries.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (VTMan.ThisEntries[i]->IsTrampoline(func))
|
|
||||||
{
|
|
||||||
// this function is a trampoline
|
|
||||||
// use the original function instead
|
|
||||||
func=VTMan.ThisEntries[i]->GetOriginalFunction();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// TODO: Inline ASM this
|
|
||||||
#ifdef _WIN32
|
|
||||||
reinterpret_cast<void (__fastcall *)(void *,int,void *)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
0, /*fastcall buffer*/
|
|
||||||
INDEXENT_NEW(params[2])->pvPrivateData /*other*/
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
reinterpret_cast<void (*)(void *,void *)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
INDEXENT_NEW(params[2])->pvPrivateData /*other*/
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
return 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
VoidVCall1(
|
|
||||||
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
|
|
||||||
ThisVTable::index, /*vtable entry*/
|
|
||||||
*(ThisVTable::baseoffset), /*size of class*/
|
|
||||||
INDEXENT_NEW(params[2])->pvPrivateData /*other*/
|
|
||||||
);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param outtrampoline The trampoline that was created.
|
|
||||||
* @param origfunc The original function that was hooked.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
|
|
||||||
{
|
|
||||||
|
|
||||||
VTableEntryBase::CreateGenericTrampoline(manager,
|
|
||||||
vtable,
|
|
||||||
ThisVTable::index,
|
|
||||||
id,
|
|
||||||
outtrampoline,
|
|
||||||
origfunc,
|
|
||||||
reinterpret_cast<void *>(ThisVTable::EntryPoint),
|
|
||||||
ThisParamCount, // param count
|
|
||||||
ThisVoidCall, // voidcall
|
|
||||||
1); // thiscall
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param plugin The plugin that's requesting this.
|
|
||||||
* @param funcid The function id of the callback.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
|
|
||||||
{
|
|
||||||
void *ptr=vtable[ThisVTable::index];
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=manager->ThisEntries.size();
|
|
||||||
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_CELL/*other*/,FP_DONE);
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (manager->ThisEntries[i]->IsTrampoline(ptr))
|
|
||||||
{
|
|
||||||
// this function is already hooked!
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// this function is NOT hooked
|
|
||||||
void *tramp;
|
|
||||||
void *func;
|
|
||||||
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
|
|
||||||
ThisVTable *entry=new ThisVTable;
|
|
||||||
|
|
||||||
entry->Setup(&vtable[ThisVTable::index],tramp,func);
|
|
||||||
|
|
||||||
manager->ThisEntries.push_back(entry);
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
entry->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the command. This is called directly from our global hook function.
|
|
||||||
*
|
|
||||||
* @param pthis The "this" pointer, cast to a void. The victim.
|
|
||||||
* @param activator Entity causing the opening.
|
|
||||||
* @param caller Entity controlling the caller.
|
|
||||||
* @param type USE_TYPE (USE_{ON,OFF,SET}
|
|
||||||
* @param value Use value, only seen set when USE_SET is used.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Execute(void *pthis, void *other)
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
|
|
||||||
int end=Forwards.size();
|
|
||||||
|
|
||||||
int result=HAM_UNSET;
|
|
||||||
int thisresult=HAM_UNSET;
|
|
||||||
|
|
||||||
int iThis=PrivateToIndex(pthis);
|
|
||||||
int iOther=PrivateToIndex(other);
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
thisresult=MF_ExecuteForward(Forwards[i++],iThis,iOther);
|
|
||||||
|
|
||||||
if (thisresult>result)
|
|
||||||
{
|
|
||||||
result=thisresult;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (result<HAM_SUPERCEDE)
|
|
||||||
{
|
|
||||||
#if defined _WIN32
|
|
||||||
reinterpret_cast<void (__fastcall *)(void *,int, void *)>(function)(pthis,0,other);
|
|
||||||
#elif defined __linux__
|
|
||||||
reinterpret_cast<void (*)(void *,void *)>(function)(pthis,other);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
i=0;
|
|
||||||
end=PostForwards.size();
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
MF_ExecuteForward(PostForwards[i++],iThis,iOther);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
void HAM_CDECL ThisVTable::EntryPoint(int id,void *pthis,void *other)
|
|
||||||
{
|
|
||||||
VTMan.ThisEntries[id]->Execute(pthis,other);
|
|
||||||
}
|
|
@ -1,366 +0,0 @@
|
|||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "VTableManager.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
#include "vfunc_gcc295.h"
|
|
||||||
#include "vfunc_msvc.h"
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
|
|
||||||
#define ThisVTable VTableBloodColor
|
|
||||||
#define ThisEntries BloodColorEntries
|
|
||||||
|
|
||||||
#define ThisKey "bloodcolor"
|
|
||||||
#define ThisNative "ham_bloodcolor"
|
|
||||||
#define ThisENative "ham_ebloodcolor"
|
|
||||||
#define ThisRegisterID HAM_BloodColor
|
|
||||||
#define ThisParamCount 0
|
|
||||||
#define ThisVoidCall 0
|
|
||||||
|
|
||||||
unsigned int *ThisVTable::pevoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::pevset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseset=0;
|
|
||||||
unsigned int ThisVTable::index=0;
|
|
||||||
unsigned int ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO callnatives[] = {
|
|
||||||
{ ThisNative, ThisVTable::NativeCall },
|
|
||||||
{ ThisENative, ThisVTable::ENativeCall },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
|
|
||||||
*
|
|
||||||
* @param poffset Pointer to an integer that stores the pev offset for this mod.
|
|
||||||
* @param pset Pointer to an integer that tells whether pev offset was set or not.
|
|
||||||
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
|
|
||||||
* @param baseset Pointer to an integer that tells whether class base offset has been set.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
|
|
||||||
{
|
|
||||||
ThisVTable::pevoffset=poffset;
|
|
||||||
ThisVTable::pevset=pset;
|
|
||||||
|
|
||||||
ThisVTable::baseoffset=baseoffs;
|
|
||||||
ThisVTable::baseset=baseset;
|
|
||||||
|
|
||||||
ThisVTable::index=0;
|
|
||||||
ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
RegisterConfigCallback(ThisVTable::ConfigDone);
|
|
||||||
|
|
||||||
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
|
|
||||||
|
|
||||||
RegisterThisRegisterName(ThisRegisterID,ThisKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when one of this table entry's keyvalues is caught in a config file.
|
|
||||||
*
|
|
||||||
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
|
|
||||||
* @param data The data this keyvalue is set to.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::KeyValue(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
if (strcmp(key,ThisKey)==0)
|
|
||||||
{
|
|
||||||
ThisVTable::index=HAM_StrToNum(data);
|
|
||||||
ThisVTable::indexset=1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called immediately after the config file is done being parsed. Register our natives here.
|
|
||||||
*
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::ConfigDone(void)
|
|
||||||
{
|
|
||||||
if (ThisVTable::indexset && *(ThisVTable::baseset))
|
|
||||||
{
|
|
||||||
MF_AddNatives(callnatives);
|
|
||||||
|
|
||||||
if (*(ThisVTable::pevset))
|
|
||||||
{
|
|
||||||
//MF_AddNatives(registernatives);
|
|
||||||
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// Get the classname
|
|
||||||
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
|
|
||||||
|
|
||||||
// create an entity, assign it the gamedll's class, hook it and destroy it
|
|
||||||
edict_t *Entity=CREATE_ENTITY();
|
|
||||||
|
|
||||||
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
// Simulate a call to hs_register_id_takedamage
|
|
||||||
cell tempparams[4];
|
|
||||||
memcpy(tempparams,params,sizeof(cell)*4);
|
|
||||||
tempparams[1]=ENTINDEX_NEW(Entity);
|
|
||||||
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int funcid;
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
|
|
||||||
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
edict_t *Entity=INDEXENT_NEW(params[1]);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::NativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// scan to see if this virtual function is a trampoline
|
|
||||||
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
|
|
||||||
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=VTMan.ThisEntries.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (VTMan.ThisEntries[i]->IsTrampoline(func))
|
|
||||||
{
|
|
||||||
// this function is a trampoline
|
|
||||||
// use the original function instead
|
|
||||||
func=VTMan.ThisEntries[i]->GetOriginalFunction();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// TODO: Inline ASM this
|
|
||||||
#ifdef _WIN32
|
|
||||||
return reinterpret_cast<int (__fastcall *)(void *,int)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
0 /*fastcall buffer*/
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
return reinterpret_cast<int (*)(void *)>(func)(
|
|
||||||
pthis /*this*/
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
return VCall4<int>(
|
|
||||||
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
|
|
||||||
ThisVTable::index, /*vtable entry*/
|
|
||||||
*(ThisVTable::baseoffset), /*size of class*/
|
|
||||||
&(INDEXENT_NEW(params[2])->v), /*inflictor*/
|
|
||||||
&(INDEXENT_NEW(params[3])->v), /*attacker*/
|
|
||||||
amx_ctof2(params[4]), /*damage*/
|
|
||||||
(int)params[5] /*dmgtype*/
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param outtrampoline The trampoline that was created.
|
|
||||||
* @param origfunc The original function that was hooked.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
|
|
||||||
{
|
|
||||||
|
|
||||||
VTableEntryBase::CreateGenericTrampoline(manager,
|
|
||||||
vtable,
|
|
||||||
ThisVTable::index,
|
|
||||||
id,
|
|
||||||
outtrampoline,
|
|
||||||
origfunc,
|
|
||||||
reinterpret_cast<void *>(ThisVTable::EntryPoint),
|
|
||||||
ThisParamCount, // param count
|
|
||||||
ThisVoidCall, // voidcall
|
|
||||||
1); // thiscall
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param plugin The plugin that's requesting this.
|
|
||||||
* @param funcid The function id of the callback.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
|
|
||||||
{
|
|
||||||
void *ptr=vtable[ThisVTable::index];
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=manager->ThisEntries.size();
|
|
||||||
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_DONE);
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (manager->ThisEntries[i]->IsTrampoline(ptr))
|
|
||||||
{
|
|
||||||
// this function is already hooked!
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// this function is NOT hooked
|
|
||||||
void *tramp;
|
|
||||||
void *func;
|
|
||||||
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
|
|
||||||
ThisVTable *entry=new ThisVTable;
|
|
||||||
|
|
||||||
entry->Setup(&vtable[ThisVTable::index],tramp,func);
|
|
||||||
|
|
||||||
manager->ThisEntries.push_back(entry);
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
entry->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the command. This is called directly from our global hook function.
|
|
||||||
*
|
|
||||||
* @param pthis The "this" pointer, cast to a void. The victim.
|
|
||||||
*/
|
|
||||||
int ThisVTable::Execute(void *pthis)
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
|
|
||||||
int end=Forwards.size();
|
|
||||||
|
|
||||||
int result=HAM_UNSET;
|
|
||||||
int thisresult=HAM_UNSET;
|
|
||||||
|
|
||||||
int iThis=PrivateToIndex(pthis);
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
thisresult=MF_ExecuteForward(Forwards[i++],iThis);
|
|
||||||
|
|
||||||
if (thisresult>result)
|
|
||||||
{
|
|
||||||
result=thisresult;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
int ireturn=0;
|
|
||||||
|
|
||||||
if (result<HAM_SUPERCEDE)
|
|
||||||
{
|
|
||||||
#if defined _WIN32
|
|
||||||
ireturn=reinterpret_cast<int (__fastcall *)(void *,int)>(function)(pthis,0);
|
|
||||||
#elif defined __linux__
|
|
||||||
ireturn=reinterpret_cast<int (*)(void *)>(function)(pthis);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
i=0;
|
|
||||||
|
|
||||||
end=PostForwards.size();
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
MF_ExecuteForward(PostForwards[i++],iThis);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (result!=HAM_OVERRIDE)
|
|
||||||
return ireturn;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
int HAM_CDECL ThisVTable::EntryPoint(int id,void *pthis)
|
|
||||||
{
|
|
||||||
return VTMan.ThisEntries[id]->Execute(pthis);
|
|
||||||
}
|
|
@ -1,366 +0,0 @@
|
|||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "VTableManager.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
#include "vfunc_gcc295.h"
|
|
||||||
#include "vfunc_msvc.h"
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
|
|
||||||
#define ThisVTable VTableClassify
|
|
||||||
#define ThisEntries ClassifyEntries
|
|
||||||
|
|
||||||
#define ThisKey "classify"
|
|
||||||
#define ThisNative "ham_classify"
|
|
||||||
#define ThisENative "ham_eclassify"
|
|
||||||
#define ThisRegisterID HAM_Classify
|
|
||||||
#define ThisParamCount 0
|
|
||||||
#define ThisVoidCall 0
|
|
||||||
|
|
||||||
unsigned int *ThisVTable::pevoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::pevset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseset=0;
|
|
||||||
unsigned int ThisVTable::index=0;
|
|
||||||
unsigned int ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO callnatives[] = {
|
|
||||||
{ ThisNative, ThisVTable::NativeCall },
|
|
||||||
{ ThisENative, ThisVTable::ENativeCall },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
|
|
||||||
*
|
|
||||||
* @param poffset Pointer to an integer that stores the pev offset for this mod.
|
|
||||||
* @param pset Pointer to an integer that tells whether pev offset was set or not.
|
|
||||||
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
|
|
||||||
* @param baseset Pointer to an integer that tells whether class base offset has been set.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
|
|
||||||
{
|
|
||||||
ThisVTable::pevoffset=poffset;
|
|
||||||
ThisVTable::pevset=pset;
|
|
||||||
|
|
||||||
ThisVTable::baseoffset=baseoffs;
|
|
||||||
ThisVTable::baseset=baseset;
|
|
||||||
|
|
||||||
ThisVTable::index=0;
|
|
||||||
ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
RegisterConfigCallback(ThisVTable::ConfigDone);
|
|
||||||
|
|
||||||
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
|
|
||||||
|
|
||||||
RegisterThisRegisterName(ThisRegisterID,ThisKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when one of this table entry's keyvalues is caught in a config file.
|
|
||||||
*
|
|
||||||
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
|
|
||||||
* @param data The data this keyvalue is set to.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::KeyValue(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
if (strcmp(key,ThisKey)==0)
|
|
||||||
{
|
|
||||||
ThisVTable::index=HAM_StrToNum(data);
|
|
||||||
ThisVTable::indexset=1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called immediately after the config file is done being parsed. Register our natives here.
|
|
||||||
*
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::ConfigDone(void)
|
|
||||||
{
|
|
||||||
if (ThisVTable::indexset && *(ThisVTable::baseset))
|
|
||||||
{
|
|
||||||
MF_AddNatives(callnatives);
|
|
||||||
|
|
||||||
if (*(ThisVTable::pevset))
|
|
||||||
{
|
|
||||||
//MF_AddNatives(registernatives);
|
|
||||||
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// Get the classname
|
|
||||||
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
|
|
||||||
|
|
||||||
// create an entity, assign it the gamedll's class, hook it and destroy it
|
|
||||||
edict_t *Entity=CREATE_ENTITY();
|
|
||||||
|
|
||||||
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
// Simulate a call to hs_register_id_takedamage
|
|
||||||
cell tempparams[4];
|
|
||||||
memcpy(tempparams,params,sizeof(cell)*4);
|
|
||||||
tempparams[1]=ENTINDEX_NEW(Entity);
|
|
||||||
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int funcid;
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
|
|
||||||
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
edict_t *Entity=INDEXENT_NEW(params[1]);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::NativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// scan to see if this virtual function is a trampoline
|
|
||||||
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
|
|
||||||
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=VTMan.ThisEntries.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (VTMan.ThisEntries[i]->IsTrampoline(func))
|
|
||||||
{
|
|
||||||
// this function is a trampoline
|
|
||||||
// use the original function instead
|
|
||||||
func=VTMan.ThisEntries[i]->GetOriginalFunction();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// TODO: Inline ASM this
|
|
||||||
#ifdef _WIN32
|
|
||||||
return reinterpret_cast<int (__fastcall *)(void *,int)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
0 /*fastcall buffer*/
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
return reinterpret_cast<int (*)(void *)>(func)(
|
|
||||||
pthis /*this*/
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
return VCall4<int>(
|
|
||||||
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
|
|
||||||
ThisVTable::index, /*vtable entry*/
|
|
||||||
*(ThisVTable::baseoffset), /*size of class*/
|
|
||||||
&(INDEXENT_NEW(params[2])->v), /*inflictor*/
|
|
||||||
&(INDEXENT_NEW(params[3])->v), /*attacker*/
|
|
||||||
amx_ctof2(params[4]), /*damage*/
|
|
||||||
(int)params[5] /*dmgtype*/
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param outtrampoline The trampoline that was created.
|
|
||||||
* @param origfunc The original function that was hooked.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
|
|
||||||
{
|
|
||||||
|
|
||||||
VTableEntryBase::CreateGenericTrampoline(manager,
|
|
||||||
vtable,
|
|
||||||
ThisVTable::index,
|
|
||||||
id,
|
|
||||||
outtrampoline,
|
|
||||||
origfunc,
|
|
||||||
reinterpret_cast<void *>(ThisVTable::EntryPoint),
|
|
||||||
ThisParamCount, // param count
|
|
||||||
ThisVoidCall, // voidcall
|
|
||||||
1); // thiscall
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param plugin The plugin that's requesting this.
|
|
||||||
* @param funcid The function id of the callback.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
|
|
||||||
{
|
|
||||||
void *ptr=vtable[ThisVTable::index];
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=manager->ThisEntries.size();
|
|
||||||
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_DONE);
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (manager->ThisEntries[i]->IsTrampoline(ptr))
|
|
||||||
{
|
|
||||||
// this function is already hooked!
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// this function is NOT hooked
|
|
||||||
void *tramp;
|
|
||||||
void *func;
|
|
||||||
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
|
|
||||||
ThisVTable *entry=new ThisVTable;
|
|
||||||
|
|
||||||
entry->Setup(&vtable[ThisVTable::index],tramp,func);
|
|
||||||
|
|
||||||
manager->ThisEntries.push_back(entry);
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
entry->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the command. This is called directly from our global hook function.
|
|
||||||
*
|
|
||||||
* @param pthis The "this" pointer, cast to a void. The victim.
|
|
||||||
*/
|
|
||||||
int ThisVTable::Execute(void *pthis)
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
|
|
||||||
int end=Forwards.size();
|
|
||||||
|
|
||||||
int result=HAM_UNSET;
|
|
||||||
int thisresult=HAM_UNSET;
|
|
||||||
|
|
||||||
int iThis=PrivateToIndex(pthis);
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
thisresult=MF_ExecuteForward(Forwards[i++],iThis);
|
|
||||||
|
|
||||||
if (thisresult>result)
|
|
||||||
{
|
|
||||||
result=thisresult;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
int ireturn=0;
|
|
||||||
|
|
||||||
if (result<HAM_SUPERCEDE)
|
|
||||||
{
|
|
||||||
#if defined _WIN32
|
|
||||||
ireturn=reinterpret_cast<int (__fastcall *)(void *,int)>(function)(pthis,0);
|
|
||||||
#elif defined __linux__
|
|
||||||
ireturn=reinterpret_cast<int (*)(void *)>(function)(pthis);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
i=0;
|
|
||||||
|
|
||||||
end=PostForwards.size();
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
MF_ExecuteForward(PostForwards[i++],iThis);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (result!=HAM_OVERRIDE)
|
|
||||||
return ireturn;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
int HAM_CDECL ThisVTable::EntryPoint(int id,void *pthis)
|
|
||||||
{
|
|
||||||
return VTMan.ThisEntries[id]->Execute(pthis);
|
|
||||||
}
|
|
@ -1,366 +0,0 @@
|
|||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "VTableManager.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
#include "vfunc_gcc295.h"
|
|
||||||
#include "vfunc_msvc.h"
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
|
|
||||||
#define ThisVTable VTableGetToggleState
|
|
||||||
#define ThisEntries GetToggleStateEntries
|
|
||||||
|
|
||||||
#define ThisKey "gettogglestate"
|
|
||||||
#define ThisNative "ham_gettogglestate"
|
|
||||||
#define ThisENative "ham_egettogglestate"
|
|
||||||
#define ThisRegisterID HAM_GetToggleState
|
|
||||||
#define ThisParamCount 0
|
|
||||||
#define ThisVoidCall 0
|
|
||||||
|
|
||||||
unsigned int *ThisVTable::pevoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::pevset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseset=0;
|
|
||||||
unsigned int ThisVTable::index=0;
|
|
||||||
unsigned int ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO callnatives[] = {
|
|
||||||
{ ThisNative, ThisVTable::NativeCall },
|
|
||||||
{ ThisENative, ThisVTable::ENativeCall },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
|
|
||||||
*
|
|
||||||
* @param poffset Pointer to an integer that stores the pev offset for this mod.
|
|
||||||
* @param pset Pointer to an integer that tells whether pev offset was set or not.
|
|
||||||
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
|
|
||||||
* @param baseset Pointer to an integer that tells whether class base offset has been set.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
|
|
||||||
{
|
|
||||||
ThisVTable::pevoffset=poffset;
|
|
||||||
ThisVTable::pevset=pset;
|
|
||||||
|
|
||||||
ThisVTable::baseoffset=baseoffs;
|
|
||||||
ThisVTable::baseset=baseset;
|
|
||||||
|
|
||||||
ThisVTable::index=0;
|
|
||||||
ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
RegisterConfigCallback(ThisVTable::ConfigDone);
|
|
||||||
|
|
||||||
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
|
|
||||||
|
|
||||||
RegisterThisRegisterName(ThisRegisterID,ThisKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when one of this table entry's keyvalues is caught in a config file.
|
|
||||||
*
|
|
||||||
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
|
|
||||||
* @param data The data this keyvalue is set to.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::KeyValue(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
if (strcmp(key,ThisKey)==0)
|
|
||||||
{
|
|
||||||
ThisVTable::index=HAM_StrToNum(data);
|
|
||||||
ThisVTable::indexset=1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called immediately after the config file is done being parsed. Register our natives here.
|
|
||||||
*
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::ConfigDone(void)
|
|
||||||
{
|
|
||||||
if (ThisVTable::indexset && *(ThisVTable::baseset))
|
|
||||||
{
|
|
||||||
MF_AddNatives(callnatives);
|
|
||||||
|
|
||||||
if (*(ThisVTable::pevset))
|
|
||||||
{
|
|
||||||
//MF_AddNatives(registernatives);
|
|
||||||
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// Get the classname
|
|
||||||
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
|
|
||||||
|
|
||||||
// create an entity, assign it the gamedll's class, hook it and destroy it
|
|
||||||
edict_t *Entity=CREATE_ENTITY();
|
|
||||||
|
|
||||||
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
// Simulate a call to hs_register_id_takedamage
|
|
||||||
cell tempparams[4];
|
|
||||||
memcpy(tempparams,params,sizeof(cell)*4);
|
|
||||||
tempparams[1]=ENTINDEX_NEW(Entity);
|
|
||||||
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int funcid;
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
|
|
||||||
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
edict_t *Entity=INDEXENT_NEW(params[1]);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::NativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// scan to see if this virtual function is a trampoline
|
|
||||||
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
|
|
||||||
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=VTMan.ThisEntries.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (VTMan.ThisEntries[i]->IsTrampoline(func))
|
|
||||||
{
|
|
||||||
// this function is a trampoline
|
|
||||||
// use the original function instead
|
|
||||||
func=VTMan.ThisEntries[i]->GetOriginalFunction();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// TODO: Inline ASM this
|
|
||||||
#ifdef _WIN32
|
|
||||||
return reinterpret_cast<int (__fastcall *)(void *,int)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
0 /*fastcall buffer*/
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
return reinterpret_cast<int (*)(void *)>(func)(
|
|
||||||
pthis /*this*/
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
return VCall4<int>(
|
|
||||||
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
|
|
||||||
ThisVTable::index, /*vtable entry*/
|
|
||||||
*(ThisVTable::baseoffset), /*size of class*/
|
|
||||||
&(INDEXENT_NEW(params[2])->v), /*inflictor*/
|
|
||||||
&(INDEXENT_NEW(params[3])->v), /*attacker*/
|
|
||||||
amx_ctof2(params[4]), /*damage*/
|
|
||||||
(int)params[5] /*dmgtype*/
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param outtrampoline The trampoline that was created.
|
|
||||||
* @param origfunc The original function that was hooked.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
|
|
||||||
{
|
|
||||||
|
|
||||||
VTableEntryBase::CreateGenericTrampoline(manager,
|
|
||||||
vtable,
|
|
||||||
ThisVTable::index,
|
|
||||||
id,
|
|
||||||
outtrampoline,
|
|
||||||
origfunc,
|
|
||||||
reinterpret_cast<void *>(ThisVTable::EntryPoint),
|
|
||||||
ThisParamCount, // param count
|
|
||||||
ThisVoidCall, // voidcall
|
|
||||||
1); // thiscall
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param plugin The plugin that's requesting this.
|
|
||||||
* @param funcid The function id of the callback.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
|
|
||||||
{
|
|
||||||
void *ptr=vtable[ThisVTable::index];
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=manager->ThisEntries.size();
|
|
||||||
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_DONE);
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (manager->ThisEntries[i]->IsTrampoline(ptr))
|
|
||||||
{
|
|
||||||
// this function is already hooked!
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// this function is NOT hooked
|
|
||||||
void *tramp;
|
|
||||||
void *func;
|
|
||||||
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
|
|
||||||
ThisVTable *entry=new ThisVTable;
|
|
||||||
|
|
||||||
entry->Setup(&vtable[ThisVTable::index],tramp,func);
|
|
||||||
|
|
||||||
manager->ThisEntries.push_back(entry);
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
entry->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the command. This is called directly from our global hook function.
|
|
||||||
*
|
|
||||||
* @param pthis The "this" pointer, cast to a void. The victim.
|
|
||||||
*/
|
|
||||||
int ThisVTable::Execute(void *pthis)
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
|
|
||||||
int end=Forwards.size();
|
|
||||||
|
|
||||||
int result=HAM_UNSET;
|
|
||||||
int thisresult=HAM_UNSET;
|
|
||||||
|
|
||||||
int iThis=PrivateToIndex(pthis);
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
thisresult=MF_ExecuteForward(Forwards[i++],iThis);
|
|
||||||
|
|
||||||
if (thisresult>result)
|
|
||||||
{
|
|
||||||
result=thisresult;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
int ireturn=0;
|
|
||||||
|
|
||||||
if (result<HAM_SUPERCEDE)
|
|
||||||
{
|
|
||||||
#if defined _WIN32
|
|
||||||
ireturn=reinterpret_cast<int (__fastcall *)(void *,int)>(function)(pthis,0);
|
|
||||||
#elif defined __linux__
|
|
||||||
ireturn=reinterpret_cast<int (*)(void *)>(function)(pthis);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
i=0;
|
|
||||||
|
|
||||||
end=PostForwards.size();
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
MF_ExecuteForward(PostForwards[i++],iThis);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (result!=HAM_OVERRIDE)
|
|
||||||
return ireturn;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
int HAM_CDECL ThisVTable::EntryPoint(int id,void *pthis)
|
|
||||||
{
|
|
||||||
return VTMan.ThisEntries[id]->Execute(pthis);
|
|
||||||
}
|
|
@ -1,366 +0,0 @@
|
|||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "VTableManager.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
#include "vfunc_gcc295.h"
|
|
||||||
#include "vfunc_msvc.h"
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
|
|
||||||
#define ThisVTable VTableIsAlive
|
|
||||||
#define ThisEntries IsAliveEntries
|
|
||||||
|
|
||||||
#define ThisKey "isalive"
|
|
||||||
#define ThisNative "ham_isalive"
|
|
||||||
#define ThisENative "ham_eisalive"
|
|
||||||
#define ThisRegisterID HAM_IsAlive
|
|
||||||
#define ThisParamCount 0
|
|
||||||
#define ThisVoidCall 0
|
|
||||||
|
|
||||||
unsigned int *ThisVTable::pevoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::pevset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseset=0;
|
|
||||||
unsigned int ThisVTable::index=0;
|
|
||||||
unsigned int ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO callnatives[] = {
|
|
||||||
{ ThisNative, ThisVTable::NativeCall },
|
|
||||||
{ ThisENative, ThisVTable::ENativeCall },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
|
|
||||||
*
|
|
||||||
* @param poffset Pointer to an integer that stores the pev offset for this mod.
|
|
||||||
* @param pset Pointer to an integer that tells whether pev offset was set or not.
|
|
||||||
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
|
|
||||||
* @param baseset Pointer to an integer that tells whether class base offset has been set.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
|
|
||||||
{
|
|
||||||
ThisVTable::pevoffset=poffset;
|
|
||||||
ThisVTable::pevset=pset;
|
|
||||||
|
|
||||||
ThisVTable::baseoffset=baseoffs;
|
|
||||||
ThisVTable::baseset=baseset;
|
|
||||||
|
|
||||||
ThisVTable::index=0;
|
|
||||||
ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
RegisterConfigCallback(ThisVTable::ConfigDone);
|
|
||||||
|
|
||||||
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
|
|
||||||
|
|
||||||
RegisterThisRegisterName(ThisRegisterID,ThisKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when one of this table entry's keyvalues is caught in a config file.
|
|
||||||
*
|
|
||||||
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
|
|
||||||
* @param data The data this keyvalue is set to.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::KeyValue(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
if (strcmp(key,ThisKey)==0)
|
|
||||||
{
|
|
||||||
ThisVTable::index=HAM_StrToNum(data);
|
|
||||||
ThisVTable::indexset=1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called immediately after the config file is done being parsed. Register our natives here.
|
|
||||||
*
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::ConfigDone(void)
|
|
||||||
{
|
|
||||||
if (ThisVTable::indexset && *(ThisVTable::baseset))
|
|
||||||
{
|
|
||||||
MF_AddNatives(callnatives);
|
|
||||||
|
|
||||||
if (*(ThisVTable::pevset))
|
|
||||||
{
|
|
||||||
//MF_AddNatives(registernatives);
|
|
||||||
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// Get the classname
|
|
||||||
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
|
|
||||||
|
|
||||||
// create an entity, assign it the gamedll's class, hook it and destroy it
|
|
||||||
edict_t *Entity=CREATE_ENTITY();
|
|
||||||
|
|
||||||
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
// Simulate a call to hs_register_id_takedamage
|
|
||||||
cell tempparams[4];
|
|
||||||
memcpy(tempparams,params,sizeof(cell)*4);
|
|
||||||
tempparams[1]=ENTINDEX_NEW(Entity);
|
|
||||||
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int funcid;
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
|
|
||||||
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
edict_t *Entity=INDEXENT_NEW(params[1]);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::NativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// scan to see if this virtual function is a trampoline
|
|
||||||
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
|
|
||||||
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=VTMan.ThisEntries.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (VTMan.ThisEntries[i]->IsTrampoline(func))
|
|
||||||
{
|
|
||||||
// this function is a trampoline
|
|
||||||
// use the original function instead
|
|
||||||
func=VTMan.ThisEntries[i]->GetOriginalFunction();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// TODO: Inline ASM this
|
|
||||||
#ifdef _WIN32
|
|
||||||
return reinterpret_cast<int (__fastcall *)(void *,int)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
0 /*fastcall buffer*/
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
return reinterpret_cast<int (*)(void *)>(func)(
|
|
||||||
pthis /*this*/
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
return VCall4<int>(
|
|
||||||
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
|
|
||||||
ThisVTable::index, /*vtable entry*/
|
|
||||||
*(ThisVTable::baseoffset), /*size of class*/
|
|
||||||
&(INDEXENT_NEW(params[2])->v), /*inflictor*/
|
|
||||||
&(INDEXENT_NEW(params[3])->v), /*attacker*/
|
|
||||||
amx_ctof2(params[4]), /*damage*/
|
|
||||||
(int)params[5] /*dmgtype*/
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param outtrampoline The trampoline that was created.
|
|
||||||
* @param origfunc The original function that was hooked.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
|
|
||||||
{
|
|
||||||
|
|
||||||
VTableEntryBase::CreateGenericTrampoline(manager,
|
|
||||||
vtable,
|
|
||||||
ThisVTable::index,
|
|
||||||
id,
|
|
||||||
outtrampoline,
|
|
||||||
origfunc,
|
|
||||||
reinterpret_cast<void *>(ThisVTable::EntryPoint),
|
|
||||||
ThisParamCount, // param count
|
|
||||||
ThisVoidCall, // voidcall
|
|
||||||
1); // thiscall
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param plugin The plugin that's requesting this.
|
|
||||||
* @param funcid The function id of the callback.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
|
|
||||||
{
|
|
||||||
void *ptr=vtable[ThisVTable::index];
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=manager->ThisEntries.size();
|
|
||||||
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_DONE);
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (manager->ThisEntries[i]->IsTrampoline(ptr))
|
|
||||||
{
|
|
||||||
// this function is already hooked!
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// this function is NOT hooked
|
|
||||||
void *tramp;
|
|
||||||
void *func;
|
|
||||||
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
|
|
||||||
ThisVTable *entry=new ThisVTable;
|
|
||||||
|
|
||||||
entry->Setup(&vtable[ThisVTable::index],tramp,func);
|
|
||||||
|
|
||||||
manager->ThisEntries.push_back(entry);
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
entry->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the command. This is called directly from our global hook function.
|
|
||||||
*
|
|
||||||
* @param pthis The "this" pointer, cast to a void. The victim.
|
|
||||||
*/
|
|
||||||
int ThisVTable::Execute(void *pthis)
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
|
|
||||||
int end=Forwards.size();
|
|
||||||
|
|
||||||
int result=HAM_UNSET;
|
|
||||||
int thisresult=HAM_UNSET;
|
|
||||||
|
|
||||||
int iThis=PrivateToIndex(pthis);
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
thisresult=MF_ExecuteForward(Forwards[i++],iThis);
|
|
||||||
|
|
||||||
if (thisresult>result)
|
|
||||||
{
|
|
||||||
result=thisresult;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
int ireturn=0;
|
|
||||||
|
|
||||||
if (result<HAM_SUPERCEDE)
|
|
||||||
{
|
|
||||||
#if defined _WIN32
|
|
||||||
ireturn=reinterpret_cast<int (__fastcall *)(void *,int)>(function)(pthis,0);
|
|
||||||
#elif defined __linux__
|
|
||||||
ireturn=reinterpret_cast<int (*)(void *)>(function)(pthis);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
i=0;
|
|
||||||
|
|
||||||
end=PostForwards.size();
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
MF_ExecuteForward(PostForwards[i++],iThis);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (result!=HAM_OVERRIDE)
|
|
||||||
return ireturn;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
int HAM_CDECL ThisVTable::EntryPoint(int id,void *pthis)
|
|
||||||
{
|
|
||||||
return VTMan.ThisEntries[id]->Execute(pthis);
|
|
||||||
}
|
|
@ -1,366 +0,0 @@
|
|||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "VTableManager.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
#include "vfunc_gcc295.h"
|
|
||||||
#include "vfunc_msvc.h"
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
|
|
||||||
#define ThisVTable VTableIsBSPModel
|
|
||||||
#define ThisEntries IsBSPModelEntries
|
|
||||||
|
|
||||||
#define ThisKey "isbspmodel"
|
|
||||||
#define ThisNative "ham_isbspmodel"
|
|
||||||
#define ThisENative "ham_eisbspmodel"
|
|
||||||
#define ThisRegisterID HAM_IsBSPModel
|
|
||||||
#define ThisParamCount 0
|
|
||||||
#define ThisVoidCall 0
|
|
||||||
|
|
||||||
unsigned int *ThisVTable::pevoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::pevset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseset=0;
|
|
||||||
unsigned int ThisVTable::index=0;
|
|
||||||
unsigned int ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO callnatives[] = {
|
|
||||||
{ ThisNative, ThisVTable::NativeCall },
|
|
||||||
{ ThisENative, ThisVTable::ENativeCall },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
|
|
||||||
*
|
|
||||||
* @param poffset Pointer to an integer that stores the pev offset for this mod.
|
|
||||||
* @param pset Pointer to an integer that tells whether pev offset was set or not.
|
|
||||||
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
|
|
||||||
* @param baseset Pointer to an integer that tells whether class base offset has been set.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
|
|
||||||
{
|
|
||||||
ThisVTable::pevoffset=poffset;
|
|
||||||
ThisVTable::pevset=pset;
|
|
||||||
|
|
||||||
ThisVTable::baseoffset=baseoffs;
|
|
||||||
ThisVTable::baseset=baseset;
|
|
||||||
|
|
||||||
ThisVTable::index=0;
|
|
||||||
ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
RegisterConfigCallback(ThisVTable::ConfigDone);
|
|
||||||
|
|
||||||
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
|
|
||||||
|
|
||||||
RegisterThisRegisterName(ThisRegisterID,ThisKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when one of this table entry's keyvalues is caught in a config file.
|
|
||||||
*
|
|
||||||
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
|
|
||||||
* @param data The data this keyvalue is set to.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::KeyValue(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
if (strcmp(key,ThisKey)==0)
|
|
||||||
{
|
|
||||||
ThisVTable::index=HAM_StrToNum(data);
|
|
||||||
ThisVTable::indexset=1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called immediately after the config file is done being parsed. Register our natives here.
|
|
||||||
*
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::ConfigDone(void)
|
|
||||||
{
|
|
||||||
if (ThisVTable::indexset && *(ThisVTable::baseset))
|
|
||||||
{
|
|
||||||
MF_AddNatives(callnatives);
|
|
||||||
|
|
||||||
if (*(ThisVTable::pevset))
|
|
||||||
{
|
|
||||||
//MF_AddNatives(registernatives);
|
|
||||||
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// Get the classname
|
|
||||||
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
|
|
||||||
|
|
||||||
// create an entity, assign it the gamedll's class, hook it and destroy it
|
|
||||||
edict_t *Entity=CREATE_ENTITY();
|
|
||||||
|
|
||||||
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
// Simulate a call to hs_register_id_takedamage
|
|
||||||
cell tempparams[4];
|
|
||||||
memcpy(tempparams,params,sizeof(cell)*4);
|
|
||||||
tempparams[1]=ENTINDEX_NEW(Entity);
|
|
||||||
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int funcid;
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
|
|
||||||
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
edict_t *Entity=INDEXENT_NEW(params[1]);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::NativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// scan to see if this virtual function is a trampoline
|
|
||||||
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
|
|
||||||
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=VTMan.ThisEntries.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (VTMan.ThisEntries[i]->IsTrampoline(func))
|
|
||||||
{
|
|
||||||
// this function is a trampoline
|
|
||||||
// use the original function instead
|
|
||||||
func=VTMan.ThisEntries[i]->GetOriginalFunction();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// TODO: Inline ASM this
|
|
||||||
#ifdef _WIN32
|
|
||||||
return reinterpret_cast<int (__fastcall *)(void *,int)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
0 /*fastcall buffer*/
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
return reinterpret_cast<int (*)(void *)>(func)(
|
|
||||||
pthis /*this*/
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
return VCall4<int>(
|
|
||||||
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
|
|
||||||
ThisVTable::index, /*vtable entry*/
|
|
||||||
*(ThisVTable::baseoffset), /*size of class*/
|
|
||||||
&(INDEXENT_NEW(params[2])->v), /*inflictor*/
|
|
||||||
&(INDEXENT_NEW(params[3])->v), /*attacker*/
|
|
||||||
amx_ctof2(params[4]), /*damage*/
|
|
||||||
(int)params[5] /*dmgtype*/
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param outtrampoline The trampoline that was created.
|
|
||||||
* @param origfunc The original function that was hooked.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
|
|
||||||
{
|
|
||||||
|
|
||||||
VTableEntryBase::CreateGenericTrampoline(manager,
|
|
||||||
vtable,
|
|
||||||
ThisVTable::index,
|
|
||||||
id,
|
|
||||||
outtrampoline,
|
|
||||||
origfunc,
|
|
||||||
reinterpret_cast<void *>(ThisVTable::EntryPoint),
|
|
||||||
ThisParamCount, // param count
|
|
||||||
ThisVoidCall, // voidcall
|
|
||||||
1); // thiscall
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param plugin The plugin that's requesting this.
|
|
||||||
* @param funcid The function id of the callback.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
|
|
||||||
{
|
|
||||||
void *ptr=vtable[ThisVTable::index];
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=manager->ThisEntries.size();
|
|
||||||
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_DONE);
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (manager->ThisEntries[i]->IsTrampoline(ptr))
|
|
||||||
{
|
|
||||||
// this function is already hooked!
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// this function is NOT hooked
|
|
||||||
void *tramp;
|
|
||||||
void *func;
|
|
||||||
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
|
|
||||||
ThisVTable *entry=new ThisVTable;
|
|
||||||
|
|
||||||
entry->Setup(&vtable[ThisVTable::index],tramp,func);
|
|
||||||
|
|
||||||
manager->ThisEntries.push_back(entry);
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
entry->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the command. This is called directly from our global hook function.
|
|
||||||
*
|
|
||||||
* @param pthis The "this" pointer, cast to a void. The victim.
|
|
||||||
*/
|
|
||||||
int ThisVTable::Execute(void *pthis)
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
|
|
||||||
int end=Forwards.size();
|
|
||||||
|
|
||||||
int result=HAM_UNSET;
|
|
||||||
int thisresult=HAM_UNSET;
|
|
||||||
|
|
||||||
int iThis=PrivateToIndex(pthis);
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
thisresult=MF_ExecuteForward(Forwards[i++],iThis);
|
|
||||||
|
|
||||||
if (thisresult>result)
|
|
||||||
{
|
|
||||||
result=thisresult;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
int ireturn=0;
|
|
||||||
|
|
||||||
if (result<HAM_SUPERCEDE)
|
|
||||||
{
|
|
||||||
#if defined _WIN32
|
|
||||||
ireturn=reinterpret_cast<int (__fastcall *)(void *,int)>(function)(pthis,0);
|
|
||||||
#elif defined __linux__
|
|
||||||
ireturn=reinterpret_cast<int (*)(void *)>(function)(pthis);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
i=0;
|
|
||||||
|
|
||||||
end=PostForwards.size();
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
MF_ExecuteForward(PostForwards[i++],iThis);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (result!=HAM_OVERRIDE)
|
|
||||||
return ireturn;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
int HAM_CDECL ThisVTable::EntryPoint(int id,void *pthis)
|
|
||||||
{
|
|
||||||
return VTMan.ThisEntries[id]->Execute(pthis);
|
|
||||||
}
|
|
@ -1,366 +0,0 @@
|
|||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "VTableManager.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
#include "vfunc_gcc295.h"
|
|
||||||
#include "vfunc_msvc.h"
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
|
|
||||||
#define ThisVTable VTableIsInWorld
|
|
||||||
#define ThisEntries IsInWorldEntries
|
|
||||||
|
|
||||||
#define ThisKey "isinworld"
|
|
||||||
#define ThisNative "ham_isinworld"
|
|
||||||
#define ThisENative "ham_eisinworld"
|
|
||||||
#define ThisRegisterID HAM_IsInWorld
|
|
||||||
#define ThisParamCount 0
|
|
||||||
#define ThisVoidCall 0
|
|
||||||
|
|
||||||
unsigned int *ThisVTable::pevoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::pevset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseset=0;
|
|
||||||
unsigned int ThisVTable::index=0;
|
|
||||||
unsigned int ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO callnatives[] = {
|
|
||||||
{ ThisNative, ThisVTable::NativeCall },
|
|
||||||
{ ThisENative, ThisVTable::ENativeCall },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
|
|
||||||
*
|
|
||||||
* @param poffset Pointer to an integer that stores the pev offset for this mod.
|
|
||||||
* @param pset Pointer to an integer that tells whether pev offset was set or not.
|
|
||||||
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
|
|
||||||
* @param baseset Pointer to an integer that tells whether class base offset has been set.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
|
|
||||||
{
|
|
||||||
ThisVTable::pevoffset=poffset;
|
|
||||||
ThisVTable::pevset=pset;
|
|
||||||
|
|
||||||
ThisVTable::baseoffset=baseoffs;
|
|
||||||
ThisVTable::baseset=baseset;
|
|
||||||
|
|
||||||
ThisVTable::index=0;
|
|
||||||
ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
RegisterConfigCallback(ThisVTable::ConfigDone);
|
|
||||||
|
|
||||||
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
|
|
||||||
|
|
||||||
RegisterThisRegisterName(ThisRegisterID,ThisKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when one of this table entry's keyvalues is caught in a config file.
|
|
||||||
*
|
|
||||||
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
|
|
||||||
* @param data The data this keyvalue is set to.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::KeyValue(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
if (strcmp(key,ThisKey)==0)
|
|
||||||
{
|
|
||||||
ThisVTable::index=HAM_StrToNum(data);
|
|
||||||
ThisVTable::indexset=1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called immediately after the config file is done being parsed. Register our natives here.
|
|
||||||
*
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::ConfigDone(void)
|
|
||||||
{
|
|
||||||
if (ThisVTable::indexset && *(ThisVTable::baseset))
|
|
||||||
{
|
|
||||||
MF_AddNatives(callnatives);
|
|
||||||
|
|
||||||
if (*(ThisVTable::pevset))
|
|
||||||
{
|
|
||||||
//MF_AddNatives(registernatives);
|
|
||||||
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// Get the classname
|
|
||||||
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
|
|
||||||
|
|
||||||
// create an entity, assign it the gamedll's class, hook it and destroy it
|
|
||||||
edict_t *Entity=CREATE_ENTITY();
|
|
||||||
|
|
||||||
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
// Simulate a call to hs_register_id_takedamage
|
|
||||||
cell tempparams[4];
|
|
||||||
memcpy(tempparams,params,sizeof(cell)*4);
|
|
||||||
tempparams[1]=ENTINDEX_NEW(Entity);
|
|
||||||
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int funcid;
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
|
|
||||||
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
edict_t *Entity=INDEXENT_NEW(params[1]);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::NativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// scan to see if this virtual function is a trampoline
|
|
||||||
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
|
|
||||||
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=VTMan.ThisEntries.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (VTMan.ThisEntries[i]->IsTrampoline(func))
|
|
||||||
{
|
|
||||||
// this function is a trampoline
|
|
||||||
// use the original function instead
|
|
||||||
func=VTMan.ThisEntries[i]->GetOriginalFunction();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// TODO: Inline ASM this
|
|
||||||
#ifdef _WIN32
|
|
||||||
return reinterpret_cast<int (__fastcall *)(void *,int)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
0 /*fastcall buffer*/
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
return reinterpret_cast<int (*)(void *)>(func)(
|
|
||||||
pthis /*this*/
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
return VCall4<int>(
|
|
||||||
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
|
|
||||||
ThisVTable::index, /*vtable entry*/
|
|
||||||
*(ThisVTable::baseoffset), /*size of class*/
|
|
||||||
&(INDEXENT_NEW(params[2])->v), /*inflictor*/
|
|
||||||
&(INDEXENT_NEW(params[3])->v), /*attacker*/
|
|
||||||
amx_ctof2(params[4]), /*damage*/
|
|
||||||
(int)params[5] /*dmgtype*/
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param outtrampoline The trampoline that was created.
|
|
||||||
* @param origfunc The original function that was hooked.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
|
|
||||||
{
|
|
||||||
|
|
||||||
VTableEntryBase::CreateGenericTrampoline(manager,
|
|
||||||
vtable,
|
|
||||||
ThisVTable::index,
|
|
||||||
id,
|
|
||||||
outtrampoline,
|
|
||||||
origfunc,
|
|
||||||
reinterpret_cast<void *>(ThisVTable::EntryPoint),
|
|
||||||
ThisParamCount, // param count
|
|
||||||
ThisVoidCall, // voidcall
|
|
||||||
1); // thiscall
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param plugin The plugin that's requesting this.
|
|
||||||
* @param funcid The function id of the callback.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
|
|
||||||
{
|
|
||||||
void *ptr=vtable[ThisVTable::index];
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=manager->ThisEntries.size();
|
|
||||||
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_DONE);
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (manager->ThisEntries[i]->IsTrampoline(ptr))
|
|
||||||
{
|
|
||||||
// this function is already hooked!
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// this function is NOT hooked
|
|
||||||
void *tramp;
|
|
||||||
void *func;
|
|
||||||
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
|
|
||||||
ThisVTable *entry=new ThisVTable;
|
|
||||||
|
|
||||||
entry->Setup(&vtable[ThisVTable::index],tramp,func);
|
|
||||||
|
|
||||||
manager->ThisEntries.push_back(entry);
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
entry->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the command. This is called directly from our global hook function.
|
|
||||||
*
|
|
||||||
* @param pthis The "this" pointer, cast to a void. The victim.
|
|
||||||
*/
|
|
||||||
int ThisVTable::Execute(void *pthis)
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
|
|
||||||
int end=Forwards.size();
|
|
||||||
|
|
||||||
int result=HAM_UNSET;
|
|
||||||
int thisresult=HAM_UNSET;
|
|
||||||
|
|
||||||
int iThis=PrivateToIndex(pthis);
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
thisresult=MF_ExecuteForward(Forwards[i++],iThis);
|
|
||||||
|
|
||||||
if (thisresult>result)
|
|
||||||
{
|
|
||||||
result=thisresult;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
int ireturn=0;
|
|
||||||
|
|
||||||
if (result<HAM_SUPERCEDE)
|
|
||||||
{
|
|
||||||
#if defined _WIN32
|
|
||||||
ireturn=reinterpret_cast<int (__fastcall *)(void *,int)>(function)(pthis,0);
|
|
||||||
#elif defined __linux__
|
|
||||||
ireturn=reinterpret_cast<int (*)(void *)>(function)(pthis);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
i=0;
|
|
||||||
|
|
||||||
end=PostForwards.size();
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
MF_ExecuteForward(PostForwards[i++],iThis);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (result!=HAM_OVERRIDE)
|
|
||||||
return ireturn;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
int HAM_CDECL ThisVTable::EntryPoint(int id,void *pthis)
|
|
||||||
{
|
|
||||||
return VTMan.ThisEntries[id]->Execute(pthis);
|
|
||||||
}
|
|
@ -1,366 +0,0 @@
|
|||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "VTableManager.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
#include "vfunc_gcc295.h"
|
|
||||||
#include "vfunc_msvc.h"
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
|
|
||||||
#define ThisVTable VTableIsMoving
|
|
||||||
#define ThisEntries IsMovingEntries
|
|
||||||
|
|
||||||
#define ThisKey "ismoving"
|
|
||||||
#define ThisNative "ham_ismoving"
|
|
||||||
#define ThisENative "ham_eismoving"
|
|
||||||
#define ThisRegisterID HAM_IsMoving
|
|
||||||
#define ThisParamCount 0
|
|
||||||
#define ThisVoidCall 0
|
|
||||||
|
|
||||||
unsigned int *ThisVTable::pevoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::pevset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseset=0;
|
|
||||||
unsigned int ThisVTable::index=0;
|
|
||||||
unsigned int ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO callnatives[] = {
|
|
||||||
{ ThisNative, ThisVTable::NativeCall },
|
|
||||||
{ ThisENative, ThisVTable::ENativeCall },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
|
|
||||||
*
|
|
||||||
* @param poffset Pointer to an integer that stores the pev offset for this mod.
|
|
||||||
* @param pset Pointer to an integer that tells whether pev offset was set or not.
|
|
||||||
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
|
|
||||||
* @param baseset Pointer to an integer that tells whether class base offset has been set.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
|
|
||||||
{
|
|
||||||
ThisVTable::pevoffset=poffset;
|
|
||||||
ThisVTable::pevset=pset;
|
|
||||||
|
|
||||||
ThisVTable::baseoffset=baseoffs;
|
|
||||||
ThisVTable::baseset=baseset;
|
|
||||||
|
|
||||||
ThisVTable::index=0;
|
|
||||||
ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
RegisterConfigCallback(ThisVTable::ConfigDone);
|
|
||||||
|
|
||||||
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
|
|
||||||
|
|
||||||
RegisterThisRegisterName(ThisRegisterID,ThisKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when one of this table entry's keyvalues is caught in a config file.
|
|
||||||
*
|
|
||||||
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
|
|
||||||
* @param data The data this keyvalue is set to.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::KeyValue(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
if (strcmp(key,ThisKey)==0)
|
|
||||||
{
|
|
||||||
ThisVTable::index=HAM_StrToNum(data);
|
|
||||||
ThisVTable::indexset=1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called immediately after the config file is done being parsed. Register our natives here.
|
|
||||||
*
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::ConfigDone(void)
|
|
||||||
{
|
|
||||||
if (ThisVTable::indexset && *(ThisVTable::baseset))
|
|
||||||
{
|
|
||||||
MF_AddNatives(callnatives);
|
|
||||||
|
|
||||||
if (*(ThisVTable::pevset))
|
|
||||||
{
|
|
||||||
//MF_AddNatives(registernatives);
|
|
||||||
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// Get the classname
|
|
||||||
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
|
|
||||||
|
|
||||||
// create an entity, assign it the gamedll's class, hook it and destroy it
|
|
||||||
edict_t *Entity=CREATE_ENTITY();
|
|
||||||
|
|
||||||
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
// Simulate a call to hs_register_id_takedamage
|
|
||||||
cell tempparams[4];
|
|
||||||
memcpy(tempparams,params,sizeof(cell)*4);
|
|
||||||
tempparams[1]=ENTINDEX_NEW(Entity);
|
|
||||||
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int funcid;
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
|
|
||||||
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
edict_t *Entity=INDEXENT_NEW(params[1]);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::NativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// scan to see if this virtual function is a trampoline
|
|
||||||
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
|
|
||||||
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=VTMan.ThisEntries.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (VTMan.ThisEntries[i]->IsTrampoline(func))
|
|
||||||
{
|
|
||||||
// this function is a trampoline
|
|
||||||
// use the original function instead
|
|
||||||
func=VTMan.ThisEntries[i]->GetOriginalFunction();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// TODO: Inline ASM this
|
|
||||||
#ifdef _WIN32
|
|
||||||
return reinterpret_cast<int (__fastcall *)(void *,int)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
0 /*fastcall buffer*/
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
return reinterpret_cast<int (*)(void *)>(func)(
|
|
||||||
pthis /*this*/
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
return VCall4<int>(
|
|
||||||
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
|
|
||||||
ThisVTable::index, /*vtable entry*/
|
|
||||||
*(ThisVTable::baseoffset), /*size of class*/
|
|
||||||
&(INDEXENT_NEW(params[2])->v), /*inflictor*/
|
|
||||||
&(INDEXENT_NEW(params[3])->v), /*attacker*/
|
|
||||||
amx_ctof2(params[4]), /*damage*/
|
|
||||||
(int)params[5] /*dmgtype*/
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param outtrampoline The trampoline that was created.
|
|
||||||
* @param origfunc The original function that was hooked.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
|
|
||||||
{
|
|
||||||
|
|
||||||
VTableEntryBase::CreateGenericTrampoline(manager,
|
|
||||||
vtable,
|
|
||||||
ThisVTable::index,
|
|
||||||
id,
|
|
||||||
outtrampoline,
|
|
||||||
origfunc,
|
|
||||||
reinterpret_cast<void *>(ThisVTable::EntryPoint),
|
|
||||||
ThisParamCount, // param count
|
|
||||||
ThisVoidCall, // voidcall
|
|
||||||
1); // thiscall
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param plugin The plugin that's requesting this.
|
|
||||||
* @param funcid The function id of the callback.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
|
|
||||||
{
|
|
||||||
void *ptr=vtable[ThisVTable::index];
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=manager->ThisEntries.size();
|
|
||||||
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_DONE);
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (manager->ThisEntries[i]->IsTrampoline(ptr))
|
|
||||||
{
|
|
||||||
// this function is already hooked!
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// this function is NOT hooked
|
|
||||||
void *tramp;
|
|
||||||
void *func;
|
|
||||||
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
|
|
||||||
ThisVTable *entry=new ThisVTable;
|
|
||||||
|
|
||||||
entry->Setup(&vtable[ThisVTable::index],tramp,func);
|
|
||||||
|
|
||||||
manager->ThisEntries.push_back(entry);
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
entry->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the command. This is called directly from our global hook function.
|
|
||||||
*
|
|
||||||
* @param pthis The "this" pointer, cast to a void. The victim.
|
|
||||||
*/
|
|
||||||
int ThisVTable::Execute(void *pthis)
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
|
|
||||||
int end=Forwards.size();
|
|
||||||
|
|
||||||
int result=HAM_UNSET;
|
|
||||||
int thisresult=HAM_UNSET;
|
|
||||||
|
|
||||||
int iThis=PrivateToIndex(pthis);
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
thisresult=MF_ExecuteForward(Forwards[i++],iThis);
|
|
||||||
|
|
||||||
if (thisresult>result)
|
|
||||||
{
|
|
||||||
result=thisresult;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
int ireturn=0;
|
|
||||||
|
|
||||||
if (result<HAM_SUPERCEDE)
|
|
||||||
{
|
|
||||||
#if defined _WIN32
|
|
||||||
ireturn=reinterpret_cast<int (__fastcall *)(void *,int)>(function)(pthis,0);
|
|
||||||
#elif defined __linux__
|
|
||||||
ireturn=reinterpret_cast<int (*)(void *)>(function)(pthis);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
i=0;
|
|
||||||
|
|
||||||
end=PostForwards.size();
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
MF_ExecuteForward(PostForwards[i++],iThis);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (result!=HAM_OVERRIDE)
|
|
||||||
return ireturn;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
int HAM_CDECL ThisVTable::EntryPoint(int id,void *pthis)
|
|
||||||
{
|
|
||||||
return VTMan.ThisEntries[id]->Execute(pthis);
|
|
||||||
}
|
|
@ -1,366 +0,0 @@
|
|||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "VTableManager.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
#include "vfunc_gcc295.h"
|
|
||||||
#include "vfunc_msvc.h"
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
|
|
||||||
#define ThisVTable VTableIsNetClient
|
|
||||||
#define ThisEntries IsNetClientEntries
|
|
||||||
|
|
||||||
#define ThisKey "isnetclient"
|
|
||||||
#define ThisNative "ham_isnetclient"
|
|
||||||
#define ThisENative "ham_eisnetclient"
|
|
||||||
#define ThisRegisterID HAM_IsNetClient
|
|
||||||
#define ThisParamCount 0
|
|
||||||
#define ThisVoidCall 0
|
|
||||||
|
|
||||||
unsigned int *ThisVTable::pevoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::pevset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseset=0;
|
|
||||||
unsigned int ThisVTable::index=0;
|
|
||||||
unsigned int ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO callnatives[] = {
|
|
||||||
{ ThisNative, ThisVTable::NativeCall },
|
|
||||||
{ ThisENative, ThisVTable::ENativeCall },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
|
|
||||||
*
|
|
||||||
* @param poffset Pointer to an integer that stores the pev offset for this mod.
|
|
||||||
* @param pset Pointer to an integer that tells whether pev offset was set or not.
|
|
||||||
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
|
|
||||||
* @param baseset Pointer to an integer that tells whether class base offset has been set.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
|
|
||||||
{
|
|
||||||
ThisVTable::pevoffset=poffset;
|
|
||||||
ThisVTable::pevset=pset;
|
|
||||||
|
|
||||||
ThisVTable::baseoffset=baseoffs;
|
|
||||||
ThisVTable::baseset=baseset;
|
|
||||||
|
|
||||||
ThisVTable::index=0;
|
|
||||||
ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
RegisterConfigCallback(ThisVTable::ConfigDone);
|
|
||||||
|
|
||||||
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
|
|
||||||
|
|
||||||
RegisterThisRegisterName(ThisRegisterID,ThisKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when one of this table entry's keyvalues is caught in a config file.
|
|
||||||
*
|
|
||||||
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
|
|
||||||
* @param data The data this keyvalue is set to.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::KeyValue(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
if (strcmp(key,ThisKey)==0)
|
|
||||||
{
|
|
||||||
ThisVTable::index=HAM_StrToNum(data);
|
|
||||||
ThisVTable::indexset=1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called immediately after the config file is done being parsed. Register our natives here.
|
|
||||||
*
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::ConfigDone(void)
|
|
||||||
{
|
|
||||||
if (ThisVTable::indexset && *(ThisVTable::baseset))
|
|
||||||
{
|
|
||||||
MF_AddNatives(callnatives);
|
|
||||||
|
|
||||||
if (*(ThisVTable::pevset))
|
|
||||||
{
|
|
||||||
//MF_AddNatives(registernatives);
|
|
||||||
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// Get the classname
|
|
||||||
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
|
|
||||||
|
|
||||||
// create an entity, assign it the gamedll's class, hook it and destroy it
|
|
||||||
edict_t *Entity=CREATE_ENTITY();
|
|
||||||
|
|
||||||
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
// Simulate a call to hs_register_id_takedamage
|
|
||||||
cell tempparams[4];
|
|
||||||
memcpy(tempparams,params,sizeof(cell)*4);
|
|
||||||
tempparams[1]=ENTINDEX_NEW(Entity);
|
|
||||||
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int funcid;
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
|
|
||||||
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
edict_t *Entity=INDEXENT_NEW(params[1]);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::NativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// scan to see if this virtual function is a trampoline
|
|
||||||
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
|
|
||||||
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=VTMan.ThisEntries.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (VTMan.ThisEntries[i]->IsTrampoline(func))
|
|
||||||
{
|
|
||||||
// this function is a trampoline
|
|
||||||
// use the original function instead
|
|
||||||
func=VTMan.ThisEntries[i]->GetOriginalFunction();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// TODO: Inline ASM this
|
|
||||||
#ifdef _WIN32
|
|
||||||
return reinterpret_cast<int (__fastcall *)(void *,int)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
0 /*fastcall buffer*/
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
return reinterpret_cast<int (*)(void *)>(func)(
|
|
||||||
pthis /*this*/
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
return VCall4<int>(
|
|
||||||
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
|
|
||||||
ThisVTable::index, /*vtable entry*/
|
|
||||||
*(ThisVTable::baseoffset), /*size of class*/
|
|
||||||
&(INDEXENT_NEW(params[2])->v), /*inflictor*/
|
|
||||||
&(INDEXENT_NEW(params[3])->v), /*attacker*/
|
|
||||||
amx_ctof2(params[4]), /*damage*/
|
|
||||||
(int)params[5] /*dmgtype*/
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param outtrampoline The trampoline that was created.
|
|
||||||
* @param origfunc The original function that was hooked.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
|
|
||||||
{
|
|
||||||
|
|
||||||
VTableEntryBase::CreateGenericTrampoline(manager,
|
|
||||||
vtable,
|
|
||||||
ThisVTable::index,
|
|
||||||
id,
|
|
||||||
outtrampoline,
|
|
||||||
origfunc,
|
|
||||||
reinterpret_cast<void *>(ThisVTable::EntryPoint),
|
|
||||||
ThisParamCount, // param count
|
|
||||||
ThisVoidCall, // voidcall
|
|
||||||
1); // thiscall
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param plugin The plugin that's requesting this.
|
|
||||||
* @param funcid The function id of the callback.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
|
|
||||||
{
|
|
||||||
void *ptr=vtable[ThisVTable::index];
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=manager->ThisEntries.size();
|
|
||||||
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_DONE);
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (manager->ThisEntries[i]->IsTrampoline(ptr))
|
|
||||||
{
|
|
||||||
// this function is already hooked!
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// this function is NOT hooked
|
|
||||||
void *tramp;
|
|
||||||
void *func;
|
|
||||||
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
|
|
||||||
ThisVTable *entry=new ThisVTable;
|
|
||||||
|
|
||||||
entry->Setup(&vtable[ThisVTable::index],tramp,func);
|
|
||||||
|
|
||||||
manager->ThisEntries.push_back(entry);
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
entry->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the command. This is called directly from our global hook function.
|
|
||||||
*
|
|
||||||
* @param pthis The "this" pointer, cast to a void. The victim.
|
|
||||||
*/
|
|
||||||
int ThisVTable::Execute(void *pthis)
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
|
|
||||||
int end=Forwards.size();
|
|
||||||
|
|
||||||
int result=HAM_UNSET;
|
|
||||||
int thisresult=HAM_UNSET;
|
|
||||||
|
|
||||||
int iThis=PrivateToIndex(pthis);
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
thisresult=MF_ExecuteForward(Forwards[i++],iThis);
|
|
||||||
|
|
||||||
if (thisresult>result)
|
|
||||||
{
|
|
||||||
result=thisresult;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
int ireturn=0;
|
|
||||||
|
|
||||||
if (result<HAM_SUPERCEDE)
|
|
||||||
{
|
|
||||||
#if defined _WIN32
|
|
||||||
ireturn=reinterpret_cast<int (__fastcall *)(void *,int)>(function)(pthis,0);
|
|
||||||
#elif defined __linux__
|
|
||||||
ireturn=reinterpret_cast<int (*)(void *)>(function)(pthis);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
i=0;
|
|
||||||
|
|
||||||
end=PostForwards.size();
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
MF_ExecuteForward(PostForwards[i++],iThis);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (result!=HAM_OVERRIDE)
|
|
||||||
return ireturn;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
int HAM_CDECL ThisVTable::EntryPoint(int id,void *pthis)
|
|
||||||
{
|
|
||||||
return VTMan.ThisEntries[id]->Execute(pthis);
|
|
||||||
}
|
|
@ -1,366 +0,0 @@
|
|||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "VTableManager.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
#include "vfunc_gcc295.h"
|
|
||||||
#include "vfunc_msvc.h"
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
|
|
||||||
#define ThisVTable VTableIsPlayer
|
|
||||||
#define ThisEntries IsPlayerEntries
|
|
||||||
|
|
||||||
#define ThisKey "isplayer"
|
|
||||||
#define ThisNative "ham_isplayer"
|
|
||||||
#define ThisENative "ham_eisplayer"
|
|
||||||
#define ThisRegisterID HAM_IsPlayer
|
|
||||||
#define ThisParamCount 0
|
|
||||||
#define ThisVoidCall 0
|
|
||||||
|
|
||||||
unsigned int *ThisVTable::pevoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::pevset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseset=0;
|
|
||||||
unsigned int ThisVTable::index=0;
|
|
||||||
unsigned int ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO callnatives[] = {
|
|
||||||
{ ThisNative, ThisVTable::NativeCall },
|
|
||||||
{ ThisENative, ThisVTable::ENativeCall },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
|
|
||||||
*
|
|
||||||
* @param poffset Pointer to an integer that stores the pev offset for this mod.
|
|
||||||
* @param pset Pointer to an integer that tells whether pev offset was set or not.
|
|
||||||
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
|
|
||||||
* @param baseset Pointer to an integer that tells whether class base offset has been set.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
|
|
||||||
{
|
|
||||||
ThisVTable::pevoffset=poffset;
|
|
||||||
ThisVTable::pevset=pset;
|
|
||||||
|
|
||||||
ThisVTable::baseoffset=baseoffs;
|
|
||||||
ThisVTable::baseset=baseset;
|
|
||||||
|
|
||||||
ThisVTable::index=0;
|
|
||||||
ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
RegisterConfigCallback(ThisVTable::ConfigDone);
|
|
||||||
|
|
||||||
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
|
|
||||||
|
|
||||||
RegisterThisRegisterName(ThisRegisterID,ThisKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when one of this table entry's keyvalues is caught in a config file.
|
|
||||||
*
|
|
||||||
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
|
|
||||||
* @param data The data this keyvalue is set to.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::KeyValue(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
if (strcmp(key,ThisKey)==0)
|
|
||||||
{
|
|
||||||
ThisVTable::index=HAM_StrToNum(data);
|
|
||||||
ThisVTable::indexset=1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called immediately after the config file is done being parsed. Register our natives here.
|
|
||||||
*
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::ConfigDone(void)
|
|
||||||
{
|
|
||||||
if (ThisVTable::indexset && *(ThisVTable::baseset))
|
|
||||||
{
|
|
||||||
MF_AddNatives(callnatives);
|
|
||||||
|
|
||||||
if (*(ThisVTable::pevset))
|
|
||||||
{
|
|
||||||
//MF_AddNatives(registernatives);
|
|
||||||
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// Get the classname
|
|
||||||
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
|
|
||||||
|
|
||||||
// create an entity, assign it the gamedll's class, hook it and destroy it
|
|
||||||
edict_t *Entity=CREATE_ENTITY();
|
|
||||||
|
|
||||||
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
// Simulate a call to hs_register_id_takedamage
|
|
||||||
cell tempparams[4];
|
|
||||||
memcpy(tempparams,params,sizeof(cell)*4);
|
|
||||||
tempparams[1]=ENTINDEX_NEW(Entity);
|
|
||||||
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int funcid;
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
|
|
||||||
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
edict_t *Entity=INDEXENT_NEW(params[1]);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::NativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// scan to see if this virtual function is a trampoline
|
|
||||||
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
|
|
||||||
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=VTMan.ThisEntries.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (VTMan.ThisEntries[i]->IsTrampoline(func))
|
|
||||||
{
|
|
||||||
// this function is a trampoline
|
|
||||||
// use the original function instead
|
|
||||||
func=VTMan.ThisEntries[i]->GetOriginalFunction();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// TODO: Inline ASM this
|
|
||||||
#ifdef _WIN32
|
|
||||||
return reinterpret_cast<int (__fastcall *)(void *,int)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
0 /*fastcall buffer*/
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
return reinterpret_cast<int (*)(void *)>(func)(
|
|
||||||
pthis /*this*/
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
return VCall4<int>(
|
|
||||||
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
|
|
||||||
ThisVTable::index, /*vtable entry*/
|
|
||||||
*(ThisVTable::baseoffset), /*size of class*/
|
|
||||||
&(INDEXENT_NEW(params[2])->v), /*inflictor*/
|
|
||||||
&(INDEXENT_NEW(params[3])->v), /*attacker*/
|
|
||||||
amx_ctof2(params[4]), /*damage*/
|
|
||||||
(int)params[5] /*dmgtype*/
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param outtrampoline The trampoline that was created.
|
|
||||||
* @param origfunc The original function that was hooked.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
|
|
||||||
{
|
|
||||||
|
|
||||||
VTableEntryBase::CreateGenericTrampoline(manager,
|
|
||||||
vtable,
|
|
||||||
ThisVTable::index,
|
|
||||||
id,
|
|
||||||
outtrampoline,
|
|
||||||
origfunc,
|
|
||||||
reinterpret_cast<void *>(ThisVTable::EntryPoint),
|
|
||||||
ThisParamCount, // param count
|
|
||||||
ThisVoidCall, // voidcall
|
|
||||||
1); // thiscall
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param plugin The plugin that's requesting this.
|
|
||||||
* @param funcid The function id of the callback.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
|
|
||||||
{
|
|
||||||
void *ptr=vtable[ThisVTable::index];
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=manager->ThisEntries.size();
|
|
||||||
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_DONE);
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (manager->ThisEntries[i]->IsTrampoline(ptr))
|
|
||||||
{
|
|
||||||
// this function is already hooked!
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// this function is NOT hooked
|
|
||||||
void *tramp;
|
|
||||||
void *func;
|
|
||||||
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
|
|
||||||
ThisVTable *entry=new ThisVTable;
|
|
||||||
|
|
||||||
entry->Setup(&vtable[ThisVTable::index],tramp,func);
|
|
||||||
|
|
||||||
manager->ThisEntries.push_back(entry);
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
entry->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the command. This is called directly from our global hook function.
|
|
||||||
*
|
|
||||||
* @param pthis The "this" pointer, cast to a void. The victim.
|
|
||||||
*/
|
|
||||||
int ThisVTable::Execute(void *pthis)
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
|
|
||||||
int end=Forwards.size();
|
|
||||||
|
|
||||||
int result=HAM_UNSET;
|
|
||||||
int thisresult=HAM_UNSET;
|
|
||||||
|
|
||||||
int iThis=PrivateToIndex(pthis);
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
thisresult=MF_ExecuteForward(Forwards[i++],iThis);
|
|
||||||
|
|
||||||
if (thisresult>result)
|
|
||||||
{
|
|
||||||
result=thisresult;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
int ireturn=0;
|
|
||||||
|
|
||||||
if (result<HAM_SUPERCEDE)
|
|
||||||
{
|
|
||||||
#if defined _WIN32
|
|
||||||
ireturn=reinterpret_cast<int (__fastcall *)(void *,int)>(function)(pthis,0);
|
|
||||||
#elif defined __linux__
|
|
||||||
ireturn=reinterpret_cast<int (*)(void *)>(function)(pthis);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
i=0;
|
|
||||||
|
|
||||||
end=PostForwards.size();
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
MF_ExecuteForward(PostForwards[i++],iThis);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (result!=HAM_OVERRIDE)
|
|
||||||
return ireturn;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
int HAM_CDECL ThisVTable::EntryPoint(int id,void *pthis)
|
|
||||||
{
|
|
||||||
return VTMan.ThisEntries[id]->Execute(pthis);
|
|
||||||
}
|
|
@ -1,366 +0,0 @@
|
|||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "VTableManager.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
#include "vfunc_gcc295.h"
|
|
||||||
#include "vfunc_msvc.h"
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
|
|
||||||
#define ThisVTable VTableIsSneaking
|
|
||||||
#define ThisEntries IsSneakingEntries
|
|
||||||
|
|
||||||
#define ThisKey "issneaking"
|
|
||||||
#define ThisNative "ham_issneaking"
|
|
||||||
#define ThisENative "ham_eissneaking"
|
|
||||||
#define ThisRegisterID HAM_IsSneaking
|
|
||||||
#define ThisParamCount 0
|
|
||||||
#define ThisVoidCall 0
|
|
||||||
|
|
||||||
unsigned int *ThisVTable::pevoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::pevset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseset=0;
|
|
||||||
unsigned int ThisVTable::index=0;
|
|
||||||
unsigned int ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO callnatives[] = {
|
|
||||||
{ ThisNative, ThisVTable::NativeCall },
|
|
||||||
{ ThisENative, ThisVTable::ENativeCall },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
|
|
||||||
*
|
|
||||||
* @param poffset Pointer to an integer that stores the pev offset for this mod.
|
|
||||||
* @param pset Pointer to an integer that tells whether pev offset was set or not.
|
|
||||||
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
|
|
||||||
* @param baseset Pointer to an integer that tells whether class base offset has been set.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
|
|
||||||
{
|
|
||||||
ThisVTable::pevoffset=poffset;
|
|
||||||
ThisVTable::pevset=pset;
|
|
||||||
|
|
||||||
ThisVTable::baseoffset=baseoffs;
|
|
||||||
ThisVTable::baseset=baseset;
|
|
||||||
|
|
||||||
ThisVTable::index=0;
|
|
||||||
ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
RegisterConfigCallback(ThisVTable::ConfigDone);
|
|
||||||
|
|
||||||
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
|
|
||||||
|
|
||||||
RegisterThisRegisterName(ThisRegisterID,ThisKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when one of this table entry's keyvalues is caught in a config file.
|
|
||||||
*
|
|
||||||
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
|
|
||||||
* @param data The data this keyvalue is set to.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::KeyValue(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
if (strcmp(key,ThisKey)==0)
|
|
||||||
{
|
|
||||||
ThisVTable::index=HAM_StrToNum(data);
|
|
||||||
ThisVTable::indexset=1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called immediately after the config file is done being parsed. Register our natives here.
|
|
||||||
*
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::ConfigDone(void)
|
|
||||||
{
|
|
||||||
if (ThisVTable::indexset && *(ThisVTable::baseset))
|
|
||||||
{
|
|
||||||
MF_AddNatives(callnatives);
|
|
||||||
|
|
||||||
if (*(ThisVTable::pevset))
|
|
||||||
{
|
|
||||||
//MF_AddNatives(registernatives);
|
|
||||||
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// Get the classname
|
|
||||||
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
|
|
||||||
|
|
||||||
// create an entity, assign it the gamedll's class, hook it and destroy it
|
|
||||||
edict_t *Entity=CREATE_ENTITY();
|
|
||||||
|
|
||||||
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
// Simulate a call to hs_register_id_takedamage
|
|
||||||
cell tempparams[4];
|
|
||||||
memcpy(tempparams,params,sizeof(cell)*4);
|
|
||||||
tempparams[1]=ENTINDEX_NEW(Entity);
|
|
||||||
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int funcid;
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
|
|
||||||
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
edict_t *Entity=INDEXENT_NEW(params[1]);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::NativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// scan to see if this virtual function is a trampoline
|
|
||||||
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
|
|
||||||
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=VTMan.ThisEntries.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (VTMan.ThisEntries[i]->IsTrampoline(func))
|
|
||||||
{
|
|
||||||
// this function is a trampoline
|
|
||||||
// use the original function instead
|
|
||||||
func=VTMan.ThisEntries[i]->GetOriginalFunction();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// TODO: Inline ASM this
|
|
||||||
#ifdef _WIN32
|
|
||||||
return reinterpret_cast<int (__fastcall *)(void *,int)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
0 /*fastcall buffer*/
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
return reinterpret_cast<int (*)(void *)>(func)(
|
|
||||||
pthis /*this*/
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
return VCall4<int>(
|
|
||||||
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
|
|
||||||
ThisVTable::index, /*vtable entry*/
|
|
||||||
*(ThisVTable::baseoffset), /*size of class*/
|
|
||||||
&(INDEXENT_NEW(params[2])->v), /*inflictor*/
|
|
||||||
&(INDEXENT_NEW(params[3])->v), /*attacker*/
|
|
||||||
amx_ctof2(params[4]), /*damage*/
|
|
||||||
(int)params[5] /*dmgtype*/
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param outtrampoline The trampoline that was created.
|
|
||||||
* @param origfunc The original function that was hooked.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
|
|
||||||
{
|
|
||||||
|
|
||||||
VTableEntryBase::CreateGenericTrampoline(manager,
|
|
||||||
vtable,
|
|
||||||
ThisVTable::index,
|
|
||||||
id,
|
|
||||||
outtrampoline,
|
|
||||||
origfunc,
|
|
||||||
reinterpret_cast<void *>(ThisVTable::EntryPoint),
|
|
||||||
ThisParamCount, // param count
|
|
||||||
ThisVoidCall, // voidcall
|
|
||||||
1); // thiscall
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param plugin The plugin that's requesting this.
|
|
||||||
* @param funcid The function id of the callback.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
|
|
||||||
{
|
|
||||||
void *ptr=vtable[ThisVTable::index];
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=manager->ThisEntries.size();
|
|
||||||
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_DONE);
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (manager->ThisEntries[i]->IsTrampoline(ptr))
|
|
||||||
{
|
|
||||||
// this function is already hooked!
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// this function is NOT hooked
|
|
||||||
void *tramp;
|
|
||||||
void *func;
|
|
||||||
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
|
|
||||||
ThisVTable *entry=new ThisVTable;
|
|
||||||
|
|
||||||
entry->Setup(&vtable[ThisVTable::index],tramp,func);
|
|
||||||
|
|
||||||
manager->ThisEntries.push_back(entry);
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
entry->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the command. This is called directly from our global hook function.
|
|
||||||
*
|
|
||||||
* @param pthis The "this" pointer, cast to a void. The victim.
|
|
||||||
*/
|
|
||||||
int ThisVTable::Execute(void *pthis)
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
|
|
||||||
int end=Forwards.size();
|
|
||||||
|
|
||||||
int result=HAM_UNSET;
|
|
||||||
int thisresult=HAM_UNSET;
|
|
||||||
|
|
||||||
int iThis=PrivateToIndex(pthis);
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
thisresult=MF_ExecuteForward(Forwards[i++],iThis);
|
|
||||||
|
|
||||||
if (thisresult>result)
|
|
||||||
{
|
|
||||||
result=thisresult;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
int ireturn=0;
|
|
||||||
|
|
||||||
if (result<HAM_SUPERCEDE)
|
|
||||||
{
|
|
||||||
#if defined _WIN32
|
|
||||||
ireturn=reinterpret_cast<int (__fastcall *)(void *,int)>(function)(pthis,0);
|
|
||||||
#elif defined __linux__
|
|
||||||
ireturn=reinterpret_cast<int (*)(void *)>(function)(pthis);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
i=0;
|
|
||||||
|
|
||||||
end=PostForwards.size();
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
MF_ExecuteForward(PostForwards[i++],iThis);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (result!=HAM_OVERRIDE)
|
|
||||||
return ireturn;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
int HAM_CDECL ThisVTable::EntryPoint(int id,void *pthis)
|
|
||||||
{
|
|
||||||
return VTMan.ThisEntries[id]->Execute(pthis);
|
|
||||||
}
|
|
@ -1,368 +0,0 @@
|
|||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "VTableManager.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
#include "vfunc_gcc295.h"
|
|
||||||
#include "vfunc_msvc.h"
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
|
|
||||||
#define ThisVTable VTableKilled
|
|
||||||
#define ThisEntries KilledEntries
|
|
||||||
|
|
||||||
#define ThisKey "killed"
|
|
||||||
#define ThisNative "ham_killed"
|
|
||||||
#define ThisENative "ham_ekilled"
|
|
||||||
#define ThisRegisterID HAM_Killed
|
|
||||||
#define ThisParamCount 2
|
|
||||||
#define ThisVoidCall 1
|
|
||||||
|
|
||||||
unsigned int *ThisVTable::pevoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::pevset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseset=0;
|
|
||||||
unsigned int ThisVTable::index=0;
|
|
||||||
unsigned int ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO callnatives[] = {
|
|
||||||
{ ThisNative, ThisVTable::NativeCall },
|
|
||||||
{ ThisENative, ThisVTable::ENativeCall },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
|
|
||||||
*
|
|
||||||
* @param poffset Pointer to an integer that stores the pev offset for this mod.
|
|
||||||
* @param pset Pointer to an integer that tells whether pev offset was set or not.
|
|
||||||
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
|
|
||||||
* @param baseset Pointer to an integer that tells whether class base offset has been set.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
|
|
||||||
{
|
|
||||||
ThisVTable::pevoffset=poffset;
|
|
||||||
ThisVTable::pevset=pset;
|
|
||||||
|
|
||||||
ThisVTable::baseoffset=baseoffs;
|
|
||||||
ThisVTable::baseset=baseset;
|
|
||||||
|
|
||||||
ThisVTable::index=0;
|
|
||||||
ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
RegisterConfigCallback(ThisVTable::ConfigDone);
|
|
||||||
|
|
||||||
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
|
|
||||||
|
|
||||||
RegisterThisRegisterName(ThisRegisterID,ThisKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when one of this table entry's keyvalues is caught in a config file.
|
|
||||||
*
|
|
||||||
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
|
|
||||||
* @param data The data this keyvalue is set to.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::KeyValue(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
if (strcmp(key,ThisKey)==0)
|
|
||||||
{
|
|
||||||
ThisVTable::index=HAM_StrToNum(data);
|
|
||||||
ThisVTable::indexset=1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called immediately after the config file is done being parsed. Register our natives here.
|
|
||||||
*
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::ConfigDone(void)
|
|
||||||
{
|
|
||||||
if (ThisVTable::indexset && *(ThisVTable::baseset))
|
|
||||||
{
|
|
||||||
MF_AddNatives(callnatives);
|
|
||||||
|
|
||||||
if (*(ThisVTable::pevset))
|
|
||||||
{
|
|
||||||
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// Get the classname
|
|
||||||
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
|
|
||||||
|
|
||||||
// create an entity, assign it the gamedll's class, hook it and destroy it
|
|
||||||
edict_t *Entity=CREATE_ENTITY();
|
|
||||||
|
|
||||||
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
// Simulate a call to hs_register_id_takedamage
|
|
||||||
cell tempparams[4];
|
|
||||||
memcpy(tempparams,params,sizeof(cell)*4);
|
|
||||||
tempparams[1]=ENTINDEX_NEW(Entity);
|
|
||||||
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int funcid;
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
|
|
||||||
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
edict_t *Entity=INDEXENT_NEW(params[1]);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::NativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// scan to see if this virtual function is a trampoline
|
|
||||||
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
|
|
||||||
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=VTMan.ThisEntries.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (VTMan.ThisEntries[i]->IsTrampoline(func))
|
|
||||||
{
|
|
||||||
// this function is a trampoline
|
|
||||||
// use the original function instead
|
|
||||||
func=VTMan.ThisEntries[i]->GetOriginalFunction();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// TODO: Inline ASM this
|
|
||||||
#ifdef _WIN32
|
|
||||||
return reinterpret_cast<int (__fastcall *)(void *,int,void *,int)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
0, /*fastcall buffer*/
|
|
||||||
&(INDEXENT_NEW(params[2])->v), /*pevattacker*/
|
|
||||||
(int)params[3] /*gib*/
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
return reinterpret_cast<int (*)(void *,void *,int)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
&(INDEXENT_NEW(params[2])->v), /*pevattacker*/
|
|
||||||
(int)params[3] /*gib*/
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
VoidVCall2(
|
|
||||||
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
|
|
||||||
ThisVTable::index, /*vtable entry*/
|
|
||||||
*(ThisVTable::baseoffset), /*size of class*/
|
|
||||||
&(INDEXENT_NEW(params[2])->v), /*pevattacker*/
|
|
||||||
(int)params[3] /*gib*/
|
|
||||||
);
|
|
||||||
return 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param outtrampoline The trampoline that was created.
|
|
||||||
* @param origfunc The original function that was hooked.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
|
|
||||||
{
|
|
||||||
|
|
||||||
VTableEntryBase::CreateGenericTrampoline(manager,
|
|
||||||
vtable,
|
|
||||||
ThisVTable::index,
|
|
||||||
id,
|
|
||||||
outtrampoline,
|
|
||||||
origfunc,
|
|
||||||
reinterpret_cast<void *>(ThisVTable::EntryPoint),
|
|
||||||
ThisParamCount, // param count
|
|
||||||
ThisVoidCall, // voidcall
|
|
||||||
1); // thiscall
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param plugin The plugin that's requesting this.
|
|
||||||
* @param funcid The function id of the callback.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
|
|
||||||
{
|
|
||||||
void *ptr=vtable[ThisVTable::index];
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=manager->ThisEntries.size();
|
|
||||||
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_CELL/*attacker*/,FP_CELL/*gib*/,FP_DONE);
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (manager->ThisEntries[i]->IsTrampoline(ptr))
|
|
||||||
{
|
|
||||||
// this function is already hooked!
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// this function is NOT hooked
|
|
||||||
void *tramp;
|
|
||||||
void *func;
|
|
||||||
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
|
|
||||||
ThisVTable *entry=new ThisVTable;
|
|
||||||
|
|
||||||
entry->Setup(&vtable[ThisVTable::index],tramp,func);
|
|
||||||
|
|
||||||
manager->ThisEntries.push_back(entry);
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
entry->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the command. This is called directly from our global hook function.
|
|
||||||
*
|
|
||||||
* @param pthis The "this" pointer, cast to a void. The victim.
|
|
||||||
* @param inflictor Damage inflictor.
|
|
||||||
* @param attacker The attacker who caused the inflictor to damage the victim.
|
|
||||||
* @param damage How much damage was caused.
|
|
||||||
* @param type Damage type (usually in bitmask form).
|
|
||||||
* @return Unsure. Does not appear to be used.
|
|
||||||
*/
|
|
||||||
void ThisVTable::Execute(void *pthis, void *attacker, int gib)
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
|
|
||||||
int end=Forwards.size();
|
|
||||||
|
|
||||||
int result=HAM_UNSET;
|
|
||||||
int thisresult=HAM_UNSET;
|
|
||||||
|
|
||||||
int iThis=PrivateToIndex(pthis);
|
|
||||||
int iAttacker=EntvarToIndex((entvars_t *)attacker);
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
thisresult=MF_ExecuteForward(Forwards[i++],iThis,iAttacker,gib);
|
|
||||||
|
|
||||||
if (thisresult>result)
|
|
||||||
{
|
|
||||||
result=thisresult;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (result<HAM_SUPERCEDE)
|
|
||||||
{
|
|
||||||
#if defined _WIN32
|
|
||||||
reinterpret_cast<void (__fastcall *)(void *,int,void *,int)>(function)(pthis,0,attacker,gib);
|
|
||||||
#elif defined __linux__
|
|
||||||
reinterpret_cast<void (*)(void *,void *,int)>(function)(pthis,attacker,gib);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
i=0;
|
|
||||||
end=PostForwards.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
MF_ExecuteForward(PostForwards[i++],iThis,iAttacker,gib);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
void HAM_CDECL ThisVTable::EntryPoint(int id,void *pthis,void *attacker,int gib)
|
|
||||||
{
|
|
||||||
VTMan.ThisEntries[id]->Execute(pthis,attacker,gib);
|
|
||||||
}
|
|
||||||
|
|
@ -1,366 +0,0 @@
|
|||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "VTableManager.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
#include "vfunc_gcc295.h"
|
|
||||||
#include "vfunc_msvc.h"
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
|
|
||||||
#define ThisVTable VTableObjectCaps
|
|
||||||
#define ThisEntries ObjectCapsEntries
|
|
||||||
|
|
||||||
#define ThisKey "objectcaps"
|
|
||||||
#define ThisNative "ham_objectcaps"
|
|
||||||
#define ThisENative "ham_eobjectcaps"
|
|
||||||
#define ThisRegisterID HAM_ObjectCaps
|
|
||||||
#define ThisParamCount 0
|
|
||||||
#define ThisVoidCall 0
|
|
||||||
|
|
||||||
unsigned int *ThisVTable::pevoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::pevset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseset=0;
|
|
||||||
unsigned int ThisVTable::index=0;
|
|
||||||
unsigned int ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO callnatives[] = {
|
|
||||||
{ ThisNative, ThisVTable::NativeCall },
|
|
||||||
{ ThisENative, ThisVTable::ENativeCall },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
|
|
||||||
*
|
|
||||||
* @param poffset Pointer to an integer that stores the pev offset for this mod.
|
|
||||||
* @param pset Pointer to an integer that tells whether pev offset was set or not.
|
|
||||||
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
|
|
||||||
* @param baseset Pointer to an integer that tells whether class base offset has been set.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
|
|
||||||
{
|
|
||||||
ThisVTable::pevoffset=poffset;
|
|
||||||
ThisVTable::pevset=pset;
|
|
||||||
|
|
||||||
ThisVTable::baseoffset=baseoffs;
|
|
||||||
ThisVTable::baseset=baseset;
|
|
||||||
|
|
||||||
ThisVTable::index=0;
|
|
||||||
ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
RegisterConfigCallback(ThisVTable::ConfigDone);
|
|
||||||
|
|
||||||
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
|
|
||||||
|
|
||||||
RegisterThisRegisterName(ThisRegisterID,ThisKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when one of this table entry's keyvalues is caught in a config file.
|
|
||||||
*
|
|
||||||
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
|
|
||||||
* @param data The data this keyvalue is set to.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::KeyValue(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
if (strcmp(key,ThisKey)==0)
|
|
||||||
{
|
|
||||||
ThisVTable::index=HAM_StrToNum(data);
|
|
||||||
ThisVTable::indexset=1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called immediately after the config file is done being parsed. Register our natives here.
|
|
||||||
*
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::ConfigDone(void)
|
|
||||||
{
|
|
||||||
if (ThisVTable::indexset && *(ThisVTable::baseset))
|
|
||||||
{
|
|
||||||
MF_AddNatives(callnatives);
|
|
||||||
|
|
||||||
if (*(ThisVTable::pevset))
|
|
||||||
{
|
|
||||||
//MF_AddNatives(registernatives);
|
|
||||||
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// Get the classname
|
|
||||||
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
|
|
||||||
|
|
||||||
// create an entity, assign it the gamedll's class, hook it and destroy it
|
|
||||||
edict_t *Entity=CREATE_ENTITY();
|
|
||||||
|
|
||||||
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
// Simulate a call to hs_register_id_takedamage
|
|
||||||
cell tempparams[4];
|
|
||||||
memcpy(tempparams,params,sizeof(cell)*4);
|
|
||||||
tempparams[1]=ENTINDEX_NEW(Entity);
|
|
||||||
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int funcid;
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
|
|
||||||
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
edict_t *Entity=INDEXENT_NEW(params[1]);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::NativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// scan to see if this virtual function is a trampoline
|
|
||||||
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
|
|
||||||
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=VTMan.ThisEntries.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (VTMan.ThisEntries[i]->IsTrampoline(func))
|
|
||||||
{
|
|
||||||
// this function is a trampoline
|
|
||||||
// use the original function instead
|
|
||||||
func=VTMan.ThisEntries[i]->GetOriginalFunction();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// TODO: Inline ASM this
|
|
||||||
#ifdef _WIN32
|
|
||||||
return reinterpret_cast<int (__fastcall *)(void *,int)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
0 /*fastcall buffer*/
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
return reinterpret_cast<int (*)(void *)>(func)(
|
|
||||||
pthis /*this*/
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
return VCall4<int>(
|
|
||||||
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
|
|
||||||
ThisVTable::index, /*vtable entry*/
|
|
||||||
*(ThisVTable::baseoffset), /*size of class*/
|
|
||||||
&(INDEXENT_NEW(params[2])->v), /*inflictor*/
|
|
||||||
&(INDEXENT_NEW(params[3])->v), /*attacker*/
|
|
||||||
amx_ctof2(params[4]), /*damage*/
|
|
||||||
(int)params[5] /*dmgtype*/
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param outtrampoline The trampoline that was created.
|
|
||||||
* @param origfunc The original function that was hooked.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
|
|
||||||
{
|
|
||||||
|
|
||||||
VTableEntryBase::CreateGenericTrampoline(manager,
|
|
||||||
vtable,
|
|
||||||
ThisVTable::index,
|
|
||||||
id,
|
|
||||||
outtrampoline,
|
|
||||||
origfunc,
|
|
||||||
reinterpret_cast<void *>(ThisVTable::EntryPoint),
|
|
||||||
ThisParamCount, // param count
|
|
||||||
ThisVoidCall, // voidcall
|
|
||||||
1); // thiscall
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param plugin The plugin that's requesting this.
|
|
||||||
* @param funcid The function id of the callback.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
|
|
||||||
{
|
|
||||||
void *ptr=vtable[ThisVTable::index];
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=manager->ThisEntries.size();
|
|
||||||
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_DONE);
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (manager->ThisEntries[i]->IsTrampoline(ptr))
|
|
||||||
{
|
|
||||||
// this function is already hooked!
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// this function is NOT hooked
|
|
||||||
void *tramp;
|
|
||||||
void *func;
|
|
||||||
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
|
|
||||||
ThisVTable *entry=new ThisVTable;
|
|
||||||
|
|
||||||
entry->Setup(&vtable[ThisVTable::index],tramp,func);
|
|
||||||
|
|
||||||
manager->ThisEntries.push_back(entry);
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
entry->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the command. This is called directly from our global hook function.
|
|
||||||
*
|
|
||||||
* @param pthis The "this" pointer, cast to a void. The victim.
|
|
||||||
*/
|
|
||||||
int ThisVTable::Execute(void *pthis)
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
|
|
||||||
int end=Forwards.size();
|
|
||||||
|
|
||||||
int result=HAM_UNSET;
|
|
||||||
int thisresult=HAM_UNSET;
|
|
||||||
|
|
||||||
int iThis=PrivateToIndex(pthis);
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
thisresult=MF_ExecuteForward(Forwards[i++],iThis);
|
|
||||||
|
|
||||||
if (thisresult>result)
|
|
||||||
{
|
|
||||||
result=thisresult;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
int ireturn=0;
|
|
||||||
|
|
||||||
if (result<HAM_SUPERCEDE)
|
|
||||||
{
|
|
||||||
#if defined _WIN32
|
|
||||||
ireturn=reinterpret_cast<int (__fastcall *)(void *,int)>(function)(pthis,0);
|
|
||||||
#elif defined __linux__
|
|
||||||
ireturn=reinterpret_cast<int (*)(void *)>(function)(pthis);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
i=0;
|
|
||||||
|
|
||||||
end=PostForwards.size();
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
MF_ExecuteForward(PostForwards[i++],iThis);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (result!=HAM_OVERRIDE)
|
|
||||||
return ireturn;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
int HAM_CDECL ThisVTable::EntryPoint(int id,void *pthis)
|
|
||||||
{
|
|
||||||
return VTMan.ThisEntries[id]->Execute(pthis);
|
|
||||||
}
|
|
@ -1,371 +0,0 @@
|
|||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "VTableManager.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
#include "vfunc_gcc295.h"
|
|
||||||
#include "vfunc_msvc.h"
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
|
|
||||||
#define ThisVTable VTableRemovePlayerItem
|
|
||||||
#define ThisEntries RemovePlayerItemEntries
|
|
||||||
|
|
||||||
#define ThisKey "removeplayeritem"
|
|
||||||
#define ThisNative "ham_removeplayeritem"
|
|
||||||
#define ThisENative "ham_eremoveplayeritem"
|
|
||||||
#define ThisRegisterID HAM_RemovePlayerItem
|
|
||||||
#define ThisParamCount 1
|
|
||||||
#define ThisVoidCall 0
|
|
||||||
|
|
||||||
unsigned int *ThisVTable::pevoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::pevset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseset=0;
|
|
||||||
unsigned int ThisVTable::index=0;
|
|
||||||
unsigned int ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO callnatives[] = {
|
|
||||||
{ ThisNative, ThisVTable::NativeCall },
|
|
||||||
{ ThisENative, ThisVTable::ENativeCall },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
|
|
||||||
*
|
|
||||||
* @param poffset Pointer to an integer that stores the pev offset for this mod.
|
|
||||||
* @param pset Pointer to an integer that tells whether pev offset was set or not.
|
|
||||||
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
|
|
||||||
* @param baseset Pointer to an integer that tells whether class base offset has been set.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
|
|
||||||
{
|
|
||||||
ThisVTable::pevoffset=poffset;
|
|
||||||
ThisVTable::pevset=pset;
|
|
||||||
|
|
||||||
ThisVTable::baseoffset=baseoffs;
|
|
||||||
ThisVTable::baseset=baseset;
|
|
||||||
|
|
||||||
ThisVTable::index=0;
|
|
||||||
ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
RegisterConfigCallback(ThisVTable::ConfigDone);
|
|
||||||
|
|
||||||
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
|
|
||||||
|
|
||||||
RegisterThisRegisterName(ThisRegisterID,ThisKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when one of this table entry's keyvalues is caught in a config file.
|
|
||||||
*
|
|
||||||
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
|
|
||||||
* @param data The data this keyvalue is set to.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::KeyValue(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
if (strcmp(key,ThisKey)==0)
|
|
||||||
{
|
|
||||||
ThisVTable::index=HAM_StrToNum(data);
|
|
||||||
ThisVTable::indexset=1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called immediately after the config file is done being parsed. Register our natives here.
|
|
||||||
*
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::ConfigDone(void)
|
|
||||||
{
|
|
||||||
if (ThisVTable::indexset && *(ThisVTable::baseset))
|
|
||||||
{
|
|
||||||
MF_AddNatives(callnatives);
|
|
||||||
|
|
||||||
if (*(ThisVTable::pevset))
|
|
||||||
{
|
|
||||||
//MF_AddNatives(registernatives);
|
|
||||||
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// Get the classname
|
|
||||||
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
|
|
||||||
|
|
||||||
// create an entity, assign it the gamedll's class, hook it and destroy it
|
|
||||||
edict_t *Entity=CREATE_ENTITY();
|
|
||||||
|
|
||||||
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
// Simulate a call to hs_register_id_takedamage
|
|
||||||
cell tempparams[4];
|
|
||||||
memcpy(tempparams,params,sizeof(cell)*4);
|
|
||||||
tempparams[1]=ENTINDEX_NEW(Entity);
|
|
||||||
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int funcid;
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
|
|
||||||
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
edict_t *Entity=INDEXENT_NEW(params[1]);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::NativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// scan to see if this virtual function is a trampoline
|
|
||||||
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
|
|
||||||
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=VTMan.ThisEntries.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (VTMan.ThisEntries[i]->IsTrampoline(func))
|
|
||||||
{
|
|
||||||
// this function is a trampoline
|
|
||||||
// use the original function instead
|
|
||||||
func=VTMan.ThisEntries[i]->GetOriginalFunction();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// TODO: Inline ASM this
|
|
||||||
#ifdef _WIN32
|
|
||||||
return reinterpret_cast<int (__fastcall *)(void *,int,void *)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
0, /*fastcall buffer*/
|
|
||||||
INDEXENT_NEW(params[2])->pvPrivateData /*item*/
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
return reinterpret_cast<int (*)(void *,void *)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
INDEXENT_NEW(params[2])->pvPrivateData /*item*/
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
return VCall1<int>(
|
|
||||||
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
|
|
||||||
ThisVTable::index, /*vtable entry*/
|
|
||||||
*(ThisVTable::baseoffset), /*size of class*/
|
|
||||||
INDEXENT_NEW(params[3])->pvPrivateData /*item*/
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param outtrampoline The trampoline that was created.
|
|
||||||
* @param origfunc The original function that was hooked.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
|
|
||||||
{
|
|
||||||
|
|
||||||
VTableEntryBase::CreateGenericTrampoline(manager,
|
|
||||||
vtable,
|
|
||||||
ThisVTable::index,
|
|
||||||
id,
|
|
||||||
outtrampoline,
|
|
||||||
origfunc,
|
|
||||||
reinterpret_cast<void *>(ThisVTable::EntryPoint),
|
|
||||||
ThisParamCount, // param count
|
|
||||||
ThisVoidCall, // voidcall
|
|
||||||
1); // thiscall
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param plugin The plugin that's requesting this.
|
|
||||||
* @param funcid The function id of the callback.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
|
|
||||||
{
|
|
||||||
void *ptr=vtable[ThisVTable::index];
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=manager->ThisEntries.size();
|
|
||||||
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_CELL/*item*/,FP_DONE);
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (manager->ThisEntries[i]->IsTrampoline(ptr))
|
|
||||||
{
|
|
||||||
// this function is already hooked!
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// this function is NOT hooked
|
|
||||||
void *tramp;
|
|
||||||
void *func;
|
|
||||||
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
|
|
||||||
ThisVTable *entry=new ThisVTable;
|
|
||||||
|
|
||||||
entry->Setup(&vtable[ThisVTable::index],tramp,func);
|
|
||||||
|
|
||||||
manager->ThisEntries.push_back(entry);
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
entry->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the command. This is called directly from our global hook function.
|
|
||||||
*
|
|
||||||
* @param pthis The "this" pointer, cast to a void. The victim.
|
|
||||||
* @param inflictor Damage inflictor.
|
|
||||||
* @param attacker The attacker who caused the inflictor to damage the victim.
|
|
||||||
* @param damage How much damage was caused.
|
|
||||||
* @param type Damage type (usually in bitmask form).
|
|
||||||
* @return Unsure. Does not appear to be used.
|
|
||||||
*/
|
|
||||||
int ThisVTable::Execute(void *pthis, void *item)
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
|
|
||||||
int end=Forwards.size();
|
|
||||||
|
|
||||||
int result=HAM_UNSET;
|
|
||||||
int thisresult=HAM_UNSET;
|
|
||||||
|
|
||||||
int iThis=PrivateToIndex(pthis);
|
|
||||||
int iItem=PrivateToIndex(item);
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
thisresult=MF_ExecuteForward(Forwards[i++],iThis,item);
|
|
||||||
|
|
||||||
if (thisresult>result)
|
|
||||||
{
|
|
||||||
result=thisresult;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
int ireturn=0;
|
|
||||||
|
|
||||||
if (result<HAM_SUPERCEDE)
|
|
||||||
{
|
|
||||||
#if defined _WIN32
|
|
||||||
ireturn=reinterpret_cast<int (__fastcall *)(void *,int,void *)>(function)(pthis,0,item);
|
|
||||||
#elif defined __linux__
|
|
||||||
ireturn=reinterpret_cast<int (*)(void *,void *)>(function)(pthis,item);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
i=0;
|
|
||||||
|
|
||||||
end=PostForwards.size();
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
MF_ExecuteForward(PostForwards[i++],iThis,iItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (result!=HAM_OVERRIDE)
|
|
||||||
return ireturn;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
int HAM_CDECL ThisVTable::EntryPoint(int id,void *pthis,void *item)
|
|
||||||
{
|
|
||||||
return VTMan.ThisEntries[id]->Execute(pthis,item);
|
|
||||||
}
|
|
@ -1,356 +0,0 @@
|
|||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "VTableManager.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
#include "vfunc_gcc295.h"
|
|
||||||
#include "vfunc_msvc.h"
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
|
|
||||||
#define ThisVTable VTableRespawn
|
|
||||||
#define ThisEntries RespawnEntries
|
|
||||||
#define ThisKey "respawn"
|
|
||||||
#define ThisNative "ham_respawn"
|
|
||||||
#define ThisENative "ham_erespawn"
|
|
||||||
#define ThisRegisterID HAM_Respawn
|
|
||||||
#define ThisParamCount 0
|
|
||||||
#define ThisVoidCall 1
|
|
||||||
|
|
||||||
unsigned int *ThisVTable::pevoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::pevset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseset=0;
|
|
||||||
unsigned int ThisVTable::index=0;
|
|
||||||
unsigned int ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO callnatives[] = {
|
|
||||||
{ ThisNative, ThisVTable::NativeCall },
|
|
||||||
{ ThisENative, ThisVTable::ENativeCall },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
|
|
||||||
*
|
|
||||||
* @param poffset Pointer to an integer that stores the pev offset for this mod.
|
|
||||||
* @param pset Pointer to an integer that tells whether pev offset was set or not.
|
|
||||||
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
|
|
||||||
* @param baseset Pointer to an integer that tells whether class base offset has been set.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
|
|
||||||
{
|
|
||||||
ThisVTable::pevoffset=poffset;
|
|
||||||
ThisVTable::pevset=pset;
|
|
||||||
|
|
||||||
ThisVTable::baseoffset=baseoffs;
|
|
||||||
ThisVTable::baseset=baseset;
|
|
||||||
|
|
||||||
ThisVTable::index=0;
|
|
||||||
ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
RegisterConfigCallback(ThisVTable::ConfigDone);
|
|
||||||
|
|
||||||
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
|
|
||||||
|
|
||||||
RegisterThisRegisterName(ThisRegisterID,ThisKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when one of this table entry's keyvalues is caught in a config file.
|
|
||||||
*
|
|
||||||
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
|
|
||||||
* @param data The data this keyvalue is set to.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::KeyValue(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
if (strcmp(key,ThisKey)==0)
|
|
||||||
{
|
|
||||||
ThisVTable::index=HAM_StrToNum(data);
|
|
||||||
ThisVTable::indexset=1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called immediately after the config file is done being parsed. Register our natives here.
|
|
||||||
*
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::ConfigDone(void)
|
|
||||||
{
|
|
||||||
if (ThisVTable::indexset && *(ThisVTable::baseset))
|
|
||||||
{
|
|
||||||
MF_AddNatives(callnatives);
|
|
||||||
|
|
||||||
if (*(ThisVTable::pevset))
|
|
||||||
{
|
|
||||||
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// Get the classname
|
|
||||||
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
|
|
||||||
|
|
||||||
// create an entity, assign it the gamedll's class, hook it and destroy it
|
|
||||||
edict_t *Entity=CREATE_ENTITY();
|
|
||||||
|
|
||||||
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
// Simulate a call to hs_register_id_takedamage
|
|
||||||
cell tempparams[4];
|
|
||||||
memcpy(tempparams,params,sizeof(cell)*4);
|
|
||||||
tempparams[1]=ENTINDEX_NEW(Entity);
|
|
||||||
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int funcid;
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
|
|
||||||
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
edict_t *Entity=INDEXENT_NEW(params[1]);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::NativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// scan to see if this virtual function is a trampoline
|
|
||||||
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
|
|
||||||
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=VTMan.ThisEntries.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (VTMan.ThisEntries[i]->IsTrampoline(func))
|
|
||||||
{
|
|
||||||
// this function is a trampoline
|
|
||||||
// use the original function instead
|
|
||||||
func=VTMan.ThisEntries[i]->GetOriginalFunction();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// TODO: Inline ASM this
|
|
||||||
#ifdef _WIN32
|
|
||||||
return PrivateToIndex(reinterpret_cast<void *(__fastcall *)(void *,int)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
0 /*fastcall buffer*/
|
|
||||||
));
|
|
||||||
#else
|
|
||||||
return PrivateToIndex(reinterpret_cast<void *(*)(void *)>(func)(
|
|
||||||
pthis /*this*/
|
|
||||||
));
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
return PrivateToIndex(VCall0<void *>(
|
|
||||||
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
|
|
||||||
ThisVTable::index, /*vtable entry*/
|
|
||||||
*(ThisVTable::baseoffset) /*size of class*/
|
|
||||||
));
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param outtrampoline The trampoline that was created.
|
|
||||||
* @param origfunc The original function that was hooked.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
|
|
||||||
{
|
|
||||||
|
|
||||||
VTableEntryBase::CreateGenericTrampoline(manager,
|
|
||||||
vtable,
|
|
||||||
ThisVTable::index,
|
|
||||||
id,
|
|
||||||
outtrampoline,
|
|
||||||
origfunc,
|
|
||||||
reinterpret_cast<void *>(ThisVTable::EntryPoint),
|
|
||||||
ThisParamCount, // param count
|
|
||||||
ThisVoidCall, // voidcall
|
|
||||||
1); // thiscall
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param plugin The plugin that's requesting this.
|
|
||||||
* @param funcid The function id of the callback.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
|
|
||||||
{
|
|
||||||
void *ptr=vtable[ThisVTable::index];
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=manager->ThisEntries.size();
|
|
||||||
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_DONE);
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (manager->ThisEntries[i]->IsTrampoline(ptr))
|
|
||||||
{
|
|
||||||
// this function is already hooked!
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// this function is NOT hooked
|
|
||||||
void *tramp;
|
|
||||||
void *func;
|
|
||||||
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
|
|
||||||
ThisVTable *entry=new ThisVTable;
|
|
||||||
|
|
||||||
entry->Setup(&vtable[ThisVTable::index],tramp,func);
|
|
||||||
|
|
||||||
manager->ThisEntries.push_back(entry);
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
entry->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the command. This is called directly from our global hook function.
|
|
||||||
*
|
|
||||||
* @param pthis The "this" pointer, cast to a void. The victim.
|
|
||||||
* @return Pointer to the this object it seems? Pointless
|
|
||||||
*/
|
|
||||||
void *ThisVTable::Execute(void *pthis)
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
|
|
||||||
int end=Forwards.size();
|
|
||||||
|
|
||||||
int result=HAM_UNSET;
|
|
||||||
int thisresult=HAM_UNSET;
|
|
||||||
|
|
||||||
int iThis=PrivateToIndex(pthis);
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
thisresult=MF_ExecuteForward(Forwards[i++],iThis);
|
|
||||||
|
|
||||||
if (thisresult>result)
|
|
||||||
{
|
|
||||||
result=thisresult;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void *ret=NULL;
|
|
||||||
if (result<HAM_SUPERCEDE)
|
|
||||||
{
|
|
||||||
#if defined _WIN32
|
|
||||||
ret=reinterpret_cast<void *(__fastcall *)(void *,int)>(function)(pthis,0);
|
|
||||||
#elif defined __linux__
|
|
||||||
ret=reinterpret_cast<void *(*)(void *)>(function)(pthis);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
i=0;
|
|
||||||
end=PostForwards.size();
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
MF_ExecuteForward(PostForwards[i++],iThis);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
};
|
|
||||||
extern "C" void *ThisVTable::EntryPoint(int id,void *pthis)
|
|
||||||
{
|
|
||||||
return VTMan.ThisEntries[id]->Execute(pthis);
|
|
||||||
}
|
|
@ -1,356 +0,0 @@
|
|||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "VTableManager.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
#include "vfunc_gcc295.h"
|
|
||||||
#include "vfunc_msvc.h"
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
|
|
||||||
#define ThisVTable VTableRestart
|
|
||||||
#define ThisEntries RestartEntries
|
|
||||||
#define ThisKey "restart"
|
|
||||||
#define ThisNative "ham_restart"
|
|
||||||
#define ThisENative "ham_erestart"
|
|
||||||
#define ThisRegisterID HAM_Restart
|
|
||||||
#define ThisParamCount 0
|
|
||||||
#define ThisVoidCall 1
|
|
||||||
|
|
||||||
unsigned int *ThisVTable::pevoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::pevset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseset=0;
|
|
||||||
unsigned int ThisVTable::index=0;
|
|
||||||
unsigned int ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO callnatives[] = {
|
|
||||||
{ ThisNative, ThisVTable::NativeCall },
|
|
||||||
{ ThisENative, ThisVTable::ENativeCall },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
|
|
||||||
*
|
|
||||||
* @param poffset Pointer to an integer that stores the pev offset for this mod.
|
|
||||||
* @param pset Pointer to an integer that tells whether pev offset was set or not.
|
|
||||||
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
|
|
||||||
* @param baseset Pointer to an integer that tells whether class base offset has been set.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
|
|
||||||
{
|
|
||||||
ThisVTable::pevoffset=poffset;
|
|
||||||
ThisVTable::pevset=pset;
|
|
||||||
|
|
||||||
ThisVTable::baseoffset=baseoffs;
|
|
||||||
ThisVTable::baseset=baseset;
|
|
||||||
|
|
||||||
ThisVTable::index=0;
|
|
||||||
ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
RegisterConfigCallback(ThisVTable::ConfigDone);
|
|
||||||
|
|
||||||
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
|
|
||||||
|
|
||||||
RegisterThisRegisterName(ThisRegisterID,ThisKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when one of this table entry's keyvalues is caught in a config file.
|
|
||||||
*
|
|
||||||
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
|
|
||||||
* @param data The data this keyvalue is set to.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::KeyValue(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
if (strcmp(key,ThisKey)==0)
|
|
||||||
{
|
|
||||||
ThisVTable::index=HAM_StrToNum(data);
|
|
||||||
ThisVTable::indexset=1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called immediately after the config file is done being parsed. Register our natives here.
|
|
||||||
*
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::ConfigDone(void)
|
|
||||||
{
|
|
||||||
if (ThisVTable::indexset && *(ThisVTable::baseset))
|
|
||||||
{
|
|
||||||
MF_AddNatives(callnatives);
|
|
||||||
|
|
||||||
if (*(ThisVTable::pevset))
|
|
||||||
{
|
|
||||||
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// Get the classname
|
|
||||||
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
|
|
||||||
|
|
||||||
// create an entity, assign it the gamedll's class, hook it and destroy it
|
|
||||||
edict_t *Entity=CREATE_ENTITY();
|
|
||||||
|
|
||||||
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
// Simulate a call to hs_register_id_takedamage
|
|
||||||
cell tempparams[4];
|
|
||||||
memcpy(tempparams,params,sizeof(cell)*4);
|
|
||||||
tempparams[1]=ENTINDEX_NEW(Entity);
|
|
||||||
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int funcid;
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
|
|
||||||
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
edict_t *Entity=INDEXENT_NEW(params[1]);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::NativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// scan to see if this virtual function is a trampoline
|
|
||||||
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
|
|
||||||
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=VTMan.ThisEntries.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (VTMan.ThisEntries[i]->IsTrampoline(func))
|
|
||||||
{
|
|
||||||
// this function is a trampoline
|
|
||||||
// use the original function instead
|
|
||||||
func=VTMan.ThisEntries[i]->GetOriginalFunction();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// TODO: Inline ASM this
|
|
||||||
#ifdef _WIN32
|
|
||||||
reinterpret_cast<void (__fastcall *)(void *,int)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
0 /*fastcall buffer*/
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
reinterpret_cast<void (*)(void *)>(func)(
|
|
||||||
pthis /*this*/
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
VoidVCall0(
|
|
||||||
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
|
|
||||||
ThisVTable::index, /*vtable entry*/
|
|
||||||
*(ThisVTable::baseoffset) /*size of class*/
|
|
||||||
);
|
|
||||||
return 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param outtrampoline The trampoline that was created.
|
|
||||||
* @param origfunc The original function that was hooked.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
|
|
||||||
{
|
|
||||||
|
|
||||||
VTableEntryBase::CreateGenericTrampoline(manager,
|
|
||||||
vtable,
|
|
||||||
ThisVTable::index,
|
|
||||||
id,
|
|
||||||
outtrampoline,
|
|
||||||
origfunc,
|
|
||||||
reinterpret_cast<void *>(ThisVTable::EntryPoint),
|
|
||||||
0, // param count
|
|
||||||
1, // voidcall
|
|
||||||
1); // thiscall
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param plugin The plugin that's requesting this.
|
|
||||||
* @param funcid The function id of the callback.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
|
|
||||||
{
|
|
||||||
void *ptr=vtable[ThisVTable::index];
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=manager->ThisEntries.size();
|
|
||||||
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_DONE);
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (manager->ThisEntries[i]->IsTrampoline(ptr))
|
|
||||||
{
|
|
||||||
// this function is already hooked!
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// this function is NOT hooked
|
|
||||||
void *tramp;
|
|
||||||
void *func;
|
|
||||||
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
|
|
||||||
ThisVTable *entry=new ThisVTable;
|
|
||||||
|
|
||||||
entry->Setup(&vtable[ThisVTable::index],tramp,func);
|
|
||||||
|
|
||||||
manager->ThisEntries.push_back(entry);
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
entry->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the command. This is called directly from our global hook function.
|
|
||||||
*
|
|
||||||
* @param pthis The "this" pointer, cast to a void. The victim.
|
|
||||||
* @return Unsure. Does not appear to be used.
|
|
||||||
*/
|
|
||||||
void ThisVTable::Execute(void *pthis)
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
|
|
||||||
int end=Forwards.size();
|
|
||||||
|
|
||||||
int result=HAM_UNSET;
|
|
||||||
int thisresult=HAM_UNSET;
|
|
||||||
|
|
||||||
int iThis=PrivateToIndex(pthis);
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
thisresult=MF_ExecuteForward(Forwards[i++],iThis);
|
|
||||||
|
|
||||||
if (thisresult>result)
|
|
||||||
{
|
|
||||||
result=thisresult;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (result<HAM_SUPERCEDE)
|
|
||||||
{
|
|
||||||
#if defined _WIN32
|
|
||||||
reinterpret_cast<void (__fastcall *)(void *,int)>(function)(pthis,0);
|
|
||||||
#elif defined __linux__
|
|
||||||
reinterpret_cast<void (*)(void *)>(function)(pthis);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
i=0;
|
|
||||||
end=PostForwards.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
MF_ExecuteForward(PostForwards[i++],iThis);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
void HAM_CDECL ThisVTable::EntryPoint(int id,void *pthis)
|
|
||||||
{
|
|
||||||
VTMan.ThisEntries[id]->Execute(pthis);
|
|
||||||
}
|
|
@ -1,381 +0,0 @@
|
|||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "VTableManager.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
#include "vfunc_gcc295.h"
|
|
||||||
#include "vfunc_msvc.h"
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
|
|
||||||
#define ThisVTable VTableTakeDamage
|
|
||||||
#define ThisEntries TakeDamageEntries
|
|
||||||
|
|
||||||
#define ThisKey "takedamage"
|
|
||||||
#define ThisNative "ham_takedamage"
|
|
||||||
#define ThisENative "ham_etakedamage"
|
|
||||||
#define ThisRegisterID HAM_TakeDamage
|
|
||||||
#define ThisParamCount 4
|
|
||||||
#define ThisVoidCall 0
|
|
||||||
|
|
||||||
unsigned int *ThisVTable::pevoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::pevset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseset=0;
|
|
||||||
unsigned int ThisVTable::index=0;
|
|
||||||
unsigned int ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO callnatives[] = {
|
|
||||||
{ ThisNative, ThisVTable::NativeCall },
|
|
||||||
{ ThisENative, ThisVTable::ENativeCall },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
|
|
||||||
*
|
|
||||||
* @param poffset Pointer to an integer that stores the pev offset for this mod.
|
|
||||||
* @param pset Pointer to an integer that tells whether pev offset was set or not.
|
|
||||||
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
|
|
||||||
* @param baseset Pointer to an integer that tells whether class base offset has been set.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
|
|
||||||
{
|
|
||||||
ThisVTable::pevoffset=poffset;
|
|
||||||
ThisVTable::pevset=pset;
|
|
||||||
|
|
||||||
ThisVTable::baseoffset=baseoffs;
|
|
||||||
ThisVTable::baseset=baseset;
|
|
||||||
|
|
||||||
ThisVTable::index=0;
|
|
||||||
ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
RegisterConfigCallback(ThisVTable::ConfigDone);
|
|
||||||
|
|
||||||
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
|
|
||||||
|
|
||||||
RegisterThisRegisterName(ThisRegisterID,ThisKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when one of this table entry's keyvalues is caught in a config file.
|
|
||||||
*
|
|
||||||
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
|
|
||||||
* @param data The data this keyvalue is set to.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::KeyValue(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
if (strcmp(key,ThisKey)==0)
|
|
||||||
{
|
|
||||||
ThisVTable::index=HAM_StrToNum(data);
|
|
||||||
ThisVTable::indexset=1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called immediately after the config file is done being parsed. Register our natives here.
|
|
||||||
*
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::ConfigDone(void)
|
|
||||||
{
|
|
||||||
if (ThisVTable::indexset && *(ThisVTable::baseset))
|
|
||||||
{
|
|
||||||
MF_AddNatives(callnatives);
|
|
||||||
|
|
||||||
if (*(ThisVTable::pevset))
|
|
||||||
{
|
|
||||||
//MF_AddNatives(registernatives);
|
|
||||||
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// Get the classname
|
|
||||||
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
|
|
||||||
|
|
||||||
// create an entity, assign it the gamedll's class, hook it and destroy it
|
|
||||||
edict_t *Entity=CREATE_ENTITY();
|
|
||||||
|
|
||||||
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
// Simulate a call to hs_register_id_takedamage
|
|
||||||
cell tempparams[4];
|
|
||||||
memcpy(tempparams,params,sizeof(cell)*4);
|
|
||||||
tempparams[1]=ENTINDEX_NEW(Entity);
|
|
||||||
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int funcid;
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
|
|
||||||
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
edict_t *Entity=INDEXENT_NEW(params[1]);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::NativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// scan to see if this virtual function is a trampoline
|
|
||||||
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
|
|
||||||
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=VTMan.ThisEntries.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (VTMan.ThisEntries[i]->IsTrampoline(func))
|
|
||||||
{
|
|
||||||
// this function is a trampoline
|
|
||||||
// use the original function instead
|
|
||||||
func=VTMan.ThisEntries[i]->GetOriginalFunction();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// TODO: Inline ASM this
|
|
||||||
#ifdef _WIN32
|
|
||||||
return reinterpret_cast<int (__fastcall *)(void *,int,void *,void *,float,int)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
0, /*fastcall buffer*/
|
|
||||||
&(INDEXENT_NEW(params[2])->v), /*inflictor*/
|
|
||||||
&(INDEXENT_NEW(params[3])->v), /*attacker*/
|
|
||||||
amx_ctof2(params[4]), /*damage*/
|
|
||||||
(int)params[5] /*dmgtype*/
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
return reinterpret_cast<int (*)(void *,void *,void *,float,int)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
&(INDEXENT_NEW(params[2])->v), /*inflictor*/
|
|
||||||
&(INDEXENT_NEW(params[3])->v), /*attacker*/
|
|
||||||
amx_ctof2(params[4]), /*damage*/
|
|
||||||
(int)params[5] /*dmgtype*/
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
return VCall4<int>(
|
|
||||||
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
|
|
||||||
ThisVTable::index, /*vtable entry*/
|
|
||||||
*(ThisVTable::baseoffset), /*size of class*/
|
|
||||||
&(INDEXENT_NEW(params[2])->v), /*inflictor*/
|
|
||||||
&(INDEXENT_NEW(params[3])->v), /*attacker*/
|
|
||||||
amx_ctof2(params[4]), /*damage*/
|
|
||||||
(int)params[5] /*dmgtype*/
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param outtrampoline The trampoline that was created.
|
|
||||||
* @param origfunc The original function that was hooked.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
|
|
||||||
{
|
|
||||||
|
|
||||||
VTableEntryBase::CreateGenericTrampoline(manager,
|
|
||||||
vtable,
|
|
||||||
ThisVTable::index,
|
|
||||||
id,
|
|
||||||
outtrampoline,
|
|
||||||
origfunc,
|
|
||||||
reinterpret_cast<void *>(ThisVTable::EntryPoint),
|
|
||||||
ThisParamCount, // param count
|
|
||||||
ThisVoidCall, // voidcall
|
|
||||||
1); // thiscall
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param plugin The plugin that's requesting this.
|
|
||||||
* @param funcid The function id of the callback.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
|
|
||||||
{
|
|
||||||
void *ptr=vtable[ThisVTable::index];
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=manager->ThisEntries.size();
|
|
||||||
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_CELL/*inflictor*/,FP_CELL/*attacker*/,FP_CELL/*damage*/,FP_CELL/*type*/,FP_DONE);
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (manager->ThisEntries[i]->IsTrampoline(ptr))
|
|
||||||
{
|
|
||||||
// this function is already hooked!
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// this function is NOT hooked
|
|
||||||
void *tramp;
|
|
||||||
void *func;
|
|
||||||
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
|
|
||||||
ThisVTable *entry=new ThisVTable;
|
|
||||||
|
|
||||||
entry->Setup(&vtable[ThisVTable::index],tramp,func);
|
|
||||||
|
|
||||||
manager->ThisEntries.push_back(entry);
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
entry->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the command. This is called directly from our global hook function.
|
|
||||||
*
|
|
||||||
* @param pthis The "this" pointer, cast to a void. The victim.
|
|
||||||
* @param inflictor Damage inflictor.
|
|
||||||
* @param attacker The attacker who caused the inflictor to damage the victim.
|
|
||||||
* @param damage How much damage was caused.
|
|
||||||
* @param type Damage type (usually in bitmask form).
|
|
||||||
* @return Unsure. Does not appear to be used.
|
|
||||||
*/
|
|
||||||
int ThisVTable::Execute(void *pthis, void *inflictor, void *attacker, float damage, int type)
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
|
|
||||||
int end=Forwards.size();
|
|
||||||
|
|
||||||
int result=HAM_UNSET;
|
|
||||||
int thisresult=HAM_UNSET;
|
|
||||||
|
|
||||||
int iThis=PrivateToIndex(pthis);
|
|
||||||
int iInflictor=EntvarToIndex((entvars_t *)inflictor);
|
|
||||||
int iAttacker=EntvarToIndex((entvars_t *)attacker);
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
thisresult=MF_ExecuteForward(Forwards[i++],iThis,iInflictor,iAttacker,amx_ftoc2(damage),type);
|
|
||||||
|
|
||||||
if (thisresult>result)
|
|
||||||
{
|
|
||||||
result=thisresult;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
int ireturn=0;
|
|
||||||
|
|
||||||
if (result<HAM_SUPERCEDE)
|
|
||||||
{
|
|
||||||
#if defined _WIN32
|
|
||||||
ireturn=reinterpret_cast<int (__fastcall *)(void *,int,void *,void *,float,int)>(function)(pthis,0,inflictor,attacker,damage,type);
|
|
||||||
#elif defined __linux__
|
|
||||||
ireturn=reinterpret_cast<int (*)(void *,void *,void *,float,int)>(function)(pthis,inflictor,attacker,damage,type);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
i=0;
|
|
||||||
|
|
||||||
end=PostForwards.size();
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
MF_ExecuteForward(PostForwards[i++],iThis,iInflictor,iAttacker,amx_ftoc2(damage),type);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (result!=HAM_OVERRIDE)
|
|
||||||
return ireturn;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
int HAM_CDECL ThisVTable::EntryPoint(int id,void *pthis,void *inflictor,void *attacker,float damage,int type)
|
|
||||||
{
|
|
||||||
return VTMan.ThisEntries[id]->Execute(pthis,inflictor,attacker,damage,type);
|
|
||||||
}
|
|
@ -1,374 +0,0 @@
|
|||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "VTableManager.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
#include "vfunc_gcc295.h"
|
|
||||||
#include "vfunc_msvc.h"
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
|
|
||||||
#define ThisVTable VTableTakeHealth
|
|
||||||
#define ThisEntries TakeHealthEntries
|
|
||||||
|
|
||||||
#define ThisKey "takehealth"
|
|
||||||
#define ThisNative "ham_takehealth"
|
|
||||||
#define ThisENative "ham_etakehealth"
|
|
||||||
#define ThisRegisterID HAM_TakeHealth
|
|
||||||
#define ThisParamCount 2
|
|
||||||
#define ThisVoidCall 0
|
|
||||||
|
|
||||||
unsigned int *ThisVTable::pevoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::pevset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseset=0;
|
|
||||||
unsigned int ThisVTable::index=0;
|
|
||||||
unsigned int ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO callnatives[] = {
|
|
||||||
{ ThisNative, ThisVTable::NativeCall },
|
|
||||||
{ ThisENative, ThisVTable::ENativeCall },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
|
|
||||||
*
|
|
||||||
* @param poffset Pointer to an integer that stores the pev offset for this mod.
|
|
||||||
* @param pset Pointer to an integer that tells whether pev offset was set or not.
|
|
||||||
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
|
|
||||||
* @param baseset Pointer to an integer that tells whether class base offset has been set.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
|
|
||||||
{
|
|
||||||
ThisVTable::pevoffset=poffset;
|
|
||||||
ThisVTable::pevset=pset;
|
|
||||||
|
|
||||||
ThisVTable::baseoffset=baseoffs;
|
|
||||||
ThisVTable::baseset=baseset;
|
|
||||||
|
|
||||||
ThisVTable::index=0;
|
|
||||||
ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
RegisterConfigCallback(ThisVTable::ConfigDone);
|
|
||||||
|
|
||||||
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
|
|
||||||
|
|
||||||
RegisterThisRegisterName(ThisRegisterID,ThisKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when one of this table entry's keyvalues is caught in a config file.
|
|
||||||
*
|
|
||||||
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
|
|
||||||
* @param data The data this keyvalue is set to.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::KeyValue(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
if (strcmp(key,ThisKey)==0)
|
|
||||||
{
|
|
||||||
ThisVTable::index=HAM_StrToNum(data);
|
|
||||||
ThisVTable::indexset=1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called immediately after the config file is done being parsed. Register our natives here.
|
|
||||||
*
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::ConfigDone(void)
|
|
||||||
{
|
|
||||||
if (ThisVTable::indexset && *(ThisVTable::baseset))
|
|
||||||
{
|
|
||||||
MF_AddNatives(callnatives);
|
|
||||||
|
|
||||||
if (*(ThisVTable::pevset))
|
|
||||||
{
|
|
||||||
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// Get the classname
|
|
||||||
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
|
|
||||||
|
|
||||||
// create an entity, assign it the gamedll's class, hook it and destroy it
|
|
||||||
edict_t *Entity=CREATE_ENTITY();
|
|
||||||
|
|
||||||
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
// Simulate a call to hs_register_id_TakeHealth
|
|
||||||
cell tempparams[4];
|
|
||||||
memcpy(tempparams,params,sizeof(cell)*4);
|
|
||||||
tempparams[1]=ENTINDEX_NEW(Entity);
|
|
||||||
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int funcid;
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
|
|
||||||
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
edict_t *Entity=INDEXENT_NEW(params[1]);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::NativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// scan to see if this virtual function is a trampoline
|
|
||||||
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
|
|
||||||
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=VTMan.ThisEntries.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (VTMan.ThisEntries[i]->IsTrampoline(func))
|
|
||||||
{
|
|
||||||
// this function is a trampoline
|
|
||||||
// use the original function instead
|
|
||||||
func=VTMan.ThisEntries[i]->GetOriginalFunction();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// TODO: Inline ASM this
|
|
||||||
#ifdef _WIN32
|
|
||||||
return reinterpret_cast<int (__fastcall *)(void *,int,void *,void *,float,int)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
0, /*fastcall buffer*/
|
|
||||||
&(INDEXENT_NEW(params[2])->v), /*inflictor*/
|
|
||||||
&(INDEXENT_NEW(params[3])->v), /*attacker*/
|
|
||||||
amx_ctof2(params[4]), /*damage*/
|
|
||||||
(int)params[5] /*dmgtype*/
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
return reinterpret_cast<int (*)(void *,void *,void *,float,int)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
&(INDEXENT_NEW(params[2])->v), /*inflictor*/
|
|
||||||
&(INDEXENT_NEW(params[3])->v), /*attacker*/
|
|
||||||
amx_ctof2(params[4]), /*damage*/
|
|
||||||
(int)params[5] /*dmgtype*/
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
return VCall4<int>(
|
|
||||||
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
|
|
||||||
ThisVTable::index, /*vtable entry*/
|
|
||||||
*(ThisVTable::baseoffset), /*size of class*/
|
|
||||||
&(INDEXENT_NEW(params[2])->v), /*inflictor*/
|
|
||||||
&(INDEXENT_NEW(params[3])->v), /*attacker*/
|
|
||||||
amx_ctof2(params[4]), /*damage*/
|
|
||||||
(int)params[5] /*dmgtype*/
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param outtrampoline The trampoline that was created.
|
|
||||||
* @param origfunc The original function that was hooked.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
|
|
||||||
{
|
|
||||||
|
|
||||||
VTableEntryBase::CreateGenericTrampoline(manager,
|
|
||||||
vtable,
|
|
||||||
ThisVTable::index,
|
|
||||||
id,
|
|
||||||
outtrampoline,
|
|
||||||
origfunc,
|
|
||||||
reinterpret_cast<void *>(ThisVTable::EntryPoint),
|
|
||||||
ThisParamCount, // param count
|
|
||||||
ThisVoidCall, // voidcall
|
|
||||||
1); // thiscall
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param plugin The plugin that's requesting this.
|
|
||||||
* @param funcid The function id of the callback.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
|
|
||||||
{
|
|
||||||
void *ptr=vtable[ThisVTable::index];
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=manager->ThisEntries.size();
|
|
||||||
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_CELL/*amount*/,FP_CELL/*type*/,FP_DONE);
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (manager->ThisEntries[i]->IsTrampoline(ptr))
|
|
||||||
{
|
|
||||||
// this function is already hooked!
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// this function is NOT hooked
|
|
||||||
void *tramp;
|
|
||||||
void *func;
|
|
||||||
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
|
|
||||||
ThisVTable *entry=new ThisVTable;
|
|
||||||
|
|
||||||
entry->Setup(&vtable[ThisVTable::index],tramp,func);
|
|
||||||
|
|
||||||
manager->ThisEntries.push_back(entry);
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
entry->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the command. This is called directly from our global hook function.
|
|
||||||
*
|
|
||||||
* @param pthis The "this" pointer, cast to a void. The victim.
|
|
||||||
* @param inflictor Damage inflictor.
|
|
||||||
* @param attacker The attacker who caused the inflictor to damage the victim.
|
|
||||||
* @param damage How much damage was caused.
|
|
||||||
* @param type Damage type (usually in bitmask form).
|
|
||||||
* @return Unsure. Does not appear to be used.
|
|
||||||
*/
|
|
||||||
int ThisVTable::Execute(void *pthis, float amount, int type)
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
|
|
||||||
int end=Forwards.size();
|
|
||||||
|
|
||||||
int result=HAM_UNSET;
|
|
||||||
int thisresult=HAM_UNSET;
|
|
||||||
|
|
||||||
int iThis=PrivateToIndex(pthis);
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
thisresult=MF_ExecuteForward(Forwards[i++],iThis,amx_ftoc2(amount),type);
|
|
||||||
|
|
||||||
if (thisresult>result)
|
|
||||||
{
|
|
||||||
result=thisresult;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
int ireturn=0;
|
|
||||||
|
|
||||||
if (result<HAM_SUPERCEDE)
|
|
||||||
{
|
|
||||||
#if defined _WIN32
|
|
||||||
ireturn=reinterpret_cast<int (__fastcall *)(void *,int,float,int)>(function)(pthis,0,amount,type);
|
|
||||||
#elif defined __linux__
|
|
||||||
ireturn=reinterpret_cast<int (*)(void *,float,int)>(function)(pthis,amount,type);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
i=0;
|
|
||||||
|
|
||||||
end=PostForwards.size();
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
MF_ExecuteForward(PostForwards[i++],iThis,amx_ftoc2(amount),type);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (result!=HAM_OVERRIDE)
|
|
||||||
return ireturn;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
};
|
|
@ -1,356 +0,0 @@
|
|||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "VTableManager.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
#include "vfunc_gcc295.h"
|
|
||||||
#include "vfunc_msvc.h"
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
|
|
||||||
#define ThisVTable VTableThink
|
|
||||||
#define ThisEntries ThinkEntries
|
|
||||||
#define ThisKey "think"
|
|
||||||
#define ThisNative "ham_think"
|
|
||||||
#define ThisENative "ham_ethink"
|
|
||||||
#define ThisRegisterID HAM_Think
|
|
||||||
#define ThisParamCount 0
|
|
||||||
#define ThisVoidCall 1
|
|
||||||
|
|
||||||
unsigned int *ThisVTable::pevoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::pevset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseset=0;
|
|
||||||
unsigned int ThisVTable::index=0;
|
|
||||||
unsigned int ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO callnatives[] = {
|
|
||||||
{ ThisNative, ThisVTable::NativeCall },
|
|
||||||
{ ThisENative, ThisVTable::ENativeCall },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
|
|
||||||
*
|
|
||||||
* @param poffset Pointer to an integer that stores the pev offset for this mod.
|
|
||||||
* @param pset Pointer to an integer that tells whether pev offset was set or not.
|
|
||||||
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
|
|
||||||
* @param baseset Pointer to an integer that tells whether class base offset has been set.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
|
|
||||||
{
|
|
||||||
ThisVTable::pevoffset=poffset;
|
|
||||||
ThisVTable::pevset=pset;
|
|
||||||
|
|
||||||
ThisVTable::baseoffset=baseoffs;
|
|
||||||
ThisVTable::baseset=baseset;
|
|
||||||
|
|
||||||
ThisVTable::index=0;
|
|
||||||
ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
RegisterConfigCallback(ThisVTable::ConfigDone);
|
|
||||||
|
|
||||||
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
|
|
||||||
|
|
||||||
RegisterThisRegisterName(ThisRegisterID,ThisKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when one of this table entry's keyvalues is caught in a config file.
|
|
||||||
*
|
|
||||||
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
|
|
||||||
* @param data The data this keyvalue is set to.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::KeyValue(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
if (strcmp(key,ThisKey)==0)
|
|
||||||
{
|
|
||||||
ThisVTable::index=HAM_StrToNum(data);
|
|
||||||
ThisVTable::indexset=1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called immediately after the config file is done being parsed. Register our natives here.
|
|
||||||
*
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::ConfigDone(void)
|
|
||||||
{
|
|
||||||
if (ThisVTable::indexset && *(ThisVTable::baseset))
|
|
||||||
{
|
|
||||||
MF_AddNatives(callnatives);
|
|
||||||
|
|
||||||
if (*(ThisVTable::pevset))
|
|
||||||
{
|
|
||||||
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// Get the classname
|
|
||||||
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
|
|
||||||
|
|
||||||
// create an entity, assign it the gamedll's class, hook it and destroy it
|
|
||||||
edict_t *Entity=CREATE_ENTITY();
|
|
||||||
|
|
||||||
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
// Simulate a call to hs_register_id_takedamage
|
|
||||||
cell tempparams[4];
|
|
||||||
memcpy(tempparams,params,sizeof(cell)*4);
|
|
||||||
tempparams[1]=ENTINDEX_NEW(Entity);
|
|
||||||
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int funcid;
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
|
|
||||||
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
edict_t *Entity=INDEXENT_NEW(params[1]);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::NativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// scan to see if this virtual function is a trampoline
|
|
||||||
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
|
|
||||||
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=VTMan.ThisEntries.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (VTMan.ThisEntries[i]->IsTrampoline(func))
|
|
||||||
{
|
|
||||||
// this function is a trampoline
|
|
||||||
// use the original function instead
|
|
||||||
func=VTMan.ThisEntries[i]->GetOriginalFunction();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// TODO: Inline ASM this
|
|
||||||
#ifdef _WIN32
|
|
||||||
reinterpret_cast<void (__fastcall *)(void *,int)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
0 /*fastcall buffer*/
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
reinterpret_cast<void (*)(void *)>(func)(
|
|
||||||
pthis /*this*/
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
VoidVCall0(
|
|
||||||
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
|
|
||||||
ThisVTable::index, /*vtable entry*/
|
|
||||||
*(ThisVTable::baseoffset) /*size of class*/
|
|
||||||
);
|
|
||||||
return 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param outtrampoline The trampoline that was created.
|
|
||||||
* @param origfunc The original function that was hooked.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
|
|
||||||
{
|
|
||||||
|
|
||||||
VTableEntryBase::CreateGenericTrampoline(manager,
|
|
||||||
vtable,
|
|
||||||
ThisVTable::index,
|
|
||||||
id,
|
|
||||||
outtrampoline,
|
|
||||||
origfunc,
|
|
||||||
reinterpret_cast<void *>(ThisVTable::EntryPoint),
|
|
||||||
0, // param count
|
|
||||||
1, // voidcall
|
|
||||||
1); // thiscall
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param plugin The plugin that's requesting this.
|
|
||||||
* @param funcid The function id of the callback.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
|
|
||||||
{
|
|
||||||
void *ptr=vtable[ThisVTable::index];
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=manager->ThisEntries.size();
|
|
||||||
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_DONE);
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (manager->ThisEntries[i]->IsTrampoline(ptr))
|
|
||||||
{
|
|
||||||
// this function is already hooked!
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// this function is NOT hooked
|
|
||||||
void *tramp;
|
|
||||||
void *func;
|
|
||||||
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
|
|
||||||
ThisVTable *entry=new ThisVTable;
|
|
||||||
|
|
||||||
entry->Setup(&vtable[ThisVTable::index],tramp,func);
|
|
||||||
|
|
||||||
manager->ThisEntries.push_back(entry);
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
entry->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the command. This is called directly from our global hook function.
|
|
||||||
*
|
|
||||||
* @param pthis The "this" pointer, cast to a void. The victim.
|
|
||||||
* @return Unsure. Does not appear to be used.
|
|
||||||
*/
|
|
||||||
void ThisVTable::Execute(void *pthis)
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
|
|
||||||
int end=Forwards.size();
|
|
||||||
|
|
||||||
int result=HAM_UNSET;
|
|
||||||
int thisresult=HAM_UNSET;
|
|
||||||
|
|
||||||
int iThis=PrivateToIndex(pthis);
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
thisresult=MF_ExecuteForward(Forwards[i++],iThis);
|
|
||||||
|
|
||||||
if (thisresult>result)
|
|
||||||
{
|
|
||||||
result=thisresult;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (result<HAM_SUPERCEDE)
|
|
||||||
{
|
|
||||||
#if defined _WIN32
|
|
||||||
reinterpret_cast<void (__fastcall *)(void *,int)>(function)(pthis,0);
|
|
||||||
#elif defined __linux__
|
|
||||||
reinterpret_cast<void (*)(void *)>(function)(pthis);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
i=0;
|
|
||||||
end=PostForwards.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
MF_ExecuteForward(PostForwards[i++],iThis);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
void HAM_CDECL ThisVTable::EntryPoint(int id,void *pthis)
|
|
||||||
{
|
|
||||||
VTMan.ThisEntries[id]->Execute(pthis);
|
|
||||||
}
|
|
@ -1,366 +0,0 @@
|
|||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "VTableManager.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
#include "vfunc_gcc295.h"
|
|
||||||
#include "vfunc_msvc.h"
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
|
|
||||||
#define ThisVTable VTableTouch
|
|
||||||
#define ThisEntries TouchEntries
|
|
||||||
|
|
||||||
#define ThisKey "touch"
|
|
||||||
#define ThisNative "ham_touch"
|
|
||||||
#define ThisENative "ham_etouch"
|
|
||||||
#define ThisRegisterID HAM_Touch
|
|
||||||
#define ThisParamCount 1
|
|
||||||
#define ThisVoidCall 1
|
|
||||||
|
|
||||||
|
|
||||||
unsigned int *ThisVTable::pevoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::pevset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseset=0;
|
|
||||||
unsigned int ThisVTable::index=0;
|
|
||||||
unsigned int ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO callnatives[] = {
|
|
||||||
{ ThisNative, ThisVTable::NativeCall },
|
|
||||||
{ ThisENative, ThisVTable::ENativeCall },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
|
|
||||||
*
|
|
||||||
* @param poffset Pointer to an integer that stores the pev offset for this mod.
|
|
||||||
* @param pset Pointer to an integer that tells whether pev offset was set or not.
|
|
||||||
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
|
|
||||||
* @param baseset Pointer to an integer that tells whether class base offset has been set.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
|
|
||||||
{
|
|
||||||
ThisVTable::pevoffset=poffset;
|
|
||||||
ThisVTable::pevset=pset;
|
|
||||||
|
|
||||||
ThisVTable::baseoffset=baseoffs;
|
|
||||||
ThisVTable::baseset=baseset;
|
|
||||||
|
|
||||||
ThisVTable::index=0;
|
|
||||||
ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
RegisterConfigCallback(ThisVTable::ConfigDone);
|
|
||||||
|
|
||||||
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
|
|
||||||
|
|
||||||
RegisterThisRegisterName(ThisRegisterID,ThisKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when one of this table entry's keyvalues is caught in a config file.
|
|
||||||
*
|
|
||||||
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
|
|
||||||
* @param data The data this keyvalue is set to.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::KeyValue(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
if (strcmp(key,ThisKey)==0)
|
|
||||||
{
|
|
||||||
ThisVTable::index=HAM_StrToNum(data);
|
|
||||||
ThisVTable::indexset=1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called immediately after the config file is done being parsed. Register our natives here.
|
|
||||||
*
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::ConfigDone(void)
|
|
||||||
{
|
|
||||||
if (ThisVTable::indexset && *(ThisVTable::baseset))
|
|
||||||
{
|
|
||||||
MF_AddNatives(callnatives);
|
|
||||||
|
|
||||||
if (*(ThisVTable::pevset))
|
|
||||||
{
|
|
||||||
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// Get the classname
|
|
||||||
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
|
|
||||||
|
|
||||||
// create an entity, assign it the gamedll's class, hook it and destroy it
|
|
||||||
edict_t *Entity=CREATE_ENTITY();
|
|
||||||
|
|
||||||
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
// Simulate a call to hs_register_id_takedamage
|
|
||||||
cell tempparams[4];
|
|
||||||
memcpy(tempparams,params,sizeof(cell)*4);
|
|
||||||
tempparams[1]=ENTINDEX_NEW(Entity);
|
|
||||||
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int funcid;
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
|
|
||||||
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
edict_t *Entity=INDEXENT_NEW(params[1]);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::NativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// scan to see if this virtual function is a trampoline
|
|
||||||
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
|
|
||||||
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=VTMan.ThisEntries.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (VTMan.ThisEntries[i]->IsTrampoline(func))
|
|
||||||
{
|
|
||||||
// this function is a trampoline
|
|
||||||
// use the original function instead
|
|
||||||
func=VTMan.ThisEntries[i]->GetOriginalFunction();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// TODO: Inline ASM this
|
|
||||||
#ifdef _WIN32
|
|
||||||
reinterpret_cast<void (__fastcall *)(void *,int,void *)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
0, /*fastcall buffer*/
|
|
||||||
INDEXENT_NEW(params[2])->pvPrivateData /*other*/
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
reinterpret_cast<void (*)(void *,void *)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
INDEXENT_NEW(params[2])->pvPrivateData /*other*/
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
return 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
VoidVCall1(
|
|
||||||
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
|
|
||||||
ThisVTable::index, /*vtable entry*/
|
|
||||||
*(ThisVTable::baseoffset), /*size of class*/
|
|
||||||
INDEXENT_NEW(params[2])->pvPrivateData /*other*/
|
|
||||||
);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param outtrampoline The trampoline that was created.
|
|
||||||
* @param origfunc The original function that was hooked.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
|
|
||||||
{
|
|
||||||
|
|
||||||
VTableEntryBase::CreateGenericTrampoline(manager,
|
|
||||||
vtable,
|
|
||||||
ThisVTable::index,
|
|
||||||
id,
|
|
||||||
outtrampoline,
|
|
||||||
origfunc,
|
|
||||||
reinterpret_cast<void *>(ThisVTable::EntryPoint),
|
|
||||||
ThisParamCount, // param count
|
|
||||||
ThisVoidCall, // voidcall
|
|
||||||
1); // thiscall
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param plugin The plugin that's requesting this.
|
|
||||||
* @param funcid The function id of the callback.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
|
|
||||||
{
|
|
||||||
void *ptr=vtable[ThisVTable::index];
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=manager->ThisEntries.size();
|
|
||||||
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_CELL/*other*/,FP_DONE);
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (manager->ThisEntries[i]->IsTrampoline(ptr))
|
|
||||||
{
|
|
||||||
// this function is already hooked!
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// this function is NOT hooked
|
|
||||||
void *tramp;
|
|
||||||
void *func;
|
|
||||||
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
|
|
||||||
ThisVTable *entry=new ThisVTable;
|
|
||||||
|
|
||||||
entry->Setup(&vtable[ThisVTable::index],tramp,func);
|
|
||||||
|
|
||||||
manager->ThisEntries.push_back(entry);
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
entry->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the command. This is called directly from our global hook function.
|
|
||||||
*
|
|
||||||
* @param pthis The "this" pointer, cast to a void. The victim.
|
|
||||||
* @param activator Entity causing the opening.
|
|
||||||
* @param caller Entity controlling the caller.
|
|
||||||
* @param type USE_TYPE (USE_{ON,OFF,SET}
|
|
||||||
* @param value Use value, only seen set when USE_SET is used.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Execute(void *pthis, void *other)
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
|
|
||||||
int end=Forwards.size();
|
|
||||||
|
|
||||||
int result=HAM_UNSET;
|
|
||||||
int thisresult=HAM_UNSET;
|
|
||||||
|
|
||||||
int iThis=PrivateToIndex(pthis);
|
|
||||||
int iOther=PrivateToIndex(other);
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
thisresult=MF_ExecuteForward(Forwards[i++],iThis,iOther);
|
|
||||||
|
|
||||||
if (thisresult>result)
|
|
||||||
{
|
|
||||||
result=thisresult;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (result<HAM_SUPERCEDE)
|
|
||||||
{
|
|
||||||
#if defined _WIN32
|
|
||||||
reinterpret_cast<void (__fastcall *)(void *,int, void *)>(function)(pthis,0,other);
|
|
||||||
#elif defined __linux__
|
|
||||||
reinterpret_cast<void (*)(void *,void *)>(function)(pthis,other);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
i=0;
|
|
||||||
end=PostForwards.size();
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
MF_ExecuteForward(PostForwards[i++],iThis,iOther);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
void HAM_CDECL ThisVTable::EntryPoint(int id,void *pthis,void *other)
|
|
||||||
{
|
|
||||||
VTMan.ThisEntries[id]->Execute(pthis,other);
|
|
||||||
}
|
|
@ -1,379 +0,0 @@
|
|||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "VTableManager.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
#include "vfunc_gcc295.h"
|
|
||||||
#include "vfunc_msvc.h"
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
// Change these on a per-hook basis! Auto-changes all the annoying fields in the following functions
|
|
||||||
#define ThisVTable VTableUse
|
|
||||||
#define ThisEntries UseEntries
|
|
||||||
|
|
||||||
#define ThisKey "use"
|
|
||||||
#define ThisNative "ham_use"
|
|
||||||
#define ThisENative "ham_euse"
|
|
||||||
#define ThisRegisterID HAM_Use
|
|
||||||
#define ThisParamCount 4
|
|
||||||
#define ThisVoidCall 1
|
|
||||||
|
|
||||||
|
|
||||||
unsigned int *ThisVTable::pevoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::pevset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseoffset=NULL;
|
|
||||||
unsigned int *ThisVTable::baseset=0;
|
|
||||||
unsigned int ThisVTable::index=0;
|
|
||||||
unsigned int ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO callnatives[] = {
|
|
||||||
{ ThisNative, ThisVTable::NativeCall },
|
|
||||||
{ ThisENative, ThisVTable::ENativeCall },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this table hook. This also registers our required keyvalue suffixes to the file parser.
|
|
||||||
*
|
|
||||||
* @param poffset Pointer to an integer that stores the pev offset for this mod.
|
|
||||||
* @param pset Pointer to an integer that tells whether pev offset was set or not.
|
|
||||||
* @param baseoffs Pointer to an integer that stores the class base offset for this mod. (GCC 2.95 only required)
|
|
||||||
* @param baseset Pointer to an integer that tells whether class base offset has been set.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Initialize(unsigned int *poffset, unsigned int *pset, unsigned int *baseoffs, unsigned int *baseset)
|
|
||||||
{
|
|
||||||
ThisVTable::pevoffset=poffset;
|
|
||||||
ThisVTable::pevset=pset;
|
|
||||||
|
|
||||||
ThisVTable::baseoffset=baseoffs;
|
|
||||||
ThisVTable::baseset=baseset;
|
|
||||||
|
|
||||||
ThisVTable::index=0;
|
|
||||||
ThisVTable::indexset=0;
|
|
||||||
|
|
||||||
RegisterConfigCallback(ThisVTable::ConfigDone);
|
|
||||||
|
|
||||||
RegisterKeySuffix(ThisKey,ThisVTable::KeyValue);
|
|
||||||
|
|
||||||
RegisterThisRegisterName(ThisRegisterID,ThisKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when one of this table entry's keyvalues is caught in a config file.
|
|
||||||
*
|
|
||||||
* @param key The keyvalue suffix ("<mod>_<os>_" is removed)
|
|
||||||
* @param data The data this keyvalue is set to.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::KeyValue(const char *key, const char *data)
|
|
||||||
{
|
|
||||||
if (strcmp(key,ThisKey)==0)
|
|
||||||
{
|
|
||||||
ThisVTable::index=HAM_StrToNum(data);
|
|
||||||
ThisVTable::indexset=1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called immediately after the config file is done being parsed. Register our natives here.
|
|
||||||
*
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::ConfigDone(void)
|
|
||||||
{
|
|
||||||
if (ThisVTable::indexset && *(ThisVTable::baseset))
|
|
||||||
{
|
|
||||||
MF_AddNatives(callnatives);
|
|
||||||
|
|
||||||
if (*(ThisVTable::pevset))
|
|
||||||
{
|
|
||||||
RegisterThisRegister(ThisRegisterID,ThisVTable::RegisterNative,ThisVTable::RegisterIDNative);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// Get the classname
|
|
||||||
char *classname=MF_GetAmxString(amx,params[1],1,NULL);
|
|
||||||
|
|
||||||
// create an entity, assign it the gamedll's class, hook it and destroy it
|
|
||||||
edict_t *Entity=CREATE_ENTITY();
|
|
||||||
|
|
||||||
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
// Simulate a call to hs_register_id_takedamage
|
|
||||||
cell tempparams[4];
|
|
||||||
memcpy(tempparams,params,sizeof(cell)*4);
|
|
||||||
tempparams[1]=ENTINDEX_NEW(Entity);
|
|
||||||
ThisVTable::RegisterIDNative(amx,&tempparams[0]);
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for \"%s\", hook for \"%s\" not active.",classname,function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is registering this entry's virtual hook. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::RegisterIDNative(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int funcid;
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
|
|
||||||
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
edict_t *Entity=INDEXENT_NEW(params[1]);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
ThisVTable::Hook(&VTMan,EdictToVTable(Entity),amx,funcid,params[0] / sizeof(cell) > 2 ? params[3] : 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// class was not found
|
|
||||||
// throw an error alerting console that this hook did not happen
|
|
||||||
MF_LogError(amx, AMX_ERR_NATIVE,"Failed to retrieve classtype for entity id %d, hook for \"%s\" not active.",params[1],function);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::NativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
// scan to see if this virtual function is a trampoline
|
|
||||||
void *pthis=INDEXENT_NEW(params[1])->pvPrivateData;
|
|
||||||
void *func=GetVTableEntry(pthis,ThisVTable::index,*ThisVTable::baseoffset);
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=VTMan.ThisEntries.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (VTMan.ThisEntries[i]->IsTrampoline(func))
|
|
||||||
{
|
|
||||||
// this function is a trampoline
|
|
||||||
// use the original function instead
|
|
||||||
func=VTMan.ThisEntries[i]->GetOriginalFunction();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// TODO: Inline ASM this
|
|
||||||
#ifdef _WIN32
|
|
||||||
reinterpret_cast<void (__fastcall *)(void *,int,void *, void *, int, float)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
0, /*fastcall buffer*/
|
|
||||||
INDEXENT_NEW(params[2])->pvPrivateData,
|
|
||||||
INDEXENT_NEW(params[3])->pvPrivateData,
|
|
||||||
params[4],
|
|
||||||
amx_ctof2(params[5])
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
reinterpret_cast<void (*)(void *,void *, void *, int, float)>(func)(
|
|
||||||
pthis, /*this*/
|
|
||||||
INDEXENT_NEW(params[2])->pvPrivateData,
|
|
||||||
INDEXENT_NEW(params[3])->pvPrivateData,
|
|
||||||
params[4],
|
|
||||||
amx_ctof2(params[5])
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A plugin is requesting a direct call of this entry's virtual function, and will be exposed to all hooks. This is a normal native callback.
|
|
||||||
*
|
|
||||||
* @param amx The AMX structure for the plugin.
|
|
||||||
* @param params The parameters passed from the plugin.
|
|
||||||
* @return 1 on success, 0 on failure. It only fails if the callback function is not found.
|
|
||||||
*/
|
|
||||||
cell ThisVTable::ENativeCall(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
VoidVCall4(
|
|
||||||
INDEXENT_NEW(params[1])->pvPrivateData, /*this*/
|
|
||||||
ThisVTable::index, /*vtable entry*/
|
|
||||||
*(ThisVTable::baseoffset), /*size of class*/
|
|
||||||
INDEXENT_NEW(params[2])->pvPrivateData, /*activator*/
|
|
||||||
INDEXENT_NEW(params[3])->pvPrivateData, /*caller*/
|
|
||||||
params[4], /*type*/
|
|
||||||
amx_ctof2(params[5])); /*value*/
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook this entry's function! This creates our trampoline and modifies the virtual table.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param outtrampoline The trampoline that was created.
|
|
||||||
* @param origfunc The original function that was hooked.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::CreateHook(VTableManager *manager, void **vtable, int id, void **outtrampoline, void **origfunc)
|
|
||||||
{
|
|
||||||
|
|
||||||
VTableEntryBase::CreateGenericTrampoline(manager,
|
|
||||||
vtable,
|
|
||||||
ThisVTable::index,
|
|
||||||
id,
|
|
||||||
outtrampoline,
|
|
||||||
origfunc,
|
|
||||||
reinterpret_cast<void *>(ThisVTable::EntryPoint),
|
|
||||||
ThisParamCount, // param count
|
|
||||||
ThisVoidCall, // voidcall
|
|
||||||
1); // thiscall
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the virtual function is already being hooked or not. If it's not, it begins hooking it. Either way it registers a forward and adds it to our vector.
|
|
||||||
*
|
|
||||||
* @param manager The VTableManager this is a child of.
|
|
||||||
* @param vtable The virtual table we're molesting.
|
|
||||||
* @param plugin The plugin that's requesting this.
|
|
||||||
* @param funcid The function id of the callback.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Hook(VTableManager *manager, void **vtable, AMX *plugin, int funcid, int post)
|
|
||||||
{
|
|
||||||
void *ptr=vtable[ThisVTable::index];
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
int end=manager->ThisEntries.size();
|
|
||||||
int fwd=MF_RegisterSPForward(plugin,funcid,FP_CELL/*this*/,FP_CELL/*inflictor*/,FP_CELL/*attacker*/,FP_CELL/*damage*/,FP_CELL/*type*/,FP_DONE);
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
if (manager->ThisEntries[i]->IsTrampoline(ptr))
|
|
||||||
{
|
|
||||||
// this function is already hooked!
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
manager->ThisEntries[i]->AddForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// this function is NOT hooked
|
|
||||||
void *tramp;
|
|
||||||
void *func;
|
|
||||||
ThisVTable::CreateHook(manager,vtable,manager->ThisEntries.size(),&tramp,&func);
|
|
||||||
ThisVTable *entry=new ThisVTable;
|
|
||||||
|
|
||||||
entry->Setup(&vtable[ThisVTable::index],tramp,func);
|
|
||||||
|
|
||||||
manager->ThisEntries.push_back(entry);
|
|
||||||
|
|
||||||
if (post)
|
|
||||||
{
|
|
||||||
entry->AddForward(fwd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->AddPostForward(fwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the command. This is called directly from our global hook function.
|
|
||||||
*
|
|
||||||
* @param pthis The "this" pointer, cast to a void. The victim.
|
|
||||||
* @param activator Entity causing the opening.
|
|
||||||
* @param caller Entity controlling the caller.
|
|
||||||
* @param type USE_TYPE (USE_{ON,OFF,SET}
|
|
||||||
* @param value Use value, only seen set when USE_SET is used.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
void ThisVTable::Execute(void *pthis, void *activator, void *caller, int type, float value)
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
|
|
||||||
int end=Forwards.size();
|
|
||||||
|
|
||||||
int result=HAM_UNSET;
|
|
||||||
int thisresult=HAM_UNSET;
|
|
||||||
|
|
||||||
int iThis=PrivateToIndex(pthis);
|
|
||||||
int iActivator=PrivateToIndex(activator);
|
|
||||||
int iCaller=PrivateToIndex(caller);
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
thisresult=MF_ExecuteForward(Forwards[i++],iThis,iActivator,iCaller,type,amx_ftoc2(value));
|
|
||||||
|
|
||||||
if (thisresult>result)
|
|
||||||
{
|
|
||||||
result=thisresult;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
if (result<HAM_SUPERCEDE)
|
|
||||||
{
|
|
||||||
#if defined _WIN32
|
|
||||||
reinterpret_cast<void (__fastcall *)(void *,int,void *,void *,int,float)>(function)(pthis,0,activator,caller,type,value);
|
|
||||||
#elif defined __linux__
|
|
||||||
reinterpret_cast<void (*)(void *,void *,void *,int,float)>(function)(pthis,activator,caller,type,value);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
i=0;
|
|
||||||
|
|
||||||
end=PostForwards.size();
|
|
||||||
|
|
||||||
while (i<end)
|
|
||||||
{
|
|
||||||
MF_ExecuteForward(PostForwards[i++],iThis,iActivator,iCaller,type,amx_ftoc2(value));
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
void HAM_CDECL ThisVTable::EntryPoint(int id,void *pthis,void *activator,void *caller,int type,float value)
|
|
||||||
{
|
|
||||||
VTMan.ThisEntries[id]->Execute(pthis,activator,caller,type,value);
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -1,193 +0,0 @@
|
|||||||
#include "sdk/amxxmodule.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "VTableManager.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
#include "NEW_Util.h"
|
|
||||||
|
|
||||||
VTableManager VTMan;
|
|
||||||
|
|
||||||
NATIVEFUNC VTableManager::RegisterNatives[HAM_END_DONT_USE_ME];
|
|
||||||
NATIVEFUNC VTableManager::RegisterIDNatives[HAM_END_DONT_USE_ME];
|
|
||||||
const char *VTableManager::RegisterNames[HAM_END_DONT_USE_ME];
|
|
||||||
|
|
||||||
void RegisterThisRegister(int index,NATIVEFUNC byname, NATIVEFUNC byid)
|
|
||||||
{
|
|
||||||
VTableManager::RegisterNatives[index]=byname;
|
|
||||||
VTableManager::RegisterIDNatives[index]=byid;
|
|
||||||
}
|
|
||||||
void RegisterThisRegisterName(int index, const char *name)
|
|
||||||
{
|
|
||||||
VTableManager::RegisterNames[index]=name;
|
|
||||||
}
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO registernatives[] = {
|
|
||||||
{ "ham_register", VTableManager::Register },
|
|
||||||
{ "ham_registerid", VTableManager::RegisterID },
|
|
||||||
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
void RegisterRegisterNatives(void)
|
|
||||||
{
|
|
||||||
MF_AddNatives(registernatives);
|
|
||||||
}
|
|
||||||
cell VTableManager::Register(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int id=params[1];
|
|
||||||
|
|
||||||
if (id<0 || id>=HAM_END_DONT_USE_ME || RegisterIDNatives[id]==NULL)
|
|
||||||
{
|
|
||||||
// this register is not found, fail the plugin
|
|
||||||
int fwd=MF_RegisterSPForwardByName(amx,"__fatal_ham_error",FP_STRING,FP_DONE);
|
|
||||||
char error[256];
|
|
||||||
|
|
||||||
snprintf(&error[0],sizeof(error)-1,"Requested to ham_registerid a function ID that is not registered in configs/hamdata.ini, cannot continue. (Requested: %d)",id);
|
|
||||||
|
|
||||||
MF_ExecuteForward(fwd,&error[0]);
|
|
||||||
|
|
||||||
MF_UnregisterSPForward(fwd);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
cell tempparams[4];
|
|
||||||
|
|
||||||
// remove one parameter from this param count
|
|
||||||
tempparams[0]=(params[0]-(sizeof(cell)));
|
|
||||||
tempparams[1]=params[2];
|
|
||||||
tempparams[2]=params[3];
|
|
||||||
tempparams[3]=params[4];
|
|
||||||
|
|
||||||
return RegisterNatives[id](amx,&tempparams[0]);
|
|
||||||
}
|
|
||||||
cell VTableManager::RegisterID(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int id=params[1];
|
|
||||||
|
|
||||||
if (id<0 || id>=HAM_END_DONT_USE_ME || RegisterNatives[id]==NULL)
|
|
||||||
{
|
|
||||||
// this register is not found, fail the plugin
|
|
||||||
int fwd=MF_RegisterSPForwardByName(amx,"__fatal_ham_error",FP_STRING,FP_DONE);
|
|
||||||
|
|
||||||
char error[256];
|
|
||||||
|
|
||||||
snprintf(&error[0],sizeof(error)-1,"Requested to ham_register a function ID that is not registered in configs/hamdata.ini, cannot continue. (Requested: %d)",id);
|
|
||||||
|
|
||||||
MF_ExecuteForward(fwd,&error[0]);
|
|
||||||
|
|
||||||
MF_UnregisterSPForward(fwd);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
cell tempparams[4];
|
|
||||||
|
|
||||||
// remove one parameter from this param count
|
|
||||||
tempparams[0]=(params[0]-(sizeof(cell)));
|
|
||||||
tempparams[1]=params[2];
|
|
||||||
tempparams[2]=params[3];
|
|
||||||
tempparams[3]=params[4];
|
|
||||||
|
|
||||||
return RegisterIDNatives[id](amx,&tempparams[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void *VTableManager::InsertIntoVTable(void **vtable, int index, void *trampoline)
|
|
||||||
{
|
|
||||||
void *func;
|
|
||||||
#if defined _WIN32
|
|
||||||
DWORD OldFlags;
|
|
||||||
VirtualProtect(&vtable[index],sizeof(int*),PAGE_READWRITE,&OldFlags);
|
|
||||||
#elif defined __linux__
|
|
||||||
mprotect(&vtable[index],sizeof(int*),PROT_READ|PROT_WRITE);
|
|
||||||
#endif
|
|
||||||
func=vtable[index];
|
|
||||||
vtable[index]=trampoline;
|
|
||||||
|
|
||||||
return func;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#define CLEAR_ENTRIES(Container) \
|
|
||||||
i=Container.size(); \
|
|
||||||
while (i--) \
|
|
||||||
{ \
|
|
||||||
Container[i]->Destroy(); \
|
|
||||||
delete Container[i]; \
|
|
||||||
} \
|
|
||||||
Container.clear()
|
|
||||||
|
|
||||||
|
|
||||||
void VTableManager::Cleanup(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
CLEAR_ENTRIES(UseEntries);
|
|
||||||
CLEAR_ENTRIES(TakeDamageEntries);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void VTableEntryBase::CreateGenericTrampoline(VTableManager *manager, void **vtable, int vtid, int id, void **outtrampoline, void **origfunc, void *callee, int paramcount, int voidcall, int thiscall)
|
|
||||||
{
|
|
||||||
Trampolines::TrampolineMaker tramp;
|
|
||||||
|
|
||||||
if (voidcall)
|
|
||||||
{
|
|
||||||
if (thiscall)
|
|
||||||
{
|
|
||||||
tramp.ThisVoidPrologue();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tramp.VoidPrologue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (thiscall)
|
|
||||||
{
|
|
||||||
tramp.ThisReturnPrologue();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tramp.ReturnPrologue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (paramcount)
|
|
||||||
{
|
|
||||||
tramp.PushParam(paramcount--);
|
|
||||||
}
|
|
||||||
if (thiscall)
|
|
||||||
{
|
|
||||||
tramp.PushThis();
|
|
||||||
}
|
|
||||||
tramp.PushNum(id);
|
|
||||||
tramp.Call(callee);
|
|
||||||
tramp.FreeTargetStack();
|
|
||||||
if (voidcall)
|
|
||||||
{
|
|
||||||
#if defined _WIN32
|
|
||||||
tramp.VoidEpilogueAndFree();
|
|
||||||
#elif defined __linux__
|
|
||||||
tramp.VoidEpilogue();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#if defined _WIN32
|
|
||||||
tramp.ReturnEpilogueAndFree();
|
|
||||||
#elif defined __linux__
|
|
||||||
tramp.ReturnEpilogue();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void *trampoline=tramp.Finish(NULL);
|
|
||||||
|
|
||||||
*outtrampoline=trampoline;
|
|
||||||
|
|
||||||
*origfunc=manager->InsertIntoVTable(vtable,vtid,trampoline);
|
|
||||||
};
|
|
@ -1,126 +0,0 @@
|
|||||||
#ifndef VTABLEMANAGER_H
|
|
||||||
#define VTABLEMANAGER_H
|
|
||||||
|
|
||||||
#include "Trampolines.h"
|
|
||||||
|
|
||||||
#include "hamsandwich.h"
|
|
||||||
|
|
||||||
#include "CVector.h"
|
|
||||||
#include "VTableEntries.h"
|
|
||||||
|
|
||||||
/* !!WARNING: HERE BE DRAGONS
|
|
||||||
|
|
||||||
.~))>>
|
|
||||||
.~)>>
|
|
||||||
.~))))>>>
|
|
||||||
.~))>> ___
|
|
||||||
.~))>>)))>> .-~))>>
|
|
||||||
.~)))))>> .-~))>>)>
|
|
||||||
.~)))>>))))>> .-~)>>)>
|
|
||||||
) .~))>>))))>> .-~)))))>>)>
|
|
||||||
( )@@*) //)>)))))) .-~))))>>)>
|
|
||||||
).@(@@ //))>>))) .-~))>>)))))>>)>
|
|
||||||
(( @.@). //))))) .-~)>>)))))>>)>
|
|
||||||
)) )@@*.@@ ) //)>))) //))))))>>))))>>)>
|
|
||||||
(( ((@@@.@@ |/))))) //)))))>>)))>>)>
|
|
||||||
)) @@*. )@@ ) (\_(\-\b |))>)) //)))>>)))))))>>)>
|
|
||||||
(( @@@(.@(@ . _/`-` ~|b |>))) //)>>)))))))>>)>
|
|
||||||
)* @@@ )@* (@) (@) /\b|))) //))))))>>))))>>
|
|
||||||
(( @. )@( @ . _/ / / \b)) //))>>)))))>>>_._
|
|
||||||
)@@ (@@*)@@. (6///6)- / ^ \b)//))))))>>)))>> ~~-.
|
|
||||||
( @jgs@@. @@@.*@_ VvvvvV// ^ \b/)>>))))>> _. `bb
|
|
||||||
((@@ @@@*.(@@ . - | o |' \ ( ^ \b)))>> .' b`,
|
|
||||||
((@@).*@@ )@ ) \^^^/ (( ^ ~)_ \ / b `,
|
|
||||||
(@@. (@@ ). `-' ((( ^ `\ \ \ \ \| b `.
|
|
||||||
(*.@* / (((( \| | | \ . b `.
|
|
||||||
/ / ((((( \ \ / _.-~\ Y, b ;
|
|
||||||
/ / / (((((( \ \.-~ _.`" _.-~`, b ;
|
|
||||||
/ / `(((((() ) (((((~ `, b ;
|
|
||||||
_/ _/ `"""/ /' ; b ;
|
|
||||||
_.-~_.-~ / /' _.'~bb _.'
|
|
||||||
((((~~ / /' _.'~bb.--~
|
|
||||||
(((( __.-~bb.-~
|
|
||||||
.' b .~~
|
|
||||||
:bb ,'
|
|
||||||
~~~~
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
HAM_UNSET = 0,
|
|
||||||
HAM_IGNORED,
|
|
||||||
HAM_HANDLED,
|
|
||||||
HAM_OVERRIDE,
|
|
||||||
HAM_SUPERCEDE
|
|
||||||
};
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
HAM_TYPE_UNKNOWN = 0,
|
|
||||||
HAM_TYPE_CBASE,
|
|
||||||
HAM_TYPE_ENTVAR,
|
|
||||||
HAM_TYPE_EDICT,
|
|
||||||
HAM_TYPE_INT,
|
|
||||||
HAM_TYPE_FLOAT
|
|
||||||
};
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
HAM_ERROR_BOUNDS = -2,
|
|
||||||
HAM_ERROR_TYPE = -1,
|
|
||||||
HAM_ERROR_NONE = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
typedef cell (*NATIVEFUNC)(AMX *, cell *);
|
|
||||||
|
|
||||||
class VTableManager
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
#define VTINIT(Type) CVector<VTable##Type *> Type##Entries
|
|
||||||
VTINIT(Use);
|
|
||||||
VTINIT(TakeDamage);
|
|
||||||
VTINIT(Blocked);
|
|
||||||
VTINIT(Killed);
|
|
||||||
VTINIT(Respawn);
|
|
||||||
VTINIT(Restart);
|
|
||||||
VTINIT(AddPoints);
|
|
||||||
VTINIT(AddPointsToTeam);
|
|
||||||
VTINIT(AddPlayerItem);
|
|
||||||
VTINIT(RemovePlayerItem);
|
|
||||||
VTINIT(BloodColor);
|
|
||||||
VTINIT(Classify);
|
|
||||||
VTINIT(GetToggleState);
|
|
||||||
VTINIT(IsAlive);
|
|
||||||
VTINIT(IsBSPModel);
|
|
||||||
VTINIT(IsInWorld);
|
|
||||||
VTINIT(IsMoving);
|
|
||||||
VTINIT(IsNetClient);
|
|
||||||
VTINIT(IsPlayer);
|
|
||||||
VTINIT(IsSneaking);
|
|
||||||
VTINIT(ObjectCaps);
|
|
||||||
VTINIT(Think);
|
|
||||||
VTINIT(Touch);
|
|
||||||
|
|
||||||
#undef VTINIT
|
|
||||||
static NATIVEFUNC RegisterNatives[HAM_END_DONT_USE_ME];
|
|
||||||
static NATIVEFUNC RegisterIDNatives[HAM_END_DONT_USE_ME];
|
|
||||||
static const char *RegisterNames[HAM_END_DONT_USE_ME];
|
|
||||||
|
|
||||||
static cell Register(AMX *amx, cell *params);
|
|
||||||
static cell RegisterID(AMX *amx, cell *params);
|
|
||||||
|
|
||||||
/* returns the original function */
|
|
||||||
void *InsertIntoVTable(void **vtable, int index, void *trampoline);
|
|
||||||
void Cleanup(void);
|
|
||||||
};
|
|
||||||
|
|
||||||
void RegisterThisRegister(int index,NATIVEFUNC byname, NATIVEFUNC byid);
|
|
||||||
void RegisterThisRegisterName(int index, const char *name);
|
|
||||||
void RegisterRegisterNatives(void);
|
|
||||||
|
|
||||||
extern VTableManager VTMan;
|
|
||||||
|
|
||||||
|
|
||||||
#endif // VTABLEMANAGER_H
|
|
@ -1,165 +0,0 @@
|
|||||||
/* Ham Sandwich
|
|
||||||
*
|
|
||||||
* by sawce
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by the
|
|
||||||
* Free Software Foundation; either version 2 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
|
|
||||||
* General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
* In addition, as a special exception, the author gives permission to
|
|
||||||
* link the code of this program with the Half-Life Game Engine ("HL
|
|
||||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
|
||||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
|
||||||
* respects for all of the code used other than the HL Engine and MODs
|
|
||||||
* from Valve. If you modify this file, you may extend this exception
|
|
||||||
* to your version of the file, but you are not obligated to do so. If
|
|
||||||
* you do not wish to do so, delete this exception statement from your
|
|
||||||
* version.
|
|
||||||
*/
|
|
||||||
// Calling virtual functions on binaries compiled with GCC 2.95
|
|
||||||
// 2.95 and before stores the virtual table at the end of the
|
|
||||||
// inheritable size of the base class.
|
|
||||||
// I have no idea how it does it for multiple inheritance; i don't
|
|
||||||
// really care. Everything I'm calling does it in single inheritence.
|
|
||||||
// GCC doesn't put this on a register like MSVC does, so
|
|
||||||
// just pass it like a normal parameter (the first one)
|
|
||||||
// For GCC 3.3 compiled binaries, set the "size" parameter to 0
|
|
||||||
|
|
||||||
#ifdef __linux__
|
|
||||||
#ifndef VFUNC_GCC295_H
|
|
||||||
#define VFUNC_GCC295_H
|
|
||||||
|
|
||||||
inline void *GetVTableEntry(void *pThis, int ventry, int size)
|
|
||||||
{
|
|
||||||
char *pcThis=*(char **)&pThis;
|
|
||||||
|
|
||||||
pcThis+=size;
|
|
||||||
|
|
||||||
void **vtbl=*(void ***)pcThis;
|
|
||||||
|
|
||||||
return vtbl[ventry];
|
|
||||||
}
|
|
||||||
|
|
||||||
// I only comment on the first call, because it's jut copy/paste after
|
|
||||||
// the rest are compacted for copy/paste ease
|
|
||||||
template <class PTypeA, class PTypeB, class PTypeC, class PTypeD>
|
|
||||||
inline void VoidVCall4(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb, PTypeC pc, PTypeD pd)
|
|
||||||
{
|
|
||||||
// First move up past the size of the class
|
|
||||||
char *pcThis=*(char **)&pThis;
|
|
||||||
|
|
||||||
pcThis+=size;
|
|
||||||
|
|
||||||
void **vtbl=*(void ***)pcThis;
|
|
||||||
|
|
||||||
// now points to the vtable of this object
|
|
||||||
|
|
||||||
typedef void (*fptr)(void*,PTypeA,PTypeB,PTypeC,PTypeD);
|
|
||||||
fptr function=reinterpret_cast<fptr>(vtbl[ventry]);
|
|
||||||
|
|
||||||
function(pThis,pa,pb,pc,pd);
|
|
||||||
};
|
|
||||||
template <class RetType, class PTypeA, class PTypeB, class PTypeC, class PTypeD>
|
|
||||||
inline RetType VCall4(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb, PTypeC pc, PTypeD pd)
|
|
||||||
{
|
|
||||||
char *pcThis=*(char **)&pThis;
|
|
||||||
pcThis+=size;
|
|
||||||
int **vtbl=*(int ***)pcThis;
|
|
||||||
typedef RetType (*fptr)(void*,PTypeA,PTypeB,PTypeC,PTypeD);
|
|
||||||
fptr function=reinterpret_cast<fptr>(vtbl[ventry]);
|
|
||||||
return function(pThis,pa,pb,pc,pd);
|
|
||||||
};
|
|
||||||
template <class PTypeA, class PTypeB, class PTypeC>
|
|
||||||
inline void VoidVCall3(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb, PTypeC pc)
|
|
||||||
{
|
|
||||||
char *pcThis=*(char **)&pThis;
|
|
||||||
pcThis+=size;
|
|
||||||
int **vtbl=*(int ***)pcThis;
|
|
||||||
typedef void (*fptr)(void*,PTypeA,PTypeB,PTypeC);
|
|
||||||
fptr function=reinterpret_cast<fptr>(vtbl[ventry]);
|
|
||||||
function(pThis,pa,pb,pc);
|
|
||||||
};
|
|
||||||
template <class RetType, class PTypeA, class PTypeB, class PTypeC>
|
|
||||||
inline RetType VCall3(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb, PTypeC pc)
|
|
||||||
{
|
|
||||||
char *pcThis=*(char **)&pThis;
|
|
||||||
pcThis+=size;
|
|
||||||
int **vtbl=*(int ***)pcThis;
|
|
||||||
typedef RetType (*fptr)(void*,PTypeA,PTypeB,PTypeC);
|
|
||||||
fptr function=reinterpret_cast<fptr>(vtbl[ventry]);
|
|
||||||
return function(pThis,pa,pb,pc);
|
|
||||||
};
|
|
||||||
template <class PTypeA, class PTypeB>
|
|
||||||
inline void VoidVCall2(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb)
|
|
||||||
{
|
|
||||||
char *pcThis=*(char **)&pThis;
|
|
||||||
pcThis+=size;
|
|
||||||
int **vtbl=*(int ***)pcThis;
|
|
||||||
typedef void (*fptr)(void*,PTypeA,PTypeB);
|
|
||||||
fptr function=reinterpret_cast<fptr>(vtbl[ventry]);
|
|
||||||
function(pThis,pa,pb);
|
|
||||||
};
|
|
||||||
template <class RetType, class PTypeA, class PTypeB>
|
|
||||||
inline RetType VCall2(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb)
|
|
||||||
{
|
|
||||||
char *pcThis=*(char **)&pThis;
|
|
||||||
pcThis+=size;
|
|
||||||
int **vtbl=*(int ***)pcThis;
|
|
||||||
typedef RetType (*fptr)(void*,PTypeA,PTypeB);
|
|
||||||
fptr function=reinterpret_cast<fptr>(vtbl[ventry]);
|
|
||||||
return function(pThis,pa,pb);
|
|
||||||
};
|
|
||||||
template <class PTypeA>
|
|
||||||
inline void VoidVCall1(void *pThis, int ventry, int size, PTypeA pa)
|
|
||||||
{
|
|
||||||
char *pcThis=*(char **)&pThis;
|
|
||||||
pcThis+=size;
|
|
||||||
int **vtbl=*(int ***)pcThis;
|
|
||||||
typedef void (*fptr)(void*,PTypeA);
|
|
||||||
fptr function=reinterpret_cast<fptr>(vtbl[ventry]);
|
|
||||||
function(pThis,pa);
|
|
||||||
};
|
|
||||||
template <class RetType, class PTypeA>
|
|
||||||
inline RetType VCall1(void *pThis, int ventry, int size, PTypeA pa)
|
|
||||||
{
|
|
||||||
char *pcThis=*(char **)&pThis;
|
|
||||||
pcThis+=size;
|
|
||||||
int **vtbl=*(int ***)pcThis;
|
|
||||||
typedef RetType (*fptr)(void*,PTypeA);
|
|
||||||
fptr function=reinterpret_cast<fptr>(vtbl[ventry]);
|
|
||||||
return function(pThis,pa);
|
|
||||||
};
|
|
||||||
inline void VoidVCall0(void *pThis, int ventry, int size)
|
|
||||||
{
|
|
||||||
char *pcThis=*(char **)&pThis;
|
|
||||||
pcThis+=size;
|
|
||||||
int **vtbl=*(int ***)pcThis;
|
|
||||||
typedef void (*fptr)(void*);
|
|
||||||
fptr function=reinterpret_cast<fptr>(vtbl[ventry]);
|
|
||||||
function(pThis);
|
|
||||||
};
|
|
||||||
template <class RetType>
|
|
||||||
inline RetType VCall0(void *pThis, int ventry, int size)
|
|
||||||
{
|
|
||||||
char *pcThis=*(char **)&pThis;
|
|
||||||
pcThis+=size;
|
|
||||||
int **vtbl=*(int ***)pcThis;
|
|
||||||
typedef RetType (*fptr)(void*);
|
|
||||||
fptr function=reinterpret_cast<fptr>(vtbl[ventry]);
|
|
||||||
return function(pThis);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //VFUNC_GCC295_H
|
|
||||||
#endif // __linux__
|
|
@ -1,245 +0,0 @@
|
|||||||
/* Ham Sandwich
|
|
||||||
*
|
|
||||||
* by sawce
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by the
|
|
||||||
* Free Software Foundation; either version 2 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
|
|
||||||
* General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
* In addition, as a special exception, the author gives permission to
|
|
||||||
* link the code of this program with the Half-Life Game Engine ("HL
|
|
||||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
|
||||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
|
||||||
* respects for all of the code used other than the HL Engine and MODs
|
|
||||||
* from Valve. If you modify this file, you may extend this exception
|
|
||||||
* to your version of the file, but you are not obligated to do so. If
|
|
||||||
* you do not wish to do so, delete this exception statement from your
|
|
||||||
* version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// MSVC stores vtable like normal at the front as well
|
|
||||||
// however these are thiscall functions
|
|
||||||
// i use inline assembly to call them
|
|
||||||
#ifdef _WIN32
|
|
||||||
#ifndef VFUNC_MSVC_H
|
|
||||||
#define VFUNC_MSVC_H
|
|
||||||
|
|
||||||
inline void *GetVTableEntry(void *pThis, int ventry, int size)
|
|
||||||
{
|
|
||||||
void **vtbl=*(void ***)pThis;
|
|
||||||
|
|
||||||
return vtbl[ventry];
|
|
||||||
}
|
|
||||||
template <class PTypeA, class PTypeB, class PTypeC, class PTypeD>
|
|
||||||
inline void VoidVCall4(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb, PTypeC pc, PTypeD pd)
|
|
||||||
{
|
|
||||||
// vtable pointer is stored in the first dword of the object
|
|
||||||
// reference it as an array of objects
|
|
||||||
void **vtbl=*(void ***)pThis;
|
|
||||||
|
|
||||||
void *func=vtbl[ventry];
|
|
||||||
|
|
||||||
// Simulate a thiscall
|
|
||||||
// this on ecx, all other parameters pushed normally
|
|
||||||
_asm {
|
|
||||||
push ecx; // save ecx
|
|
||||||
push eax; // save eax - shouldn't be needed, but just incase
|
|
||||||
|
|
||||||
push pd; // push param 4
|
|
||||||
push pc; // push param 3
|
|
||||||
push pb; // push param 2
|
|
||||||
push pa; // push param 1
|
|
||||||
|
|
||||||
mov ecx, pThis; // store this in ecx
|
|
||||||
|
|
||||||
call [func]; // call function
|
|
||||||
|
|
||||||
pop eax; // restore eax
|
|
||||||
pop ecx; // restore ecx
|
|
||||||
};
|
|
||||||
};
|
|
||||||
template <class RetType, class PTypeA, class PTypeB, class PTypeC, class PTypeD>
|
|
||||||
inline RetType VCall4(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb, PTypeC pc, PTypeD pd)
|
|
||||||
{
|
|
||||||
void **vtbl=*(void ***)pThis;
|
|
||||||
|
|
||||||
void *func=vtbl[ventry];
|
|
||||||
|
|
||||||
RetType _ret;
|
|
||||||
_asm {
|
|
||||||
push ecx;
|
|
||||||
push eax;
|
|
||||||
push pd;
|
|
||||||
push pc;
|
|
||||||
push pb;
|
|
||||||
push pa;
|
|
||||||
mov ecx, pThis;
|
|
||||||
call [func];
|
|
||||||
mov _ret, eax;
|
|
||||||
pop eax;
|
|
||||||
pop ecx;
|
|
||||||
};
|
|
||||||
|
|
||||||
return _ret;
|
|
||||||
};
|
|
||||||
template <class PTypeA, class PTypeB, class PTypeC>
|
|
||||||
inline void VoidVCall3(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb, PTypeC pc)
|
|
||||||
{
|
|
||||||
void **vtbl=*(void ***)pThis;
|
|
||||||
void *func=vtbl[ventry];
|
|
||||||
_asm {
|
|
||||||
push ecx;
|
|
||||||
push eax;
|
|
||||||
push pc;
|
|
||||||
push pb;
|
|
||||||
push pa;
|
|
||||||
mov ecx, pThis;
|
|
||||||
call [func];
|
|
||||||
pop eax;
|
|
||||||
pop ecx;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
template <class RetType, class PTypeA, class PTypeB, class PTypeC>
|
|
||||||
inline RetType VCall3(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb, PTypeC pc)
|
|
||||||
{
|
|
||||||
void **vtbl=*(void ***)pThis;
|
|
||||||
void *func=vtbl[ventry];
|
|
||||||
RetType _ret;
|
|
||||||
_asm {
|
|
||||||
push ecx;
|
|
||||||
push eax;
|
|
||||||
push pc;
|
|
||||||
push pb;
|
|
||||||
push pa;
|
|
||||||
mov ecx, pThis;
|
|
||||||
call [func];
|
|
||||||
mov _ret, eax;
|
|
||||||
pop eax;
|
|
||||||
pop ecx;
|
|
||||||
};
|
|
||||||
return _ret;
|
|
||||||
};
|
|
||||||
template <class PTypeA, class PTypeB>
|
|
||||||
inline void VoidVCall2(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb)
|
|
||||||
{
|
|
||||||
void **vtbl=*(void ***)pThis;
|
|
||||||
void *func=vtbl[ventry];
|
|
||||||
_asm {
|
|
||||||
push ecx;
|
|
||||||
push eax;
|
|
||||||
push pb;
|
|
||||||
push pa;
|
|
||||||
mov ecx, pThis;
|
|
||||||
call [func];
|
|
||||||
pop eax;
|
|
||||||
pop ecx;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
template <class RetType, class PTypeA, class PTypeB>
|
|
||||||
inline RetType VCall2(void *pThis, int ventry, int size, PTypeA pa, PTypeB pb)
|
|
||||||
{
|
|
||||||
void **vtbl=*(void ***)pThis;
|
|
||||||
void *func=vtbl[ventry];
|
|
||||||
RetType _ret;
|
|
||||||
_asm {
|
|
||||||
push ecx;
|
|
||||||
push eax;
|
|
||||||
push pb;
|
|
||||||
push pa;
|
|
||||||
mov ecx, pThis;
|
|
||||||
call [func];
|
|
||||||
mov _ret, eax;
|
|
||||||
pop eax;
|
|
||||||
pop ecx;
|
|
||||||
};
|
|
||||||
return _ret;
|
|
||||||
};
|
|
||||||
template <class PTypeA>
|
|
||||||
inline void VoidVCall1(void *pThis, int ventry, int size, PTypeA pa)
|
|
||||||
{
|
|
||||||
void **vtbl=*(void ***)pThis;
|
|
||||||
|
|
||||||
void *func=vtbl[ventry];
|
|
||||||
|
|
||||||
_asm {
|
|
||||||
push ecx;
|
|
||||||
push eax;
|
|
||||||
push pa;
|
|
||||||
mov ecx, pThis;
|
|
||||||
call [func];
|
|
||||||
pop eax;
|
|
||||||
pop ecx;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
template <class RetType, class PTypeA>
|
|
||||||
inline RetType VCall1(void *pThis, int ventry, int size, PTypeA pa)
|
|
||||||
{
|
|
||||||
void **vtbl=*(void ***)pThis;
|
|
||||||
|
|
||||||
void *func=vtbl[ventry];
|
|
||||||
|
|
||||||
RetType _ret;
|
|
||||||
_asm {
|
|
||||||
push ecx;
|
|
||||||
push eax;
|
|
||||||
push pa;
|
|
||||||
mov ecx, pThis;
|
|
||||||
call [func];
|
|
||||||
mov _ret, eax;
|
|
||||||
pop eax;
|
|
||||||
pop ecx;
|
|
||||||
};
|
|
||||||
|
|
||||||
return _ret;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void VoidVCall0(void *pThis, int ventry, int size)
|
|
||||||
{
|
|
||||||
void **vtbl=*(void ***)pThis;
|
|
||||||
|
|
||||||
void *func=vtbl[ventry];
|
|
||||||
|
|
||||||
_asm {
|
|
||||||
push ecx;
|
|
||||||
push eax;
|
|
||||||
mov ecx, pThis;
|
|
||||||
call [func];
|
|
||||||
pop eax;
|
|
||||||
pop ecx;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
template <class RetType>
|
|
||||||
inline RetType VCall0(void *pThis, int ventry, int size)
|
|
||||||
{
|
|
||||||
void **vtbl=*(void ***)pThis;
|
|
||||||
|
|
||||||
void *func=vtbl[ventry];
|
|
||||||
|
|
||||||
RetType _ret;
|
|
||||||
_asm {
|
|
||||||
push ecx;
|
|
||||||
push eax;
|
|
||||||
mov ecx, pThis;
|
|
||||||
call [func];
|
|
||||||
mov _ret, eax;
|
|
||||||
pop eax;
|
|
||||||
pop ecx;
|
|
||||||
};
|
|
||||||
|
|
||||||
return _ret;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //VFUNC_MSVC_H
|
|
||||||
#endif // _WIN32
|
|
@ -1,51 +0,0 @@
|
|||||||
|
|
||||||
/**
|
|
||||||
* These are the functions called by the trampolines
|
|
||||||
* I explicitly declare them as cdecl so I know exactly
|
|
||||||
* how to work the stack in the trampoline.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
static cell AMX_NATIVE_CALL register_takedamage(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
};
|
|
||||||
static cell AMX_NATIVE_CALL register_use(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int funcid;
|
|
||||||
char *function=MF_GetAmxString(amx,params[2],0,NULL);
|
|
||||||
if (MF_AmxFindPublic(amx,function,&funcid)!=AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
MF_LogError(amx,AMX_ERR_NATIVE,"Can not find function \"%s\"",function);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
// Get the classname
|
|
||||||
char *classname=MF_GetAmxString(amx,params[1],0,NULL);
|
|
||||||
|
|
||||||
edict_t *Entity=CREATE_ENTITY();
|
|
||||||
|
|
||||||
CALL_GAME_ENTITY(PLID,classname,&Entity->v);
|
|
||||||
|
|
||||||
if (Entity->pvPrivateData)
|
|
||||||
{
|
|
||||||
VTableUse::Hook(&VTMan,EdictToVTable(Entity),amx,funcid);
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
REMOVE_ENTITY(Entity);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
static AMX_NATIVE_INFO tdhooks[] = {
|
|
||||||
{ "register_takedamage", register_takedamage },
|
|
||||||
{ "register_use", register_use },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
void VTH_Natives()
|
|
||||||
{
|
|
||||||
MF_AddNatives(tdhooks);
|
|
||||||
};
|
|
||||||
|
|
||||||
*/
|
|
Loading…
Reference in New Issue
Block a user