This commit is contained in:
TheLuda 2008-10-14 00:29:20 +02:00
parent d767495d5b
commit 800ee76535
3322 changed files with 903437 additions and 0 deletions

View file

@ -0,0 +1,81 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#include "AuthCrypt.h"
#include "Hmac.h"
AuthCrypt::AuthCrypt()
{
_initialized = false;
}
void AuthCrypt::Init()
{
_send_i = _send_j = _recv_i = _recv_j = 0;
_initialized = true;
}
void AuthCrypt::DecryptRecv(uint8 *data, size_t len)
{
if (!_initialized) return;
if (len < CRYPTED_RECV_LEN) return;
for (size_t t = 0; t < CRYPTED_RECV_LEN; t++)
{
_recv_i %= _key.size();
uint8 x = (data[t] - _recv_j) ^ _key[_recv_i];
++_recv_i;
_recv_j = data[t];
data[t] = x;
}
}
void AuthCrypt::EncryptSend(uint8 *data, size_t len)
{
if (!_initialized) return;
if (len < CRYPTED_SEND_LEN) return;
for (size_t t = 0; t < CRYPTED_SEND_LEN; t++)
{
_send_i %= _key.size();
uint8 x = (data[t] ^ _key[_send_i]) + _send_j;
++_send_i;
data[t] = _send_j = x;
}
}
void AuthCrypt::SetKey(BigNumber *bn)
{
uint8 *key = new uint8[SHA_DIGEST_LENGTH];
GenerateKey(key, bn);
_key.resize(SHA_DIGEST_LENGTH);
std::copy(key, key + SHA_DIGEST_LENGTH, _key.begin());
delete key;
}
AuthCrypt::~AuthCrypt()
{
}
void AuthCrypt::GenerateKey(uint8 *key, BigNumber *bn)
{
HmacHash hash;
hash.UpdateBigNumber(bn);
hash.Finalize();
memcpy(key, hash.GetDigest(), SHA_DIGEST_LENGTH);
}

View file

@ -0,0 +1,52 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef _AUTHCRYPT_H
#define _AUTHCRYPT_H
#include <Common.h>
#include <vector>
class BigNumber;
class AuthCrypt
{
public:
AuthCrypt();
~AuthCrypt();
const static size_t CRYPTED_SEND_LEN = 4;
const static size_t CRYPTED_RECV_LEN = 6;
void Init();
void SetKey(BigNumber *);
void DecryptRecv(uint8 *, size_t);
void EncryptSend(uint8 *, size_t);
bool IsInitialized() { return _initialized; }
static void GenerateKey(uint8 *, BigNumber *);
private:
std::vector<uint8> _key;
uint8 _send_i, _send_j, _recv_i, _recv_j;
bool _initialized;
};
#endif

View file

@ -0,0 +1,207 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#include "Auth/BigNumber.h"
#include <openssl/bn.h>
#include <algorithm>
BigNumber::BigNumber()
{
_bn = BN_new();
_array = NULL;
}
BigNumber::BigNumber(const BigNumber &bn)
{
_bn = BN_dup(bn._bn);
_array = NULL;
}
BigNumber::BigNumber(uint32 val)
{
_bn = BN_new();
BN_set_word(_bn, val);
_array = NULL;
}
BigNumber::~BigNumber()
{
BN_free(_bn);
if(_array) delete[] _array;
}
void BigNumber::SetDword(uint32 val)
{
BN_set_word(_bn, val);
}
void BigNumber::SetQword(uint64 val)
{
BN_add_word(_bn, (uint32)(val >> 32));
BN_lshift(_bn, _bn, 32);
BN_add_word(_bn, (uint32)(val & 0xFFFFFFFF));
}
void BigNumber::SetBinary(const uint8 *bytes, int len)
{
uint8 t[1000];
for (int i = 0; i < len; i++) t[i] = bytes[len - 1 - i];
BN_bin2bn(t, len, _bn);
}
void BigNumber::SetHexStr(const char *str)
{
BN_hex2bn(&_bn, str);
}
void BigNumber::SetRand(int numbits)
{
BN_rand(_bn, numbits, 0, 1);
}
BigNumber BigNumber::operator=(const BigNumber &bn)
{
BN_copy(_bn, bn._bn);
return *this;
}
BigNumber BigNumber::operator+=(const BigNumber &bn)
{
BN_add(_bn, _bn, bn._bn);
return *this;
}
BigNumber BigNumber::operator-=(const BigNumber &bn)
{
BN_sub(_bn, _bn, bn._bn);
return *this;
}
BigNumber BigNumber::operator*=(const BigNumber &bn)
{
BN_CTX *bnctx;
bnctx = BN_CTX_new();
BN_mul(_bn, _bn, bn._bn, bnctx);
BN_CTX_free(bnctx);
return *this;
}
BigNumber BigNumber::operator/=(const BigNumber &bn)
{
BN_CTX *bnctx;
bnctx = BN_CTX_new();
BN_div(_bn, NULL, _bn, bn._bn, bnctx);
BN_CTX_free(bnctx);
return *this;
}
BigNumber BigNumber::operator%=(const BigNumber &bn)
{
BN_CTX *bnctx;
bnctx = BN_CTX_new();
BN_mod(_bn, _bn, bn._bn, bnctx);
BN_CTX_free(bnctx);
return *this;
}
BigNumber BigNumber::Exp(const BigNumber &bn)
{
BigNumber ret;
BN_CTX *bnctx;
bnctx = BN_CTX_new();
BN_exp(ret._bn, _bn, bn._bn, bnctx);
BN_CTX_free(bnctx);
return ret;
}
BigNumber BigNumber::ModExp(const BigNumber &bn1, const BigNumber &bn2)
{
BigNumber ret;
BN_CTX *bnctx;
bnctx = BN_CTX_new();
BN_mod_exp(ret._bn, _bn, bn1._bn, bn2._bn, bnctx);
BN_CTX_free(bnctx);
return ret;
}
int BigNumber::GetNumBytes(void)
{
return BN_num_bytes(_bn);
}
uint32 BigNumber::AsDword()
{
return (uint32)BN_get_word(_bn);
}
uint8 *BigNumber::AsByteArray(int minSize)
{
int length = (minSize >= GetNumBytes()) ? minSize : GetNumBytes();
if (_array)
{
delete[] _array;
_array = NULL;
}
_array = new uint8[length];
// If we need more bytes than length of BigNumber set the rest to 0
if (length > GetNumBytes())
memset((void*)_array, 0, length);
BN_bn2bin(_bn, (unsigned char *)_array);
std::reverse(_array, _array + length);
return _array;
}
ByteBuffer BigNumber::AsByteBuffer()
{
ByteBuffer ret(GetNumBytes());
ret.append(AsByteArray(), GetNumBytes());
return ret;
}
std::vector<uint8> BigNumber::AsByteVector()
{
std::vector<uint8> ret;
ret.resize(GetNumBytes());
memcpy(&ret[0], AsByteArray(), GetNumBytes());
return ret;
}
const char *BigNumber::AsHexStr()
{
return BN_bn2hex(_bn);
}
const char *BigNumber::AsDecStr()
{
return BN_bn2dec(_bn);
}

View file

@ -0,0 +1,94 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef _AUTH_BIGNUMBER_H
#define _AUTH_BIGNUMBER_H
#include "Common.h"
#include "ByteBuffer.h"
struct bignum_st;
class BigNumber
{
public:
BigNumber();
BigNumber(const BigNumber &bn);
BigNumber(uint32);
~BigNumber();
void SetDword(uint32);
void SetQword(uint64);
void SetBinary(const uint8 *bytes, int len);
void SetHexStr(const char *str);
void SetRand(int numbits);
BigNumber operator=(const BigNumber &bn);
BigNumber operator+=(const BigNumber &bn);
BigNumber operator+(const BigNumber &bn)
{
BigNumber t(*this);
return t += bn;
}
BigNumber operator-=(const BigNumber &bn);
BigNumber operator-(const BigNumber &bn)
{
BigNumber t(*this);
return t -= bn;
}
BigNumber operator*=(const BigNumber &bn);
BigNumber operator*(const BigNumber &bn)
{
BigNumber t(*this);
return t *= bn;
}
BigNumber operator/=(const BigNumber &bn);
BigNumber operator/(const BigNumber &bn)
{
BigNumber t(*this);
return t /= bn;
}
BigNumber operator%=(const BigNumber &bn);
BigNumber operator%(const BigNumber &bn)
{
BigNumber t(*this);
return t %= bn;
}
BigNumber ModExp(const BigNumber &bn1, const BigNumber &bn2);
BigNumber Exp(const BigNumber &);
int GetNumBytes(void);
struct bignum_st *BN() { return _bn; }
uint32 AsDword();
uint8* AsByteArray(int minSize = 0);
ByteBuffer AsByteBuffer();
std::vector<uint8> AsByteVector();
const char *AsHexStr();
const char *AsDecStr();
private:
struct bignum_st *_bn;
uint8 *_array;
};
#endif

56
src/shared/Auth/Hmac.cpp Normal file
View file

@ -0,0 +1,56 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#include "Auth/Hmac.h"
#include "BigNumber.h"
HmacHash::HmacHash()
{
uint8 temp[SEED_KEY_SIZE] = { 0x38, 0xA7, 0x83, 0x15, 0xF8, 0x92, 0x25, 0x30, 0x71, 0x98, 0x67, 0xB1, 0x8C, 0x4, 0xE2, 0xAA };
memcpy(&m_key, &temp, SEED_KEY_SIZE);
HMAC_CTX_init(&m_ctx);
HMAC_Init_ex(&m_ctx, &m_key, SEED_KEY_SIZE, EVP_sha1(), NULL);
}
HmacHash::~HmacHash()
{
memset(&m_key, 0x00, SEED_KEY_SIZE);
HMAC_CTX_cleanup(&m_ctx);
}
void HmacHash::UpdateBigNumber(BigNumber *bn)
{
UpdateData(bn->AsByteArray(), bn->GetNumBytes());
}
void HmacHash::UpdateData(const uint8 *data, int length)
{
HMAC_Update(&m_ctx, data, length);
}
void HmacHash::Initialize()
{
HMAC_Init_ex(&m_ctx, &m_key, SEED_KEY_SIZE, EVP_sha1(), NULL);
}
void HmacHash::Finalize()
{
uint32 length = 0;
HMAC_Final(&m_ctx, m_digest, &length);
ASSERT(length == SHA_DIGEST_LENGTH)
}

46
src/shared/Auth/Hmac.h Normal file
View file

@ -0,0 +1,46 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef _AUTH_HMAC_H
#define _AUTH_HMAC_H
#include "Common.h"
#include <openssl/hmac.h>
#include <openssl/sha.h>
class BigNumber;
#define SEED_KEY_SIZE 16
class HmacHash
{
public:
HmacHash();
~HmacHash();
void UpdateBigNumber(BigNumber *bn);
void UpdateData(const uint8 *data, int length);
void Initialize();
void Finalize();
uint8 *GetDigest() { return m_digest; };
int GetLength() { return SHA_DIGEST_LENGTH; };
private:
HMAC_CTX m_ctx;
uint8 m_key[SEED_KEY_SIZE];
uint8 m_digest[SHA_DIGEST_LENGTH];
};
#endif

View file

@ -0,0 +1,39 @@
# Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
#
# 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
## Process this file with automake to produce Makefile.in
## Sub-directories to parse
## CPP flags for includes, defines, etc.
AM_CPPFLAGS = $(MANGOS_INCLUDES) -I$(top_builddir)/src/shared -I$(srcdir) -I$(srcdir)/../../../dep/include -I$(srcdir)/../../framework -I$(srcdir)/../../shared -I$(srcdir)/../../../dep/include/g3dlite
## Build MaNGOS shared library and its parts as convenience library.
# All libraries will be convenience libraries. Might be changed to shared
# later.
noinst_LIBRARIES = libmangosauth.a
libmangosauth_a_SOURCES = \
AuthCrypt.cpp \
AuthCrypt.h \
BigNumber.cpp \
BigNumber.h \
Hmac.cpp \
Hmac.h \
Sha1.cpp \
Sha1.h \
md5.c \
md5.h

65
src/shared/Auth/Sha1.cpp Normal file
View file

@ -0,0 +1,65 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#include "Auth/Sha1.h"
#include <stdarg.h>
Sha1Hash::Sha1Hash()
{
SHA1_Init(&mC);
}
Sha1Hash::~Sha1Hash()
{
SHA1_Init(&mC);
}
void Sha1Hash::UpdateData(const uint8 *dta, int len)
{
SHA1_Update(&mC, dta, len);
}
void Sha1Hash::UpdateData(const std::string &str)
{
UpdateData((uint8 const*)str.c_str(), str.length());
}
void Sha1Hash::UpdateBigNumbers(BigNumber *bn0, ...)
{
va_list v;
BigNumber *bn;
va_start(v, bn0);
bn = bn0;
while (bn)
{
UpdateData(bn->AsByteArray(), bn->GetNumBytes());
bn = va_arg(v, BigNumber *);
}
va_end(v);
}
void Sha1Hash::Initialize()
{
SHA1_Init(&mC);
}
void Sha1Hash::Finalize(void)
{
SHA1_Final(mDigest, &mC);
}

51
src/shared/Auth/Sha1.h Normal file
View file

@ -0,0 +1,51 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef _AUTH_SHA1_H
#define _AUTH_SHA1_H
#include "Common.h"
#include <openssl/sha.h>
#include <openssl/crypto.h>
#include "Auth/BigNumber.h"
class Sha1Hash
{
public:
Sha1Hash();
~Sha1Hash();
void UpdateFinalizeBigNumbers(BigNumber *bn0, ...);
void UpdateBigNumbers(BigNumber *bn0, ...);
void UpdateData(const uint8 *dta, int len);
void UpdateData(const std::string &str);
void Initialize();
void Finalize();
uint8 *GetDigest(void) { return mDigest; };
int GetLength(void) { return SHA_DIGEST_LENGTH; };
BigNumber GetBigNumber();
private:
SHA_CTX mC;
uint8 mDigest[SHA_DIGEST_LENGTH];
};
#endif

385
src/shared/Auth/md5.c Normal file
View file

@ -0,0 +1,385 @@
/*
Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
L. Peter Deutsch
ghost@aladdin.com
*/
/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
/*
Independent implementation of MD5 (RFC 1321).
This code implements the MD5 Algorithm defined in RFC 1321, whose
text is available at
http://www.ietf.org/rfc/rfc1321.txt
The code is derived from the text of the RFC, including the test suite
(section A.5) but excluding the rest of Appendix A. It does not include
any code or documentation that is identified in the RFC as being
copyrighted.
The original and principal author of md5.c is L. Peter Deutsch
<ghost@aladdin.com>. Other authors are noted in the change history
that follows (in reverse chronological order):
2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
either statically or dynamically; added missing #include <string.h>
in library.
2002-03-11 lpd Corrected argument list for main(), and added int return
type, in test program and T value program.
2002-02-21 lpd Added missing #include <stdio.h> in test program.
2000-07-03 lpd Patched to eliminate warnings about "constant is
unsigned in ANSI C, signed in traditional"; made test program
self-checking.
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
1999-05-03 lpd Original version.
*/
#include "md5.h"
#include <string.h>
#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
#ifdef ARCH_IS_BIG_ENDIAN
# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
#else
# define BYTE_ORDER 0
#endif
#define T_MASK ((md5_word_t)~0)
#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
#define T3 0x242070db
#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
#define T6 0x4787c62a
#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
#define T9 0x698098d8
#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
#define T13 0x6b901122
#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
#define T16 0x49b40821
#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
#define T19 0x265e5a51
#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
#define T22 0x02441453
#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
#define T25 0x21e1cde6
#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
#define T28 0x455a14ed
#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
#define T31 0x676f02d9
#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
#define T35 0x6d9d6122
#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
#define T38 0x4bdecfa9
#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
#define T41 0x289b7ec6
#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
#define T44 0x04881d05
#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
#define T47 0x1fa27cf8
#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
#define T50 0x432aff97
#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
#define T53 0x655b59c3
#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
#define T57 0x6fa87e4f
#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
#define T60 0x4e0811a1
#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
#define T63 0x2ad7d2bb
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
static void
md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
{
md5_word_t
a = pms->abcd[0], b = pms->abcd[1],
c = pms->abcd[2], d = pms->abcd[3];
md5_word_t t;
#if BYTE_ORDER > 0
/* Define storage only for big-endian CPUs. */
md5_word_t X[16];
#else
/* Define storage for little-endian or both types of CPUs. */
md5_word_t xbuf[16];
const md5_word_t *X;
#endif
{
#if BYTE_ORDER == 0
/*
* Determine dynamically whether this is a big-endian or
* little-endian machine, since we can use a more efficient
* algorithm on the latter.
*/
static const int w = 1;
if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
#endif
#if BYTE_ORDER <= 0 /* little-endian */
{
/*
* On little-endian machines, we can process properly aligned
* data without copying it.
*/
if (!((data - (const md5_byte_t *)0) & 3))
{
/* data are properly aligned */
X = (const md5_word_t *)data;
}
else
{
/* not aligned */
memcpy(xbuf, data, 64);
X = xbuf;
}
}
#endif
#if BYTE_ORDER == 0
else /* dynamic big-endian */
#endif
#if BYTE_ORDER >= 0 /* big-endian */
{
/*
* On big-endian machines, we must arrange the bytes in the
* right order.
*/
const md5_byte_t *xp = data;
int i;
# if BYTE_ORDER == 0
X = xbuf; /* (dynamic only) */
# else
# define xbuf X /* (static only) */
# endif
for (i = 0; i < 16; ++i, xp += 4)
xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
}
#endif
}
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
/* Round 1. */
/* Let [abcd k s i] denote the operation
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + F(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 0, 7, T1);
SET(d, a, b, c, 1, 12, T2);
SET(c, d, a, b, 2, 17, T3);
SET(b, c, d, a, 3, 22, T4);
SET(a, b, c, d, 4, 7, T5);
SET(d, a, b, c, 5, 12, T6);
SET(c, d, a, b, 6, 17, T7);
SET(b, c, d, a, 7, 22, T8);
SET(a, b, c, d, 8, 7, T9);
SET(d, a, b, c, 9, 12, T10);
SET(c, d, a, b, 10, 17, T11);
SET(b, c, d, a, 11, 22, T12);
SET(a, b, c, d, 12, 7, T13);
SET(d, a, b, c, 13, 12, T14);
SET(c, d, a, b, 14, 17, T15);
SET(b, c, d, a, 15, 22, T16);
#undef SET
/* Round 2. */
/* Let [abcd k s i] denote the operation
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + G(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 1, 5, T17);
SET(d, a, b, c, 6, 9, T18);
SET(c, d, a, b, 11, 14, T19);
SET(b, c, d, a, 0, 20, T20);
SET(a, b, c, d, 5, 5, T21);
SET(d, a, b, c, 10, 9, T22);
SET(c, d, a, b, 15, 14, T23);
SET(b, c, d, a, 4, 20, T24);
SET(a, b, c, d, 9, 5, T25);
SET(d, a, b, c, 14, 9, T26);
SET(c, d, a, b, 3, 14, T27);
SET(b, c, d, a, 8, 20, T28);
SET(a, b, c, d, 13, 5, T29);
SET(d, a, b, c, 2, 9, T30);
SET(c, d, a, b, 7, 14, T31);
SET(b, c, d, a, 12, 20, T32);
#undef SET
/* Round 3. */
/* Let [abcd k s t] denote the operation
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define SET(a, b, c, d, k, s, Ti)\
t = a + H(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 5, 4, T33);
SET(d, a, b, c, 8, 11, T34);
SET(c, d, a, b, 11, 16, T35);
SET(b, c, d, a, 14, 23, T36);
SET(a, b, c, d, 1, 4, T37);
SET(d, a, b, c, 4, 11, T38);
SET(c, d, a, b, 7, 16, T39);
SET(b, c, d, a, 10, 23, T40);
SET(a, b, c, d, 13, 4, T41);
SET(d, a, b, c, 0, 11, T42);
SET(c, d, a, b, 3, 16, T43);
SET(b, c, d, a, 6, 23, T44);
SET(a, b, c, d, 9, 4, T45);
SET(d, a, b, c, 12, 11, T46);
SET(c, d, a, b, 15, 16, T47);
SET(b, c, d, a, 2, 23, T48);
#undef SET
/* Round 4. */
/* Let [abcd k s t] denote the operation
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + I(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 0, 6, T49);
SET(d, a, b, c, 7, 10, T50);
SET(c, d, a, b, 14, 15, T51);
SET(b, c, d, a, 5, 21, T52);
SET(a, b, c, d, 12, 6, T53);
SET(d, a, b, c, 3, 10, T54);
SET(c, d, a, b, 10, 15, T55);
SET(b, c, d, a, 1, 21, T56);
SET(a, b, c, d, 8, 6, T57);
SET(d, a, b, c, 15, 10, T58);
SET(c, d, a, b, 6, 15, T59);
SET(b, c, d, a, 13, 21, T60);
SET(a, b, c, d, 4, 6, T61);
SET(d, a, b, c, 11, 10, T62);
SET(c, d, a, b, 2, 15, T63);
SET(b, c, d, a, 9, 21, T64);
#undef SET
/* Then perform the following additions. (That is increment each
of the four registers by the value it had before this block
was started.) */
pms->abcd[0] += a;
pms->abcd[1] += b;
pms->abcd[2] += c;
pms->abcd[3] += d;
}
void
md5_init(md5_state_t *pms)
{
pms->count[0] = pms->count[1] = 0;
pms->abcd[0] = 0x67452301;
pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
pms->abcd[3] = 0x10325476;
}
void
md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
{
const md5_byte_t *p = data;
int left = nbytes;
int offset = (pms->count[0] >> 3) & 63;
md5_word_t nbits = (md5_word_t)(nbytes << 3);
if (nbytes <= 0)
return;
/* Update the message length. */
pms->count[1] += nbytes >> 29;
pms->count[0] += nbits;
if (pms->count[0] < nbits)
++pms->count[1];
/* Process an initial partial block. */
if (offset)
{
int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
memcpy(pms->buf + offset, p, copy);
if (offset + copy < 64)
return;
p += copy;
left -= copy;
md5_process(pms, pms->buf);
}
/* Process full blocks. */
for (; left >= 64; p += 64, left -= 64)
md5_process(pms, p);
/* Process a final partial block. */
if (left)
memcpy(pms->buf, p, left);
}
void
md5_finish(md5_state_t *pms, md5_byte_t digest[16])
{
static const md5_byte_t pad[64] =
{
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
md5_byte_t data[8];
int i;
/* Save the length before padding. */
for (i = 0; i < 8; ++i)
data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
/* Pad to 56 bytes mod 64. */
md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
/* Append the length. */
md5_append(pms, data, 8);
for (i = 0; i < 16; ++i)
digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
}

91
src/shared/Auth/md5.h Normal file
View file

@ -0,0 +1,91 @@
/*
Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
L. Peter Deutsch
ghost@aladdin.com
*/
/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
/*
Independent implementation of MD5 (RFC 1321).
This code implements the MD5 Algorithm defined in RFC 1321, whose
text is available at
http://www.ietf.org/rfc/rfc1321.txt
The code is derived from the text of the RFC, including the test suite
(section A.5) but excluding the rest of Appendix A. It does not include
any code or documentation that is identified in the RFC as being
copyrighted.
The original and principal author of md5.h is L. Peter Deutsch
<ghost@aladdin.com>. Other authors are noted in the change history
that follows (in reverse chronological order):
2002-04-13 lpd Removed support for non-ANSI compilers; removed
references to Ghostscript; clarified derivation from RFC 1321;
now handles byte order either statically or dynamically.
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
added conditionalization for C++ compilation from Martin
Purschke <purschke@bnl.gov>.
1999-05-03 lpd Original version.
*/
#ifndef md5_INCLUDED
# define md5_INCLUDED
/*
* This package supports both compile-time and run-time determination of CPU
* byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
* compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
* defined as non-zero, the code will be compiled to run only on big-endian
* CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
* run on either big- or little-endian CPUs, but will run slightly less
* efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
*/
typedef unsigned char md5_byte_t; /* 8-bit byte */
typedef unsigned int md5_word_t; /* 32-bit word */
/* Define the state of the MD5 Algorithm. */
typedef struct md5_state_s
{
md5_word_t count[2]; /* message length in bits, lsw first */
md5_word_t abcd[4]; /* digest buffer */
md5_byte_t buf[64]; /* accumulate block */
} md5_state_t;
#ifdef __cplusplus
extern "C"
{
#endif
/* Initialize the algorithm. */
void md5_init(md5_state_t *pms);
/* Append a string to the message. */
void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
/* Finish the message and return the digest. */
void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
#ifdef __cplusplus
} /* end extern "C" */
#endif
#endif /* md5_INCLUDED */

67
src/shared/Base.cpp Normal file
View file

@ -0,0 +1,67 @@
/*
Base class interface
Copyright (C) 1998,1999 by Andrew Zabolotny
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Base.h"
Base::~Base ()
{
}
/**
* Decrement object's reference count; as soon as the last reference
* to the object is removed, it is destroyed.
*/
void Base::DecRef ()
{
if (!--RefCount)
delete this;
}
/**
* Object initialization. The initial reference count is set to one;
* this means if you call DecRef() immediately after creating the object,
* it will be destroyed.
*/
Base::Base ()
{
RefCount = 1;
}
/**
* Increment reference count.
* Every time when you copy a pointer to a object and store it for
* later use you MUST call IncRef() on it; this will allow to keep
* objects as long as they are referenced by some entity.
*/
void Base::IncRef ()
{
++RefCount;
}
/**
* Query number of references to this object.
* I would rather prefer to have the reference counter strictly private,
* but sometimes, mostly for debugging, such a function can help.
*/
int Base::GetRefCount ()
{
return RefCount;
}

54
src/shared/Base.h Normal file
View file

@ -0,0 +1,54 @@
/*
Base class interface
Copyright (C) 1998,1999 by Andrew Zabolotny
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __BASE_H__
#define __BASE_H__
#include "Common.h"
/**
* This class is intended to be a base class for every other class.
* It defines the basic interface available for any object.
*/
class Base
{
private:
/// Object reference count
int RefCount;
protected:
/**
* Destroy this object. Destructor is virtual, because class contains
* virtual methods; also it is private because it is never intended
* to be called directly; use DecRef() instead: when reference counter
* reaches zero, the object will be destroyed.
*/
virtual ~Base ();
public:
Base ();
void IncRef ();
void DecRef ();
int GetRefCount ();
};
#endif // __BASE_H__

479
src/shared/ByteBuffer.h Normal file
View file

@ -0,0 +1,479 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef _BYTEBUFFER_H
#define _BYTEBUFFER_H
#include "Common.h"
#include "Errors.h"
#include "Log.h"
#include "Utilities/ByteConverter.h"
class ByteBuffer
{
public:
const static size_t DEFAULT_SIZE = 0x1000;
// constructor
ByteBuffer(): _rpos(0), _wpos(0)
{
_storage.reserve(DEFAULT_SIZE);
}
// constructor
ByteBuffer(size_t res): _rpos(0), _wpos(0)
{
_storage.reserve(res);
}
// copy constructor
ByteBuffer(const ByteBuffer &buf): _rpos(buf._rpos), _wpos(buf._wpos), _storage(buf._storage) { }
void clear()
{
_storage.clear();
_rpos = _wpos = 0;
}
template <typename T> void append(T value)
{
EndianConvert(value);
append((uint8 *)&value, sizeof(value));
}
template <typename T> void put(size_t pos,T value)
{
EndianConvert(value);
put(pos,(uint8 *)&value,sizeof(value));
}
ByteBuffer &operator<<(uint8 value)
{
append<uint8>(value);
return *this;
}
ByteBuffer &operator<<(uint16 value)
{
append<uint16>(value);
return *this;
}
ByteBuffer &operator<<(uint32 value)
{
append<uint32>(value);
return *this;
}
ByteBuffer &operator<<(uint64 value)
{
append<uint64>(value);
return *this;
}
// signed as in 2e complement
ByteBuffer &operator<<(int8 value)
{
append<int8>(value);
return *this;
}
ByteBuffer &operator<<(int16 value)
{
append<int16>(value);
return *this;
}
ByteBuffer &operator<<(int32 value)
{
append<int32>(value);
return *this;
}
ByteBuffer &operator<<(int64 value)
{
append<int64>(value);
return *this;
}
// floating points
ByteBuffer &operator<<(float value)
{
append<float>(value);
return *this;
}
ByteBuffer &operator<<(double value)
{
append<double>(value);
return *this;
}
ByteBuffer &operator<<(const std::string &value)
{
append((uint8 const *)value.c_str(), value.length());
append((uint8)0);
return *this;
}
ByteBuffer &operator<<(const char *str)
{
append((uint8 const *)str, str ? strlen(str) : 0);
append((uint8)0);
return *this;
}
ByteBuffer &operator>>(bool &value)
{
value = read<char>() > 0 ? true : false;
return *this;
}
ByteBuffer &operator>>(uint8 &value)
{
value = read<uint8>();
return *this;
}
ByteBuffer &operator>>(uint16 &value)
{
value = read<uint16>();
return *this;
}
ByteBuffer &operator>>(uint32 &value)
{
value = read<uint32>();
return *this;
}
ByteBuffer &operator>>(uint64 &value)
{
value = read<uint64>();
return *this;
}
//signed as in 2e complement
ByteBuffer &operator>>(int8 &value)
{
value = read<int8>();
return *this;
}
ByteBuffer &operator>>(int16 &value)
{
value = read<int16>();
return *this;
}
ByteBuffer &operator>>(int32 &value)
{
value = read<int32>();
return *this;
}
ByteBuffer &operator>>(int64 &value)
{
value = read<int64>();
return *this;
}
ByteBuffer &operator>>(float &value)
{
value = read<float>();
return *this;
}
ByteBuffer &operator>>(double &value)
{
value = read<double>();
return *this;
}
ByteBuffer &operator>>(std::string& value)
{
value.clear();
while (rpos() < size()) // prevent crash at wrong string format in packet
{
char c=read<char>();
if (c==0)
break;
value+=c;
}
return *this;
}
uint8 operator[](size_t pos) const
{
return read<uint8>(pos);
}
size_t rpos() const { return _rpos; }
size_t rpos(size_t rpos_)
{
_rpos = rpos_;
return _rpos;
};
size_t wpos() const { return _wpos; }
size_t wpos(size_t wpos_)
{
_wpos = wpos_;
return _wpos;
}
template <typename T> T read()
{
T r=read<T>(_rpos);
_rpos += sizeof(T);
return r;
};
template <typename T> T read(size_t pos) const
{
ASSERT(pos + sizeof(T) <= size() || PrintPosError(false,pos,sizeof(T)));
T val = *((T const*)&_storage[pos]);
EndianConvert(val);
return val;
}
void read(uint8 *dest, size_t len)
{
ASSERT(_rpos + len <= size() || PrintPosError(false,_rpos,len));
memcpy(dest, &_storage[_rpos], len);
_rpos += len;
}
const uint8 *contents() const { return &_storage[0]; }
size_t size() const { return _storage.size(); }
bool empty() const { return _storage.empty(); }
void resize(size_t newsize)
{
_storage.resize(newsize);
_rpos = 0;
_wpos = size();
};
void reserve(size_t ressize)
{
if (ressize > size()) _storage.reserve(ressize);
};
void append(const std::string& str)
{
append((uint8 const*)str.c_str(),str.size() + 1);
}
void append(const char *src, size_t cnt)
{
return append((const uint8 *)src, cnt);
}
template<class T>
void append(const T *src, size_t cnt)
{
return append((const uint8 *)src, cnt*sizeof(T));
}
void append(const uint8 *src, size_t cnt)
{
if (!cnt) return;
ASSERT(size() < 10000000);
if (_storage.size() < _wpos + cnt)
_storage.resize(_wpos + cnt);
memcpy(&_storage[_wpos], src, cnt);
_wpos += cnt;
}
void append(const ByteBuffer& buffer)
{
if(buffer.size()) append(buffer.contents(),buffer.size());
}
void appendPackGUID(uint64 guid)
{
size_t mask_position = wpos();
*this << uint8(0);
for(uint8 i = 0; i < 8; i++)
{
if(guid & 0xFF)
{
_storage[mask_position] |= uint8(1<<i);
*this << uint8(guid & 0xFF);
}
guid >>= 8;
}
}
void put(size_t pos, const uint8 *src, size_t cnt)
{
ASSERT(pos + cnt <= size() || PrintPosError(true,pos,cnt));
memcpy(&_storage[pos], src, cnt);
}
void print_storage() const
{
if(!sLog.IsOutDebug()) // optimize disabled debug output
return;
sLog.outDebug("STORAGE_SIZE: %u", size() );
for(uint32 i = 0; i < size(); i++)
sLog.outDebugInLine("%u - ", read<uint8>(i) );
sLog.outDebug(" ");
}
void textlike() const
{
if(!sLog.IsOutDebug()) // optimize disabled debug output
return;
sLog.outDebug("STORAGE_SIZE: %u", size() );
for(uint32 i = 0; i < size(); i++)
sLog.outDebugInLine("%c", read<uint8>(i) );
sLog.outDebug(" ");
}
void hexlike() const
{
if(!sLog.IsOutDebug()) // optimize disabled debug output
return;
uint32 j = 1, k = 1;
sLog.outDebug("STORAGE_SIZE: %u", size() );
if(sLog.IsIncludeTime())
sLog.outDebugInLine(" ");
for(uint32 i = 0; i < size(); i++)
{
if ((i == (j*8)) && ((i != (k*16))))
{
if (read<uint8>(i) < 0x0F)
{
sLog.outDebugInLine("| 0%X ", read<uint8>(i) );
}
else
{
sLog.outDebugInLine("| %X ", read<uint8>(i) );
}
++j;
}
else if (i == (k*16))
{
if (read<uint8>(i) < 0x0F)
{
sLog.outDebugInLine("\n");
if(sLog.IsIncludeTime())
sLog.outDebugInLine(" ");
sLog.outDebugInLine("0%X ", read<uint8>(i) );
}
else
{
sLog.outDebugInLine("\n");
if(sLog.IsIncludeTime())
sLog.outDebugInLine(" ");
sLog.outDebugInLine("%X ", read<uint8>(i) );
}
++k;
++j;
}
else
{
if (read<uint8>(i) < 0x0F)
{
sLog.outDebugInLine("0%X ", read<uint8>(i) );
}
else
{
sLog.outDebugInLine("%X ", read<uint8>(i) );
}
}
}
sLog.outDebugInLine("\n");
}
protected:
bool PrintPosError(bool add, size_t pos, size_t esize) const
{
sLog.outError("ERROR: Attempt %s in ByteBuffer (pos: %u size: %u) value with size: %u",(add ? "put" : "get"),pos, size(), esize);
// assert must fail after function call
return false;
}
size_t _rpos, _wpos;
std::vector<uint8> _storage;
};
template <typename T> ByteBuffer &operator<<(ByteBuffer &b, std::vector<T> v)
{
b << (uint32)v.size();
for (typename std::vector<T>::iterator i = v.begin(); i != v.end(); i++)
{
b << *i;
}
return b;
}
template <typename T> ByteBuffer &operator>>(ByteBuffer &b, std::vector<T> &v)
{
uint32 vsize;
b >> vsize;
v.clear();
while(vsize--)
{
T t;
b >> t;
v.push_back(t);
}
return b;
}
template <typename T> ByteBuffer &operator<<(ByteBuffer &b, std::list<T> v)
{
b << (uint32)v.size();
for (typename std::list<T>::iterator i = v.begin(); i != v.end(); i++)
{
b << *i;
}
return b;
}
template <typename T> ByteBuffer &operator>>(ByteBuffer &b, std::list<T> &v)
{
uint32 vsize;
b >> vsize;
v.clear();
while(vsize--)
{
T t;
b >> t;
v.push_back(t);
}
return b;
}
template <typename K, typename V> ByteBuffer &operator<<(ByteBuffer &b, std::map<K, V> &m)
{
b << (uint32)m.size();
for (typename std::map<K, V>::iterator i = m.begin(); i != m.end(); i++)
{
b << i->first << i->second;
}
return b;
}
template <typename K, typename V> ByteBuffer &operator>>(ByteBuffer &b, std::map<K, V> &m)
{
uint32 msize;
b >> msize;
m.clear();
while(msize--)
{
K k;
V v;
b >> k >> v;
m.insert(make_pair(k, v));
}
return b;
}
#endif

40
src/shared/Common.cpp Normal file
View file

@ -0,0 +1,40 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#include "Common.h"
char const* localeNames[MAX_LOCALE] = {
"enUS",
"koKR",
"frFR",
"deDE",
"zhCN",
"zhTW",
"esES",
"esMX",
"ruRU"
};
LocaleConstant GetLocaleByName(std::string name)
{
for(uint32 i = 0; i < MAX_LOCALE; ++i)
if(name==localeNames[i])
return LocaleConstant(i);
return LOCALE_enUS; // including enGB case
}

203
src/shared/Common.h Normal file
View file

@ -0,0 +1,203 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef MANGOSSERVER_COMMON_H
#define MANGOSSERVER_COMMON_H
// config.h needs to be included 1st
#ifdef HAVE_CONFIG_H
#ifdef PACKAGE
#undef PACKAGE
#endif //PACKAGE
#ifdef PACKAGE_BUGREPORT
#undef PACKAGE_BUGREPORT
#endif //PACKAGE_BUGREPORT
#ifdef PACKAGE_NAME
#undef PACKAGE_NAME
#endif //PACKAGE_NAME
#ifdef PACKAGE_STRING
#undef PACKAGE_STRING
#endif //PACKAGE_STRING
#ifdef PACKAGE_TARNAME
#undef PACKAGE_TARNAME
#endif //PACKAGE_TARNAME
#ifdef PACKAGE_VERSION
#undef PACKAGE_VERSION
#endif //PACKAGE_VERSION
#ifdef VERSION
#undef VERSION
#endif //VERSION
# include "config.h"
#undef PACKAGE
#undef PACKAGE_BUGREPORT
#undef PACKAGE_NAME
#undef PACKAGE_STRING
#undef PACKAGE_TARNAME
#undef PACKAGE_VERSION
#undef VERSION
#endif //HAVE_CONFIG_H
#include "Platform/Define.h"
#if COMPILER == COMPILER_MICROSOFT
#pragma warning(disable:4996)
#ifndef __SHOW_STUPID_WARNINGS__
#pragma warning(disable:4244)
#pragma warning(disable:4267)
#pragma warning(disable:4800)
#pragma warning(disable:4018)
#pragma warning(disable:4311)
#pragma warning(disable:4305)
#pragma warning(disable:4005)
#endif // __SHOW_STUPID_WARNINGS__
#endif // __GNUC__
// must be the first thing to include for it to work
#include "MemoryLeaks.h"
#include "Utilities/HashMap.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <errno.h>
#include <signal.h>
#if PLATFORM == PLATFORM_WINDOWS
#define STRCASECMP stricmp
#else
#define STRCASECMP strcasecmp
#endif
#include <set>
#include <list>
#include <string>
#include <map>
#include <queue>
#include <sstream>
#include <algorithm>
#include <zthread/FastMutex.h>
#include <zthread/LockedQueue.h>
#include <zthread/Runnable.h>
#include <zthread/Thread.h>
#if PLATFORM == PLATFORM_WINDOWS
# define FD_SETSIZE 4096
# include <ace/config-all.h>
// XP winver - needed to compile with standard leak check in MemoryLeaks.h
// uncomment later if needed
//#define _WIN32_WINNT 0x0501
# include <ws2tcpip.h>
//#undef WIN32_WINNT
#else
# include <sys/types.h>
# include <sys/ioctl.h>
# include <sys/socket.h>
# include <netinet/in.h>
# include <unistd.h>
# include <netdb.h>
#endif
#if COMPILER == COMPILER_MICROSOFT
#include <float.h>
#define I64FMT "%016I64X"
#define I64FMTD "%I64u"
#define SI64FMTD "%I64d"
#define snprintf _snprintf
#define atoll __atoi64
#define vsnprintf _vsnprintf
#define strdup _strdup
#define finite(X) _finite(X)
#else
#define stricmp strcasecmp
#define strnicmp strncasecmp
#define I64FMT "%016llX"
#define I64FMTD "%llu"
#define SI64FMTD "%lld"
#endif
inline float finiteAlways(float f) { return finite(f) ? f : 0.0f; }
#define atol(a) strtoul( a, NULL, 10)
#define STRINGIZE(a) #a
enum TimeConstants
{
MINUTE = 60,
HOUR = MINUTE*60,
DAY = HOUR*24,
MONTH = DAY*30
};
enum AccountTypes
{
SEC_PLAYER = 0,
SEC_MODERATOR = 1,
SEC_GAMEMASTER = 2,
SEC_ADMINISTRATOR = 3
};
enum LocaleConstant
{
LOCALE_enUS = 0,
LOCALE_koKR = 1,
LOCALE_frFR = 2,
LOCALE_deDE = 3,
LOCALE_zhCN = 4,
LOCALE_zhTW = 5,
LOCALE_esES = 6,
LOCALE_esMX = 7,
LOCALE_ruRU = 8
};
#define MAX_LOCALE 9
extern char const* localeNames[MAX_LOCALE];
LocaleConstant GetLocaleByName(std::string name);
// we always use stdlibc++ std::max/std::min, undefine some not C++ standard defines (Win API and some pother platforms)
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#endif

View file

@ -0,0 +1,174 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#include "ConfigEnv.h"
#include "Policies/SingletonImp.h"
INSTANTIATE_SINGLETON_1(Config);
Config::Config() : mIgnoreCase(true), mConf(NULL)
{
}
Config::~Config()
{
delete mConf;
}
bool Config::SetSource(const char *file, bool ignorecase)
{
mIgnoreCase = ignorecase;
mFilename = file;
return Reload();
}
bool Config::Reload()
{
delete mConf;
mConf = new DOTCONFDocument(mIgnoreCase ?
DOTCONFDocument::CASEINSENSETIVE :
DOTCONFDocument::CASESENSETIVE);
if (mConf->setContent(mFilename.c_str()) == -1)
{
delete mConf;
mConf = NULL;
return false;
}
return true;
}
bool Config::GetString(const char* name, std::string *value)
{
if(!mConf)
return false;
DOTCONFDocumentNode const *node = mConf->findNode(name);
if(!node || !node->getValue())
return false;
*value = node->getValue();
return true;
}
bool Config::GetString(const char* name, char const **value)
{
if(!mConf)
return false;
DOTCONFDocumentNode const *node = mConf->findNode(name);
if(!node || !node->getValue())
return false;
*value = node->getValue();
return true;
}
std::string Config::GetStringDefault(const char* name, const char* def)
{
if(!mConf)
return std::string(def);
DOTCONFDocumentNode const *node = mConf->findNode(name);
if(!node || !node->getValue())
return std::string(def);
return std::string(node->getValue());
}
bool Config::GetBool(const char* name, bool *value)
{
if(!mConf)
return false;
DOTCONFDocumentNode const *node = mConf->findNode(name);
if(!node || !node->getValue())
return false;
const char* str = node->getValue();
if(strcmp(str, "true") == 0 || strcmp(str, "TRUE") == 0 ||
strcmp(str, "yes") == 0 || strcmp(str, "YES") == 0 ||
strcmp(str, "1") == 0)
{
*value = true;
}
else
*value = false;
return true;
}
bool Config::GetBoolDefault(const char* name, const bool def)
{
bool val;
return GetBool(name, &val) ? val : def;
}
bool Config::GetInt(const char* name, int *value)
{
if(!mConf)
return false;
DOTCONFDocumentNode const *node = mConf->findNode(name);
if(!node || !node->getValue())
return false;
*value = atoi(node->getValue());
return true;
}
bool Config::GetFloat(const char* name, float *value)
{
if(!mConf)
return false;
DOTCONFDocumentNode const *node = mConf->findNode(name);
if(!node || !node->getValue())
return false;
*value = atof(node->getValue());
return true;
}
int Config::GetIntDefault(const char* name, const int def)
{
int val;
return GetInt(name, &val) ? val : def;
}
float Config::GetFloatDefault(const char* name, const float def)
{
float val;
return (GetFloat(name, &val) ? val : def);
}

View file

@ -0,0 +1,58 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef CONFIG_H
#define CONFIG_H
#include <Policies/Singleton.h>
#include "Platform/Define.h"
class DOTCONFDocument;
class MANGOS_DLL_SPEC Config
{
public:
Config();
~Config();
bool SetSource(const char *file, bool ignorecase = true);
bool Reload();
bool GetString(const char* name, std::string *value);
bool GetString(const char* name, char const **value);
std::string GetStringDefault(const char* name, const char* def);
bool GetBool(const char* name, bool *value);
bool GetBoolDefault(const char* name, const bool def = false);
bool GetInt(const char* name, int *value);
int GetIntDefault(const char* name, const int def);
bool GetFloat(const char* name, float *value);
float GetFloatDefault(const char* name, const float def);
std::string GetFilename() const { return mFilename; }
private:
std::string mFilename;
bool mIgnoreCase;
DOTCONFDocument *mConf;
};
#define sConfig MaNGOS::Singleton<Config>::Instance()
#endif

View file

@ -0,0 +1,28 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#if !defined(CONFIGENVIRONMENT_H)
#define CONFIGENVIRONMENT_H
#include "Common.h"
#include "dotconfpp/dotconfpp.h"
#include "Config.h"
#include "Log.h"
#endif

View file

@ -0,0 +1,137 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="ConfigLibrary"
ProjectGUID="{C849D54F-32A6-4025-95BE-E64D1CF0686E}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="4"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories=""
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/ConfigLibrary.lib"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="4"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/ConfigLibrary.lib"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath=".\Config.cpp">
</File>
<File
RelativePath=".\dotconfpp\dotconfpp.cpp">
</File>
<File
RelativePath=".\dotconfpp\mempool.cpp">
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
<File
RelativePath=".\Config.h">
</File>
<File
RelativePath=".\ConfigEnv.h">
</File>
<File
RelativePath=".\dotconfpp\dotconfpp.h">
</File>
<File
RelativePath=".\dotconfpp\mempool.h">
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View file

@ -0,0 +1,40 @@
# Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
#
# 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
## Process this file with automake to produce Makefile.in
## Sub-directories to parse
## CPP flags for includes, defines, etc.
AM_CPPFLAGS = $(MANGOS_INCLUDES) -I$(top_builddir)/src/shared -I$(srcdir) -I$(srcdir)/../../../dep/include -I$(srcdir)/../../framework -I$(srcdir)/../../shared -I$(srcdir)/../../../dep/include/g3dlite
## Build MaNGOS shared library and its parts as convenience library.
# All libraries will be convenience libraries. Might be changed to shared
# later.
noinst_LIBRARIES = libmangosconfig.a
libmangosconfig_a_SOURCES = \
dotconfpp/dotconfpp.cpp \
dotconfpp/dotconfpp.h \
dotconfpp/mempool.cpp \
dotconfpp/mempool.h \
Config.cpp \
Config.h \
ConfigEnv.h
# VC++ project workspace for dotconfpp
EXTRA_DIST = \
ConfigLibrary.vcproj

View file

@ -0,0 +1,583 @@
#include "Common.h"
#include "dotconfpp.h"
#if !defined(R_OK)
#define R_OK 04
#endif
DOTCONFDocumentNode::DOTCONFDocumentNode():previousNode(NULL), nextNode(NULL), parentNode(NULL), childNode(NULL),
values(NULL), valuesCount(0),
name(NULL), lineNum(0), fileName(NULL), closed(true)
{
}
DOTCONFDocumentNode::~DOTCONFDocumentNode()
{
free(name);
if(values != NULL){
for(int i = 0 ; i < valuesCount; i++){
free(values[i]);
}
free(values);
}
}
void DOTCONFDocumentNode::pushValue(char * _value)
{
++valuesCount;
values = (char**)realloc(values, valuesCount*sizeof(char*));
values[valuesCount-1] = strdup(_value);
}
const char* DOTCONFDocumentNode::getValue(int index) const
{
if(index >= valuesCount){
return NULL;
}
return values[index];
}
DOTCONFDocument::DOTCONFDocument(DOTCONFDocument::CaseSensitive caseSensitivity):
mempool(NULL),
curParent(NULL), curPrev(NULL), curLine(0), file(NULL), fileName(NULL)
{
if(caseSensitivity == CASESENSETIVE){
cmp_func = strcmp;
} else {
cmp_func = strcasecmp;
}
mempool = new AsyncDNSMemPool(1024);
mempool->initialize();
}
DOTCONFDocument::~DOTCONFDocument()
{
for(std::list<DOTCONFDocumentNode*>::iterator i = nodeTree.begin(); i != nodeTree.end(); i++){
delete(*i);
}
for(std::list<char*>::iterator i = requiredOptions.begin(); i != requiredOptions.end(); i++){
free(*i);
}
for(std::list<char*>::iterator i = processedFiles.begin(); i != processedFiles.end(); i++){
free(*i);
}
free(fileName);
delete mempool;
}
int DOTCONFDocument::cleanupLine(char * line)
{
char * start = line;
char * bg = line;
bool multiline = false;
bool concat = false;
char * word = NULL;
if(!words.empty() && quoted)
concat = true;
while(*line){
if((*line == '#' || *line == ';') && !quoted){
*bg = 0;
if(strlen(start)){
if(concat){
word = (char*)mempool->alloc(strlen(words.back())+strlen(start)+1);
strcpy(word, words.back());
strcat(word, start);
words.pop_back();
concat = false;
} else {
word = mempool->strdup(start);
}
words.push_back(word);
}
break;
}
if(*line == '=' && !quoted){
*line = ' ';continue;
}
// Allowing \" in there causes problems with directory paths
// like "C:\MaNGOS\"
//if(*line == '\\' && (*(line+1) == '"' || *(line+1) == '\'')){
if(*line == '\\' && (*(line+1) == '\'')) {
*bg++ = *(line+1);
line+=2; continue;
}
if(*line == '\\' && *(line+1) == 'n'){
*bg++ = '\n';
line+=2; continue;
}
if(*line == '\\' && *(line+1) == 'r'){
*bg++ = '\r';
line+=2; continue;
}
if(*line == '\\' && (*(line+1) == '\n' || *(line+1) == '\r')){
*bg = 0;
if(strlen(start)){
if(concat){
word = (char*)mempool->alloc(strlen(words.back())+strlen(start)+1);
strcpy(word, words.back());
strcat(word, start);
words.pop_back();
concat = false;
} else {
word = mempool->strdup(start);
}
words.push_back(word);
}
multiline = true;
break;
}
if(*line == '"' || *line == '\''){
quoted = !quoted;
++line; continue;
}
if(isspace(*line) && !quoted){
*bg++ = 0;
if(strlen(start)){
if(concat){
word = (char*)mempool->alloc(strlen(words.back())+strlen(start)+1);
strcpy(word, words.back());
strcat(word, start);
words.pop_back();
concat = false;
} else {
word = mempool->strdup(start);
}
words.push_back(word);
}
start = bg;
while(isspace(*++line)) {}
continue;
}
*bg++ = *line++;
}
if(quoted && !multiline){
error(curLine, fileName, "unterminated quote");
return -1;
}
return multiline?1:0;
}
int DOTCONFDocument::parseLine()
{
char * word = NULL;
char * nodeName = NULL;
char * nodeValue = NULL;
DOTCONFDocumentNode * tagNode = NULL;
bool newNode = false;
for(std::list<char*>::iterator i = words.begin(); i != words.end(); i++) {
word = *i;
if(*word == '<'){
newNode = true;
}
if(newNode){
nodeValue = NULL;
nodeName = NULL;
newNode = false;
}
size_t wordLen = strlen(word);
if(word[wordLen-1] == '>'){
word[wordLen-1] = 0;
newNode = true;
}
if(nodeName == NULL){
nodeName = word;
bool closed = true;
if(*nodeName == '<'){
if(*(nodeName+1) != '/'){
++nodeName;
closed = false;
} else {
nodeName+=2;
std::list<DOTCONFDocumentNode*>::reverse_iterator itr=nodeTree.rbegin();
for(; itr!=nodeTree.rend(); ++itr){
if(!cmp_func(nodeName, (*itr)->name) && !(*itr)->closed){
(*itr)->closed = true;
curParent = (*itr)->parentNode;
curPrev = *itr;
break;
}
}
if(itr==nodeTree.rend()){
error(curLine, fileName, "not matched closing tag </%s>", nodeName);
return -1;
}
continue;
}
}
tagNode = new DOTCONFDocumentNode;
tagNode->name = strdup(nodeName);
tagNode->document = this;
tagNode->fileName = processedFiles.back();
tagNode->lineNum = curLine;
tagNode->closed = closed;
if(!nodeTree.empty()){
DOTCONFDocumentNode * prev = nodeTree.back();
if(prev->closed){
curPrev->nextNode = tagNode;
tagNode->previousNode = curPrev;
tagNode->parentNode = curParent;
} else {
prev->childNode = tagNode;
tagNode->parentNode = prev;
curParent = prev;
}
}
nodeTree.push_back(tagNode);
curPrev = tagNode;
} else {
nodeValue = word;
tagNode->pushValue(nodeValue);
}
}
return 0;
}
int DOTCONFDocument::parseFile(DOTCONFDocumentNode * _parent)
{
char str[512];
int ret = 0;
curLine = 0;
curParent = _parent;
quoted = false;
size_t slen = 0;
while(fgets(str, 511, file)){
++curLine;
slen = strlen(str);
if( slen >= 510 ){
error(curLine, fileName, "warning: line too long");
}
if(str[slen-1] != '\n'){
str[slen] = '\n';
str[slen+1] = 0;
}
if((ret = cleanupLine(str)) == -1){
break;
}
if(ret == 0){
if(!words.empty()){
ret = parseLine();
mempool->free();
words.clear();
if(ret == -1){
break;
}
}
}
}
return ret;
}
int DOTCONFDocument::checkConfig(const std::list<DOTCONFDocumentNode*>::iterator & from)
{
int ret = 0;
DOTCONFDocumentNode * tagNode = NULL;
int vi = 0;
for(std::list<DOTCONFDocumentNode*>::iterator i = from; i != nodeTree.end(); i++){
tagNode = *i;
if(!tagNode->closed){
error(tagNode->lineNum, tagNode->fileName, "unclosed tag %s", tagNode->name);
ret = -1;
break;
}
vi = 0;
while( vi < tagNode->valuesCount ){
if(strstr(tagNode->values[vi], "${") && strchr(tagNode->values[vi], '}') ){
ret = macroSubstitute(tagNode, vi );
mempool->free();
if(ret == -1){
break;
}
}
++vi;
}
if(ret == -1){
break;
}
}
return ret;
}
int DOTCONFDocument::setContent(const char * _fileName)
{
int ret = 0;
char realpathBuf[PATH_MAX];
if(realpath(_fileName, realpathBuf) == NULL){
error(0, NULL, "realpath(%s) failed: %s", _fileName, strerror(errno));
return -1;
}
fileName = strdup(realpathBuf);
processedFiles.push_back(strdup(realpathBuf));
if(( file = fopen(fileName, "r")) == NULL){
error(0, NULL, "failed to open file '%s': %s", fileName, strerror(errno));
return -1;
}
ret = parseFile();
(void) fclose(file);
if(!ret){
if( (ret = checkConfig(nodeTree.begin())) == -1){
return -1;
}
std::list<DOTCONFDocumentNode*>::iterator from;
DOTCONFDocumentNode * tagNode = NULL;
int vi = 0;
for(std::list<DOTCONFDocumentNode*>::iterator i = nodeTree.begin(); i!=nodeTree.end(); i++){
tagNode = *i;
if(!cmp_func("DOTCONFPPIncludeFile", tagNode->name)){
vi = 0;
while( vi < tagNode->valuesCount ){
if(access(tagNode->values[vi], R_OK) == -1){
error(tagNode->lineNum, tagNode->fileName, "%s: %s", tagNode->values[vi], strerror(errno));
return -1;
}
if(realpath(tagNode->values[vi], realpathBuf) == NULL){
error(tagNode->lineNum, tagNode->fileName, "realpath(%s) failed: %s", tagNode->values[vi], strerror(errno));
return -1;
}
bool processed = false;
for(std::list<char*>::const_iterator itInode = processedFiles.begin(); itInode != processedFiles.end(); itInode++){
if(!strcmp(*itInode, realpathBuf)){
processed = true;
break;
}
}
if(processed){
break;
}
processedFiles.push_back(strdup(realpathBuf));
file = fopen(tagNode->values[vi], "r");
if(file == NULL){
error(tagNode->lineNum, fileName, "failed to open file '%s': %s", tagNode->values[vi], strerror(errno));
return -1;
}
fileName = strdup(realpathBuf);
from = nodeTree.end(); --from;
ret = parseFile();
(void) fclose(file);
if(ret == -1)
return -1;
if(checkConfig(++from) == -1){
return -1;
}
++vi;
}
}
}
if(!requiredOptions.empty())
ret = checkRequiredOptions();
}
return ret;
}
int DOTCONFDocument::checkRequiredOptions()
{
for(std::list<char*>::const_iterator ci = requiredOptions.begin(); ci != requiredOptions.end(); ci++){
bool matched = false;
for(std::list<DOTCONFDocumentNode*>::iterator i = nodeTree.begin(); i!=nodeTree.end(); i++){
if(!cmp_func((*i)->name, *ci)){
matched = true;
break;
}
}
if(!matched){
error(0, NULL, "required option '%s' not specified", *ci);
return -1;
}
}
return 0;
}
void DOTCONFDocument::error(int lineNum, const char * fileName_, const char * fmt, ...)
{
va_list args;
va_start(args, fmt);
size_t len = (lineNum!=0?strlen(fileName_):0) + strlen(fmt) + 50;
char * buf = (char*)mempool->alloc(len);
if(lineNum)
(void) snprintf(buf, len, "DOTCONF++: file '%s', line %d: %s\n", fileName_, lineNum, fmt);
else
(void) snprintf(buf, len, "DOTCONF++: %s\n", fmt);
(void) vfprintf(stderr, buf, args);
va_end(args);
}
char * DOTCONFDocument::getSubstitution(char * macro, int lineNum)
{
char * buf = NULL;
char * variable = macro+2;
char * endBr = strchr(macro, '}');
if(!endBr){
error(lineNum, fileName, "unterminated '{'");
return NULL;
}
*endBr = 0;
char * defaultValue = strchr(variable, ':');
if(defaultValue){
*defaultValue++ = 0;
if(*defaultValue != '-'){
error(lineNum, fileName, "incorrect macro substitution syntax");
return NULL;
}
++defaultValue;
if(*defaultValue == '"' || *defaultValue == '\''){
++defaultValue;
defaultValue[strlen(defaultValue)-1] = 0;
}
} else {
defaultValue = NULL;
}
char * subs = getenv(variable);
if( subs ){
buf = mempool->strdup(subs);
} else {
std::list<DOTCONFDocumentNode*>::iterator i = nodeTree.begin();
DOTCONFDocumentNode * tagNode = NULL;
for(; i!=nodeTree.end(); i++){
tagNode = *i;
if(!cmp_func(tagNode->name, variable)){
if(tagNode->valuesCount != 0){
buf = mempool->strdup(tagNode->values[0]);
break;
}
}
}
if( i == nodeTree.end() ){
if( defaultValue ){
buf = mempool->strdup(defaultValue);
} else {
error(lineNum, fileName, "substitution not found and default value not given");
return NULL;
}
}
}
return buf;
}
int DOTCONFDocument::macroSubstitute(DOTCONFDocumentNode * tagNode, int valueIndex)
{
int ret = 0;
char * macro = tagNode->values[valueIndex];
size_t valueLen = strlen(tagNode->values[valueIndex])+1;
char * value = (char*)mempool->alloc(valueLen);
char * v = value;
char * subs = NULL;
while(*macro){
if(*macro == '$' && *(macro+1) == '{'){
char * m = strchr(macro, '}');
subs = getSubstitution(macro, tagNode->lineNum);
if(subs == NULL){
ret = -1;
break;
}
macro = m + 1;
*v = 0;
v = (char*)mempool->alloc(strlen(value)+strlen(subs)+valueLen);
strcpy(v, value);
value = strcat(v, subs);
v = value + strlen(value);
continue;
}
*v++ = *macro++;
}
*v = 0;
free(tagNode->values[valueIndex]);
tagNode->values[valueIndex] = strdup(value);
return ret;
}
const DOTCONFDocumentNode * DOTCONFDocument::getFirstNode() const
{
if ( !nodeTree.empty() ) {
return *nodeTree.begin();
} else {
return NULL;
}
}
const DOTCONFDocumentNode * DOTCONFDocument::findNode(const char * nodeName, const DOTCONFDocumentNode * parentNode, const DOTCONFDocumentNode * startNode) const
{
std::list<DOTCONFDocumentNode*>::const_iterator i = nodeTree.begin();
if(startNode == NULL)
startNode = parentNode;
if(startNode != NULL){
while( i != nodeTree.end() && (*i) != startNode ){
++i;
}
if( i != nodeTree.end() ) ++i;
}
for(; i!=nodeTree.end(); i++){
if((*i)->parentNode != parentNode){
continue;
}
if(!cmp_func(nodeName, (*i)->name)){
return *i;
}
}
return NULL;
}
void DOTCONFDocument::setRequiredOptionNames(const char ** requiredOptionNames)
{
while(*requiredOptionNames){
requiredOptions.push_back(strdup( *requiredOptionNames ));
++requiredOptionNames;
}
}

View file

@ -0,0 +1,110 @@
#ifndef DOTCONFPP_H
#define DOTCONFPP_H
#include <list>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef WIN32
#define PATH_MAX _MAX_PATH
#define snprintf _snprintf
#define strcasecmp stricmp
#define realpath(path,resolved_path) _fullpath(resolved_path, path, _MAX_PATH)
#include <io.h>
#else
#include <unistd.h>
#include <limits.h>
#include <stdint.h>
#include <strings.h>
#endif
#include "mempool.h"
class DOTCONFDocument;
class DOTCONFDocumentNode
{
friend class DOTCONFDocument;
private:
DOTCONFDocumentNode * previousNode;
DOTCONFDocumentNode * nextNode;
DOTCONFDocumentNode * parentNode;
DOTCONFDocumentNode * childNode;
char ** values;
int valuesCount;
char * name;
const DOTCONFDocument * document;
int lineNum;
char * fileName;
bool closed;
void pushValue(char * _value);
public:
DOTCONFDocumentNode();
~DOTCONFDocumentNode();
const char * getConfigurationFileName()const { return fileName; }
int getConfigurationLineNumber() const { return lineNum; }
const DOTCONFDocumentNode * getNextNode() const { return nextNode; }
const DOTCONFDocumentNode * getPreviuosNode() const { return previousNode; }
const DOTCONFDocumentNode * getParentNode() const { return parentNode; }
const DOTCONFDocumentNode * getChildNode() const { return childNode; }
const char* getValue(int index = 0) const;
const char * getName() const { return name; }
const DOTCONFDocument * getDocument() const { return document; }
};
class DOTCONFDocument
{
public:
enum CaseSensitive { CASESENSETIVE, CASEINSENSETIVE };
protected:
AsyncDNSMemPool * mempool;
private:
DOTCONFDocumentNode * curParent;
DOTCONFDocumentNode * curPrev;
int curLine;
bool quoted;
std::list<DOTCONFDocumentNode*> nodeTree;
std::list<char*> requiredOptions;
std::list<char*> processedFiles;
FILE * file;
char * fileName;
std::list<char*> words;
int (*cmp_func)(const char *, const char *);
int checkRequiredOptions();
int parseLine();
int parseFile(DOTCONFDocumentNode * _parent = NULL);
int checkConfig(const std::list<DOTCONFDocumentNode*>::iterator & from);
int cleanupLine(char * line);
char * getSubstitution(char * macro, int lineNum);
int macroSubstitute(DOTCONFDocumentNode * tagNode, int valueIndex);
protected:
virtual void error(int lineNum, const char * fileName, const char * fmt, ...) ATTR_PRINTF(4,5);
public:
DOTCONFDocument(CaseSensitive caseSensitivity = CASESENSETIVE);
virtual ~DOTCONFDocument();
int setContent(const char * _fileName);
void setRequiredOptionNames(const char ** requiredOptionNames);
const DOTCONFDocumentNode * getFirstNode() const;
const DOTCONFDocumentNode * findNode(const char * nodeName, const DOTCONFDocumentNode * parentNode = NULL, const DOTCONFDocumentNode * startNode = NULL) const;
};
#endif

View file

@ -0,0 +1,100 @@
#include "mempool.h"
AsyncDNSMemPool::PoolChunk::PoolChunk(size_t _size):
pool(NULL), pos(0), size(_size)
{
pool = ::malloc(size);
}
AsyncDNSMemPool::PoolChunk::~PoolChunk()
{
::free(pool);
}
AsyncDNSMemPool::AsyncDNSMemPool(size_t _defaultSize):
chunks(NULL), chunksCount(0), defaultSize(_defaultSize),
poolUsage(0), poolUsageCounter(0)
{
}
AsyncDNSMemPool::~AsyncDNSMemPool()
{
for(size_t i = 0; i<chunksCount; i++){
delete chunks[i];
}
::free(chunks);
}
int AsyncDNSMemPool::initialize()
{
chunksCount = 1;
chunks = (PoolChunk**)::malloc(sizeof(PoolChunk*));
if(chunks == NULL)
return -1;
chunks[chunksCount-1] = new PoolChunk(defaultSize);
return 0;
}
void AsyncDNSMemPool::addNewChunk(size_t size)
{
++chunksCount;
chunks = (PoolChunk**)::realloc(chunks, chunksCount*sizeof(PoolChunk*));
if(size <= defaultSize)
chunks[chunksCount-1] = new PoolChunk(defaultSize);
else
chunks[chunksCount-1] = new PoolChunk(size);
}
void * AsyncDNSMemPool::alloc(size_t size)
{
PoolChunk * chunk = NULL;
for(size_t i = 0; i<chunksCount; i++){
chunk = chunks[i];
if((chunk->size - chunk->pos) >= size){
chunk->pos += size;
return ((char*)chunk->pool) + chunk->pos - size;
}
}
addNewChunk(size);
chunks[chunksCount-1]->pos = size;
return chunks[chunksCount-1]->pool;
}
void AsyncDNSMemPool::free()
{
size_t pu = 0;
size_t psz = 0;
++poolUsageCounter;
for(size_t i = 0; i<chunksCount; i++){
pu += chunks[i]->pos;
psz += chunks[i]->size;
chunks[i]->pos = 0;
}
poolUsage=(poolUsage>pu)?poolUsage:pu;
if(poolUsageCounter >= 10 && chunksCount > 1){
psz -= chunks[chunksCount-1]->size;
if(poolUsage < psz){
--chunksCount;
delete chunks[chunksCount];
}
poolUsage = 0;
poolUsageCounter = 0;
}
}
void * AsyncDNSMemPool::calloc(size_t size)
{
return ::memset(this->alloc(size), 0, size);
}
char * AsyncDNSMemPool::strdup(const char *str)
{
return ::strcpy((char*)this->alloc(strlen(str)+1), str);
}

View file

@ -0,0 +1,46 @@
#ifndef ASYNC_DNS_MEMPOOL_H
#define ASYNC_DNS_MEMPOOL_H
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#undef free
#undef calloc
#undef strdup
class AsyncDNSMemPool
{
private:
struct PoolChunk {
void * pool;
size_t pos;
size_t size;
PoolChunk(size_t _size);
~PoolChunk();
};
PoolChunk ** chunks;
size_t chunksCount;
size_t defaultSize;
size_t poolUsage;
size_t poolUsageCounter;
void addNewChunk(size_t size);
public:
AsyncDNSMemPool(size_t _defaultSize = 4096);
virtual ~AsyncDNSMemPool();
int initialize();
void free();
void * alloc(size_t size);
void * calloc(size_t size);
char * strdup(const char *str);
};
#endif

View file

@ -0,0 +1,104 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef DBCENUMS_H
#define DBCENUMS_H
enum AreaTeams
{
AREATEAM_NONE = 0,
AREATEAM_ALLY = 2,
AREATEAM_HORDE = 4
};
enum AreaFlags
{
AREA_FLAG_SNOW = 0x00000001, // snow (only Dun Morogh, Naxxramas, Razorfen Downs and Winterspring)
AREA_FLAG_UNK1 = 0x00000002, // unknown, (only Naxxramas and Razorfen Downs)
AREA_FLAG_UNK2 = 0x00000004, // Only used on development map
AREA_FLAG_SLAVE_CAPITAL = 0x00000008, // slave capital city flag?
AREA_FLAG_UNK3 = 0x00000010, // unknown
AREA_FLAG_SLAVE_CAPITAL2 = 0x00000020, // slave capital city flag?
AREA_FLAG_UNK4 = 0x00000040, // many zones have this flag
AREA_FLAG_ARENA = 0x00000080, // arena, both instanced and world arenas
AREA_FLAG_CAPITAL = 0x00000100, // main capital city flag
AREA_FLAG_CITY = 0x00000200, // only for one zone named "City" (where it located?)
AREA_FLAG_OUTLAND = 0x00000400, // outland zones? (only Eye of the Storm not have this flag, but have 0x00004000 flag)
AREA_FLAG_SANCTUARY = 0x00000800, // sanctuary area (PvP disabled)
AREA_FLAG_NEED_FLY = 0x00001000, // only Netherwing Ledge, Socrethar's Seat, Tempest Keep, The Arcatraz, The Botanica, The Mechanar, Sorrow Wing Point, Dragonspine Ridge, Netherwing Mines, Dragonmaw Base Camp, Dragonmaw Skyway
AREA_FLAG_UNUSED1 = 0x00002000, // not used now (no area/zones with this flag set in 2.4.2)
AREA_FLAG_OUTLAND2 = 0x00004000, // outland zones? (only Circle of Blood Arena not have this flag, but have 0x00000400 flag)
AREA_FLAG_PVP = 0x00008000, // pvp objective area? (Death's Door also has this flag although it's no pvp object area)
AREA_FLAG_ARENA_INSTANCE = 0x00010000, // used by instanced arenas only
AREA_FLAG_UNUSED2 = 0x00020000, // not used now (no area/zones with this flag set in 2.4.2)
AREA_FLAG_UNK5 = 0x00040000, // just used for Amani Pass, Hatchet Hills
AREA_FLAG_LOWLEVEL = 0x00100000 // used for some starting areas with area_level <=15
};
enum FactionTemplateFlags
{
FACTION_TEMPLATE_FLAG_CONTESTED_GUARD = 0x00001000, // faction will attack players that were involved in PvP combats
};
enum FactionMasks
{
FACTION_MASK_PLAYER = 1, // any player
FACTION_MASK_ALLIANCE = 2, // player or creature from alliance team
FACTION_MASK_HORDE = 4, // player or creature from horde team
FACTION_MASK_MONSTER = 8 // aggressive creature from monster team
// if none flags set then non-aggressive creature
};
enum MapTypes
{
MAP_COMMON = 0,
MAP_INSTANCE = 1,
MAP_RAID = 2,
MAP_BATTLEGROUND = 3,
MAP_ARENA = 4
};
enum AbilytyLearnType
{
ABILITY_LEARNED_ON_GET_PROFESSION_SKILL = 1,
ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL = 2
};
enum ItemEnchantmentType
{
ITEM_ENCHANTMENT_TYPE_NONE = 0,
ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL = 1,
ITEM_ENCHANTMENT_TYPE_DAMAGE = 2,
ITEM_ENCHANTMENT_TYPE_EQUIP_SPELL = 3,
ITEM_ENCHANTMENT_TYPE_RESISTANCE = 4,
ITEM_ENCHANTMENT_TYPE_STAT = 5,
ITEM_ENCHANTMENT_TYPE_TOTEM = 6
};
enum TotemCategoryType
{
TOTEM_CATEGORY_TYPE_KNIFE = 1,
TOTEM_CATEGORY_TYPE_TOTEM = 2,
TOTEM_CATEGORY_TYPE_ROD = 3,
TOTEM_CATEGORY_TYPE_PICK = 21,
TOTEM_CATEGORY_TYPE_STONE = 22,
TOTEM_CATEGORY_TYPE_HAMMER = 23,
TOTEM_CATEGORY_TYPE_SPANNER = 24
};
#endif

View file

@ -0,0 +1,637 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#include "DBCStores.h"
//#include "DataStore.h"
#include "Policies/SingletonImp.h"
#include "Log.h"
#include "ProgressBar.h"
#include "DBCfmt.cpp"
#include <map>
typedef std::map<uint16,uint32> AreaFlagByAreaID;
typedef std::map<uint32,uint32> AreaFlagByMapID;
DBCStorage <AreaTableEntry> sAreaStore(AreaTableEntryfmt);
static AreaFlagByAreaID sAreaFlagByAreaID;
static AreaFlagByMapID sAreaFlagByMapID; // for instances without generated *.map files
DBCStorage <AreaTriggerEntry> sAreaTriggerStore(AreaTriggerEntryfmt);
DBCStorage <BankBagSlotPricesEntry> sBankBagSlotPricesStore(BankBagSlotPricesEntryfmt);
DBCStorage <BattlemasterListEntry> sBattlemasterListStore(BattlemasterListEntryfmt);
DBCStorage <CharTitlesEntry> sCharTitlesStore(CharTitlesEntryfmt);
DBCStorage <ChatChannelsEntry> sChatChannelsStore(ChatChannelsEntryfmt);
DBCStorage <ChrClassesEntry> sChrClassesStore(ChrClassesEntryfmt);
DBCStorage <ChrRacesEntry> sChrRacesStore(ChrRacesEntryfmt);
DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore(CreatureDisplayInfofmt);
DBCStorage <CreatureFamilyEntry> sCreatureFamilyStore(CreatureFamilyfmt);
DBCStorage <CreatureSpellDataEntry> sCreatureSpellDataStore(CreatureSpellDatafmt);
DBCStorage <DurabilityQualityEntry> sDurabilityQualityStore(DurabilityQualityfmt);
DBCStorage <DurabilityCostsEntry> sDurabilityCostsStore(DurabilityCostsfmt);
DBCStorage <EmotesTextEntry> sEmotesTextStore(EmoteEntryfmt);
typedef std::map<uint32,SimpleFactionsList> FactionTeamMap;
static FactionTeamMap sFactionTeamMap;
DBCStorage <FactionEntry> sFactionStore(FactionEntryfmt);
DBCStorage <FactionTemplateEntry> sFactionTemplateStore(FactionTemplateEntryfmt);
DBCStorage <GemPropertiesEntry> sGemPropertiesStore(GemPropertiesEntryfmt);
DBCStorage <GtCombatRatingsEntry> sGtCombatRatingsStore(GtCombatRatingsfmt);
DBCStorage <GtChanceToMeleeCritBaseEntry> sGtChanceToMeleeCritBaseStore(GtChanceToMeleeCritBasefmt);
DBCStorage <GtChanceToMeleeCritEntry> sGtChanceToMeleeCritStore(GtChanceToMeleeCritfmt);
DBCStorage <GtChanceToSpellCritBaseEntry> sGtChanceToSpellCritBaseStore(GtChanceToSpellCritBasefmt);
DBCStorage <GtChanceToSpellCritEntry> sGtChanceToSpellCritStore(GtChanceToSpellCritfmt);
DBCStorage <GtOCTRegenHPEntry> sGtOCTRegenHPStore(GtOCTRegenHPfmt);
//DBCStorage <GtOCTRegenMPEntry> sGtOCTRegenMPStore(GtOCTRegenMPfmt); -- not used currently
DBCStorage <GtRegenHPPerSptEntry> sGtRegenHPPerSptStore(GtRegenHPPerSptfmt);
DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore(GtRegenMPPerSptfmt);
DBCStorage <ItemEntry> sItemStore(Itemfmt);
//DBCStorage <ItemCondExtCostsEntry> sItemCondExtCostsStore(ItemCondExtCostsEntryfmt);
//DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore(ItemDisplayTemplateEntryfmt); -- not used currently
DBCStorage <ItemExtendedCostEntry> sItemExtendedCostStore(ItemExtendedCostEntryfmt);
DBCStorage <ItemRandomPropertiesEntry> sItemRandomPropertiesStore(ItemRandomPropertiesfmt);
DBCStorage <ItemRandomSuffixEntry> sItemRandomSuffixStore(ItemRandomSuffixfmt);
DBCStorage <ItemSetEntry> sItemSetStore(ItemSetEntryfmt);
DBCStorage <LockEntry> sLockStore(LockEntryfmt);
DBCStorage <MailTemplateEntry> sMailTemplateStore(MailTemplateEntryfmt);
DBCStorage <MapEntry> sMapStore(MapEntryfmt);
DBCStorage <QuestSortEntry> sQuestSortStore(QuestSortEntryfmt);
DBCStorage <RandomPropertiesPointsEntry> sRandomPropertiesPointsStore(RandomPropertiesPointsfmt);
DBCStorage <SkillLineEntry> sSkillLineStore(SkillLinefmt);
DBCStorage <SkillLineAbilityEntry> sSkillLineAbilityStore(SkillLineAbilityfmt);
DBCStorage <SoundEntriesEntry> sSoundEntriesStore(SoundEntriesfmt);
DBCStorage <SpellItemEnchantmentEntry> sSpellItemEnchantmentStore(SpellItemEnchantmentfmt);
DBCStorage <SpellItemEnchantmentConditionEntry> sSpellItemEnchantmentConditionStore(SpellItemEnchantmentConditionfmt);
DBCStorage <SpellEntry> sSpellStore(SpellEntryfmt);
SpellCategoryStore sSpellCategoryStore;
PetFamilySpellsStore sPetFamilySpellsStore;
DBCStorage <SpellCastTimesEntry> sSpellCastTimesStore(SpellCastTimefmt);
DBCStorage <SpellDurationEntry> sSpellDurationStore(SpellDurationfmt);
DBCStorage <SpellFocusObjectEntry> sSpellFocusObjectStore(SpellFocusObjectfmt);
DBCStorage <SpellRadiusEntry> sSpellRadiusStore(SpellRadiusfmt);
DBCStorage <SpellRangeEntry> sSpellRangeStore(SpellRangefmt);
DBCStorage <SpellShapeshiftEntry> sSpellShapeshiftStore(SpellShapeshiftfmt);
DBCStorage <StableSlotPricesEntry> sStableSlotPricesStore(StableSlotPricesfmt);
DBCStorage <TalentEntry> sTalentStore(TalentEntryfmt);
TalentSpellPosMap sTalentSpellPosMap;
DBCStorage <TalentTabEntry> sTalentTabStore(TalentTabEntryfmt);
// store absolute bit position for first rank for talent inspect
typedef std::map<uint32,uint32> TalentInspectMap;
static TalentInspectMap sTalentPosInInspect;
static TalentInspectMap sTalentTabSizeInInspect;
static uint32 sTalentTabPages[12/*MAX_CLASSES*/][3];
DBCStorage <TaxiNodesEntry> sTaxiNodesStore(TaxiNodesEntryfmt);
TaxiMask sTaxiNodesMask;
// DBC used only for initialization sTaxiPathSetBySource at startup.
TaxiPathSetBySource sTaxiPathSetBySource;
DBCStorage <TaxiPathEntry> sTaxiPathStore(TaxiPathEntryfmt);
// DBC used only for initialization sTaxiPathSetBySource at startup.
TaxiPathNodesByPath sTaxiPathNodesByPath;
static DBCStorage <TaxiPathNodeEntry> sTaxiPathNodeStore(TaxiPathNodeEntryfmt);
DBCStorage <TotemCategoryEntry> sTotemCategoryStore(TotemCategoryEntryfmt);
DBCStorage <WorldMapAreaEntry> sWorldMapAreaStore(WorldMapAreaEntryfmt);
DBCStorage <WorldSafeLocsEntry> sWorldSafeLocsStore(WorldSafeLocsEntryfmt);
typedef std::list<std::string> StoreProblemList;
static bool LoadDBC_assert_print(uint32 fsize,uint32 rsize, std::string filename)
{
sLog.outError("ERROR: Size of '%s' setted by format string (%u) not equal size of C++ structure (%u).",filename.c_str(),fsize,rsize);
// assert must fail after function call
return false;
}
template<class T>
inline void LoadDBC(uint32& availableDbcLocales,barGoLink& bar, StoreProblemList& errlist, DBCStorage<T>& storage, std::string dbc_path, std::string filename)
{
// compatibility format and C++ structure sizes
assert(DBCFile::GetFormatRecordSize(storage.GetFormat()) == sizeof(T) || LoadDBC_assert_print(DBCFile::GetFormatRecordSize(storage.GetFormat()),sizeof(T),filename));
std::string dbc_filename = dbc_path + filename;
if(storage.Load(dbc_filename.c_str()))
{
bar.step();
for(uint8 i = 0; i < MAX_LOCALE; ++i)
{
if(!(availableDbcLocales & (1 << i)))
continue;
std::string dbc_filename_loc = dbc_path + localeNames[i] + "/" + filename;
if(!storage.LoadStringsFrom(dbc_filename_loc.c_str()))
availableDbcLocales &= ~(1<<i); // mark as not available for speedup next checks
}
}
else
{
// sort problematic dbc to (1) non compatible and (2) non-existed
FILE * f=fopen(dbc_filename.c_str(),"rb");
if(f)
{
char buf[100];
snprintf(buf,100," (exist, but have %d fields instead %d) Wrong client version DBC file?",storage.GetFieldCount(),strlen(storage.GetFormat()));
errlist.push_back(dbc_filename + buf);
fclose(f);
}
else
errlist.push_back(dbc_filename);
}
}
void LoadDBCStores(std::string dataPath)
{
std::string dbcPath = dataPath+"dbc/";
const uint32 DBCFilesCount = 56;
barGoLink bar( DBCFilesCount );
StoreProblemList bad_dbc_files;
uint32 availableDbcLocales = 0xFFFFFFFF;
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sAreaStore, dbcPath,"AreaTable.dbc");
// must be after sAreaStore loading
for(uint32 i = 0; i < sAreaStore.GetNumRows(); ++i) // areaflag numbered from 0
{
if(AreaTableEntry const* area = sAreaStore.LookupEntry(i))
{
// fill AreaId->DBC records
sAreaFlagByAreaID.insert(AreaFlagByAreaID::value_type(uint16(area->ID),area->exploreFlag));
// fill MapId->DBC records ( skip sub zones and continents )
if(area->zone==0 && area->mapid != 0 && area->mapid != 1 && area->mapid != 530 )
sAreaFlagByMapID.insert(AreaFlagByMapID::value_type(area->mapid,area->exploreFlag));
}
}
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sAreaTriggerStore, dbcPath,"AreaTrigger.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sBankBagSlotPricesStore, dbcPath,"BankBagSlotPrices.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sBattlemasterListStore, dbcPath,"BattlemasterList.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCharTitlesStore, dbcPath,"CharTitles.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sChatChannelsStore, dbcPath,"ChatChannels.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sChrClassesStore, dbcPath,"ChrClasses.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sChrRacesStore, dbcPath,"ChrRaces.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCreatureDisplayInfoStore, dbcPath,"CreatureDisplayInfo.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCreatureFamilyStore, dbcPath,"CreatureFamily.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCreatureSpellDataStore, dbcPath,"CreatureSpellData.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sDurabilityCostsStore, dbcPath,"DurabilityCosts.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sDurabilityQualityStore, dbcPath,"DurabilityQuality.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sEmotesTextStore, dbcPath,"EmotesText.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sFactionStore, dbcPath,"Faction.dbc");
for (uint32 i=0;i<sFactionStore.GetNumRows(); ++i)
{
FactionEntry const * faction = sFactionStore.LookupEntry(i);
if (faction && faction->team)
{
SimpleFactionsList &flist = sFactionTeamMap[faction->team];
flist.push_back(i);
}
}
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sFactionTemplateStore, dbcPath,"FactionTemplate.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGemPropertiesStore, dbcPath,"GemProperties.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtCombatRatingsStore, dbcPath,"gtCombatRatings.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtChanceToMeleeCritBaseStore, dbcPath,"gtChanceToMeleeCritBase.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtChanceToMeleeCritStore, dbcPath,"gtChanceToMeleeCrit.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtChanceToSpellCritBaseStore, dbcPath,"gtChanceToSpellCritBase.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtChanceToSpellCritStore, dbcPath,"gtChanceToSpellCrit.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtOCTRegenHPStore, dbcPath,"gtOCTRegenHP.dbc");
//LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtOCTRegenMPStore, dbcPath,"gtOCTRegenMP.dbc"); -- not used currently
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtRegenHPPerSptStore, dbcPath,"gtRegenHPPerSpt.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtRegenMPPerSptStore, dbcPath,"gtRegenMPPerSpt.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemStore, dbcPath,"Item.dbc");
//LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemDisplayInfoStore, dbcPath,"ItemDisplayInfo.dbc"); -- not used currently
//LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemCondExtCostsStore, dbcPath,"ItemCondExtCosts.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemExtendedCostStore, dbcPath,"ItemExtendedCost.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemRandomPropertiesStore,dbcPath,"ItemRandomProperties.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemRandomSuffixStore, dbcPath,"ItemRandomSuffix.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemSetStore, dbcPath,"ItemSet.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sLockStore, dbcPath,"Lock.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sMailTemplateStore, dbcPath,"MailTemplate.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sMapStore, dbcPath,"Map.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sQuestSortStore, dbcPath,"QuestSort.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sRandomPropertiesPointsStore, dbcPath,"RandPropPoints.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSkillLineStore, dbcPath,"SkillLine.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSkillLineAbilityStore, dbcPath,"SkillLineAbility.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSoundEntriesStore, dbcPath,"SoundEntries.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellStore, dbcPath,"Spell.dbc");
for(uint32 i = 1; i < sSpellStore.GetNumRows(); ++i)
{
SpellEntry const * spell = sSpellStore.LookupEntry(i);
if(spell && spell->Category)
sSpellCategoryStore[spell->Category].insert(i);
// DBC not support uint64 fields but SpellEntry have SpellFamilyFlags mapped at 2 uint32 fields
// uint32 field already converted to bigendian if need, but must be swapped for correct uint64 bigendian view
#if MANGOS_ENDIAN == MANGOS_BIGENDIAN
std::swap(*((uint32*)(&spell->SpellFamilyFlags)),*(((uint32*)(&spell->SpellFamilyFlags))+1));
#endif
}
for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j)
{
SkillLineAbilityEntry const *skillLine = sSkillLineAbilityStore.LookupEntry(j);
if(!skillLine)
continue;
SpellEntry const* spellInfo = sSpellStore.LookupEntry(skillLine->spellId);
if(spellInfo && (spellInfo->Attributes & 0x1D0) == 0x1D0)
{
for (unsigned int i = 1; i < sCreatureFamilyStore.GetNumRows(); ++i)
{
CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(i);
if(!cFamily)
continue;
if(skillLine->skillId != cFamily->skillLine[0] && skillLine->skillId != cFamily->skillLine[1])
continue;
sPetFamilySpellsStore[i].insert(spellInfo->Id);
}
}
}
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellCastTimesStore, dbcPath,"SpellCastTimes.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellDurationStore, dbcPath,"SpellDuration.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellFocusObjectStore, dbcPath,"SpellFocusObject.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellItemEnchantmentStore,dbcPath,"SpellItemEnchantment.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellItemEnchantmentConditionStore,dbcPath,"SpellItemEnchantmentCondition.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellRadiusStore, dbcPath,"SpellRadius.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellRangeStore, dbcPath,"SpellRange.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellShapeshiftStore, dbcPath,"SpellShapeshiftForm.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sStableSlotPricesStore, dbcPath,"StableSlotPrices.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTalentStore, dbcPath,"Talent.dbc");
// create talent spells set
for (unsigned int i = 0; i < sTalentStore.GetNumRows(); ++i)
{
TalentEntry const *talentInfo = sTalentStore.LookupEntry(i);
if (!talentInfo) continue;
for (int j = 0; j < 5; j++)
if(talentInfo->RankID[j])
sTalentSpellPosMap[talentInfo->RankID[j]] = TalentSpellPos(i,j);
}
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTalentTabStore, dbcPath,"TalentTab.dbc");
// preper fast data access to bit pos of talent ranks for use at inspecting
{
// fill table by amount of talent ranks and fill sTalentTabBitSizeInInspect
// store in with (row,col,talent)->size key for correct sorting by (row,col)
typedef std::map<uint32,uint32> TalentBitSize;
TalentBitSize sTalentBitSize;
for(uint32 i = 1; i < sTalentStore.GetNumRows(); ++i)
{
TalentEntry const *talentInfo = sTalentStore.LookupEntry(i);
if (!talentInfo) continue;
TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry( talentInfo->TalentTab );
if(!talentTabInfo)
continue;
// find talent rank
uint32 curtalent_maxrank = 0;
for(uint32 k = 5; k > 0; --k)
{
if(talentInfo->RankID[k-1])
{
curtalent_maxrank = k;
break;
}
}
sTalentBitSize[(talentInfo->Row<<24) + (talentInfo->Col<<16)+talentInfo->TalentID] = curtalent_maxrank;
sTalentTabSizeInInspect[talentInfo->TalentTab] += curtalent_maxrank;
}
// now have all max ranks (and then bit amount used for store talent ranks in inspect)
for(uint32 talentTabId = 1; talentTabId < sTalentTabStore.GetNumRows(); ++talentTabId)
{
TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry( talentTabId );
if(!talentTabInfo)
continue;
// store class talent tab pages
uint32 cls = 1;
for(uint32 m=1;!(m & talentTabInfo->ClassMask) && cls < 12 /*MAX_CLASSES*/;m <<=1, ++cls) {}
sTalentTabPages[cls][talentTabInfo->tabpage]=talentTabId;
// add total amount bits for first rank starting from talent tab first talent rank pos.
uint32 pos = 0;
for(TalentBitSize::iterator itr = sTalentBitSize.begin(); itr != sTalentBitSize.end(); ++itr)
{
uint32 talentId = itr->first & 0xFFFF;
TalentEntry const *talentInfo = sTalentStore.LookupEntry( talentId );
if(!talentInfo)
continue;
if(talentInfo->TalentTab != talentTabId)
continue;
sTalentPosInInspect[talentId] = pos;
pos+= itr->second;
}
}
}
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTaxiNodesStore, dbcPath,"TaxiNodes.dbc");
// Initialize global taxinodes mask
memset(sTaxiNodesMask,0,sizeof(sTaxiNodesMask));
for(uint32 i = 1; i < sTaxiNodesStore.GetNumRows(); ++i)
{
if(sTaxiNodesStore.LookupEntry(i))
{
uint8 field = (uint8)((i - 1) / 32);
uint32 submask = 1<<((i-1)%32);
sTaxiNodesMask[field] |= submask;
}
}
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTaxiPathStore, dbcPath,"TaxiPath.dbc");
for(uint32 i = 1; i < sTaxiPathStore.GetNumRows(); ++i)
if(TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(i))
sTaxiPathSetBySource[entry->from][entry->to] = TaxiPathBySourceAndDestination(entry->ID,entry->price);
uint32 pathCount = sTaxiPathStore.GetNumRows();
//## TaxiPathNode.dbc ## Loaded only for initialization different structures
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTaxiPathNodeStore, dbcPath,"TaxiPathNode.dbc");
// Calculate path nodes count
std::vector<uint32> pathLength;
pathLength.resize(pathCount); // 0 and some other indexes not used
for(uint32 i = 1; i < sTaxiPathNodeStore.GetNumRows(); ++i)
if(TaxiPathNodeEntry const* entry = sTaxiPathNodeStore.LookupEntry(i))
++pathLength[entry->path];
// Set path length
sTaxiPathNodesByPath.resize(pathCount); // 0 and some other indexes not used
for(uint32 i = 1; i < sTaxiPathNodesByPath.size(); ++i)
sTaxiPathNodesByPath[i].resize(pathLength[i]);
// fill data
for(uint32 i = 1; i < sTaxiPathNodeStore.GetNumRows(); ++i)
if(TaxiPathNodeEntry const* entry = sTaxiPathNodeStore.LookupEntry(i))
sTaxiPathNodesByPath[entry->path][entry->index] = TaxiPathNode(entry->mapid,entry->x,entry->y,entry->z,entry->actionFlag,entry->delay);
sTaxiPathNodeStore.Clear();
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sTotemCategoryStore, dbcPath,"TotemCategory.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sWorldMapAreaStore, dbcPath,"WorldMapArea.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sWorldSafeLocsStore, dbcPath,"WorldSafeLocs.dbc");
// error checks
if(bad_dbc_files.size() >= DBCFilesCount )
{
sLog.outError("\nIncorrect DataDir value in mangosd.conf or ALL required *.dbc files (%d) not found by path: %sdbc",DBCFilesCount,dataPath.c_str());
exit(1);
}
else if(!bad_dbc_files.empty() )
{
std::string str;
for(std::list<std::string>::iterator i = bad_dbc_files.begin(); i != bad_dbc_files.end(); ++i)
str += *i + "\n";
sLog.outError("\nSome required *.dbc files (%u from %d) not found or not compatible:\n%s",bad_dbc_files.size(),DBCFilesCount,str.c_str());
exit(1);
}
// check at up-to-date DBC files (53085 is last added spell in 2.4.3)
// check at up-to-date DBC files (17514 is last ID in SkillLineAbilities in 2.4.3)
// check at up-to-date DBC files (598 is last map added in 2.4.3)
// check at up-to-date DBC files (1127 is last gem property added in 2.4.3)
// check at up-to-date DBC files (2425 is last item extended cost added in 2.4.3)
// check at up-to-date DBC files (71 is last char title added in 2.4.3)
// check at up-to-date DBC files (1768 is last area added in 2.4.3)
if( !sSpellStore.LookupEntry(53085) ||
!sSkillLineAbilityStore.LookupEntry(17514) ||
!sMapStore.LookupEntry(598) ||
!sGemPropertiesStore.LookupEntry(1127) ||
!sItemExtendedCostStore.LookupEntry(2425) ||
!sCharTitlesStore.LookupEntry(71) ||
!sAreaStore.LookupEntry(1768) )
{
sLog.outError("\nYou have _outdated_ DBC files. Please extract correct versions from current using client.");
exit(1);
}
sLog.outString();
sLog.outString( ">> Loaded %d data stores", DBCFilesCount );
sLog.outString();
}
SimpleFactionsList const* GetFactionTeamList(uint32 faction)
{
FactionTeamMap::const_iterator itr = sFactionTeamMap.find(faction);
if(itr==sFactionTeamMap.end())
return NULL;
return &itr->second;
}
char* GetPetName(uint32 petfamily, uint32 dbclang)
{
if(!petfamily)
return NULL;
CreatureFamilyEntry const *pet_family = sCreatureFamilyStore.LookupEntry(petfamily);
if(!pet_family)
return NULL;
return pet_family->Name[dbclang]?pet_family->Name[dbclang]:NULL;
}
TalentSpellPos const* GetTalentSpellPos(uint32 spellId)
{
TalentSpellPosMap::const_iterator itr = sTalentSpellPosMap.find(spellId);
if(itr==sTalentSpellPosMap.end())
return NULL;
return &itr->second;
}
uint32 GetTalentSpellCost(uint32 spellId)
{
if(TalentSpellPos const* pos = GetTalentSpellPos(spellId))
return pos->rank+1;
return 0;
}
AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id)
{
AreaFlagByAreaID::iterator i = sAreaFlagByAreaID.find(area_id);
if(i == sAreaFlagByAreaID.end())
return NULL;
return sAreaStore.LookupEntry(i->second);
}
AreaTableEntry const* GetAreaEntryByAreaFlagAndMap(uint32 area_flag,uint32 map_id)
{
if(area_flag)
return sAreaStore.LookupEntry(area_flag);
if(MapEntry const* mapEntry = sMapStore.LookupEntry(map_id))
return GetAreaEntryByAreaID(mapEntry->linked_zone);
return NULL;
}
uint32 GetAreaFlagByMapId(uint32 mapid)
{
AreaFlagByMapID::iterator i = sAreaFlagByMapID.find(mapid);
if(i == sAreaFlagByMapID.end())
return 0;
else
return i->second;
}
uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId)
{
if(mapid != 530) // speed for most cases
return mapid;
if(WorldMapAreaEntry const* wma = sWorldMapAreaStore.LookupEntry(zoneId))
return wma->virtual_map_id >= 0 ? wma->virtual_map_id : wma->map_id;
return mapid;
}
ContentLevels GetContentLevelsForMapAndZone(uint32 mapid, uint32 zoneId)
{
mapid = GetVirtualMapForMapAndZone(mapid,zoneId);
if(mapid < 2)
return CONTENT_1_60;
MapEntry const* mapEntry = sMapStore.LookupEntry(mapid);
if(!mapEntry)
return CONTENT_1_60;
switch(mapEntry->Expansion())
{
default: return CONTENT_1_60;
case 1: return CONTENT_61_70;
case 2: return CONTENT_71_80;
}
}
ChatChannelsEntry const* GetChannelEntryFor(uint32 channel_id)
{
// not sorted, numbering index from 0
for(uint32 i = 0; i < sChatChannelsStore.GetNumRows(); ++i)
{
ChatChannelsEntry const* ch = sChatChannelsStore.LookupEntry(i);
if(ch && ch->ChannelID == channel_id)
return ch;
}
return NULL;
}
bool IsTotemCategoryCompatiableWith(uint32 itemTotemCategoryId, uint32 requiredTotemCategoryId)
{
if(requiredTotemCategoryId==0)
return true;
if(itemTotemCategoryId==0)
return false;
TotemCategoryEntry const* itemEntry = sTotemCategoryStore.LookupEntry(itemTotemCategoryId);
if(!itemEntry)
return false;
TotemCategoryEntry const* reqEntry = sTotemCategoryStore.LookupEntry(requiredTotemCategoryId);
if(!reqEntry)
return false;
if(itemEntry->categoryType!=reqEntry->categoryType)
return false;
return (itemEntry->categoryMask & reqEntry->categoryMask)==reqEntry->categoryMask;
}
void Zone2MapCoordinates(float& x,float& y,uint32 zone)
{
WorldMapAreaEntry const* maEntry = sWorldMapAreaStore.LookupEntry(zone);
// if not listed then map coordinates (instance)
if(!maEntry)
return;
std::swap(x,y); // at client map coords swapped
x = x*((maEntry->x2-maEntry->x1)/100)+maEntry->x1;
y = y*((maEntry->y2-maEntry->y1)/100)+maEntry->y1; // client y coord from top to down
}
void Map2ZoneCoordinates(float& x,float& y,uint32 zone)
{
WorldMapAreaEntry const* maEntry = sWorldMapAreaStore.LookupEntry(zone);
// if not listed then map coordinates (instance)
if(!maEntry)
return;
x = (x-maEntry->x1)/((maEntry->x2-maEntry->x1)/100);
y = (y-maEntry->y1)/((maEntry->y2-maEntry->y1)/100); // client y coord from top to down
std::swap(x,y); // client have map coords swapped
}
uint32 GetTalentInspectBitPosInTab(uint32 talentId)
{
TalentInspectMap::const_iterator itr = sTalentPosInInspect.find(talentId);
if(itr == sTalentPosInInspect.end())
return 0;
return itr->second;
}
uint32 GetTalentTabInspectBitSize(uint32 talentTabId)
{
TalentInspectMap::const_iterator itr = sTalentTabSizeInInspect.find(talentTabId);
if(itr == sTalentTabSizeInInspect.end())
return 0;
return itr->second;
}
uint32 const* GetTalentTabPages(uint32 cls)
{
return sTalentTabPages[cls];
}
// script support functions
MANGOS_DLL_SPEC DBCStorage <SoundEntriesEntry> const* GetSoundEntriesStore() { return &sSoundEntriesStore; }
MANGOS_DLL_SPEC DBCStorage <SpellEntry> const* GetSpellStore() { return &sSpellStore; }
MANGOS_DLL_SPEC DBCStorage <SpellRangeEntry> const* GetSpellRangeStore() { return &sSpellRangeStore; }

View file

@ -0,0 +1,202 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef DBCSTORES_H
#define DBCSTORES_H
#include "Common.h"
//#include "DataStore.h"
#include "dbcfile.h"
#include "DBCStructure.h"
#include <list>
typedef std::list<uint32> SimpleFactionsList;
SimpleFactionsList const* GetFactionTeamList(uint32 faction);
char* GetPetName(uint32 petfamily, uint32 dbclang);
uint32 GetTalentSpellCost(uint32 spellId);
TalentSpellPos const* GetTalentSpellPos(uint32 spellId);
AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id);
AreaTableEntry const* GetAreaEntryByAreaFlagAndMap(uint32 area_flag,uint32 map_id);
uint32 GetAreaFlagByMapId(uint32 mapid);
uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId);
enum ContentLevels
{
CONTENT_1_60 = 0,
CONTENT_61_70,
CONTENT_71_80
};
ContentLevels GetContentLevelsForMapAndZone(uint32 mapid, uint32 zoneId);
ChatChannelsEntry const* GetChannelEntryFor(uint32 channel_id);
bool IsTotemCategoryCompatiableWith(uint32 itemTotemCategoryId, uint32 requiredTotemCategoryId);
void Zone2MapCoordinates(float& x,float& y,uint32 zone);
void Map2ZoneCoordinates(float& x,float& y,uint32 zone);
uint32 GetTalentInspectBitPosInTab(uint32 talentId);
uint32 GetTalentTabInspectBitSize(uint32 talentTabId);
uint32 const* /*[3]*/ GetTalentTabPages(uint32 cls);
template<class T>
class DBCStorage
{
typedef std::list<char*> StringPoolList;
public:
explicit DBCStorage(const char *f) : nCount(0), fieldCount(0), fmt(f), indexTable(NULL), m_dataTable(NULL) { }
~DBCStorage() { Clear(); }
T const* LookupEntry(uint32 id) const { return (id>=nCount)?NULL:indexTable[id]; }
uint32 GetNumRows() const { return nCount; }
char const* GetFormat() const { return fmt; }
uint32 GetFieldCount() const { return fieldCount; }
bool Load(char const* fn)
{
DBCFile dbc;
// Check if load was sucessful, only then continue
if(!dbc.Load(fn, fmt))
return false;
fieldCount = dbc.GetCols();
m_dataTable = (T*)dbc.AutoProduceData(fmt,nCount,(char**&)indexTable);
m_stringPoolList.push_back(dbc.AutoProduceStrings(fmt,(char*)m_dataTable));
// error in dbc file at loading if NULL
return indexTable!=NULL;
}
bool LoadStringsFrom(char const* fn)
{
// DBC must be already loaded using Load
if(!indexTable)
return false;
DBCFile dbc;
// Check if load was successful, only then continue
if(!dbc.Load(fn, fmt))
return false;
m_stringPoolList.push_back(dbc.AutoProduceStrings(fmt,(char*)m_dataTable));
return true;
}
void Clear()
{
if (!indexTable)
return;
delete[] ((char*)indexTable);
indexTable = NULL;
delete[] ((char*)m_dataTable);
m_dataTable = NULL;
while(!m_stringPoolList.empty())
{
delete[] m_stringPoolList.front();
m_stringPoolList.pop_front();
}
nCount = 0;
}
private:
uint32 nCount;
uint32 fieldCount;
char const* fmt;
T** indexTable;
T* m_dataTable;
StringPoolList m_stringPoolList;
};
extern DBCStorage <AreaTableEntry> sAreaStore;// recommend access using functions
extern DBCStorage <AreaTriggerEntry> sAreaTriggerStore;
extern DBCStorage <BankBagSlotPricesEntry> sBankBagSlotPricesStore;
extern DBCStorage <BattlemasterListEntry> sBattlemasterListStore;
//extern DBCStorage <ChatChannelsEntry> sChatChannelsStore; -- accessed using function, no usable index
extern DBCStorage <CharTitlesEntry> sCharTitlesStore;
extern DBCStorage <ChrClassesEntry> sChrClassesStore;
extern DBCStorage <ChrRacesEntry> sChrRacesStore;
extern DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore;
extern DBCStorage <CreatureFamilyEntry> sCreatureFamilyStore;
extern DBCStorage <CreatureSpellDataEntry> sCreatureSpellDataStore;
extern DBCStorage <DurabilityCostsEntry> sDurabilityCostsStore;
extern DBCStorage <DurabilityQualityEntry> sDurabilityQualityStore;
extern DBCStorage <EmotesTextEntry> sEmotesTextStore;
extern DBCStorage <FactionEntry> sFactionStore;
extern DBCStorage <FactionTemplateEntry> sFactionTemplateStore;
extern DBCStorage <GemPropertiesEntry> sGemPropertiesStore;
extern DBCStorage <GtCombatRatingsEntry> sGtCombatRatingsStore;
extern DBCStorage <GtChanceToMeleeCritBaseEntry> sGtChanceToMeleeCritBaseStore;
extern DBCStorage <GtChanceToMeleeCritEntry> sGtChanceToMeleeCritStore;
extern DBCStorage <GtChanceToSpellCritBaseEntry> sGtChanceToSpellCritBaseStore;
extern DBCStorage <GtChanceToSpellCritEntry> sGtChanceToSpellCritStore;
extern DBCStorage <GtOCTRegenHPEntry> sGtOCTRegenHPStore;
//extern DBCStorage <GtOCTRegenMPEntry> sGtOCTRegenMPStore; -- not used currently
extern DBCStorage <GtRegenHPPerSptEntry> sGtRegenHPPerSptStore;
extern DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore;
extern DBCStorage <ItemEntry> sItemStore;
//extern DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore; -- not used currently
extern DBCStorage <ItemExtendedCostEntry> sItemExtendedCostStore;
extern DBCStorage <ItemRandomPropertiesEntry> sItemRandomPropertiesStore;
extern DBCStorage <ItemRandomSuffixEntry> sItemRandomSuffixStore;
extern DBCStorage <ItemSetEntry> sItemSetStore;
extern DBCStorage <LockEntry> sLockStore;
extern DBCStorage <MailTemplateEntry> sMailTemplateStore;
extern DBCStorage <MapEntry> sMapStore;
extern DBCStorage <QuestSortEntry> sQuestSortStore;
extern DBCStorage <RandomPropertiesPointsEntry> sRandomPropertiesPointsStore;
extern DBCStorage <SkillLineEntry> sSkillLineStore;
extern DBCStorage <SkillLineAbilityEntry> sSkillLineAbilityStore;
extern DBCStorage <SoundEntriesEntry> sSoundEntriesStore;
extern DBCStorage <SpellCastTimesEntry> sSpellCastTimesStore;
extern DBCStorage <SpellDurationEntry> sSpellDurationStore;
extern DBCStorage <SpellFocusObjectEntry> sSpellFocusObjectStore;
extern DBCStorage <SpellItemEnchantmentEntry> sSpellItemEnchantmentStore;
extern DBCStorage <SpellItemEnchantmentConditionEntry> sSpellItemEnchantmentConditionStore;
extern SpellCategoryStore sSpellCategoryStore;
extern PetFamilySpellsStore sPetFamilySpellsStore;
extern DBCStorage <SpellRadiusEntry> sSpellRadiusStore;
extern DBCStorage <SpellRangeEntry> sSpellRangeStore;
extern DBCStorage <SpellShapeshiftEntry> sSpellShapeshiftStore;
extern DBCStorage <SpellEntry> sSpellStore;
extern DBCStorage <StableSlotPricesEntry> sStableSlotPricesStore;
extern DBCStorage <TalentEntry> sTalentStore;
extern DBCStorage <TalentTabEntry> sTalentTabStore;
extern DBCStorage <TaxiNodesEntry> sTaxiNodesStore;
extern DBCStorage <TaxiPathEntry> sTaxiPathStore;
extern TaxiMask sTaxiNodesMask;
extern TaxiPathSetBySource sTaxiPathSetBySource;
extern TaxiPathNodesByPath sTaxiPathNodesByPath;
extern DBCStorage <TotemCategoryEntry> sTotemCategoryStore;
//extern DBCStorage <WorldMapAreaEntry> sWorldMapAreaStore; -- use Zone2MapCoordinates and Map2ZoneCoordinates
extern DBCStorage <WorldSafeLocsEntry> sWorldSafeLocsStore;
void LoadDBCStores(std::string dataPath);
// script support functions
MANGOS_DLL_SPEC DBCStorage <SoundEntriesEntry> const* GetSoundEntriesStore();
MANGOS_DLL_SPEC DBCStorage <SpellEntry> const* GetSpellStore();
MANGOS_DLL_SPEC DBCStorage <SpellRangeEntry> const* GetSpellRangeStore();
#endif

View file

@ -0,0 +1,868 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef DBCSTRUCTURE_H
#define DBCSTRUCTURE_H
#include "DBCEnums.h"
#include "Platform/Define.h"
#include <map>
#include <set>
#include <vector>
// Structures using to access raw DBC data and required packing to portability
// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform
#if defined( __GNUC__ )
#pragma pack(1)
#else
#pragma pack(push,1)
#endif
struct AreaTableEntry
{
uint32 ID; // 0
uint32 mapid; // 1
uint32 zone; // 2 if 0 then it's zone, else it's zone id of this area
uint32 exploreFlag; // 3, main index
uint32 flags; // 4, unknown value but 312 for all cities
// 5-9 unused
int32 area_level; // 10
char* area_name[16]; // 11-26
// 27, string flags, unused
uint32 team; // 28
};
struct AreaTriggerEntry
{
uint32 id; // 0
uint32 mapid; // 1
float x; // 2
float y; // 3
float z; // 4
float radius; // 5
float box_x; // 6 extent x edge
float box_y; // 7 extent y edge
float box_z; // 8 extent z edge
float box_orientation; // 9 extent rotation by about z axis
};
struct BankBagSlotPricesEntry
{
uint32 ID;
uint32 price;
};
struct BattlemasterListEntry
{
uint32 id; // 0
uint32 mapid[3]; // 1-3 mapid
// 4-8 unused
uint32 type; // 9 (3 - BG, 4 - arena)
uint32 minlvl; // 10
uint32 maxlvl; // 11
uint32 maxplayersperteam; // 12
// 13-14 unused
char* name[16]; // 15-30
// 31 string flag, unused
// 32 unused
};
struct CharTitlesEntry
{
uint32 ID; // 0, title ids, for example in Quest::GetCharTitleId()
//uint32 unk1; // 1 flags?
//char* name[16]; // 2-17, unused
// 18 string flag, unused
//char* name2[16]; // 19-34, unused
// 35 string flag, unused
uint32 bit_index; // 36 used in PLAYER_CHOSEN_TITLE and 1<<index in PLAYER__FIELD_KNOWN_TITLES
};
struct ChatChannelsEntry
{
uint32 ChannelID; // 0
uint32 flags; // 1
char* pattern[16]; // 3-18
// 19 string flags, unused
//char* name[16]; // 20-35 unused
// 36 string flag, unused
};
struct ChrClassesEntry
{
uint32 ClassID; // 0
// 1-2, unused
uint32 powerType; // 3
// 4, unused
//char* name[16]; // 5-20 unused
// 21 string flag, unused
//char* string1[16]; // 21-36 unused
// 37 string flag, unused
//char* string2[16]; // 38-53 unused
// 54 string flag, unused
// 55, unused
uint32 spellfamily; // 56
// 57, unused
};
struct ChrRacesEntry
{
uint32 RaceID; // 0
// 1 unused
uint32 FactionID; // 2 facton template id
// 3 unused
uint32 model_m; // 4
uint32 model_f; // 5
// 6-7 unused
uint32 TeamID; // 8 (7-Alliance 1-Horde)
// 9-12 unused
uint32 startmovie; // 13 id from CinematicCamera.dbc
char* name[16]; // 14-29 used for DBC language detection/selection
// 30 string flags, unused
//char* string1[16]; // 31-46 used for DBC language detection/selection
// 47 string flags, unused
//char* string2[16]; // 48-63 used for DBC language detection/selection
// 64 string flags, unused
// 65-67 unused
uint32 addon; // 68 (0 - original race, 1 - tbc addon, ...)
};
struct CreatureDisplayInfoEntry
{
uint32 Displayid; // 0
// 1-3,unused
float scale; // 4
// 5-13,unused
};
struct CreatureFamilyEntry
{
uint32 ID; // 0
float minScale; // 1
uint32 minScaleLevel; // 2 0/1
float maxScale; // 3
uint32 maxScaleLevel; // 4 0/60
uint32 skillLine[2]; // 5-6
uint32 petFoodMask; // 7
char* Name[16]; // 8-23
// 24 string flags, unused
// 25 icon, unused
};
struct CreatureSpellDataEntry
{
uint32 ID; // 0
//uint32 spellId[4]; // 1-4 hunter pet learned spell (for later use)
};
struct DurabilityCostsEntry
{
uint32 Itemlvl; // 0
uint32 multiplier[29]; // 1-29
};
struct DurabilityQualityEntry
{
uint32 Id; // 0
float quality_mod; // 1
};
struct EmotesTextEntry
{
uint32 Id;
uint32 textid;
};
struct FactionEntry
{
uint32 ID; // 0
int32 reputationListID; // 1
uint32 BaseRepRaceMask[4]; // 2-5 Base reputation race masks (see enum Races)
uint32 BaseRepClassMask[4]; // 6-9 Base reputation class masks (see enum Classes)
int32 BaseRepValue[4]; // 10-13 Base reputation values
uint32 ReputationFlags[4]; // 14-17 Default flags to apply
uint32 team; // 18 enum Team
char* name[16]; // 19-34
// 35 string flags, unused
//char* description[16]; // 36-51 unused
// 52 string flags, unused
};
struct FactionTemplateEntry
{
uint32 ID; // 0
uint32 faction; // 1
uint32 factionFlags; // 2 specific flags for that faction
uint32 ourMask; // 3 if mask set (see FactionMasks) then faction included in masked team
uint32 friendlyMask; // 4 if mask set (see FactionMasks) then faction friendly to masked team
uint32 hostileMask; // 5 if mask set (see FactionMasks) then faction hostile to masked team
uint32 enemyFaction1; // 6
uint32 enemyFaction2; // 7
uint32 enemyFaction3; // 8
uint32 enemyFaction4; // 9
uint32 friendFaction1; // 10
uint32 friendFaction2; // 11
uint32 friendFaction3; // 12
uint32 friendFaction4; // 13
//------------------------------------------------------- end structure
// helpers
bool IsFriendlyTo(FactionTemplateEntry const& entry) const
{
if(enemyFaction1 == entry.faction || enemyFaction2 == entry.faction || enemyFaction3 == entry.faction || enemyFaction4 == entry.faction )
return false;
if(friendFaction1 == entry.faction || friendFaction2 == entry.faction || friendFaction3 == entry.faction || friendFaction4 == entry.faction )
return true;
return (friendlyMask & entry.ourMask) || (ourMask & entry.friendlyMask);
}
bool IsHostileTo(FactionTemplateEntry const& entry) const
{
if(enemyFaction1 == entry.faction || enemyFaction2 == entry.faction || enemyFaction3 == entry.faction || enemyFaction4 == entry.faction )
return true;
if(friendFaction1 == entry.faction || friendFaction2 == entry.faction || friendFaction3 == entry.faction || friendFaction4 == entry.faction )
return false;
return (hostileMask & entry.ourMask) != 0;
}
bool IsHostileToPlayers() const { return (hostileMask & FACTION_MASK_PLAYER) !=0; }
bool IsNeutralToAll() const { return hostileMask == 0 && friendlyMask == 0 && enemyFaction1==0 && enemyFaction2==0 && enemyFaction3==0 && enemyFaction4==0; }
bool IsContestedGuardFaction() const { return (factionFlags & FACTION_TEMPLATE_FLAG_CONTESTED_GUARD)!=0; }
};
struct GemPropertiesEntry
{
uint32 ID;
uint32 spellitemenchantement;
uint32 color;
};
#define GT_MAX_LEVEL 100
struct GtCombatRatingsEntry
{
float ratio;
};
struct GtChanceToMeleeCritBaseEntry
{
float base;
};
struct GtChanceToMeleeCritEntry
{
float ratio;
};
struct GtChanceToSpellCritBaseEntry
{
float base;
};
struct GtChanceToSpellCritEntry
{
float ratio;
};
struct GtOCTRegenHPEntry
{
float ratio;
};
//struct GtOCTRegenMPEntry
//{
// float ratio;
//};
struct GtRegenHPPerSptEntry
{
float ratio;
};
struct GtRegenMPPerSptEntry
{
float ratio;
};
struct ItemEntry
{
uint32 ID;
uint32 DisplayId;
uint32 InventoryType;
uint32 Sheath;
};
struct ItemDisplayInfoEntry
{
uint32 ID;
uint32 randomPropertyChance;
};
//struct ItemCondExtCostsEntry
//{
// uint32 ID;
// uint32 condExtendedCost; // ItemPrototype::CondExtendedCost
// uint32 itemextendedcostentry; // ItemPrototype::ExtendedCost
// uint32 arenaseason; // arena season number(1-4)
//};
struct ItemExtendedCostEntry
{
uint32 ID; // 0 extended-cost entry id
uint32 reqhonorpoints; // 1 required honor points
uint32 reqarenapoints; // 2 required arena points
uint32 reqitem[5]; // 3-7 required item id
uint32 reqitemcount[5]; // 8-12 required count of 1st item
uint32 reqpersonalarenarating; // 13 required personal arena rating
};
struct ItemRandomPropertiesEntry
{
uint32 ID; // 0
//char* internalName // 1 unused
uint32 enchant_id[3]; // 2-4
// 5-6 unused, 0 only values, reserved for additional enchantments?
//char* nameSuffix[16] // 7-22, unused
// 23 nameSufix flags, unused
};
struct ItemRandomSuffixEntry
{
uint32 ID; // 0
//char* name[16] // 1-16 unused
// 17, name flags, unused
// 18 unused
uint32 enchant_id[3]; // 19-21
uint32 prefix[3]; // 22-24
};
struct ItemSetEntry
{
//uint32 id // 0 item set ID
char* name[16]; // 1-16
// 17 string flags, unused
// 18-28 items from set, but not have all items listed, use ItemPrototype::ItemSet instead
// 29-34 unused
uint32 spells[8]; // 35-42
uint32 items_to_triggerspell[8]; // 43-50
uint32 required_skill_id; // 51
uint32 required_skill_value; // 52
};
struct LockEntry
{
uint32 ID; // 0
uint32 keytype[5]; // 1-5
// 6-8, not used
uint32 key[5]; // 9-13
// 14-16, not used
uint32 requiredminingskill; // 17
uint32 requiredlockskill; // 18
// 19-32, not used
};
struct MailTemplateEntry
{
uint32 ID; // 0
//char* subject[16]; // 1-16
// 17 name flags, unused
//char* content[16]; // 18-33
};
struct MapEntry
{
uint32 MapID; // 0
//char* internalname; // 1 unused
uint32 map_type; // 2
// 3 unused
char* name[16]; // 4-19
// 20 name flags, unused
// 21-23 unused (something PvPZone related - levels?)
// 24-26
uint32 linked_zone; // 27 common zone for instance and continent map
//char* hordeIntro // 28-43 text for PvP Zones
// 44 intro text flags
//char* allianceIntro // 45-60 text for PvP Zones
// 46 intro text flags
// 47-61 not used
uint32 multimap_id; // 62
// 63-65 not used
//chat* unknownText1 // 66-81 unknown empty text fields, possible normal Intro text.
// 82 text flags
//chat* heroicIntroText // 83-98 heroic mode requirement text
// 99 text flags
//chat* unknownText2 // 100-115 unknown empty text fields
// 116 text flags
int32 parent_map; // 117 map_id of parent map
//float start_x // 118 enter x coordinate (if exist single entry)
//float start_y // 119 enter y coordinate (if exist single entry)
uint32 resetTimeRaid; // 120
uint32 resetTimeHeroic; // 121
// 122-123
uint32 addon; // 124 (0-original maps,1-tbc addon)
// Helpers
uint32 Expansion() const { return addon; }
bool Instanceable() const { return map_type == MAP_INSTANCE || map_type == MAP_RAID; }
// NOTE: this duplicate of Instanceable(), but Instanceable() can be changed when BG also will be instanceable
bool IsDungeon() const { return map_type == MAP_INSTANCE || map_type == MAP_RAID; }
bool IsRaid() const { return map_type == MAP_RAID; }
bool IsBattleGround() const { return map_type == MAP_BATTLEGROUND; }
bool IsBattleArena() const { return map_type == MAP_ARENA; }
bool IsBattleGroundOrArena() const { return map_type == MAP_BATTLEGROUND || map_type == MAP_ARENA; }
bool SupportsHeroicMode() const { return resetTimeHeroic && !resetTimeRaid; }
bool HasResetTime() const { return resetTimeHeroic || resetTimeRaid; }
bool IsMountAllowed() const
{
return !IsDungeon() ||
MapID==568 || MapID==309 || MapID==209 || MapID==534 ||
MapID==560 || MapID==509 || MapID==269;
}
};
struct QuestSortEntry
{
uint32 id; // 0, sort id
//char* name[16]; // 1-16, unused
// 17 name flags, unused
};
struct RandomPropertiesPointsEntry
{
//uint32 Id; // 0 hidden key
uint32 itemLevel; // 1
uint32 EpicPropertiesPoints[5]; // 2-6
uint32 RarePropertiesPoints[5]; // 7-11
uint32 UncommonPropertiesPoints[5]; // 12-16
};
//struct SkillLineCategoryEntry{
// uint32 id; // 0 hidden key
// char* name[16]; // 1 - 17 Category name
// // 18 string flag
// uint32 displayOrder; // Display order in character tab
//};
//struct SkillRaceClassInfoEntry{
// uint32 id; // 0
// uint32 skillId; // 1 present some refrences to unknown skill
// uint32 raceMask; // 2
// uint32 classMask; // 3
// uint32 flags; // 4 mask for some thing
// uint32 reqLevel; // 5
// uint32 skillTierId; // 6
// uint32 skillCostID; // 7
//};
//struct SkillTiersEntry{
// uint32 id; // 0
// uint32 skillValue[16]; // 1-17 unknown possibly add value on learn?
// uint32 maxSkillValue[16]; // Max value for rank
//};
struct SkillLineEntry
{
uint32 id; // 0
uint32 categoryId; // 1 (index from SkillLineCategory.dbc)
//uint32 skillCostID; // 2 not used
char* name[16]; // 3-18
// 19 string flags, not used
//char* description[16]; // 20-35, not used
// 36 string flags, not used
uint32 spellIcon; // 37
};
struct SkillLineAbilityEntry
{
uint32 id; // 0, INDEX
uint32 skillId; // 1
uint32 spellId; // 2
uint32 racemask; // 3
uint32 classmask; // 4
//uint32 racemaskNot; // 5 always 0 in 2.4.2
//uint32 classmaskNot; // 6 always 0 in 2.4.2
uint32 req_skill_value; // 7 for trade skill.not for training.
uint32 forward_spellid; // 8
uint32 learnOnGetSkill; // 9 can be 1 or 2 for spells learned on get skill
uint32 max_value; // 10
uint32 min_value; // 11
// 12-13, unknown, always 0
uint32 reqtrainpoints; // 14
};
struct SoundEntriesEntry
{
uint32 Id; // 0, sound id
//uint32 Type; // 1, sound type (10 generally for creature, etc)
//char* InternalName; // 2, internal name, for use in lookup command for example
//char* FileName[10]; // 3-12, file names
//uint32 Unk13[10]; // 13-22, linked with file names?
//char* Path; // 23
// 24-28, unknown
};
struct SpellEntry
{
uint32 Id; // 0 normally counted from 0 field (but some tools start counting from 1, check this before tool use for data view!)
uint32 Category; // 1
//uint32 castUI // 2 not used
uint32 Dispel; // 3
uint32 Mechanic; // 4
uint32 Attributes; // 5
uint32 AttributesEx; // 6
uint32 AttributesEx2; // 7
uint32 AttributesEx3; // 8
uint32 AttributesEx4; // 9
uint32 AttributesEx5; // 10
//uint32 AttributesEx6; // 11 not used
uint32 Stances; // 12
uint32 StancesNot; // 13
uint32 Targets; // 14
uint32 TargetCreatureType; // 15
uint32 RequiresSpellFocus; // 16
uint32 FacingCasterFlags; // 17
uint32 CasterAuraState; // 18
uint32 TargetAuraState; // 19
uint32 CasterAuraStateNot; // 20
uint32 TargetAuraStateNot; // 21
uint32 CastingTimeIndex; // 22
uint32 RecoveryTime; // 23
uint32 CategoryRecoveryTime; // 24
uint32 InterruptFlags; // 25
uint32 AuraInterruptFlags; // 26
uint32 ChannelInterruptFlags; // 27
uint32 procFlags; // 28
uint32 procChance; // 29
uint32 procCharges; // 30
uint32 maxLevel; // 31
uint32 baseLevel; // 32
uint32 spellLevel; // 33
uint32 DurationIndex; // 34
uint32 powerType; // 35
uint32 manaCost; // 36
uint32 manaCostPerlevel; // 37
uint32 manaPerSecond; // 38
uint32 manaPerSecondPerLevel; // 39
uint32 rangeIndex; // 40
float speed; // 41
//uint32 modalNextSpell; // 42
uint32 StackAmount; // 43
uint32 Totem[2]; // 44-45
int32 Reagent[8]; // 46-53
uint32 ReagentCount[8]; // 54-61
int32 EquippedItemClass; // 62 (value)
int32 EquippedItemSubClassMask; // 63 (mask)
int32 EquippedItemInventoryTypeMask; // 64 (mask)
uint32 Effect[3]; // 65-67
int32 EffectDieSides[3]; // 68-70
uint32 EffectBaseDice[3]; // 71-73
float EffectDicePerLevel[3]; // 74-76
float EffectRealPointsPerLevel[3]; // 77-79
int32 EffectBasePoints[3]; // 80-82 (don't must be used in spell/auras explicitly, must be used cached Spell::m_currentBasePoints)
uint32 EffectMechanic[3]; // 83-85
uint32 EffectImplicitTargetA[3]; // 86-88
uint32 EffectImplicitTargetB[3]; // 89-91
uint32 EffectRadiusIndex[3]; // 92-94 - spellradius.dbc
uint32 EffectApplyAuraName[3]; // 95-97
uint32 EffectAmplitude[3]; // 98-100
float EffectMultipleValue[3]; // 101-103
uint32 EffectChainTarget[3]; // 104-106
uint32 EffectItemType[3]; // 107-109
int32 EffectMiscValue[3]; // 110-112
int32 EffectMiscValueB[3]; // 113-115
uint32 EffectTriggerSpell[3]; // 116-118
float EffectPointsPerComboPoint[3]; // 119-121
uint32 SpellVisual; // 122
// 123 not used
uint32 SpellIconID; // 124
uint32 activeIconID; // 125
//uint32 spellPriority; // 126
char* SpellName[16]; // 127-142
//uint32 SpellNameFlag; // 143
char* Rank[16]; // 144-159
//uint32 RankFlags; // 160
//char* Description[16]; // 161-176 not used
//uint32 DescriptionFlags; // 177 not used
//char* ToolTip[16]; // 178-193 not used
//uint32 ToolTipFlags; // 194 not used
uint32 ManaCostPercentage; // 195
uint32 StartRecoveryCategory; // 196
uint32 StartRecoveryTime; // 197
uint32 MaxTargetLevel; // 198
uint32 SpellFamilyName; // 199
uint64 SpellFamilyFlags; // 200+201
uint32 MaxAffectedTargets; // 202
uint32 DmgClass; // 203 defenseType
uint32 PreventionType; // 204
//uint32 StanceBarOrder; // 205 not used
float DmgMultiplier[3]; // 206-208
//uint32 MinFactionId; // 209 not used, and 0 in 2.4.2
//uint32 MinReputation; // 210 not used, and 0 in 2.4.2
//uint32 RequiredAuraVision; // 211 not used
uint32 TotemCategory[2]; // 212-213
uint32 AreaId; // 214
uint32 SchoolMask; // 215 school mask
private:
// prevent creating custom entries (copy data from original in fact)
SpellEntry(SpellEntry const&); // DON'T must have implementation
};
typedef std::set<uint32> SpellCategorySet;
typedef std::map<uint32,SpellCategorySet > SpellCategoryStore;
typedef std::set<uint32> PetFamilySpellsSet;
typedef std::map<uint32,PetFamilySpellsSet > PetFamilySpellsStore;
struct SpellCastTimesEntry
{
uint32 ID; // 0
int32 CastTime; // 1
//float CastTimePerLevel; // 2 unsure / per skill?
//int32 MinCastTime; // 3 unsure
};
struct SpellFocusObjectEntry
{
uint32 ID; // 0
//char* Name[16]; // 1-15 unused
// 16 string flags, unused
};
// stored in SQL table
struct SpellThreatEntry
{
uint32 spellId;
int32 threat;
};
struct SpellRadiusEntry
{
uint32 ID;
float Radius;
float Radius2;
};
struct SpellRangeEntry
{
uint32 ID;
float minRange;
float maxRange;
};
struct SpellShapeshiftEntry
{
uint32 ID; // 0
//uint32 buttonPosition; // 1 unused
//char* Name[16]; // 2-17 unused
//uint32 NameFlags; // 18 unused
uint32 flags1; // 19
int32 creatureType; // 20 <=0 humanoid, other normal creature types
//uint32 unk1; // 21 unused
uint32 attackSpeed; // 22
//uint32 modelID; // 23 unused, alliance modelid (where horde case?)
//uint32 unk2; // 24 unused
//uint32 unk3; // 25 unused
//uint32 unk4; // 26 unused
//uint32 unk5; // 27 unused
//uint32 unk6; // 28 unused
//uint32 unk7; // 29 unused
//uint32 unk8; // 30 unused
//uint32 unk9; // 31 unused
//uint32 unk10; // 32 unused
//uint32 unk11; // 33 unused
//uint32 unk12; // 34 unused
};
struct SpellDurationEntry
{
uint32 ID;
int32 Duration[3];
};
struct SpellItemEnchantmentEntry
{
uint32 ID; // 0
uint32 type[3]; // 1-3
uint32 amount[3]; // 4-6
//uint32 amount2[3] // 7-9 always same as similar `amount` value
uint32 spellid[3]; // 10-12
char* description[16]; // 13-29
// 30 description flags
uint32 aura_id; // 31
uint32 slot; // 32
uint32 GemID; // 33
uint32 EnchantmentCondition; // 34
};
struct SpellItemEnchantmentConditionEntry
{
uint32 ID;
uint8 Color[5];
uint8 Comparator[5];
uint8 CompareColor[5];
uint32 Value[5];
};
struct StableSlotPricesEntry
{
uint32 Slot;
uint32 Price;
};
struct TalentEntry
{
uint32 TalentID; // 0
uint32 TalentTab; // 1 index in TalentTab.dbc (TalentTabEntry)
uint32 Row; // 2
uint32 Col; // 3
uint32 RankID[5]; // 4-8
// 9-12 not used, always 0, maybe not used high ranks
uint32 DependsOn; // 13 index in Talent.dbc (TalentEntry)
// 14-15 not used
uint32 DependsOnRank; // 16
// 17-19 not used
uint32 DependsOnSpell; // 20 req.spell
};
struct TalentTabEntry
{
uint32 TalentTabID; // 0
//char* name[16]; // 1-16, unused
//uint32 nameFlags; // 17, unused
//unit32 spellicon; // 18
// 19 not used
uint32 ClassMask; // 20
uint32 tabpage; // 21
//char* internalname; // 22
};
struct TaxiNodesEntry
{
uint32 ID; // 0
uint32 map_id; // 1
float x; // 2
float y; // 3
float z; // 4
//char* name[16]; // 5-21
// 22 string flags, unused
uint32 horde_mount_type; // 23
uint32 alliance_mount_type; // 24
};
struct TaxiPathEntry
{
uint32 ID;
uint32 from;
uint32 to;
uint32 price;
};
struct TaxiPathNodeEntry
{
uint32 path;
uint32 index;
uint32 mapid;
float x;
float y;
float z;
uint32 actionFlag;
uint32 delay;
};
struct TotemCategoryEntry
{
uint32 ID; // 0
//char* name[16]; // 1-16
// 17 string flags, unused
uint32 categoryType; // 18 (one for specialization)
uint32 categoryMask; // 19 (compatibility mask for same type: different for totems, compatible from high to low for rods)
};
struct WorldMapAreaEntry
{
//uint32 ID; // 0
uint32 map_id; // 1
uint32 area_id; // 2 index (continent 0 areas ignored)
//char* internal_name // 3
float y1; // 4
float y2; // 5
float x1; // 6
float x2; // 7
int32 virtual_map_id; // 8 -1 (map_id have correct map) other: virtual map where zone show (map_id - where zone in fact internally)
};
struct WorldSafeLocsEntry
{
uint32 ID; // 0
uint32 map_id; // 1
float x; // 2
float y; // 3
float z; // 4
//char* name[16] // 5-20 name, unused
// 21 name flags, unused
};
// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform
#if defined( __GNUC__ )
#pragma pack()
#else
#pragma pack(pop)
#endif
// Structures not used for casting to loaded DBC data and not required then packing
struct TalentSpellPos
{
TalentSpellPos() : talent_id(0), rank(0) {}
TalentSpellPos(uint16 _talent_id, uint8 _rank) : talent_id(_talent_id), rank(_rank) {}
uint16 talent_id;
uint8 rank;
};
typedef std::map<uint32,TalentSpellPos> TalentSpellPosMap;
struct TaxiPathBySourceAndDestination
{
TaxiPathBySourceAndDestination() : ID(0),price(0) {}
TaxiPathBySourceAndDestination(uint32 _id,uint32 _price) : ID(_id),price(_price) {}
uint32 ID;
uint32 price;
};
typedef std::map<uint32,TaxiPathBySourceAndDestination> TaxiPathSetForSource;
typedef std::map<uint32,TaxiPathSetForSource> TaxiPathSetBySource;
struct TaxiPathNode
{
TaxiPathNode() : mapid(0), x(0),y(0),z(0),actionFlag(0),delay(0) {}
TaxiPathNode(uint32 _mapid, float _x, float _y, float _z, uint32 _actionFlag, uint32 _delay) : mapid(_mapid), x(_x),y(_y),z(_z),actionFlag(_actionFlag),delay(_delay) {}
uint32 mapid;
float x;
float y;
float z;
uint32 actionFlag;
uint32 delay;
};
typedef std::vector<TaxiPathNode> TaxiPathNodeList;
typedef std::vector<TaxiPathNodeList> TaxiPathNodesByPath;
#define TaxiMaskSize 16
typedef uint32 TaxiMask[TaxiMaskSize];
#endif

View file

@ -0,0 +1,78 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
const char AreaTableEntryfmt[]="iiinixxxxxissssssssssssssssxixxxxxx";
const char AreaTriggerEntryfmt[]="niffffffff";
const char BankBagSlotPricesEntryfmt[]="ni";
const char BattlemasterListEntryfmt[]="niiixxxxxiiiixxssssssssssssssssxx";
const char CharTitlesEntryfmt[]="nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxi";
const char ChatChannelsEntryfmt[]="iixssssssssssssssssxxxxxxxxxxxxxxxxxx";
// ChatChannelsEntryfmt, index not used (more compact store)
const char ChrClassesEntryfmt[]="nxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxix";
const char ChrRacesEntryfmt[]="nxixiixxixxxxissssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxi";
const char CreatureDisplayInfofmt[]="nxxxfxxxxxxxxx";
const char CreatureFamilyfmt[]="nfifiiiissssssssssssssssxx";
const char CreatureSpellDatafmt[]="nxxxxxxxx";
const char DurabilityCostsfmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiii";
const char DurabilityQualityfmt[]="nf";
const char EmoteEntryfmt[]="nxixxxxxxxxxxxxxxxx";
const char FactionEntryfmt[]="niiiiiiiiiiiiiiiiiissssssssssssssssxxxxxxxxxxxxxxxxxx";
const char FactionTemplateEntryfmt[]="niiiiiiiiiiiii";
const char GemPropertiesEntryfmt[]="nixxi";
const char GtCombatRatingsfmt[]="f";
const char GtChanceToMeleeCritBasefmt[]="f";
const char GtChanceToMeleeCritfmt[]="f";
const char GtChanceToSpellCritBasefmt[]="f";
const char GtChanceToSpellCritfmt[]="f";
const char GtOCTRegenHPfmt[]="f";
//const char GtOCTRegenMPfmt[]="f";
const char GtRegenHPPerSptfmt[]="f";
const char GtRegenMPPerSptfmt[]="f";
const char Itemfmt[]="niii";
//const char ItemDisplayTemplateEntryfmt[]="nxxxxxxxxxxixxxxxxxxxxx";
//const char ItemCondExtCostsEntryfmt[]="xiii";
const char ItemExtendedCostEntryfmt[]="niiiiiiiiiiiii";
const char ItemRandomPropertiesfmt[]="nxiiixxxxxxxxxxxxxxxxxxx";
const char ItemRandomSuffixfmt[]="nxxxxxxxxxxxxxxxxxxiiiiii";
const char ItemSetEntryfmt[]="dssssssssssssssssxxxxxxxxxxxxxxxxxxiiiiiiiiiiiiiiiiii";
const char LockEntryfmt[]="niiiiixxxiiiiixxxiixxxxxxxxxxxxxx";
const char MailTemplateEntryfmt[]="nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
const char MapEntryfmt[]="nxixssssssssssssssssxxxxxxxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixxiixxi";
const char QuestSortEntryfmt[]="nxxxxxxxxxxxxxxxxx";
const char RandomPropertiesPointsfmt[]="niiiiiiiiiiiiiii";
const char SkillLinefmt[]="nixssssssssssssssssxxxxxxxxxxxxxxxxxxi";
const char SkillLineAbilityfmt[]="niiiixxiiiiixxi";
const char SoundEntriesfmt[]="nxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
const char SpellCastTimefmt[]="nixx";
const char SpellDurationfmt[]="niii";
const char SpellEntryfmt[]="nixiiiiiiiixiiiiiiiiiiiiiiiiiiiiiiiiiiiiifxiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffffffiiiiiiiiiiiiiiiiiiiiifffiiiiiiiiiiiiiiifffixiixssssssssssssssssxssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiiiiiiiiiixfffxxxiiii";
const char SpellFocusObjectfmt[]="nxxxxxxxxxxxxxxxxx";
const char SpellItemEnchantmentfmt[]="niiiiiixxxiiissssssssssssssssxiiii";
const char SpellItemEnchantmentConditionfmt[]="nbbbbbxxxxxbbbbbbbbbbiiiiiXXXXX";
const char SpellRadiusfmt[]="nfxf";
const char SpellRangefmt[]="nffxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
const char SpellShapeshiftfmt[]="nxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxx";
const char StableSlotPricesfmt[] = "ni";
const char TalentEntryfmt[]="niiiiiiiixxxxixxixxxi";
const char TalentTabEntryfmt[]="nxxxxxxxxxxxxxxxxxxxiix";
const char TaxiNodesEntryfmt[]="nifffxxxxxxxxxxxxxxxxxii";
const char TaxiPathEntryfmt[]="niii";
const char TaxiPathNodeEntryfmt[]="diiifffiixx";
const char TotemCategoryEntryfmt[]="nxxxxxxxxxxxxxxxxxii";
const char WorldMapAreaEntryfmt[]="xinxffffi";
const char WorldSafeLocsEntryfmt[]="nifffxxxxxxxxxxxxxxxxx";

View file

@ -0,0 +1,171 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#include "DatabaseEnv.h"
#include "Config/ConfigEnv.h"
#include <ctime>
#include <iostream>
#include <fstream>
Database::~Database()
{
/*Delete objects*/
}
bool Database::Initialize(const char *)
{
// Enable logging of SQL commands (usally only GM commands)
// (See method: PExecuteLog)
m_logSQL = sConfig.GetBoolDefault("LogSQL", false);
m_logsDir = sConfig.GetStringDefault("LogsDir","");
if(!m_logsDir.empty())
{
if((m_logsDir.at(m_logsDir.length()-1)!='/') && (m_logsDir.at(m_logsDir.length()-1)!='\\'))
m_logsDir.append("/");
}
return true;
}
void Database::ThreadStart()
{
}
void Database::ThreadEnd()
{
}
void Database::escape_string(std::string& str)
{
if(str.empty())
return;
char* buf = new char[str.size()*2+1];
escape_string(buf,str.c_str(),str.size());
str = buf;
delete[] buf;
}
bool Database::PExecuteLog(const char * format,...)
{
if (!format)
return false;
va_list ap;
char szQuery [MAX_QUERY_LEN];
va_start(ap, format);
int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
va_end(ap);
if(res==-1)
{
sLog.outError("SQL Query truncated (and not execute) for format: %s",format);
return false;
}
if( m_logSQL )
{
time_t curr;
tm local;
time(&curr); // get current time_t value
local=*(localtime(&curr)); // dereference and assign
char fName[128];
sprintf( fName, "%04d-%02d-%02d_logSQL.sql", local.tm_year+1900, local.tm_mon+1, local.tm_mday );
FILE* log_file;
std::string logsDir_fname = m_logsDir+fName;
log_file = fopen(logsDir_fname.c_str(), "a");
if (log_file)
{
fprintf(log_file, "%s;\n", szQuery);
fclose(log_file);
}
else
{
// The file could not be opened
sLog.outError("SQL-Logging is disabled - Log file for the SQL commands could not be openend: %s",fName);
}
}
return Execute(szQuery);
}
void Database::SetResultQueue(SqlResultQueue * queue)
{
m_queryQueues[ZThread::ThreadImpl::current()] = queue;
}
QueryResult* Database::PQuery(const char *format,...)
{
if(!format) return NULL;
va_list ap;
char szQuery [MAX_QUERY_LEN];
va_start(ap, format);
int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
va_end(ap);
if(res==-1)
{
sLog.outError("SQL Query truncated (and not execute) for format: %s",format);
return false;
}
return Query(szQuery);
}
bool Database::PExecute(const char * format,...)
{
if (!format)
return false;
va_list ap;
char szQuery [MAX_QUERY_LEN];
va_start(ap, format);
int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
va_end(ap);
if(res==-1)
{
sLog.outError("SQL Query truncated (and not execute) for format: %s",format);
return false;
}
return Execute(szQuery);
}
bool Database::DirectPExecute(const char * format,...)
{
if (!format)
return false;
va_list ap;
char szQuery [MAX_QUERY_LEN];
va_start(ap, format);
int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
va_end(ap);
if(res==-1)
{
sLog.outError("SQL Query truncated (and not execute) for format: %s",format);
return false;
}
return DirectExecute(szQuery);
}

View file

@ -0,0 +1,113 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef DATABASE_H
#define DATABASE_H
#include "zthread/Thread.h"
#include "../src/zthread/ThreadImpl.h"
#include "Utilities/HashMap.h"
#include "Database/SqlDelayThread.h"
class SqlTransaction;
class SqlResultQueue;
class SqlQueryHolder;
typedef HM_NAMESPACE::hash_map<ZThread::ThreadImpl*, SqlTransaction*> TransactionQueues;
typedef HM_NAMESPACE::hash_map<ZThread::ThreadImpl*, SqlResultQueue*> QueryQueues;
#define MAX_QUERY_LEN 1024
class MANGOS_DLL_SPEC Database
{
protected:
Database() : m_threadBody(NULL), m_delayThread(NULL) {};
TransactionQueues m_tranQueues; ///< Transaction queues from diff. threads
QueryQueues m_queryQueues; ///< Query queues from diff threads
SqlDelayThread* m_threadBody; ///< Pointer to delay sql executer
ZThread::Thread* m_delayThread; ///< Pointer to executer thread
public:
virtual ~Database();
virtual bool Initialize(const char *infoString);
virtual void InitDelayThread() = 0;
virtual void HaltDelayThread() = 0;
virtual QueryResult* Query(const char *sql) = 0;
QueryResult* PQuery(const char *format,...) ATTR_PRINTF(2,3);
/// Async queries and query holders, implemented in DatabaseImpl.h
template<class Class>
bool AsyncQuery(Class *object, void (Class::*method)(QueryResult*), const char *sql);
template<class Class, typename ParamType1>
bool AsyncQuery(Class *object, void (Class::*method)(QueryResult*, ParamType1), ParamType1 param1, const char *sql);
template<typename ParamType1>
bool AsyncQuery(void (*method)(QueryResult*, ParamType1), ParamType1 param1, const char *sql);
template<class Class>
bool AsyncPQuery(Class *object, void (Class::*method)(QueryResult*), const char *format,...) ATTR_PRINTF(4,5);
template<class Class, typename ParamType1>
bool AsyncPQuery(Class *object, void (Class::*method)(QueryResult*, ParamType1), ParamType1 param1, const char *format,...) ATTR_PRINTF(5,6);
template<typename ParamType1>
bool AsyncPQuery(void (*method)(QueryResult*, ParamType1), ParamType1 param1, const char *format,...) ATTR_PRINTF(5,6);
template<class Class>
bool DelayQueryHolder(Class *object, void (Class::*method)(QueryResult*, SqlQueryHolder*), SqlQueryHolder *holder);
template<class Class, typename ParamType1>
bool DelayQueryHolder(Class *object, void (Class::*method)(QueryResult*, SqlQueryHolder*, ParamType1), SqlQueryHolder *holder, ParamType1 param1);
virtual bool Execute(const char *sql) = 0;
bool PExecute(const char *format,...) ATTR_PRINTF(2,3);
virtual bool DirectExecute(const char* sql) = 0;
bool DirectPExecute(const char *format,...) ATTR_PRINTF(2,3);
// Writes SQL commands to a LOG file (see mangosd.conf "LogSQL")
bool PExecuteLog(const char *format,...) ATTR_PRINTF(2,3);
virtual bool BeginTransaction() // nothing do if DB not support transactions
{
return true;
}
virtual bool CommitTransaction() // nothing do if DB not support transactions
{
return true;
}
virtual bool RollbackTransaction() // can't rollback without transaction support
{
return false;
}
virtual operator bool () const = 0;
virtual unsigned long escape_string(char *to, const char *from, unsigned long length) { strncpy(to,from,length); return length; }
void escape_string(std::string& str);
// must be called before first query in thread (one time for thread using one from existed Database objects)
virtual void ThreadStart();
// must be called before finish thread run (one time for thread using one from existed Database objects)
virtual void ThreadEnd();
// sets the result queue of the current thread, be careful what thread you call this from
void SetResultQueue(SqlResultQueue * queue);
private:
bool m_logSQL;
std::string m_logsDir;
};
#endif

View file

@ -0,0 +1,54 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#if !defined(DATABASEENV_H)
#define DATABASEENV_H
#include "Common.h"
#include "Log.h"
#include "Errors.h"
#include "Database/DBCStores.h"
#include "Database/Field.h"
#include "Database/QueryResult.h"
#ifdef DO_POSTGRESQL
#include "Database/QueryResultPostgre.h"
#include "Database/Database.h"
#include "Database/DatabasePostgre.h"
typedef DatabasePostgre DatabaseType;
#define _LIKE_ "ILIKE"
#define _TABLE_SIM_ "\""
#define _CONCAT3_(A,B,C) "( " A " || " B " || " C " )"
#else
#include "Database/QueryResultMysql.h"
#include "Database/QueryResultSqlite.h"
#include "Database/Database.h"
#include "Database/DatabaseMysql.h"
#include "Database/DatabaseSqlite.h"
typedef DatabaseMysql DatabaseType;
#define _LIKE_ "LIKE"
#define _TABLE_SIM_ "`"
#define _CONCAT3_(A,B,C) "CONCAT( " A " , " B " , " C " )"
#endif
extern DatabaseType WorldDatabase;
extern DatabaseType CharacterDatabase;
extern DatabaseType loginDatabase;
#endif

View file

@ -0,0 +1,145 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#include "Database/Database.h"
#include "Database/SqlOperations.h"
/// Function body definitions for the template function members of the Database class
template<class Class>
bool
Database::AsyncQuery(Class *object, void (Class::*method)(QueryResult*), const char *sql)
{
if (!sql) return false;
ZThread::ThreadImpl * queryThread = ZThread::ThreadImpl::current();
QueryQueues::iterator itr = m_queryQueues.find(queryThread);
if (itr == m_queryQueues.end()) return false;
m_threadBody->Delay(new SqlQuery(sql, new MaNGOS::QueryCallback<Class>(object, method), itr->second));
return true;
}
template<class Class, typename ParamType1>
bool
Database::AsyncQuery(Class *object, void (Class::*method)(QueryResult*, ParamType1), ParamType1 param1, const char *sql)
{
if (!sql) return false;
ZThread::ThreadImpl * queryThread = ZThread::ThreadImpl::current();
QueryQueues::iterator itr = m_queryQueues.find(queryThread);
if (itr == m_queryQueues.end()) return false;
m_threadBody->Delay(new SqlQuery(sql, new MaNGOS::QueryCallback<Class, ParamType1>(object, method, (QueryResult*)NULL, param1), itr->second));
return true;
}
template<typename ParamType1>
bool
Database::AsyncQuery(void (*method)(QueryResult*, ParamType1), ParamType1 param1, const char *sql)
{
if (!sql) return false;
ZThread::ThreadImpl * queryThread = ZThread::ThreadImpl::current();
QueryQueues::iterator itr = m_queryQueues.find(queryThread);
if (itr == m_queryQueues.end()) return false;
m_threadBody->Delay(new SqlQuery(sql, new MaNGOS::SQueryCallback<ParamType1>(method, (QueryResult*)NULL, param1), itr->second));
return true;
}
template<class Class>
bool
Database::AsyncPQuery(Class *object, void (Class::*method)(QueryResult*), const char *format,...)
{
if(!format) return false;
va_list ap;
char szQuery [MAX_QUERY_LEN];
va_start(ap, format);
int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
va_end(ap);
if(res==-1)
{
sLog.outError("SQL Query truncated (and not execute) for format: %s",format);
return false;
}
return AsyncQuery(object, method, szQuery);
}
template<class Class, typename ParamType1>
bool
Database::AsyncPQuery(Class *object, void (Class::*method)(QueryResult*, ParamType1), ParamType1 param1, const char *format,...)
{
if(!format) return false;
va_list ap;
char szQuery [MAX_QUERY_LEN];
va_start(ap, format);
int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
va_end(ap);
if(res==-1)
{
sLog.outError("SQL Query truncated (and not execute) for format: %s",format);
return false;
}
return AsyncQuery(object, method, param1, szQuery);
}
template<typename ParamType1>
bool
Database::AsyncPQuery(void (*method)(QueryResult*, ParamType1), ParamType1 param1, const char *format,...)
{
if(!format) return false;
va_list ap;
char szQuery [MAX_QUERY_LEN];
va_start(ap, format);
int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
va_end(ap);
if(res==-1)
{
sLog.outError("SQL Query truncated (and not execute) for format: %s",format);
return false;
}
return AsyncQuery(method, param1, szQuery);
}
template<class Class>
bool
Database::DelayQueryHolder(Class *object, void (Class::*method)(QueryResult*, SqlQueryHolder*), SqlQueryHolder *holder)
{
if (!holder) return false;
ZThread::ThreadImpl * queryThread = ZThread::ThreadImpl::current();
QueryQueues::iterator itr = m_queryQueues.find(queryThread);
if (itr == m_queryQueues.end()) return false;
holder->Execute(new MaNGOS::QueryCallback<Class, SqlQueryHolder*>(object, method, (QueryResult*)NULL, holder), m_threadBody, itr->second);
return true;
}
template<class Class, typename ParamType1>
bool
Database::DelayQueryHolder(Class *object, void (Class::*method)(QueryResult*, SqlQueryHolder*, ParamType1), SqlQueryHolder *holder, ParamType1 param1)
{
if (!holder) return false;
ZThread::ThreadImpl * queryThread = ZThread::ThreadImpl::current();
QueryQueues::iterator itr = m_queryQueues.find(queryThread);
if (itr == m_queryQueues.end()) return false;
holder->Execute(new MaNGOS::QueryCallback<Class, SqlQueryHolder*, ParamType1>(object, method, (QueryResult*)NULL, holder, param1), m_threadBody, itr->second);
return true;
}

View file

@ -0,0 +1,408 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef DO_POSTGRESQL
#include "Util.h"
#include "Policies/SingletonImp.h"
#include "Platform/Define.h"
#include "../src/zthread/ThreadImpl.h"
#include "DatabaseEnv.h"
#include "Database/MySQLDelayThread.h"
#include "Database/SqlOperations.h"
#include "Timer.h"
void DatabaseMysql::ThreadStart()
{
mysql_thread_init();
}
void DatabaseMysql::ThreadEnd()
{
mysql_thread_end();
}
size_t DatabaseMysql::db_count = 0;
DatabaseMysql::DatabaseMysql() : Database(), mMysql(0)
{
// before first connection
if( db_count++ == 0 )
{
// Mysql Library Init
mysql_library_init(-1, NULL, NULL);
if (!mysql_thread_safe())
{
sLog.outError("FATAL ERROR: Used MySQL library isn't thread-safe.");
exit(1);
}
}
}
DatabaseMysql::~DatabaseMysql()
{
if (m_delayThread)
HaltDelayThread();
if (mMysql)
mysql_close(mMysql);
//Free Mysql library pointers for last ~DB
if(--db_count == 0)
mysql_library_end();
}
bool DatabaseMysql::Initialize(const char *infoString)
{
if(!Database::Initialize(infoString))
return false;
tranThread = NULL;
MYSQL *mysqlInit;
mysqlInit = mysql_init(NULL);
if (!mysqlInit)
{
sLog.outError( "Could not initialize Mysql connection" );
return false;
}
InitDelayThread();
Tokens tokens = StrSplit(infoString, ";");
Tokens::iterator iter;
std::string host, port_or_socket, user, password, database;
int port;
char const* unix_socket;
iter = tokens.begin();
if(iter != tokens.end())
host = *iter++;
if(iter != tokens.end())
port_or_socket = *iter++;
if(iter != tokens.end())
user = *iter++;
if(iter != tokens.end())
password = *iter++;
if(iter != tokens.end())
database = *iter++;
mysql_options(mysqlInit,MYSQL_SET_CHARSET_NAME,"utf8");
#ifdef WIN32
if(host==".") // named pipe use option (Windows)
{
unsigned int opt = MYSQL_PROTOCOL_PIPE;
mysql_options(mysqlInit,MYSQL_OPT_PROTOCOL,(char const*)&opt);
port = 0;
unix_socket = 0;
}
else // generic case
{
port = atoi(port_or_socket.c_str());
unix_socket = 0;
}
#else
if(host==".") // socket use option (Unix/Linux)
{
unsigned int opt = MYSQL_PROTOCOL_SOCKET;
mysql_options(mysqlInit,MYSQL_OPT_PROTOCOL,(char const*)&opt);
host = "localhost";
port = 0;
unix_socket = port_or_socket.c_str();
}
else // generic case
{
port = atoi(port_or_socket.c_str());
unix_socket = 0;
}
#endif
mMysql = mysql_real_connect(mysqlInit, host.c_str(), user.c_str(),
password.c_str(), database.c_str(), port, unix_socket, 0);
if (mMysql)
{
sLog.outDetail( "Connected to MySQL database at %s",
host.c_str());
sLog.outString( "MySQL client library: %s", mysql_get_client_info());
sLog.outString( "MySQL server ver: %s ", mysql_get_server_info( mMysql));
/*----------SET AUTOCOMMIT ON---------*/
// It seems mysql 5.0.x have enabled this feature
// by default. In crash case you can lose data!!!
// So better to turn this off
// ---
// This is wrong since mangos use transactions,
// autocommit is turned of during it.
// Setting it to on makes atomic updates work
if (!mysql_autocommit(mMysql, 1))
sLog.outDetail("AUTOCOMMIT SUCCESSFULLY SET TO 1");
else
sLog.outDetail("AUTOCOMMIT NOT SET TO 1");
/*-------------------------------------*/
// set connection properties to UTF8 to properly handle locales for different
// server configs - core sends data in UTF8, so MySQL must expect UTF8 too
PExecute("SET NAMES `utf8`");
PExecute("SET CHARACTER SET `utf8`");
return true;
}
else
{
sLog.outError( "Could not connect to MySQL database at %s: %s\n",
host.c_str(),mysql_error(mysqlInit));
mysql_close(mysqlInit);
return false;
}
}
QueryResult* DatabaseMysql::Query(const char *sql)
{
if (!mMysql)
return 0;
MYSQL_RES *result = 0;
uint64 rowCount = 0;
uint32 fieldCount = 0;
{
// guarded block for thread-safe mySQL request
ZThread::Guard<ZThread::FastMutex> query_connection_guard(mMutex);
#ifdef MANGOS_DEBUG
uint32 _s = getMSTime();
#endif
if(mysql_query(mMysql, sql))
{
sLog.outErrorDb( "SQL: %s", sql );
sLog.outErrorDb("query ERROR: %s", mysql_error(mMysql));
return NULL;
}
else
{
#ifdef MANGOS_DEBUG
sLog.outDebug("[%u ms] SQL: %s", getMSTimeDiff(_s,getMSTime()), sql );
#endif
}
result = mysql_store_result(mMysql);
rowCount = mysql_affected_rows(mMysql);
fieldCount = mysql_field_count(mMysql);
// end guarded block
}
if (!result )
return NULL;
if (!rowCount)
{
mysql_free_result(result);
return NULL;
}
QueryResultMysql *queryResult = new QueryResultMysql(result, rowCount, fieldCount);
queryResult->NextRow();
return queryResult;
}
bool DatabaseMysql::Execute(const char *sql)
{
if (!mMysql)
return false;
// don't use queued execution if it has not been initialized
if (!m_threadBody) return DirectExecute(sql);
tranThread = ZThread::ThreadImpl::current(); // owner of this transaction
TransactionQueues::iterator i = m_tranQueues.find(tranThread);
if (i != m_tranQueues.end() && i->second != NULL)
{ // Statement for transaction
i->second->DelayExecute(sql);
}
else
{
// Simple sql statement
m_threadBody->Delay(new SqlStatement(sql));
}
return true;
}
bool DatabaseMysql::DirectExecute(const char* sql)
{
if (!mMysql)
return false;
{
// guarded block for thread-safe mySQL request
ZThread::Guard<ZThread::FastMutex> query_connection_guard(mMutex);
#ifdef MANGOS_DEBUG
uint32 _s = getMSTime();
#endif
if(mysql_query(mMysql, sql))
{
sLog.outErrorDb("SQL: %s", sql);
sLog.outErrorDb("SQL ERROR: %s", mysql_error(mMysql));
return false;
}
else
{
#ifdef MANGOS_DEBUG
sLog.outDebug("[%u ms] SQL: %s", getMSTimeDiff(_s,getMSTime()), sql );
#endif
}
// end guarded block
}
return true;
}
bool DatabaseMysql::_TransactionCmd(const char *sql)
{
if (mysql_query(mMysql, sql))
{
sLog.outError("SQL: %s", sql);
sLog.outError("SQL ERROR: %s", mysql_error(mMysql));
return false;
}
else
{
DEBUG_LOG("SQL: %s", sql);
}
return true;
}
bool DatabaseMysql::BeginTransaction()
{
if (!mMysql)
return false;
// don't use queued execution if it has not been initialized
if (!m_threadBody)
{
if (tranThread==ZThread::ThreadImpl::current())
return false; // huh? this thread already started transaction
mMutex.acquire();
if (!_TransactionCmd("START TRANSACTION"))
{
mMutex.release(); // can't start transaction
return false;
}
return true; // transaction started
}
tranThread = ZThread::ThreadImpl::current(); // owner of this transaction
TransactionQueues::iterator i = m_tranQueues.find(tranThread);
if (i != m_tranQueues.end() && i->second != NULL)
// If for thread exists queue and also contains transaction
// delete that transaction (not allow trans in trans)
delete i->second;
m_tranQueues[tranThread] = new SqlTransaction();
return true;
}
bool DatabaseMysql::CommitTransaction()
{
if (!mMysql)
return false;
// don't use queued execution if it has not been initialized
if (!m_threadBody)
{
if (tranThread!=ZThread::ThreadImpl::current())
return false;
bool _res = _TransactionCmd("COMMIT");
tranThread = NULL;
mMutex.release();
return _res;
}
tranThread = ZThread::ThreadImpl::current();
TransactionQueues::iterator i = m_tranQueues.find(tranThread);
if (i != m_tranQueues.end() && i->second != NULL)
{
m_threadBody->Delay(i->second);
i->second = NULL;
return true;
}
else
return false;
}
bool DatabaseMysql::RollbackTransaction()
{
if (!mMysql)
return false;
// don't use queued execution if it has not been initialized
if (!m_threadBody)
{
if (tranThread!=ZThread::ThreadImpl::current())
return false;
bool _res = _TransactionCmd("ROLLBACK");
tranThread = NULL;
mMutex.release();
return _res;
}
tranThread = ZThread::ThreadImpl::current();
TransactionQueues::iterator i = m_tranQueues.find(tranThread);
if (i != m_tranQueues.end() && i->second != NULL)
{
delete i->second;
i->second = NULL;
}
return true;
}
unsigned long DatabaseMysql::escape_string(char *to, const char *from, unsigned long length)
{
if (!mMysql || !to || !from || !length)
return 0;
return(mysql_real_escape_string(mMysql, to, from, length));
}
void DatabaseMysql::InitDelayThread()
{
assert(!m_delayThread);
//New delay thread for delay execute
m_delayThread = new ZThread::Thread(m_threadBody = new MySQLDelayThread(this));
}
void DatabaseMysql::HaltDelayThread()
{
if (!m_threadBody || !m_delayThread) return;
m_threadBody->Stop(); //Stop event
m_delayThread->wait(); //Wait for flush to DB
delete m_delayThread; //This also deletes m_threadBody
m_delayThread = NULL;
m_threadBody = NULL;
}
#endif

View file

@ -0,0 +1,77 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef DO_POSTGRESQL
#ifndef _DATABASEMYSQL_H
#define _DATABASEMYSQL_H
#include "Database.h"
#include "Policies/Singleton.h"
#include "zthread/FastMutex.h"
#ifdef WIN32
#define FD_SETSIZE 1024
#include <winsock2.h>
#include <mysql/mysql.h>
#else
#include <mysql.h>
#endif
class MANGOS_DLL_SPEC DatabaseMysql : public Database
{
friend class MaNGOS::OperatorNew<DatabaseMysql>;
public:
DatabaseMysql();
~DatabaseMysql();
//! Initializes Mysql and connects to a server.
/*! infoString should be formated like hostname;username;password;database. */
bool Initialize(const char *infoString);
void InitDelayThread();
void HaltDelayThread();
QueryResult* Query(const char *sql);
bool Execute(const char *sql);
bool DirectExecute(const char* sql);
bool BeginTransaction();
bool CommitTransaction();
bool RollbackTransaction();
operator bool () const { return mMysql != NULL; }
unsigned long escape_string(char *to, const char *from, unsigned long length);
using Database::escape_string;
// must be call before first query in thread
void ThreadStart();
// must be call before finish thread run
void ThreadEnd();
private:
ZThread::FastMutex mMutex;
ZThread::ThreadImpl* tranThread;
MYSQL *mMysql;
static size_t db_count;
bool _TransactionCmd(const char *sql);
};
#endif
#endif

View file

@ -0,0 +1,345 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifdef DO_POSTGRESQL
#include "Util.h"
#include "Policies/SingletonImp.h"
#include "Platform/Define.h"
#include "../src/zthread/ThreadImpl.h"
#include "DatabaseEnv.h"
#include "Database/PGSQLDelayThread.h"
#include "Database/SqlOperations.h"
#include "Timer.h"
void DatabasePostgre::ThreadStart()
{
}
void DatabasePostgre::ThreadEnd()
{
}
size_t DatabasePostgre::db_count = 0;
DatabasePostgre::DatabasePostgre() : Database(), mPGconn(NULL)
{
// before first connection
if( db_count++ == 0 )
{
if (!PQisthreadsafe())
{
sLog.outError("FATAL ERROR: PostgreSQL libpq isn't thread-safe.");
exit(1);
}
}
}
DatabasePostgre::~DatabasePostgre()
{
if (m_delayThread)
HaltDelayThread();
if( mPGconn )
{
PQfinish(mPGconn);
mPGconn = NULL;
}
}
bool DatabasePostgre::Initialize(const char *infoString)
{
if(!Database::Initialize(infoString))
return false;
tranThread = NULL;
InitDelayThread();
Tokens tokens = StrSplit(infoString, ";");
Tokens::iterator iter;
std::string host, port_or_socket, user, password, database;
iter = tokens.begin();
if(iter != tokens.end())
host = *iter++;
if(iter != tokens.end())
port_or_socket = *iter++;
if(iter != tokens.end())
user = *iter++;
if(iter != tokens.end())
password = *iter++;
if(iter != tokens.end())
database = *iter++;
mPGconn = PQsetdbLogin(host.c_str(), port_or_socket.c_str(), NULL, NULL, database.c_str(), user.c_str(), password.c_str());
/* check to see that the backend connection was successfully made */
if (PQstatus(mPGconn) != CONNECTION_OK)
{
sLog.outError( "Could not connect to Postgre database at %s: %s",
host.c_str(), PQerrorMessage(mPGconn));
PQfinish(mPGconn);
return false;
}
else
{
sLog.outDetail( "Connected to Postgre database at %s",
host.c_str());
sLog.outString( "PostgreSQL server ver: %d",PQserverVersion(mPGconn));
return true;
}
}
QueryResult* DatabasePostgre::Query(const char *sql)
{
if (!mPGconn)
return 0;
uint64 rowCount = 0;
uint32 fieldCount = 0;
// guarded block for thread-safe request
ZThread::Guard<ZThread::FastMutex> query_connection_guard(mMutex);
#ifdef MANGOS_DEBUG
uint32 _s = getMSTime();
#endif
// Send the query
PGresult * result = PQexec(mPGconn, sql);
if (!result )
{
return NULL;
}
if (PQresultStatus(result) != PGRES_TUPLES_OK)
{
sLog.outErrorDb( "SQL : %s", sql );
sLog.outErrorDb( "SQL %s", PQerrorMessage(mPGconn));
PQclear(result);
return NULL;
}
else
{
#ifdef MANGOS_DEBUG
sLog.outDebug("[%u ms] SQL: %s", getMSTime() - _s, sql );
#endif
}
rowCount = PQntuples(result);
fieldCount = PQnfields(result);
// end guarded block
if (!rowCount)
{
PQclear(result);
return NULL;
}
QueryResultPostgre * queryResult = new QueryResultPostgre(result, rowCount, fieldCount);
queryResult->NextRow();
return queryResult;
}
bool DatabasePostgre::Execute(const char *sql)
{
if (!mPGconn)
return false;
// don't use queued execution if it has not been initialized
if (!m_threadBody) return DirectExecute(sql);
tranThread = ZThread::ThreadImpl::current(); // owner of this transaction
TransactionQueues::iterator i = m_tranQueues.find(tranThread);
if (i != m_tranQueues.end() && i->second != NULL)
{ // Statement for transaction
i->second->DelayExecute(sql);
}
else
{
// Simple sql statement
m_threadBody->Delay(new SqlStatement(sql));
}
return true;
}
bool DatabasePostgre::DirectExecute(const char* sql)
{
if (!mPGconn)
return false;
{
// guarded block for thread-safe request
ZThread::Guard<ZThread::FastMutex> query_connection_guard(mMutex);
#ifdef MANGOS_DEBUG
uint32 _s = getMSTime();
#endif
PGresult *res = PQexec(mPGconn, sql);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
sLog.outErrorDb( "SQL: %s", sql );
sLog.outErrorDb( "SQL %s", PQerrorMessage(mPGconn) );
return false;
}
else
{
#ifdef MANGOS_DEBUG
sLog.outDebug("[%u ms] SQL: %s", getMSTime() - _s, sql );
#endif
}
PQclear(res);
// end guarded block
}
return true;
}
bool DatabasePostgre::_TransactionCmd(const char *sql)
{
if (!mPGconn)
return false;
PGresult *res = PQexec(mPGconn, sql);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
sLog.outError("SQL: %s", sql);
sLog.outError("SQL ERROR: %s", PQerrorMessage(mPGconn));
return false;
}
else
{
DEBUG_LOG("SQL: %s", sql);
}
return true;
}
bool DatabasePostgre::BeginTransaction()
{
if (!mPGconn)
return false;
// don't use queued execution if it has not been initialized
if (!m_threadBody)
{
if (tranThread==ZThread::ThreadImpl::current())
return false; // huh? this thread already started transaction
mMutex.acquire();
if (!_TransactionCmd("START TRANSACTION"))
{
mMutex.release(); // can't start transaction
return false;
}
return true;
}
// transaction started
tranThread = ZThread::ThreadImpl::current(); // owner of this transaction
TransactionQueues::iterator i = m_tranQueues.find(tranThread);
if (i != m_tranQueues.end() && i->second != NULL)
// If for thread exists queue and also contains transaction
// delete that transaction (not allow trans in trans)
delete i->second;
m_tranQueues[tranThread] = new SqlTransaction();
return true;
}
bool DatabasePostgre::CommitTransaction()
{
if (!mPGconn)
return false;
// don't use queued execution if it has not been initialized
if (!m_threadBody)
{
if (tranThread!=ZThread::ThreadImpl::current())
return false;
bool _res = _TransactionCmd("COMMIT");
tranThread = NULL;
mMutex.release();
return _res;
}
tranThread = ZThread::ThreadImpl::current();
TransactionQueues::iterator i = m_tranQueues.find(tranThread);
if (i != m_tranQueues.end() && i->second != NULL)
{
m_threadBody->Delay(i->second);
i->second = NULL;
return true;
}
else
return false;
}
bool DatabasePostgre::RollbackTransaction()
{
if (!mPGconn)
return false;
// don't use queued execution if it has not been initialized
if (!m_threadBody)
{
if (tranThread!=ZThread::ThreadImpl::current())
return false;
bool _res = _TransactionCmd("ROLLBACK");
tranThread = NULL;
mMutex.release();
return _res;
}
tranThread = ZThread::ThreadImpl::current();
TransactionQueues::iterator i = m_tranQueues.find(tranThread);
if (i != m_tranQueues.end() && i->second != NULL)
{
delete i->second;
i->second = NULL;
}
return true;
}
unsigned long DatabasePostgre::escape_string(char *to, const char *from, unsigned long length)
{
if (!mPGconn || !to || !from || !length)
return 0;
return PQescapeString(to, from, length);
}
void DatabasePostgre::InitDelayThread()
{
assert(!m_delayThread);
//New delay thread for delay execute
m_delayThread = new ZThread::Thread(m_threadBody = new PGSQLDelayThread(this));
}
void DatabasePostgre::HaltDelayThread()
{
if (!m_threadBody || !m_delayThread) return;
m_threadBody->Stop(); //Stop event
m_delayThread->wait(); //Wait for flush to DB
delete m_delayThread; //This also deletes m_threadBody
m_delayThread = NULL;
m_threadBody = NULL;
}
#endif

View file

@ -0,0 +1,75 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef _DatabasePostgre_H
#define _DatabasePostgre_H
#include "Policies/Singleton.h"
#include "zthread/FastMutex.h"
#include <stdarg.h>
#ifdef WIN32
#define FD_SETSIZE 1024
#include <winsock2.h>
#include <postgre/libpq-fe.h>
#else
#include <libpq-fe.h>
#endif
class DatabasePostgre : public Database
{
friend class MaNGOS::OperatorNew<DatabasePostgre>;
public:
DatabasePostgre();
~DatabasePostgre();
//! Initializes Postgres and connects to a server.
/*! infoString should be formated like hostname;username;password;database. */
bool Initialize(const char *infoString);
void InitDelayThread();
void HaltDelayThread();
QueryResult* Query(const char *sql);
bool Execute(const char *sql);
bool DirectExecute(const char* sql);
bool BeginTransaction();
bool CommitTransaction();
bool RollbackTransaction();
operator bool () const { return mPGconn != NULL; }
unsigned long escape_string(char *to, const char *from, unsigned long length);
using Database::escape_string;
// must be call before first query in thread
void ThreadStart();
// must be call before finish thread run
void ThreadEnd();
private:
ZThread::FastMutex mMutex;
ZThread::FastMutex tranMutex;
ZThread::ThreadImpl* tranThread;
PGconn *mPGconn;
static size_t db_count;
bool _TransactionCmd(const char *sql);
};
#endif

View file

@ -0,0 +1,101 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef DO_POSTGRESQL
#include "DatabaseEnv.h"
DatabaseSqlite::DatabaseSqlite() : Database(), mSqlite(0)
{
}
DatabaseSqlite::~DatabaseSqlite()
{
if (mSqlite)
sqlite_close(mSqlite);
}
bool DatabaseSqlite::Initialize(const char *infoString)
{
if(!Database::Initialize(infoString))
return false;
char *errmsg;
mSqlite = sqlite_open(infoString, 0, &errmsg);
if (!mSqlite)
{
if (errmsg)
sqlite_freemem(errmsg);
return false;
}
return true;
}
QueryResult* DatabaseSqlite::Query(const char *sql)
{
char *errmsg;
if (!mSqlite)
return 0;
char **tableData;
int rowCount;
int fieldCount;
sqlite_get_table(mSqlite, sql, &tableData, &rowCount, &fieldCount, &errmsg);
if (!rowCount)
return 0;
if (!tableData)
{
if (errmsg)
sqlite_freemem(errmsg);
return 0;
}
QueryResultSqlite *queryResult = new QueryResultSqlite(tableData, rowCount, fieldCount);
if(!queryResult)
{
return 0;
}
queryResult->NextRow();
return queryResult;
}
bool DatabaseSqlite::Execute(const char *sql)
{
char *errmsg;
if (!mSqlite)
return false;
if(sqlite_exec(mSqlite, sql, NULL, NULL, &errmsg) != SQLITE_OK)
return false;
return true;
}
#endif

View file

@ -0,0 +1,43 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef DO_POSTGRESQL
#ifndef _DATABASESQLITE_H
#define _DATABASESQLITE_H
#include <sqlite/sqlite.h>
class DatabaseSqlite : public Database
{
public:
DatabaseSqlite();
~DatabaseSqlite();
bool Initialize(const char *infoString);
QueryResult* Query(const char *sql);
bool Execute(const char *sql);
operator bool () const { return mSqlite != NULL; }
private:
sqlite *mSqlite;
};
#endif
#endif

View file

@ -0,0 +1,65 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#include "DatabaseEnv.h"
Field::Field() :
mValue(NULL), mType(DB_TYPE_UNKNOWN)
{
}
Field::Field(Field &f)
{
const char *value;
value = f.GetString();
if (value && (mValue = new char[strlen(value) + 1]))
strcpy(mValue, value);
else
mValue = NULL;
mType = f.GetType();
}
Field::Field(const char *value, enum Field::DataTypes type) :
mType(type)
{
if (value && (mValue = new char[strlen(value) + 1]))
strcpy(mValue, value);
else
mValue = NULL;
}
Field::~Field()
{
if(mValue) delete [] mValue;
}
void Field::SetValue(const char *value)
{
if(mValue) delete [] mValue;
if (value)
{
mValue = new char[strlen(value) + 1];
strcpy(mValue, value);
}
else
mValue = NULL;
}

View file

@ -0,0 +1,75 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#if !defined(FIELD_H)
#define FIELD_H
class Field
{
public:
enum DataTypes
{
DB_TYPE_UNKNOWN = 0x00,
DB_TYPE_STRING = 0x01,
DB_TYPE_INTEGER = 0x02,
DB_TYPE_FLOAT = 0x03,
DB_TYPE_BOOL = 0x04
};
Field();
Field(Field &f);
Field(const char *value, enum DataTypes type);
~Field();
enum DataTypes GetType() const { return mType; }
const char *GetString() const { return mValue; }
std::string GetCppString() const
{
return mValue ? mValue : ""; // std::string s = 0 have undefine result in C++
}
float GetFloat() const { return mValue ? static_cast<float>(atof(mValue)) : 0.0f; }
bool GetBool() const { return mValue ? atoi(mValue) > 0 : false; }
int32 GetInt32() const { return mValue ? static_cast<int32>(atol(mValue)) : int32(0); }
uint8 GetUInt8() const { return mValue ? static_cast<uint8>(atol(mValue)) : uint8(0); }
uint16 GetUInt16() const { return mValue ? static_cast<uint16>(atol(mValue)) : uint16(0); }
int16 GetInt16() const { return mValue ? static_cast<int16>(atol(mValue)) : int16(0); }
uint32 GetUInt32() const { return mValue ? static_cast<uint32>(atol(mValue)) : uint32(0); }
uint64 GetUInt64() const
{
if(mValue)
{
uint64 value;
sscanf(mValue,I64FMTD,&value);
return value;
}
else
return 0;
}
void SetType(enum DataTypes type) { mType = type; }
void SetValue(const char *value);
private:
char *mValue;
enum DataTypes mType;
};
#endif

View file

@ -0,0 +1,63 @@
# Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
#
# 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
## Process this file with automake to produce Makefile.in
## Sub-directories to parse
## CPP flags for includes, defines, etc.
AM_CPPFLAGS = $(MANGOS_INCLUDES) -I$(top_builddir)/src/shared -I$(srcdir) -I$(srcdir)/../../../dep/include -I$(srcdir)/../../framework -I$(srcdir)/../../shared -I$(srcdir)/../../../dep/include/g3dlite
## Build MaNGOS shared library and its parts as convenience library.
# All libraries will be convenience libraries. Might be changed to shared
# later.
noinst_LIBRARIES = libmangosdatabase.a
libmangosdatabase_a_SOURCES = \
DBCStores.cpp \
DBCStores.h \
DBCStructure.h \
DBCfmt.cpp \
Database.cpp \
Database.h \
DatabaseEnv.h \
DatabaseImpl.h \
DatabaseMysql.cpp \
DatabasePostgre.cpp \
DatabaseMysql.h \
DatabasePostgre.h \
DatabaseSqlite.cpp \
DatabaseSqlite.h \
DBCEnums.h \
Field.cpp \
Field.h \
MySQLDelayThread.h \
PGSQLDelayThread.h \
QueryResult.h \
QueryResultMysql.cpp \
QueryResultMysql.h \
QueryResultPostgre.cpp \
QueryResultPostgre.h \
QueryResultSqlite.cpp \
QueryResultSqlite.h \
SQLStorage.cpp \
SQLStorage.h \
SqlDelayThread.cpp \
SqlDelayThread.h \
SqlOperations.cpp \
SqlOperations.h \
dbcfile.cpp \
dbcfile.h

View file

@ -0,0 +1,30 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef __MYSQLDELAYTHREAD_H
#define __MYSQLDELAYTHREAD_H
#include "Database/SqlDelayThread.h"
class MySQLDelayThread : public SqlDelayThread
{
public:
MySQLDelayThread(Database* db) : SqlDelayThread(db) {}
void Stop() { SqlDelayThread::Stop(); }
};
#endif //__MYSQLDELAYTHREAD_H

View file

@ -0,0 +1,30 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef __PGSQLDELAYTHREAD_H
#define __PGSQLDELAYTHREAD_H
#include "Database/SqlDelayThread.h"
class PGSQLDelayThread : public SqlDelayThread
{
public:
PGSQLDelayThread(Database* db) : SqlDelayThread(db) {}
void Stop() { SqlDelayThread::Stop(); }
};
#endif //__PGSQLDELAYTHREAD_H

View file

@ -0,0 +1,64 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#if !defined(QUERYRESULT_H)
#define QUERYRESULT_H
class MANGOS_DLL_SPEC QueryResult
{
public:
QueryResult(uint64 rowCount, uint32 fieldCount)
: mFieldCount(fieldCount), mRowCount(rowCount) {}
virtual ~QueryResult() {}
virtual bool NextRow() = 0;
typedef std::map<uint32, std::string> FieldNames;
uint32 GetField_idx(const std::string &name) const
{
for(FieldNames::const_iterator iter = GetFiedNames().begin(); iter != GetFiedNames().end(); ++iter)
{
if(iter->second == name)
return iter->first;
}
assert(false && "unknown field name");
return uint32(-1);
}
Field *Fetch() const { return mCurrentRow; }
const Field & operator [] (int index) const { return mCurrentRow[index]; }
const Field & operator [] (const std::string &name) const
{
return mCurrentRow[GetField_idx(name)];
}
uint32 GetFieldCount() const { return mFieldCount; }
uint64 GetRowCount() const { return mRowCount; }
FieldNames const& GetFiedNames() const {return mFieldNames; }
protected:
Field *mCurrentRow;
uint32 mFieldCount;
uint64 mRowCount;
FieldNames mFieldNames;
};
#endif

View file

@ -0,0 +1,110 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef DO_POSTGRESQL
#include "DatabaseEnv.h"
QueryResultMysql::QueryResultMysql(MYSQL_RES *result, uint64 rowCount, uint32 fieldCount) :
QueryResult(rowCount, fieldCount), mResult(result)
{
mCurrentRow = new Field[mFieldCount];
ASSERT(mCurrentRow);
MYSQL_FIELD *fields = mysql_fetch_fields(mResult);
for (uint32 i = 0; i < mFieldCount; i++)
{
mFieldNames[i] = fields[i].name;
mCurrentRow[i].SetType(ConvertNativeType(fields[i].type));
}
}
QueryResultMysql::~QueryResultMysql()
{
EndQuery();
}
bool QueryResultMysql::NextRow()
{
MYSQL_ROW row;
if (!mResult)
return false;
row = mysql_fetch_row(mResult);
if (!row)
{
EndQuery();
return false;
}
for (uint32 i = 0; i < mFieldCount; i++)
mCurrentRow[i].SetValue(row[i]);
return true;
}
void QueryResultMysql::EndQuery()
{
if (mCurrentRow)
{
delete [] mCurrentRow;
mCurrentRow = 0;
}
if (mResult)
{
mysql_free_result(mResult);
mResult = 0;
}
}
enum Field::DataTypes QueryResultMysql::ConvertNativeType(enum_field_types mysqlType) const
{
switch (mysqlType)
{
case FIELD_TYPE_TIMESTAMP:
case FIELD_TYPE_DATE:
case FIELD_TYPE_TIME:
case FIELD_TYPE_DATETIME:
case FIELD_TYPE_YEAR:
case FIELD_TYPE_STRING:
case FIELD_TYPE_VAR_STRING:
case FIELD_TYPE_BLOB:
case FIELD_TYPE_SET:
case FIELD_TYPE_NULL:
return Field::DB_TYPE_STRING;
case FIELD_TYPE_TINY:
case FIELD_TYPE_SHORT:
case FIELD_TYPE_LONG:
case FIELD_TYPE_INT24:
case FIELD_TYPE_LONGLONG:
case FIELD_TYPE_ENUM:
return Field::DB_TYPE_INTEGER;
case FIELD_TYPE_DECIMAL:
case FIELD_TYPE_FLOAT:
case FIELD_TYPE_DOUBLE:
return Field::DB_TYPE_FLOAT;
default:
return Field::DB_TYPE_UNKNOWN;
}
}
#endif

View file

@ -0,0 +1,48 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef DO_POSTGRESQL
#if !defined(QUERYRESULTMYSQL_H)
#define QUERYRESULTMYSQL_H
#ifdef WIN32
#define FD_SETSIZE 1024
#include <winsock2.h>
#include <mysql/mysql.h>
#else
#include <mysql.h>
#endif
class QueryResultMysql : public QueryResult
{
public:
QueryResultMysql(MYSQL_RES *result, uint64 rowCount, uint32 fieldCount);
~QueryResultMysql();
bool NextRow();
private:
enum Field::DataTypes ConvertNativeType(enum_field_types mysqlType) const;
void EndQuery();
MYSQL_RES *mResult;
};
#endif
#endif

View file

@ -0,0 +1,139 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifdef DO_POSTGRESQL
#include "DatabaseEnv.h"
QueryResultPostgre::QueryResultPostgre(PGresult *result, uint64 rowCount, uint32 fieldCount) :
QueryResult(rowCount, fieldCount), mResult(result), mTableIndex(0)
{
mCurrentRow = new Field[mFieldCount];
ASSERT(mCurrentRow);
for (uint32 i = 0; i < mFieldCount; i++)
{
mFieldNames[i] = PQfname(result, i);
mCurrentRow[i].SetType(ConvertNativeType(PQftype( result, i )));
}
}
QueryResultPostgre::~QueryResultPostgre()
{
EndQuery();
}
bool QueryResultPostgre::NextRow()
{
if (!mResult)
return false;
if (mTableIndex >= mRowCount)
{
EndQuery();
return false;
}
char* pPQgetvalue;
for (int j = 0; j < mFieldCount; j++)
{
pPQgetvalue = PQgetvalue(mResult, mTableIndex, j);
if(pPQgetvalue && !(*pPQgetvalue))
pPQgetvalue = NULL;
mCurrentRow[j].SetValue(pPQgetvalue);
}
++mTableIndex;
return true;
}
void QueryResultPostgre::EndQuery()
{
if (mCurrentRow)
{
delete [] mCurrentRow;
mCurrentRow = 0;
}
if (mResult)
{
PQclear(mResult);
mResult = 0;
}
}
// see types in #include <postgre/pg_type.h>
enum Field::DataTypes QueryResultPostgre::ConvertNativeType(Oid pOid ) const
{
switch (pOid)
{
case BPCHAROID:
case CIDOID:
case CIDROID:
case CIRCLEOID:
case INETOID:
case NAMEOID:
case TEXTOID:
case VARCHAROID:
return Field::DB_TYPE_STRING;
case CASHOID:
case FLOAT4OID:
case FLOAT8OID:
case NUMERICOID:
return Field::DB_TYPE_FLOAT;
case DATEOID: // Date
case RELTIMEOID: // Date
case TIMEOID: // Time
case TIMETZOID: // Time
case ABSTIMEOID: // DateTime
case INTERVALOID: // DateTime
case TIMESTAMPOID: // DateTime
case TIMESTAMPTZOID: // DateTime
case INT2OID: // Int
case INT2VECTOROID: // Int
case INT4OID: // Int
case OIDOID: // Int
case CHAROID: // UInt
case INT8OID: // LongLong
return Field::DB_TYPE_INTEGER;
case BOOLOID:
return Field::DB_TYPE_BOOL; // Bool
/*
case BOXOID: Rect;
case LINEOID: Rect;
case VARBITOID: BitArray;
case BYTEAOID: ByteArray;
*/
case LSEGOID:
case OIDVECTOROID:
case PATHOID:
case POINTOID:
case POLYGONOID:
case REGPROCOID:
case TIDOID:
case TINTERVALOID:
case UNKNOWNOID:
case XIDOID:
default:
return Field::DB_TYPE_UNKNOWN;
}
return Field::DB_TYPE_UNKNOWN;
}
#endif

View file

@ -0,0 +1,48 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#if !defined(QUERYRESULTPOSTGRE_H)
#define QUERYRESULTPOSTGRE_H
#ifdef WIN32
#define FD_SETSIZE 1024
#include <winsock2.h>
#include <postgre/libpq-fe.h>
#include <postgre/pg_type.h>
#else
#include <libpq-fe.h>
//#include <pg_type.h>
#endif
class QueryResultPostgre : public QueryResult
{
public:
QueryResultPostgre(PGresult *result, uint64 rowCount, uint32 fieldCount);
~QueryResultPostgre();
bool NextRow();
private:
enum Field::DataTypes ConvertNativeType(Oid pOid) const;
void EndQuery();
PGresult *mResult;
uint32 mTableIndex;
};
#endif

View file

@ -0,0 +1,96 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef DO_POSTGRESQL
#include "DatabaseEnv.h"
QueryResultSqlite::QueryResultSqlite(char **tableData, uint32 rowCount, uint32 fieldCount) :
QueryResult(rowCount, fieldCount), mTableData(tableData), mTableIndex(0)
{
mCurrentRow = new Field[mFieldCount];
for (uint32 i = 0; i < mFieldCount; i++)
{
mFieldNames[i] = mTableData[i];
mCurrentRow[i].SetType(Field::DB_TYPE_UNKNOWN);
}
}
QueryResultSqlite::~QueryResultSqlite()
{
EndQuery();
}
bool QueryResultSqlite::NextRow()
{
int startIndex;
uint32 i;
if (!mTableData)
return false;
if (mTableIndex >= mRowCount)
{
EndQuery();
return false;
}
startIndex = (mTableIndex + 1) * mFieldCount;
for (i = 0; i < mFieldCount; i++)
{
mCurrentRow[i].SetValue(mTableData[startIndex + i]);
}
++mTableIndex;
return true;
}
void QueryResultSqlite::EndQuery()
{
if (mCurrentRow)
{
delete [] mCurrentRow;
mCurrentRow = NULL;
}
if (mTableData)
{
sqlite_free_table(mTableData);
mTableData = NULL;
}
}
enum Field::DataTypes QueryResultSqlite::ConvertNativeType(const char* sqliteType) const
{
if (sqliteType)
{
switch (*sqliteType)
{
case 'S':
return Field::DB_TYPE_STRING;
case 'I':
return Field::DB_TYPE_INTEGER;
case 'F':
return Field::DB_TYPE_FLOAT;
default:
return Field::DB_TYPE_UNKNOWN;
};
}
return Field::DB_TYPE_UNKNOWN;
}
#endif

View file

@ -0,0 +1,43 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef DO_POSTGRESQL
#if !defined(QUERYRESULTSQLITE_H)
#define QUERYRESULTSQLITE_H
#include <sqlite/sqlite.h>
class QueryResultSqlite : public QueryResult
{
public:
QueryResultSqlite(char **tableData, uint32 rowCount, uint32 fieldCount);
~QueryResultSqlite();
bool NextRow();
private:
enum Field::DataTypes ConvertNativeType(const char* sqliteType) const;
void EndQuery();
char **mTableData;
uint32 mTableIndex;
};
#endif
#endif

View file

@ -0,0 +1,191 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#include "SQLStorage.h"
#include "ProgressBar.h"
#include "Log.h"
#include "dbcfile.h"
#ifdef DO_POSTGRESQL
extern DatabasePostgre WorldDatabase;
#else
extern DatabaseMysql WorldDatabase;
#endif
const char CreatureInfofmt[]="iiiiiisssiiiiiiiiiiffiffiiiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiilliiis";
const char CreatureDataAddonInfofmt[]="iiiiiiis";
const char CreatureModelfmt[]="iffbi";
const char CreatureInfoAddonInfofmt[]="iiiiiiis";
const char EquipmentInfofmt[]="iiiiiiiiii";
const char GameObjectInfofmt[]="iiissiifiiiiiiiiiiiiiiiiiiiiiiiis";
const char ItemPrototypefmt[]="iiiisiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffiffiffiffiffiiiiiiiiiifiiifiiiiiifiiiiiifiiiiiifiiiiiifiiiisiiiiiiiiiiiiiiiiiiiiiiiiifsiiiii";
const char PageTextfmt[]="isi";
const char SpellThreatfmt[]="ii";
const char InstanceTemplatefmt[]="iiiiiiffffs";
SQLStorage sCreatureStorage(CreatureInfofmt,"entry","creature_template");
SQLStorage sCreatureDataAddonStorage(CreatureDataAddonInfofmt,"guid","creature_addon");
SQLStorage sCreatureModelStorage(CreatureModelfmt,"modelid","creature_model_info");
SQLStorage sCreatureInfoAddonStorage(CreatureInfoAddonInfofmt,"entry","creature_template_addon");
SQLStorage sEquipmentStorage(EquipmentInfofmt,"entry","creature_equip_template");
SQLStorage sGOStorage(GameObjectInfofmt,"entry","gameobject_template");
SQLStorage sItemStorage(ItemPrototypefmt,"entry","item_template");
SQLStorage sPageTextStore(PageTextfmt,"entry","page_text");
SQLStorage sSpellThreatStore(SpellThreatfmt,"entry","spell_threat");
SQLStorage sInstanceTemplate(InstanceTemplatefmt,"map","instance_template");
void SQLStorage::Free ()
{
uint32 offset=0;
for(uint32 x=0;x<iNumFields;x++)
if (format[x]==FT_STRING)
{
for(uint32 y=0;y<MaxEntry;y++)
if(pIndex[y])
delete [] *(char**)((char*)(pIndex[y])+offset);
offset+=sizeof(char*);
}
else if (format[x]==FT_LOGIC)
offset+=sizeof(bool);
else if (format[x]==FT_BYTE)
offset+=sizeof(char);
else
offset+=4;
delete [] pIndex;
delete [] data;
}
void SQLStorage::Load ()
{
uint32 maxi;
Field *fields;
QueryResult *result = WorldDatabase.PQuery("SELECT MAX(%s) FROM %s",entry_field,table);
if(!result)
{
sLog.outError("Error loading %s table (not exist?)\n",table);
exit(1); // Stop server at loading non exited table or not accessable table
}
maxi= (*result)[0].GetUInt32()+1;
delete result;
result = WorldDatabase.PQuery("SELECT COUNT(*) FROM %s",table);
if(result)
{
fields = result->Fetch();
RecordCount=fields[0].GetUInt32();
delete result;
}
else
RecordCount = 0;
result = WorldDatabase.PQuery("SELECT * FROM %s",table);
if(!result)
{
sLog.outError("%s table is empty!\n",table);
RecordCount = 0;
return;
}
uint32 recordsize=0;
uint32 offset=0;
if(iNumFields!=result->GetFieldCount())
{
RecordCount = 0;
sLog.outError("Error in %s table, probably sql file format was updated (there should be %d fields in sql).\n",table,iNumFields);
delete result;
exit(1); // Stop server at loading broken or non-compatible table.
}
//get struct size
uint32 sc=0;
uint32 bo=0;
uint32 bb=0;
for(uint32 x=0;x<iNumFields;x++)
if(format[x]==FT_STRING)
++sc;
else if (format[x]==FT_LOGIC)
++bo;
else if (format[x]==FT_BYTE)
++bb;
recordsize=(iNumFields-sc-bo-bb)*4+sc*sizeof(char*)+bo*sizeof(bool)+bb*sizeof(char);
char** newIndex=new char*[maxi];
memset(newIndex,0,maxi*sizeof(char*));
char * _data= new char[RecordCount *recordsize];
uint32 count=0;
barGoLink bar( RecordCount );
do
{
fields = result->Fetch();
bar.step();
char *p=(char*)&_data[recordsize*count];
newIndex[fields[0].GetUInt32()]=p;
offset=0;
for(uint32 x=0;x<iNumFields;x++)
switch(format[x])
{
case FT_LOGIC:
*((bool*)(&p[offset]))=(fields[x].GetUInt32()>0);
offset+=sizeof(bool);
break;
case FT_BYTE:
*((char*)(&p[offset]))=(fields[x].GetUInt8());
offset+=sizeof(char);
break;
case FT_INT:
*((uint32*)(&p[offset]))=fields[x].GetUInt32();
offset+=sizeof(uint32);
break;
case FT_FLOAT:
*((float*)(&p[offset]))=fields[x].GetFloat();
offset+=sizeof(float);
break;
case FT_STRING:
char const* tmp = fields[x].GetString();
char* st;
if(!tmp)
{
st=new char[1];
*st=0;
}
else
{
uint32 l=strlen(tmp)+1;
st=new char[l];
memcpy(st,tmp,l);
}
*((char**)(&p[offset]))=st;
offset+=sizeof(char*);
break;
}
++count;
}while( result->NextRow() );
delete result;
pIndex =newIndex;
MaxEntry=maxi;
data=_data;
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef SQLSTORAGE_H
#define SQLSTORAGE_H
#include "Common.h"
#include "Database/DatabaseEnv.h"
class SQLStorage
{
public:
SQLStorage(const char*fmt,const char * _entry_field,const char * sqlname)
{
format=fmt;
entry_field = _entry_field;
table=sqlname;
data=NULL;
pIndex=NULL;
iNumFields =strlen(fmt);
MaxEntry = 0;
}
~SQLStorage()
{
Free();
}
template<class T>
T const* LookupEntry(uint32 id) const
{
if( id == 0 )
return NULL;
if(id >= MaxEntry)
return NULL;
return reinterpret_cast<T const*>(pIndex[id]);
}
uint32 RecordCount;
uint32 MaxEntry;
uint32 iNumFields;
void Load();
void Free();
private:
char** pIndex;
char *data;
const char *format;
const char *table;
const char *entry_field;
//bool HasString;
};
#endif

View file

@ -0,0 +1,55 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#include "Database/SqlDelayThread.h"
#include "Database/SqlOperations.h"
#include "DatabaseEnv.h"
SqlDelayThread::SqlDelayThread(Database* db) : m_dbEngine(db), m_running(true)
{
}
void SqlDelayThread::run()
{
SqlOperation* s;
#ifndef DO_POSTGRESQL
mysql_thread_init();
#endif
while (m_running)
{
// if the running state gets turned off while sleeping
// empty the queue before exiting
ZThread::Thread::sleep(10);
while (!m_sqlQueue.empty())
{
s = m_sqlQueue.next();
s->Execute(m_dbEngine);
delete s;
}
}
#ifndef DO_POSTGRESQL
mysql_thread_end();
#endif
}
void SqlDelayThread::Stop()
{
m_running = false;
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef __SQLDELAYTHREAD_H
#define __SQLDELAYTHREAD_H
#include "zthread/Thread.h"
#include "zthread/Runnable.h"
#include "zthread/FastMutex.h"
#include "zthread/LockedQueue.h"
class Database;
class SqlOperation;
class SqlDelayThread : public ZThread::Runnable
{
typedef ZThread::LockedQueue<SqlOperation*, ZThread::FastMutex> SqlQueue;
private:
SqlQueue m_sqlQueue; ///< Queue of SQL statements
Database* m_dbEngine; ///< Pointer to used Database engine
bool m_running;
SqlDelayThread();
public:
SqlDelayThread(Database* db);
///< Put sql statement to delay queue
inline void Delay(SqlOperation* sql) { m_sqlQueue.add(sql); }
virtual void Stop(); ///< Stop event
virtual void run(); ///< Main Thread loop
};
#endif //__SQLDELAYTHREAD_H

View file

@ -0,0 +1,197 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#include "SqlOperations.h"
#include "SqlDelayThread.h"
#include "DatabaseEnv.h"
#include "DatabaseImpl.h"
/// ---- ASYNC STATEMENTS / TRANSACTIONS ----
void SqlStatement::Execute(Database *db)
{
/// just do it
db->DirectExecute(m_sql);
}
void SqlTransaction::Execute(Database *db)
{
if(m_queue.empty())
return;
db->DirectExecute("START TRANSACTION");
while(!m_queue.empty())
{
char const *sql = m_queue.front();
m_queue.pop();
if(!db->DirectExecute(sql))
{
free((void*)const_cast<char*>(sql));
db->DirectExecute("ROLLBACK");
while(!m_queue.empty())
{
free((void*)const_cast<char*>(m_queue.front()));
m_queue.pop();
}
return;
}
free((void*)const_cast<char*>(sql));
}
db->DirectExecute("COMMIT");
}
/// ---- ASYNC QUERIES ----
void SqlQuery::Execute(Database *db)
{
if(!m_callback || !m_queue)
return;
/// execute the query and store the result in the callback
m_callback->SetResult(db->Query(m_sql));
/// add the callback to the sql result queue of the thread it originated from
m_queue->add(m_callback);
}
void SqlResultQueue::Update()
{
/// execute the callbacks waiting in the synchronization queue
while(!empty())
{
MaNGOS::IQueryCallback * callback = next();
callback->Execute();
delete callback;
}
}
void SqlQueryHolder::Execute(MaNGOS::IQueryCallback * callback, SqlDelayThread *thread, SqlResultQueue *queue)
{
if(!callback || !thread || !queue)
return;
/// delay the execution of the queries, sync them with the delay thread
/// which will in turn resync on execution (via the queue) and call back
SqlQueryHolderEx *holderEx = new SqlQueryHolderEx(this, callback, queue);
thread->Delay(holderEx);
}
bool SqlQueryHolder::SetQuery(size_t index, const char *sql)
{
if(m_queries.size() <= index)
{
sLog.outError("Query index (%u) out of range (size: %u) for query: %s",index,m_queries.size(),sql);
return false;
}
if(m_queries[index].first != NULL)
{
sLog.outError("Attempt assign query to holder index (%u) where other query stored (Old: [%s] New: [%s])",index,m_queries.size(),m_queries[index].first,sql);
return false;
}
/// not executed yet, just stored (it's not called a holder for nothing)
m_queries[index] = SqlResultPair(strdup(sql), NULL);
return true;
}
bool SqlQueryHolder::SetPQuery(size_t index, const char *format, ...)
{
if(!format)
{
sLog.outError("Query (index: %u) is empty.",index);
return false;
}
va_list ap;
char szQuery [MAX_QUERY_LEN];
va_start(ap, format);
int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
va_end(ap);
if(res==-1)
{
sLog.outError("SQL Query truncated (and not execute) for format: %s",format);
return false;
}
return SetQuery(index,szQuery);
}
QueryResult* SqlQueryHolder::GetResult(size_t index)
{
if(index < m_queries.size())
{
/// the query strings are freed on the first GetResult or in the destructor
if(m_queries[index].first != NULL)
{
free((void*)(const_cast<char*>(m_queries[index].first)));
m_queries[index].first = NULL;
}
/// when you get a result aways remember to delete it!
return m_queries[index].second;
}
else
return NULL;
}
void SqlQueryHolder::SetResult(size_t index, QueryResult *result)
{
/// store the result in the holder
if(index < m_queries.size())
m_queries[index].second = result;
}
SqlQueryHolder::~SqlQueryHolder()
{
for(size_t i = 0; i < m_queries.size(); i++)
{
/// if the result was never used, free the resources
/// results used already (getresult called) are expected to be deleted
if(m_queries[i].first != NULL)
{
free((void*)(const_cast<char*>(m_queries[i].first)));
if(m_queries[i].second)
delete m_queries[i].second;
}
}
}
void SqlQueryHolder::SetSize(size_t size)
{
/// to optimize push_back, reserve the number of queries about to be executed
m_queries.resize(size);
}
void SqlQueryHolderEx::Execute(Database *db)
{
if(!m_holder || !m_callback || !m_queue)
return;
/// we can do this, we are friends
std::vector<SqlQueryHolder::SqlResultPair> &queries = m_holder->m_queries;
for(size_t i = 0; i < queries.size(); i++)
{
/// execute all queries in the holder and pass the results
char const *sql = queries[i].first;
if(sql) m_holder->SetResult(i, db->Query(sql));
}
/// sync with the caller thread
m_queue->add(m_callback);
}

View file

@ -0,0 +1,121 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef __SQLOPERATIONS_H
#define __SQLOPERATIONS_H
#include "Common.h"
#include "zthread/LockedQueue.h"
#include "zthread/FastMutex.h"
#include "zthread/Thread.h"
#include <queue>
#include "Utilities/Callback.h"
/// ---- BASE ---
class Database;
class SqlDelayThread;
class SqlOperation
{
public:
virtual void OnRemove() { delete this; }
virtual void Execute(Database *db) = 0;
virtual ~SqlOperation() {}
};
/// ---- ASYNC STATEMENTS / TRANSACTIONS ----
class SqlStatement : public SqlOperation
{
private:
const char *m_sql;
public:
SqlStatement(const char *sql) : m_sql(strdup(sql)){}
~SqlStatement() { void* tofree = const_cast<char*>(m_sql); free(tofree); }
void Execute(Database *db);
};
class SqlTransaction : public SqlOperation
{
private:
std::queue<const char *> m_queue;
public:
SqlTransaction() {}
void DelayExecute(const char *sql) { m_queue.push(strdup(sql)); }
void Execute(Database *db);
};
/// ---- ASYNC QUERIES ----
class SqlQuery; /// contains a single async query
class QueryResult; /// the result of one
class SqlResultQueue; /// queue for thread sync
class SqlQueryHolder; /// groups several async quries
class SqlQueryHolderEx; /// points to a holder, added to the delay thread
class SqlResultQueue : public ZThread::LockedQueue<MaNGOS::IQueryCallback*, ZThread::FastMutex>
{
public:
SqlResultQueue() {}
void Update();
};
class SqlQuery : public SqlOperation
{
private:
const char *m_sql;
MaNGOS::IQueryCallback * m_callback;
SqlResultQueue * m_queue;
public:
SqlQuery(const char *sql, MaNGOS::IQueryCallback * callback, SqlResultQueue * queue)
: m_sql(strdup(sql)), m_callback(callback), m_queue(queue) {}
~SqlQuery() { void* tofree = const_cast<char*>(m_sql); free(tofree); }
void Execute(Database *db);
};
class SqlQueryHolder
{
friend class SqlQueryHolderEx;
private:
typedef std::pair<const char*, QueryResult*> SqlResultPair;
std::vector<SqlResultPair> m_queries;
public:
SqlQueryHolder() {}
~SqlQueryHolder();
bool SetQuery(size_t index, const char *sql);
bool SetPQuery(size_t index, const char *format, ...) ATTR_PRINTF(3,4);
void SetSize(size_t size);
QueryResult* GetResult(size_t index);
void SetResult(size_t index, QueryResult *result);
void Execute(MaNGOS::IQueryCallback * callback, SqlDelayThread *thread, SqlResultQueue *queue);
};
class SqlQueryHolderEx : public SqlOperation
{
private:
SqlQueryHolder * m_holder;
MaNGOS::IQueryCallback * m_callback;
SqlResultQueue * m_queue;
public:
SqlQueryHolderEx(SqlQueryHolder *holder, MaNGOS::IQueryCallback * callback, SqlResultQueue * queue)
: m_holder(holder), m_callback(callback), m_queue(queue) {}
void Execute(Database *db);
};
#endif //__SQLOPERATIONS_H

View file

@ -0,0 +1,243 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dbcfile.h"
DBCFile::DBCFile()
{
data = NULL;
fieldsOffset = NULL;
}
bool DBCFile::Load(const char *filename, const char *fmt)
{
uint32 header;
if(data)
{
delete [] data;
data=NULL;
}
FILE * f=fopen(filename,"rb");
if(!f)return false;
fread(&header,4,1,f); // Number of records
EndianConvert(header);
if(header!=0x43424457)
{
//printf("not dbc file");
return false; //'WDBC'
}
fread(&recordCount,4,1,f); // Number of records
EndianConvert(recordCount);
fread(&fieldCount,4,1,f); // Number of fields
EndianConvert(fieldCount);
fread(&recordSize,4,1,f); // Size of a record
EndianConvert(recordSize);
fread(&stringSize,4,1,f); // String size
EndianConvert(stringSize);
fieldsOffset = new uint32[fieldCount];
fieldsOffset[0] = 0;
for(uint32 i = 1; i < fieldCount; i++)
{
fieldsOffset[i] = fieldsOffset[i - 1];
if (fmt[i - 1] == 'b' || fmt[i - 1] == 'X') // byte fields
fieldsOffset[i] += 1;
else // 4 byte fields (int32/float/strings)
fieldsOffset[i] += 4;
}
data = new unsigned char[recordSize*recordCount+stringSize];
stringTable = data + recordSize*recordCount;
fread(data,recordSize*recordCount+stringSize,1,f);
fclose(f);
return true;
}
DBCFile::~DBCFile()
{
if(data)
delete [] data;
if(fieldsOffset)
delete [] fieldsOffset;
}
DBCFile::Record DBCFile::getRecord(size_t id)
{
assert(data);
return Record(*this, data + id*recordSize);
}
uint32 DBCFile::GetFormatRecordSize(const char * format,int32* index_pos)
{
uint32 recordsize = 0;
int32 i = -1;
for(uint32 x=0; format[x];++x)
switch(format[x])
{
case FT_FLOAT:
case FT_INT:
recordsize+=4;
break;
case FT_STRING:
recordsize+=sizeof(char*);
break;
case FT_SORT:
i=x;
break;
case FT_IND:
i=x;
recordsize+=4;
break;
case FT_BYTE:
recordsize += 1;
break;
}
if(index_pos)
*index_pos = i;
return recordsize;
}
char* DBCFile::AutoProduceData(const char* format, uint32& records, char**& indexTable)
{
/*
format STRING, NA, FLOAT,NA,INT <=>
struct{
char* field0,
float field1,
int field2
}entry;
this func will generate entry[rows] data;
*/
typedef char * ptr;
if(strlen(format)!=fieldCount)
return NULL;
//get struct size and index pos
int32 i;
uint32 recordsize=GetFormatRecordSize(format,&i);
if(i>=0)
{
uint32 maxi=0;
//find max index
for(uint32 y=0;y<recordCount;y++)
{
uint32 ind=getRecord(y).getUInt (i);
if(ind>maxi)maxi=ind;
}
++maxi;
records=maxi;
indexTable=new ptr[maxi];
memset(indexTable,0,maxi*sizeof(ptr));
}
else
{
records = recordCount;
indexTable = new ptr[recordCount];
}
char* dataTable= new char[recordCount*recordsize];
uint32 offset=0;
for(uint32 y =0;y<recordCount;y++)
{
if(i>=0)
{
indexTable[getRecord(y).getUInt(i)]=&dataTable[offset];
}
else
indexTable[y]=&dataTable[offset];
for(uint32 x=0;x<fieldCount;x++)
{
switch(format[x])
{
case FT_FLOAT:
*((float*)(&dataTable[offset]))=getRecord(y).getFloat(x);
offset+=4;
break;
case FT_IND:
case FT_INT:
*((uint32*)(&dataTable[offset]))=getRecord(y).getUInt(x);
offset+=4;
break;
case FT_BYTE:
*((uint8*)(&dataTable[offset]))=getRecord(y).getUInt8(x);
offset+=1;
break;
case FT_STRING:
*((char**)(&dataTable[offset]))=NULL; // will be replaces non-empty or "" strings in AutoProduceStrings
offset+=sizeof(char*);
break;
}
}
}
return dataTable;
}
char* DBCFile::AutoProduceStrings(const char* format, char* dataTable)
{
if(strlen(format)!=fieldCount)
return NULL;
char* stringPool= new char[stringSize];
memcpy(stringPool,stringTable,stringSize);
uint32 offset=0;
for(uint32 y =0;y<recordCount;y++)
{
for(uint32 x=0;x<fieldCount;x++)
switch(format[x])
{
case FT_FLOAT:
case FT_IND:
case FT_INT:
offset+=4;
break;
case FT_BYTE:
offset+=1;
break;
case FT_STRING:
// fill only not filled entries
char** slot = (char**)(&dataTable[offset]);
if(!*slot || !**slot)
{
const char * st = getRecord(y).getString(x);
*slot=stringPool+(st-(const char*)stringTable);
}
offset+=sizeof(char*);
break;
}
}
return stringPool;
}

View file

@ -0,0 +1,107 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef DBCFILE_H
#define DBCFILE_H
#include "Platform/Define.h"
#include "Utilities/ByteConverter.h"
#include <cassert>
enum
{
FT_NA='x', //not used or unknown, 4 byte size
FT_NA_BYTE='X', //not used or unknown, byte
FT_STRING='s', //char*
FT_FLOAT='f', //float
FT_INT='i', //uint32
FT_BYTE='b', //uint8
FT_SORT='d', //sorted by this field, field is not included
FT_IND='n', //the same,but parsed to data
FT_LOGIC='l' //Logical (boolean)
};
class DBCFile
{
public:
DBCFile();
~DBCFile();
bool Load(const char *filename, const char *fmt);
class Record
{
public:
float getFloat(size_t field) const
{
assert(field < file.fieldCount);
float val = *reinterpret_cast<float*>(offset+file.GetOffset(field));
EndianConvert(val);
return val;
}
uint32 getUInt(size_t field) const
{
assert(field < file.fieldCount);
uint32 val = *reinterpret_cast<uint32*>(offset+file.GetOffset(field));
EndianConvert(val);
return val;
}
uint8 getUInt8(size_t field) const
{
assert(field < file.fieldCount);
return *reinterpret_cast<uint8*>(offset+file.GetOffset(field));
}
const char *getString(size_t field) const
{
assert(field < file.fieldCount);
size_t stringOffset = getUInt(field);
assert(stringOffset < file.stringSize);
return reinterpret_cast<char*>(file.stringTable + stringOffset);
}
private:
Record(DBCFile &file_, unsigned char *offset_): offset(offset_), file(file_) {}
unsigned char *offset;
DBCFile &file;
friend class DBCFile;
};
// Get record by id
Record getRecord(size_t id);
/// Get begin iterator over records
uint32 GetNumRows() const { return recordCount;}
uint32 GetCols() const { return fieldCount; }
uint32 GetOffset(size_t id) const { return (fieldsOffset != NULL && id < fieldCount) ? fieldsOffset[id] : 0; }
bool IsLoaded() {return (data!=NULL);}
char* AutoProduceData(const char* fmt, uint32& count, char**& indexTable);
char* AutoProduceStrings(const char* fmt, char* dataTable);
static uint32 GetFormatRecordSize(const char * format, int32 * index_pos = NULL);
private:
uint32 recordSize;
uint32 recordCount;
uint32 fieldCount;
uint32 stringSize;
uint32 *fieldsOffset;
unsigned char *data;
unsigned char *stringTable;
};
#endif

29
src/shared/Errors.h Normal file
View file

@ -0,0 +1,29 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef MANGOSSERVER_ERRORS_H
#define MANGOSSERVER_ERRORS_H
#define WPAssert( assertion ) { if( !(assertion) ) { fprintf( stderr, "\n%s:%i ASSERTION FAILED:\n %s\n", __FILE__, __LINE__, #assertion ); assert( #assertion &&0 ); } }
#define WPError( assertion, errmsg ) if( ! (assertion) ) { sLog.outError( "%s:%i ERROR:\n %s\n", __FILE__, __LINE__, (char *)errmsg ); assert( false ); }
#define WPWarning( assertion, errmsg ) if( ! (assertion) ) { sLog.outError( "%s:%i WARNING:\n %s\n", __FILE__, __LINE__, (char *)errmsg ); }
#define WPFatal( assertion, errmsg ) if( ! (assertion) ) { sLog.outError( "%s:%i FATAL ERROR:\n %s\n", __FILE__, __LINE__, (char *)errmsg ); assert( #assertion &&0 ); abort(); }
#define ASSERT WPAssert
#endif

762
src/shared/Log.cpp Normal file
View file

@ -0,0 +1,762 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#include "Common.h"
#include "Log.h"
#include "Policies/SingletonImp.h"
#include "Config/ConfigEnv.h"
#include "Util.h"
#include <stdarg.h>
INSTANTIATE_SINGLETON_1( Log );
enum LogType
{
LogNormal = 0,
LogDetails,
LogDebug,
LogError
};
const int LogType_count = int(LogError) +1;
void Log::InitColors(std::string str)
{
if(str.empty())
{
m_colored = false;
return;
}
int color[4];
std::istringstream ss(str);
for(int i = 0; i < LogType_count; ++i)
{
ss >> color[i];
if(!ss)
return;
if(color[i] < 0 || color[i] >= Color_count)
return;
}
for(int i = 0; i < LogType_count; ++i)
m_colors[i] = Color(color[i]);
m_colored = true;
}
void Log::SetColor(bool stdout_stream, Color color)
{
#if PLATFORM == PLATFORM_WINDOWS
static WORD WinColorFG[Color_count] =
{
0, // BLACK
FOREGROUND_RED, // RED
FOREGROUND_GREEN, // GREEN
FOREGROUND_RED | FOREGROUND_GREEN, // BROWN
FOREGROUND_BLUE, // BLUE
FOREGROUND_RED | FOREGROUND_BLUE,// MAGENTA
FOREGROUND_GREEN | FOREGROUND_BLUE, // CYAN
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,// WHITE
// YELLOW
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
// RED_BOLD
FOREGROUND_RED | FOREGROUND_INTENSITY,
// GREEN_BOLD
FOREGROUND_GREEN | FOREGROUND_INTENSITY,
FOREGROUND_BLUE | FOREGROUND_INTENSITY, // BLUE_BOLD
// MAGENTA_BOLD
FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
// CYAN_BOLD
FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
// WHITE_BOLD
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY
};
HANDLE hConsole = GetStdHandle(stdout_stream ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE );
SetConsoleTextAttribute(hConsole, WinColorFG[color]);
#else
enum ANSITextAttr
{
TA_NORMAL=0,
TA_BOLD=1,
TA_BLINK=5,
TA_REVERSE=7
};
enum ANSIFgTextAttr
{
FG_BLACK=30, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE,
FG_MAGENTA, FG_CYAN, FG_WHITE, FG_YELLOW
};
enum ANSIBgTextAttr
{
BG_BLACK=40, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE,
BG_MAGENTA, BG_CYAN, BG_WHITE
};
static uint8 UnixColorFG[Color_count] =
{
FG_BLACK, // BLACK
FG_RED, // RED
FG_GREEN, // GREEN
FG_BROWN, // BROWN
FG_BLUE, // BLUE
FG_MAGENTA, // MAGENTA
FG_CYAN, // CYAN
FG_WHITE, // WHITE
FG_YELLOW, // YELLOW
FG_RED, // LRED
FG_GREEN, // LGREEN
FG_BLUE, // LBLUE
FG_MAGENTA, // LMAGENTA
FG_CYAN, // LCYAN
FG_WHITE // LWHITE
};
fprintf((stdout_stream? stdout : stderr), "\x1b[%d%sm",UnixColorFG[color],(color>=YELLOW&&color<Color_count ?";1":""));
#endif
}
void Log::ResetColor(bool stdout_stream)
{
#if PLATFORM == PLATFORM_WINDOWS
HANDLE hConsole = GetStdHandle(stdout_stream ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE );
SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED );
#else
fprintf(( stdout_stream ? stdout : stderr ), "\x1b[0m");
#endif
}
void Log::SetLogLevel(char *Level)
{
int32 NewLevel =atoi((char*)Level);
if ( NewLevel <0 )
NewLevel = 0;
m_logLevel = NewLevel;
printf( "LogLevel is %u\n",m_logLevel );
}
void Log::SetLogFileLevel(char *Level)
{
int32 NewLevel =atoi((char*)Level);
if ( NewLevel <0 )
NewLevel = 0;
m_logFileLevel = NewLevel;
printf( "LogFileLevel is %u\n",m_logFileLevel );
}
void Log::Initialize()
{
std::string logsDir = sConfig.GetStringDefault("LogsDir","");
if(!logsDir.empty())
{
if((logsDir.at(logsDir.length()-1)!='/') && (logsDir.at(logsDir.length()-1)!='\\'))
logsDir.append("/");
}
std::string logfn=sConfig.GetStringDefault("LogFile", "");
if(!logfn.empty())
{
if(sConfig.GetBoolDefault("LogTimestamp",false))
{
std::string logTimestamp = GetTimestampStr();
logTimestamp.insert(0,"_");
size_t dot_pos = logfn.find_last_of(".");
if(dot_pos!=logfn.npos)
logfn.insert(dot_pos,logTimestamp);
else
logfn += logTimestamp;
}
logfile = fopen((logsDir+logfn).c_str(), "w");
}
std::string gmlogname = sConfig.GetStringDefault("GMLogFile", "");
if(!gmlogname.empty())
{
if(sConfig.GetBoolDefault("GmLogTimestamp",false))
{
std::string gmLogTimestamp = GetTimestampStr();
gmLogTimestamp.insert(0,"_");
size_t dot_pos = gmlogname.find_last_of(".");
if(dot_pos!=gmlogname.npos)
gmlogname.insert(dot_pos,gmLogTimestamp);
else
gmlogname += gmLogTimestamp;
}
gmLogfile = fopen((logsDir+gmlogname).c_str(), "a");
}
std::string charlogname = sConfig.GetStringDefault("CharLogFile", "");
if(!charlogname.empty())
{
if(sConfig.GetBoolDefault("CharLogTimestamp",false))
{
std::string charLogTimestamp = GetTimestampStr();
charLogTimestamp.insert(0,"_");
size_t dot_pos = charlogname.find_last_of(".");
if(dot_pos!=charlogname.npos)
charlogname.insert(dot_pos,charLogTimestamp);
else
charlogname += charLogTimestamp;
}
charLogfile = fopen((logsDir+charlogname).c_str(), "a");
}
std::string dberlogname = sConfig.GetStringDefault("DBErrorLogFile", "");
if(!dberlogname.empty())
{
dberLogfile = fopen((logsDir+dberlogname).c_str(), "a");
}
std::string ralogname = sConfig.GetStringDefault("RaLogFile", "");
if(!ralogname.empty())
{
raLogfile = fopen((logsDir+ralogname).c_str(), "a");
}
m_includeTime = sConfig.GetBoolDefault("LogTime", false);
m_logLevel = sConfig.GetIntDefault("LogLevel", 0);
m_logFileLevel = sConfig.GetIntDefault("LogFileLevel", 0);
InitColors(sConfig.GetStringDefault("LogColors", ""));
m_logFilter = 0;
if(sConfig.GetBoolDefault("LogFilter_TransportMoves", true))
m_logFilter |= LOG_FILTER_TRANSPORT_MOVES;
if(sConfig.GetBoolDefault("LogFilter_CreatureMoves", true))
m_logFilter |= LOG_FILTER_CREATURE_MOVES;
if(sConfig.GetBoolDefault("LogFilter_VisibilityChanges", true))
m_logFilter |= LOG_FILTER_VISIBILITY_CHANGES;
m_charLog_Dump = sConfig.GetBoolDefault("CharLogDump", false);
}
void Log::outTimestamp(FILE* file)
{
time_t t = time(NULL);
tm* aTm = localtime(&t);
// YYYY year
// MM month (2 digits 01-12)
// DD day (2 digits 01-31)
// HH hour (2 digits 00-23)
// MM minutes (2 digits 00-59)
// SS seconds (2 digits 00-59)
fprintf(file,"%-4d-%02d-%02d %02d:%02d:%02d ",aTm->tm_year+1900,aTm->tm_mon+1,aTm->tm_mday,aTm->tm_hour,aTm->tm_min,aTm->tm_sec);
}
void Log::outTime()
{
time_t t = time(NULL);
tm* aTm = localtime(&t);
// YYYY year
// MM month (2 digits 01-12)
// DD day (2 digits 01-31)
// HH hour (2 digits 00-23)
// MM minutes (2 digits 00-59)
// SS seconds (2 digits 00-59)
printf("%02d:%02d:%02d ",aTm->tm_hour,aTm->tm_min,aTm->tm_sec);
}
std::string Log::GetTimestampStr()
{
time_t t = time(NULL);
tm* aTm = localtime(&t);
// YYYY year
// MM month (2 digits 01-12)
// DD day (2 digits 01-31)
// HH hour (2 digits 00-23)
// MM minutes (2 digits 00-59)
// SS seconds (2 digits 00-59)
char buf[20];
snprintf(buf,20,"%04d-%02d-%02d_%02d-%02d-%02d",aTm->tm_year+1900,aTm->tm_mon+1,aTm->tm_mday,aTm->tm_hour,aTm->tm_min,aTm->tm_sec);
return std::string(buf);
}
void Log::outTitle( const char * str)
{
if( !str )
return;
if(m_colored)
SetColor(true,WHITE);
// not expected utf8 and then send as-is
printf( str );
if(m_colored)
ResetColor(true);
printf( "\n" );
if(logfile)
{
fprintf(logfile, str);
fprintf(logfile, "\n" );
fflush(logfile);
}
fflush(stdout);
}
void Log::outString()
{
if(m_includeTime)
outTime();
printf( "\n" );
if(logfile)
{
outTimestamp(logfile);
fprintf(logfile, "\n" );
fflush(logfile);
}
fflush(stdout);
}
void Log::outString( const char * str, ... )
{
if( !str )
return;
if(m_colored)
SetColor(true,m_colors[LogNormal]);
if(m_includeTime)
outTime();
UTF8PRINTF(stdout,str,);
if(m_colored)
ResetColor(true);
printf( "\n" );
if(logfile)
{
outTimestamp(logfile);
va_list ap;
va_start(ap, str);
vfprintf(logfile, str, ap);
fprintf(logfile, "\n" );
va_end(ap);
fflush(logfile);
}
fflush(stdout);
}
void Log::outError( const char * err, ... )
{
if( !err )
return;
if(m_colored)
SetColor(false,m_colors[LogError]);
if(m_includeTime)
outTime();
UTF8PRINTF(stderr,err,);
if(m_colored)
ResetColor(false);
fprintf( stderr, "\n" );
if(logfile)
{
outTimestamp(logfile);
fprintf(logfile, "ERROR:" );
va_list ap;
va_start(ap, err);
vfprintf(logfile, err, ap);
va_end(ap);
fprintf(logfile, "\n" );
fflush(logfile);
}
fflush(stderr);
}
void Log::outErrorDb( const char * err, ... )
{
if( !err )
return;
if(m_colored)
SetColor(false,m_colors[LogError]);
if(m_includeTime)
outTime();
UTF8PRINTF(stderr,err,);
if(m_colored)
ResetColor(false);
fprintf( stderr, "\n" );
if(logfile)
{
outTimestamp(logfile);
fprintf(logfile, "ERROR:" );
va_list ap;
va_start(ap, err);
vfprintf(logfile, err, ap);
va_end(ap);
fprintf(logfile, "\n" );
fflush(logfile);
}
if(dberLogfile)
{
outTimestamp(dberLogfile);
va_list ap;
va_start(ap, err);
vfprintf(dberLogfile, err, ap);
va_end(ap);
fprintf(dberLogfile, "\n" );
fflush(dberLogfile);
}
fflush(stderr);
}
void Log::outBasic( const char * str, ... )
{
if( !str )
return;
if( m_logLevel > 0 )
{
if(m_colored)
SetColor(true,m_colors[LogDetails]);
if(m_includeTime)
outTime();
UTF8PRINTF(stdout,str,);
if(m_colored)
ResetColor(true);
printf( "\n" );
}
if(logfile && m_logFileLevel > 0)
{
va_list ap;
outTimestamp(logfile);
va_start(ap, str);
vfprintf(logfile, str, ap);
fprintf(logfile, "\n" );
va_end(ap);
fflush(logfile);
}
fflush(stdout);
}
void Log::outDetail( const char * str, ... )
{
if( !str )
return;
if( m_logLevel > 1 )
{
if(m_colored)
SetColor(true,m_colors[LogDetails]);
if(m_includeTime)
outTime();
UTF8PRINTF(stdout,str,);
if(m_colored)
ResetColor(true);
printf( "\n" );
}
if(logfile && m_logFileLevel > 1)
{
va_list ap;
outTimestamp(logfile);
va_start(ap, str);
vfprintf(logfile, str, ap);
fprintf(logfile, "\n" );
va_end(ap);
fflush(logfile);
}
fflush(stdout);
}
void Log::outDebugInLine( const char * str, ... )
{
if( !str )
return;
if( m_logLevel > 2 )
{
if(m_colored)
SetColor(true,m_colors[LogDebug]);
UTF8PRINTF(stdout,str,);
if(m_colored)
ResetColor(true);
}
if(logfile && m_logFileLevel > 2)
{
va_list ap;
va_start(ap, str);
vfprintf(logfile, str, ap);
va_end(ap);
}
}
void Log::outDebug( const char * str, ... )
{
if( !str )
return;
if( m_logLevel > 2 )
{
if(m_colored)
SetColor(true,m_colors[LogDebug]);
if(m_includeTime)
outTime();
UTF8PRINTF(stdout,str,);
if(m_colored)
ResetColor(true);
printf( "\n" );
}
if(logfile && m_logFileLevel > 2)
{
outTimestamp(logfile);
va_list ap;
va_start(ap, str);
vfprintf(logfile, str, ap);
va_end(ap);
fprintf(logfile, "\n" );
fflush(logfile);
}
fflush(stdout);
}
void Log::outCommand( const char * str, ... )
{
if( !str )
return;
if( m_logLevel > 1 )
{
if(m_colored)
SetColor(true,m_colors[LogDetails]);
if(m_includeTime)
outTime();
UTF8PRINTF(stdout,str,);
if(m_colored)
ResetColor(true);
printf( "\n" );
}
if(logfile && m_logFileLevel > 1)
{
va_list ap;
outTimestamp(logfile);
va_start(ap, str);
vfprintf(logfile, str, ap);
fprintf(logfile, "\n" );
va_end(ap);
fflush(logfile);
}
if(gmLogfile)
{
va_list ap;
outTimestamp(gmLogfile);
va_start(ap, str);
vfprintf(gmLogfile, str, ap);
fprintf(gmLogfile, "\n" );
va_end(ap);
fflush(gmLogfile);
}
fflush(stdout);
}
void Log::outChar(const char * str, ... )
{
if (!str)
return;
if(charLogfile)
{
va_list ap;
outTimestamp(charLogfile);
va_start(ap, str);
vfprintf(charLogfile, str, ap);
fprintf(charLogfile, "\n" );
va_end(ap);
fflush(charLogfile);
}
}
void Log::outCharDump( const char * str, uint32 account_id, uint32 guid, const char * name )
{
if(charLogfile)
{
fprintf(charLogfile, "== START DUMP == (account: %u guid: %u name: %s )\n%s\n== END DUMP ==\n",account_id,guid,name,str );
fflush(charLogfile);
}
}
void Log::outMenu( const char * str, ... )
{
if( !str )
return;
SetColor(true,m_colors[LogNormal]);
if(m_includeTime)
outTime();
UTF8PRINTF(stdout,str,);
ResetColor(true);
if(logfile)
{
outTimestamp(logfile);
va_list ap;
va_start(ap, str);
vfprintf(logfile, str, ap);
va_end(ap);
fprintf(logfile, "\n" );
fflush(logfile);
}
fflush(stdout);
}
void Log::outRALog( const char * str, ... )
{
if( !str )
return;
va_list ap;
if (raLogfile)
{
outTimestamp(raLogfile);
va_start(ap, str);
vfprintf(raLogfile, str, ap);
fprintf(raLogfile, "\n" );
va_end(ap);
fflush(raLogfile);
}
fflush(stdout);
}
void outstring_log(const char * str, ...)
{
if( !str )
return;
char buf[256];
va_list ap;
va_start(ap, str);
vsnprintf(buf,256, str, ap);
va_end(ap);
MaNGOS::Singleton<Log>::Instance().outString(buf);
}
void detail_log(const char * str, ...)
{
if( !str )
return;
char buf[256];
va_list ap;
va_start(ap, str);
vsnprintf(buf,256, str, ap);
va_end(ap);
MaNGOS::Singleton<Log>::Instance().outDetail(buf);
}
void debug_log(const char * str, ...)
{
if( !str )
return;
char buf[256];
va_list ap;
va_start(ap, str);
vsnprintf(buf,256, str, ap);
va_end(ap);
MaNGOS::Singleton<Log>::Instance().outDebug(buf);
}
void error_log(const char * str, ...)
{
if( !str )
return;
char buf[256];
va_list ap;
va_start(ap, str);
vsnprintf(buf,256, str, ap);
va_end(ap);
MaNGOS::Singleton<Log>::Instance().outError(buf);
}
void error_db_log(const char * str, ...)
{
if( !str )
return;
char buf[256];
va_list ap;
va_start(ap, str);
vsnprintf(buf,256, str, ap);
va_end(ap);
MaNGOS::Singleton<Log>::Instance().outErrorDb(buf);
}

154
src/shared/Log.h Normal file
View file

@ -0,0 +1,154 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef MANGOSSERVER_LOG_H
#define MANGOSSERVER_LOG_H
#include "Common.h"
#include "Policies/Singleton.h"
class Config;
// bitmask
enum LogFilters
{
LOG_FILTER_TRANSPORT_MOVES = 1,
LOG_FILTER_CREATURE_MOVES = 2,
LOG_FILTER_VISIBILITY_CHANGES = 4
};
enum Color
{
BLACK,
RED,
GREEN,
BROWN,
BLUE,
MAGENTA,
CYAN,
GREY,
YELLOW,
LRED,
LGREEN,
LBLUE,
LMAGENTA,
LCYAN,
WHITE
};
const int Color_count = int(WHITE)+1;
class Log : public MaNGOS::Singleton<Log, MaNGOS::ClassLevelLockable<Log, ZThread::FastMutex> >
{
friend class MaNGOS::OperatorNew<Log>;
Log() : raLogfile(NULL), logfile(NULL), gmLogfile(NULL), charLogfile(NULL), dberLogfile(NULL), m_colored(false) { Initialize(); }
~Log()
{
if( logfile != NULL )
fclose(logfile);
logfile = NULL;
if( gmLogfile != NULL )
fclose(gmLogfile);
gmLogfile = NULL;
if (charLogfile != NULL)
fclose(charLogfile);
charLogfile = NULL;
if( dberLogfile != NULL )
fclose(dberLogfile);
dberLogfile = NULL;
if (raLogfile != NULL)
fclose(raLogfile);
raLogfile = NULL;
}
public:
void Initialize();
void InitColors(std::string init_str);
void outTitle( const char * str);
void outCommand( const char * str, ...) ATTR_PRINTF(2,3);
void outString(); // any log level
// any log level
void outString( const char * str, ... ) ATTR_PRINTF(2,3);
// any log level
void outError( const char * err, ... ) ATTR_PRINTF(2,3);
// log level >= 1
void outBasic( const char * str, ... ) ATTR_PRINTF(2,3);
// log level >= 2
void outDetail( const char * str, ... ) ATTR_PRINTF(2,3);
// log level >= 3
void outDebugInLine( const char * str, ... ) ATTR_PRINTF(2,3);
// log level >= 3
void outDebug( const char * str, ... ) ATTR_PRINTF(2,3);
// any log level
void outMenu( const char * str, ... ) ATTR_PRINTF(2,3);
// any log level
void outErrorDb( const char * str, ... ) ATTR_PRINTF(2,3);
// any log level
void outChar( const char * str, ... ) ATTR_PRINTF(2,3);
// any log level
void outCharDump( const char * str, uint32 account_id, uint32 guid, const char * name );
void outRALog( const char * str, ... ) ATTR_PRINTF(2,3);
void SetLogLevel(char * Level);
void SetLogFileLevel(char * Level);
void SetColor(bool stdout_stream, Color color);
void ResetColor(bool stdout_stream);
void outTime();
static void outTimestamp(FILE* file);
static std::string GetTimestampStr();
uint32 getLogFilter() const { return m_logFilter; }
bool IsOutDebug() const { return m_logLevel > 2 || (m_logFileLevel > 2 && logfile); }
bool IsOutCharDump() const { return m_charLog_Dump; }
bool IsIncludeTime() const { return m_includeTime; }
private:
FILE* raLogfile;
FILE* logfile;
FILE* gmLogfile;
FILE* charLogfile;
FILE* dberLogfile;
// log/console control
uint32 m_logLevel;
uint32 m_logFileLevel;
bool m_colored;
bool m_includeTime;
Color m_colors[4];
uint32 m_logFilter;
// char log control
bool m_charLog_Dump;
};
#define sLog MaNGOS::Singleton<Log>::Instance()
#ifdef MANGOS_DEBUG
#define DEBUG_LOG MaNGOS::Singleton<Log>::Instance().outDebug
#else
#define DEBUG_LOG
#endif
// primary for script library
void MANGOS_DLL_SPEC outstring_log(const char * str, ...) ATTR_PRINTF(1,2);
void MANGOS_DLL_SPEC detail_log(const char * str, ...) ATTR_PRINTF(1,2);
void MANGOS_DLL_SPEC debug_log(const char * str, ...) ATTR_PRINTF(1,2);
void MANGOS_DLL_SPEC error_log(const char * str, ...) ATTR_PRINTF(1,2);
void MANGOS_DLL_SPEC error_db_log(const char * str, ...) ATTR_PRINTF(1,2);
#endif

79
src/shared/Makefile.am Normal file
View file

@ -0,0 +1,79 @@
# Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
#
# 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
## Process this file with automake to produce Makefile.in
## Sub-directories to parse
SUBDIRS = Auth Config Database vmap
## CPP flags for includes, defines, etc.
AM_CPPFLAGS = $(MANGOS_INCLUDES) -I$(top_builddir)/src/shared -I$(srcdir) -I$(srcdir)/../../dep/include -I$(srcdir)/../framework -I$(srcdir)/../shared -I$(srcdir)/../../dep/include/g3dlite
## AM_CPPFLAGS += -I$(srcdir)/../game -I$(srcdir)/../realmd
## Build MaNGOS shared library and its parts as convenience library.
# All libraries will be convenience libraries. Might be changed to shared
# later.
noinst_LIBRARIES = libmangosshared.a
# libmangosshared library will later be reused by ...
libmangosshared_a_SOURCES = \
Base.cpp \
Base.h \
ByteBuffer.h \
Common.cpp \
Common.h \
Errors.h \
Log.cpp \
Log.h \
MemoryLeaks.cpp \
MemoryLeaks.h \
Mthread.cpp \
Mthread.h \
ProgressBar.cpp \
ProgressBar.h \
Timer.h \
Util.cpp \
Util.h \
WorldPacket.h \
svn_revision.h
# Get svn revision
SVN_REVISION_FILE = svn_revision.h
BUILT_SOURCES = $(SVN_REVISION_FILE)
CLEANFILES = $(SVN_REVISION_FILE)
FORCE:
$(SVN_REVISION_FILE) : $(top_builddir)/src/tools/gensvnrevision/gensvnrevision FORCE
$(top_builddir)/src/tools/gensvnrevision/gensvnrevision $(top_srcdir)
## Additional files to include when running 'make dist'
# Disabled packet logger
EXTRA_DIST = \
PacketLog.cpp \
PacketLog.h
# System configuration
EXTRA_DIST += \
SystemConfig.h
# System Win32 files
EXTRA_DIST += \
ServiceWin32.cpp \
ServiceWin32.h \
WheatyExceptionReport.cpp \
WheatyExceptionReport.h

View file

@ -0,0 +1,32 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#include "MemoryLeaks.h"
#include "Policies/SingletonImp.h"
INSTANTIATE_SINGLETON_1( MemoryManager ) ;
MemoryManager::MemoryManager( )
{
#if COMPILER == MICROSOFT
// standard leak check initialization
//_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
// uncomment to disable Visual Leak Detector from code
//VLDDisable();
#endif
}

48
src/shared/MemoryLeaks.h Normal file
View file

@ -0,0 +1,48 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef MANGOSSERVER_MEMORY_H
#define MANGOSSERVER_MEMORY_H
#include "Platform/CompilerDefs.h"
#if COMPILER == COMPILER_MICROSOFT
#ifndef _WIN64
// Visual Leak Detector support enabled
#include <vld/vld.h>
// standard Visual Studio leak check disabled,
//# define _CRTDBG_MAP_ALLOC
//# include <stdlib.h>
//# include <crtdbg.h>
#else
# define _CRTDBG_MAP_ALLOC
# include <stdlib.h>
# include <crtdbg.h>
#endif
#endif
#include "Policies/Singleton.h"
struct MemoryManager : public MaNGOS::Singleton < MemoryManager >
{
MemoryManager();
};
#endif

205
src/shared/Mthread.cpp Normal file
View file

@ -0,0 +1,205 @@
/*
Cross-platform thread handling
Copyright (C) 2005 Andrew Zabolotny
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Mthread.h"
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE_CC__)
# define MANGOS_PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE
#else
# define MANGOS_PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
#endif
#if PLATFORM != PLATFORM_WINDOWS
MThread::MThread ()
{
tid = 0;
}
MThread::~MThread ()
{
/* Kill thread if this is not the current thread */
if (tid && (pthread_self () != tid))
{
pthread_cancel (tid);
pthread_join (tid, NULL);
}
}
static void *thread_start_routine (void *arg)
{
MThread *newthr = (MThread *)arg;
pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
newthr->routine (newthr->arg);
return NULL;
}
MThread *MThread::Start (void (*routine) (void *arg), void *arg)
{
MThread *newthr = new MThread ();
newthr->routine = routine;
newthr->arg = arg;
int rc = pthread_create (&newthr->tid, NULL, thread_start_routine, newthr);
if (rc)
{
newthr->DecRef ();
return NULL;
}
return newthr;
}
pthread_mutexattr_t MMutex::attr;
int MMutex::attr_refcount = 0;
MMutex::MMutex ()
{
if (!attr_refcount++)
{
pthread_mutexattr_init (&attr);
pthread_mutexattr_settype (&attr, MANGOS_PTHREAD_MUTEX_RECURSIVE);
}
pthread_mutex_init (&mutex, &attr);
}
MMutex::~MMutex ()
{
pthread_mutex_destroy (&mutex);
if (!--attr_refcount)
pthread_mutexattr_destroy (&attr);
}
bool MMutex::Lock ()
{
return (pthread_mutex_lock (&mutex) == 0);
}
bool MMutex::TryLock ()
{
return (pthread_mutex_trylock (&mutex) == 0);
}
void MMutex::Unlock ()
{
pthread_mutex_unlock (&mutex);
}
MMutex *MMutex::Create ()
{
return new MMutex ();
}
#else //windows
MThread::MThread()
{
th = NULL;
}
MThread::~MThread ()
{
/* Kill thread if this is not current thread */
if (th && (GetCurrentThreadId () != id))
{
TerminateThread (th, 0);
WaitForSingleObject (th, INFINITE);
CloseHandle (th);
}
}
bool MThread::SetPriority (ThreadPriority prio)
{
int p;
switch (prio)
{
case IDLE: p = THREAD_PRIORITY_IDLE; break;
case LOWER: p = THREAD_PRIORITY_LOWEST; break;
case LOW: p = THREAD_PRIORITY_BELOW_NORMAL; break;
case NORMAL: p = THREAD_PRIORITY_NORMAL; break;
case HIGH: p = THREAD_PRIORITY_ABOVE_NORMAL; break;
case HIGHER: p = THREAD_PRIORITY_HIGHEST; break;
case REALTIME: p = THREAD_PRIORITY_TIME_CRITICAL; break;
default: p = THREAD_PRIORITY_NORMAL; break;
}
return SetThreadPriority (th, p);
}
static DWORD WINAPI thread_start_routine (void *arg)
//static void thread_start_routine (void *arg)
{
MThread *newthr = (MThread *)arg;
newthr->id = GetCurrentThreadId ();
newthr->routine (newthr->arg);
return 0;
}
MThread *MThread::Start (void (*routine) (void *arg), void *arg)
{
DWORD dwtid;
MThread *newthr = new MThread ();
newthr->routine = routine;
newthr->arg = arg;
newthr->th = CreateThread (NULL, WIN32_THREAD_STACK_SIZE, thread_start_routine, newthr, 0, &dwtid);
//newthr->th = (HANDLE)_beginthread(thread_start_routine, 0, newthr);
if (!newthr->th)
{
newthr->DecRef ();
return NULL;
}
return newthr;
}
MMutex::MMutex ()
{
sem = CreateMutex (NULL, FALSE, NULL);
}
MMutex::~MMutex ()
{
CloseHandle (sem);
}
bool MMutex::Lock ()
{
return (WaitForSingleObject (sem, INFINITE) != WAIT_FAILED);
}
bool MMutex::TryLock ()
{
DWORD state = WaitForSingleObject (sem, 0);
return (state == WAIT_OBJECT_0) && (state != WAIT_ABANDONED);
}
void MMutex::Unlock ()
{
ReleaseMutex (sem);
}
MMutex *MMutex::Create ()
{
MMutex *mutex = new MMutex ();
if (!mutex->sem)
{
mutex->DecRef ();
return NULL;
}
return mutex;
}
#endif

62
src/shared/Mthread.h Normal file
View file

@ -0,0 +1,62 @@
#ifndef MTHREAD_H
#define MTHREAD_H
#include "Base.h"
#ifndef WIN32
#include <pthread.h>
#else
#include <windows.h>
//#include "Process.h"
#define WIN32_THREAD_STACK_SIZE 0x10000
#endif
enum ThreadPriority
{
IDLE,
LOWER,
LOW,
NORMAL,
HIGH,
HIGHER,
REALTIME
};
class MThread: public Base
{
public:
static MThread *Start (void (*routine) (void *arg), void *arg);
MThread ();
~MThread ();
bool SetPriority (ThreadPriority prio);
void (*routine) (void *arg);
void *arg;
#ifdef WIN32
HANDLE th;
ULONG id;
#else
pthread_t tid;
#endif
};
class MMutex : public Base
{
public:
#ifdef WIN32
HANDLE sem;
#else
pthread_mutex_t mutex;
static pthread_mutexattr_t attr;
static int attr_refcount;
#endif
static MMutex *Create ();
MMutex ();
virtual ~MMutex ();
virtual bool Lock ();
virtual bool TryLock ();
virtual void Unlock ();
};
#endif // MTHREAD_H

157
src/shared/PacketLog.cpp Normal file
View file

@ -0,0 +1,157 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#include "Common.h"
#include "PacketLog.h"
#include "Config/ConfigEnv.h"
#include "Policies/SingletonImpl.h"
#include <ctype.h>
INSTANTIATE_SINGLETON_1( PacketLog );
PacketLog::PacketLog()
{
if (sConfig.GetBoolDefault("LogRealm", false))
{
FILE *pFile = fopen("realm.log", "w+");
fclose(pFile);
}
if (sConfig.GetBoolDefault("LogWorld", false))
{
FILE *pFile = fopen("world.log", "w+");
fclose(pFile);
}
}
PacketLog::~PacketLog()
{
}
char PacketLog::makehexchar(int i)
{
return (i<=9) ? '0'+i : 'A'+(i-10);
}
int PacketLog::hextoint(char c)
{
c = toupper(c);
return (c > '9' ? c - 'A' + 10 : c - '0');
}
void PacketLog::HexDump(const unsigned char* data, size_t length, const char* file)
{
FILE *pFile;
pFile = fopen(file, "a");
const int char_offset = 16*3 + 2;
const int line_size = 16*3 + 16 + 3;
char line[line_size+1];
fprintf(pFile,"OFFSET 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F | 0123456789ABCDEF\n");
fprintf(pFile,"--------------------------------------------------------------------------\n");
line[char_offset - 1] = ' ';
line[char_offset - 2] = ' ';
for (size_t i=0; i<length; )
{
int bi=0;
int ci=0;
int start_i = i;
for (int line_i=0; i < length && line_i < 16; i++, line_i++)
{
line[bi++] = makehexchar(*data>>4);
line[bi++] = makehexchar(*data & 0x0f);
line[bi++] = ' ';
line[char_offset+(ci++)]=(isprint(*data) ? *data : '.');
++data;
}
while (bi<16*3)
{
line[bi++]=' ';
}
line[char_offset+(ci++)]='\n';
line[char_offset+ci]=0;
fprintf(pFile,"%06X %s", start_i, line);
}
fprintf(pFile, "\n\n");
fclose(pFile);
}
void PacketLog::HexDump(const char *data, size_t length, const char* file)
{
HexDump((unsigned char *)data, length, file);
}
void PacketLog::HexDumpStr(const char *msg, const char *data, size_t len, const char* file)
{
FILE *pFile;
pFile = fopen(file, "a");
fprintf(pFile,"%s\n", msg);
fclose(pFile);
HexDump(data, len, file);
}
void PacketLog::RealmHexDump(RealmPacket* data, uint32 socket, bool direction)
{
if (!sConfig.GetBoolDefault("LogRealm", false))
return;
FILE *pFile;
pFile = fopen("realm.log", "a");
uint16 len = data->size() + 2;
uint8 opcode = data->GetOpcode();
if (direction)
fprintf(pFile, "SERVER:\nSOCKET: %d\nLENGTH: %d\nOPCODE: %.2X\nDATA:\n", socket, len, opcode);
else
fprintf(pFile, "CLIENT:\nSOCKET: %d\nLENGTH: %d\nOPCODE: %.2X\nDATA:\n", socket, len, opcode);
fclose(pFile);
HexDump((char *)data->contents(), data->size(), "realm.log");
}
void PacketLog::WorldHexDump(WorldPacket* data, uint32 socket, bool direction)
{
if (!sConfig.GetBoolDefault("LogWorld", false))
return;
FILE *pFile;
pFile = fopen("world.log", "a");
uint16 len = data->size();
uint16 opcode = data->GetOpcode();
if (direction)
fprintf(pFile, "SERVER:\nSOCKET: %d\nLENGTH: %d\nOPCODE: %.4X\nDATA:\n", socket, len, opcode);
else
fprintf(pFile, "CLIENT:\nSOCKET: %d\nLENGTH: %d\nOPCODE: %.4X\nDATA:\n", socket, len, opcode);
fclose(pFile);
HexDump((char *)data->contents(), data->size(), "world.log");
}

46
src/shared/PacketLog.h Normal file
View file

@ -0,0 +1,46 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef MANGOSSERVER_PACKETLOG_H
#define MANGOSSERVER_PACKETLOG_H
#include "Common.h"
#include "Policies/Singleton.h"
#include "RealmPacket.h"
#include "WorldPacket.h"
class PacketLog
{
public:
PacketLog();
~PacketLog();
int hextoint(char c);
char makehexchar(int i);
void HexDump(const unsigned char* data, size_t length, const char* file);
void HexDump(const char *data, size_t length, const char* file);
void HexDumpStr(const char *msg, const char *data, size_t len, const char* file);
void RealmHexDump(RealmPacket * data, uint32 socket, bool direction);
void WorldHexDump(WorldPacket * data, uint32 socket, bool direction);
};
#define sPacketLog MaNGOS::Singleton<PacketLog>::Instance()
#endif

View file

@ -0,0 +1,80 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#include "ProgressBar.h"
char const* const barGoLink::empty = " ";
#ifdef _WIN32
char const* const barGoLink::full = "\x3D";
#else
char const* const barGoLink::full = "*";
#endif
barGoLink::~barGoLink()
{
printf( "\n" );
fflush(stdout);
}
barGoLink::barGoLink( int row_count )
{
rec_no = 0;
rec_pos = 0;
indic_len = 50;
num_rec = row_count;
#ifdef _WIN32
printf( "\x3D" );
#else
printf( "[" );
#endif
for ( int i = 0; i < indic_len; i++ ) printf( empty );
#ifdef _WIN32
printf( "\x3D 0%%\r\x3D" );
#else
printf( "] 0%%\r[" );
#endif
fflush(stdout);
}
void barGoLink::step( void )
{
int i, n;
if ( num_rec == 0 ) return;
++rec_no;
n = rec_no * indic_len / num_rec;
if ( n != rec_pos )
{
#ifdef _WIN32
printf( "\r\x3D" );
#else
printf( "\r[" );
#endif
for ( i = 0; i < n; i++ ) printf( full );
for ( ; i < indic_len; i++ ) printf( empty );
float percent = (((float)n/(float)indic_len)*100);
#ifdef _WIN32
printf( "\x3D %i%% \r\x3D", (int)percent);
#else
printf( "] %i%% \r[", (int)percent);
#endif
fflush(stdout);
rec_pos = n;
}
}

40
src/shared/ProgressBar.h Normal file
View file

@ -0,0 +1,40 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef MANGOSSERVER_PROGRESSBAR_H
#define MANGOSSERVER_PROGRESSBAR_H
#include <stdio.h>
#include "Platform/Define.h"
class MANGOS_DLL_SPEC barGoLink
{
static char const * const empty;
static char const * const full;
int rec_no;
int rec_pos;
int num_rec;
int indic_len;
public:
void step( void );
barGoLink( int );
~barGoLink();
};
#endif

260
src/shared/ServiceWin32.cpp Normal file
View file

@ -0,0 +1,260 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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.
*/
#ifdef WIN32
#include "Common.h"
#include "Log.h"
#include <cstring>
#include <windows.h>
#include <winsvc.h>
#if !defined(WINADVAPI)
#if !defined(_ADVAPI32_)
#define WINADVAPI DECLSPEC_IMPORT
#else
#define WINADVAPI
#endif
#endif
extern int main(int argc, char ** argv);
extern char serviceLongName[];
extern char serviceName[];
extern char serviceDescription[];
extern int m_ServiceStatus;
SERVICE_STATUS serviceStatus;
SERVICE_STATUS_HANDLE serviceStatusHandle = 0;
typedef WINADVAPI BOOL (WINAPI *CSD_T)(SC_HANDLE, DWORD, LPCVOID);
bool WinServiceInstall()
{
CSD_T ChangeService_Config2;
HMODULE advapi32;
SC_HANDLE serviceControlManager = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
if (serviceControlManager)
{
char path[_MAX_PATH + 10];
if (GetModuleFileName( 0, path, sizeof(path)/sizeof(path[0]) ) > 0)
{
SC_HANDLE service;
std::strcat(path, " --service");
service = CreateService(serviceControlManager,
serviceName, // name of service
serviceLongName, // service name to display
SERVICE_ALL_ACCESS, // desired access
// service type
SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
SERVICE_AUTO_START, // start type
SERVICE_ERROR_IGNORE, // error control type
path, // service's binary
0, // no load ordering group
0, // no tag identifier
0, // no dependencies
0, // LocalSystem account
0); // no password
if (service)
{
advapi32 = GetModuleHandle("ADVAPI32.DLL");
if(!advapi32)
{
CloseServiceHandle(service);
CloseServiceHandle(serviceControlManager);
return false;
}
ChangeService_Config2 = (CSD_T) GetProcAddress(advapi32, "ChangeServiceConfig2A");
if (!ChangeService_Config2)
{
CloseServiceHandle(service);
CloseServiceHandle(serviceControlManager);
return false;
}
SERVICE_DESCRIPTION sdBuf;
sdBuf.lpDescription = serviceDescription;
ChangeService_Config2(
service, // handle to service
SERVICE_CONFIG_DESCRIPTION, // change: description
&sdBuf); // new data
SC_ACTION _action[1];
_action[0].Type = SC_ACTION_RESTART;
_action[0].Delay = 10000;
SERVICE_FAILURE_ACTIONS sfa;
ZeroMemory(&sfa, sizeof(SERVICE_FAILURE_ACTIONS));
sfa.lpsaActions = _action;
sfa.cActions = 1;
sfa.dwResetPeriod =INFINITE;
ChangeService_Config2(
service, // handle to service
SERVICE_CONFIG_FAILURE_ACTIONS, // information level
&sfa); // new data
CloseServiceHandle(service);
}
}
CloseServiceHandle(serviceControlManager);
}
return true;
}
bool WinServiceUninstall()
{
SC_HANDLE serviceControlManager = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
if (serviceControlManager)
{
SC_HANDLE service = OpenService(serviceControlManager,
serviceName, SERVICE_QUERY_STATUS | DELETE);
if (service)
{
SERVICE_STATUS serviceStatus;
if (QueryServiceStatus(service, &serviceStatus))
{
if (serviceStatus.dwCurrentState == SERVICE_STOPPED)
DeleteService(service);
}
CloseServiceHandle(service);
}
CloseServiceHandle(serviceControlManager);
}
return true;
}
void WINAPI ServiceControlHandler(DWORD controlCode)
{
switch (controlCode)
{
case SERVICE_CONTROL_INTERROGATE:
break;
case SERVICE_CONTROL_SHUTDOWN:
case SERVICE_CONTROL_STOP:
serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus(serviceStatusHandle, &serviceStatus);
m_ServiceStatus = 0;
return;
case SERVICE_CONTROL_PAUSE:
m_ServiceStatus = 2;
serviceStatus.dwCurrentState = SERVICE_PAUSED;
SetServiceStatus(serviceStatusHandle, &serviceStatus);
break;
case SERVICE_CONTROL_CONTINUE:
serviceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(serviceStatusHandle, &serviceStatus);
m_ServiceStatus = 1;
break;
default:
if ( controlCode >= 128 && controlCode <= 255 )
// user defined control code
break;
else
// unrecognized control code
break;
}
SetServiceStatus(serviceStatusHandle, &serviceStatus);
}
void WINAPI ServiceMain(DWORD argc, char *argv[])
{
// initialise service status
serviceStatus.dwServiceType = SERVICE_WIN32;
serviceStatus.dwCurrentState = SERVICE_START_PENDING;
serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
serviceStatus.dwWin32ExitCode = NO_ERROR;
serviceStatus.dwServiceSpecificExitCode = NO_ERROR;
serviceStatus.dwCheckPoint = 0;
serviceStatus.dwWaitHint = 0;
serviceStatusHandle = RegisterServiceCtrlHandler(serviceName, ServiceControlHandler);
if ( serviceStatusHandle )
{
char path[_MAX_PATH + 1];
unsigned int i, last_slash = 0;
GetModuleFileName(0, path, sizeof(path)/sizeof(path[0]));
for (i = 0; i < std::strlen(path); i++)
{
if (path[i] == '\\') last_slash = i;
}
path[last_slash] = 0;
// service is starting
serviceStatus.dwCurrentState = SERVICE_START_PENDING;
SetServiceStatus(serviceStatusHandle, &serviceStatus);
// do initialisation here
SetCurrentDirectory(path);
// running
serviceStatus.dwControlsAccepted |= (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
serviceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus( serviceStatusHandle, &serviceStatus );
////////////////////////
// service main cycle //
////////////////////////
m_ServiceStatus = 1;
argc = 1;
main(argc , argv);
// service was stopped
serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus(serviceStatusHandle, &serviceStatus);
// do cleanup here
// service is now stopped
serviceStatus.dwControlsAccepted &= ~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
serviceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(serviceStatusHandle, &serviceStatus);
}
}
bool WinServiceRun()
{
SERVICE_TABLE_ENTRY serviceTable[] =
{
{ serviceName, ServiceMain },
{ 0, 0 }
};
if (!StartServiceCtrlDispatcher(serviceTable))
{
sLog.outError("StartService Failed. Error [%u]", ::GetLastError());
return false;
}
return true;
}
#endif

28
src/shared/ServiceWin32.h Normal file
View file

@ -0,0 +1,28 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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.
*/
#ifdef WIN32
#ifndef _WIN32_SERVICE_
#define _WIN32_SERVICE_
bool WinServiceInstall();
bool WinServiceUninstall();
bool WinServiceRun();
#endif // _WIN32_SERVICE_
#endif // WIN32

View file

@ -0,0 +1,70 @@
/*
* Copyright (C) 2005,2006 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef MANGOS_SYSTEMCONFIG_H
#define MANGOS_SYSTEMCONFIG_H
#ifndef _PACKAGENAME
#define _PACKAGENAME "MaNGOS"
#endif
#include "Platform/Define.h"
#include "svn_revision.h"
#ifndef _VERSION
#if PLATFORM == PLATFORM_WINDOWS
# define _VERSION "0.12.0-SVN" " (Revision " SVN_REVISION ")"
#else
# define _VERSION "@VERSION@" " (Revision " SVN_REVISION ")"
#endif
#endif
// Format is YYYYMMDDRR where RR is the change in the conf file
// for that day.
#ifndef _MANGOSDCONFVERSION
# define _MANGOSDCONFVERSION 2008022901
#endif
#ifndef _REALMDCONFVERSION
# define _REALMDCONFVERSION 2007062001
#endif
#if MANGOS_ENDIAN == MANGOS_BIGENDIAN
# define _ENDIAN_STRING "big-endian"
#else
# define _ENDIAN_STRING "little-endian"
#endif
#if PLATFORM == PLATFORM_WINDOWS
# ifdef _WIN64
# define _FULLVERSION _PACKAGENAME "/" _VERSION " (Win64," _ENDIAN_STRING ")"
# else
# define _FULLVERSION _PACKAGENAME "/" _VERSION " (Win32," _ENDIAN_STRING ")"
# endif
# define _MANGOSD_CONFIG "mangosd.conf"
# define _REALMD_CONFIG "realmd.conf"
#else
# define _FULLVERSION _PACKAGENAME "/" _VERSION " (Unix," _ENDIAN_STRING ")"
# define _MANGOSD_CONFIG "@sysconfdir@/mangosd.conf"
# define _REALMD_CONFIG "@sysconfdir@/realmd.conf"
#endif
#define DEFAULT_PLAYER_LIMIT 100
#define DEFAULT_WORLDSERVER_PORT 8085 //8129
#define DEFAULT_REALMSERVER_PORT 3724
#define DEFAULT_SOCKET_SELECT_TIME 10000
#endif

96
src/shared/Timer.h Normal file
View file

@ -0,0 +1,96 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef MANGOS_TIMER_H
#define MANGOS_TIMER_H
#include "Platform/CompilerDefs.h"
#if PLATFORM == PLATFORM_WINDOWS
# include <ace/config-all.h>
# include <mmsystem.h>
# include <time.h>
#else
# if defined(__APPLE_CC__)
# include <time.h>
# endif
# include <sys/time.h>
# include <sys/timeb.h>
#endif
#if PLATFORM == PLATFORM_WINDOWS
inline uint32 getMSTime() { return GetTickCount(); }
#else
inline uint32 getMSTime()
{
struct timeval tv;
struct timezone tz;
gettimeofday( &tv, &tz );
return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
}
#endif
inline uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime)
{
// getMSTime() have limited data range and this is case when it overflow in this tick
if (oldMSTime > newMSTime)
return (0xFFFFFFFF - oldMSTime) + newMSTime;
else
return newMSTime - oldMSTime;
}
class IntervalTimer
{
public:
IntervalTimer() : _interval(0), _current(0) {}
void Update(time_t diff) { _current += diff; if(_current<0) _current=0;}
bool Passed() { return _current >= _interval; }
void Reset() { if(_current >= _interval) _current -= _interval; }
void SetCurrent(time_t current) { _current = current; }
void SetInterval(time_t interval) { _interval = interval; }
time_t GetInterval() const { return _interval; }
time_t GetCurrent() const { return _current; }
private:
time_t _interval;
time_t _current;
};
struct TimeTracker
{
TimeTracker(time_t expiry) : i_expiryTime(expiry) {}
void Update(time_t diff) { i_expiryTime -= diff; }
bool Passed(void) const { return (i_expiryTime <= 0); }
void Reset(time_t interval) { i_expiryTime = interval; }
time_t GetExpiry(void) const { return i_expiryTime; }
time_t i_expiryTime;
};
struct TimeTrackerSmall
{
TimeTrackerSmall(int32 expiry) : i_expiryTime(expiry) {}
void Update(int32 diff) { i_expiryTime -= diff; }
bool Passed(void) const { return (i_expiryTime <= 0); }
void Reset(int32 interval) { i_expiryTime = interval; }
int32 GetExpiry(void) const { return i_expiryTime; }
int32 i_expiryTime;
};
#endif

425
src/shared/Util.cpp Normal file
View file

@ -0,0 +1,425 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#include "Util.h"
#include "sockets/socket_include.h"
#include "utf8cpp/utf8.h"
#include "mersennetwister/MersenneTwister.h"
#include "zthread/ThreadLocal.h"
typedef ZThread::ThreadLocal<MTRand> MTRandTSS;
/* NOTE: Not sure if static initialization is ok for TSS objects ,
* as I see zthread uses custom implementation of the TSS
* ,and in the consturctor there is no code ,so I suppose its ok
* If its not ok ,change it to use singleton.
*/
static MTRandTSS mtRand;
int32 irand (int32 min, int32 max)
{
return int32 (mtRand.get ().randInt (max - min)) + min;
}
uint32 urand (uint32 min, uint32 max)
{
return mtRand.get ().randInt (max - min) + min;
}
int32 rand32 ()
{
return mtRand.get ().randInt ();
}
double rand_norm(void)
{
return mtRand.get ().randExc ();
}
double rand_chance (void)
{
return mtRand.get ().randExc (100.0);
}
Tokens StrSplit(const std::string &src, const std::string &sep)
{
Tokens r;
std::string s;
for (std::string::const_iterator i = src.begin(); i != src.end(); i++)
{
if (sep.find(*i) != std::string::npos)
{
if (s.length()) r.push_back(s);
s = "";
}
else
{
s += *i;
}
}
if (s.length()) r.push_back(s);
return r;
}
void stripLineInvisibleChars(std::string &str)
{
static std::string invChars = " \t\7";
size_t wpos = 0;
bool space = false;
for(size_t pos = 0; pos < str.size(); ++pos)
{
if(invChars.find(str[pos])!=std::string::npos)
{
if(!space)
{
str[wpos++] = ' ';
space = true;
}
}
else
{
if(wpos!=pos)
str[wpos++] = str[pos];
else
++wpos;
space = false;
}
}
if(wpos < str.size())
str.erase(wpos,str.size());
}
std::string secsToTimeString(uint32 timeInSecs, bool shortText, bool hoursOnly)
{
uint32 secs = timeInSecs % MINUTE;
uint32 minutes = timeInSecs % HOUR / MINUTE;
uint32 hours = timeInSecs % DAY / HOUR;
uint32 days = timeInSecs / DAY;
std::ostringstream ss;
if(days)
ss << days << (shortText ? "d" : " Day(s) ");
if(hours || hoursOnly)
ss << hours << (shortText ? "h" : " Hour(s) ");
if(!hoursOnly)
{
if(minutes)
ss << minutes << (shortText ? "m" : " Minute(s) ");
if(secs || (!days && !hours && !minutes) )
ss << secs << (shortText ? "s" : " Second(s).");
}
return ss.str();
}
uint32 TimeStringToSecs(std::string timestring)
{
uint32 secs = 0;
uint32 buffer = 0;
uint32 multiplier = 0;
for(std::string::iterator itr = timestring.begin(); itr != timestring.end(); itr++ )
{
if(isdigit(*itr))
{
std::string str; //very complicated typecast char->const char*; is there no better way?
str += *itr;
const char* tmp = str.c_str();
buffer*=10;
buffer+=atoi(tmp);
}
else
{
switch(*itr)
{
case 'd': multiplier = DAY; break;
case 'h': multiplier = HOUR; break;
case 'm': multiplier = MINUTE; break;
case 's': multiplier = 1; break;
default : return 0; //bad format
}
buffer*=multiplier;
secs+=buffer;
buffer=0;
}
}
return secs;
}
std::string TimeToTimestampStr(time_t t)
{
tm* aTm = localtime(&t);
// YYYY year
// MM month (2 digits 01-12)
// DD day (2 digits 01-31)
// HH hour (2 digits 00-23)
// MM minutes (2 digits 00-59)
// SS seconds (2 digits 00-59)
char buf[20];
snprintf(buf,20,"%04d-%02d-%02d_%02d-%02d-%02d",aTm->tm_year+1900,aTm->tm_mon+1,aTm->tm_mday,aTm->tm_hour,aTm->tm_min,aTm->tm_sec);
return std::string(buf);
}
/// Check if the string is a valid ip address representation
bool IsIPAddress(char const* ipaddress)
{
if(!ipaddress)
return false;
// Let the big boys do it.
// Drawback: all valid ip address formats are recognized e.g.: 12.23,121234,0xABCD)
return inet_addr(ipaddress) != INADDR_NONE;
}
/// create PID file
uint32 CreatePIDFile(std::string filename)
{
FILE * pid_file = fopen (filename.c_str(), "w" );
if (pid_file == NULL)
return 0;
#ifdef WIN32
DWORD pid = GetCurrentProcessId();
#else
pid_t pid = getpid();
#endif
fprintf(pid_file, "%d", pid );
fclose(pid_file);
return (uint32)pid;
}
size_t utf8length(std::string& utf8str)
{
try
{
return utf8::distance(utf8str.c_str(),utf8str.c_str()+utf8str.size());
}
catch(std::exception)
{
utf8str = "";
return 0;
}
}
void utf8truncate(std::string& utf8str,size_t len)
{
try
{
size_t wlen = utf8::distance(utf8str.c_str(),utf8str.c_str()+utf8str.size());
if(wlen <= len)
return;
std::wstring wstr;
wstr.resize(wlen);
utf8::utf8to16(utf8str.c_str(),utf8str.c_str()+utf8str.size(),&wstr[0]);
wstr.resize(len);
char* oend = utf8::utf16to8(wstr.c_str(),wstr.c_str()+wstr.size(),&utf8str[0]);
utf8str.resize(oend-(&utf8str[0])); // remove unused tail
}
catch(std::exception)
{
utf8str = "";
}
}
bool Utf8toWStr(char const* utf8str, size_t csize, wchar_t* wstr, size_t& wsize)
{
try
{
size_t len = utf8::distance(utf8str,utf8str+csize);
if(len > wsize)
{
wsize = 0;
wstr = L"";
return false;
}
wsize = len;
utf8::utf8to16(utf8str,utf8str+csize,wstr);
wstr[len] = L'\0';
}
catch(std::exception)
{
wsize = 0;
wstr = L"";
return false;
}
return true;
}
bool Utf8toWStr(std::string utf8str, std::wstring& wstr)
{
try
{
size_t len = utf8::distance(utf8str.c_str(),utf8str.c_str()+utf8str.size());
wstr.resize(len);
utf8::utf8to16(utf8str.c_str(),utf8str.c_str()+utf8str.size(),&wstr[0]);
}
catch(std::exception)
{
wstr = L"";
return false;
}
return true;
}
bool WStrToUtf8(wchar_t* wstr, size_t size, std::string& utf8str)
{
try
{
std::string utf8str2;
utf8str2.resize(size*4); // allocate for most long case
char* oend = utf8::utf16to8(wstr,wstr+size,&utf8str2[0]);
utf8str2.resize(oend-(&utf8str2[0])); // remove unused tail
utf8str = utf8str2;
}
catch(std::exception)
{
utf8str = "";
return false;
}
return true;
}
bool WStrToUtf8(std::wstring wstr, std::string& utf8str)
{
try
{
std::string utf8str2;
utf8str2.resize(wstr.size()*4); // allocate for most long case
char* oend = utf8::utf16to8(wstr.c_str(),wstr.c_str()+wstr.size(),&utf8str2[0]);
utf8str2.resize(oend-(&utf8str2[0])); // remove unused tail
utf8str = utf8str2;
}
catch(std::exception)
{
utf8str = "";
return false;
}
return true;
}
typedef wchar_t const* const* wstrlist;
std::wstring GetMainPartOfName(std::wstring wname, uint32 declension)
{
// supported only Cyrillic cases
if(wname.size() < 1 || !isCyrillicCharacter(wname[0]) || declension > 5)
return wname;
// Important: end length must be <= MAX_INTERNAL_PLAYER_NAME-MAX_PLAYER_NAME (3 currently)
static wchar_t const a_End[] = { wchar_t(1), wchar_t(0x0430),wchar_t(0x0000)};
static wchar_t const o_End[] = { wchar_t(1), wchar_t(0x043E),wchar_t(0x0000)};
static wchar_t const ya_End[] = { wchar_t(1), wchar_t(0x044F),wchar_t(0x0000)};
static wchar_t const ie_End[] = { wchar_t(1), wchar_t(0x0435),wchar_t(0x0000)};
static wchar_t const i_End[] = { wchar_t(1), wchar_t(0x0438),wchar_t(0x0000)};
static wchar_t const yeru_End[] = { wchar_t(1), wchar_t(0x044B),wchar_t(0x0000)};
static wchar_t const u_End[] = { wchar_t(1), wchar_t(0x0443),wchar_t(0x0000)};
static wchar_t const yu_End[] = { wchar_t(1), wchar_t(0x044E),wchar_t(0x0000)};
static wchar_t const oj_End[] = { wchar_t(2), wchar_t(0x043E),wchar_t(0x0439),wchar_t(0x0000)};
static wchar_t const ie_j_End[] = { wchar_t(2), wchar_t(0x0435),wchar_t(0x0439),wchar_t(0x0000)};
static wchar_t const io_j_End[] = { wchar_t(2), wchar_t(0x0451),wchar_t(0x0439),wchar_t(0x0000)};
static wchar_t const o_m_End[] = { wchar_t(2), wchar_t(0x043E),wchar_t(0x043C),wchar_t(0x0000)};
static wchar_t const io_m_End[] = { wchar_t(2), wchar_t(0x0451),wchar_t(0x043C),wchar_t(0x0000)};
static wchar_t const ie_m_End[] = { wchar_t(2), wchar_t(0x0435),wchar_t(0x043C),wchar_t(0x0000)};
static wchar_t const soft_End[] = { wchar_t(1), wchar_t(0x044C),wchar_t(0x0000)};
static wchar_t const j_End[] = { wchar_t(1), wchar_t(0x0439),wchar_t(0x0000)};
static wchar_t const* const dropEnds[6][8] = {
{ &a_End[1], &o_End[1], &ya_End[1], &ie_End[1], &soft_End[1], &j_End[1], NULL, NULL },
{ &a_End[1], &ya_End[1], &yeru_End[1], &i_End[1], NULL, NULL, NULL, NULL },
{ &ie_End[1], &u_End[1], &yu_End[1], &i_End[1], NULL, NULL, NULL, NULL },
{ &u_End[1], &yu_End[1], &o_End[1], &ie_End[1], &soft_End[1], &ya_End[1], &a_End[1], NULL },
{ &oj_End[1], &io_j_End[1], &ie_j_End[1], &o_m_End[1], &io_m_End[1], &ie_m_End[1], &yu_End[1], NULL },
{ &ie_End[1], &i_End[1], NULL, NULL, NULL, NULL, NULL, NULL }
};
for(wchar_t const * const* itr = &dropEnds[declension][0]; *itr; ++itr)
{
size_t len = size_t((*itr)[-1]); // get length from string size field
if(wname.substr(wname.size()-len,len)==*itr)
return wname.substr(0,wname.size()-len);
}
return wname;
}
bool utf8ToConsole(std::string utf8str, std::string& conStr)
{
#if PLATFORM == PLATFORM_WINDOWS
std::wstring wstr;
if(!Utf8toWStr(utf8str,wstr))
return false;
conStr.resize(wstr.size());
CharToOemBuffW(&wstr[0],&conStr[0],wstr.size());
#else
// not implemented yet
conStr = utf8str;
#endif
return true;
}
bool consoleToUtf8(std::string conStr,std::string& utf8str)
{
#if PLATFORM == PLATFORM_WINDOWS
std::wstring wstr;
wstr.resize(conStr.size());
OemToCharBuffW(&conStr[0],&wstr[0],conStr.size());
return WStrToUtf8(wstr,utf8str);
#else
// not implemented yet
utf8str = conStr;
return true;
#endif
}
bool Utf8FitTo(std::string str, std::wstring search)
{
std::wstring temp;
if(!Utf8toWStr(str,temp))
return false;
// converting to lower case
wstrToLower( temp );
if(temp.find(search) == std::wstring::npos)
return false;
return true;
}

306
src/shared/Util.h Normal file
View file

@ -0,0 +1,306 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef _UTIL_H
#define _UTIL_H
#include "Common.h"
#include <string>
#include <vector>
typedef std::vector<std::string> Tokens;
Tokens StrSplit(const std::string &src, const std::string &sep);
void stripLineInvisibleChars(std::string &src);
std::string secsToTimeString(uint32 timeInSecs, bool shortText = false, bool hoursOnly = false);
uint32 TimeStringToSecs(std::string timestring);
std::string TimeToTimestampStr(time_t t);
inline uint32 secsToTimeBitFields(time_t secs)
{
tm* lt = localtime(&secs);
return (lt->tm_year - 100) << 24 | lt->tm_mon << 20 | (lt->tm_mday - 1) << 14 | lt->tm_wday << 11 | lt->tm_hour << 6 | lt->tm_min;
}
/* Return a random number in the range min..max; (max-min) must be smaller than 32768. */
MANGOS_DLL_SPEC int32 irand(int32 min, int32 max);
/* Return a random number in the range min..max (inclusive). For reliable results, the difference
* between max and min should be less than RAND32_MAX. */
MANGOS_DLL_SPEC uint32 urand(uint32 min, uint32 max);
/* Return a random number in the range 0 .. RAND32_MAX. */
MANGOS_DLL_SPEC int32 rand32();
/* Return a random double from 0.0 to 1.0 (exclusive). Floats support only 7 valid decimal digits.
* A double supports up to 15 valid decimal digits and is used internally (RAND32_MAX has 10 digits).
* With an FPU, there is usually no difference in performance between float and double. */
MANGOS_DLL_SPEC double rand_norm(void);
/* Return a random double from 0.0 to 99.9999999999999. Floats support only 7 valid decimal digits.
* A double supports up to 15 valid decimal digits and is used internaly (RAND32_MAX has 10 digits).
* With an FPU, there is usually no difference in performance between float and double. */
MANGOS_DLL_SPEC double rand_chance(void);
/* Return true if a random roll fits in the specified chance (range 0-100). */
inline bool roll_chance_f(float chance)
{
return chance > rand_chance();
}
/* Return true if a random roll fits in the specified chance (range 0-100). */
inline bool roll_chance_i(int chance)
{
return chance > irand(0, 99);
}
inline void ApplyModUInt32Var(uint32& var, int32 val, bool apply)
{
int32 cur = var;
cur += (apply ? val : -val);
if(cur < 0)
cur = 0;
var = cur;
}
inline void ApplyModFloatVar(float& var, float val, bool apply)
{
var += (apply ? val : -val);
if(var < 0)
var = 0;
}
inline void ApplyPercentModFloatVar(float& var, float val, bool apply)
{
if (!apply && val == -100.0f)
val = -99.99f;
var *= (apply?(100.0f+val)/100.0f : 100.0f / (100.0f+val));
}
bool Utf8toWStr(std::string utf8str, std::wstring& wstr);
// in wsize==max size of buffer, out wsize==real string size
bool Utf8toWStr(char const* utf8str, size_t csize, wchar_t* wstr, size_t& wsize);
inline bool Utf8toWStr(std::string utf8str, wchar_t* wstr, size_t& wsize)
{
return Utf8toWStr(utf8str.c_str(), utf8str.size(), wstr, wsize);
}
bool WStrToUtf8(std::wstring wstr, std::string& utf8str);
// size==real string size
bool WStrToUtf8(wchar_t* wstr, size_t size, std::string& utf8str);
size_t utf8length(std::string& utf8str); // set string to "" if invalid utf8 sequence
void utf8truncate(std::string& utf8str,size_t len);
inline bool isBasicLatinCharacter(wchar_t wchar)
{
if(wchar >= L'a' && wchar <= L'z') // LATIN SMALL LETTER A - LATIN SMALL LETTER Z
return true;
if(wchar >= L'A' && wchar <= L'Z') // LATIN CAPITAL LETTER A - LATIN CAPITAL LETTER Z
return true;
return false;
}
inline bool isExtendedLatinCharacter(wchar_t wchar)
{
if(isBasicLatinCharacter(wchar))
return true;
if(wchar >= 0x00C0 && wchar <= 0x00D6) // LATIN CAPITAL LETTER A WITH GRAVE - LATIN CAPITAL LETTER O WITH DIAERESIS
return true;
if(wchar >= 0x00D8 && wchar <= 0x00DF) // LATIN CAPITAL LETTER O WITH STROKE - LATIN CAPITAL LETTER THORN
return true;
if(wchar == 0x00DF) // LATIN SMALL LETTER SHARP S
return true;
if(wchar >= 0x00E0 && wchar <= 0x00F6) // LATIN SMALL LETTER A WITH GRAVE - LATIN SMALL LETTER O WITH DIAERESIS
return true;
if(wchar >= 0x00F8 && wchar <= 0x00FE) // LATIN SMALL LETTER O WITH STROKE - LATIN SMALL LETTER THORN
return true;
if(wchar >= 0x0100 && wchar <= 0x012F) // LATIN CAPITAL LETTER A WITH MACRON - LATIN SMALL LETTER I WITH OGONEK
return true;
if(wchar == 0x1E9E) // LATIN CAPITAL LETTER SHARP S
return true;
return false;
}
inline bool isCyrillicCharacter(wchar_t wchar)
{
if(wchar >= 0x0410 && wchar <= 0x044F) // CYRILLIC CAPITAL LETTER A - CYRILLIC SMALL LETTER YA
return true;
if(wchar == 0x0401 || wchar == 0x0451) // CYRILLIC CAPITAL LETTER IO, CYRILLIC SMALL LETTER IO
return true;
return false;
}
inline bool isEastAsianCharacter(wchar_t wchar)
{
if(wchar >= 0x1100 && wchar <= 0x11F9) // Hangul Jamo
return true;
if(wchar >= 0x3041 && wchar <= 0x30FF) // Hiragana + Katakana
return true;
if(wchar >= 0x3131 && wchar <= 0x318E) // Hangul Compatibility Jamo
return true;
if(wchar >= 0x31F0 && wchar <= 0x31FF) // Katakana Phonetic Ext.
return true;
if(wchar >= 0x3400 && wchar <= 0x4DB5) // CJK Ideographs Ext. A
return true;
if(wchar >= 0x4E00 && wchar <= 0x9FC3) // Unified CJK Ideographs
return true;
if(wchar >= 0xAC00 && wchar <= 0xD7A3) // Hangul Syllables
return true;
if(wchar >= 0xFF01 && wchar <= 0xFFEE) // Halfwidth forms
return true;
return false;
}
inline bool isNumericOrSpace(wchar_t wchar)
{
return (wchar >= L'0' && wchar <=L'9') || wchar == L' ';
}
inline bool isBasicLatinString(std::wstring wstr, bool numericOrSpace)
{
for(size_t i = 0; i < wstr.size(); ++i)
if(!isBasicLatinCharacter(wstr[i]) && (!numericOrSpace || !isNumericOrSpace(wstr[i])))
return false;
return true;
}
inline bool isExtendedLatinString(std::wstring wstr, bool numericOrSpace)
{
for(size_t i = 0; i < wstr.size(); ++i)
if(!isExtendedLatinCharacter(wstr[i]) && (!numericOrSpace || !isNumericOrSpace(wstr[i])))
return false;
return true;
}
inline bool isCyrillicString(std::wstring wstr, bool numericOrSpace)
{
for(size_t i = 0; i < wstr.size(); ++i)
if(!isCyrillicCharacter(wstr[i]) && (!numericOrSpace || !isNumericOrSpace(wstr[i])))
return false;
return true;
}
inline bool isEastAsianString(std::wstring wstr, bool numericOrSpace)
{
for(size_t i = 0; i < wstr.size(); ++i)
if(!isEastAsianCharacter(wstr[i]) && (!numericOrSpace || !isNumericOrSpace(wstr[i])))
return false;
return true;
}
inline wchar_t wcharToUpper(wchar_t wchar)
{
if(wchar >= L'a' && wchar <= L'z') // LATIN SMALL LETTER A - LATIN SMALL LETTER Z
return wchar_t(uint16(wchar)-0x0020);
if(wchar == 0x00DF) // LATIN SMALL LETTER SHARP S
return wchar_t(0x1E9E);
if(wchar >= 0x00E0 && wchar <= 0x00F6) // LATIN SMALL LETTER A WITH GRAVE - LATIN SMALL LETTER O WITH DIAERESIS
return wchar_t(uint16(wchar)-0x0020);
if(wchar >= 0x00F8 && wchar <= 0x00FE) // LATIN SMALL LETTER O WITH STROKE - LATIN SMALL LETTER THORN
return wchar_t(uint16(wchar)-0x0020);
if(wchar >= 0x0101 && wchar <= 0x012F) // LATIN SMALL LETTER A WITH MACRON - LATIN SMALL LETTER I WITH OGONEK (only %2=1)
{
if(wchar % 2 == 1)
return wchar_t(uint16(wchar)-0x0001);
}
if(wchar >= 0x0430 && wchar <= 0x044F) // CYRILLIC SMALL LETTER A - CYRILLIC SMALL LETTER YA
return wchar_t(uint16(wchar)-0x0020);
if(wchar == 0x0451) // CYRILLIC SMALL LETTER IO
return wchar_t(0x0401);
return wchar;
}
inline wchar_t wcharToUpperOnlyLatin(wchar_t wchar)
{
return isBasicLatinCharacter(wchar) ? wcharToUpper(wchar) : wchar;
}
inline wchar_t wcharToLower(wchar_t wchar)
{
if(wchar >= L'A' && wchar <= L'Z') // LATIN CAPITAL LETTER A - LATIN CAPITAL LETTER Z
return wchar_t(uint16(wchar)+0x0020);
if(wchar >= 0x00C0 && wchar <= 0x00D6) // LATIN CAPITAL LETTER A WITH GRAVE - LATIN CAPITAL LETTER O WITH DIAERESIS
return wchar_t(uint16(wchar)+0x0020);
if(wchar >= 0x00D8 && wchar <= 0x00DE) // LATIN CAPITAL LETTER O WITH STROKE - LATIN CAPITAL LETTER THORN
return wchar_t(uint16(wchar)+0x0020);
if(wchar >= 0x0100 && wchar <= 0x012E) // LATIN CAPITAL LETTER A WITH MACRON - LATIN CAPITAL LETTER I WITH OGONEK (only %2=0)
{
if(wchar % 2 == 0)
return wchar_t(uint16(wchar)+0x0001);
}
if(wchar == 0x1E9E) // LATIN CAPITAL LETTER SHARP S
return wchar_t(0x00DF);
if(wchar == 0x0401) // CYRILLIC CAPITAL LETTER IO
return wchar_t(0x0451);
if(wchar >= 0x0410 && wchar <= 0x042F) // CYRILLIC CAPITAL LETTER A - CYRILLIC CAPITAL LETTER YA
return wchar_t(uint16(wchar)+0x0020);
return wchar;
}
inline void wstrToUpper(std::wstring& str)
{
std::transform( str.begin(), str.end(), str.begin(), wcharToUpper );
}
inline void wstrToLower(std::wstring& str)
{
std::transform( str.begin(), str.end(), str.begin(), wcharToLower );
}
std::wstring GetMainPartOfName(std::wstring wname, uint32 declension);
bool utf8ToConsole(std::string utf8str, std::string& conStr);
bool consoleToUtf8(std::string conStr,std::string& utf8str);
bool Utf8FitTo(std::string str, std::wstring search);
#if PLATFORM == PLATFORM_WINDOWS
#define UTF8PRINTF(OUT,FRM,RESERR) \
{ \
char temp_buf[6000]; \
va_list ap; \
va_start(ap, FRM); \
size_t temp_len = vsnprintf(temp_buf,6000,FRM,ap); \
va_end(ap); \
\
wchar_t wtemp_buf[6000]; \
size_t wtemp_len = 6000-1; \
if(!Utf8toWStr(temp_buf,temp_len,wtemp_buf,wtemp_len)) \
return RESERR; \
CharToOemBuffW(&wtemp_buf[0],&temp_buf[0],wtemp_len+1);\
fprintf(OUT,temp_buf); \
}
#else
#define UTF8PRINTF(OUT,FRM,RESERR) \
{ \
va_list ap; \
va_start(ap, FRM); \
vfprintf(OUT, FRM, ap ); \
va_end(ap); \
}
#endif
bool IsIPAddress(char const* ipaddress);
uint32 CreatePIDFile(std::string filename);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,117 @@
#ifndef _WHEATYEXCEPTIONREPORT_
#define _WHEATYEXCEPTIONREPORT_
#include <dbghelp.h>
#if _MSC_VER < 1400
# define countof(array) (sizeof(array) / sizeof(array[0]))
#else
# include <stdlib.h>
# define countof _countof
#endif // _MSC_VER < 1400
enum BasicType // Stolen from CVCONST.H in the DIA 2.0 SDK
{
btNoType = 0,
btVoid = 1,
btChar = 2,
btWChar = 3,
btInt = 6,
btUInt = 7,
btFloat = 8,
btBCD = 9,
btBool = 10,
btLong = 13,
btULong = 14,
btCurrency = 25,
btDate = 26,
btVariant = 27,
btComplex = 28,
btBit = 29,
btBSTR = 30,
btHresult = 31
};
const char* const rgBaseType[] =
{
" <user defined> ", // btNoType = 0,
" void ", // btVoid = 1,
" char* ", // btChar = 2,
" wchar_t* ", // btWChar = 3,
" signed char ",
" unsigned char ",
" int ", // btInt = 6,
" unsigned int ", // btUInt = 7,
" float ", // btFloat = 8,
" <BCD> ", // btBCD = 9,
" bool ", // btBool = 10,
" short ",
" unsigned short ",
" long ", // btLong = 13,
" unsigned long ", // btULong = 14,
" __int8 ",
" __int16 ",
" __int32 ",
" __int64 ",
" __int128 ",
" unsigned __int8 ",
" unsigned __int16 ",
" unsigned __int32 ",
" unsigned __int64 ",
" unsigned __int128 ",
" <currency> ", // btCurrency = 25,
" <date> ", // btDate = 26,
" VARIANT ", // btVariant = 27,
" <complex> ", // btComplex = 28,
" <bit> ", // btBit = 29,
" BSTR ", // btBSTR = 30,
" HRESULT " // btHresult = 31
};
class WheatyExceptionReport
{
public:
WheatyExceptionReport( );
~WheatyExceptionReport( );
// entry point where control comes on an unhandled exception
static LONG WINAPI WheatyUnhandledExceptionFilter(
PEXCEPTION_POINTERS pExceptionInfo );
static void printTracesForAllThreads();
private:
// where report info is extracted and generated
static void GenerateExceptionReport( PEXCEPTION_POINTERS pExceptionInfo );
static void PrintSystemInfo();
static BOOL _GetWindowsVersion(TCHAR* szVersion, DWORD cntMax);
static BOOL _GetProcessorName(TCHAR* sProcessorName, DWORD maxcount);
// Helper functions
static LPTSTR GetExceptionString( DWORD dwCode );
static BOOL GetLogicalAddress( PVOID addr, PTSTR szModule, DWORD len,
DWORD& section, DWORD_PTR& offset );
static void WriteStackDetails( PCONTEXT pContext, bool bWriteVariables, HANDLE pThreadHandle);
static BOOL CALLBACK EnumerateSymbolsCallback(PSYMBOL_INFO,ULONG, PVOID);
static bool FormatSymbolValue( PSYMBOL_INFO, STACKFRAME *, char * pszBuffer, unsigned cbBuffer );
static char * DumpTypeIndex( char *, DWORD64, DWORD, unsigned, DWORD_PTR, bool & , char*);
static char * FormatOutputValue( char * pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress );
static BasicType GetBasicType( DWORD typeIndex, DWORD64 modBase );
static int __cdecl _tprintf(const TCHAR * format, ...);
// Variables used by the class
static TCHAR m_szLogFileName[MAX_PATH];
static LPTOP_LEVEL_EXCEPTION_FILTER m_previousFilter;
static HANDLE m_hReportFile;
static HANDLE m_hProcess;
};
extern WheatyExceptionReport g_WheatyExceptionReport; // global instance of class
#endif //WheatyExceptionReport

51
src/shared/WorldPacket.h Normal file
View file

@ -0,0 +1,51 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef MANGOSSERVER_WORLDPACKET_H
#define MANGOSSERVER_WORLDPACKET_H
#include "Common.h"
#include "ByteBuffer.h"
class WorldPacket : public ByteBuffer
{
public:
// just container for later use
WorldPacket() : ByteBuffer(0), m_opcode(0)
{
}
explicit WorldPacket(uint16 opcode, size_t res=200) : ByteBuffer(res), m_opcode(opcode) { }
// copy constructor
WorldPacket(const WorldPacket &packet) : ByteBuffer(packet), m_opcode(packet.m_opcode)
{
}
void Initialize(uint16 opcode, size_t newres=200)
{
clear();
_storage.reserve(newres);
m_opcode = opcode;
}
uint16 GetOpcode() const { return m_opcode; }
void SetOpcode(uint16 opcode) { m_opcode = opcode; }
protected:
uint16 m_opcode;
};
#endif

1620
src/shared/vmap/AABSPTree.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,95 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#include "BaseModel.h"
#include "VMapTools.h"
using namespace G3D;
namespace VMAP
{
//==========================================================
void BaseModel::getMember(Array<TriangleBox>& pMembers)
{
for(unsigned int i=0; i<iNTriangles; i++)
{
pMembers.append(iTriangles[i]);
}
}
//==========================================================
BaseModel::BaseModel(unsigned int pNNodes, unsigned int pNTriangles)
{
init(pNNodes, pNTriangles);
};
//==========================================================
void BaseModel::init(unsigned int pNNodes, unsigned int pNTriangles)
{
iNNodes = pNNodes;
iNTriangles = pNTriangles;
iTriangles = 0;
iTreeNodes = 0;
if(iNNodes >0) iTreeNodes = new TreeNode[iNNodes];
if(iNTriangles >0) iTriangles = new TriangleBox[iNTriangles];
}
//==========================================================
void BaseModel::free()
{
if(getTriangles() != 0) delete [] getTriangles(); setNTriangles(0);
if(getTreeNodes() != 0) delete [] getTreeNodes(); setNNodes(0);
}
//==========================================================
void BaseModel::intersect(const G3D::AABox& pBox, const G3D::Ray& pRay, float& pMaxDist, G3D::Vector3& pOutLocation, G3D::Vector3& /*pOutNormal*/) const
{
bool isInside = false;
float d = MyCollisionDetection::collisionLocationForMovingPointFixedAABox(
pRay.origin, pRay.direction,
pBox,
pOutLocation, isInside);
if (!isInside && ((d > 0) && (d < pMaxDist)))
{
pMaxDist = d;
}
}
//==========================================================
bool BaseModel::intersect(const G3D::AABox& pBox, const G3D::Ray& pRay, float& pMaxDist) const
{
// See if the ray will ever hit this node or its children
Vector3 location;
bool alreadyInsideBounds = false;
bool rayWillHitBounds =
MyCollisionDetection::collisionLocationForMovingPointFixedAABox(
pRay.origin, pRay.direction, pBox, location, alreadyInsideBounds);
bool canHitThisNode = (alreadyInsideBounds ||
(rayWillHitBounds && ((location - pRay.origin).squaredLength() < (pMaxDist * pMaxDist))));
return canHitThisNode;
}
} // VMAP

View file

@ -0,0 +1,99 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef _BASEMODEL_H_
#define _BASEMODEL_H_
#include <G3D/AABox.h>
#include <G3D/Vector3.h>
#include "ShortVector.h"
#include "ShortBox.h"
#include "TreeNode.h"
/**
A model is based on triangles. To be able to check intersection we need a BSP-Tree.
This Class holds the array of triangles as well as the management information for the BSP-Tree.
Both are stored in static array and index information is used instead of pointers.
Therefore we can load the whole object as a binary block.
The vectors are relative to a base position.
*/
namespace VMAP
{
class BaseModel
{
protected:
TriangleBox *iTriangles;
TreeNode *iTreeNodes;
unsigned int iNTriangles;
unsigned int iNNodes;
G3D::Vector3 iBasePosition;
public:
BaseModel() { iNTriangles = 0; iNNodes = 0; iTriangles = 0; iTreeNodes = 0;};
BaseModel(unsigned int pNNodes , TreeNode* pTreeNode, unsigned int pNTriangles, TriangleBox* pTriangleBox)
{
iNNodes = pNNodes; iNTriangles = pNTriangles; iTriangles = pTriangleBox; iTreeNodes = pTreeNode;
};
BaseModel(unsigned int pNNodes, unsigned int pNTriangles);
// destructor does nothing ! The subclass controles the array memory and knows when to free it
~BaseModel() {}
void free();
void init(unsigned int pNNodes, unsigned int pNTriangles);
void getMember(G3D::Array<TriangleBox>& pMembers);
inline const TriangleBox& getTriangle(int pPos) const { return(iTriangles[pPos]); }
inline TriangleBox& getTriangle(int pPos) { return(iTriangles[pPos]); }
inline void setTriangle(const TriangleBox& pTriangleBox, int pPos) { iTriangles[pPos] = pTriangleBox; }
inline const TreeNode& getTreeNode(int pPos) const { return(getTreeNodes()[pPos]); }
inline TreeNode& getTreeNode(int pPos) { return(getTreeNodes()[pPos]); }
inline void setTreeNode(const TreeNode& pTreeNode, int pPos) { getTreeNodes()[pPos] = pTreeNode; }
inline void setBasePosition(const G3D::Vector3& pBasePosition) { iBasePosition = pBasePosition; }
inline const G3D::Vector3& getBasePosition() const { return(iBasePosition); }
inline unsigned int getNNodes() const { return(iNNodes); }
inline unsigned int getNTriangles() const { return(iNTriangles); }
inline void setNNodes(unsigned int pNNodes) { iNNodes = pNNodes; }
inline void setNTriangles(unsigned int pNTriangles) { iNTriangles = pNTriangles; }
inline void setTriangleArray(TriangleBox *pGlobalTriangleArray ) { iTriangles = pGlobalTriangleArray ; }
inline void setTreeNodeArray(TreeNode *pGlobalTreeNodeArray ) { iTreeNodes = pGlobalTreeNodeArray ; }
inline TriangleBox* getTriangles() const { return(iTriangles); }
inline TreeNode* getTreeNodes() const{ return(iTreeNodes); }
inline size_t getMemUsage() { return(iNTriangles * sizeof(TriangleBox) + iNNodes * sizeof(TreeNode) + sizeof(BaseModel)); }
void intersect(const G3D::AABox& pBox, const G3D::Ray& pRay, float& pMaxDist, G3D::Vector3& pOutLocation, G3D::Vector3& pOutNormal) const;
bool intersect(const G3D::AABox& pBox, const G3D::Ray& pRay, float& pMaxDist) const;
};
}
#endif /*BASEMODEL_H_*/

View file

@ -0,0 +1,187 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#include "CoordModelMapping.h"
#include <string.h>
using namespace G3D;
namespace VMAP
{
//============================================================
//============================================================
void CMappingEntry::addFilename(char *pName)
{
std::string name = std::string(pName);
if(!iFilenames.contains(name))
iFilenames.append(std::string(pName));
}
//============================================================
const std::string CMappingEntry::getKeyString() const
{
return(CMappingEntry::getKeyString(iMapId,xPos, yPos));
}
//============================================================
//============================================================
//============================================================
CoordModelMapping::~CoordModelMapping()
{
Array<std::string> keys = iMapObjectFiles.getKeys();
for (int k = 0; k < keys.length(); k++)
{
CMappingEntry *value = getCMappingEntry(keys[k]);
if(value != 0)
{
iMapObjectFiles.remove(keys[k]);
delete value;
}
}
}
//============================================================
int findPosChar(const char *namebuffer, char pSearch, int pCount)
{
int result = -1;
int pos=0;
while(namebuffer[pos] != 0)
{
if(namebuffer[pos] == pSearch)
{
--pCount;
}
if(pCount == 0)
{
result = pos;
break;
}
++pos;
}
return result;
}
//============================================================
bool CoordModelMapping::readCoordinateMapping(const std::string& pDirectoryFileName)
{
FILE *f = fopen(pDirectoryFileName.c_str(), "rb");
bool result = false;
char buffer[500+1];
if(f)
{
result = true;
CMappingEntry* cMappingEntry;
while(fgets(buffer, 500, f))
{
//char namebuffer[500];
char positionbuffer[500];
int xpos, ypos, noVec;
float scale;
xpos = ypos = noVec = 0;
//sscanf(buffer, "%d %d %s %s %f %d", &xpos, &ypos, namebuffer,positionbuffer, &scale, &noVec);
// this is ugly, but the format has no read delimiter and a space could be in the first part of the name
int nameStart = findPosChar(buffer, ' ', 2);// find the 2. space
if(nameStart > -1 && (iFilterMethod == NULL || (*iFilterMethod)(buffer)))
{
++nameStart;
// find the 1. / (now a space only can be found at the end of the name)
int nameEnd = nameStart + findPosChar(&buffer[nameStart], '/', 1);
// find the 1. space (after the name)
nameEnd += findPosChar(&buffer[nameEnd], ' ', 1);
buffer[nameEnd] = 0; // terminate the name
sscanf(buffer, "%d %d", &xpos, &ypos);
sscanf(&buffer[nameEnd+1], "%s %f %d", positionbuffer, &scale, &noVec);
unsigned int mapId = getMapIdFromFilename(std::string(&buffer[nameStart]));
if(!iMapIds.contains(mapId))
{
iMapIds.append(mapId);
}
if(!isWorldAreaMap(mapId))
{
xpos = 0; // store all files under the groupKey
ypos = 0;
}
std::string key = CMappingEntry::getKeyString(mapId, xpos, ypos);
cMappingEntry = getCMappingEntry(key);
if(cMappingEntry == 0)
{
cMappingEntry = new CMappingEntry(mapId, xpos, ypos);
addCMappingEntry(cMappingEntry);
}
char namebuffer2[500];
sprintf(namebuffer2, "%d %s#%s_%f", noVec, &buffer[nameStart], positionbuffer, scale);
cMappingEntry->addFilename(namebuffer2);
//break;
}
}
fclose(f);
}
return result;
}
//============================================================
const NameCollection CoordModelMapping::getFilenamesForCoordinate(unsigned int pMapId, int xPos, int yPos)
{
NameCollection result;
Array<std::string> rawNames;
CMappingEntry *entry = getCMappingEntry(CMappingEntry::getKeyString(pMapId, xPos, yPos));
if(entry != 0)
{
rawNames = entry->getFilenames();
int pos = 0;
while(pos < rawNames.size())
{
char namebuffer[500];
int noVerc;
int startName = findPosChar(rawNames[pos].c_str(), ' ', 1) + 1;
int endName = (int) rawNames[pos].length();
sscanf(rawNames[pos].c_str(), "%d", &noVerc);
memcpy(namebuffer, &rawNames[pos].c_str()[startName], endName-startName);
namebuffer[endName-startName] = 0;
sscanf(rawNames[pos].c_str(), "%d", &noVerc);
std::string modelPosFileName = std::string(namebuffer);
if(noVerc > MIN_VERTICES_FOR_OWN_CONTAINER_FILE)
{
result.appendToSingle(modelPosFileName);
}
else
{
result.appendToMain(modelPosFileName);
}
++pos;
}
}
return result;
}
//=================================================================
}

View file

@ -0,0 +1,144 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef _COORDMODELMAPPING_H_
#define _COORDMODELMAPPING_H_
#include <G3D/Table.h>
#include <G3D/Array.h>
/**
This Class is a helper Class to convert the raw vector data into BSP-Trees.
We read the directory file of the raw data output and build logical groups.
Models with a lot of vectors are not merged into a resulting model, but separated into an additional file.
*/
namespace VMAP
{
#define MIN_VERTICES_FOR_OWN_CONTAINER_FILE 65000
// if we are in an instance
#define MIN_INST_VERTICES_FOR_OWN_CONTAINER_FILE 40000
//=====================================================
class NameCollection
{
public:
G3D::Array<std::string> iMainFiles;
G3D::Array<std::string> iSingeFiles;
void appendToMain(std::string pStr) { iMainFiles.append(pStr); }
void appendToSingle(std::string pStr) { iSingeFiles.append(pStr); }
size_t size() { return (iMainFiles.size() + iSingeFiles.size()); }
};
//=====================================================
class CMappingEntry
{
private:
int xPos;
int yPos;
unsigned int iMapId;
G3D::Array<std::string> iFilenames;
public:
CMappingEntry() { };
CMappingEntry(unsigned int pMapId, const int pXPos, const int pYPos)
{
iMapId = pMapId;
xPos = pXPos; yPos = pYPos;
};
~CMappingEntry() {};
void addFilename(char *pName);
const std::string getKeyString() const;
inline const G3D::Array<std::string>& getFilenames() const { return(iFilenames); }
static const std::string getKeyString(unsigned int pMapId, int pXPos, int pYPos)
{
char b[100];
sprintf(b,"%03u_%d_%d", pMapId, pXPos, pYPos);
return(std::string(b));
}
};
//=====================================================
class CoordModelMapping
{
private:
G3D::Table<std::string, CMappingEntry *> iMapObjectFiles;
G3D::Table<std::string, std::string> iProcesseSingleFiles;
G3D::Array<unsigned int> iMapIds;
G3D::Array<unsigned int> iWorldAreaGroups;
bool (*iFilterMethod)(char *pName);
inline void addCMappingEntry(CMappingEntry* pCMappingEntry)
{
iMapObjectFiles.set(pCMappingEntry->getKeyString(), pCMappingEntry);
}
inline CMappingEntry* getCMappingEntry(const std::string& pKey)
{
if(iMapObjectFiles.containsKey(pKey))
return(iMapObjectFiles.get(pKey));
else
return 0;
}
public:
CoordModelMapping() { iFilterMethod = NULL; }
virtual ~CoordModelMapping();
bool readCoordinateMapping(const std::string& pDirectoryFileName);
const NameCollection getFilenamesForCoordinate(unsigned int pMapId, int xPos, int yPos);
static unsigned int getMapIdFromFilename(std::string pName)
{
size_t spos;
spos = pName.find_last_of('/');
std::string basename = pName.substr(0, spos);
spos = basename.find_last_of('/');
std::string groupname = basename.substr(spos+1, basename.length());
unsigned int mapId = atoi(groupname.c_str());
return(mapId);
}
const G3D::Array<unsigned int>& getMaps() const { return iMapIds; }
inline bool isAlreadyProcessedSingleFile(std::string pName) { return(iProcesseSingleFiles.containsKey(pName)); }
inline void addAlreadyProcessedSingleFile(std::string pName) { iProcesseSingleFiles.set(pName,pName); }
inline void addWorldAreaMap(unsigned int pMapId)
{
if(!iWorldAreaGroups.contains(pMapId))
{
iWorldAreaGroups.append(pMapId);
}
}
inline bool isWorldAreaMap(unsigned int pMapId) { return(iWorldAreaGroups.contains(pMapId)); }
void setModelNameFilterMethod(bool (*pFilterMethod)(char *pName)) { iFilterMethod = pFilterMethod; }
};
}
#endif /*_COORDMODELMAPPING_H_*/

View file

@ -0,0 +1,125 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#include "DebugCmdLogger.h"
using namespace G3D;
namespace VMAP
{
bool CommandFileRW::appendCmd(const Command&
#ifdef _DEBUG
pCommand
#endif
)
{
#ifdef _DEBUG
bool result = false;
if(iWritingEnabled || pCommand.isCoreCmd())
{
FILE* f = fopen(iFileName.c_str(), "ab");
if(f)
{
result = true;
if(fwrite(&pCommand, sizeof(Command), 1, f) != 1) { result = false; }
fclose(f);
}
}
else
{
result = true;
}
return result;
#else
return true;
#endif
}
//=========================================================
bool CommandFileRW::appendCmds(const Array<Command>&
#ifdef _DEBUG
pCmdArray
#endif
)
{
#ifdef _DEBUG
bool result = false;
if(iWritingEnabled)
{
FILE* f;
if(resetfile)
f = fopen(iFileName.c_str(), "wb");
else
f = fopen(iFileName.c_str(), "ab");
resetfile = false;
if(f)
{
result = true;
for(int i=0; i<pCmdArray.size(); ++i)
{
if(fwrite(&pCmdArray[i], sizeof(Command), 1, f) != 1) { result = false; break; }
}
fclose(f);
}
}
else
{
result = true;
}
return result;
#else
return true;
#endif
}
//=========================================================
bool CommandFileRW::getNewCommands(Array<Command>& pCmdArray)
{
bool result = false;
FILE* f = fopen(iFileName.c_str(), "rb");
if(f)
{
Command cmd;
if(fseek(f, iLastPos, SEEK_SET) == 0) { result = true; }
while(result)
{
if(fread(&cmd, sizeof(Command), 1, f) != 1)
{
result = false;
}
iLastPos = ftell(f);
if(cmd.getType() == STOP)
{
break;
}
pCmdArray.append(cmd);
}
fclose(f);
}
if(result)
{
iCommandArray.append(pCmdArray);
}
return(result);
}
//========================================================
}

View file

@ -0,0 +1,116 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef _DEBUGCMDLOGGER_H
#define _DEBUGCMDLOGGER_H
#include <G3D/Vector3.h>
#include <G3D/Array.h>
/**
Class is used for debugging. We log activities into a file.
With an external Class we read that log and display the activity in a graphical view.
*/
namespace VMAP
{
//==========================================
enum C_TYPES
{
STOP,
START,
LOAD_TILE,
UNLOAD_TILE,
SET_POS,
TEST_VIS,
LOAD_INSTANCE,
UNLOAD_INSTANCE,
TEST_HEIGHT,
TEST_OBJECT_HIT,
};
class Command
{
int iType;
float floats[9];
int ints[4];
char buffer[100];
public:
Command() { iType = STOP; }
inline int getType() { return iType; }
inline G3D::Vector3 getVector(int pos) { return(G3D::Vector3(floats[pos*3+0], floats[pos*3+1], floats[pos*3+2])); }
inline int getInt(int pos) { return(ints[pos]); }
inline char* getBuffer() { return(buffer); }
void fillStopCmd() { iType = STOP; }
void fillStartCmd() { iType = START; }
void fillLoadTileCmd(int x, int y, G3D::uint32 pMapId) { iType = LOAD_TILE; ints[0] = x; ints[1] = y; ints[2] = pMapId; }
//void fillLoadTileCmd(int x,int y) { iType = LOAD_TILE; ints[0] = x; ints[1] = y; }
void fillUnloadTileCmd(G3D::uint32 pMapId) { iType = UNLOAD_INSTANCE; ints[0] = pMapId; }
void fillUnloadTileCmd(unsigned int pMapId, int x,int y) { iType = UNLOAD_TILE; ints[0] = x; ints[1] = y; ints[0]=pMapId; }
void fillSetPosCmd(G3D::Vector3 pPos) { iType = SET_POS; floats[0] = pPos.x; floats[1]=pPos.y; floats[2]=pPos.z; }
void fillTestVisCmd(int pMapId, G3D::Vector3 pPos1, G3D::Vector3 pPos2, bool result)
{
iType = TEST_VIS; floats[0] = pPos1.x; floats[1]=pPos1.y; floats[2]=pPos1.z;
floats[3] = pPos2.x; floats[4]=pPos2.y; floats[5]=pPos2.z;
ints[0] = result; ints[1] = pMapId;
}
void fillTestHeightCmd(int pMapId, G3D::Vector3 pPos, float result)
{
iType = TEST_HEIGHT; floats[0] = pPos.x; floats[1]=pPos.y; floats[2]=pPos.z;
floats[3] = result; ints[0] = pMapId;
}
void fillTestObjectHitCmd(int pMapId, G3D::Vector3 pPos1, G3D::Vector3 pPos2, G3D::Vector3 pResultPos, bool result)
{
iType = TEST_OBJECT_HIT; floats[0] = pPos1.x; floats[1]=pPos1.y; floats[2]=pPos1.z;
floats[3] = pPos2.x; floats[4]=pPos2.y; floats[5]=pPos2.z;
floats[6] = pResultPos.x; floats[7]=pResultPos.y; floats[8]=pResultPos.z;
ints[0] = result; ints[1] = pMapId;
}
bool isCoreCmd() const { return(iType != TEST_VIS); }
};
//==========================================
class CommandFileRW
{
private:
std::string iFileName;
long iLastPos;
G3D::Array<G3D::Array<Command> > iCommandArray;
bool resetfile;
bool iWritingEnabled;
public:
CommandFileRW() { iLastPos=0; iWritingEnabled = true; resetfile = true;}
CommandFileRW(const std::string& pFileName) { iLastPos = 0; iFileName = pFileName; iWritingEnabled = true; resetfile = true; }
void setResetFile() { resetfile = true; }
void enableWriting(bool pValue) { iWritingEnabled = pValue; }
void setFileName(const std::string& pName) { iFileName = pName; }
bool getNewCommands(G3D::Array<Command>& commandArray);
const G3D::Array<G3D::Array<Command> >& getFullCommandArray() { return iCommandArray; }
bool appendCmd(const Command& pCommand);
bool appendCmds(const G3D::Array<Command>& pCmdArray);
};
}
#endif

View file

@ -0,0 +1,99 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef _IVMAPMANAGER_H
#define _IVMAPMANAGER_H
#include<string>
//===========================================================
/**
This is the minimum interface to the VMapMamager.
*/
namespace VMAP
{
enum VMAP_LOAD_RESULT
{
VMAP_LOAD_RESULT_ERROR,
VMAP_LOAD_RESULT_OK,
VMAP_LOAD_RESULT_IGNORED,
};
#define VMAP_INVALID_HEIGHT -100000.0f // for check
#define VMAP_INVALID_HEIGHT_VALUE -200000.0f // real assigned value in unknown height case
//===========================================================
class IVMapManager
{
private:
bool iEnableLineOfSightCalc;
bool iEnableHeightCalc;
public:
IVMapManager() : iEnableLineOfSightCalc(true), iEnableHeightCalc(true) {}
virtual ~IVMapManager(void) {}
virtual int loadMap(const char* pBasePath, unsigned int pMapId, int x, int y) = 0;
virtual bool existsMap(const char* pBasePath, unsigned int pMapId, int x, int y) = 0;
virtual void unloadMap(unsigned int pMapId, int x, int y) = 0;
virtual void unloadMap(unsigned int pMapId) = 0;
virtual bool isInLineOfSight(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2) = 0;
virtual float getHeight(unsigned int pMapId, float x, float y, float z) = 0;
/**
test if we hit an object. return true if we hit one. rx,ry,rz will hold the hit position or the dest position, if no intersection was found
return a position, that is pReduceDist closer to the origin
*/
virtual bool getObjectHitPos(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float &ry, float& rz, float pModifyDist) = 0;
/**
send debug commands
*/
virtual bool processCommand(char *pCommand)= 0;
/**
Enable/disable LOS calculation
It is enabled by default. If it is enabled in mid game the maps have to loaded manualy
*/
void setEnableLineOfSightCalc(bool pVal) { iEnableLineOfSightCalc = pVal; }
/**
Enable/disable model height calculation
It is enabled by default. If it is enabled in mid game the maps have to loaded manualy
*/
void setEnableHeightCalc(bool pVal) { iEnableHeightCalc = pVal; }
bool isLineOfSightCalcEnabled() const { return(iEnableLineOfSightCalc); }
bool isHeightCalcEnabled() const { return(iEnableHeightCalc); }
bool isMapLoadingEnabled() const { return(iEnableLineOfSightCalc || iEnableHeightCalc ); }
virtual std::string getDirFileName(unsigned int pMapId, int x, int y) const =0;
/**
Block maps from being used.
parameter: String of map ids. Delimiter = ","
e.g.: "0,1,530"
*/
virtual void preventMapsFromBeingUsed(const char* pMapIdString) =0;
};
}
#endif

View file

@ -0,0 +1,56 @@
# Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
#
# 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
## Process this file with automake to produce Makefile.in
## Sub-directories to parse
## CPP flags for includes, defines, etc.
AM_CPPFLAGS = $(MANGOS_INCLUDES) -I$(top_builddir)/src/shared -I$(srcdir) -I$(srcdir)/../../../dep/include -I$(srcdir)/../../framework -I$(srcdir)/../../shared -I$(srcdir)/../../../dep/include/g3dlite
## Build MaNGOS shared library and its parts as convenience library.
# All libraries will be convenience libraries. Might be changed to shared
# later.
noinst_LIBRARIES = libmangosvmaps.a
libmangosvmaps_a_SOURCES = \
AABSPTree.h \
BaseModel.cpp \
BaseModel.h \
CoordModelMapping.cpp \
CoordModelMapping.h \
DebugCmdLogger.cpp \
DebugCmdLogger.h \
IVMapManager.h \
ManagedModelContainer.cpp \
ManagedModelContainer.h \
ModelContainer.cpp \
ModelContainer.h \
NodeValueAccess.h \
ShortBox.h \
ShortVector.h \
SubModel.cpp \
SubModel.h \
TileAssembler.cpp \
TileAssembler.h \
TreeNode.cpp \
TreeNode.h \
VMapDefinitions.h \
VMapFactory.cpp \
VMapFactory.h \
VMapManager.cpp \
VMapManager.h \
VMapTools.h

View file

@ -0,0 +1,35 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#include "ManagedModelContainer.h"
using namespace G3D;
namespace VMAP
{
ManagedModelContainer::ManagedModelContainer(void) : ModelContainer()
{
refCount = 0;
}
ManagedModelContainer::~ManagedModelContainer(void)
{
}
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef _MANAGEDMODELCONTAINER_H
#define _MANAGEDMODELCONTAINER_H
#include "ModelContainer.h"
//=======================================================
/**
This is a ModelContainer with reference count information.
*/
namespace VMAP
{
//=======================================================
class ManagedModelContainer :
public ModelContainer
{
private:
int refCount;
public:
ManagedModelContainer(void) ;
~ManagedModelContainer(void);
void incRefCount() { ++refCount; }
void decRefCount() { --refCount; if(refCount < 0) refCount = 0; }
int getRefCount() { return refCount; }
};
//=======================================================
}
#endif

View file

@ -0,0 +1,375 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#include <iostream>
#include <fstream>
#include <string.h>
#include "ModelContainer.h"
#include "VMapDefinitions.h"
using namespace G3D;
namespace VMAP
{
//==========================================================
/**
Functions to use ModelContainer with a AABSPTree
*/
size_t hashCode(const ModelContainer& pMc)
{
return (pMc.getBasePosition() * pMc.getNTriangles()).hashCode();
}
//==========================================================
ModelContainer::ModelContainer(unsigned int pNTriangles, unsigned int pNNodes, unsigned int pNSubModel) :
BaseModel(pNNodes, pNTriangles)
{
iNSubModel = pNSubModel;
iSubModel = 0;
if(pNSubModel > 0) iSubModel = new SubModel[iNSubModel];
}
//==========================================================
bool ModelContainer::operator==(const ModelContainer& pMc2) const
{
if (this->iNSubModel == 0 && pMc2.iNSubModel == 0 && this->iSubModel == 0 && pMc2.iSubModel == 0)
return true;
return this == &pMc2;
}
//==========================================================
void ModelContainer::countSubModelsAndNodesAndTriangles(AABSPTree<SubModel *>::Node& pNode, int& nSubModels, int& nNodes, int& nTriangles)
{
// For this node we will need a TreeNode as well as for the internal nodes
++nNodes;
nSubModels += pNode.valueArray.size();
for(int i=0;i<pNode.valueArray.size(); i++)
{
G3D::_AABSPTree::Handle<SubModel*>* h= pNode.valueArray[i];
SubModel *m = h->value;
// add the internal nodes as well
nNodes += m->getNNodes();
nTriangles += m->getNTriangles();
}
if(pNode.child[0] != 0)
{
countSubModelsAndNodesAndTriangles(*pNode.child[0], nSubModels, nNodes, nTriangles);
}
if(pNode.child[1] != 0)
{
countSubModelsAndNodesAndTriangles(*pNode.child[1], nSubModels, nNodes, nTriangles);
}
}
//==========================================================
void ModelContainer::fillContainer(const AABSPTree<SubModel *>::Node& pNode, int &pSubModelPos, int &pTreeNodePos, int &pTrianglePos, Vector3& pLo, Vector3& pHi, Vector3& pFinalLo, Vector3& pFinalHi)
{
// TreeNode for the SubModel
TreeNode treeNode = TreeNode(pNode.valueArray.size(), pSubModelPos);
treeNode.setSplitAxis(pNode.splitAxis);
treeNode.setSplitLocation(pNode.splitLocation);
int currentTreeNodePos = pTreeNodePos++;
Vector3 lo = Vector3(inf(),inf(),inf());
Vector3 hi = Vector3(-inf(),-inf(),-inf());
for(int i=0;i<pNode.valueArray.size(); i++)
{
G3D::_AABSPTree::Handle<SubModel*>* h= pNode.valueArray[i];
SubModel *m = h->value;
memcpy(&getTreeNodes()[pTreeNodePos], &m->getTreeNode(0), sizeof(TreeNode) * m->getNNodes());
memcpy(&getTriangles()[pTrianglePos], &m->getTriangle(0), sizeof(TriangleBox) * m->getNTriangles());
SubModel newModel = SubModel(m->getNTriangles(), getTriangles(), pTrianglePos, m->getNNodes(), getTreeNodes(), pTreeNodePos);
newModel.setReletiveBounds(m->getReletiveBounds().getLo(), m->getReletiveBounds().getHi());
newModel.setBasePosition(m->getBasePosition());
iSubModel[pSubModelPos++] = newModel;
pTreeNodePos += m->getNNodes();
pTrianglePos += m->getNTriangles();
AABox box = m->getAABoxBounds();
lo = lo.min(box.low());
hi = hi.max(box.high());
pFinalLo = pFinalLo.min(lo);
pFinalHi = pFinalHi.max(hi);
}
/*
if(pNode.valueArray.size() == 0) {
int xxx = 0; // just for the breakpoint
}
*/
// get absolute bounds
if(pNode.child[0] != 0)
{
treeNode.setChildPos(0, pTreeNodePos);
fillContainer(*pNode.child[0], pSubModelPos, pTreeNodePos, pTrianglePos, lo, hi,pFinalLo,pFinalHi);
}
if(pNode.child[1] != 0)
{
treeNode.setChildPos(1, pTreeNodePos);
fillContainer(*pNode.child[1], pSubModelPos, pTreeNodePos, pTrianglePos, lo, hi,pFinalLo,pFinalHi);
}
pLo = pLo.min(lo);
pHi = pHi.max(hi);
treeNode.setBounds(lo,hi);
setTreeNode(treeNode, currentTreeNodePos);
}
//==========================================================
/**
Create the structure out of a AABSPTree
*/
ModelContainer::ModelContainer(AABSPTree<SubModel *> *pTree)
{
int nSubModels, nNodes, nTriangles;
nSubModels = nNodes = nTriangles = 0;
countSubModelsAndNodesAndTriangles(*pTree->root, nSubModels, nNodes, nTriangles);
init(nNodes, nTriangles);
iNSubModel = nSubModels;
iSubModel = new SubModel[iNSubModel];
int subModelPos,treeNodePos, trianglePos;
subModelPos = treeNodePos = trianglePos = 0;
Vector3 lo = Vector3(inf(),inf(),inf());
Vector3 hi = Vector3(-inf(),-inf(),-inf());
Vector3 finalLo, finalHi;
finalLo = lo;
finalHi = hi;
fillContainer(*pTree->root, subModelPos, treeNodePos, trianglePos, lo, hi, finalLo, finalHi);
setBounds(finalLo, finalHi);
}
//==========================================================
ModelContainer::~ModelContainer(void)
{
free();
if(iSubModel != 0) delete [] iSubModel;
}
//==========================================================
bool ModelContainer::writeFile(const char *filename)
{
bool result = false;
unsigned int flags=0;
unsigned int size;
FILE *wf =fopen(filename,"wb");
if(wf)
{
fwrite(VMAP_MAGIC,1,8,wf);
result = true;
if(result && fwrite("CTREE01",8,1,wf) != 1) result = false;
if(result && fwrite(&flags,sizeof(unsigned int),1,wf) != 1) result = false;
if(result && fwrite("POS ",4,1,wf) != 1) result = false;
size = sizeof(float)*3;
if(result && fwrite(&size,4,1,wf) != 1) result = false;
Vector3 basePos = getBasePosition();
if(result && fwrite(&basePos,sizeof(float),3,wf) != 3) result = false;
if(result && fwrite("BOX ",4,1,wf) != 1) result = false;
size = sizeof(float)*6;
if(result && fwrite(&size,4,1,wf) != 1) result = false;
Vector3 low = iBox.low();
if(result && fwrite(&low,sizeof(float),3,wf) != 3) result = false;
Vector3 high = iBox.high();
if(result && fwrite(&high,sizeof(float),3,wf) != 3) result = false;
if(result && fwrite("NODE",4,1,wf) != 1) result = false;
size = sizeof(unsigned int)+ sizeof(TreeNode)*getNNodes();
if(result && fwrite(&size,4,1,wf) != 1) result = false;
unsigned int val = getNNodes();
if(result && fwrite(&val,sizeof(unsigned int),1,wf) != 1) result = false;
if(result && fwrite(getTreeNodes(),sizeof(TreeNode),getNNodes(),wf) != getNNodes()) result = false;
if(result && fwrite("TRIB",4,1,wf) != 1) result = false;
size = sizeof(unsigned int)+ sizeof(TriangleBox)*getNTriangles();
if(result && fwrite(&size,4,1,wf) != 1) result = false;
val = getNTriangles();
if(result && fwrite(&val,sizeof(unsigned int),1,wf) != 1) result = false;
if(result && fwrite(getTriangles(),sizeof(TriangleBox),getNTriangles(),wf) != getNTriangles()) result = false;
if(result && fwrite("SUBM",4,1,wf) != 1) result = false;
size = sizeof(unsigned int)+ sizeof(SubModel)*iNSubModel;
if(result && fwrite(&size,4,1,wf) != 1) result = false;
if(result && fwrite(&iNSubModel,sizeof(unsigned int),1,wf) != 1) result = false;
if(result && fwrite(iSubModel,sizeof(SubModel),iNSubModel,wf) != iNSubModel) result = false;
fclose(wf);
}
return(result);
}
//===============================================================
bool ModelContainer::readFile(const char *filename)
{
bool result = false;
unsigned int flags;
unsigned int size;
char ident[8];
char chunk[4];
unsigned int ival;
FILE *rf = fopen(filename, "rb");
if(rf)
{
free();
result = true;
char magic[8]; // Ignore the added magic header
fread(magic,1,8,rf);
if(strncmp(VMAP_MAGIC,magic,8)) result = false;
if(result && fread(ident,8,1,rf) != 1) result = false;
if(result && fread(&flags,sizeof(unsigned int),1,rf) != 1) result = false;
//POS
if(result && fread(chunk,4,1,rf) != 1) result = false;
if(result && fread(&size,4,1,rf) != 1) result = false;
Vector3 basePos;
if(result && fread(&basePos,sizeof(float),3,rf) != 3) result = false;
setBasePosition(basePos);
//---- Box
if(result && fread(chunk,4,1,rf) != 1) result = false;
if(result && fread(&size,4,1,rf) != 1) result = false;
Vector3 low,high;
if(result && fread(&low,sizeof(float),3,rf) != 3) result = false;
if(result && fread(&high,sizeof(float),3,rf) != 3) result = false;
setBounds(low, high);
//---- TreeNodes
if(result && fread(chunk,4,1,rf) != 1) result = false;
if(result && fread(&size,4,1,rf) != 1) result = false;
if(result && fread(&ival,sizeof(unsigned int),1,rf) != 1) result = false;
if(result) setNNodes(ival);
if(result) setTreeNodeArray(new TreeNode[getNNodes()]);
if(result && fread(getTreeNodes(),sizeof(TreeNode),getNNodes(),rf) != getNNodes()) result = false;
//---- TriangleBoxes
if(result && fread(chunk,4,1,rf) != 1) result = false;
if(result && fread(&size,4,1,rf) != 1) result = false;
if(result && fread(&ival,sizeof(unsigned int),1,rf) != 1) result = false;
setNTriangles(ival);
if(result) setTriangleArray(new TriangleBox[getNTriangles()]);
if(result && fread(getTriangles(),sizeof(TriangleBox),getNTriangles(),rf) != getNTriangles()) result = false;
//---- SubModel
if(result && fread(chunk,4,1,rf) != 1) result = false;
if(result && fread(&size,4,1,rf) != 1) result = false;
if(result && fread(&iNSubModel,sizeof(unsigned int),1,rf) != 1) result = false;
if(result) iSubModel = new SubModel[iNSubModel];
if(result)
{
for(unsigned int i=0;i<iNSubModel && result; ++i)
{
unsigned char readBuffer[52]; // this is the size of SubModel on 32 bit systems
if(fread(readBuffer,sizeof(readBuffer),1,rf) != 1) result = false;
iSubModel[i].initFromBinBlock(readBuffer);
iSubModel[i].setTriangleArray(getTriangles());
iSubModel[i].setTreeNodeArray(getTreeNodes());
}
}
fclose(rf);
}
return result;
}
//=================================================================
size_t ModelContainer::getMemUsage()
{
// BaseModel is included in ModelContainer
return(iNSubModel * sizeof(SubModel) + BaseModel::getMemUsage() + sizeof(ModelContainer) - sizeof(BaseModel));
}
//=================================================================
#ifdef _DEBUG_VMAPS
#ifndef gBoxArray
extern Vector3 p1,p2,p3,p4,p5,p6,p7;
extern Array<AABox>gBoxArray;
extern int gCount1, gCount2, gCount3, gCount4;
extern bool myfound;
#endif
#endif
void ModelContainer::intersect(const G3D::Ray& pRay, float& pMaxDist, bool pStopAtFirstHit, G3D::Vector3& /*pOutLocation*/, G3D::Vector3& /*pOutNormal*/) const
{
IntersectionCallBack<SubModel> intersectCallback;
NodeValueAccess<TreeNode, SubModel> vna = NodeValueAccess<TreeNode, SubModel>(getTreeNodes(), iSubModel);
Ray relativeRay = Ray::fromOriginAndDirection(pRay.origin - getBasePosition(), pRay.direction);
iTreeNodes[0].intersectRay(pRay, intersectCallback, pMaxDist, vna, pStopAtFirstHit, false);
}
//==========================================================
bool ModelContainer::intersect(const G3D::Ray& pRay, float& pMaxDist) const
{
return BaseModel::intersect(getAABoxBounds(), pRay, pMaxDist);
}
//=================================================================
template<typename RayCallback>
void ModelContainer::intersectRay(const G3D::Ray& pRay, RayCallback& intersectCallback, float& pMaxDist, bool pStopAtFirstHit, bool intersectCallbackIsFast)
{
if(intersect(pRay, pMaxDist))
{
NodeValueAccess<TreeNode, SubModel> vna = NodeValueAccess<TreeNode, SubModel>(getTreeNodes(), iSubModel);
iTreeNodes[0].intersectRay(pRay, intersectCallback, distance, vna, pStopAtFirstHit, true);
}
}
//=================================================================
void getBounds(const ModelContainer& pMc, G3D::AABox& pAABox)
{
pAABox = pMc.getAABoxBounds();
}
//=================================================================
void getBounds(const ModelContainer* pMc, G3D::AABox& pAABox)
{
pAABox = pMc->getAABoxBounds();
}
//=================================================================
} // VMAP

View file

@ -0,0 +1,108 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef _MODELCONTAINER_H
#define _MODELCONTAINER_H
// load our modified version first !!
#include "AABSPTree.h"
#include <G3D/AABox.h>
#include <G3D/Vector3.h>
#include <G3D/Ray.h>
#include "ShortBox.h"
#include "TreeNode.h"
#include "VMapTools.h"
#include "SubModel.h"
#include "BaseModel.h"
namespace VMAP
{
/**
The ModelContainer is a balanced BSP-Tree of SubModels.
We store a map tile or an instance in one ModelContainer.
The ModelContainer manages the memory used for the tree nodes, the SubModels and its triangles in static arrays.
The tree nodes are used for the BSP-Tree of SubModels as well as for the BSP-Tree of triangles within one SubModel.
The references are done by indexes within these static arrays.
Therefore we are able to just load a binary block and do not need to mess around with memory allocation and pointers.
*/
//=====================================================
class ModelContainer : public BaseModel
{
private:
unsigned int iNSubModel;
SubModel *iSubModel;
G3D::AABox iBox;
ModelContainer (const ModelContainer& c): BaseModel(c) {}
ModelContainer& operator=(const ModelContainer& ) {}
public:
ModelContainer() : BaseModel() { iNSubModel =0; iSubModel = 0; };
// for the mainnode
ModelContainer(unsigned int pNTriangles, unsigned int pNNodes, unsigned int pNSubModel);
ModelContainer(G3D::AABSPTree<SubModel *> *pTree);
~ModelContainer(void);
inline const void setSubModel(const SubModel& pSubModel, int pPos) { iSubModel[pPos] = pSubModel; }
inline const SubModel& getSubModel(int pPos) const { return iSubModel[pPos]; }
inline unsigned int getNSubModel() const { return(iNSubModel); }
void countSubModelsAndNodesAndTriangles(G3D::AABSPTree<SubModel *>::Node& pNode, int& nSubModels, int& nNodes, int& nTriangles);
void fillContainer(const G3D::AABSPTree<SubModel *>::Node& pNode, int &pSubModelPos, int &pTreeNodePos, int &pTrianglePos, G3D::Vector3& pLo, G3D::Vector3& pHi, G3D::Vector3& pFinalLo, G3D::Vector3& pFinalHi);
bool readRawFile(const char *name);
inline const G3D::AABox& getAABoxBounds() const { return(iBox); }
inline void setBounds(const G3D::Vector3& lo, const G3D::Vector3& hi) { iBox.set(lo,hi); }
bool writeFile(const char *filename);
bool readFile(const char *filename);
size_t getMemUsage();
size_t hashCode() { return (getBasePosition() * getNTriangles()).hashCode(); }
void intersect(const G3D::Ray& pRay, float& pMaxDist, bool pStopAtFirstHit, G3D::Vector3& pOutLocation, G3D::Vector3& pOutNormal) const;
bool intersect(const G3D::Ray& pRay, float& pMaxDist) const;
template<typename RayCallback>
void intersectRay(const G3D::Ray& ray, RayCallback& intersectCallback, float& distance, bool pStopAtFirstHit, bool intersectCallbackIsFast = false);
bool operator==(const ModelContainer& pMc2) const;
};
//=====================================================
//=====================================================
size_t hashCode(const ModelContainer& pMc);
void getBounds(const ModelContainer& pMc, G3D::AABox& pAABox);
void getBounds(const ModelContainer* pMc, G3D::AABox& pAABox);
}
#endif

View file

@ -0,0 +1,48 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef _NODEVALUEACCESS_H
#define _NODEVALUEACCESS_H
namespace VMAP
{
/**
This is a helper Class to get access to SubModels or triangles when analyzing the BSP-Tree.
*/
template<class TNode, class TValue> class NodeValueAccess
{
private:
TNode const* iNodeArray;
TValue const* iValueArray;
public:
inline NodeValueAccess() : iNodeArray(NULL), iValueArray(NULL) {}
inline NodeValueAccess(TNode const* pNodeArray, TValue const* pValueArray) : iNodeArray(pNodeArray), iValueArray(pValueArray) {}
inline TNode const* getNodePtr() const { return(iNodeArray); }
inline TValue const* getValuePtr() const { return(iValueArray); }
inline TNode const& getNode(unsigned int pPos) const { return(iNodeArray[pPos]); }
inline void setNode(const TNode& pNode, unsigned int pPos) { iNodeArray[pPos] = pNode; }
inline TValue const& getValue(unsigned int pPos) const { return(iValueArray[pPos]); }
inline void setValue(const TValue& pValue, unsigned int pPos) { iValueArray[pPos] = pValue; }
};
}
#endif

148
src/shared/vmap/ShortBox.h Normal file
View file

@ -0,0 +1,148 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef _SHORTBOX_H
#define _SHORTBOX_H
#include <G3D/Vector3.h>
#include <G3D/AABox.h>
#include <G3D/Triangle.h>
#include <G3D/Ray.h>
#include "ShortVector.h"
/**
This is a box and a triangle Class using ShortVectors. Each vector has 16 bit an a fixed point 12.4 representation.
*/
namespace VMAP
{
class ShortBox
{
private:
ShortVector iV1;
ShortVector iV2;
public:
ShortBox() {}
inline const ShortVector& getLo() const { return(iV1); }
inline const ShortVector& getHi() const { return(iV2); }
inline void setLo(const ShortVector& pV){ iV1 = pV; }
inline void setHi(const ShortVector& pV){ iV2 = pV; }
inline void setLo(const G3D::Vector3& pV){ iV1 = ShortVector(pV); }
inline void setHi(const G3D::Vector3& pV){ iV2 = ShortVector(pV); }
inline bool operator==(const ShortBox& b) const
{
return ((iV1 == b.iV1) && (iV2 == b.iV2));
}
inline bool operator!=(const ShortBox& b) const
{
return !((iV1 == b.iV1) && (iV2 == b.iV2));
}
};
//=====================================================================
#ifdef _DEBUG_VMAPS
#ifndef gBoxArray
extern G3D::Vector3 p1,p2,p3,p4,p5,p6,p7;
extern G3D::Array<G3D::AABox>gBoxArray;
extern G3D::Array<G3D::Triangle>gTriArray;
extern int gCount1, gCount2, gCount3, gCount4;
extern bool myfound;
#endif
#endif
static const G3D::Vector3 dummyZeroPosition = G3D::Vector3(0,0,0);
class TriangleBox
{
private:
ShortVector _vertex[3];
//ShortBox iBox;
public:
inline TriangleBox() { }
inline TriangleBox(const ShortVector& pV1, const ShortVector& pV2, const ShortVector& pV3)
{
_vertex[0] = pV1;
_vertex[1] = pV2;
_vertex[2] = pV3;
}
inline const ShortVector& vertex (int n) const
{
return(_vertex[n]);
}
inline const ShortBox getBounds()const
{
ShortBox box;
ShortVector lo = _vertex[0];
ShortVector hi = lo;
for (int i = 1; i < 3; ++i)
{
lo = lo.min(_vertex[i]);
hi = hi.max(_vertex[i]);
}
box.setLo(lo);
box.setHi(hi);
return(box);
}
inline const G3D::Vector3& getBasePosition() { return(dummyZeroPosition); }
inline const G3D::AABox getAABoxBounds() const { ShortBox box = getBounds(); return(G3D::AABox(box.getLo().getVector3(), box.getHi().getVector3())); }
inline bool operator==(const TriangleBox& t) const
{
return ((_vertex[0] == t._vertex[0]) && (_vertex[1] == t._vertex[1]) &&(_vertex[2] == t._vertex[2]));
}
inline bool operator!=(const TriangleBox& t) const
{
return !((_vertex[0] == t._vertex[0]) && (_vertex[1] == t._vertex[1]) &&(_vertex[2] == t._vertex[2]));
}
inline void intersect(const G3D::Ray& pRay, float& pMaxDist, bool /*pStopAtFirstHitDummy*/, G3D::Vector3& /*pOutLocationDummy*/, G3D::Vector3& /*pOutNormalDummy*/) const
{
static const double epsilon = 0.00001;
G3D::Triangle testT(vertex(0).getVector3(),vertex(1).getVector3(),vertex(2).getVector3());
float t = pRay.intersectionTime(testT);
if ((t < pMaxDist) || t < (pMaxDist + epsilon))
pMaxDist = t;
else
{
testT = G3D::Triangle(vertex(2).getVector3(),vertex(1).getVector3(),vertex(0).getVector3());
#ifdef _DEBUG_VMAPS
{
G3D::Triangle myt(testT.vertex(0)+p6, testT.vertex(1)+p6,testT.vertex(2)+p6);
gTriArray.push_back(myt);
}
#endif
t = pRay.intersectionTime(testT);
if ((t < pMaxDist) || t < (pMaxDist + epsilon))
pMaxDist = t;
}
}
};
}
#endif

View file

@ -0,0 +1,134 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef _SHORTVECTOR_H
#define _SHORTVECTOR_H
#include <G3D/Vector3.h>
namespace VMAP
{
/**
Vector with 16 bit fix point values 12.4 bit.
*/
class ShortVector
{
private:
short iX;
short iY;
short iZ;
const static short maxvalue = 0x7fff;
const static short minvalue = -0x7fff;
const static int fixpointdiv = 16;
const static short fixpoint_maxvalue = maxvalue / fixpointdiv;
const static short fixpoint_minvalue = minvalue / fixpointdiv;
inline short float2Short(float fv) const
{
short sv;
debugAssert((fv <= fixpoint_maxvalue || fv >= 1000000) && (fv >= fixpoint_minvalue || fv <= -1000000));
if(fv >= fixpoint_maxvalue)
sv=maxvalue;
else if(fv <= fixpoint_minvalue)
sv=minvalue;
else
sv = (short) (fv * fixpointdiv + 0.5);
return(sv);
}
inline float short2Float(short sv) const
{
float fv;
if(sv >= maxvalue)
fv=G3D::inf();
else if(sv <= minvalue)
fv=-G3D::inf();
else
fv = ((float)sv) / fixpointdiv;
return fv;
}
inline float getFX() const { return(short2Float(iX)); }
inline float getFY() const { return(short2Float(iY)); }
inline float getFZ() const { return(short2Float(iZ)); }
public:
inline ShortVector() {}
inline ShortVector(const G3D::Vector3& pVector)
{
iX = float2Short(pVector.x);
iY = float2Short(pVector.y);
iZ = float2Short(pVector.z);
}
inline ShortVector(float pX, float pY, float pZ)
{
iX = float2Short(pX);
iY = float2Short(pY);
iZ = float2Short(pZ);
}
inline ShortVector(short pX, short pY, short pZ)
{
iX = pX;
iY = pY;
iZ = pZ;
}
inline ShortVector(const ShortVector& pShortVector)
{
iX = pShortVector.iX;
iY = pShortVector.iY;
iZ = pShortVector.iZ;
}
inline float getX() const { return(iX); }
inline float getY() const { return(iY); }
inline float getZ() const { return(iZ); }
inline G3D::Vector3 getVector3() const { return(G3D::Vector3(getFX(), getFY(), getFZ())); }
inline ShortVector min(const ShortVector pShortVector)
{
ShortVector result = pShortVector;
if(pShortVector.iX > iX) { result.iX = iX; }
if(pShortVector.iY > iY) { result.iY = iY; }
if(pShortVector.iZ > iZ) { result.iZ = iZ; }
return(result);
}
inline ShortVector max(const ShortVector pShortVector)
{
ShortVector result = pShortVector;
if(pShortVector.iX < iX) { result.iX = iX; }
if(pShortVector.iY < iY) { result.iY = iY; }
if(pShortVector.iZ < iZ) { result.iZ = iZ; }
return(result);
}
inline bool operator==(const ShortVector& v) const
{
return (iX == v.iX && iY == v.iY && iZ == v.iZ);
}
inline bool operator!=(const ShortVector& v) const
{
return !(iX == v.iX && iY == v.iY && iZ == v.iZ);
}
};
}
#endif

View file

@ -0,0 +1,248 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#include "SubModel.h"
#ifdef _ASSEMBLER_DEBUG
extern FILE *::g_df;
#endif
using namespace G3D;
namespace VMAP
{
//==========================================================
/**
Functions to use ModelContainer with a AABSPTree
*/
unsigned int hashCode(const SubModel& pSm)
{
return pSm.getNTriangles();
}
void getBounds(const SubModel& pSm, G3D::AABox& pAABox)
{
ShortBox box = pSm.getReletiveBounds();
pAABox.set(box.getLo().getVector3()+pSm.getBasePosition(), box.getHi().getVector3()+pSm.getBasePosition());
}
void getBounds(const SubModel* pSm, G3D::AABox& pAABox)
{
ShortBox box = pSm->getReletiveBounds();
pAABox.set(box.getLo().getVector3()+pSm->getBasePosition(), box.getHi().getVector3()+pSm->getBasePosition());
}
//==========================================================
//==========================================================
//==========================================================
//==========================================================
SubModel::SubModel(unsigned int pNTriangles, TriangleBox *pTriangles, unsigned int pTrianglesPos, unsigned int pNNodes, TreeNode *pTreeNodes, unsigned int pNodesPos) :
BaseModel(pNNodes, pTreeNodes, pNTriangles, pTriangles)
{
iTrianglesPos = pTrianglesPos;
iNodesPos = pNodesPos;
iHasInternalMemAlloc = false;
}
//==========================================================
SubModel::~SubModel(void)
{
if(iHasInternalMemAlloc)
{
free();
}
}
//==========================================================
bool SubModel::operator==(const SubModel& pSm2) const
{
bool result = false;
if(getNNodes() == pSm2.getNNodes() &&
getNTriangles() == pSm2.getNTriangles() &&
getBasePosition() == pSm2.getBasePosition() &&
getNodesPos() == pSm2.getNodesPos() &&
getTrianglesPos() == pSm2.getTrianglesPos())
{
result = true;
}
return result;
}
//==========================================================
enum BIN_POSITIONS
{
BP_iNTriangles=8,
BP_iNNodes=12,
BP_iBasePosition=16,
BP_iNodesPos=28,
BP_iTrianglesPos=32,
BP_iHasInternalMemAlloc=36,
BP_iBox=38,
};
/**
This is ugly, but due to compatibility and 64 bit support we have to do that ... sorry
*/
void SubModel::initFromBinBlock(void *pBinBlock)
{
iNTriangles = *((unsigned int *)(((char *) pBinBlock) + BP_iNTriangles));
iNNodes = *((unsigned int *) (((char *) pBinBlock) + BP_iNNodes));
iBasePosition = *((Vector3 *) (((char *) pBinBlock) + BP_iBasePosition));
iNodesPos = *((unsigned int *) (((char *) pBinBlock) + BP_iNodesPos));
iTrianglesPos = *((unsigned int *) (((char *) pBinBlock) + BP_iTrianglesPos));
iHasInternalMemAlloc = *((bool *) (((char *) pBinBlock) + BP_iHasInternalMemAlloc));
iBox = *((ShortBox *) (((char *) pBinBlock) + BP_iBox));
}
//==========================================================
void SubModel::countNodesAndTriangles(AABSPTree<Triangle>::Node& pNode, int &pNNodes, int &pNTriabgles)
{
++pNNodes;
pNTriabgles += pNode.valueArray.size();
#ifdef _ASSEMBLER_DEBUG
fprintf(::g_df, "Nodes: %d, Tris: %d\n",pNNodes, pNTriabgles);
#endif
if(pNode.child[0] != 0)
{
countNodesAndTriangles(*pNode.child[0], pNNodes, pNTriabgles);
}
if(pNode.child[1] != 0)
{
countNodesAndTriangles(*pNode.child[1], pNNodes, pNTriabgles);
}
}
//==========================================================
void SubModel::fillContainer(const AABSPTree<Triangle>::Node& pNode, int &pTreeNodePos, int &pTrianglePos, Vector3& pLo, Vector3& pHi)
{
TreeNode treeNode = TreeNode(pNode.valueArray.size(), pTrianglePos);
treeNode.setSplitAxis(pNode.splitAxis);
treeNode.setSplitLocation(pNode.splitLocation);
int currentTreeNodePos = pTreeNodePos++;
Vector3 lo = Vector3(inf(),inf(),inf());
Vector3 hi = Vector3(-inf(),-inf(),-inf());
for(int i=0;i<pNode.valueArray.size(); i++)
{
G3D::_AABSPTree::Handle<Triangle>* h= pNode.valueArray[i];
Triangle t = h->value;
TriangleBox triangleBox = TriangleBox(t.vertex(0),t.vertex(1), t.vertex(2));
lo = lo.min(triangleBox.getBounds().getLo().getVector3());
hi = hi.max(triangleBox.getBounds().getHi().getVector3());
getTriangles()[pTrianglePos++] = triangleBox;
}
if(pNode.child[0] != 0)
{
treeNode.setChildPos(0, pTreeNodePos);
fillContainer(*pNode.child[0], pTreeNodePos, pTrianglePos, lo, hi);
}
if(pNode.child[1] != 0)
{
treeNode.setChildPos(1, pTreeNodePos);
fillContainer(*pNode.child[1], pTreeNodePos, pTrianglePos, lo, hi);
}
treeNode.setBounds(lo,hi);
// get absolute bounds
pLo = pLo.min(lo);
pHi = pHi.max(hi);
getTreeNodes()[currentTreeNodePos] = treeNode;
}
//==========================================================
SubModel::SubModel(AABSPTree<Triangle> *pTree)
{
int nNodes, nTriangles;
nNodes = nTriangles = 0;
countNodesAndTriangles(*pTree->root, nNodes, nTriangles);
init(nNodes, nTriangles);
iTrianglesPos = 0; // this is the global array
iNodesPos = 0; // this is the global array
iHasInternalMemAlloc = true;
int treeNodePos, trianglePos;
treeNodePos = trianglePos = 0;
Vector3 lo = Vector3(inf(),inf(),inf());
Vector3 hi = Vector3(-inf(),-inf(),-inf());
fillContainer(*pTree->root, treeNodePos, trianglePos, lo, hi);
setReletiveBounds(lo, hi);
}
//==========================================================
#ifdef _DEBUG_VMAPS
#ifndef gBoxArray
extern Vector3 p1,p2,p3,p4,p5,p6,p7;
extern Array<AABox>gBoxArray;
extern Array<G3D::Triangle>gTriArray;
extern int gCount1, gCount2, gCount3, gCount4;
extern bool myfound;
#endif
#endif
//==========================================================
void SubModel::intersect(const G3D::Ray& pRay, float& pMaxDist, bool pStopAtFirstHit, G3D::Vector3& /*pOutLocation*/, G3D::Vector3& /*pOutNormal*/) const
{
NodeValueAccess<TreeNode, TriangleBox> vna = NodeValueAccess<TreeNode, TriangleBox>(getTreeNodes(), getTriangles());
IntersectionCallBack<TriangleBox> intersectCallback;
Ray relativeRay = Ray::fromOriginAndDirection(pRay.origin - getBasePosition(), pRay.direction);
#ifdef _DEBUG_VMAPS
//p6=getBasePosition();
//gBoxArray.push_back(getAABoxBounds());
#endif
getTreeNode(0).intersectRay(relativeRay, intersectCallback, pMaxDist, vna, pStopAtFirstHit, false);
}
//==========================================================
bool SubModel::intersect(const G3D::Ray& pRay, float& pMaxDist) const
{
return BaseModel::intersect(getAABoxBounds(), pRay, pMaxDist);
}
//==========================================================
template<typename RayCallback>
void SubModel::intersectRay(const Ray& pRay, RayCallback& pIntersectCallback, float& pMaxDist, bool pStopAtFirstHit, bool intersectCallbackIsFast)
{
if(intersect(pRay, pMaxDist))
{
NodeValueAccess<TreeNode, TriangleBox> vna = NodeValueAccess<TreeNode, TriangleBox>(getTreeNodes(), getTriangles());
IntersectionCallBack<TriangleBox> intersectCallback;
getTreeNode(0).intersectRay(pRay, intersectCallback, pMaxDist, vna, pStopAtFirstHit, false);
}
}
//==========================================================
}

102
src/shared/vmap/SubModel.h Normal file
View file

@ -0,0 +1,102 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#ifndef _SUBMODEL_H
#define _SUBMODEL_H
// load our modified version first !!
#include "AABSPTree.h"
#include "ShortVector.h"
#include "ShortBox.h"
#include "TreeNode.h"
#include "VMapTools.h"
#include "BaseModel.h"
namespace VMAP
{
/**
This is a balanced static BSP-Tree of triangles.
The memory for the tree nodes and the triangles are managed by the ModelContainer.
The exception to this is during the conversion of raw data info balanced BSP-Trees.
During this conversion the memory management is done internally.
*/
class SubModel : public BaseModel
{
private:
unsigned int iNodesPos;
unsigned int iTrianglesPos;
bool iHasInternalMemAlloc;
ShortBox iBox;
#ifdef _DEBUG_VIEW
G3D::Array<TriangleBox *> iDrawBox;
#endif
public:
SubModel() : BaseModel(){ };
SubModel(unsigned int pNTriangles, TriangleBox *pTriangles, unsigned int pTrianglesPos, unsigned int pNNodes, TreeNode *pTreeNodes, unsigned int pNodesPos);
SubModel(G3D::AABSPTree<G3D::Triangle> *pTree);
~SubModel(void);
//Gets a 50 byte binary block
void initFromBinBlock(void *pBinBlock);
void fillRenderArray(G3D::Array<TriangleBox> &pArray, const TreeNode* pTreeNode);
void countNodesAndTriangles(G3D::AABSPTree<G3D::Triangle>::Node& pNode, int &pNNodes, int &pNTriabgles);
void fillContainer(const G3D::AABSPTree<G3D::Triangle>::Node& pNode, int &pTreeNodePos, int &pTrianglePos, G3D::Vector3& pLo, G3D::Vector3& pHi);
inline const ShortBox& getReletiveBounds() const { return(iBox); }
inline void setReletiveBounds(const ShortVector& lo, const ShortVector& hi) { iBox.setLo(lo); iBox.setHi(hi); }
inline const G3D::AABox getAABoxBounds() const { return(G3D::AABox(iBox.getLo().getVector3() + getBasePosition(), iBox.getHi().getVector3()+ getBasePosition())); }
// get start pos bases on the global array
inline TriangleBox const* getTriangles() const { return &BaseModel::getTriangle(iTrianglesPos); }
inline TriangleBox * getTriangles() { return &BaseModel::getTriangle(iTrianglesPos); }
// get start pos bases on the global array
inline TreeNode const* getTreeNodes() const { return &BaseModel::getTreeNode(iNodesPos); }
inline TreeNode * getTreeNodes() { return &BaseModel::getTreeNode(iNodesPos); }
// internal method usign internal offset
inline const TreeNode& getTreeNode(int pPos) const { return(SubModel::getTreeNodes()[pPos]); }
// internal method usign internal offset
inline const TriangleBox& getTriangle(int pPos) const { return(SubModel::getTriangles()[pPos]); }
inline unsigned int getNodesPos() const { return(iNodesPos); }
inline unsigned int getTrianglesPos() const { return(iTrianglesPos); }
//unsigned int hashCode() { return (getBasePosition() * getNTriangles()).hashCode(); }
void intersect(const G3D::Ray& pRay, float& pMaxDist, bool pStopAtFirstHit, G3D::Vector3& pOutLocation, G3D::Vector3& pOutNormal) const;
bool intersect(const G3D::Ray& pRay, float& pMaxDist) const;
template<typename RayCallback>
void intersectRay(const G3D::Ray& ray, RayCallback& intersectCallback, float& distance, bool pStopAtFirstHit, bool intersectCallbackIsFast = false);
bool operator==(const SubModel& pSm2) const;
unsigned int hashCode() const { return BaseModel::getNTriangles(); }
};
unsigned int hashCode(const SubModel& pSm);
void getBounds(const SubModel& pSm, G3D::AABox& pAABox);
void getBounds(const SubModel* pSm, G3D::AABox& pAABox);
//====================================
} // VMAP
#endif

View file

@ -0,0 +1,571 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
*
* 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
*/
#include <G3D/Vector3.h>
#include <G3D/Triangle.h>
#include "TileAssembler.h"
#include "CoordModelMapping.h"
#include "ModelContainer.h"
#include <limits.h>
#include <string.h>
#ifdef _ASSEMBLER_DEBUG
FILE *g_df = NULL;
#endif
using namespace G3D;
namespace VMAP
{
//=================================================================
Vector3 ModelPosition::transform(const Vector3& pIn) const
{
//return(pIn);
Vector3 out = pIn * iScale;
out = izMatrix * out;
out = ixMatrix * out;
out = iyMatrix * out;
return(out);
}
//=================================================================
TileAssembler::TileAssembler(const std::string& pSrcDirName, const std::string& pDestDirName)
{
iCurrentUniqueNameId = 0;
iFilterMethod = NULL;
iSrcDir = pSrcDirName;
iDestDir = pDestDirName;
//mkdir(iDestDir);
init();
}
//=================================================================
TileAssembler::~TileAssembler()
{
delete iCoordModelMapping;
}
//=================================================================
void TileAssembler::init()
{
iCoordModelMapping = new CoordModelMapping();
addWorldAreaMapId(0); //Azeroth
addWorldAreaMapId(1); //Kalimdor
addWorldAreaMapId(530); //Expansion01
}
//=================================================================
std::string getModNameFromModPosName(const std::string& pModPosName)
{
size_t spos = pModPosName.find_first_of('#');
std::string modelFileName = pModPosName.substr(0,spos);
return(modelFileName);
}
//=================================================================
unsigned int TileAssembler::getUniqueNameId(const std::string pName)
{
unsigned int result;
if(!iUniqueNameIds.containsKey(pName))
{
++iCurrentUniqueNameId;
iUniqueNameIds.set(pName, iCurrentUniqueNameId);
}
result = iUniqueNameIds.get(pName);
return result;
}
//=================================================================
std::string TileAssembler::getDirEntryNameFromModName(unsigned int pMapId, const std::string& pModPosName)
{
size_t spos;
char buffer[20];
std::string modelFileName = getModNameFromModPosName(pModPosName);
//std::string fext = pModPosName.substr(modelFileName.length(),pModPosName.length());
unsigned int fextId = getUniqueNameId(pModPosName);
sprintf(buffer, "_%07d",fextId);
std::string fext(buffer);
spos = modelFileName.find_last_of('/');
std::string fname = modelFileName.substr(spos+1, modelFileName.length());
spos = fname.find_last_of('.');
fname = fname.substr(0,spos);
sprintf(buffer, "%03u", pMapId);
std::string dirEntry(buffer);
dirEntry.append("_");
dirEntry.append(fname);
dirEntry.append(fext);
dirEntry.append(".vmap");
return(dirEntry);
}
//=================================================================
void emptyArray(Array<ModelContainer*>& mc)
{
int no=mc.size();
while(no > 0)
{
--no;
delete mc[no];
mc.remove(no);
}
}
//=================================================================
bool TileAssembler::convertWorld()
{
#ifdef _ASSEMBLER_DEBUG
# ifdef _DEBUG
::g_df = fopen("../TileAssembler_debug.txt", "wb");
# else
::g_df = fopen("../TileAssembler_release.txt", "wb");
# endif
#endif
bool result = true;
std::string fname = iSrcDir;
fname.append("/");
fname.append("dir");
iCoordModelMapping->setModelNameFilterMethod(iFilterMethod);
iCoordModelMapping->readCoordinateMapping(fname);
Array<unsigned int> mapIds = iCoordModelMapping->getMaps();
if(mapIds.size() == 0)
{
result = false;
}
for(int i=0; i<mapIds.size() && result; ++i)
{
unsigned int mapId = mapIds[i];
#ifdef _ASSEMBLER_DEBUG
if(mapId == 0) // "Azeroth" just for debug
{
for(int x=28; x<29 && result; ++x) //debug
{
for(int y=28; y<29 && result; ++y)
{
#else
// ignore DeeprunTram (369) it is too large for short vector and not important
// ignore test (13), Test (29) , development (451)
if(mapId != 369 && mapId != 13 && mapId != 29 && mapId != 451)
{
for(int x=0; x<66 && result; ++x)
{
for(int y=0; y<66 && result; ++y)
{
#endif
Array<ModelContainer*> mc;
std::string dirname;
char buffer[100];
if(iCoordModelMapping->isWorldAreaMap(mapId) && x<65 && y<65)
{
sprintf(buffer, "%03u_%d_%d",mapId,y,x); // Let's flip x and y here
dirname = std::string(buffer);
}
else
{
sprintf(buffer, "%03u",mapId);
dirname = std::string(buffer);
}
result = fillModelContainerArray(dirname, mapId, x, y, mc);
emptyArray(mc);
}
}
}
}
#ifdef _ASSEMBLER_DEBUG
if(::g_df) fclose(::g_df);
#endif
return result;
}
//=================================================================
bool TileAssembler::fillModelContainerArray(const std::string& pDirFileName, unsigned int pMapId, int pXPos, int pYPos, Array<ModelContainer*>& pMC)
{
bool result = true;
ModelContainer* modelContainer;
NameCollection nameCollection = iCoordModelMapping->getFilenamesForCoordinate(pMapId, pXPos, pYPos);
if(nameCollection.size() > 0)
{
result = false;
char dirfilename[500];
sprintf(dirfilename,"%s/%s.vmdir",iDestDir.c_str(),pDirFileName.c_str());
FILE *dirfile = fopen(dirfilename, "ab");
if(dirfile)
{
result = true;
char destnamebuffer[500];
char fullnamedestnamebuffer[500];
if(nameCollection.iMainFiles.size() >0)
{
sprintf(destnamebuffer,"%03u_%i_%i.vmap",pMapId, pYPos, pXPos); // flip it here too
std::string checkDoubleStr = std::string(dirfilename);
checkDoubleStr.append("##");
checkDoubleStr.append(std::string(destnamebuffer));
// Check, if same file already is in the same dir file
if(!iCoordModelMapping->isAlreadyProcessedSingleFile(checkDoubleStr))
{
iCoordModelMapping->addAlreadyProcessedSingleFile(checkDoubleStr);
fprintf(dirfile, "%s\n",destnamebuffer);
sprintf(fullnamedestnamebuffer,"%s/%s",iDestDir.c_str(),destnamebuffer);
modelContainer = processNames(nameCollection.iMainFiles, fullnamedestnamebuffer);
if(modelContainer)
{
pMC.append(modelContainer);
}
else
{
result = false;
}
}
}
// process the large singe files
int pos = 0;
while(result && (pos < nameCollection.iSingeFiles.size()))
{
std::string destFileName = iDestDir;
destFileName.append("/");
std::string dirEntryName = getDirEntryNameFromModName(pMapId,nameCollection.iSingeFiles[pos]);
std::string checkDoubleStr = std::string(dirfilename);
checkDoubleStr.append("##");
checkDoubleStr.append(nameCollection.iSingeFiles[pos]);
// Check, if same file already is in the same dir file
if(!iCoordModelMapping->isAlreadyProcessedSingleFile(checkDoubleStr))
{
iCoordModelMapping->addAlreadyProcessedSingleFile(checkDoubleStr);
fprintf(dirfile, "%s\n",dirEntryName.c_str());
destFileName.append(dirEntryName);
Array<std::string> positionarray;
positionarray.append(nameCollection.iSingeFiles[pos]);
if(!iCoordModelMapping->isAlreadyProcessedSingleFile(nameCollection.iSingeFiles[pos]))
{
modelContainer = processNames(positionarray, destFileName.c_str());
iCoordModelMapping->addAlreadyProcessedSingleFile(nameCollection.iSingeFiles[pos]);
if(modelContainer)
{
pMC.append(modelContainer);
}
else
{
result = false;
}
}
}
++pos;
}
fclose(dirfile);
}
}
return(result);
}
//=================================================================
void removeEntriesFromTree(AABSPTree<SubModel *>* pTree)
{
Array<SubModel *> submodelArray;
pTree->getMembers(submodelArray);
int no = submodelArray.size();
while(no > 0)
{
--no;
delete submodelArray[no];
}
}
//=================================================================
ModelContainer* TileAssembler::processNames(const Array<std::string>& pPositions, const char* pDestFileName)
{
ModelContainer *modelContainer = 0;
Vector3 basepos = Vector3(0,0,0);
AABSPTree<SubModel *>* mainTree = new AABSPTree<SubModel *>();
int pos = 0;
bool result = true;
while(result && (pos < pPositions.size()))
{
std::string modelPosString = pPositions[pos];
std::string modelFileName = getModNameFromModPosName(modelPosString);
if(!fillModelIntoTree(mainTree, basepos, modelPosString, modelFileName))
{
result = false;
break;
}
++pos;
}
if(result && mainTree->size() > 0)
{
mainTree->balance();
modelContainer = new ModelContainer(mainTree);
modelContainer->writeFile(pDestFileName);
}
removeEntriesFromTree(mainTree);
delete mainTree;
return(modelContainer);
}
//=================================================================
bool TileAssembler::readRawFile(std::string& pModelFilename, ModelPosition& pModelPosition, AABSPTree<SubModel *> *pMainTree)
{
bool result = false;
std::string filename = iSrcDir;
if(filename.length() >0)
filename.append("/");
filename.append(pModelFilename);
FILE *rf = fopen(filename.c_str(), "rb");
if(!rf)
{
// depending on the extractor version, the data could be located in the root dir
std::string baseModelFilename = pModelFilename.substr((pModelFilename.find_first_of("/")+1),pModelFilename.length());
filename = iSrcDir;
if(filename.length() >0)
filename.append("/");
filename.append(baseModelFilename);
rf = fopen(filename.c_str(), "rb");
}
char ident[8];
int trianglecount =0;
#ifdef _ASSEMBLER_DEBUG
int startgroup = 0; //2;
int endgroup = INT_MAX; //2;
fprintf(::g_df,"-------------------------------------------------\n");
fprintf(::g_df,"%s\n", pModelFilename.c_str());
fprintf(::g_df,"-------------------------------------------------\n");
#else
int startgroup = 0;
int endgroup = INT_MAX;
#endif
if(rf)
{
if(fread(&ident, 8, 1, rf) != 1) { fclose(rf); return(false); }
if(strcmp(ident, "VMAP001") == 0)
{
// OK, do nothing
}
else if(strcmp(ident, "VMAP002") == 0)
{
// we have to read one int. This is needed during the export and we have to skip it here
int tempNVectors;
if(fread(&tempNVectors, sizeof(int), 1, rf) != 1) { fclose(rf); return(false); }
}
else
{
// wrong version
fclose(rf);
return(false);
}
G3D::uint32 groups;
char blockId[5];
blockId[4] = 0;
int blocksize;
if(fread(&groups, sizeof(G3D::uint32), 1, rf) != 1) { fclose(rf); return(false); }
for(int g=0;g<(int)groups;g++)
{
// group MUST NOT have more then 65536 indexes !! Array will have a problem with that !! (strange ...)
Array<int> tempIndexArray;
Array<Vector3> tempVertexArray;
AABSPTree<Triangle> *gtree = new AABSPTree<Triangle>();
G3D::uint32 flags;
if(fread(&flags, sizeof(G3D::uint32), 1, rf) != 1) { fclose(rf); return(false); }
G3D::uint32 branches;
if(fread(&blockId, 4, 1, rf) != 1) { fclose(rf); return(false); }
if(strcmp(blockId, "GRP ") != 0) { fclose(rf); return(false); }
if(fread(&blocksize, sizeof(int), 1, rf) != 1) { fclose(rf); return(false); }
if(fread(&branches, sizeof(G3D::uint32), 1, rf) != 1) { fclose(rf); return(false); }
for(int b=0;b<(int)branches; b++)
{
G3D::uint32 indexes;
// indexes for each branch (not used jet)
if(fread(&indexes, sizeof(G3D::uint32), 1, rf) != 1) { fclose(rf); return(false); }
}
// ---- indexes
if(fread(&blockId, 4, 1, rf) != 1) { fclose(rf); return(false); }
if(strcmp(blockId, "INDX") != 0) { fclose(rf); return(false); }
if(fread(&blocksize, sizeof(int), 1, rf) != 1) { fclose(rf); return(false); }
unsigned int nindexes;
if(fread(&nindexes, sizeof(G3D::uint32), 1, rf) != 1) { fclose(rf); return(false); }
if(nindexes >0)
{
unsigned short *indexarray = new unsigned short[nindexes*sizeof(unsigned short)];
if(fread(indexarray, sizeof(unsigned short), nindexes, rf) != nindexes) { fclose(rf); return(false); }
for(int i=0;i<(int)nindexes; i++)
{
unsigned short val = indexarray[i];
tempIndexArray.append(val);
}
delete indexarray;
}
// ---- vectors
if(fread(&blockId, 4, 1, rf) != 1) {fclose(rf); return(false); }
if(strcmp(blockId, "VERT") != 0) { fclose(rf); return(false); }
if(fread(&blocksize, sizeof(int), 1, rf) != 1) { fclose(rf); return(false); }
unsigned int nvectors;
if(fread(&nvectors, sizeof(int), 1, rf) != 1) { fclose(rf); return(false); }
float *vectorarray = 0;
if(nvectors >0)
{
vectorarray = new float[nvectors*sizeof(float)*3];
if(fread(vectorarray, sizeof(float)*3, nvectors, rf) != nvectors) { fclose(rf); return(false); }
}
// ----- liquit
if(flags & 1)
{
// we have liquit -> not handled yet ... skip
if(fread(&blockId, 4, 1, rf) != 1) { fclose(rf); return(false); }
if(strcmp(blockId, "LIQU") != 0) { fclose(rf); return(false); }
if(fread(&blocksize, sizeof(int), 1, rf) != 1) { fclose(rf); return(false); }
fseek(rf, blocksize, SEEK_CUR);
}
for(unsigned int i=0, indexNo=0; indexNo<nvectors; indexNo++)
{
Vector3 v = Vector3(vectorarray[i+2], vectorarray[i+1], vectorarray[i+0]);
i+=3;
v = pModelPosition.transform(v);
float swapy = v.y;
v.y = v.x;
v.x = swapy;
tempVertexArray.append(v);
}
// ---- calculate triangles
int rest = nindexes%3;
if(rest != 0)
{
nindexes -= rest;
}
for(unsigned int i=0;i<(nindexes);)
{
Triangle t = Triangle(tempVertexArray[tempIndexArray[i+2]], tempVertexArray[tempIndexArray[i+1]], tempVertexArray[tempIndexArray[i+0]] );
i+=3;
++trianglecount;
if(g>= startgroup && g <= endgroup)
{
gtree->insert(t);
}
}
if(vectorarray != 0)
{
delete vectorarray;
}
if(gtree->size() >0)
{
gtree->balance();
SubModel *sm = new SubModel(gtree);
#ifdef _ASSEMBLER_DEBUG
if(::g_df) fprintf(::g_df,"group trianglies: %d, Tris: %d, Nodes: %d, gtree.triangles: %d\n", g, sm->getNTriangles(), sm->getNNodes(), gtree->memberTable.size());
if(sm->getNTriangles() != gtree->memberTable.size())
{
if(::g_df) fprintf(::g_df,"ERROR !!!! group trianglies: %d, Tris: %d, Nodes: %d, gtree.triangles: %d\n", g, sm->getNTriangles(), sm->getNNodes(), gtree->memberTable.size());
}
#endif
sm->setBasePosition(pModelPosition.iPos);
pMainTree->insert(sm);
}
delete gtree;
}
fclose(rf);
result = true;
}
return(result);
}
//=================================================================
bool TileAssembler::fillModelIntoTree(AABSPTree<SubModel *> *pMainTree, const Vector3& pBasePos, std::string& pPos, std::string& pModelFilename)
{
bool result = false;
ModelPosition modelPosition;
getModelPosition(pPos, modelPosition);
// all should be relative to object base position
modelPosition.moveToBasePos(pBasePos);
modelPosition.init();
if(readRawFile(pModelFilename, modelPosition, pMainTree))
{
result = true;
}
return result;
}
//=================================================================
void TileAssembler::getModelPosition(std::string& pPosString, ModelPosition& pModelPosition)
{
float vposarray[3];
float vdirarray[3];
float scale;
size_t spos = pPosString.find_first_of('#');
std::string stripedPosString = pPosString.substr(spos+1,pPosString.length());
sscanf(stripedPosString.c_str(), "%f,%f,%f_%f,%f,%f_%f",
&vposarray[0],&vposarray[1],&vposarray[2],
&vdirarray[0],&vdirarray[1],&vdirarray[2],
&scale);
pModelPosition.iPos = Vector3(vposarray[0], vposarray[1], vposarray[2]);
pModelPosition.iDir = Vector3(vdirarray[0], vdirarray[1], vdirarray[2]);
pModelPosition.iScale = scale;
}
//==========================================
} // VMAP

Some files were not shown because too many files have changed in this diff Show more